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

TWI driver remains busy right after the nrf_drv_twi_tx() even though TX transfer is completed

I am using a nrf_drv_twi_tx() and nrf_drv_twi_rx() for a simple I2C transaction but I'm noticing a strange behavior.

  1. If I don't use APP_ERROR_CHECK(err_code); right after read(), I see the interrupt is firing as expected and I also see the read bytes sent and actual sensor data is received in response in the logic analyzer. However, when I use APP_ERROR_CHECK(err_code);, I see the execution stops with an error code 0x11 which indicates the driver is busy.
  2. Adding a random delay of 2s seemed to have solved the issue regarding the busy driver error. Even though the interrupt is finished executing, what's still causing the driver to be busy right after the write()?
  3. if I include ulTaskNotifyTake() after read(), for some weird reason, the read() function doesn't seem to fully execute i.e don't see the read bytes sent in the logic analyzer. As soon as I put the breakpoint on a read(), I see things working as expected i.e read bytes are sent and interrupt is fired. 

void twi_handler(nrf_drv_twi_evt_t const * p_event, void * p_context)	   
{
    Sensor *obj = static_cast<Sensor*>(p_context);
    
    switch (p_event->type)
    {
        case NRF_DRV_TWI_EVT_DONE:
            if (p_event->xfer_desc.type == NRF_DRV_TWI_XFER_RX)
            {
	            vTaskNotifyGiveFromISR(obj->taskHandle, pdFALSE);
            }
    	    else if (p_event->xfer_desc.type == NRF_DRV_TWI_XFER_TX)
    	    {
                // ...
    	    }
            m_xfer_done = true; 
            break;
        default:
            break;
    }
}

void Sensor::read()
{
    ret_code_t err_code = nrf_drv_twi_rx(&m_twi, ADDR, _buffer, 2);
    APP_ERROR_CHECK(err_code);
}

void Sensor::write(uint8_t reg, uint8_t *buffer, uint8_t size)
{
    ret_code_t err_code;

    err_code = nrf_drv_twi_tx(&m_twi, ADDR, &reg, size, false);
    APP_ERROR_CHECK(err_code);
    while (m_xfer_done == false);
}


void Sensor::readTask()
{
    write();  

    while(true)
    {   
        read();

        uint32_t taskNotify = ulTaskNotifyTake(pdTRUE, portMAX_DELAY); // block till data is read
        
        processData();
    }
}

Any help is greatly appreciated


Edit:

One other thing I noticed was if I include the m_xfer_done flag inside read(), I see everything working fine as expected but then I wonder what purpose is ulTaskNotifyTake serving since the m_xfer_done flag is mainly used for synchronizing the ISR and the task? Without the m_xfer_done flag used, looks to me the readTask remains blocked as there are no read bytes sent resulting in NO ISR being fired

void Sensor::read()
{
    ret_code_t err_code = nrf_drv_twi_rx(&m_twi, ADDR, _buffer, 2);
    APP_ERROR_CHECK(err_code);
    while(!m_xfer_done);  // flag that's set to true inside ISR
}

Parents Reply
  • Hi 

    The obvious reason would be that the next read is issued too fast, depending on how long the processData() takes to execute, but then you should have seen a BUSY error when trying to read the second time. 

    morpho said:
    perhaps there's a better approach to it?

    It seems a bit suboptimal to schedule reads as fast as possible, unless you really need to read the status that often. 

    Have you considered scheduling these reads from a timer instead?
    Then you can reduce power draw and CPU usage, while getting a more consistent and even readout from the sensor. 

    Also, if the sensor has an interrupt pin it makes sense to hook that up, so you only need to read when there is new data available. 

    Best regards
    Torbjørn

Children
  • My initial hunch was I was reading too fast but I have a delay of 3s between each read (for now). I wouldn't want to be reading without any delay anyways...just seems too abrupt for no particular reason.

    I don't see any BUSY error; it's just for some reason excluding the while(!m_xfer_done) from the read() call causes issues with subsequent reads, and I'm unable to understand why would that be. I don't see any error. If I don't exclude it, it works fine but then I don't see the point of using it with task notifications.

    Plus it's hard to debug because if I put the breakpoint everywhere, it would probably work.

    Timer is a good option too but then i'd need to decide between using a thread and a timer in that case. 

    nrf_drv_twi_rx()  enables the interrupt which fires the ISR and the handler, isn't it?

  • Hi

    morpho said:
    nrf_drv_twi_rx()  enables the interrupt which fires the ISR and the handler, isn't it?

    That, and quite a bit more. 

    Can you confirm which nRF device you are using, and whether or not you are using the nrfx_twim or the nrfx_twi driver under the hood?

    Are you able to show me how you initialize the driver, and what configuration you are using?

    Best regards
    Torbjørn 

  • it's nRF52840, and I'm using nrfx_twi driver. In the other thread for the BLE advertisement issue, I attached the project. There, you can check the mcp9808.cpp file. The following is how I configure it.

        i2cConfig = {
           .scl                = TWI_SCLK,
           .sda                = TWI_SDA,
           .frequency          = static_cast (TWI_FREQ),	  
           .interrupt_priority = TWI_IRQ_PRIORITY,
           .clear_bus_init     = false
        };
        
        ret_code_t err_code = nrf_drv_twi_init(&m_twi, &i2cConfig, twi_handler, this);


  • Hi

    Do you have the datasheet for your sensor?

    It seems a bit odd the way you split the write and read operations into two separate events, several seconds apart. 
    Most I2C sensors use a tx_rx scheme, where you write the internal register address and then immediately issue a read to get the data. 

    Best regards
    Torbjørn

  • I do have the datasheet, yes. 

    it mentions the device doesn't support sequential register read/write but seems to support repeated read which is what I'm doing (I believe so..) (also how's sequential read different from repeated?)

Related