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

app_timer_start in radio notification event handler

I have tried to create delay_timer function using app_uart as nrf_delay replacement in order to save power as much as possible in a short delay existed in any part of my code. (similar to this)

APP_TIMER_DEF(m_delay_timer_id);

then call timers_init in the beginning of main code just after ble_stack_init() enabling lfclk.

void timers_init(void)
{
    // Initialize timer module.
    APP_TIMER_INIT(APP_TIMER_PRESCALER, APP_TIMER_OP_QUEUE_SIZE, false);
    enter code here
    // Create timers.
    uint32_t err_code;
    err_code = app_timer_create(&m_meas_timer_id, APP_TIMER_MODE_REPEATED, meas_timer_timeout_handler);
    APP_ERROR_CHECK(err_code);
    err_code = app_timer_create(&m_led_timer_id, APP_TIMER_MODE_REPEATED, led_timer_timeout_handler);
    APP_ERROR_CHECK(err_code);
	err_code = app_timer_create(&m_delay_timer_id, APP_TIMER_MODE_SINGLE_SHOT, delay_timer_timeout_handler);
    APP_ERROR_CHECK(err_code);
}

in timeout handler (timer callback), just simply changing flag state.

void delay_timer_timeout_handler(void * p_context)
{
    delay_flag = false;
}

And, delay_timer() execute the delay in millisecond.

void delay_timer (uint32_t time)
{
    uint32_t err_code;
    delay_flag = true;
    err_code = app_timer_start(m_delay_timer_id, APP_TIMER_TICKS(time, APP_TIMER_PRESCALER), NULL);
    APP_ERROR_CHECK(err_code);
    while (delay_flag)
    {
        err_code = sd_app_evt_wait();
        APP_ERROR_CHECK(err_code);
    }
}

This code is perfectly working if I call delay_timer somewhere in main code.

However, if I called delay_timer() from the radio notification event handler, delay_timer_timeout_handler was never called, and could not exit from while loop since the state of delay_flag was never changed.

// Radio notification initialize.
    err_code = ble_radio_notification_init(NRF_APP_PRIORITY_LOW, NRF_RADIO_NOTIFICATION_DISTANCE_800US, meas_update);
    APP_ERROR_CHECK(err_code);

...

void meas_update(bool radio_active)
{
    if (radio_active) {
    	// Do something
    }
    led_on(PIN_LED_GREEN);
    delay_timer(30);
    led_off(PIN_LED_GREEN);
}

Are there any difference in calling app_timer_start in main code and radio_notification event handler? I need help to solve this issue. Or any good suggestion on how to get the device in low power state while in the short delay (such as 30ms) instead of using nrf_delay?

I am using S110, SDK10 on nrf51822.

Parents
  • This is a problem of interrupt priorities. The radio notification event handler runs with interrupt priority (NRF_APP_PRIORITY_LOW). That means that your application will stay in the loop in your delay_timer() until delay_flag is set to 0 or a higher priority interrupt is run. The timer interrupt will wake up the CPU, but it will continue in the loop in delay_timer().

    In your case, you could fix this issue by making sure that the app timer has a higher priority than the call to delay_timer(). The easiest way to do this would be to handle the radio notification in the application context. You could do that manually or by using the scheduler.

    Alternatively, you can try to set the priority of the RTC1 IRQ to NRF_APP_PRIORITY_HIGH (modify RTC1_IRQ_PRI in components/libraries/timer/app_timer.c). I have not tested myself, but I do not think it will have bad side effects in this case. However, you cannot make any calls to the SoftDevice from the app timer if it has high priority, so it is probably not a good idea.

  • Thank you Einar. Setting another flag in radio notification event, then handling its tasks in the application main context solved this issue.

    The tasks related to radio notification and delay_timer are now working as I expected.

Reply Children
No Data
Related