Softdevice - how to get twi / i2c address from twi_handler

Hello All,

I am using nRF SDK 17.0.2 (softdevice). I have connected multiple sensors using I2C protocol, I want to know if there is any failure in sensor and if it is not responding on twi then I am getting event NRF_DRV_TWI_EVT_ADDRESS_NACK but how to get the address for which this address has not acknowleged? if p_context holds such information, how to use it?

void twi_handler(nrf_drv_twi_evt_t const * p_event, void * p_context)
{
    switch (p_event->type)
    {
        case NRF_DRV_TWI_EVT_DONE:
            if (p_event->xfer_desc.type == NRF_DRV_TWI_XFER_RX)
            {
               NRF_LOG_INFO("twi_handler");
            }
            m_xfer_done = true;
            break;
             case NRF_DRV_TWI_EVT_ADDRESS_NACK: 
            SEGGER_RTT_printf(0,"No address ACK on address: %#x!\r\n", 0); 
            m_xfer_done = true;
             break; 
         case NRF_DRV_TWI_EVT_DATA_NACK: 
            SEGGER_RTT_printf(0,"No data ACK on address: %#x!\r\n", 0); 
             break; 
        default:
            break;
    }
}

Thanks and regards,

Neeraj Dhekale

  • Hi,

    The NRF_DRV_TWI_EVT_ADDRESS_NACK event is triggered when the slave device does not acknowledge its address. However, the p_context does not hold the address of the non-acknowledging device. The p_context is a void pointer that you can use to pass extra information to the event handler, but it's not automatically filled with any specific data by the TWI driver.

    To identify which device is not acknowledging its address, you could modify your code to store the address of the device you're currently trying to communicate with in a global variable. Then, in your event handler, you can check this global variable when you receive the NRF_DRV_TWI_EVT_ADDRESS_NACK event.

    uint8_t current_address;
    
    void twi_event_handler(nrf_drv_twi_evt_t const * p_event, void * p_context)
    {
        switch (p_event->type)
        {
            case NRF_DRV_TWI_EVT_ADDRESS_NACK:
                printf("No ACK from device with address: 0x%x\n", current_address);
                break;
            // Handle other events...
        }
    }
    
    void communicate_with_device(uint8_t address)
    {
        current_address = address;
        // Start communication...
    }

    In this example, before you start communicating with a device, you store its address in current_address. Then, if you receive a NRF_DRV_TWI_EVT_ADDRESS_NACK event, you know that current_address is the address of the device that didn't acknowledge its address.

    Please note that this is a simple example and might not cover all your needs. For example, if you're communicating with multiple devices simultaneously from different threads, you'll need a more sophisticated way to track which address corresponds to which NACK event.

  • Hi  

    Thanks for the reply.

    Got it your logic using current_address.

    The p_context is a void pointer that you can use to pass extra information to the event handler,

    Any chance to pass i2c address to p_context as extra information? if yes, how can I implement it?

    Thanks and regards,

    Neeraj Dhekale

  • Hi Neeraj,

    Not directly. The context is provided by nrf_drv_twi_init(), and not nrf_drv_twi_xfer(), so not for each transaction. You could of course provide a pointer to a variable and update that same variable before every call to nrf_drv_twi_xfer(), but that would not give you any benefits compared to using a global variable (it would just make things a bit more complicated).

    Einar

Related