cpu: samd21: add periph/pm support

This commit is contained in:
Kaspar Schleiser 2017-01-09 18:13:04 +01:00
parent 807a190e20
commit f42e5381ee
6 changed files with 104 additions and 2 deletions

View File

@ -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

View File

@ -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

View File

@ -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 );

View File

@ -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

View File

@ -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));

89
cpu/samd21/periph/pm.c Normal file
View File

@ -0,0 +1,89 @@
/*
* Copyright (C) 2016 Kaspar Schleiser <kaspar@schleiser.de>
* 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 <thomas.eichinger@fu-berlin.de>
* @author Saurabh Singh <saurabh@cezy.co>
* @author Kaspar Schleiser <kaspar@schleiser.de>
*
* @}
*/
#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();
}