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

Timer handler not called

I know this was asked before, but none of the posts address my problem. There is a similar thread , but the issue on that one was that the softdevice was not being used. I'm using S210 softdevice and trying to make a current efficient delay using a timer, but my handler is never called:

// do nothing

static void delay(void * p_context)

{

// do nothing

}


 app_timer_id_t module_init(void)

{

	
    // Initialize and start a single shot timer, which is used as a delay

    APP_TIMER_INIT(RTC_PRESCALER, 1u, 1u, false);
    app_timer_id_t timer_id;
    uint32_t err_code = app_timer_create(&timer_id, APP_TIMER_MODE_SINGLE_SHOT, delay);
    APP_ERROR_CHECK(err_code);

	
	return (timer_id);
}

	

app_timer_id_t timer_id;
	
{
.
.
.

   timer_id = module_init(); 

   uint32_t err_code = app_timer_start(timer_id, 50u, NULL);  

   app_timer_stop(timer_id);
	
.
.
.
.
}
  • When you stop an app_timer it does not cause the handler function to execute. You need to let the timer expire. How long do you want your delay to be? What is the value of your APP_TIMER_PRESCALER?

    Your handler does nothing so I'm not sure how you are testing whether execution reaches the handler or now. Most compiler would either not allow breakpoints within a blank function, or simply compiler of the function all together.

  • What do you expect that code to do?

    You start a timer, then you instantly stop it again. Or have you left out some code from the real project?

    Did you think that app_timer_start() is a blocking call which only returns when the timer fires, because it's not, it instantly returns and continues running the code and the timer firing happens in an interrupt handler entirely asynchronously, calling your handler at that point.

    If you are trying to delay you want something more like this (untested)

    static void *delay( void *p_context )
    {
        *((bool*)p_context)=true;
    }
    
    {
        ...
    
        bool has_fired = false;
        uint32_t err_code = app_timer_start( timer_id, (void*)(&has_fired);
        while( !has_fired)
            __wfe();
        ...
    }
    

    So the delay() routine sets the flag that the timer has finished and any interrupt or event in the system (including the timer IRQ) will wake up the __wfe() call to check it. After the timer successfully fires you'll drop out of the while loop and continue.

    PS As a matter of good practice I suggest wrapping any call which can produce an error in APP_ERROR_CHECK() or similar, at least in a debug build. It's saved me hours of debugging time because it instantly dumps you in the error handler and you can figure out what call you made failed, and why.

  • Thank you! Yes, you are correct that there is more code between the start and stop of the timer. It is actually inside a loop which is reading SPI at regular intervals. I used NOPS to test my app and the timer now for reducing current. I meant to leave that (stop timer call) out.

    You are also correct that I thought that it was a blocking call. It now makes a little more sense. The timer app does not seem very well documented. I tried toggling LED's inside my delay() routine, but even when I started the timer, the LED's never toggled and in the program never hit a breakpoint inside the delay routine in debug. It never got executed, and not sure why. Now that I know that it runs asynchronously I will try it with your suggestion above. Should I worry about a race condition and use sd_app_evt_wait()? Thanks for the recommendation about using APP_ERROR_CHECK(). Great advice!

Related