Hi all,
I am working on a project with multiple DUE's talking to each other over I2C. The crux of the problem is that in between the DUE's are a set of slip rings that can add ~5 mOhm resistance to the wires as the slip ring completes 1 rev (I also use about 2m of shielded cable between the DUEs). After changing my I2C to SDA1 & SCL1 so that I could put my own pull-up resistors on, and reducing the clock speed to 25k, I found that I could get some communication by having a pull-up resistor on either end of the cable for a total resistance ~18kOhm.
When the slip rings are stationary, the communication is fine. However, after about 10 seconds of them rotating the I2C receives a NACK (either during data transmit or address transmit). If I manually restart the DUE, then it usually works again for a few seconds.
My questions:
- On the hardware side, what can I do to ensure that I2C hangs less? It seems like the SCL line is that one that is very susceptible to noise. I have some ferrite beads coming in the mail. Make an RC filter with cutoff frequency much higher than clock speed? I know the SAM3X data sheet says C<400pF.
- On the software side, what can I do so that if there is an error in the transmit process, I can still keep transmitting. Ideally if there is a NACK I would just like to reset and try again. I tried many different variations in the source code to be able to automatically reset, but what ended up sort of working is:
uint8_t TwoWire::endTransmission(uint8_t sendStop) {
uint8_t error = 0;
// transmit buffer (blocking)
TWI_StartWrite(twi, txAddress, 0, 0, txBuffer[0]);
if (!TWI_WaitByteSent(twi, XMIT_TIMEOUT))
error = 2; // error, got NACK on address transmit
if (error == 0) {
uint16_t sent = 1;
while (sent < txBufferLength) {
TWI_WriteByte(twi, txBuffer[sent++]);
if (!TWI_WaitByteSent(twi, XMIT_TIMEOUT))
error = 3; // error, got NACK during data transmmit
TWI_Reset(twi); //get out of this while loop
}
}
if (error == 0) {
TWI_Stop(twi);
if (!TWI_WaitTransferComplete(twi, XMIT_TIMEOUT))
error = 4; // error, finishing up
}
txBufferLength = 0; // empty buffer
status = MASTER_IDLE;
return error;
}
where I copied from TWI_Stop to write TWI_Reset:
void TWI_Reset( Twi *pTwi )
{
assert( pTwi != NULL ) ;
pTwi->TWI_CR = TWI_CR_SWRST;
}
but the I2C still hangs! I know that someone wrote a more resilient code for the older chips:Arduino Playground - SoftwareI2CLibrary, but I haven't been able to find anything of that sort for the SAM3X.
Any thoughts on either of these questions would be much appreciated.
Sam