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

How to implement a simple non-blocking delay on nRF51822 with SoftDevice

Using nrf_delay_ms() can be energy consuming and indeterministic. I am trying to use application timers (from "app_timer.h") in nRF SDK 8.0. The way I did could be partially described as follows:

#define LED_DURATION_IN_MS    400   
#define LED_DURATION_TICKS      APP_TIMER_TICKS(LED_DURATION_IN_MS, APP_TIMER_PRESCALER)

static app_timer_id_t m_lazy_wait_timer;
static volatile uint8_t lazy_wait_flag = 0;

static void power_manage(void)
{
    uint32_t err_code = sd_app_evt_wait();
    APP_ERROR_CHECK(err_code);
}

void lazy_wait_handler(void * p_context)
{ 
	// Clear the wait flag 
	lazy_wait_flag = 0;
}

static void timers_init(void)
{
  APP_TIMER_APPSH_INIT(APP_TIMER_PRESCALER, APP_TIMER_MAX_TIMERS, APP_TIMER_OP_QUEUE_SIZE, true);
  err_code = app_timer_create(&m_lazy_wait_timer, APP_TIMER_MODE_SINGLE_SHOT, lazy_wait_handler);
  APP_ERROR_CHECK(err_code);
}
	
void main()
{
    ...
    ...

    timers_init();
    nrf_gpio_cfg_output(1);
    nrf_gpio_pin_set(1);
    uint32_t err_code = app_timer_start(m_lazy_wait_timer, LED_DURATION_TICKS, NULL);
    APP_ERROR_CHECK(err_code);
    lazy_wait_flag = 1;
    while(lazy_wait_flag) {
        power_manage();
    }
    nrf_gpio_pin_clear(1);

    for (;;)
    {
        app_sched_execute();
        power_manage();
    }
}

However, the code doesn't work as expected. It seems the "lazy_wait_flag" is not cleared and the code is stuck in the while loop. What is the correct way of doing it?

  • Do you start an LF clock source somewhere in the elided code? Have you put a breakpoint into the timer routine to check and see if it's being called or not to determine whether your timer code is wrong or your waiting code is wrong?

  • If you mean something like "SOFTDEVICE_HANDLER_INIT(NRF_CLOCK_LFCLKSRC_RC_250_PPM_TEMP_4000MS_CALIBRATION, false);", I did it when initialization BLE stack. I also had other app timers in this code (which I didn't show above), and they were all working okay. I set a breakpoint in lazy_wait_handler(), and it was not reached. So I assumed for some reason ISR was not called and the lazy_wait_flag was not cleared properly.

  • Hello. Your last parameter in APP_TIMER_APPSH_INIT is "True", which means that you intend to use the scheduler. However, the scheduler is not run in your while loop. Try setting the last parameter to "False", or run app_sched_execute() in the while loop.

    Edit: About using the app_scheduler:

    The main reason to use this module, is to execute some procedure from main context (low priority) instead of the interrupt context (higher priority). If your procedure is short and have real time timing requirements, you should execute it directly in the interrupt handler and not use the scheduler. If your procedure takes some time, and timing is not critical, the scheduler is a good way to ensure that you procedure does not interfere with more important tasks.

    The documentation of the app_scheduler can be found here.

  • @Anders Thanks for your suggestions. Changing the app scheduling to "false" works. For the second option, it only works when I call app_sched_execute() after power_manage() in the while loop containing "lazy_wait_flag". It doesn't work if app_sched_execute() is called before power_manage(). Why is that? Also, what are the pros and cons of disabling scheduling of app timers? I have some app timers and also app buttons which use app timers elsewhere in the code. I just wonder how they will affect the deterministicity of the delay.

  • If the LED being set indicates success, i believe your code behaves exactly how it should be :) If you call app_sched_execute() before power_manage(), this happens: power_manage()->Timer event->app_sched_execute->lazy_wait_handler->power_manage(). It never escaped the while loop, it will sleep forever inside power manage. If you call it after: power_manage()->Timer event->app_sched_execute->lazy_wait_handler->While loop checking flag ->escape while loop. See the scheduler docs for some more info.

Related