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

RBC mesh timer 0 usage

Hi I am using the RBC mesh "github.com/.../nRF51-ble-bcast-mesh", sd_110_7.1 and sdk_6.2

The rbc mesh is using timer0 as well as the softdevice. I removed the app timers from my project so it compiles and works but there is a problem.

It craches after some time due to timer0 beeing protected by the MPU and write reqests beeing sent from the rbc mesh to timer0 peripheral which results in hardfaults.

What can I do to fix this? Also problem occures when writing to PPI but this can be fixed by running ppi accesses through the sd_ppi api.

For example my code halts here (timer_control.c):

void timer_abort(uint8_t timer_index){
if (timer_index < 4)
{
    [HERE] NRF_TIMER0->INTENCLR = (1 << (TIMER_INTENCLR_COMPARE0_Pos + timer_index));
    active_callbacks &= ~(1 << timer_index);   
    NRF_PPI->CHENCLR = (1 << (TIMER_PPI_CH_START + timer_index));
    never_used_bitmap |= (1 << timer_index);
}}

And NRF_MPU->PERR0= 0xc300f903

Parents
  • Hi,

    This is caused by the function being called outside of the RBC mesh timeslot granted by the Softdevice Timeslot API, and is probably the result of a race condition in the framework.

    I am unable to reproduce the crash on my setup, are you able to produce a stack trace of the crash?

    Assuming it happens in the SWI0_IRQHandler() context, this can (assumably) be fixed by avoiding calling the end_timer_handler() callback while an async_evt is being processed in SWI0. This could be solved by three minor changes in timeslot_handler.c:

    • Change both calls to

    timer_order_cb_sync_exec(g_timeslot_length - TIMESLOT_END_SAFETY_MARGIN_US, end_timer_handler);

    in timeslot_handler.c to

    timer_order_cb(g_timeslot_length - TIMESLOT_END_SAFETY_MARGIN_US, end_timer_handler);

    (notice the removed sync_exec from the function name). This will put the end_timer_handler in the async_evt queue, instead of interrupting any ongoing async events.

    timeslot_handler.c, L290:

     static bool g_end_timer_triggered = false;
     /**
     * @brief Timeslot end guard timer callback. Attempts to extend the timeslot. 
     */
     static void end_timer_handler(void)
     {
        g_end_timer_triggered = true;
    
        /* Fake a radio IRQ, making the SD call radio_signal_callback(), letting us end timeslot */
        NVIC_SetPendingIRQ(RADIO_IRQn);
     }`
    
    • Finally, put the following 10 lines right after the large switch-case in radio_signal_callback():

    _

    if (g_end_timer_triggered)
    {
        uint32_t length_us = ((g_timeslot_length > 100000)? 100000 : g_timeslot_length);
        radio_request_earliest.params.earliest.length_us = length_us;
        g_ret_param.callback_action = NRF_RADIO_SIGNAL_CALLBACK_ACTION_REQUEST_AND_END;
        g_ret_param.params.request.p_next = &radio_request_earliest;
        
        g_next_timeslot_length = length_us;
        
        g_end_timer_triggered = false;
    }
    

    This is a dirty hotfix, and lacks some proper verification before it should be considered completely safe, but it does not introduce any immediate new errors on my setup. Does this solve your issue (preferrably without introducing new ones)?

    If you could post this issue to the project's issue tracker on GitHub, I'll see if I can provide a cleaner fix in the next patch, as it appears to be a bug in the framework.

Reply
  • Hi,

    This is caused by the function being called outside of the RBC mesh timeslot granted by the Softdevice Timeslot API, and is probably the result of a race condition in the framework.

    I am unable to reproduce the crash on my setup, are you able to produce a stack trace of the crash?

    Assuming it happens in the SWI0_IRQHandler() context, this can (assumably) be fixed by avoiding calling the end_timer_handler() callback while an async_evt is being processed in SWI0. This could be solved by three minor changes in timeslot_handler.c:

    • Change both calls to

    timer_order_cb_sync_exec(g_timeslot_length - TIMESLOT_END_SAFETY_MARGIN_US, end_timer_handler);

    in timeslot_handler.c to

    timer_order_cb(g_timeslot_length - TIMESLOT_END_SAFETY_MARGIN_US, end_timer_handler);

    (notice the removed sync_exec from the function name). This will put the end_timer_handler in the async_evt queue, instead of interrupting any ongoing async events.

    timeslot_handler.c, L290:

     static bool g_end_timer_triggered = false;
     /**
     * @brief Timeslot end guard timer callback. Attempts to extend the timeslot. 
     */
     static void end_timer_handler(void)
     {
        g_end_timer_triggered = true;
    
        /* Fake a radio IRQ, making the SD call radio_signal_callback(), letting us end timeslot */
        NVIC_SetPendingIRQ(RADIO_IRQn);
     }`
    
    • Finally, put the following 10 lines right after the large switch-case in radio_signal_callback():

    _

    if (g_end_timer_triggered)
    {
        uint32_t length_us = ((g_timeslot_length > 100000)? 100000 : g_timeslot_length);
        radio_request_earliest.params.earliest.length_us = length_us;
        g_ret_param.callback_action = NRF_RADIO_SIGNAL_CALLBACK_ACTION_REQUEST_AND_END;
        g_ret_param.params.request.p_next = &radio_request_earliest;
        
        g_next_timeslot_length = length_us;
        
        g_end_timer_triggered = false;
    }
    

    This is a dirty hotfix, and lacks some proper verification before it should be considered completely safe, but it does not introduce any immediate new errors on my setup. Does this solve your issue (preferrably without introducing new ones)?

    If you could post this issue to the project's issue tracker on GitHub, I'll see if I can provide a cleaner fix in the next patch, as it appears to be a bug in the framework.

Children
Related