79698428

Date: 2025-07-11 13:51:39
Score: 1
Natty:
Report link

Finally came across the answer to this conundrum. Since this was the cause of quite quite a bit of wheel spinning and I was unable to find the answer easily, I'm answering this question here for any future beleaguered Arduino Due I2C user:

It turned out that my observations of the behaviour and the workaround were a red herring. The real issue is in fact that I had overlooked a small but significant detail of the I2C specification:
enter image description here

What this means is that if the controller (master) ACK's the byte received from the peripheral (slave) then the peripheral should continue to clock out the next byte. If that byte happens to be a 0x00, then this will will prevent the controller from successfully sending the STOP byte, and will manifest itself as the SDA line being held low for another 9 clock cycles. Thus if the controller only wants to read a single byte at a time it is important that it "sends a NACK" (i.e., it doesn't ACK the received byte)

In the case of my Arduino Due running my own code it raises the question of "what byte should the I2C peripheral send in such cases?". Presumably whatever is in the transmit buffer. Ideally that transmit buffer would be empty and my code would be made aware of the demand for a byte via the relevant interrupt firing, thus I would have come to learn that the controller was implying it wanted more bytes. However I found that the SAM3X8E always required me to populate the I2C transmit buffer in advance, even when there was no I2C read operation on the distant horizon. Therefore the code always pushed something into the transmit buffer (then had to overwrite it quickly just as soon as a read operation was received, hopefully prior to the bogus byte being clocked out. This seems a little surprising as a hardware interface goes, but the Arduino Due is cheap as chips I suppose). The upshot of this is that I was never aware that the transmit buffer was being read during those "SDA line held low" periods.

Reasons:
  • Long answer (-1):
  • No code block (0.5):
  • Contains question mark (0.5):
  • Self-answer (0.5):
  • Low reputation (0.5):
Posted by: thecowster