From 3a7aa5d09a7a1df3fe51f695c7c0a6e1830234f8 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Fri, 4 Dec 2020 00:02:00 +0100 Subject: [PATCH] cpu/sam0_common: RTC: add timeout to spurious tamper event Errate 2.17.4 says: > Upon enabling the RTC tamper detection feature, a false tamper > detection *can* be reported by the RTC. It turns out that this spurious event is not always generated. If RTC alarm is used and the CPU was previously woken from hibernate by RTC, it *can* happen that the false tamper event is *not* generated. In this case, we will block indefinitely on the mutex. To solve this, add a timeout to the event. Also poll the event instead of using a mutex, as we have already set `PM->SLEEPCFG.bit.SLEEPMODE` at this point. --- cpu/sam0_common/periph/rtc_rtt.c | 40 ++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/cpu/sam0_common/periph/rtc_rtt.c b/cpu/sam0_common/periph/rtc_rtt.c index 70237f08fe..bbd2541051 100644 --- a/cpu/sam0_common/periph/rtc_rtt.c +++ b/cpu/sam0_common/periph/rtc_rtt.c @@ -25,7 +25,6 @@ */ #include -#include "mutex.h" #include "periph/rtc.h" #include "periph/rtt.h" #include "periph_conf.h" @@ -337,14 +336,9 @@ int rtc_tamper_register(gpio_t pin, gpio_flank_t flank) return 0; } -static void _unlock(void *m) -{ - mutex_unlock(m); -} - void rtc_tamper_enable(void) { - mutex_t m = MUTEX_INIT; + DEBUG("enable tamper\n"); /* clear tamper id */ RTC->MODE0.TAMPID.reg = 0xF; @@ -352,16 +346,32 @@ void rtc_tamper_enable(void) /* work around errata 2.17.4: * ignore the first tamper event on the rising edge */ if (RTC->MODE0.TAMPCTRL.reg & RTC_TAMPCTRL_TAMLVL_Msk) { - mutex_lock(&m); - tamper_cb.cb = _unlock; - tamper_cb.arg = &m; + + /* If an RTC alarm happened before, the spurious tamper + * event is sometimes not generated. + * Tamper event must happen within one RTC clock period. */ + unsigned timeout = CLOCK_CORECLOCK / 32768; + + /* prevent RTC interrupt from triggering */ + NVIC_DisableIRQ(RTC_IRQn); + + /* enable tamper detect as wake-up source */ + RTC->MODE0.INTENSET.bit.TAMPER = 1; + + /* wait for first tamper event */ + while (!RTC->MODE0.INTFLAG.bit.TAMPER && --timeout) {} + + /* clear tamper flag flag */ + RTC->MODE0.INTFLAG.reg = RTC_MODE0_INTFLAG_TAMPER; + + /* restore RTC IRQ */ + NVIC_EnableIRQ(RTC_IRQn); + } else { + /* no spurious event on falling edge */ + RTC->MODE0.INTENSET.bit.TAMPER = 1; } - /* enable tamper detect as wake-up source */ - RTC->MODE0.INTENSET.bit.TAMPER = 1; - - /* wait for first tamper event */ - mutex_lock(&m); + DEBUG("tamper enabled\n"); } #endif /* RTC_NUM_OF_TAMPERS */