From 1c90449f35512182e893dc60c1a6c028acc048b6 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Brucker Date: Wed, 5 Aug 2015 09:46:49 +0100 Subject: [PATCH] Nordic: handle unwanted RTC interrupts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- .../hal/TARGET_NORDIC/TARGET_MCU_NRF51822/us_ticker.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/mbed/targets/hal/TARGET_NORDIC/TARGET_MCU_NRF51822/us_ticker.c b/libraries/mbed/targets/hal/TARGET_NORDIC/TARGET_MCU_NRF51822/us_ticker.c index 68fb545015..78f966ab7f 100644 --- a/libraries/mbed/targets/hal/TARGET_NORDIC/TARGET_MCU_NRF51822/us_ticker.c +++ b/libraries/mbed/targets/hal/TARGET_NORDIC/TARGET_MCU_NRF51822/us_ticker.c @@ -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(); } }