Nordic: handle unwanted RTC interrupts

This patch clears the EVENT_COMPARE register even when we're not
expecting to get a COMPARE interrupt.

Here is a scenario where we get an unwelcome interrupt, and where it
currently results in a deadlock:

* A Ticker T1 runs at 500ms
* Its handler registers a Timeout T2 at 20µs. Since LF clock runs at
  32.768kHz, this will be rounded up to a multiple of 30.5µs (actually
  61µs, to ensure we're in the next tick window)

           T1  T2                                T1' T2'
    -------|---|---------------------------------|---|--------->
           :   :                                 :
           <---> n * 30.5µs                      :
           <--------------- 500ms --------------->

* When the ticker API handles T1, it calls us_ticker_set_interrupt a
  first time for T1', and then for registering T2.
* Since T2 period is less than one RTC tick (30.5µs), there is a high
  chance it will go past *while* we're still in this first handler.
* So ticker_irq_handler also handles T2 as well, and removes it from the
  queue.
* us_ticker_set_interrupt is called for T1' before returning from
  ticker_irq_handler

The problem resides in the fact that us_ticker_set_interrupt takes more
than 2 RTC ticks to execute: while inside the handler, T2 interrupt will
fire.

* Because of this pending interrupt, RTC1_IRQHandler will be called
  right away, but since we removed T2 from the queue, the handler is
  waiting for T1' instead, and will not clear EVENT_COMPARE until we
  reach the T1' tick, in about 500ms.
* This results in a lock and main isn't executed anymore.

With this patch, we avoid being stuck in RTC1_IRQHandler while waiting
for T1'.

Note: even when T2 isn't handled in the same loop as T1, we may get a
spurious interrupt, because us_ticker_set_interrupt will be called twice
for T2... and will register T2+m the second time, while T2 interrupt is
fired in the background.
That case isn't as harmful, since RTC1_IRQHandler will be waiting for
T2+m, which is only one or two ticks further, and then it won't be
called again before T1'.

Signed-off-by: Jean-Philippe Brucker <jean-philippe.brucker@arm.com>
pull/1281/head
Jean-Philippe Brucker 2015-08-05 09:46:49 +01:00
parent 24cc331f12
commit 1c90449f35
1 changed files with 3 additions and 2 deletions

View File

@ -159,10 +159,11 @@ void RTC1_IRQHandler(void)
NRF_RTC1->EVENTS_OVRFLW = 0;
NRF_RTC1->EVTENCLR = RTC_EVTEN_OVRFLW_Msk;
}
if (NRF_RTC1->EVENTS_COMPARE[0] && us_ticker_callbackPending && ((int)(us_ticker_callbackTimestamp - rtc1_getCounter()) <= 0)) {
if (NRF_RTC1->EVENTS_COMPARE[0]) {
NRF_RTC1->EVENTS_COMPARE[0] = 0;
NRF_RTC1->EVTENCLR = RTC_EVTEN_COMPARE0_Msk;
invokeCallback();
if (us_ticker_callbackPending && ((int)(us_ticker_callbackTimestamp - rtc1_getCounter()) <= 0))
invokeCallback();
}
}