mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
Merge pull request #14030 from benpicco/cpu/sam0_common-rtc_tamper
cpu/sam0_common: GPIO: use tamper detection to wake from Deep Sleep
This commit is contained in:
commit
bcd2b3e369
@ -1069,6 +1069,32 @@ void dma_wait(dma_t dma);
|
||||
void dma_cancel(dma_t dma);
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name sam0 RTC Tamper Detection
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Power on the RTC (if the RTC/RTT is not otherwise used)
|
||||
*/
|
||||
void rtc_tamper_init(void);
|
||||
|
||||
/**
|
||||
* @brief Enable Tamper Detection IRQs
|
||||
*
|
||||
* @param pin The GPIO pin to be used for tamper detection
|
||||
* @param flank The Flank to trigger the even
|
||||
*
|
||||
* @return 0 on success, -1 if pin is not RTC pin
|
||||
*/
|
||||
int rtc_tamper_register(gpio_t pin, gpio_flank_t flank);
|
||||
|
||||
/**
|
||||
* @brief Enable Tamper Detection IRQs
|
||||
*/
|
||||
void rtc_tamper_enable(void);
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -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 <troels.d.hoffmeyer@gmail.com>
|
||||
* @author Thomas Eichinger <thomas.eichinger@fu-berlin.de>
|
||||
* @author Kaspar Schleiser <kaspar@schleiser.de>
|
||||
@ -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");
|
||||
|
@ -25,6 +25,7 @@
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "mutex.h"
|
||||
#include "periph/rtc.h"
|
||||
#include "periph/rtt.h"
|
||||
#include "periph_conf.h"
|
||||
@ -101,6 +102,16 @@ static void _poweron(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
__attribute__((unused))
|
||||
static bool _power_is_on(void)
|
||||
{
|
||||
#ifdef MCLK
|
||||
return MCLK->APBAMASK.reg & MCLK_APBAMASK_RTC;
|
||||
#else
|
||||
return PM->APBAMASK.reg & PM_APBAMASK_RTC;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void _poweroff(void)
|
||||
{
|
||||
#ifdef MCLK
|
||||
@ -268,6 +279,93 @@ void rtt_init(void)
|
||||
NVIC_EnableIRQ(RTC_IRQn);
|
||||
}
|
||||
|
||||
#if RTC_NUM_OF_TAMPERS
|
||||
|
||||
static rtc_state_t tamper_cb;
|
||||
|
||||
/* check if pin is a RTC tamper pin */
|
||||
static int _rtc_pin(gpio_t pin)
|
||||
{
|
||||
for (unsigned i = 0; i < ARRAY_SIZE(rtc_tamper_pins); ++i) {
|
||||
if (rtc_tamper_pins[i] == pin) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void rtc_tamper_init(void)
|
||||
{
|
||||
if (IS_ACTIVE(MODULE_PERIPH_RTC) ||
|
||||
IS_ACTIVE(MODULE_PERIPH_RTT) ||
|
||||
_power_is_on()) {
|
||||
return;
|
||||
}
|
||||
|
||||
_rtt_clock_setup();
|
||||
_poweron();
|
||||
|
||||
/* disable all interrupt sources */
|
||||
RTC->MODE0.INTENCLR.reg = RTC_MODE0_INTENCLR_MASK;
|
||||
|
||||
NVIC_EnableIRQ(RTC_IRQn);
|
||||
}
|
||||
|
||||
int rtc_tamper_register(gpio_t pin, gpio_flank_t flank)
|
||||
{
|
||||
int in = _rtc_pin(pin);
|
||||
|
||||
if (in < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* TAMPCTRL is enable-protected */
|
||||
_rtc_set_enabled(0);
|
||||
|
||||
RTC->MODE0.TAMPCTRL.reg |= RTC_TAMPCTRL_IN0ACT_WAKE << (2 * in);
|
||||
|
||||
if (flank == GPIO_RISING) {
|
||||
RTC->MODE0.TAMPCTRL.reg |= RTC_TAMPCTRL_TAMLVL0 << in;
|
||||
} else if (flank == GPIO_FALLING) {
|
||||
RTC->MODE0.TAMPCTRL.reg &= ~(RTC_TAMPCTRL_TAMLVL0 << in);
|
||||
}
|
||||
|
||||
/* enable the RTC again */
|
||||
_rtc_set_enabled(1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _unlock(void *m)
|
||||
{
|
||||
mutex_unlock(m);
|
||||
}
|
||||
|
||||
void rtc_tamper_enable(void)
|
||||
{
|
||||
mutex_t m = MUTEX_INIT;
|
||||
|
||||
/* clear tamper id */
|
||||
RTC->MODE0.TAMPID.reg = 0xF;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* enable tamper detect as wake-up source */
|
||||
RTC->MODE0.INTENSET.bit.TAMPER = 1;
|
||||
|
||||
/* wait for first tamper event */
|
||||
mutex_lock(&m);
|
||||
}
|
||||
|
||||
#endif /* RTC_NUM_OF_TAMPERS */
|
||||
|
||||
void rtt_set_overflow_cb(rtt_cb_t cb, void *arg)
|
||||
{
|
||||
/* clear overflow cb to avoid race while assigning */
|
||||
@ -503,9 +601,23 @@ static void _isr_rtt(void)
|
||||
}
|
||||
}
|
||||
|
||||
static void _isr_tamper(void)
|
||||
{
|
||||
#ifdef RTC_MODE0_INTFLAG_TAMPER
|
||||
if (RTC->MODE0.INTFLAG.bit.TAMPER) {
|
||||
RTC->MODE0.INTFLAG.reg = RTC_MODE0_INTFLAG_TAMPER;
|
||||
if (tamper_cb.cb) {
|
||||
tamper_cb.cb(tamper_cb.arg);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void isr_rtc(void)
|
||||
{
|
||||
_isr_rtc();
|
||||
_isr_rtt();
|
||||
_isr_tamper();
|
||||
|
||||
cortexm_isr_end();
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -1 +1,5 @@
|
||||
ifneq (,$(filter periph_gpio_tamper_wake,$(USEMODULE)))
|
||||
USEMODULE += periph_rtc_rtt
|
||||
endif
|
||||
|
||||
include $(RIOTCPU)/sam0_common/Makefile.dep
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -1,8 +1,9 @@
|
||||
include ../Makefile.tests_common
|
||||
|
||||
FEATURES_REQUIRED = periph_gpio
|
||||
FEATURES_OPTIONAL = periph_gpio_irq
|
||||
FEATURES_REQUIRED += periph_gpio
|
||||
FEATURES_OPTIONAL += periph_gpio_irq
|
||||
FEATURES_OPTIONAL += periph_gpio_fast_read
|
||||
FEATURES_OPTIONAL += periph_gpio_tamper_wake
|
||||
|
||||
USEMODULE += shell
|
||||
USEMODULE += shell_commands
|
||||
|
Loading…
Reference in New Issue
Block a user