Code Monkey home page Code Monkey logo

Comments (6)

rsta2 avatar rsta2 commented on September 27, 2024

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.

u77345 avatar u77345 commented on September 27, 2024

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.

rsta2 avatar rsta2 commented on September 27, 2024

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.

u77345 avatar u77345 commented on September 27, 2024

Thanks again, it worked wonderfully! Tested on BCM2837/Pi 3 A+.

from circle.

rsta2 avatar rsta2 commented on September 27, 2024

Great! The patch has been added on the develop branch now. Thanks again for testing!

from circle.

rsta2 avatar rsta2 commented on September 27, 2024

Support for I2C repeated start is in Circle 45.3.

from circle.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.