今天分析一下,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封裝好了,拿來就用就好,不會用可以參考官方例程,

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/395228.html
標籤:其他
上一篇:科技革命——智慧農業時代



>