This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

SCL Stuck Low with NRF52810 SDK 15.0 on Custom Board

I've got a custom board using the NRF52810 with SDK v15.0.0.

I am using the TWIM driver (nrfx_twim.c master mode) to drive an LCD driver IC, a capacitive touch sensor IC, and a fuel gauge IC.  After connection there is no activity on I2C for the LED driver IC and the Fuel Gauge IC (I am intentionally not sending them anything so as not to confuse the issue..)

After connection, my code is just reading 300 bytes of data off of the touch sensor IC five times per second.  The SCL clock is 100 kHz and the waveform looks perfectly fine.

This works well for anywhere from 5 seconds up to 60 seconds--I can see the data being sent across the I2C bus and I am capturing this data and putting it into an array without any issues.  After a while (q.v. anywhere from 5 to 60s) the SCL line goes low at the beginning of a read, and never goes high again.  I added code that detects this condition and then disables TWIM and uses nrf_gpio_cfg_default to deassert the line.  After the nrf_gpio_cfg_default line is executed, the SCL line goes back high.  This tells me that it is the NRF52 that is pulling the SCL line low, and not one of the slave I2C devices.

I can't figure out why the TWIM is stopping.  I  get no error messages, and these are what my TWIM registers say:

TASK_STARTRX:          0

TASK_STARTTX            0

TASKS_STOP                0

TASKS_SUSPEND        0

TASKS_RESUME          0

EVENTS_STOPPED      0

EVENTS_ERROR          0

EVENTS_SUSPENDED 0

EVENTS_RESTARTED  1

EVENTS_TXSTARTED   1

EVENTS_LASTRX          0

EVENTS_LASTTX         0

SHORTS ->LASTTX_STOP         1

INTEN->STOPPED         1

INTEN->ERROR             1

ERRORSRC                    0

ENABLE                           6

PSEL->SCL                     5 (correct pin)

PSEL->SDA                     6 (correct pin)

RXD->PTR                      0x200033F8 (address of correct secondary buffer)

RXD->MAXCNT              0x12C (the 300 bytes I am reading)

RXD->AMOUNT              0x02B (I've seen various numbers here from 0x000 to 0x12C)

RXD->LIST                      0

TXD->PTR                       0x20001D88 (address of correct primary buffer)

TXD->MAXCNT               2 (register address is 2 bytes)

TXD->AMOUNT               2

TXD->LIST                       0

ADDRESS                        0x74 (correct I2C address)

Any ideas what may be happening?

Parents
  • I put a breakpoint in my TWIM handler function.  When the SCL line is getting stuck low, I am getting an NRFX_TWIM_EVT_DONE event, but the AMOUNT != MAXCNT.  I reduced the amount of data I am transferring so that MAXCNT is now only 0xAF.

    I will be writing some code to reset the I2C when this error occurs (as a workaround), but I really would like a better understanding of the root cause.  Why would I be getting an NRFX_TWIM_EVT_DONE event when I have received all of the data I requested in nrfx_twim_xfer()?  It works perfectly fine sometimes for 2-300 calls, but then suddenly one call returns done without completing the request...

  • Not sure what caused it but you may want to have a look at this alternative i2c driver for the nRF52.  It is probably simpler to understand. 

  • Thanks for the code--I'll definitely take a look a closer look at it in the near future to see if it fixes the issue.  I wish that I had the time to look into this more, but I have to get some other features working before our software team starts to complain about not having hardware to develop on and/or our delaying production schedule.

    For now, I added a check in my EVT handler for the stuck condition and am performing an I2C reset, and then resending the last command.  This is a clunky "solution", but it is working.

  • Hi

    I cannot recreate the problem, but guessing by the registers state you have provided we can tell that the twim_irq_handler (line 493 in nrfx_twim.c) hited the "else" conditional in line 562. The way this condition is added here seems not to be 100% safe. For quick test could you replace it by:

    if (nrf_twim_event_check(p_twim, NRF_TWIM_EVENT_SUSPENDED))

    And check if the problem persist?

    To clarify, there should be

        if (nrf_twim_event_check(p_twim, NRF_TWIM_EVENT_SUSPENDED))
        {
            nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_SUSPENDED);
            NRFX_LOG_DEBUG("TWIM: Event: %s.", EVT_TO_STR_TWIM(NRF_TWIM_EVENT_SUSPENDED));
            if (p_cb->xfer_desc.type == NRFX_TWIM_XFER_TX)

    Instead of

        else
        {
            nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_SUSPENDED);
            NRFX_LOG_DEBUG("TWIM: Event: %s.", EVT_TO_STR_TWIM(NRF_TWIM_EVENT_SUSPENDED));
            if (p_cb->xfer_desc.type == NRFX_TWIM_XFER_TX)

    Sorry for providing not tested solution, but as you did not provide any code to check the problem and we cannot recreate it this was the only one I can think right now. It would really speed thing up if you could test it in your application.

  • I have similar issue: https://devzone.nordicsemi.com/f/nordic-q-a/30878/app_twi-gets-stuck-in-while-internal_transaction_in_progress

    I have tried above solution and I'm still getting it to hang with my repro code from the thread.

    I've also observed random hangs in scenario where there's a lot of long TWI TX operations (complete overwrite of Adesto RM24C512C eeprom).

    EDIT: I've dug some deeper in my repro and It seems that in certain circumstances TWIM irq handler stops being called despite pending transfers so no events are propagated to the app_twi and the application code.

    Also in my case value of AMMOUNT register is larger than MAXCNT which is weird.

Reply Children
No Data
Related