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:
commit
defdf1e6f5
@ -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.
|
||||
*
|
||||
|
@ -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 */
|
||||
|
@ -82,5 +82,5 @@ void pm_set(unsigned mode)
|
||||
break;
|
||||
}
|
||||
|
||||
cortexm_sleep(deep);
|
||||
sam0_cortexm_sleep(deep);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -47,5 +47,5 @@ void pm_set(unsigned mode)
|
||||
while (PM->SLEEPCFG.bit.SLEEPMODE != _mode) {}
|
||||
}
|
||||
|
||||
cortexm_sleep(0);
|
||||
sam0_cortexm_sleep(0);
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -55,5 +55,5 @@ void pm_set(unsigned mode)
|
||||
while (PM->SLEEPCFG.bit.SLEEPMODE != _mode) {}
|
||||
}
|
||||
|
||||
cortexm_sleep(0);
|
||||
sam0_cortexm_sleep(0);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user