I2C DMA

Hi everyone

I'm trying to reduce the cycle time of an application running on SAM3X8E. Currently everything is very tight: total time cycle <1ms

The only real bottleneck remains an I2C reading that I'm currently doing with Wire.h at 400Khz successfully.

Are there libraries or examples of use of I2C with DMA?

I searched around (for example here: I2C + DMA - Arduino Due - Arduino Forum) but found nothing working.

Thank you

I guess it's a continuous reading of an I2C slave ?

ard_newbie:
I guess it's a continuous reading of an I2C slave ?

Yes. I have to read the status of 4 MCP23017 connected via I2C to the same bus.
I use them as input port expander and at every cycle i read the status of 8 pin of a MCP23017 with these instructions:

Wire.beginTransmission(_address);
Wire.write (reg);
Wire.endTransmission ();
Wire.requestFrom (_address, 1);
return Wire.read();

There are 2 PDC DMA for the TWI peripheral (TWI0 (SDA1/SCL1), TWI1(SDA/SCL)), and one AHB DMA for TWI0(SDA1/SCL1).

To read alternatively 4 I2C slaves with one arduino DUE board, it should be interesting to read 2 of them with the first I2C bus (TWI0(SDA1/SCL1)), and the last 2 with the other IC2 bus. This configuration requires adding 2K2 pull-ups for SDA1/SCL1 and nothing more for SDA/SCL because pull-ups are already there. Of course I guess your slaves beakout boards don't have pull-ups.

There is no library for that, you'll have to write your own code with TWI registers. Although this should not be too difficult, you should try first this configuration (2 I2C bus for 4 slaves) without a PDC DMA. In theory, this should be twice as fast. However, with the wire library, it's not possible to use both TWI (TWI0 and TW1) at the same time, you'll have to write your own code using TWI registers.

If the read speed is twice as fast as the one you can reach with your actual code, is it ok for your project ?

I've found this library:

"An alternative I2C library for Due with DMA support"

I can't understand if it really uses DMA or not.

Library seems to work. The only problem i get is that sometimes the bus "hang" and the routine keep waiting in a infinite state without trying to restore the control of the bus.

uint8_t TwoWire::requestFrom(uint8_t address, uint16_t quantity, uint8_t sendStop)
{
	if (quantity > BUFFER_LENGTH)		quantity = BUFFER_LENGTH;

	// perform blocking read into buffer
	int readed = 0;
	TWI_StartRead(twi, address, 0, 0);
	do {
		// Stop condition must be set during the reception of last byte
		if (readed + 1 == quantity)	TWI_SendSTOPCondition( twi);

		TWI_WaitByteReceived(twi, RECV_TIMEOUT);
		
		rxBuffer[readed++] = TWI_ReadByte(twi);
	} while (readed < quantity);
	TWI_WaitTransferComplete(twi, RECV_TIMEOUT);

	// set rx buffer iterator vars
	rxBufferIndex = 0;
	rxBufferLength = readed;

	return readed;
}

biccius:
I've found this library:
GitHub - collin80/due_wire: An alternative I2C library for Due with DMA support

"An alternative I2C library for Due with DMA support"

I can't understand if it really uses DMA or not.

Library seems to work. The only problem i get is that sometimes the bus "hang" and the routine keep waiting in a infinite state without trying to restore the control of the bus.

uint8_t TwoWire::requestFrom(uint8_t address, uint16_t quantity, uint8_t sendStop)

{
if (quantity > BUFFER_LENGTH) quantity = BUFFER_LENGTH;

// perform blocking read into buffer
int readed = 0;
TWI_StartRead(twi, address, 0, 0);
do {
	// Stop condition must be set during the reception of last byte
	if (readed + 1 == quantity)	TWI_SendSTOPCondition( twi);

	TWI_WaitByteReceived(twi, RECV_TIMEOUT);
	
	rxBuffer[readed++] = TWI_ReadByte(twi);
} while (readed < quantity);
TWI_WaitTransferComplete(twi, RECV_TIMEOUT);

// set rx buffer iterator vars
rxBufferIndex = 0;
rxBufferLength = readed;

return readed;

}

I'm quite suspicious about the DMA part. It look exactly like the original Arduino SAM library: ArduinoCore-sam/libraries/Wire/src/Wire.cpp at master · arduino/ArduinoCore-sam · GitHub
Also, there's a part that it disables PCD in the begin() due_wire/due_wire.cpp at master · collin80/due_wire · GitHub. Not sure what's going on here. I would really love to have some working sample code about I2C using PDC/DMA