From 310eb4970ccba0853da0e577faa2d560c6a1a7ff Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Wed, 6 May 2020 00:11:29 +0200 Subject: [PATCH] cpu/sam0_common: GPIO: use tamper detection to wake from Deep Sleep On samd5x only the RTC can wake the CPU from Deep Sleep (pm modes 0 & 1). The external interrupt controller is disabled, but we can use the tamper detection of the RTC. If an gpio interrupt is configured on one of the five tamper detect pins, those can be used to wake the CPU from Deep Sleep / Hibernate. --- cpu/sam0_common/periph/gpio.c | 47 ++++++++++++++++++++++++++++++++- cpu/samd5x/Kconfig | 1 + cpu/samd5x/Makefile.dep | 4 +++ cpu/samd5x/Makefile.features | 1 + cpu/samd5x/include/periph_cpu.h | 9 +++++++ cpu/saml1x/include/periph_cpu.h | 9 +++++++ drivers/periph_common/init.c | 7 +++++ kconfigs/Kconfig.features | 6 +++++ 8 files changed, 83 insertions(+), 1 deletion(-) diff --git a/cpu/sam0_common/periph/gpio.c b/cpu/sam0_common/periph/gpio.c index a61146a3bb..d649964865 100644 --- a/cpu/sam0_common/periph/gpio.c +++ b/cpu/sam0_common/periph/gpio.c @@ -16,6 +16,15 @@ * @file gpio.c * @brief Low-level GPIO driver implementation * + * On processors that support Deep Sleep the External Interrupt Controller + * will be off during Deep Sleep. + * To wake the CPU up from Deep Sleep the RTC Tamper Detection will be + * used instead. + * Only a few pins (@ref rtc_tamper_pins) can be used for that purpose. + * + * Note that when configuring those pins as interrupt, the RTC/RTT will be + * stopped briefly as the RTC configuration is enable protected. + * * @author Troels Hoffmeyer * @author Thomas Eichinger * @author Kaspar Schleiser @@ -240,11 +249,41 @@ static int _exti(gpio_t pin) return exti_config[port_num][_pin_pos(pin)]; } +/* check if an RTC tamper pin was configured as interrupt */ +__attribute__ ((unused)) +static bool _rtc_irq_enabled(void) +{ +#if MODULE_PERIPH_GPIO_TAMPER_WAKE + for (unsigned i = 0; i < ARRAY_SIZE(rtc_tamper_pins); ++i) { + int exti = _exti(rtc_tamper_pins[i]); + + if (exti == -1) { + continue; + } + + if (_EIC->INTENSET.reg & (1 << exti)) { + return true; + } + } +#endif + return false; +} + +static void _init_rtc_pin(gpio_t pin, gpio_flank_t flank) +{ + if (IS_ACTIVE(MODULE_PERIPH_GPIO_TAMPER_WAKE)) { + rtc_tamper_register(pin, flank); + } +} + int gpio_init_int(gpio_t pin, gpio_mode_t mode, gpio_flank_t flank, gpio_cb_t cb, void *arg) { int exti = _exti(pin); + /* if it's a tamper pin configure wake from Deep Sleep */ + _init_rtc_pin(pin, flank); + /* make sure EIC channel is valid */ if (exti == -1) { return -1; @@ -330,11 +369,17 @@ void gpio_pm_cb_enter(int deep) { #if defined(PM_SLEEPCFG_SLEEPMODE_STANDBY) (void) deep; + unsigned mode = PM->SLEEPCFG.bit.SLEEPMODE; - if (PM->SLEEPCFG.bit.SLEEPMODE == PM_SLEEPCFG_SLEEPMODE_STANDBY) { + if (mode == PM_SLEEPCFG_SLEEPMODE_STANDBY) { DEBUG_PUTS("gpio: switching EIC to slow clock"); reenable_eic(_EIC_CLOCK_SLOW); } + else if (IS_ACTIVE(MODULE_PERIPH_GPIO_TAMPER_WAKE) + && mode > PM_SLEEPCFG_SLEEPMODE_STANDBY + && _rtc_irq_enabled()) { + rtc_tamper_enable(); + } #else if (deep) { DEBUG_PUTS("gpio: switching EIC to slow clock"); diff --git a/cpu/samd5x/Kconfig b/cpu/samd5x/Kconfig index 786ad65c99..bf9005ef5a 100644 --- a/cpu/samd5x/Kconfig +++ b/cpu/samd5x/Kconfig @@ -12,6 +12,7 @@ config CPU_COMMON_SAMD5X select HAS_BACKUP_RAM select HAS_CORTEXM_MPU select HAS_CPU_SAMD5X + select HAS_PERIPH_GPIO_TAMPER_WAKE select HAS_PERIPH_HWRNG config CPU_FAM_SAMD51 diff --git a/cpu/samd5x/Makefile.dep b/cpu/samd5x/Makefile.dep index eccd575bc9..a51a8aa278 100644 --- a/cpu/samd5x/Makefile.dep +++ b/cpu/samd5x/Makefile.dep @@ -1 +1,5 @@ +ifneq (,$(filter periph_gpio_tamper_wake,$(USEMODULE))) + USEMODULE += periph_rtc_rtt +endif + include $(RIOTCPU)/sam0_common/Makefile.dep diff --git a/cpu/samd5x/Makefile.features b/cpu/samd5x/Makefile.features index 5ef1caaa40..ff90cc6e8b 100644 --- a/cpu/samd5x/Makefile.features +++ b/cpu/samd5x/Makefile.features @@ -3,5 +3,6 @@ CPU_CORE = cortex-m4f FEATURES_PROVIDED += periph_hwrng FEATURES_PROVIDED += backup_ram FEATURES_PROVIDED += cortexm_mpu +FEATURES_PROVIDED += periph_gpio_tamper_wake include $(RIOTCPU)/sam0_common/Makefile.features diff --git a/cpu/samd5x/include/periph_cpu.h b/cpu/samd5x/include/periph_cpu.h index a7b39a952c..21b80c7cdf 100644 --- a/cpu/samd5x/include/periph_cpu.h +++ b/cpu/samd5x/include/periph_cpu.h @@ -116,6 +116,15 @@ typedef enum { #define RTT_MAX_FREQUENCY (RTT_CLOCK_FREQUENCY) /* in Hz */ /** @} */ +/** + * @brief RTC input pins that can be used for tamper detection and + * wake from Deep Sleep + */ +static const gpio_t rtc_tamper_pins[RTC_NUM_OF_TAMPERS] = { + GPIO_PIN(PB, 0), GPIO_PIN(PB, 2), GPIO_PIN(PA, 2), + GPIO_PIN(PC, 0), GPIO_PIN(PC, 1) +}; + #ifdef __cplusplus } #endif diff --git a/cpu/saml1x/include/periph_cpu.h b/cpu/saml1x/include/periph_cpu.h index 3c81e6dd58..2429ae4648 100644 --- a/cpu/saml1x/include/periph_cpu.h +++ b/cpu/saml1x/include/periph_cpu.h @@ -82,6 +82,15 @@ typedef enum { #define RTT_MAX_FREQUENCY (RTT_CLOCK_FREQUENCY) /* in Hz */ /** @} */ +/** + * @brief RTC input pins that can be used for tamper detection and + * wake from Deep Sleep + */ +static const gpio_t rtc_tamper_pins[RTC_NUM_OF_TAMPERS] = { + GPIO_PIN(PA, 8), GPIO_PIN(PA, 9), GPIO_PIN(PA, 16), + GPIO_PIN(PA, 17) +}; + #ifdef __cplusplus } #endif diff --git a/drivers/periph_common/init.c b/drivers/periph_common/init.c index a6a8ad57d2..c3f6bd4463 100644 --- a/drivers/periph_common/init.c +++ b/drivers/periph_common/init.c @@ -22,6 +22,8 @@ #define USB_H_USER_IS_RIOT_INTERNAL +#include "periph_cpu.h" + #ifdef MODULE_PERIPH_INIT #ifdef MODULE_PERIPH_INIT_I2C #include "periph/i2c.h" @@ -73,6 +75,11 @@ void periph_init(void) rtc_init(); #endif + /* Initialize Tamper Detection */ +#ifdef MODULE_PERIPH_INIT_GPIO_TAMPER_WAKE + rtc_tamper_init(); +#endif + #ifdef MODULE_PERIPH_INIT_HWRNG hwrng_init(); #endif diff --git a/kconfigs/Kconfig.features b/kconfigs/Kconfig.features index 057ee85e2d..1ce168aebb 100644 --- a/kconfigs/Kconfig.features +++ b/kconfigs/Kconfig.features @@ -150,6 +150,12 @@ config HAS_PERIPH_GPIO_FAST_READ operations are faster, usually with a tradeoff against a different property. +config HAS_PERIPH_GPIO_TAMPER_WAKE + bool + help + Indicates that Tamper Detection can be used to wake the CPU from + Deep Sleep. + config HAS_PERIPH_HWRNG bool help