You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
583 lines
18 KiB
583 lines
18 KiB
/*
|
|
* Copyright (c) 2019, Erich Styger
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
#include "platform.h"
|
|
#include "LowPower.h"
|
|
#include "fsl_pit.h"
|
|
#include "fsl_smc.h"
|
|
#include "fsl_lptmr.h"
|
|
#include "fsl_port.h"
|
|
#include "fsl_llwu.h"
|
|
|
|
static smc_power_state_t LP_curPowerState;
|
|
static uint8_t s_wakeupTimeout; /* Wakeup timeout. (Unit: Second) */
|
|
static app_wakeup_source_t s_wakeupSource; /* Wakeup source. */
|
|
|
|
#define APP_WAKEUP_BUTTON_GPIO GPIOC
|
|
#define APP_WAKEUP_BUTTON_PORT PORTC
|
|
#define APP_WAKEUP_BUTTON_GPIO_PIN 1
|
|
#define APP_WAKEUP_BUTTON_IRQ PORTC_IRQn
|
|
#define APP_WAKEUP_BUTTON_IRQ_HANDLER PORTC_IRQHandler
|
|
#define APP_WAKEUP_BUTTON_IRQ_TYPE kPORT_InterruptFallingEdge
|
|
|
|
#define LLWU_LPTMR_IDX 0U /* LLWU_M0IF */
|
|
#define LLWU_WAKEUP_PIN_IDX 6U /* LLWU_P6 */
|
|
#define LLWU_WAKEUP_PIN_TYPE kLLWU_ExternalPinFallingEdge
|
|
|
|
static void LP_SetClockVlpr(void) {
|
|
const sim_clock_config_t simConfig = {
|
|
.pllFllSel = 3U, /* PLLFLLSEL select IRC48MCLK. */
|
|
.er32kSrc = 2U, /* ERCLK32K selection, use RTC. */
|
|
.clkdiv1 = 0x00040000U, /* SIM_CLKDIV1. */
|
|
};
|
|
|
|
CLOCK_SetSimSafeDivs();
|
|
CLOCK_SetInternalRefClkConfig(kMCG_IrclkEnable, kMCG_IrcFast, 0U);
|
|
|
|
/* MCG works in PEE mode now, will switch to BLPI mode. */
|
|
|
|
CLOCK_ExternalModeToFbeModeQuick(); /* Enter FBE. */
|
|
CLOCK_SetFbiMode(kMCG_Dmx32Default, kMCG_DrsLow, NULL); /* Enter FBI. */
|
|
CLOCK_SetLowPowerEnable(true); /* Enter BLPI. */
|
|
|
|
CLOCK_SetSimConfig(&simConfig);
|
|
}
|
|
|
|
static void LP_SetClockRunFromVlpr(void) {
|
|
const sim_clock_config_t simConfig = {
|
|
.pllFllSel = 1U, /* PLLFLLSEL select PLL. */
|
|
.er32kSrc = 2U, /* ERCLK32K selection, use RTC. */
|
|
.clkdiv1 = 0x01230000U, /* SIM_CLKDIV1. */
|
|
};
|
|
|
|
const mcg_pll_config_t pll0Config = {
|
|
.enableMode = 0U,
|
|
.prdiv = 0x3U,
|
|
.vdiv = 0x10U,
|
|
};
|
|
|
|
CLOCK_SetSimSafeDivs();
|
|
|
|
/* Currently in BLPI mode, will switch to PEE mode. */
|
|
/* Enter FBI. */
|
|
CLOCK_SetLowPowerEnable(false);
|
|
/* Enter FBE. */
|
|
CLOCK_SetFbeMode(3U, kMCG_Dmx32Default, kMCG_DrsLow, NULL);
|
|
/* Enter PBE. */
|
|
CLOCK_SetPbeMode(kMCG_PllClkSelPll0, &pll0Config);
|
|
/* Enter PEE. */
|
|
CLOCK_SetPeeMode();
|
|
|
|
CLOCK_SetSimConfig(&simConfig);
|
|
}
|
|
|
|
static void LP_SetClockHsrun(void) {
|
|
const sim_clock_config_t simConfig = {
|
|
.pllFllSel = 1U, /* PLLFLLSEL select PLL. */
|
|
.er32kSrc = 2U, /* ERCLK32K selection, use RTC. */
|
|
.clkdiv1 = 0x01340000U, /* SIM_CLKDIV1. */
|
|
};
|
|
|
|
const mcg_pll_config_t pll0Config = {
|
|
.enableMode = 0U,
|
|
.prdiv = 0x1U,
|
|
.vdiv = 0x6U,
|
|
};
|
|
|
|
CLOCK_SetPbeMode(kMCG_PllClkSelPll0, &pll0Config);
|
|
CLOCK_SetPeeMode();
|
|
|
|
CLOCK_SetSimConfig(&simConfig);
|
|
}
|
|
|
|
static void LP_SetClockRunFromHsrun(void) {
|
|
const sim_clock_config_t simConfig = {
|
|
.pllFllSel = 1U, /* PLLFLLSEL select PLL. */
|
|
.er32kSrc = 2U, /* ERCLK32K selection, use RTC. */
|
|
.clkdiv1 = 0x01230000U, /* SIM_CLKDIV1. */
|
|
};
|
|
|
|
const mcg_pll_config_t pll0Config = {
|
|
.enableMode = 0U,
|
|
.prdiv = 0x3U,
|
|
.vdiv = 0x10U,
|
|
};
|
|
|
|
CLOCK_SetPbeMode(kMCG_PllClkSelPll0, &pll0Config);
|
|
CLOCK_SetPeeMode();
|
|
|
|
CLOCK_SetSimConfig(&simConfig);
|
|
}
|
|
|
|
/*
|
|
* Check whether could switch to target power mode from current mode.
|
|
* Return true if could switch, return false if could not switch.
|
|
*/
|
|
bool LP_CheckPowerMode(smc_power_state_t curPowerState, app_power_mode_t targetPowerMode) {
|
|
bool modeValid = true;
|
|
|
|
/*
|
|
* Check whether the mode change is allowed.
|
|
* 1. If current mode is HSRUN mode, the target mode must be RUN mode.
|
|
* 2. If current mode is RUN mode, the target mode must not be VLPW mode.
|
|
* 3. If current mode is VLPR mode, the target mode must not be HSRUN/WAIT/STOP mode.
|
|
* 4. If already in the target mode.
|
|
*/
|
|
switch (curPowerState) {
|
|
case kSMC_PowerStateHsrun:
|
|
if (kAPP_PowerModeRun != targetPowerMode) {
|
|
//PRINTF("Current mode is HSRUN, please choose RUN mode as the target mode.\r\n");
|
|
modeValid = false;
|
|
}
|
|
break;
|
|
|
|
case kSMC_PowerStateRun:
|
|
if (kAPP_PowerModeVlpw == targetPowerMode) {
|
|
//PRINTF("Could not enter VLPW mode from RUN mode.\r\n");
|
|
modeValid = false;
|
|
}
|
|
break;
|
|
|
|
case kSMC_PowerStateVlpr:
|
|
if ((kAPP_PowerModeWait == targetPowerMode) || (kAPP_PowerModeHsrun == targetPowerMode) ||
|
|
(kAPP_PowerModeStop == targetPowerMode)) {
|
|
//PRINTF("Could not enter HSRUN/STOP/WAIT modes from VLPR mode.\r\n");
|
|
modeValid = false;
|
|
}
|
|
break;
|
|
default:
|
|
//PRINTF("Wrong power state.\r\n");
|
|
modeValid = false;
|
|
break;
|
|
}
|
|
|
|
if (!modeValid) {
|
|
return false;
|
|
}
|
|
|
|
/* Don't need to change power mode if current mode is already the target mode. */
|
|
if (((kAPP_PowerModeRun == targetPowerMode) && (kSMC_PowerStateRun == curPowerState)) ||
|
|
((kAPP_PowerModeHsrun == targetPowerMode) && (kSMC_PowerStateHsrun == curPowerState)) ||
|
|
((kAPP_PowerModeVlpr == targetPowerMode) && (kSMC_PowerStateVlpr == curPowerState)))
|
|
{
|
|
//PRINTF("Already in the target power mode.\r\n");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
* Power mode switch.
|
|
*/
|
|
void LP_PowerModeSwitch(smc_power_state_t curPowerState, app_power_mode_t targetPowerMode) {
|
|
smc_power_mode_vlls_config_t vlls_config;
|
|
vlls_config.enablePorDetectInVlls0 = true;
|
|
smc_power_mode_lls_config_t lls_config;
|
|
lls_config.subMode = kSMC_StopSub3;
|
|
|
|
switch (targetPowerMode) {
|
|
case kAPP_PowerModeVlpr:
|
|
LP_SetClockVlpr();
|
|
SMC_SetPowerModeVlpr(SMC);
|
|
while (kSMC_PowerStateVlpr != SMC_GetPowerModeState(SMC))
|
|
{
|
|
}
|
|
break;
|
|
|
|
case kAPP_PowerModeRun:
|
|
/* If enter RUN from HSRUN, first change clock. */
|
|
if (kSMC_PowerStateHsrun == curPowerState) {
|
|
LP_SetClockRunFromHsrun();
|
|
}
|
|
|
|
/* Power mode change. */
|
|
SMC_SetPowerModeRun(SMC);
|
|
while (kSMC_PowerStateRun != SMC_GetPowerModeState(SMC))
|
|
{
|
|
}
|
|
|
|
/* If enter RUN from VLPR, change clock after the power mode change. */
|
|
if (kSMC_PowerStateVlpr == curPowerState)
|
|
{
|
|
LP_SetClockRunFromVlpr();
|
|
}
|
|
break;
|
|
|
|
case kAPP_PowerModeHsrun:
|
|
SMC_SetPowerModeHsrun(SMC);
|
|
while (kSMC_PowerStateHsrun != SMC_GetPowerModeState(SMC))
|
|
{
|
|
}
|
|
|
|
LP_SetClockHsrun(); /* Change clock setting after power mode change. */
|
|
break;
|
|
|
|
case kAPP_PowerModeWait:
|
|
SMC_PreEnterWaitModes();
|
|
SMC_SetPowerModeWait(SMC);
|
|
SMC_PostExitWaitModes();
|
|
break;
|
|
|
|
case kAPP_PowerModeStop:
|
|
SMC_PreEnterStopModes();
|
|
SMC_SetPowerModeStop(SMC, kSMC_PartialStop);
|
|
SMC_PostExitStopModes();
|
|
break;
|
|
|
|
case kAPP_PowerModeVlpw:
|
|
SMC_PreEnterWaitModes();
|
|
SMC_SetPowerModeVlpw(SMC);
|
|
SMC_PostExitWaitModes();
|
|
break;
|
|
|
|
case kAPP_PowerModeVlps:
|
|
SMC_PreEnterStopModes();
|
|
SMC_SetPowerModeVlps(SMC);
|
|
SMC_PostExitStopModes();
|
|
break;
|
|
|
|
case kAPP_PowerModeLls:
|
|
SMC_PreEnterStopModes();
|
|
SMC_SetPowerModeLls(SMC, &lls_config);
|
|
SMC_PostExitStopModes();
|
|
break;
|
|
|
|
case kAPP_PowerModeVlls0:
|
|
vlls_config.subMode = kSMC_StopSub0;
|
|
SMC_PreEnterStopModes();
|
|
SMC_SetPowerModeVlls(SMC, &vlls_config);
|
|
SMC_PostExitStopModes();
|
|
break;
|
|
|
|
case kAPP_PowerModeVlls1:
|
|
vlls_config.subMode = kSMC_StopSub1;
|
|
SMC_PreEnterStopModes();
|
|
SMC_SetPowerModeVlls(SMC, &vlls_config);
|
|
SMC_PostExitStopModes();
|
|
break;
|
|
|
|
case kAPP_PowerModeVlls2:
|
|
vlls_config.subMode = kSMC_StopSub2;
|
|
SMC_PreEnterStopModes();
|
|
SMC_SetPowerModeVlls(SMC, &vlls_config);
|
|
SMC_PostExitStopModes();
|
|
break;
|
|
|
|
case kAPP_PowerModeVlls3:
|
|
vlls_config.subMode = kSMC_StopSub3;
|
|
SMC_PreEnterStopModes();
|
|
SMC_SetPowerModeVlls(SMC, &vlls_config);
|
|
SMC_PostExitStopModes();
|
|
break;
|
|
|
|
default:
|
|
//PRINTF("Wrong value");
|
|
break;
|
|
}
|
|
}
|
|
|
|
void LP_PowerPreSwitchHook(smc_power_state_t originPowerState, app_power_mode_t targetMode) {
|
|
#if 0
|
|
/* Wait for debug console output finished. */
|
|
while (!(kUART_TransmissionCompleteFlag & UART_GetStatusFlags((UART_Type *)BOARD_DEBUG_UART_BASEADDR)))
|
|
{
|
|
}
|
|
DbgConsole_Deinit();
|
|
#endif
|
|
if ((kAPP_PowerModeRun != targetMode) && (kAPP_PowerModeHsrun != targetMode) && (kAPP_PowerModeVlpr != targetMode)) {
|
|
/*
|
|
* Set pin for current leakage.
|
|
* Debug console RX pin: Set to pinmux to disable.
|
|
* Debug console TX pin: Don't need to change.
|
|
*/
|
|
// PORT_SetPinMux(DEBUG_CONSOLE_RX_PORT, DEBUG_CONSOLE_RX_PIN, kPORT_PinDisabledOrAnalog);
|
|
}
|
|
}
|
|
|
|
void LP_PowerPostSwitchHook(smc_power_state_t originPowerState, app_power_mode_t targetMode) {
|
|
smc_power_state_t powerState = SMC_GetPowerModeState(SMC);
|
|
|
|
/*
|
|
* For some other platforms, if enter LLS mode from VLPR mode, when wake-up, the
|
|
* power mode is VLPR. But for some platforms, if enter LLS mode from VLPR mode,
|
|
* when wakeup, the power mode is RUN. In this case, the clock setting is still
|
|
* VLPR mode setting, so change to RUN mode setting here.
|
|
*/
|
|
if ((kSMC_PowerStateVlpr == originPowerState) && (kSMC_PowerStateRun == powerState)) {
|
|
LP_SetClockRunFromVlpr();
|
|
}
|
|
|
|
if ((kAPP_PowerModeRun != targetMode) && (kAPP_PowerModeHsrun != targetMode) && (kAPP_PowerModeVlpr != targetMode)) {
|
|
/*
|
|
* Debug console RX pin is set to disable for current leakage, need to re-configure pinmux.
|
|
* Debug console TX pin: Don't need to change.
|
|
*/
|
|
//PORT_SetPinMux(DEBUG_CONSOLE_RX_PORT, DEBUG_CONSOLE_RX_PIN, DEBUG_CONSOLE_RX_PINMUX);
|
|
}
|
|
|
|
/*
|
|
* If enter stop modes when MCG in PEE mode, then after wake-up, the MCG is in PBE mode,
|
|
* need to enter PEE mode manually.
|
|
*/
|
|
if ((kAPP_PowerModeRun != targetMode) && (kAPP_PowerModeWait != targetMode) && (kAPP_PowerModeVlpw != targetMode) &&
|
|
(kAPP_PowerModeHsrun != targetMode) && (kAPP_PowerModeVlpr != targetMode))
|
|
{
|
|
if (kSMC_PowerStateRun == originPowerState) {
|
|
/* Wait for PLL lock. */
|
|
while (!(kMCG_Pll0LockFlag & CLOCK_GetStatusFlags()))
|
|
{
|
|
}
|
|
CLOCK_SetPeeMode();
|
|
}
|
|
}
|
|
/* Set debug console clock source. */
|
|
//APP_InitDebugConsole();
|
|
}
|
|
|
|
/* Get wake-up source by user input. */
|
|
static app_wakeup_source_t LP_GetWakeupSource(void) {
|
|
#if 0
|
|
uint8_t ch;
|
|
|
|
while (1)
|
|
{
|
|
PRINTF("Select the wake up source:\r\n");
|
|
PRINTF("Press T for LPTMR - Low Power Timer\r\n");
|
|
PRINTF("Press S for switch/button %s. \r\n", APP_WAKEUP_BUTTON_NAME);
|
|
|
|
PRINTF("\r\nWaiting for key press..\r\n\r\n");
|
|
|
|
ch = GETCHAR();
|
|
|
|
if ((ch >= 'a') && (ch <= 'z'))
|
|
{
|
|
ch -= 'a' - 'A';
|
|
}
|
|
|
|
if (ch == 'T')
|
|
{
|
|
return kAPP_WakeupSourceLptmr;
|
|
}
|
|
else if (ch == 'S')
|
|
{
|
|
return kAPP_WakeupSourcePin;
|
|
}
|
|
else
|
|
{
|
|
PRINTF("Wrong value!\r\n");
|
|
}
|
|
}
|
|
#else
|
|
return kAPP_WakeupSourceLptmr;
|
|
#endif
|
|
}
|
|
|
|
void LP_SetWakeupConfig(app_power_mode_t targetMode) {
|
|
/* Set LPTMR timeout value. */
|
|
if (kAPP_WakeupSourceLptmr == s_wakeupSource)
|
|
{
|
|
LPTMR_SetTimerPeriod(LPTMR0, (LPO_CLK_FREQ * s_wakeupTimeout) - 1U);
|
|
LPTMR_StartTimer(LPTMR0);
|
|
}
|
|
|
|
/* Set the wakeup module. */
|
|
if (kAPP_WakeupSourceLptmr == s_wakeupSource)
|
|
{
|
|
LPTMR_EnableInterrupts(LPTMR0, kLPTMR_TimerInterruptEnable);
|
|
}
|
|
else
|
|
{
|
|
PORT_SetPinInterruptConfig(APP_WAKEUP_BUTTON_PORT, APP_WAKEUP_BUTTON_GPIO_PIN, APP_WAKEUP_BUTTON_IRQ_TYPE);
|
|
}
|
|
|
|
/* If targetMode is VLLS/LLS, setup LLWU. */
|
|
if ((kAPP_PowerModeWait != targetMode) && (kAPP_PowerModeVlpw != targetMode) &&
|
|
(kAPP_PowerModeVlps != targetMode) && (kAPP_PowerModeStop != targetMode))
|
|
{
|
|
if (kAPP_WakeupSourceLptmr == s_wakeupSource)
|
|
{
|
|
LLWU_EnableInternalModuleInterruptWakup(LLWU, LLWU_LPTMR_IDX, true);
|
|
}
|
|
else
|
|
{
|
|
LLWU_SetExternalWakeupPinMode(LLWU, LLWU_WAKEUP_PIN_IDX, LLWU_WAKEUP_PIN_TYPE);
|
|
}
|
|
NVIC_EnableIRQ(LLWU_IRQn);
|
|
}
|
|
}
|
|
|
|
static uint8_t LP_GetWakeupTimeout(void) {
|
|
return 1; /* seconds */
|
|
}
|
|
|
|
/* Get wake-up timeout and wake-up source. */
|
|
void LP_GetWakeupConfig(app_power_mode_t targetMode) {
|
|
/* Get wakeup source by user input. */
|
|
if (targetMode == kAPP_PowerModeVlls0) {
|
|
/* In VLLS0 mode, the LPO is disabled, LPTMR could not work. */
|
|
// PRINTF("Not support LPTMR wakeup because LPO is disabled in VLLS0 mode.\r\n");
|
|
s_wakeupSource = kAPP_WakeupSourcePin;
|
|
} else {
|
|
/* Get wakeup source by user input. */
|
|
s_wakeupSource = LP_GetWakeupSource();
|
|
}
|
|
if (kAPP_WakeupSourceLptmr == s_wakeupSource) {
|
|
/* Wakeup source is LPTMR, user should input wakeup timeout value. */
|
|
s_wakeupTimeout = LP_GetWakeupTimeout();
|
|
// PRINTF("Will wakeup in %d seconds.\r\n", s_wakeupTimeout);
|
|
} else {
|
|
// PRINTF("Press %s to wake up.\r\n", APP_WAKEUP_BUTTON_NAME);
|
|
}
|
|
}
|
|
|
|
/*!
|
|
* @brief LLWU interrupt handler.
|
|
*/
|
|
void LLWU_IRQHandler(void) {
|
|
/* If wakeup by LPTMR. */
|
|
if (LLWU_GetInternalWakeupModuleFlag(LLWU, LLWU_LPTMR_IDX))
|
|
{
|
|
/* Disable lptmr as a wakeup source, so that lptmr's IRQ Handler will be executed when reset from VLLSx mode. */
|
|
LLWU_EnableInternalModuleInterruptWakup(LLWU, LLWU_LPTMR_IDX, false);
|
|
}
|
|
/* If wakeup by external pin. */
|
|
if (LLWU_GetExternalWakeupPinFlag(LLWU, LLWU_WAKEUP_PIN_IDX))
|
|
{
|
|
/* Disable WAKEUP pin as a wakeup source, so that WAKEUP pin's IRQ Handler will be executed when reset from
|
|
* VLLSx mode. */
|
|
LLWU_ClearExternalWakeupPinFlag(LLWU, LLWU_WAKEUP_PIN_IDX);
|
|
}
|
|
/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping
|
|
exception return operation might vector to incorrect interrupt */
|
|
__DSB();
|
|
}
|
|
|
|
void LPTMR0_IRQHandler(void) {
|
|
if (kLPTMR_TimerInterruptEnable & LPTMR_GetEnabledInterrupts(LPTMR0)) {
|
|
LPTMR_DisableInterrupts(LPTMR0, kLPTMR_TimerInterruptEnable);
|
|
LPTMR_ClearStatusFlags(LPTMR0, kLPTMR_TimerCompareFlag);
|
|
LPTMR_StopTimer(LPTMR0);
|
|
}
|
|
/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping
|
|
exception return operation might vector to incorrect interrupt */
|
|
__DSB();
|
|
}
|
|
|
|
void PORTC_IRQHandler(void) {
|
|
if ((1U << APP_WAKEUP_BUTTON_GPIO_PIN) & PORT_GetPinsInterruptFlags(APP_WAKEUP_BUTTON_PORT)) {
|
|
/* Disable interrupt. */
|
|
PORT_SetPinInterruptConfig(APP_WAKEUP_BUTTON_PORT, APP_WAKEUP_BUTTON_GPIO_PIN, kPORT_InterruptOrDMADisabled);
|
|
PORT_ClearPinsInterruptFlags(APP_WAKEUP_BUTTON_PORT, (1U << APP_WAKEUP_BUTTON_GPIO_PIN));
|
|
}
|
|
/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping
|
|
exception return operation might vector to incorrect interrupt */
|
|
__DSB();
|
|
}
|
|
|
|
|
|
|
|
#if LP_MODE==LP_MODE_WAIT || LP_MODE==LP_MODE_STOP
|
|
#define PIT_BASEADDR PIT
|
|
#define PIT_SOURCE_CLOCK CLOCK_GetFreq(kCLOCK_BusClk)
|
|
#define PIT_CHANNEL kPIT_Chnl_0
|
|
#define PIT_HANDLER PIT0_IRQHandler
|
|
#define PIT_IRQ_ID PIT0_IRQn
|
|
|
|
|
|
void PIT_HANDLER(void) {
|
|
PIT_ClearStatusFlags(PIT_BASEADDR, PIT_CHANNEL, kPIT_TimerFlag);
|
|
__DSB();
|
|
}
|
|
|
|
static void ConfigurePIT(void) {
|
|
pit_config_t config;
|
|
|
|
PIT_GetDefaultConfig(&config);
|
|
config.enableRunInDebug = false;
|
|
PIT_Init(PIT_BASEADDR, &config);
|
|
PIT_SetTimerPeriod(PIT_BASEADDR, PIT_CHANNEL, MSEC_TO_COUNT(1*1000U, PIT_SOURCE_CLOCK));
|
|
PIT_EnableInterrupts(PIT_BASEADDR, PIT_CHANNEL, kPIT_TimerInterruptEnable);
|
|
NVIC_SetPriority(PIT_IRQ_ID, 0);
|
|
EnableIRQ(PIT_IRQ_ID);
|
|
PIT_StartTimer(PIT_BASEADDR, PIT_CHANNEL);
|
|
}
|
|
#endif
|
|
|
|
void LP_EnterLowPower(app_power_mode_t targetPowerMode) {
|
|
bool needSetWakeup;
|
|
|
|
if (!LP_CheckPowerMode(LP_curPowerState, targetPowerMode)) {
|
|
return;
|
|
}
|
|
/* If target mode is RUN/VLPR/HSRUN, don't need to set wakeup source. */
|
|
if ((kAPP_PowerModeRun == targetPowerMode) || (kAPP_PowerModeHsrun == targetPowerMode) ||
|
|
(kAPP_PowerModeVlpr == targetPowerMode))
|
|
{
|
|
needSetWakeup = false;
|
|
} else {
|
|
needSetWakeup = true;
|
|
}
|
|
if (needSetWakeup) {
|
|
LP_GetWakeupConfig(targetPowerMode);
|
|
}
|
|
LP_PowerPreSwitchHook(LP_curPowerState, targetPowerMode);
|
|
if (needSetWakeup) {
|
|
LP_SetWakeupConfig(targetPowerMode);
|
|
}
|
|
LP_PowerModeSwitch(LP_curPowerState, targetPowerMode);
|
|
LP_PowerPostSwitchHook(LP_curPowerState, targetPowerMode);
|
|
|
|
#if 0
|
|
#if LP_MODE==LP_MODE_RUN
|
|
/* not entering any low power mode */
|
|
#elif LP_MODE==LP_MODE_WAIT
|
|
SMC_SetPowerModeWait(SMC);
|
|
/* next interrupt will wake me up */
|
|
#elif LP_MODE==LP_MODE_STOP
|
|
SMC_SetPowerModeStop(SMC, kSMC_PartialStop2); /* Partial Stop with system clock disabled and bus clock enabled */
|
|
/* next interrupt will wake me up */
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
smc_power_state_t LP_GetCurrPowerMode(void) {
|
|
return LP_curPowerState;
|
|
}
|
|
|
|
static void LP_InitLPTMR(void) {
|
|
static const lptmr_config_t LPTMR_config = {.timerMode = kLPTMR_TimerModeTimeCounter,
|
|
.pinSelect = kLPTMR_PinSelectInput_0,
|
|
.pinPolarity = kLPTMR_PinPolarityActiveHigh,
|
|
.enableFreeRunning = false,
|
|
.bypassPrescaler = true,
|
|
.prescalerClockSource = kLPTMR_PrescalerClock_1,
|
|
.value = kLPTMR_Prescale_Glitch_0};
|
|
|
|
/* Initialize the LPTMR */
|
|
LPTMR_Init(LPTMR0, &LPTMR_config);
|
|
/* Set LPTMR period to 1000000us */
|
|
LPTMR_SetTimerPeriod(LPTMR0, 1000);
|
|
/* Configure timer interrupt */
|
|
LPTMR_EnableInterrupts(LPTMR0, kLPTMR_TimerInterruptEnable);
|
|
/* Enable interrupt LPTMR0_IRQn request in the NVIC */
|
|
EnableIRQ(LPTMR0_IRQn);
|
|
}
|
|
|
|
void LP_Init(void) {
|
|
LP_curPowerState = SMC_GetPowerModeState(SMC);
|
|
/* initialize LLWU */
|
|
EnableIRQ(LLWU_IRQn);
|
|
|
|
LP_InitLPTMR();
|
|
|
|
#if LP_MODE==LP_MODE_RUN
|
|
/* not entering any low power mode */
|
|
#elif LP_MODE==LP_MODE_WAIT
|
|
ConfigurePIT(); /* configure timer used as wake-up source */
|
|
#elif LP_MODE==LP_MODE_STOP
|
|
ConfigurePIT(); /* configure timer used as wake-up source */
|
|
#endif
|
|
}
|
|
|