From 73dbda99ac72493eb26b5c78962ea0200e70487f Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Thu, 11 Mar 2021 22:30:27 +0100 Subject: [PATCH 1/4] cpu/sam0_common: add rtc_get_tamper() Add a function to query which tamper event woke the CPU from hibernation. --- cpu/sam0_common/include/periph_cpu_common.h | 9 +++++++++ cpu/sam0_common/periph/rtc_rtt.c | 10 ++++++++++ 2 files changed, 19 insertions(+) diff --git a/cpu/sam0_common/include/periph_cpu_common.h b/cpu/sam0_common/include/periph_cpu_common.h index 4172c859df..9953d8aad6 100644 --- a/cpu/sam0_common/include/periph_cpu_common.h +++ b/cpu/sam0_common/include/periph_cpu_common.h @@ -1144,6 +1144,15 @@ int rtc_tamper_register(gpio_t pin, gpio_flank_t flank); * @brief Enable Tamper Detection IRQs */ void rtc_tamper_enable(void); + +/** + * @brief Get and clear the RTC tamper event that has woken the CPU + * from Deep Sleep. + * + * @return The set bits in the return value correspond to the tamper + * pin index inside the @ref rtc_tamper_pins array. + */ +uint8_t rtc_get_tamper_event(void); /** @} */ /** diff --git a/cpu/sam0_common/periph/rtc_rtt.c b/cpu/sam0_common/periph/rtc_rtt.c index bbd2541051..7901aeaeec 100644 --- a/cpu/sam0_common/periph/rtc_rtt.c +++ b/cpu/sam0_common/periph/rtc_rtt.c @@ -374,6 +374,16 @@ void rtc_tamper_enable(void) DEBUG("tamper enabled\n"); } +uint8_t rtc_get_tamper_event(void) +{ + uint32_t ret = RTC->MODE0.TAMPID.reg; + + /* clear tamper event */ + RTC->MODE0.INTFLAG.reg = RTC_MODE0_INTFLAG_TAMPER; + RTC->MODE0.TAMPID.reg = ret; + + return ret & RTC_TAMPID_TAMPID_Msk; +} #endif /* RTC_NUM_OF_TAMPERS */ void rtt_set_overflow_cb(rtt_cb_t cb, void *arg) From 55c95cd8fd90f49532ebdc8ac46d090655a5ef25 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Thu, 11 Mar 2021 22:31:32 +0100 Subject: [PATCH 2/4] tests/periph_gpio: display tamper wake event --- tests/periph_gpio/main.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/periph_gpio/main.c b/tests/periph_gpio/main.c index 1e9223c2a5..8011f45dc1 100644 --- a/tests/periph_gpio/main.c +++ b/tests/periph_gpio/main.c @@ -429,6 +429,13 @@ int main(void) "NOTE: make sure the values you use exist on your platform! The\n" " behavior for not existing ports/pins is not defined!"); +#if IS_ACTIVE(MODULE_PERIPH_GPIO_TAMPER_WAKE) + uint8_t tamper = rtc_get_tamper_event(); + if (tamper) { + printf("\nWoken by RTC tamper event: %x\n", tamper); + } +#endif + /* start the shell */ char line_buf[SHELL_DEFAULT_BUFSIZE]; shell_run(shell_commands, line_buf, SHELL_DEFAULT_BUFSIZE); From 9d482c4448b94b57591f9e46e921b1b64dbac2ab Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Sun, 14 Mar 2021 19:31:39 +0100 Subject: [PATCH 3/4] cpu/sam0_common: RTC: only write TAMPCTRL when tamper is enabled If we configure TAMPCTRL early, GPIO events will set bits in the TAMPCTRL register. That means that after a wake-up, we can't tell if the bit was set because it was the wake-up source or if it was already set by a run-time GPIO event. --- cpu/sam0_common/periph/rtc_rtt.c | 50 +++++++++++++++++++------------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/cpu/sam0_common/periph/rtc_rtt.c b/cpu/sam0_common/periph/rtc_rtt.c index 7901aeaeec..54c16ec734 100644 --- a/cpu/sam0_common/periph/rtc_rtt.c +++ b/cpu/sam0_common/periph/rtc_rtt.c @@ -281,6 +281,7 @@ void rtt_init(void) #if RTC_NUM_OF_TAMPERS static rtc_state_t tamper_cb; +static uint32_t tampctr; /* check if pin is a RTC tamper pin */ static int _rtc_pin(gpio_t pin) @@ -294,20 +295,32 @@ static int _rtc_pin(gpio_t pin) return -1; } +static void _set_tampctrl(uint32_t reg) +{ + _rtc_set_enabled(0); + RTC->MODE0.TAMPCTRL.reg = reg; + _rtc_set_enabled(1); +} + void rtc_tamper_init(void) { - if (IS_ACTIVE(MODULE_PERIPH_RTC) || - IS_ACTIVE(MODULE_PERIPH_RTT) || - _power_is_on()) { - return; + DEBUG("tamper init\n"); + + /* configure RTC clock only if it is not already configured */ + if (!IS_ACTIVE(MODULE_PERIPH_RTC) && + !IS_ACTIVE(MODULE_PERIPH_RTT)) { + + if (!_power_is_on()) { + _rtt_clock_setup(); + _poweron(); + } + + /* disable all interrupt sources */ + RTC->MODE0.INTENCLR.reg = RTC_MODE0_INTENCLR_MASK; } - _rtt_clock_setup(); - _poweron(); - - /* disable all interrupt sources */ - RTC->MODE0.INTENCLR.reg = RTC_MODE0_INTENCLR_MASK; - + /* disable old tamper events */ + _set_tampctrl(0); NVIC_EnableIRQ(RTC_IRQn); } @@ -319,20 +332,14 @@ int rtc_tamper_register(gpio_t pin, gpio_flank_t flank) return -1; } - /* TAMPCTRL is enable-protected */ - _rtc_set_enabled(0); - - RTC->MODE0.TAMPCTRL.reg |= RTC_TAMPCTRL_IN0ACT_WAKE << (2 * in); + tampctr |= RTC_TAMPCTRL_IN0ACT_WAKE << (2 * in); if (flank == GPIO_RISING) { - RTC->MODE0.TAMPCTRL.reg |= RTC_TAMPCTRL_TAMLVL0 << in; + tampctr |= RTC_TAMPCTRL_TAMLVL0 << in; } else if (flank == GPIO_FALLING) { - RTC->MODE0.TAMPCTRL.reg &= ~(RTC_TAMPCTRL_TAMLVL0 << in); + tampctr &= ~(RTC_TAMPCTRL_TAMLVL0 << in); } - /* enable the RTC again */ - _rtc_set_enabled(1); - return 0; } @@ -341,7 +348,10 @@ void rtc_tamper_enable(void) DEBUG("enable tamper\n"); /* clear tamper id */ - RTC->MODE0.TAMPID.reg = 0xF; + RTC->MODE0.TAMPID.reg = 0x1F; + + /* write TAMPCTRL register */ + _set_tampctrl(tampctr); /* work around errata 2.17.4: * ignore the first tamper event on the rising edge */ From 13fbb7c1a07562ebfd25391afff2607eeade9596 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Tue, 16 Mar 2021 11:50:05 +0100 Subject: [PATCH 4/4] cpu/sam0_common: add rtc_tamper_pin_mask() --- cpu/sam0_common/include/periph_cpu_common.h | 12 ++++++++++++ cpu/sam0_common/periph/rtc_rtt.c | 10 ++++++++++ 2 files changed, 22 insertions(+) diff --git a/cpu/sam0_common/include/periph_cpu_common.h b/cpu/sam0_common/include/periph_cpu_common.h index 9953d8aad6..39bd90840d 100644 --- a/cpu/sam0_common/include/periph_cpu_common.h +++ b/cpu/sam0_common/include/periph_cpu_common.h @@ -1153,6 +1153,18 @@ void rtc_tamper_enable(void); * pin index inside the @ref rtc_tamper_pins array. */ uint8_t rtc_get_tamper_event(void); + +/** + * @brief Get the tamper event mask for a certain pin. + * Can be used together with @ref rtc_get_tamper_event to + * check which RTC pin caused the tamper event. + * + * @param pin Pin to query + * + * @return Bit mask with the bit corresponding to @p pin set + * 0 if @p pin is no RTC tamper pin + */ +uint8_t rtc_tamper_pin_mask(gpio_t pin); /** @} */ /** diff --git a/cpu/sam0_common/periph/rtc_rtt.c b/cpu/sam0_common/periph/rtc_rtt.c index 54c16ec734..407314c18c 100644 --- a/cpu/sam0_common/periph/rtc_rtt.c +++ b/cpu/sam0_common/periph/rtc_rtt.c @@ -394,6 +394,16 @@ uint8_t rtc_get_tamper_event(void) return ret & RTC_TAMPID_TAMPID_Msk; } + +uint8_t rtc_tamper_pin_mask(gpio_t pin) +{ + int idx = _rtc_pin(pin); + if (idx < 0) { + return 0; + } + + return 1 << idx; +} #endif /* RTC_NUM_OF_TAMPERS */ void rtt_set_overflow_cb(rtt_cb_t cb, void *arg)