1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

Merge pull request #13415 from jue89/feature/saml21-pm-low-power

cpu/sam0*: enhance power saving by switching EIC clock source during STANDBY mode
This commit is contained in:
benpicco 2020-02-24 18:00:58 +01:00 committed by GitHub
commit defdf1e6f5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 128 additions and 8 deletions

View File

@ -352,6 +352,38 @@ 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
*
* @param[in] deep
*/
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
}
/**
* @brief Returns the frequency of a GCLK provider.
*

View File

@ -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,76 @@ 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)
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;
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);
}
#else
if (deep) {
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);
}
#else
if (deep) {
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 +361,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 */

View File

@ -82,5 +82,5 @@ void pm_set(unsigned mode)
break;
}
cortexm_sleep(deep);
sam0_cortexm_sleep(deep);
}

View File

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

View File

@ -47,5 +47,5 @@ void pm_set(unsigned mode)
while (PM->SLEEPCFG.bit.SLEEPMODE != _mode) {}
}
cortexm_sleep(0);
sam0_cortexm_sleep(0);
}

View File

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

View File

@ -55,5 +55,5 @@ void pm_set(unsigned mode)
while (PM->SLEEPCFG.bit.SLEEPMODE != _mode) {}
}
cortexm_sleep(0);
sam0_cortexm_sleep(0);
}