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

TWIM issue (nrf_twim_event_check)

Hi,

I have faced an issue during an I2C read operation. My code stuck in the infinite loop of

while (!nrf_twim_event_check(p_twim, evt_to_wait))
    {
        if (nrf_twim_event_check(p_twim, NRF_TWIM_EVENT_ERROR))
        {
            NRF_LOG_DEBUG("TWIM: Event: %s.\r\n", (uint32_t)EVT_TO_STR_TWIM(NRF_TWIM_EVENT_ERROR)); 
            nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_ERROR);
            nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_RESUME);
            nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_STOP);
            evt_to_wait = NRF_TWIM_EVENT_STOPPED;
        }
    }

The issue occurred after I was running my application for the entire day in debug mode, and did a breakpoint to check on some program variables. My code went into softreset and stuck in the aforementioned while loop. Before that the reading operation is smooth. The only way to fix this issue is to perform a hard restart which involves powering down completely and powering up. Is there any way to prevent this or breakout from this loop. Before using the TWIM (with easyDMA), I also have similar issue when I was using the TWI driver. In both cases, the code stuck in a while loop. The SCL pin is held high (normal) but the SDA is held low. FYI: I was porting my application from SDK11 to SDK12. The code worked well in SDK11.

Similar issues have been mentioned before -> devzone.nordicsemi.com/.../ devzone.nordicsemi.com/.../

Parents
  • I think I have fixed the issue by manually configure the I2C pins for input sensing with internal pull up (code below) before initializing the driver. However, more testings are required.

    //set sensing
    nrf_gpio_cfg_input(TWI_SCL_M, NRF_GPIO_PIN_PULLUP);
    nrf_gpio_cfg_input(TWI_SDA_M, NRF_GPIO_PIN_PULLUP);
    

    I have also found out that the while-loop stuck is a rare occurrence, so it was a little difficult for me to replicate the issue. The only way for me to replicate it was through running my application with constant I2C read for the entire day, and while it's reading, I will reset and reflash in my softdevice, boot-loader and upload my application. After that, the device will hang if I uploaded a version without the manual config (even soft reset will not get me out of the loop).

    Edit: I have confirmed that after I did this, I don't experience any issue with my TWI. If anyone can offer me a good explanation, that would be great. Thank you in advance.

Reply
  • I think I have fixed the issue by manually configure the I2C pins for input sensing with internal pull up (code below) before initializing the driver. However, more testings are required.

    //set sensing
    nrf_gpio_cfg_input(TWI_SCL_M, NRF_GPIO_PIN_PULLUP);
    nrf_gpio_cfg_input(TWI_SDA_M, NRF_GPIO_PIN_PULLUP);
    

    I have also found out that the while-loop stuck is a rare occurrence, so it was a little difficult for me to replicate the issue. The only way for me to replicate it was through running my application with constant I2C read for the entire day, and while it's reading, I will reset and reflash in my softdevice, boot-loader and upload my application. After that, the device will hang if I uploaded a version without the manual config (even soft reset will not get me out of the loop).

    Edit: I have confirmed that after I did this, I don't experience any issue with my TWI. If anyone can offer me a good explanation, that would be great. Thank you in advance.

Children
  • This is strange, the only difference this should make is that the drive is set to S0S1 instead of SOD1. SOD1 should be correct as the pin should only sink current (the pull-up will drive the line to the correct level when the pin is set high/released). Here is the SCL/SDA config:

    #define SCL_PIN_INIT_CONF     ( (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) \
                                  | (GPIO_PIN_CNF_DRIVE_S0D1     << GPIO_PIN_CNF_DRIVE_Pos) \
                                  | (GPIO_PIN_CNF_PULL_Pullup    << GPIO_PIN_CNF_PULL_Pos)  \
                                  | (GPIO_PIN_CNF_INPUT_Connect  << GPIO_PIN_CNF_INPUT_Pos) \
                                  | (GPIO_PIN_CNF_DIR_Input      << GPIO_PIN_CNF_DIR_Pos))
    #define SDA_PIN_INIT_CONF        SCL_PIN_INIT_CONF
    

    And here is the nrf_gpio_cfg_input(..) function:

    __STATIC_INLINE void nrf_gpio_cfg_input(uint32_t pin_number, nrf_gpio_pin_pull_t pull_config)
    {
        nrf_gpio_cfg(
            pin_number,
            NRF_GPIO_PIN_DIR_INPUT,
            NRF_GPIO_PIN_INPUT_CONNECT,
            pull_config,
            NRF_GPIO_PIN_S0S1,
            NRF_GPIO_PIN_NOSENSE);
    }
    
  • Yeah, that's a little strange but I have actually placed the manual pin config before my TWI init. The reason for doing that (which might be a little silly) was actually just me trying to pull the TWI pins high before TWI init, since I suspect the reason for the stuck is because my SDA wasn't pulled up for some reason after the TWI init (SDA was low during the stuck). Also to note that I was relying on the internal pullups.

  • Hi, My code is also stuck in this infinite loop. I have added your posted code //set sensing nrf_gpio_cfg_input(TWI_SCL_M, NRF_GPIO_PIN_PULLUP); nrf_gpio_cfg_input(TWI_SDA_M, NRF_GPIO_PIN_PULLUP); before my twi_master_init(); function call, but I am still stuck in the infinite loop. Do you have any suggestions I can try? Thanks

  • Hi Levi,

    I guess a couple of things you can try:

    1. Check if your I2C slave device is holding up the I2C bus. You can try to imitate a stop command before init TWI. Alternatively, you can try to perform a clear bus before init. The latest SDK does not do that by default.
    2. One of the Nordic AFEs offered me the following solution to modify the I2C driver by adding a 4us delay between NRF_GPIO->PIN_CNF[p_config->scl] = SCL_PIN_CONF; NRF_GPIO->PIN_CNF[p_config->sda] = SDA_PIN_CONF; But it didn't resolve my issue unfortunately. Hope it helps you.
  • Here's what I tried:

    1. #define TWI_DEFAULT_CONFIG_CLR_BUS_INIT 1 in sdk_config.h to enable clearing the bus during initialization.
    2. Added the nrf_delay_us(4); where you said to add it.

    No luck so far. It appears my code is getting stuck in my driver function for my TWI sensor and not TWI_init(). Just wanted to make sure we are on the same page. I'll keep digging! Thanks for the help!

Related