From f42e5381eee801f2df52bf632e6a593f746014f9 Mon Sep 17 00:00:00 2001 From: Kaspar Schleiser Date: Mon, 9 Jan 2017 18:13:04 +0100 Subject: [PATCH] cpu: samd21: add periph/pm support --- boards/samr21-xpro/Makefile.features | 1 + cpu/samd21/Makefile.include | 2 + cpu/samd21/cpu.c | 10 +++- cpu/samd21/include/periph_cpu.h | 2 + cpu/samd21/periph/gpio.c | 2 +- cpu/samd21/periph/pm.c | 89 ++++++++++++++++++++++++++++ 6 files changed, 104 insertions(+), 2 deletions(-) create mode 100644 cpu/samd21/periph/pm.c diff --git a/boards/samr21-xpro/Makefile.features b/boards/samr21-xpro/Makefile.features index 3b09ac148d..ce28e8a41e 100644 --- a/boards/samr21-xpro/Makefile.features +++ b/boards/samr21-xpro/Makefile.features @@ -2,6 +2,7 @@ FEATURES_PROVIDED += periph_cpuid FEATURES_PROVIDED += periph_gpio FEATURES_PROVIDED += periph_i2c +FEATURES_PROVIDED += periph_pm FEATURES_PROVIDED += periph_pwm FEATURES_PROVIDED += periph_rtc FEATURES_PROVIDED += periph_rtt diff --git a/cpu/samd21/Makefile.include b/cpu/samd21/Makefile.include index 30e261c9fd..a95fff8036 100644 --- a/cpu/samd21/Makefile.include +++ b/cpu/samd21/Makefile.include @@ -1,5 +1,7 @@ export CPU_ARCH = cortex-m0plus export CPU_FAM = samd21 +USEMODULE += pm_layered + include $(RIOTCPU)/sam0_common/Makefile.include include $(RIOTCPU)/Makefile.include.cortexm_common diff --git a/cpu/samd21/cpu.c b/cpu/samd21/cpu.c index dbb488d5fc..cef8383a01 100644 --- a/cpu/samd21/cpu.c +++ b/cpu/samd21/cpu.c @@ -39,7 +39,7 @@ static void clk_init(void) /* configure internal 8MHz oscillator to run without prescaler */ SYSCTRL->OSC8M.bit.PRESC = 0; - SYSCTRL->OSC8M.bit.ONDEMAND = 0; + SYSCTRL->OSC8M.bit.ONDEMAND = 1; SYSCTRL->OSC8M.bit.RUNSTDBY = 0; SYSCTRL->OSC8M.bit.ENABLE = 1; while (!(SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_OSC8MRDY)) {} @@ -84,6 +84,14 @@ static void clk_init(void) /* make sure we synchronize clock generator 0 before we go on */ while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) {} + /* Setup Clock generator 2 with divider 1 (32.768kHz) */ + GCLK->GENDIV.reg = (GCLK_GENDIV_ID(2) | GCLK_GENDIV_DIV(0)); + GCLK->GENCTRL.reg = (GCLK_GENCTRL_ID(2) | GCLK_GENCTRL_GENEN | + GCLK_GENCTRL_RUNSTDBY | + GCLK_GENCTRL_SRC_OSCULP32K); + + while (GCLK->STATUS.bit.SYNCBUSY) {} + /* redirect all peripherals to a disabled clock generator (7) by default */ for (int i = 0x3; i <= 0x22; i++) { GCLK->CLKCTRL.reg = ( GCLK_CLKCTRL_ID(i) | GCLK_CLKCTRL_GEN_GCLK7 ); diff --git a/cpu/samd21/include/periph_cpu.h b/cpu/samd21/include/periph_cpu.h index c07a056429..1c0de37407 100644 --- a/cpu/samd21/include/periph_cpu.h +++ b/cpu/samd21/include/periph_cpu.h @@ -102,6 +102,8 @@ static inline int _sercom_id(SercomUsart *sercom) return ((((uint32_t)sercom) >> 10) & 0x7) - 2; } +#define PM_NUM_MODES (3) + #ifdef __cplusplus } #endif diff --git a/cpu/samd21/periph/gpio.c b/cpu/samd21/periph/gpio.c index 3c0b600d6e..80e31f0162 100644 --- a/cpu/samd21/periph/gpio.c +++ b/cpu/samd21/periph/gpio.c @@ -138,7 +138,7 @@ int gpio_init_int(gpio_t pin, gpio_mode_t mode, gpio_flank_t flank, PM->APBAMASK.reg |= PM_APBAMASK_EIC; GCLK->CLKCTRL.reg = (EIC_GCLK_ID | GCLK_CLKCTRL_CLKEN | - GCLK_CLKCTRL_GEN_GCLK0); + GCLK_CLKCTRL_GEN_GCLK2); while (GCLK->STATUS.bit.SYNCBUSY) {} /* configure the active flank */ EIC->CONFIG[exti >> 3].reg &= ~(0xf << ((exti & 0x7) * 4)); diff --git a/cpu/samd21/periph/pm.c b/cpu/samd21/periph/pm.c new file mode 100644 index 0000000000..8af3775d70 --- /dev/null +++ b/cpu/samd21/periph/pm.c @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2016 Kaspar Schleiser + * Copyright (C) 2014 Freie Universität Berlin + * Copyright (C) 2015 Saurabh Singh + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup cpu_samd21 + * @{ + * + * @file + * @brief Implementation of the kernels power management interface + * + * @author Thomas Eichinger + * @author Saurabh Singh + * @author Kaspar Schleiser + * + * @} + */ + +#include "periph/pm.h" + +#define ENABLE_DEBUG (1) +#include "debug.h" + +enum system_sleepmode { + /** + * Idle 0 mode. + * Potential Wake Up sources: Synchronous(APB, AHB), asynchronous. + */ + SYSTEM_SLEEPMODE_IDLE_0, + /** + * Idle 1 mode. + * Potential Wake Up sources: Synchronous (APB), asynchronous + */ + SYSTEM_SLEEPMODE_IDLE_1, + /** + * Idle 2 mode. + * Potential Wake Up sources: Asynchronous + */ + SYSTEM_SLEEPMODE_IDLE_2, + /** + * Standby mode. + * Potential Wake Up sources: Asynchronous + */ + SYSTEM_SLEEPMODE_STANDBY, +}; + +void pm_set(unsigned mode) +{ + switch (mode) { + case 0: + /* Standby Mode + * Potential Wake Up sources: asynchronous + */ + SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; + break; + case 1: + /* Sleep mode Idle 2 + * Potential Wake Up sources: asynchronous + */ + SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk; + PM->SLEEP.reg = SYSTEM_SLEEPMODE_IDLE_2; + break; + case 2: + /* Sleep mode Idle 1 + * Potential Wake Up sources: Synchronous (APB), asynchronous + */ + SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk; + PM->SLEEP.reg = SYSTEM_SLEEPMODE_IDLE_1; + break; + case 3: + /* Sleep mode Idle 0 + * Potential Wake Up sources: Synchronous (APB, AHB), asynchronous + */ + SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk; + PM->SLEEP.reg = SYSTEM_SLEEPMODE_IDLE_0; + break; + } + + /* Executes a device DSB (Data Synchronization Barrier) */ + __DSB(); + /* Enter standby mode */ + __WFI(); +}