cpu/kinetis: implement power modes for pm_layered
This commit is contained in:
parent
00b14cce27
commit
ae7ec96731
@ -18,5 +18,6 @@ else ifneq (,$(filter periph_mcg,$(FEATURES_USED)))
|
||||
endif
|
||||
|
||||
USEMODULE += periph_wdog
|
||||
USEMODULE += pm_layered
|
||||
|
||||
include $(RIOTCPU)/cortexm_common/Makefile.dep
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
FEATURES_PROVIDED += periph_cpuid
|
||||
FEATURES_PROVIDED += periph_pm
|
||||
|
||||
# TRNG driver is not implemented for mkw41z models
|
||||
_KINETIS_CPU_MODELS_WITHOUT_HWRNG += mkw41z256vht4 mkw41z512vht4
|
||||
|
||||
@ -130,9 +130,32 @@ typedef uint16_t gpio_t;
|
||||
#define PERIPH_TIMER_PROVIDES_SET
|
||||
|
||||
/**
|
||||
* @brief number of usable power modes
|
||||
* @name Kinetis power mode configuration
|
||||
* @{
|
||||
*/
|
||||
#define PM_NUM_MODES (1U)
|
||||
#define PM_NUM_MODES (3U)
|
||||
enum {
|
||||
KINETIS_PM_LLS = 0,
|
||||
KINETIS_PM_VLPS = 1,
|
||||
KINETIS_PM_STOP = 2,
|
||||
KINETIS_PM_WAIT = 3,
|
||||
};
|
||||
#if MODULE_PM_LAYERED
|
||||
#include "pm_layered.h"
|
||||
/**
|
||||
* @brief pm_block iff pm_layered is used
|
||||
*/
|
||||
#define PM_BLOCK(x) pm_block(x)
|
||||
/**
|
||||
* @brief pm_unblock iff pm_layered is used
|
||||
*/
|
||||
#define PM_UNBLOCK(x) pm_unblock(x)
|
||||
#else
|
||||
/* ignore these calls when not using pm_layered */
|
||||
#define PM_BLOCK(x)
|
||||
#define PM_UNBLOCK(x)
|
||||
#endif
|
||||
/** @} */
|
||||
|
||||
#ifdef RTC
|
||||
/* All Kinetis CPUs have exactly one RTC hardware module, except for the KL02
|
||||
|
||||
@ -26,17 +26,92 @@
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
/**
|
||||
* @note The current PM implementation is very much simplified down to only
|
||||
* using the 'WAIT' mode. This implementation must be further expanded
|
||||
* to make use of the available and more efficient (deep) sleep modes
|
||||
* of the Kinetis CPUs.
|
||||
*/
|
||||
/* Set to 1 to use the LEDx macros to show which sleep mode is entered */
|
||||
#define ENABLE_LEDS (0)
|
||||
|
||||
#if ENABLE_LEDS
|
||||
#include "board.h"
|
||||
#define PM_LED(x, state) LED ## x ## _ ## state
|
||||
#else
|
||||
#define PM_LED(x, state)
|
||||
#endif
|
||||
|
||||
/* SMC_PMCTRL_STOPM masks */
|
||||
enum {
|
||||
SMC_PMCTRL_STOPM_STOP = 0,
|
||||
/* 1 is reserved */
|
||||
SMC_PMCTRL_STOPM_VLPS = 2,
|
||||
SMC_PMCTRL_STOPM_LLS = 3,
|
||||
/* VLLS is not supported */
|
||||
};
|
||||
|
||||
/** Configure which stop mode will be entered when cortexm_sleep(1) is called */
|
||||
static inline void pm_stopm(uint8_t stopm)
|
||||
{
|
||||
SMC->PMCTRL = (SMC->PMCTRL & ~(SMC_PMCTRL_STOPM_MASK)) | SMC_PMCTRL_STOPM(stopm);
|
||||
}
|
||||
|
||||
void pm_set(unsigned mode)
|
||||
{
|
||||
unsigned deep = 1;
|
||||
switch (mode) {
|
||||
case 0:
|
||||
cortexm_sleep(0);
|
||||
/* Only the CPU stops in this mode. No clocks or peripherals are powered
|
||||
* off. This state should always be safe to use, as any interrupt will
|
||||
* wake it. Power consumption in this state is reduced by about 50%. */
|
||||
case KINETIS_PM_WAIT: /* 3 - ARM Sleep */
|
||||
/* WAIT */
|
||||
deep = 0;
|
||||
PM_LED(0, ON);
|
||||
break;
|
||||
|
||||
/* Some system clocks are stopped in this mode. Usage, means of waking,
|
||||
* and power consumption depend heavily on board-level clock and
|
||||
* peripheral configuration.*/
|
||||
/* If the debug hardware has been used since the last POR, the debug
|
||||
* hardware as well as the clock needed to support it will stay on in
|
||||
* this mode. Thus, after flashing, issue a POR before testing it. */
|
||||
case KINETIS_PM_STOP: /* 2 - ARM Deep Sleep */
|
||||
/* STOP */
|
||||
pm_stopm(SMC_PMCTRL_STOPM_STOP);
|
||||
PM_LED(1, ON);
|
||||
break;
|
||||
|
||||
/* Some system clocks are stopped in this mode. Usage, means of waking,
|
||||
* and power consumption depend heavily on board-level clock and
|
||||
* peripheral configuration.*/
|
||||
/* If the debug hardware has been used since the last POR, the debug
|
||||
* hardware as well as the clock needed to support it will stay on in
|
||||
* this mode. Thus, after flashing, issue a POR before testing it. */
|
||||
case KINETIS_PM_VLPS: /* 1 - ARM Deep Sleep */
|
||||
/* VLPS */
|
||||
pm_stopm(SMC_PMCTRL_STOPM_VLPS);
|
||||
PM_LED(2, ON);
|
||||
break;
|
||||
|
||||
/* All clocks except 32kHz are stopped. Wakeup can occur from
|
||||
* interrupts, several (LLWU-enabled) GPIOs, RTC, or (if the board
|
||||
* configuration uses the 32kHz clock for xtimer) xtimer. Debug hardware
|
||||
* is powered off. Power consumption in this state should be on the
|
||||
* order of 5 uA for the MCU alone, with most boards having additional
|
||||
* parts that will raise this amount. */
|
||||
case KINETIS_PM_LLS: /* 0 - ARM Deep Sleep */
|
||||
/* LLSx */
|
||||
pm_stopm(SMC_PMCTRL_STOPM_LLS);
|
||||
PM_LED(0, ON);
|
||||
PM_LED(2, ON);
|
||||
/* Enable LLWU interrupt, or else we can never resume from LLS */
|
||||
/* Clear pending flag first, the LLWU has no purpose in RUN mode, so
|
||||
* if the flag is set then it must be a remainder from handling the
|
||||
* previous wakeup. */
|
||||
LLWU->F1 = 0xffu;
|
||||
LLWU->F2 = 0xffu;
|
||||
NVIC_ClearPendingIRQ(LLWU_IRQn);
|
||||
NVIC_EnableIRQ(LLWU_IRQn);
|
||||
break;
|
||||
}
|
||||
DEBUG("pm_set(%u)\n", mode);
|
||||
cortexm_sleep(deep);
|
||||
PM_LED(0, OFF);
|
||||
PM_LED(1, OFF);
|
||||
PM_LED(2, OFF);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user