From 3f95d3d2e3d32f7a3a820f8c0c26e9f48b983fa7 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Mon, 24 Feb 2020 19:25:08 +0100 Subject: [PATCH 1/4] cpu/saml21: pm: set deep flag Set the deep flag for consistency with other family members. --- cpu/saml21/periph/pm.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cpu/saml21/periph/pm.c b/cpu/saml21/periph/pm.c index 4d390a8d23..107c520f1a 100644 --- a/cpu/saml21/periph/pm.c +++ b/cpu/saml21/periph/pm.c @@ -26,16 +26,19 @@ void pm_set(unsigned mode) { + int deep = 0; uint32_t _mode; switch (mode) { case 0: DEBUG_PUTS("pm_set(): setting BACKUP mode."); _mode = PM_SLEEPCFG_SLEEPMODE_BACKUP; + deep = 1; break; case 1: DEBUG_PUTS("pm_set(): setting STANDBY mode."); _mode = PM_SLEEPCFG_SLEEPMODE_STANDBY; + deep = 1; break; default: /* Falls through */ case 2: @@ -53,5 +56,5 @@ void pm_set(unsigned mode) /* make sure value has been set */ while (PM->SLEEPCFG.bit.SLEEPMODE != _mode) {} - sam0_cortexm_sleep(0); + sam0_cortexm_sleep(deep); } From f037e06b13cbef3941a2e84abccc5451d9663e37 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Fri, 21 Feb 2020 17:03:12 +0100 Subject: [PATCH 2/4] cpu/saml21: enable buck voltage regulator when possible MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Switch from the on-chip LDO to the on-chip buck voltage regulator when not fast internal oscillators are used. On `saml21-xpro` with `examples/default` this gives **before:** 750 µA ** after:** 385 µA --- cpu/saml21/cpu.c | 67 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 61 insertions(+), 6 deletions(-) diff --git a/cpu/saml21/cpu.c b/cpu/saml21/cpu.c index b739f82773..bcf04e9fa7 100644 --- a/cpu/saml21/cpu.c +++ b/cpu/saml21/cpu.c @@ -23,6 +23,22 @@ #include "periph_conf.h" #include "stdio_base.h" +/* As long as DFLL & DPLL are not used, we can default to + * always use the buck converter when available. + * + * An external inductor needs to be present on the board, + * so the feature can only be enabled by the board configuration. + */ +#ifndef USE_VREG_BUCK +#define USE_VREG_BUCK (0) +#endif + +#if (CLOCK_CORECLOCK == 48000000U) || defined (MODULE_PERIPH_USBDEV) +#define USE_DFLL (1) +#else +#define USE_DFLL (0) +#endif + static void _gclk_setup(int gclk, uint32_t reg) { GCLK->GENCTRL[gclk].reg = reg; @@ -86,7 +102,10 @@ uint32_t sam0_gclk_freq(uint8_t id) static void _dfll_setup(void) { -#if (CLOCK_CORECLOCK == 48000000U) || defined (MODULE_PERIPH_USBDEV) + if (!USE_DFLL) { + return; + } + GCLK->PCHCTRL[OSCCTRL_GCLK_ID_DFLL48].reg = GCLK_PCHCTRL_CHEN | GCLK_PCHCTRL_GEN_GCLK2; @@ -124,19 +143,52 @@ static void _dfll_setup(void) MCLK->APBBMASK.reg |= MCLK_APBBMASK_NVMCTRL; /* Set Wait State to meet requirements */ NVMCTRL->CTRLB.reg |= NVMCTRL_CTRLB_RWS(3); -#endif +} + +static void _set_active_mode_vreg(void) +{ + if (!USE_VREG_BUCK) { + return; + } + + /* not compatible with 48 MHz DFLL & 96 MHz FDPLL */ + if (USE_DFLL) { + sam0_set_voltage_regulator(SAM0_VREG_LDO); + } else { + sam0_set_voltage_regulator(SAM0_VREG_BUCK); + } } void cpu_pm_cb_enter(int deep) { - (void) deep; - /* will be called before entering sleep */ + if (!deep) { + return; + } + + /* If you are using saml21 rev. B, switch Main Clock to OSCULP32 during standby + to work around errata 1.2.1. + See discussion in #13441 */ + assert((DSU->DID.bit.REVISION > 1) || ((PM->STDBYCFG.reg & 0x80) == 0)); + + /* errata 51.1.5 – When VDDCORE is supplied by the BUCK converter in performance + level 0, the chip cannot wake-up from standby mode because the + VCORERDY status is stuck at 0. */ + if (USE_VREG_BUCK && !PM->PLCFG.bit.PLSEL) { + sam0_set_voltage_regulator(SAM0_VREG_LDO); + } + + /* TODO: If we source Main Clock from OSCULP32 during standby and are not in + performance level 0, we should always be able to use the BUCK converter + during standby */ } void cpu_pm_cb_leave(int deep) { - (void) deep; - /* will be called after wake-up */ + if (!deep) { + return; + } + + _set_active_mode_vreg(); } /** @@ -158,6 +210,9 @@ void cpu_init(void) /* initialize the Cortex-M core */ cortexm_init(); + /* select the right voltage regulator config for active mode */ + _set_active_mode_vreg(); + /* turn on only needed APB peripherals */ MCLK->APBAMASK.reg = MCLK_APBAMASK_PM From a102ad3d3d3953be86a8a55c782a83cfe0643422 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Wed, 25 Mar 2020 16:21:39 +0100 Subject: [PATCH 3/4] boards/saml21-xpro: enable buck converter --- boards/saml21-xpro/include/periph_conf.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/boards/saml21-xpro/include/periph_conf.h b/boards/saml21-xpro/include/periph_conf.h index 23418e3be6..44cd399685 100644 --- a/boards/saml21-xpro/include/periph_conf.h +++ b/boards/saml21-xpro/include/periph_conf.h @@ -34,6 +34,12 @@ extern "C" { */ #define CLOCK_CORECLOCK (48000000U) +/** + * @brief Enable the internal DC/DC converter + * The board is equipped with the necessary inductor. + */ +#define USE_VREG_BUCK (1) + /** * @name Timer peripheral configuration * @{ From 09ef2f69086c59730b7cb2a30587f14a7a37039a Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Wed, 25 Mar 2020 16:22:14 +0100 Subject: [PATCH 4/4] boards/samr34-xpro: enable buck converter --- boards/samr34-xpro/include/periph_conf.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/boards/samr34-xpro/include/periph_conf.h b/boards/samr34-xpro/include/periph_conf.h index 1a6c66d234..04e9bf45b9 100644 --- a/boards/samr34-xpro/include/periph_conf.h +++ b/boards/samr34-xpro/include/periph_conf.h @@ -31,6 +31,12 @@ extern "C" { */ #define CLOCK_CORECLOCK (48000000U) +/** + * @brief Enable the internal DC/DC converter + * The board is equipped with the necessary inductor. + */ +#define USE_VREG_BUCK (1) + /** * @name Timer peripheral configuration * @{