This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts
This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Where the twi_handler() is called in twi sensor example?

Hello. I'm trying to understand twi_sensor sample code on nRF51. (nRF51_SDK_10.0.0_dc26b5e\examples\peripheral\twi_sensor)

I have a trouble finding where the function twi_handler() in main.c is called.

void twi_handler(nrf_drv_twi_evt_t const * p_event, void * p_context)
{   
ret_code_t err_code;
static sample_t m_sample;

switch(p_event->type)
{
    case NRF_DRV_TWI_RX_DONE:
        read_data(&m_sample);
        m_xfer_done = true;
        break;
    case NRF_DRV_TWI_TX_DONE:
        if(m_set_mode_done != true)
        {
            m_set_mode_done  = true;
            return;
        }
        m_xfer_done = false;
        /* Read 4 bytes from the specified address. */
        err_code = nrf_drv_twi_rx(&m_twi_mma_7660, MMA7660_ADDR, (uint8_t*)&m_sample, sizeof(m_sample), false);
        APP_ERROR_CHECK(err_code);
        break;
    default:
        break;        
}   
}

I know that the address of twi_handler() is passed to nrf_drv_twi_init() and stored in m_handlers. And I guess this handler should be called somewhere in twi_transfer() inside nrf_drv_twi_tx().

  • nrf_drv_twi_tx() of main.c:
void MMA7660_set_mode(void)
{
ret_code_t err_code;
/* Writing to MMA7660_REG_MODE "1" enables the accelerometer. */
uint8_t reg[2] = {MMA7660_REG_MODE, ACTIVE_MODE};

err_code = nrf_drv_twi_tx(&m_twi_mma_7660, MMA7660_ADDR, reg, sizeof(reg), false);  
APP_ERROR_CHECK(err_code);

while(m_set_mode_done == false);
}
  • twi_transfer() of nrf_drv_twi.c:
static ret_code_t twi_transfer(nrf_drv_twi_t const * const p_instance,
                           uint8_t                     address,
                           uint8_t const             * p_data,
                           uint32_t                    length,
                           bool                        xfer_pending,
                           bool                        is_tx)
{
ASSERT(m_cb[p_instance->instance_id].state == NRF_DRV_STATE_POWERED_ON);
ASSERT(length > 0);

control_block_t * p_cb = &m_cb[p_instance->instance_id];

bool is_busy = false;
CRITICAL_REGION_ENTER();
if (p_cb->transfer_in_progress)
{
    is_busy = true;
}
else
{
    p_cb->transfer_in_progress = true;
}
CRITICAL_REGION_EXIT();
if (is_busy)
{
    return NRF_ERROR_BUSY;
}

transfer_t * p_transfer = &p_cb->transfer;
p_transfer->address         = address;
p_transfer->length          = (uint16_t)length;
p_transfer->p_data          = (uint8_t *)p_data;
p_transfer->count           = 0;
p_transfer->xfer_pending    = xfer_pending;
p_transfer->is_tx           = is_tx;
p_transfer->error_condition = false;

state_machine(p_instance, p_transfer->is_tx ? TX_ADDR_REQ : RX_ADDR_REQ);

if (!m_handlers[p_instance->instance_id])
{
    // blocking mode
    sm_evt_t evt = p_transfer->is_tx ? TX_DONE : RX_DONE;
    do
    {
        if (twi_action_wait(p_instance) == false)
        {
            nrf_twi_event_clear(p_instance->p_reg, NRF_TWI_EVENTS_ERROR);
            evt = ON_ERROR;
        }
        nrf_twi_event_clear(p_instance->p_reg, p_transfer->end_event);
        state_machine(p_instance, evt);

        if (p_transfer->error_condition)
        {
            p_cb->transfer_in_progress = false;
            return NRF_ERROR_INTERNAL;
        }
    }
    while (p_transfer->count < p_transfer->length);
    p_cb->transfer_in_progress = false;
}
return NRF_SUCCESS;
}

Can you help me find where this handler is called? It will be very helpful for me to get into the next step. Thanks.

Parents
  • Hi

    When you set up the TWI with a handler like this the twi_handler will be stored in the variable m_handlers of type nrf_drv_twi_evt_handler_t. In SDK 10 this happens in nrf_drv_twi_init() defined in nrf_drv_twi.c:

    m_handlers[p_instance->instance_id]  = event_handler;
    

    Then in nrf_drv_twi_enable() there is a call to nrf_twi_int_enable() which enables the TWI interrupts. Then when you do TWI transfers and these interrupts are triggered this happens at the bottom of nrf_drv_twi.c:

    void SPI0_TWI0_IRQHandler(void)
    {
        nrf_drv_twi_int_handler(NRF_TWI0, TWI0_INSTANCE_INDEX);
    }
    

    Then finally, inside nrf_drv_twi_int_handler() you will find this call:

    m_handlers[instance_id](&evt, mp_contexts[instance_id]);
    

    which is where your particular twi handler is called.

    It is a labyrinth and in some cases, especially if you need speed, you might be better off writing your own init and interrupt routine.

  • Thanks. Your answer is very helpful to me.

Reply Children
No Data
Related