From ac8a81b8f38e3b3ef58442f3a129927eea2a37e9 Mon Sep 17 00:00:00 2001 From: Juergen Fitschen Date: Wed, 19 Feb 2020 18:40:08 +0100 Subject: [PATCH 1/4] cpu/saml21: disable fast clock if it is not requested --- cpu/saml21/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpu/saml21/cpu.c b/cpu/saml21/cpu.c index 65783ae973..03e3b1dd1f 100644 --- a/cpu/saml21/cpu.c +++ b/cpu/saml21/cpu.c @@ -119,7 +119,7 @@ void cpu_init(void) /* set OSC16M to 16MHz */ OSCCTRL->OSC16MCTRL.bit.FSEL = 3; - OSCCTRL->OSC16MCTRL.bit.ONDEMAND = 0; + OSCCTRL->OSC16MCTRL.bit.ONDEMAND = 1; OSCCTRL->OSC16MCTRL.bit.RUNSTDBY = 0; _osc32k_setup(); From 1265efc7859294c93e703702585901b49830902a Mon Sep 17 00:00:00 2001 From: Juergen Fitschen Date: Fri, 21 Feb 2020 16:18:36 +0100 Subject: [PATCH 2/4] cpu/sam0*: Wrap cortexm_sleep call --- cpu/sam0_common/include/periph_cpu_common.h | 10 ++++++++++ cpu/samd21/periph/pm.c | 2 +- cpu/samd5x/periph/pm.c | 2 +- cpu/saml1x/periph/pm.c | 2 +- cpu/saml21/periph/pm.c | 2 +- 5 files changed, 14 insertions(+), 4 deletions(-) diff --git a/cpu/sam0_common/include/periph_cpu_common.h b/cpu/sam0_common/include/periph_cpu_common.h index 19753d91fe..7bd161b94d 100644 --- a/cpu/sam0_common/include/periph_cpu_common.h +++ b/cpu/sam0_common/include/periph_cpu_common.h @@ -352,6 +352,16 @@ typedef struct { */ void gpio_init_mux(gpio_t pin, gpio_mux_t mux); +/** + * @brief Wrapper for cortexm_sleep calling power management callbacks + * + * @param[in] deep + */ +static inline void sam0_cortexm_sleep(int deep) +{ + cortexm_sleep(deep); +} + /** * @brief Returns the frequency of a GCLK provider. * diff --git a/cpu/samd21/periph/pm.c b/cpu/samd21/periph/pm.c index 17e8f7a706..687d8199a1 100644 --- a/cpu/samd21/periph/pm.c +++ b/cpu/samd21/periph/pm.c @@ -82,5 +82,5 @@ void pm_set(unsigned mode) break; } - cortexm_sleep(deep); + sam0_cortexm_sleep(deep); } diff --git a/cpu/samd5x/periph/pm.c b/cpu/samd5x/periph/pm.c index 8229881749..cbbc65c768 100644 --- a/cpu/samd5x/periph/pm.c +++ b/cpu/samd5x/periph/pm.c @@ -57,5 +57,5 @@ void pm_set(unsigned mode) /* make sure value has been set */ while (PM->SLEEPCFG.bit.SLEEPMODE != _mode) {} - cortexm_sleep(deep); + sam0_cortexm_sleep(deep); } diff --git a/cpu/saml1x/periph/pm.c b/cpu/saml1x/periph/pm.c index 4624533577..5068425492 100644 --- a/cpu/saml1x/periph/pm.c +++ b/cpu/saml1x/periph/pm.c @@ -47,5 +47,5 @@ void pm_set(unsigned mode) while (PM->SLEEPCFG.bit.SLEEPMODE != _mode) {} } - cortexm_sleep(0); + sam0_cortexm_sleep(0); } diff --git a/cpu/saml21/periph/pm.c b/cpu/saml21/periph/pm.c index af839e5bd9..01e16c6707 100644 --- a/cpu/saml21/periph/pm.c +++ b/cpu/saml21/periph/pm.c @@ -55,5 +55,5 @@ void pm_set(unsigned mode) while (PM->SLEEPCFG.bit.SLEEPMODE != _mode) {} } - cortexm_sleep(0); + sam0_cortexm_sleep(0); } From 43ff72ad56a860badaa18940739844d3f42a0d06 Mon Sep 17 00:00:00 2001 From: Juergen Fitschen Date: Fri, 21 Feb 2020 16:25:45 +0100 Subject: [PATCH 3/4] cpu/sam0*: Switch EIC clock to slow speed on STANDBY mode --- cpu/sam0_common/include/periph_cpu_common.h | 22 +++++++ cpu/sam0_common/periph/gpio.c | 73 ++++++++++++++++++++- 2 files changed, 92 insertions(+), 3 deletions(-) diff --git a/cpu/sam0_common/include/periph_cpu_common.h b/cpu/sam0_common/include/periph_cpu_common.h index 7bd161b94d..38cc58ac69 100644 --- a/cpu/sam0_common/include/periph_cpu_common.h +++ b/cpu/sam0_common/include/periph_cpu_common.h @@ -352,6 +352,20 @@ typedef struct { */ void gpio_init_mux(gpio_t pin, gpio_mux_t mux); +/** + * @brief Called before the power management enters a power mode + * + * @param[in] deep + */ +void gpio_pm_cb_enter(int deep); + +/** + * @brief Called after the power management left a power mode + * + * @param[in] deep + */ +void gpio_pm_cb_leave(int deep); + /** * @brief Wrapper for cortexm_sleep calling power management callbacks * @@ -359,7 +373,15 @@ void gpio_init_mux(gpio_t pin, gpio_mux_t mux); */ static inline void sam0_cortexm_sleep(int deep) { +#ifdef MODULE_PERIPH_GPIO + gpio_pm_cb_enter(deep); +#endif + cortexm_sleep(deep); + +#ifdef MODULE_PERIPH_GPIO + gpio_pm_cb_leave(deep); +#endif } /** diff --git a/cpu/sam0_common/periph/gpio.c b/cpu/sam0_common/periph/gpio.c index 83892f9507..ed78cd2c13 100644 --- a/cpu/sam0_common/periph/gpio.c +++ b/cpu/sam0_common/periph/gpio.c @@ -56,6 +56,14 @@ #define _EIC EIC #endif +/** + * @brief Clock source for the External Interrupt Controller + */ +typedef enum { + _EIC_CLOCK_FAST, + _EIC_CLOCK_SLOW +} gpio_eic_clock_t; + static gpio_isr_ctx_t gpio_config[NUMOF_IRQS]; #endif /* MODULE_PERIPH_GPIO_IRQ */ @@ -155,6 +163,13 @@ void gpio_write(gpio_t pin, int value) } #ifdef MODULE_PERIPH_GPIO_IRQ + +#ifdef CPU_FAM_SAMD21 +#define EIC_SYNC() while (_EIC->STATUS.bit.SYNCBUSY) +#else +#define EIC_SYNC() while (_EIC->SYNCBUSY.bit.ENABLE) +#endif + static int _exti(gpio_t pin) { unsigned port_num = ((pin >> 7) & 0x03); @@ -196,7 +211,7 @@ int gpio_init_int(gpio_t pin, gpio_mode_t mode, gpio_flank_t flank, GCLK->PCHCTRL[EIC_GCLK_ID].reg = GCLK_PCHCTRL_CHEN | GCLK_PCHCTRL_GEN(SAM0_GCLK_MAIN); /* disable the EIC module*/ _EIC->CTRLA.reg = 0; - while (_EIC->SYNCBUSY.reg & EIC_SYNCBUSY_ENABLE) {} + EIC_SYNC(); #endif /* configure the active flank */ _EIC->CONFIG[exti >> 3].reg &= ~(0xf << ((exti & 0x7) * 4)); @@ -217,15 +232,55 @@ int gpio_init_int(gpio_t pin, gpio_mode_t mode, gpio_flank_t flank, _EIC->WAKEUP.reg |= (1 << exti); /* enable the EIC module*/ _EIC->CTRL.reg = EIC_CTRL_ENABLE; - while (_EIC->STATUS.reg & EIC_STATUS_SYNCBUSY) {} + EIC_SYNC(); #else /* CPU_FAM_SAML21 */ /* enable the EIC module*/ _EIC->CTRLA.reg = EIC_CTRLA_ENABLE; - while (_EIC->SYNCBUSY.reg & EIC_SYNCBUSY_ENABLE) {} + EIC_SYNC(); #endif return 0; } +inline static void reenable_eic(gpio_eic_clock_t clock) { +#if !defined(CPU_SAMD21) + uint32_t ctrla_reg = EIC_CTRLA_ENABLE; + + EIC->CTRLA.reg = 0; + EIC_SYNC(); + + if (clock == _EIC_CLOCK_SLOW) { + ctrla_reg |= EIC_CTRLA_CKSEL; + } + + EIC->CTRLA.reg = ctrla_reg; + EIC_SYNC(); +#endif +} + +void gpio_pm_cb_enter(int deep) +{ +#if defined(PM_SLEEPCFG_SLEEPMODE_STANDBY) + (void) deep; + + if (PM->SLEEPCFG.bit.SLEEPMODE == PM_SLEEPCFG_SLEEPMODE_STANDBY) { + DEBUG_PUTS("gpio: switching EIC to slow clock"); + reenable_eic(_EIC_CLOCK_SLOW); + } +#endif +} + +void gpio_pm_cb_leave(int deep) +{ +#if defined(PM_SLEEPCFG_SLEEPMODE_STANDBY) + (void) deep; + + if (PM->SLEEPCFG.bit.SLEEPMODE == PM_SLEEPCFG_SLEEPMODE_STANDBY) { + DEBUG_PUTS("gpio: switching EIC to fast clock"); + reenable_eic(_EIC_CLOCK_FAST); + } +#endif +} + void gpio_irq_enable(gpio_t pin) { int exti = _exti(pin); @@ -285,4 +340,16 @@ ISR_EICn(_other) #endif /* CPU_SAML1X */ #endif /* CPU_SAML1X || CPU_SAMD5X */ +#else /* MODULE_PERIPH_GPIO_IRQ */ + +void gpio_pm_cb_enter(int deep) +{ + (void) deep; +} + +void gpio_pm_cb_leave(int deep) +{ + (void) deep; +} + #endif /* MODULE_PERIPH_GPIO_IRQ */ From 442ddc134673afb72a23e8c258c9a6d2e7d76795 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Fri, 21 Feb 2020 18:05:35 +0100 Subject: [PATCH 4/4] cpu/samd21: Switch EIC clock to slow speed on STANDBY mode --- cpu/sam0_common/periph/gpio.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/cpu/sam0_common/periph/gpio.c b/cpu/sam0_common/periph/gpio.c index ed78cd2c13..e721d75a72 100644 --- a/cpu/sam0_common/periph/gpio.c +++ b/cpu/sam0_common/periph/gpio.c @@ -242,7 +242,18 @@ int gpio_init_int(gpio_t pin, gpio_mode_t mode, gpio_flank_t flank, } inline static void reenable_eic(gpio_eic_clock_t clock) { -#if !defined(CPU_SAMD21) +#if defined(CPU_SAMD21) + if (clock == _EIC_CLOCK_SLOW) { + GCLK->CLKCTRL.reg = EIC_GCLK_ID + | GCLK_CLKCTRL_CLKEN + | GCLK_CLKCTRL_GEN(SAM0_GCLK_32KHZ); + } else { + GCLK->CLKCTRL.reg = EIC_GCLK_ID + | GCLK_CLKCTRL_CLKEN + | GCLK_CLKCTRL_GEN(SAM0_GCLK_MAIN); + } + while (GCLK->STATUS.bit.SYNCBUSY) {} +#else uint32_t ctrla_reg = EIC_CTRLA_ENABLE; EIC->CTRLA.reg = 0; @@ -266,6 +277,11 @@ void gpio_pm_cb_enter(int deep) DEBUG_PUTS("gpio: switching EIC to slow clock"); reenable_eic(_EIC_CLOCK_SLOW); } +#else + if (deep) { + DEBUG_PUTS("gpio: switching EIC to slow clock"); + reenable_eic(_EIC_CLOCK_SLOW); + } #endif } @@ -278,6 +294,11 @@ void gpio_pm_cb_leave(int deep) DEBUG_PUTS("gpio: switching EIC to fast clock"); reenable_eic(_EIC_CLOCK_FAST); } +#else + if (deep) { + DEBUG_PUTS("gpio: switching EIC to fast clock"); + reenable_eic(_EIC_CLOCK_FAST); + } #endif }