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

Atomic variable access (locking)

Hi All,

I'm implementing system clock using approach similar to devzone.nordicsemi.com/.../

The idea:

NRF_RTC_EVENT_COMPARE_0 -> PPI -> NRF_TIMER_TASK_COUNT
(translate 125ms RTC ticks to counter mode TIMER 1sec ticks)

All works great, however handling UNIX timestamps require handling "overflows" to update global counter, because TIMER1...4 instances are 16bit max. (I'm using SoftDevice so TIMER0 is not available)

Handler for 8bit TIMER looks like this:

   static void hwtimer_handler(nrf_timer_event_t event_type, void* p_context)
    {
        if (p_context == &m_hwtimer && event_type == NRF_TIMER_EVENT_COMPARE1)
          m_epoch_time += 0x100UL;
    }

And "real time" getter:

uint32_t cval = nrf_drv_timer_capture(&m_hwtimer, NRF_TIMER_CC_CHANNEL0);
    nrf_drv_timer_clear(&m_hwtimer);
    nrf_drv_timer_compare_int_disable(&m_hwtimer, NRF_TIMER_CC_CHANNEL1); // write access to m_epoch_time must be atomic
    m_epoch_time += cval;
    nrf_drv_timer_compare_int_enable(&m_hwtimer, NRF_TIMER_CC_CHANNEL1); // write access to m_epoch_time must be atomic
    return m_epoch_time;

To prevent race conditions when modifying m_epoch_time I just disabling interrupts. Is it optimal approach? Are race interrupts pended of declined? It's important to know because each interrupt decline equals to +1 second lost in system clock. Maybe better to temporarily disable events passing via PPI ? Which way is more safe?

PS: ARM arch is new for me, so please tell me if my question is ARM generic rather than NRF specific.

Best, Alex

  • Hi Alex,

    You are disabling interrupt at the timer peripheral level so if there should have been any interrupt in these race period then it will be lost because the peripheral will not produce and hence cannot pend it.

    In your case it will be better if you can disable it at NVIC level, because NVIC have pend bits then the incoming interrupt will be pended instead of being lost. So when you enable it, and if there was timer interrupt from peripheral in the mean time that caused a pendbit then it will be serviced and not lost.

    Proposed solution is to do below, assuming that this is not ISR

    NVIC_DisableIRQ(time_you_are_using_IRQn);
    m_epoch_time += cval;
    NVIC_EnableIRQ(time_you_are_using_IRQn);
    
Related