Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs

TWIS driver does not trigger "NRFX_TWIS_EVT_READ_DONE" events with fast consecutive reads

I have built a system with 2 MCUs communicating through I2C.
The NRF52 is I2C slave and the other MCU is master.
I have implemented a command style interface which sends commands to the NRF52 (I2C writes, TWIS RX) followed by a I2C read (TWIS TX). The NRF52 uses address 0x51.
The buffer for TWIS TX is prepared in the "NRFX_TWIS_EVT_WRITE_DONE" event function.
The first byte in the response indicates the length / status of the response. Now I have implemented a function in the I2C master MCU to first read only a single byte.
After reading this first byte the I2C bus is stopped. Then the I2C is directly started again and the full length message is read again. To be able to read the same buffer contents again, I implemented the TX prepare function also in the "TWIS_EVT_READ_DONE" event.

For most of the times, this implementation works. However, if the nRF52 CPU gets busy with SoftDevice interrupts (BLE connections / flash writing), the "TWIS_EVT_READ_DONE" event is not always triggered by the TWIS driver on the first read. In this situation the I2C hangs as TWIS peripheral hangs streching the clock waiting for the TX prepare function which never gets triggered. The "NRFX_TWIS_EVT_READ_REQ" event does get triggered, but since I do not know if the previous I2C transter was a read or a write, I cannot call the TX prepare function.

I am wondering whether this behavior is expected?

Attached is the TWIS register status, is it true there is no way for me to get the TWIS peripheral status/state? I can only see the events from the registers.

Also attached is a I2C transfer showing the second I2C read hanging up due to the missing "tx prepare" function.

Chip I am using is nRF52832 and I use nRF5_SDK_17.1.0_ddde560.

For the short term I will probably rewrite the I2C driver of the host MCU to allow for variable length reads without stopping and starting again. I think this will solve my problems.
But I am still interested if the missing "NRFX_TWIS_EVT_READ_DONE" events can be explained.

I2C Transfer:

TWIS register view:

  • Hi,

    I am wondering whether this behavior is expected?

    Normally if the driver is in the write pending internal state (NRFX_TWIS_SUBSTATE_READ_PENDING), a stopped, read or write event from the TWIM peripheral will result in a TWIS_EVT_READ_DONE event. However, all interrupts are handled by the same handler, and the STOPPED event is cleared so if more events happen before the CPU has time to process them it could be that it is missed. If the nRF had been the master you could ensure that things do not happen too quickly, but as it is the slave I do not immediately see a way around this other than slowing down, doing less, increasing the interrupt priority (if possible and sensible) or chancing the behavior on the master end as you have done.

    Attached is the TWIS register status, is it true there is no way for me to get the TWIS peripheral status/state? I can only see the events from the registers.

    Regarding status there are the EVENTS_* registers and a few specific status registers (like MATCH, ERRORSRCS and the AMOUNT registers), but that is about it. There is no other generic status register.

  • Thanks Einar!

    I tried restarting the I2C transfer instead of stopping after reading 1 byte, but this also triggers an "Unprepare TX" in the TWIS peripheral and does not solve my problem.

    In the end I changed the behavior on my master, STM32 in this case. I have used the "RELOAD" mode and this allows me to read and evaluate the first byte before reading more bytes without having to send a start or stop condition on the bus.

Related