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

TWI doesn't work when a handler is set

I'm learning how to use TWI with the nRF52 PDK, and I have it connected to a LSM6DS3 module for testing.

When initializing the TWI, if I use the following line, it works great:

ret_code_t err_code = nrf_drv_twi_init(&m_twi, &twi_config, NULL, NULL);

However, I run into a problem when I pass an event handler, like so:

ret_code_t err_code = nrf_drv_twi_init(&m_twi, &twi_config, twi_handler, NULL);

It will execute the transfer once (verified on an oscilloscope), but the event handler never gets called, and the app appears to freeze.

I've stripped the event handler down to the bare essentials:

void twi_handler(nrf_drv_twi_evt_t const * p_event, void * p_context){
   NRF_LOG_INFO("twi event\r\n");
   NRF_LOG_FLUSH();
}

And in main(), here's how I call it:

int main(void)
    ret_code_t err_code;
    uint8_t address = 0x6B;
    uint8_t registerAddr = 0x0f;

    APP_ERROR_CHECK(NRF_LOG_INIT(NULL));
    NRF_LOG_INFO("TWI scanner.\r\n");
    NRF_LOG_FLUSH();
   twi_init();

   nrf_drv_twi_xfer_desc_t xfer = NRF_DRV_TWI_XFER_DESC_TXRX(address, &registerAddr, 1, &byteWeReceived, 1);
    while(1){
    	err_code = nrf_drv_twi_xfer(&m_twi, &xfer, 0);
    	if (err_code == NRF_SUCCESS)
		{
			NRF_LOG_INFO("sent command. got 0x%x\r\n", byteWeReceived);
	}else{
			NRF_LOG_INFO("had a problem\r\n");
		}
		NRF_LOG_FLUSH();
    	nrf_delay_ms(1000);
    }
}

I have verified with an oscilloscope that that the no-handler version works just fine--it sends the command every 1000 ms with no issues.

Is there something I'm doing incorrectly when initializing the TWI, or that I'm not handling correctly in the event handler?

  • I don't see anything particularly wrong with the way you're initializing twi, although you're not sharing the contents of your nrf_drv_twi_config_t. Your main() doesn't have logic for waiting for the interrupt, but I assume you know that. Have you considered starting with the examples/peripheral/twi_sensor example in the SDK? It's a relatively simple interrupt-based TWI example.

  • Here's the nrf_drv_twi_config_t:

        const nrf_drv_twi_config_t twi_lm75b_config = {
       .scl                = ARDUINO_SCL_PIN,
       .sda                = ARDUINO_SDA_PIN,
       .frequency          = NRF_TWI_FREQ_100K,
       .interrupt_priority = APP_IRQ_PRIORITY_HIGH,
       .clear_bus_init     = false
    };
    

    I actually used the twi_scanner code as the basis for my main.c, although there's little resemblance left after all my edits :) I'll try modifying the twi_sensor example and see if I have any more luck.

  • It appears that having NRF_LOG_FLUSH() in the event handler is what causes the problem. I don't know the precise root cause, but I suspect that it has something to do with calling it from within what is effectively an ISR. Removing that statement allowed the code to run as expected.

  • It appears that having NRF_LOG_FLUSH() in the event handler is what causes the problem. I don't know the precise root cause, but I suspect that it has something to do with calling it from within what is effectively an ISR. Removing that statement allowed the code to run as expected.

  • A little late to the party, but for future readers I just answered a similar question here:

    NRF_LOG_FLUSH() is a blocking function and if you are using UART as backend this is using interrupts while printing messages. Hence, you are triggering interrupts from within an interrupt context and this might cause priority issues. If you are using RTT as backend it will not use interrupts the same way, but since NRF_LOG_FLUSH() is blocking and since it takes a significant amount of time to format a string you should never flush in an interrupt context. NRF_LOG_FLUSH() is intended to be used only in main context.

Related