NXP S32K146 Power Manager Component分析
Posted nininiccccc
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了NXP S32K146 Power Manager Component分析相关的知识,希望对你有一定的参考价值。
今天分析一下,NXP S32K1系列的电源管理,先翻译一下S32K-RM的Chapter 39 Power Management P1141。
- 电源模式描述
电源管理控制器(PMC)提供了多个电源选项,允许用户根据需要的功能级别优化功耗。
根据用户应用程序的停止需求,有多种停止模式可供选择,它们提供某些逻辑和/或内存的状态保持、部分断电或完全断电。
对于运行模式和极低功耗运行(VLPR)模式,有相应的停止模式。 停止模式(VLPS, STOP1, STOP2)类似于Arm睡眠深度模式。 当不需要最大总线频率来支持应用需求时,VLPR工作模式可以降低运行时功耗。
该芯片不能直接从高速运行(HSRUN)模式进入停止模式。 要从HSRUN进入停止模式,芯片必须首先切换到正常运行模式。之后,它可以进入停止模式。
两种主要的操作模式是运行、停止。 等待中断(WFI)指令为芯片调用停止模式。 可用的功率模式允许应用程序只消耗执行所需的功率。 下面比较了不同的功率模式
Normal Run
默认模式退出复位; 片上电压调节器打开。
High Speed Run(HSRUN)
允许芯片的最大性能。 在这种模式下,芯片可以运行在一个更高的频率相比正常运行模式,但功能受限。 有关详细信息,请参阅模块在可用电源模式下的操作。 有关详细信息,请参阅内部时钟要求。
Normal Stop (通过WFI 指令)
将芯片置于静态状态。 在这种电源模式下,所有寄存器被保留,LVD保护被保持。 禁用NVIC。 AWIC用于从中断中唤醒。 一些外围时钟停止。 有关详细信息,请参阅模块在可用电源模式下的操作。 |
Very Low PowerRun (VLPR)
片上电压调节器处于低功耗模式,只提供足够的功率以降低频率运行芯片。 降低频率的闪存访问模式(1 MHz) LVD关 SIRC为核心、总线和外围时钟提供了一个低功耗4 MHz的源。
Very Low Power Stop (VLPS, (通过WFI 指令)
关闭低电压检测(LVD),将芯片置于静态状态。 这是可以使用引脚中断的最低功耗模式。 一些外围时钟停止。 请参见模块在各种电源模式下的运行。 支持LPTMR、RTC、CMP。 禁用NVIC。 AWIC用于从中断中唤醒。 片上电压调节器处于低功耗模式,仅提供芯片在降低频率下运行所需的功率。 所有SRAM是可操作的(内容保留和I/O状态保持)。
参阅模块在可用电源模式下的操作(Module operation in available power modes)
电源模式的切换和退出
WFI指令调用芯片的停止模式。 处理器通过中断退出低功耗模式。 关于中断操作和哪些外设可以导致中断的描述,请参见嵌套向量中断控制器(NVIC)配置。
Chapter 40
System Mode Controller (SMC)
系统模式控制器(SMC)负责排序系统进入和退出所有低功率停止和运行模式。
本章描述了所有可用的低功耗模式,进入/退出每种模式的顺序,以及每种模式下可用的功能。 SMC甚至可以在最深的低功耗模式下工作。 有关使用SMC的详细信息,请参阅AN4503: Kinetis mcu的电源管理。
模式转换>
//
#define SMC_PMCTRL_RUNM(x) (((uint32_t)(((uint32_t)(x))<<SMC_PMCTRL_RUNM_SHIFT))&SMC_PMCTRL_RUNM_MASK)
/* STOPCTRL Bit Fields */
static inline void SMC_SetRunModeControl(SMC_Type * const baseAddr,
const smc_run_mode_t runMode)
uint32_t regValue = baseAddr->PMCTRL;
regValue &= ~(SMC_PMCTRL_RUNM_MASK);
regValue |= SMC_PMCTRL_RUNM(runMode);
baseAddr->PMCTRL = regValue;
status_t SMC_SetPowerMode(SMC_Type * const baseAddr,
const smc_power_mode_config_t * const powerModeConfig)
status_t retCode;
smc_stop_mode_t stopMode;
power_manager_modes_t powerModeName = powerModeConfig->powerModeName;
/* Branch based on power mode name*/
switch (powerModeName)
case POWER_MANAGER_RUN:
/* Set to RUN mode. */
SMC_SetRunModeControl(baseAddr, SMC_RUN);
/* Wait for stat change */
if (!SMC_WaitForStatChange(baseAddr, STAT_RUN, SMC_TIMEOUT))
/* Timeout for power mode change expired. */
retCode = STATUS_MCU_TRANSITION_FAILED;
else
retCode = STATUS_SUCCESS;
break;
case POWER_MANAGER_VLPR:
/* Set power mode to VLPR*/
SMC_SetRunModeControl(baseAddr, SMC_VLPR);
/* Wait for stat change */
if (!SMC_WaitForStatChange(baseAddr, STAT_VLPR, SMC_TIMEOUT))
/* Timeout for power mode change expired. */
retCode = STATUS_MCU_TRANSITION_FAILED;
else
retCode = STATUS_SUCCESS;
break;
#if FEATURE_SMC_HAS_HIGH_SPEED_RUN_MODE
case POWER_MANAGER_HSRUN:
/* Set power mode to HSRUN */
SMC_SetRunModeControl(baseAddr, SMC_HSRUN);
/* Wait for stat change */
if (!SMC_WaitForStatChange(baseAddr, STAT_HSRUN, SMC_TIMEOUT))
/* Timeout for power mode change expired. */
retCode = STATUS_MCU_TRANSITION_FAILED;
else
retCode = STATUS_SUCCESS;
break;
#endif /* if FEATURE_SMC_HAS_HIGH_SPEED_RUN_MODE */
#if FEATURE_SMC_HAS_WAIT_VLPW
case POWER_MANAGER_WAIT:
/* Fall-through */
case POWER_MANAGER_VLPW:
/* Clear the SLEEPDEEP bit to disable deep sleep mode - WAIT */
S32_SCB->SCR &= ~S32_SCB_SCR_SLEEPDEEP_MASK;
/* Cpu is going into sleep state */
STANDBY();
retCode = STATUS_SUCCESS;
break;
#endif /* if FEATURE_SMC_HAS_WAIT_VLPW */
case POWER_MANAGER_STOP1:
/* Fall-through */
case POWER_MANAGER_STOP2:
/* Fall-through */
case POWER_MANAGER_VLPS:
if ((powerModeName == POWER_MANAGER_STOP1) || (powerModeName == POWER_MANAGER_STOP2))
stopMode = SMC_STOP;
#if FEATURE_SMC_HAS_STOPO
SMC_SetStopOption(baseAddr, powerModeConfig->stopOptionValue);
#endif
#if FEATURE_SMC_HAS_PSTOPO
SMC_SetPStopOption(baseAddr, powerModeConfig->pStopOptionValue);
#endif
else
stopMode = SMC_VLPS;
/* Set power mode to specified STOP mode*/
SMC_SetStopModeControl(baseAddr, stopMode);
/* Set the SLEEPDEEP bit to enable deep sleep mode (STOP)*/
S32_SCB->SCR |= S32_SCB_SCR_SLEEPDEEP_MASK;
/* Cpu is going into deep sleep state */
STANDBY();
retCode = STATUS_SUCCESS;
break;
default:
retCode = STATUS_UNSUPPORTED;
break;
return retCode;
static status_t POWER_SYS_SwitchToRunningPowerMode(const power_manager_user_config_t * const configPtr)
smc_power_mode_config_t modeConfig; /* SMC hardware layer configuration structure */
power_mode_stat_t currentMode = SMC_GetPowerModeStatus(SMC);
status_t returnCode = STATUS_SUCCESS;
/* Configure the running mode */
switch (configPtr->powerMode)
#if FEATURE_SMC_HAS_HIGH_SPEED_RUN_MODE
/* High speed run mode */
case POWER_MANAGER_HSRUN:
/* High speed run mode can be entered only from Run mode */
if (currentMode != STAT_HSRUN)
if (currentMode != STAT_RUN)
modeConfig.powerModeName = POWER_MANAGER_RUN;
/* Switch the mode */
returnCode = SMC_SetPowerMode(SMC, &modeConfig);
if (returnCode == STATUS_SUCCESS)
returnCode = POWER_SYS_EnterHsrunMode();
else
returnCode = STATUS_SUCCESS;
break;
#endif /* if FEATURE_SMC_HAS_HIGH_SPEED_RUN_MODE */
/* Run mode */
case POWER_MANAGER_RUN:
if (currentMode != STAT_RUN)
modeConfig.powerModeName = POWER_MANAGER_RUN;
/* Switch the mode */
returnCode = SMC_SetPowerMode(SMC, &modeConfig);
if ((returnCode == STATUS_SUCCESS) && changeClkVlp)
/* Enable all clock source */
POWER_DRV_EnableVlpClockSrc();
/* Update initialize clock configuration */
returnCode = POWER_DRV_UpdateInitClk(&sysClkConfig);
if (returnCode == STATUS_SUCCESS)
changeClkVlp = false;
break;
/* Very low power run mode */
case POWER_MANAGER_VLPR:
if (currentMode != STAT_VLPR)
/* Very low power run mode can be entered only from Run mode */
if (SMC_GetPowerModeStatus(SMC) != STAT_RUN)
modeConfig.powerModeName = POWER_MANAGER_RUN;
/* Switch the mode */
returnCode = SMC_SetPowerMode(SMC, &modeConfig);
if (STATUS_SUCCESS == returnCode)
if (!changeClkVlp)
CLOCK_DRV_GetSystemClockSource(&sysClkConfig);
returnCode = POWER_DRV_SwitchVlprClk(&sysClkConfig);
if (STATUS_SUCCESS == returnCode)
changeClkVlp = true;
modeConfig.powerModeName = POWER_MANAGER_VLPR;
/* Disable all clock source except SIRC */
POWER_DRV_DisableVlpClockSrc();
/* Switch the mode */
returnCode = SMC_SetPowerMode(SMC, &modeConfig);
else
returnCode = STATUS_SUCCESS;
break;
/* Wait mode */
default:
/* invalid power mode */
returnCode = STATUS_UNSUPPORTED;
modeConfig.powerModeName = POWER_MANAGER_MAX;
break;
return returnCode;
status_t POWER_SYS_DoSetMode(const power_manager_user_config_t * const configPtr)
status_t returnCode; /* Function return */
/* Check whether the power mode is a sleeping or a running power mode */
if (configPtr->powerMode <= POWER_MANAGER_VLPR)
/* Switch to a running power mode */
returnCode = POWER_SYS_SwitchToRunningPowerMode(configPtr);
else
/* Switch to a sleeping power mode */
returnCode = POWER_SYS_SwitchToSleepingPowerMode(configPtr);
return returnCode;
status_t POWER_SYS_SetMode(uint8_t powerModeIndex,
power_manager_policy_t policy)
power_manager_user_config_t * configPtr; /* Local pointer to the requested user-defined power mode configuration */
status_t returnCode; /* Function return */
status_t errorCode;
bool successfulSwitch; /* Power mode switch is successful or not */
uint8_t currentStaticCallback = 0U; /* Index to array of statically registered call-backs */
power_manager_notify_struct_t notifyStruct; /* Callback notification structure */
/* Driver is already initialized. */
DEV_ASSERT(gPowerManagerState.configs != NULL);
DEV_ASSERT(gPowerManagerState.configsNumber != 0U);
/* Power mode index is valid. */
DEV_ASSERT(powerModeIndex < gPowerManagerState.configsNumber);
/* Initialization of local pointer to the requested user-defined power mode configuration */
configPtr = (*gPowerManagerState.configs)[powerModeIndex];
/* Reference to the requested user-defined power mode configuration is valid. */
DEV_ASSERT(configPtr != NULL);
/* Default value of handle of last call-back that returned error */
gPowerManagerState.errorCallbackIndex = gPowerManagerState.staticCallbacksNumber;
/* Set the transaction policy in the notification structure */
notifyStruct.policy = policy;
/* Set the target power mode configuration in the notification structure */
notifyStruct.targetPowerConfigIndex = powerModeIndex;
notifyStruct.targetPowerConfigPtr = configPtr;
/* Notify those which asked to be called before the power mode change */
notifyStruct.notifyType = POWER_MANAGER_NOTIFY_BEFORE;
returnCode = POWER_SYS_CallbacksManagement(¬ifyStruct, ¤tStaticCallback, policy);
/* Power mode switch */
/* In case that any call-back returned error code and policy doesn't force the mode switch go to after switch call-backs */
if ((policy == POWER_MANAGER_POLICY_FORCIBLE) || (returnCode == STATUS_SUCCESS))
returnCode = POWER_SYS_DoSetMode(configPtr);
successfulSwitch = (STATUS_SUCCESS == returnCode);
else
/* Unsuccessful switch */
successfulSwitch = false;
if (successfulSwitch)
/* End of successful switch */
/* Update current configuration index */
gPowerManagerState.currentConfig = powerModeIndex;
/* Notify those which asked to be called after the power mode change */
notifyStruct.notifyType = POWER_MANAGER_NOTIFY_AFTER;
returnCode = POWER_SYS_CallbacksManagement(¬ifyStruct, ¤tStaticCallback, POWER_MANAGER_POLICY_FORCIBLE);
else
/* End of unsuccessful switch */
/* Notify those which have been called before the power mode change */
notifyStruct.notifyType = POWER_MANAGER_NOTIFY_RECOVER;
errorCode = POWER_SYS_CallbacksManagement(¬ifyStruct, ¤tStaticCallback, POWER_MANAGER_POLICY_FORCIBLE);
(void)(errorCode);
return returnCode;
关于函数全部在SDK封装好了,拿来就用就好。不会用可以参考官方例程。
以上是关于NXP S32K146 Power Manager Component分析的主要内容,如果未能解决你的问题,请参考以下文章