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

Unable to clear timer event flag

I'm running the Nordic/Thread SDK 3.2 with an NRF52840 (Rigado BMD-340) on SES 4.42.

I've got a project using BLE + Thread and I'm having problems implementing a hardware timer interrupt.  I've cut this down to bare bones to try to understand what I'm doing wrong here, and I'm trying to generate an interrupt every 750mS via Timer2 Compare_Event 0.

I'm modifying the ble_thread_dyn_template example project with the following:

- Add /modules/nrfx/drivers/src/nrfx_timer.c to the nRF_Drivers folder

- Include nrf_drv_timer.h in main.c.

-Modify the sdk_config.h to enable Timer2

If I paste this code into the Timer Peripheral example and call 'hw_timers_init();' from the main loop then it works as expected, I get an interrupt every 750mS.  If I put this in the ble_thread_dyn_template example then I am unable to clear the Timer2 Event flag and the code just lives in the ISR.  

const nrf_drv_timer_t HW_DELAYTIME = NRF_DRV_TIMER_INSTANCE(2); //softdevice uses Timer0, OpenThread uses Timer1

//this is the handler for hardware timer 1 which will be used to control the delay between turning on the IR_LED and then checking the 
void hw_timer_event_handler(nrf_timer_event_t event_type, void* p_context){
ret_code_t err_code;
    volatile uint32_t dummy;
    
    switch (event_type)
    {

        case NRF_TIMER_EVENT_COMPARE0:
               // NRF_LOG_INFO("At hardware timer handler");
                NRF_TIMER2->EVENTS_COMPARE[0] = 0;
                dummy = NRF_TIMER2->EVENTS_COMPARE[0];
                dummy; 
                nrf_gpio_pin_toggle(31);
            break;
    }
}



//function to initialize hardware timers.
static void hw_timers_init(void){

  
    nrf_gpio_cfg_output(31); //IO config shouldn't go in timers init, but pasting here for simple portablility with Timer example
    ret_code_t err_code;
    uint32_t time_ms = 750; //Time(in miliseconds) between timer start and rollover.
    uint32_t time_ticks;

    nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;

    err_code = nrf_drv_timer_init(&HW_DELAYTIME, &timer_cfg, hw_timer_event_handler);
    APP_ERROR_CHECK(err_code);

    time_ticks = nrf_drv_timer_ms_to_ticks(&HW_DELAYTIME, time_ms);
    nrf_drv_timer_extended_compare(
         &HW_DELAYTIME, NRF_TIMER_CC_CHANNEL0, time_ticks,NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, true);
  
 nrf_drv_timer_enable(&HW_DELAYTIME);

}

If anybody has any thoughts on what I'm doing wrong here I would really appreciate it

  • "and the code just lives in the ISR.  "
    What do you mean exactly, that you're stuck in a loop?

    This does look correct:
    NRF_TIMER2->EVENTS_COMPARE[0] = 0;
    dummy = NRF_TIMER2->EVENTS_COMPARE[0];
    dummy;

    Have you tried the HAL's nrf_timer_event_clear


  • Thank you Haakonsh for the response.

    I should have been more specific...The Event flag never clears and so the instant that it leaves the ISR it returns immediately.  If I watch the Timer registers using a debugger, it appears that the flag is never cleared in hardware.

    The nrf_timer_event_clear is being called somewhere behind the scenes (I can set a breakpoint on line 536 of timer.h and see where this is being called) and that line is actually clearing the flag in the hardware peripheral example, but it is not working with my configuration.  I added the lines you reference where I'm manually clearing the flag in the ISR after first discovering this issue.

    For my immediate needs I ended up using an additional APP_TIMER to achieve what I was working towards, but I would very much like to understand what is going on here, just for general future knowledge.  

    I was curious if this issue was related to the SoftDevice or OpenThread utilizing timers 0 and 1, so I tried pasting the code above into the perisperhal-only led_softblink example project and I have the same issue.  For the softblink test, I had to copy in the timer sections (nrf and nrfx) to sdk_config.h

    If you have any thoughts or would like any further information please let me know.  

  • rogerarchibald said:
    The nrf_timer_event_clear is being called somewhere behind the scenes

    Aah, yes, that's true. The TIMER ISR should clear that flag before or after calling the event handler. You will not need to clear the event in the event handler. 

    Even if the event is not cleared, for whatever reason, the event handler won't be called until another TIMER IRQ has been triggered. 

    Do note that at 750ms intervals you will appear to always be stuck in your event handler if you set a break-point in it due to pending interrupts. Try using a longer timer timeout, like 10 seconds. 

  • I realize that breakpoints in the ISR aren't helpful when it comes to measuring time...I was just using them to verify whether or not the flag was being cleared.

    My main indication that I'm not getting beyond the ISR is the line where I'm toggling pin 31 every time I enter the ISR.  With a 750mS rollover I should clearly see the transitions of pin 31 (and I do when I paste this code into the hardware timer example) but when I run this code in a project where I've added the timer files the voltage on pin 31 appears fixed at VDD/2 when viewed on a Fluke meter, telling me it's switching relatively quickly.  I haven't put a scope on it to see the transition speed, but seeing VDD/2 coupled with the fact that my later initialization code isn't running and I'm unable to clear the event flag makes me pretty confident that I'm hanging up here.  

    Again, if I copy that exact same code into an example that's configured for the hardware timer then it works as expected.  For that reason, I assume that my problem has something to do with how I'm configuring the project, although I can't imagine what step I am missing.

  • If you were stuck in the event handler you would not be able to call the event handler again as they are executing at the same priority.  

    rogerarchibald said:
    With a 750mS rollover I should clearly see the transitions of pin 31 (and I do when I paste this code into the hardware timer example) but when I run this code in a project where I've added the timer files the voltage on pin 31 appears fixed at VDD/2 when viewed on a Fluke meter, telling me it's switching relatively quickly.

    This proves that you are in fact executing the event handler with a fixed period, most likely of 750ms, so you're probably not stuck there. 
    What is the sample rate of the Fluke multimeter? Does it have any averaging filter running, and if so, what's the width in samples?

    I suggest you increase the timer period to at least 60 seconds, put a breakpoint at the end of your event handler, and see to what function you return to after the event handler and or ISR has finished. 

Related