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

Calling nrf_drv_timer_init(...) changes content of the static twi_control_block_t structure

Hello,

Today I stumbled upon very strange nRF52832 behaviour which I cannot explain. I am using two TWIM instances (0 and 1) and one SPIM instance (2).

First strange behaviour was that the TWIM instance 1 is working OK and TWIM instance 0 is always failing, even if I swap the configuration between them. I traced the error and discovered that TWIM0 is returning NRF_ERROR_BUSY error code, even that I use blocking mode. Moreover, TWIM1 is working fine with exactly the same code. I traced the error even further and discovered that the handler of the TWIM0 is not NULL, despite the fact that it is NULL after initialization.

I added this piece of code to the TWI driver to locate the error:

components\drivers_nrf\twi_master\nrf_drv_twi.h

/*
 * @return Handler passed to the nrf_drv_twi_init function as a event_handler parameter.
 */
nrf_drv_twi_evt_handler_t nrf_drv_get_handler(nrf_drv_twi_t const * p_instance);

components\drivers_nrf\twi_master\nrf_drv_twi.c

nrf_drv_twi_evt_handler_t nrf_drv_get_handler(nrf_drv_twi_t const * p_instance)
{
    twi_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
    return p_cb->handler;
}

Here the magic happens - my (stripped) initialization code:

nrf_drv_twi_t twi0 = NRF_DRV_TWI_INSTANCE(0);
nrf_drv_twi_t twi1 = NRF_DRV_TWI_INSTANCE(1);
nrf_drv_timer_t timer0 = NRF_DRV_TIMER_INSTANCE(1); // Instance 0 makes sd_softdevice_enable returning NRF_ERROR_SDM_INCORRECT_INTERRUPT_CONFIGURATION.

void timer0_event_handler(nrf_timer_event_t event_type, void *p_context)
{
}

void init_peripherals(void)
{
    ret_code_t ret;
    
    ret = nrf_drv_ppi_init();
    APP_ERROR_CHECK(ret);

    ret = nrf_drv_gpiote_init();
    APP_ERROR_CHECK(ret);

    nrf_drv_twi_config_t twi_config = {
        //.scl = 
        TWI0_SCL,
        //.sda = 
        TWI0_SDA,
        //.frequency = 
        NRF_TWI_FREQ_400K,
        //.interrupt_priority = 
        7,
        // Clear bus during init?
        //.clear_bus_init = 
        false,
        // Hold pull up state on gpio pins after uninit?
        //.hold_bus_uninit = 
        false
    };
    ret = nrf_drv_twi_init(&twi0, &twi_config, NULL, NULL);
    APP_ERROR_CHECK(ret);
    nrf_drv_twi_enable(&twi0);

    twi_config.scl = TWI1_SCL;
    twi_config.sda = TWI1_SDA;
    ret = nrf_drv_twi_init(&twi1, &twi_config, NULL, NULL);
    APP_ERROR_CHECK(ret);
    nrf_drv_twi_enable(&twi1);

    NRF_LOG_WARNING("TWI %u handler A = %x", twi0.drv_inst_idx, nrf_drv_get_handler(&twi0));

    // Configure timer, but do not enable it yet.
    nrf_drv_timer_config_t timer_config = {
        //.frequency = 
        NRF_TIMER_FREQ_8MHz,
        //.mode = 
        NRF_TIMER_MODE_TIMER,
        //.bit_width = 
        NRF_TIMER_BIT_WIDTH_16,
        //.interrupt_priority = 
        7,
        //.p_context = 
        NULL
    };
    ret = nrf_drv_timer_init(&timer0, &timer_config, timer0_event_handler);
    APP_ERROR_CHECK(ret);
    // Timer compare interrupt frequency = (timer_frequency / 2) / cc_value
    nrf_drv_timer_extended_compare(&timer0, NRF_TIMER_CC_CHANNEL0, 1, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, false);

    NRF_LOG_WARNING("TWI %u handler B = %x", twi0.drv_inst_idx, nrf_drv_get_handler(&twi0));
}

This is the RTT console output:

<info> twi: Function: nrf_drv_twi_init, error code: NRF_SUCCESS.
<info> twi: Instance enabled: 0.
<info> twi: Function: nrf_drv_twi_init, error code: NRF_SUCCESS.
<info> twi: Instance enabled: 1.
<warning> app: TWI 0 handler A = 0
<warning> app: TWI 0 handler B = 23579
<info> app: Initialization done.

Does anyone have any idea how could this happen? TWIM instance 1 is always fine (even if I assign it to the twi0 variable).

Thank you.

  • I have copied your code and I am unable to recreate your error. The handlers at my end are always reported as zero. What compiler are you using? Could there be something in your code that is writing to the memory location where the control block is located? Are you able to set a breakpoint on access to the memory location where your control block is located?

Related