Note about I2C implementation

From Bare Metal micro:bit
Jump to: navigation, search

From the Nordic forums:

Is it necessary to SUSPEND TWI for each byte read?

The nrf51 reference manual shows timing diagrams for the TWI interface when reading from slaves to have a shortcut between BB and SUSPEND. My assumption would be that's there to delay the ACK at the end of the read pending software reading the byte and deciding whether a STOP or repeated START should be sent.

However the text also says that once a byte is received the TWI master stretches the clock anyway before sending an ACK until the byte is read from RXD. If that's the case, I don't see why you need the SUSPEND as well, you just need to decide whether to trigger a STOP or repeated START, or nothing, before you read the byte.

Which is correct? Does the TWI master indeed delay ACK/NACK automatically until RXD is read, or is it necessary to suspend the TWI master each byte read in order to delay the ACK?

After some work with an analyser indeed the text in the manual is wrong in several places, adding some notes for the next person looking for this information. The statement

After receiving a byte, the TWI master will delay sending the ACK/NACK bit by stretching the clock until the CPU has extracted the received byte, that is, by reading the RXD register.

is not true. If you haven't already triggered a STOP or START by the time the last bit is clocked in, the TWI master sends an ACK and continues going, there's no waiting until RXD is read.

This is similarly misleading

The TWI master read sequence is stopped by triggering the STOP task. This task must be triggered before the last byte is extracted from RXD to ensure that the TWI master sends a NACK back to the slave before generating the stop condition.

Triggering a STOP before reading the byte from RXD is not enough, the ACK has already been sent by then, you have to trigger the STOP during the read of the final byte, before the RXRDY event.

SUSPEND, which isn't really documented at all, does suspend the TWI transaction after an ACK and just holds the clock line low until it's resumed. That's too late a place in the transaction to send a STOP or repeated START event however, the ACK has already occurred and the slave is expecting to send another byte.

So indeed for read transactions you pretty much must use SUSPEND for every non-final byte, to ensure you have time to read the byte before the next one clocks in. You should use a shortcut to do this and not just call TASK_SUSPEND in code, unless you are very sure your code won't be interrupted before it calls it (you have only a few hundred CPU cycles before the next byte has arrived at 100kHz, less at faster speeds so an interrupt at the wrong time would be problematic).

Having to use SUSPEND also puts your code slightly at risk of hitting PAN 56 lockup although I haven't yet.

Similarly for STOP and repeated START they need to be called while the final byte is clocking in and similarly you should use a short for that for the same reason, to ensure hardware triggers it when software could get delayed. If you are doing repeated STARTS, as there isn't a TWI short for BB->START, that would mean using PPI in that case and I haven't tested it.

The timing diagrams are correct, although they don't show repeated START after read, the text is wrong in a few areas. Would be good if the errors were corrected and the SUSPEND mode properly documented.