diff --git a/boards/saml21-xpro/include/periph_conf.h b/boards/saml21-xpro/include/periph_conf.h index 08317f22cb..c624f73e78 100644 --- a/boards/saml21-xpro/include/periph_conf.h +++ b/boards/saml21-xpro/include/periph_conf.h @@ -57,12 +57,14 @@ extern "C" { #define UART_0_DEV SERCOM3->USART #define UART_0_IRQ SERCOM3_IRQn #define UART_0_ISR isr_sercom3 +#define UART_0_REF_F (16000000UL) +#define UART_0_RUNSTDBY 1 + /* UART 0 pin configuration */ #define UART_0_PORT (PORT->Group[0]) #define UART_0_TX_PIN (22) #define UART_0_RX_PIN (23) #define UART_0_PINS (((PORT_PA22 | PORT_PA23) >> 16) | PORT_WRCONFIG_HWSEL) -#define UART_0_REF_F (16000000UL) /** @} */ /** @@ -99,7 +101,7 @@ extern "C" { * @{ */ #define RTT_FREQUENCY (32768U) -#define RTT_MAX_VALUE (0xffffffffU) +#define RTT_MAX_VALUE (0xffffffffU) #define RTT_NUMOF (1) /** @} */ diff --git a/cpu/saml21/cpu.c b/cpu/saml21/cpu.c index ebb1411e5d..d1893dc964 100644 --- a/cpu/saml21/cpu.c +++ b/cpu/saml21/cpu.c @@ -18,8 +18,16 @@ * @} */ +#include "arch/lpm_arch.h" + #include "cpu.h" +static void _gclk_setup(int gclk, uint32_t reg) +{ + while (GCLK->SYNCBUSY.reg & GCLK_SYNCBUSY_GENCTRL(gclk)); + GCLK->GENCTRL[gclk].reg = reg; +} + /** * @brief Initialize the CPU, set IRQ priorities, clocks */ @@ -31,8 +39,21 @@ void cpu_init(void) /* initialize the Cortex-M core */ cortexm_init(); - /* turn on MCLK */ - MCLK->APBAMASK.reg |= MCLK_APBAMASK_GCLK; + /* turn on only needed APB peripherals */ + MCLK->APBAMASK.reg = + MCLK_APBAMASK_PM + |MCLK_APBAMASK_MCLK + |MCLK_APBAMASK_RSTC + |MCLK_APBAMASK_OSCCTRL + |MCLK_APBAMASK_OSC32KCTRL + |MCLK_APBAMASK_SUPC + |MCLK_APBAMASK_GCLK + |MCLK_APBAMASK_WDT + |MCLK_APBAMASK_RTC + |MCLK_APBAMASK_EIC + |MCLK_APBAMASK_PORT + //|MCLK_APBAMASK_TAL + ; /* Software reset the GCLK module to ensure it is re-initialized correctly */ GCLK->CTRLA.reg = GCLK_CTRLA_SWRST; @@ -41,11 +62,12 @@ void cpu_init(void) /* set OSC16M to 16MHz */ OSCCTRL->OSC16MCTRL.bit.FSEL = 3; + OSCCTRL->OSC16MCTRL.bit.ONDEMAND = 0; + OSCCTRL->OSC16MCTRL.bit.RUNSTDBY = 0; - /* Select the correct generator */ - while (GCLK->SYNCBUSY.reg & GCLK_SYNCBUSY_GENCTRL(0)); - GCLK->GENCTRL[0].reg = ( - GCLK_GENCTRL_GENEN /* enable gclk */ - | GCLK_GENCTRL_SRC_OSC16M - ); + /* Setup GCLK generators */ + _gclk_setup(0, GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_OSC16M); + _gclk_setup(1, GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_OSCULP32K); + + lpm_arch_init(); } diff --git a/cpu/saml21/lpm_arch.c b/cpu/saml21/lpm_arch.c index ac11c39252..1f50448564 100644 --- a/cpu/saml21/lpm_arch.c +++ b/cpu/saml21/lpm_arch.c @@ -18,16 +18,58 @@ * @} */ +#include + #include "arch/lpm_arch.h" +#include "cpu.h" +#include "kernel.h" + +#define ENABLE_DEBUG 0 +#include "debug.h" void lpm_arch_init(void) { - // TODO + MCLK->APBAMASK.reg |= MCLK_APBAMASK_PM; + PM->CTRLA.reg = PM_CTRLA_MASK & (~PM_CTRLA_IORET); + + SUPC->BOD33.bit.ENABLE=0; + + lpm_prevent_sleep = 1; } enum lpm_mode lpm_arch_set(enum lpm_mode target) { - // TODO + uint32_t mode; + switch(target) { + case LPM_IDLE: + DEBUG("lpm_arch_set(): setting IDLE mode.\n"); + mode = PM_SLEEPCFG_SLEEPMODE_IDLE2; + break; + case LPM_SLEEP: + DEBUG("lpm_arch_set(): setting STANDBY mode.\n"); + mode = PM_SLEEPCFG_SLEEPMODE_STANDBY; + break; + case LPM_POWERDOWN: + DEBUG("lpm_arch_set(): setting BACKUP mode.\n"); + mode = PM_SLEEPCFG_SLEEPMODE_BACKUP; + break; + default: + DEBUG("lpm_arch_set(): unhandled low-power mode.\n"); + return 0; + } + + /* write sleep configuration */ + PM->SLEEPCFG.bit.SLEEPMODE = mode; + + /* make sure value has been set */ + while (PM->SLEEPCFG.bit.SLEEPMODE != mode); + + /* ensure all memory accesses have completed */ + __DSB(); + + /* go to sleep mode (issue wait-for-interrupt instruction) */ + __WFI(); + return 0; } diff --git a/cpu/saml21/periph/uart.c b/cpu/saml21/periph/uart.c index 08d0f67e0c..480f64fb7f 100644 --- a/cpu/saml21/periph/uart.c +++ b/cpu/saml21/periph/uart.c @@ -123,7 +123,7 @@ int uart_init_blocking(uart_t uart, uint32_t baudrate) | SERCOM_USART_CTRLA_RXPO(0x1) \ | SERCOM_USART_CTRLA_SAMPR(0x0) \ | SERCOM_USART_CTRLA_MODE(0x1) \ - | SERCOM_USART_CTRLA_RUNSTDBY; + | (UART_0_RUNSTDBY ? SERCOM_USART_CTRLA_RUNSTDBY : 0); /* Set baud rate */ UART_0_DEV.BAUD.bit.BAUD = baud_calculated;