Comments (6)
Here is a patch for the develop branch, which tries to add the method CI2CMaster::WriteReadRepeatedStart()
. It is not tested, because I do not have an I2C device, which needs repeated start. Please let me know, if it works.
diff --git a/include/circle/i2cmaster.h b/include/circle/i2cmaster.h
index 831e5ea..f882cec 100644
--- a/include/circle/i2cmaster.h
+++ b/include/circle/i2cmaster.h
@@ -2,7 +2,7 @@
/// \file i2cmaster.h
//
// Circle - A C++ bare metal environment for Raspberry Pi
-// Copyright (C) 2014-2022 R. Stange <[email protected]>
+// Copyright (C) 2014-2023 R. Stange <[email protected]>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -74,6 +74,17 @@ public:
/// \return Number of written bytes or < 0 on failure
int Write (u8 ucAddress, const void *pBuffer, unsigned nCount);
+ /// \brief Consecutive write and read operation with repeated start
+ /// \param ucAddress I2C slave address of target device
+ /// \param pWriteBuffer Write data for will be taken from here
+ /// \param nWriteCount Number of bytes to be written (max. 16)
+ /// \param pReadBuffer Read data will be stored here
+ /// \param nReadCount Number of bytes to be read
+ /// \return Number of read bytes or < 0 on failure
+ int WriteReadRepeatedStart (u8 ucAddress,
+ const void *pWriteBuffer, unsigned nWriteCount,
+ void *pReadBuffer, unsigned nReadCount);
+
private:
unsigned m_nDevice;
uintptr m_nBaseAddress;
diff --git a/lib/i2cmaster.cpp b/lib/i2cmaster.cpp
index 7c7f927..5ca5172 100644
--- a/lib/i2cmaster.cpp
+++ b/lib/i2cmaster.cpp
@@ -2,7 +2,7 @@
// i2cmaster.cpp
//
// Circle - A C++ bare metal environment for Raspberry Pi
-// Copyright (C) 2014-2022 R. Stange <[email protected]>
+// Copyright (C) 2014-2023 R. Stange <[email protected]>
//
// Large portions are:
// Copyright (C) 2011-2013 Mike McCauley
@@ -331,3 +331,115 @@ int CI2CMaster::Write (u8 ucAddress, const void *pBuffer, unsigned nCount)
return nResult;
}
+
+int CI2CMaster::WriteReadRepeatedStart (u8 ucAddress,
+ const void *pWriteBuffer, unsigned nWriteCount,
+ void *pReadBuffer, unsigned nReadCount)
+{
+ assert (m_bValid);
+
+ if (ucAddress >= 0x80)
+ {
+ return -I2C_MASTER_INALID_PARM;
+ }
+
+ if ( nWriteCount == 0 || nWriteCount > FIFO_SIZE || pWriteBuffer == 0
+ || nReadCount == 0 || pReadBuffer == 0
+ )
+ {
+ return -I2C_MASTER_INALID_PARM;
+ }
+
+ m_SpinLock.Acquire ();
+
+ u8 *pWriteData = (u8 *) pWriteBuffer;
+
+ PeripheralEntry ();
+
+ // setup transfer
+ write32 (m_nBaseAddress + ARM_BSC_A__OFFSET, ucAddress);
+
+ write32 (m_nBaseAddress + ARM_BSC_C__OFFSET, C_CLEAR);
+ write32 (m_nBaseAddress + ARM_BSC_S__OFFSET, S_CLKT | S_ERR | S_DONE);
+
+ write32 (m_nBaseAddress + ARM_BSC_DLEN__OFFSET, nWriteCount);
+
+ // fill FIFO
+ while (nWriteCount-- > 0)
+ {
+ write32 (m_nBaseAddress + ARM_BSC_FIFO__OFFSET, *pWriteData++);
+ }
+
+ // start transfer
+ write32 (m_nBaseAddress + ARM_BSC_C__OFFSET, C_I2CEN | C_ST);
+
+ // poll for transfer has started
+ while (!(read32 (m_nBaseAddress + ARM_BSC_S__OFFSET) & S_TA))
+ {
+ if (read32 (m_nBaseAddress + ARM_BSC_S__OFFSET) & S_DONE)
+ {
+ break;
+ }
+ }
+
+ // transfer active
+ while (!(read32 (m_nBaseAddress + ARM_BSC_S__OFFSET) & S_DONE))
+ {
+ // just wait
+ }
+
+ u8 *pReadData = (u8 *) pReadBuffer;
+
+ int nResult = 0;
+
+ // setup transfer
+ write32 (m_nBaseAddress + ARM_BSC_DLEN__OFFSET, nReadCount);
+
+ write32 (m_nBaseAddress + ARM_BSC_C__OFFSET, C_I2CEN | C_ST | C_READ);
+
+ // transfer active
+ while (!(read32 (m_nBaseAddress + ARM_BSC_S__OFFSET) & S_DONE))
+ {
+ while (read32 (m_nBaseAddress + ARM_BSC_S__OFFSET) & S_RXD)
+ {
+ *pReadData++ = read32 (m_nBaseAddress + ARM_BSC_FIFO__OFFSET) & FIFO__MASK;
+
+ nReadCount--;
+ nResult++;
+ }
+ }
+
+ // transfer has finished, grab any remaining stuff from FIFO
+ while ( nReadCount > 0
+ && (read32 (m_nBaseAddress + ARM_BSC_S__OFFSET) & S_RXD))
+ {
+ *pReadData++ = read32 (m_nBaseAddress + ARM_BSC_FIFO__OFFSET) & FIFO__MASK;
+
+ nReadCount--;
+ nResult++;
+ }
+
+ u32 nStatus = read32 (m_nBaseAddress + ARM_BSC_S__OFFSET);
+ if (nStatus & S_ERR)
+ {
+ write32 (m_nBaseAddress + ARM_BSC_S__OFFSET, S_ERR);
+
+ nResult = -I2C_MASTER_ERROR_NACK;
+ }
+ else if (nStatus & S_CLKT)
+ {
+ nResult = -I2C_MASTER_ERROR_CLKT;
+ }
+ else if (nReadCount > 0)
+ {
+ nResult = -I2C_MASTER_DATA_LEFT;
+ }
+
+ write32 (m_nBaseAddress + ARM_BSC_S__OFFSET, S_DONE);
+
+ PeripheralExit ();
+
+ m_SpinLock.Release ();
+
+ return nResult;
+}
from circle.
Thanks for the patch; did not work. The call returned with -4 (I2C_MASTER_DATA_LEFT). On the wire only the device address was written out on 8 bit, the command byte was not. The address was acknowladged. Target was MAX31334, however any other device, working by addressing a register before read should pass the repeat start test.
u8 Cmd[] = {0x09};
u8 Reg[7];
int nResult = m_pI2CMaster->WriteReadRepeatedStart (m_ucSlaveAddress, Cmd, sizeof Cmd, Reg, sizeof Reg);
if (nResult != sizeof Reg)
{
CLogger::Get ()->Write (FromMCP7941X, LogError, "I2C read/write failed (err %d)", nResult);
return FALSE;
}
from circle.
Thanks for testing! Here comes another patch. It now contains the delay, which I was trying to eliminate before, which was obviously not working. The previous patch is included in this one.
diff --git a/include/circle/i2cmaster.h b/include/circle/i2cmaster.h
index 831e5ea..4b13f25 100644
--- a/include/circle/i2cmaster.h
+++ b/include/circle/i2cmaster.h
@@ -2,7 +2,7 @@
/// \file i2cmaster.h
//
// Circle - A C++ bare metal environment for Raspberry Pi
-// Copyright (C) 2014-2022 R. Stange <[email protected]>
+// Copyright (C) 2014-2023 R. Stange <[email protected]>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -74,6 +74,17 @@ public:
/// \return Number of written bytes or < 0 on failure
int Write (u8 ucAddress, const void *pBuffer, unsigned nCount);
+ /// \brief Consecutive write and read operation with repeated start
+ /// \param ucAddress I2C slave address of target device
+ /// \param pWriteBuffer Write data for will be taken from here
+ /// \param nWriteCount Number of bytes to be written (max. 16)
+ /// \param pReadBuffer Read data will be stored here
+ /// \param nReadCount Number of bytes to be read
+ /// \return Number of read bytes or < 0 on failure
+ int WriteReadRepeatedStart (u8 ucAddress,
+ const void *pWriteBuffer, unsigned nWriteCount,
+ void *pReadBuffer, unsigned nReadCount);
+
private:
unsigned m_nDevice;
uintptr m_nBaseAddress;
@@ -85,6 +96,7 @@ private:
CGPIOPin m_SCL;
unsigned m_nCoreClockRate;
+ unsigned m_nClockSpeed;
CSpinLock m_SpinLock;
};
diff --git a/lib/i2cmaster.cpp b/lib/i2cmaster.cpp
index 7c7f927..537a44b 100644
--- a/lib/i2cmaster.cpp
+++ b/lib/i2cmaster.cpp
@@ -2,7 +2,7 @@
// i2cmaster.cpp
//
// Circle - A C++ bare metal environment for Raspberry Pi
-// Copyright (C) 2014-2022 R. Stange <[email protected]>
+// Copyright (C) 2014-2023 R. Stange <[email protected]>
//
// Large portions are:
// Copyright (C) 2011-2013 Mike McCauley
@@ -26,6 +26,7 @@
#include <circle/bcm2835.h>
#include <circle/machineinfo.h>
#include <circle/synchronize.h>
+#include <circle/timer.h>
#include <assert.h>
#if RASPPI < 4
@@ -108,6 +109,7 @@ CI2CMaster::CI2CMaster (unsigned nDevice, boolean bFastMode, unsigned nConfig)
m_nConfig (nConfig),
m_bValid (FALSE),
m_nCoreClockRate (CMachineInfo::Get ()->GetClockRate (CLOCK_ID_CORE)),
+ m_nClockSpeed (0),
m_SpinLock (TASK_LEVEL)
{
if ( m_nDevice >= DEVICES
@@ -165,6 +167,8 @@ void CI2CMaster::SetClock (unsigned nClockSpeed)
PeripheralEntry ();
assert (nClockSpeed > 0);
+ m_nClockSpeed = nClockSpeed;
+
u16 nDivider = (u16) (m_nCoreClockRate / nClockSpeed);
write32 (m_nBaseAddress + ARM_BSC_DIV__OFFSET, nDivider);
@@ -331,3 +335,112 @@ int CI2CMaster::Write (u8 ucAddress, const void *pBuffer, unsigned nCount)
return nResult;
}
+
+int CI2CMaster::WriteReadRepeatedStart (u8 ucAddress,
+ const void *pWriteBuffer, unsigned nWriteCount,
+ void *pReadBuffer, unsigned nReadCount)
+{
+ assert (m_bValid);
+
+ if (ucAddress >= 0x80)
+ {
+ return -I2C_MASTER_INALID_PARM;
+ }
+
+ if ( nWriteCount == 0 || nWriteCount > FIFO_SIZE || pWriteBuffer == 0
+ || nReadCount == 0 || pReadBuffer == 0
+ )
+ {
+ return -I2C_MASTER_INALID_PARM;
+ }
+
+ m_SpinLock.Acquire ();
+
+ u8 *pWriteData = (u8 *) pWriteBuffer;
+
+ PeripheralEntry ();
+
+ // setup transfer
+ write32 (m_nBaseAddress + ARM_BSC_A__OFFSET, ucAddress);
+
+ write32 (m_nBaseAddress + ARM_BSC_C__OFFSET, C_CLEAR);
+ write32 (m_nBaseAddress + ARM_BSC_S__OFFSET, S_CLKT | S_ERR | S_DONE);
+
+ write32 (m_nBaseAddress + ARM_BSC_DLEN__OFFSET, nWriteCount);
+
+ // fill FIFO
+ for (unsigned i = 0; i < nWriteCount; i++)
+ {
+ write32 (m_nBaseAddress + ARM_BSC_FIFO__OFFSET, *pWriteData++);
+ }
+
+ // start transfer
+ write32 (m_nBaseAddress + ARM_BSC_C__OFFSET, C_I2CEN | C_ST);
+
+ // poll for transfer has started
+ while (!(read32 (m_nBaseAddress + ARM_BSC_S__OFFSET) & S_TA))
+ {
+ if (read32 (m_nBaseAddress + ARM_BSC_S__OFFSET) & S_DONE)
+ {
+ break;
+ }
+ }
+
+ u8 *pReadData = (u8 *) pReadBuffer;
+
+ int nResult = 0;
+
+ // setup transfer
+ write32 (m_nBaseAddress + ARM_BSC_DLEN__OFFSET, nReadCount);
+
+ write32 (m_nBaseAddress + ARM_BSC_C__OFFSET, C_I2CEN | C_ST | C_READ);
+
+ assert (m_nClockSpeed > 0);
+ CTimer::SimpleusDelay ((nWriteCount + 1) * 9 * 1000000 / m_nClockSpeed);
+
+ // transfer active
+ while (!(read32 (m_nBaseAddress + ARM_BSC_S__OFFSET) & S_DONE))
+ {
+ while (read32 (m_nBaseAddress + ARM_BSC_S__OFFSET) & S_RXD)
+ {
+ *pReadData++ = read32 (m_nBaseAddress + ARM_BSC_FIFO__OFFSET) & FIFO__MASK;
+
+ nReadCount--;
+ nResult++;
+ }
+ }
+
+ // transfer has finished, grab any remaining stuff from FIFO
+ while ( nReadCount > 0
+ && (read32 (m_nBaseAddress + ARM_BSC_S__OFFSET) & S_RXD))
+ {
+ *pReadData++ = read32 (m_nBaseAddress + ARM_BSC_FIFO__OFFSET) & FIFO__MASK;
+
+ nReadCount--;
+ nResult++;
+ }
+
+ u32 nStatus = read32 (m_nBaseAddress + ARM_BSC_S__OFFSET);
+ if (nStatus & S_ERR)
+ {
+ write32 (m_nBaseAddress + ARM_BSC_S__OFFSET, S_ERR);
+
+ nResult = -I2C_MASTER_ERROR_NACK;
+ }
+ else if (nStatus & S_CLKT)
+ {
+ nResult = -I2C_MASTER_ERROR_CLKT;
+ }
+ else if (nReadCount > 0)
+ {
+ nResult = -I2C_MASTER_DATA_LEFT;
+ }
+
+ write32 (m_nBaseAddress + ARM_BSC_S__OFFSET, S_DONE);
+
+ PeripheralExit ();
+
+ m_SpinLock.Release ();
+
+ return nResult;
+}
from circle.
Thanks again, it worked wonderfully! Tested on BCM2837/Pi 3 A+.
from circle.
Great! The patch has been added on the develop branch now. Thanks again for testing!
from circle.
Support for I2C repeated start is in Circle 45.3.
from circle.
Related Issues (20)
- USB CDC/ACM gadget HOT 19
- GetClockTicks without wrap HOT 3
- GPU support on Raspi 4 HOT 4
- Circle linker failure with softfp HOT 2
- Make USB gadget vendor and device strings configurable HOT 2
- Support for touchscreens with additional reports in HID descriptor HOT 7
- Question about log when testing with Qemu HOT 2
- Help with setting PREFIX HOT 4
- Question: Waveshare 5'' DSI display support? HOT 2
- Waveshare 15.6inch Capacitive Touch Screen HOT 2
- Can I run OpenCV? HOT 2
- Sample "07-usbstorage" fails with Pi5 HOT 8
- Unsuportted USB touch screen driver - Big Tree Tech HDMI7 HOT 10
- How to do GPIOPin button Interrupt correctly HOT 23
- FIQ support on RPI Zero 2 HOT 3
- How to remove all text not from own CSerialDevice HOT 11
- Ability to set HDMI output refresh rate HOT 3
- About memory management on CM4 HOT 2
- Building circle-stdlib w/Circle: This header is not available in freestanding mode. HOT 6
- I2S simultaneous input+output HOT 4
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from circle.