浅析RT1170的功耗管理(1)--概述
概述
单片机的开发过程中,我们会遇到功耗模式管理的问题。
通过功耗模式管理,我们可以实现在需要高性能的时候使用高频率的时钟,以及使用大电流。
在待机的时候,使用低频率时钟,甚至关掉时钟,此时采用小电流(可以达到uA级别)。
如果采取精细化管理,这种操作可以具体到某一个内存块,或者某一个外设都可以做单独的时钟和电源管理配置。
所以功耗管理,包含以下几个方面:
- 时钟管理
- 电源管理
- 唤醒管理
其实,单片机的研发者也很不容易,因为各种应用千差万别。
如果把系统的管理功能做得很强大,就会带来极大的复杂性。
如果做得很简单,有可能又不能满足某些应用的需求。
RT1170上搞功耗管理必须知道的知识
各个相关的模块列表:
Clock Control Module (CCM) :时钟管理,源控制、时钟频率生成
Low Power Clock Gating (LPCG) :时钟使能管理
General Power Controller (GPC):功耗模式管理,功耗模式的切换以及SP的切换,是功耗管理的核心单元
Power Management Unit (PMU):电源管理,比如DCDC, LDO
System Reset Controller (SRC):复位管理
Resource Domain Controller(RDC):资源域管理器
RT1170的电源管理域
CM7, CM4 WAKEUP, DISPLAY, MEMGA, LPSR, SNVS
CPU的工作模式
typedef enum _gpc_cpu_mode
{
kGPC_RunMode = 0x0UL, /*!< Stay in RUN mode. */
kGPC_WaitMode = 0x1UL, /*!< Transit to WAIT mode. */
kGPC_StopMode = 0x2UL, /*!< Transit to STOP mode. */
kGPC_SuspendMode = 0x3UL, /*!< Transit to SUSPEND mode. */
} gpc_cpu_mode_t;
SDK核心函数解析
// 模式转换统一入口
void PowerModeTransition(gpc_cpu_mode_t cpuMode, uint8_t sleepSp, uint8_t targetSp, gpc_cm_wakeup_sp_sel_t wakeupSel, bool stbyEn)
{
… …
if (cpuMode == kGPC_RunMode)
{
// 这里是只切SP的核心代码
gpc_cm_run_sp_tran_config_t runSpTranConfig;
runSpTranConfig.enableRunTransition = true;
runSpTranConfig.setPointRun = targetSp;
GPC_CM_RequestRunModeSetPointTransition(GPC_CPU_MODE_CTRL, &runSpTranConfig);
WaitForSpTransitionDone();
}
else
{
// to STOP/SLEEP/STANDBY mode
GPC_ConfigCpuMode(cpuMode);
gpc_cm_sleep_sp_tran_config_t sleepSpTranConfig;
sleepSpTranConfig.enableSleepTransition = true;
sleepSpTranConfig.setPointSleep = sleepSp;
sleepSpTranConfig.enableWakeupTransition = true;
sleepSpTranConfig.setPointWakeup = targetSp;
sleepSpTranConfig.wakeupSel = wakeupSel;
GPC_CM_RequestSleepModeSetPointTransition(GPC_CPU_MODE_CTRL, &sleepSpTranConfig);
SystemEnterSleepMode(cpuMode);
}
}
// Run to Run, switch SP
void GPC_CM_RequestRunModeSetPointTransition(GPC_CPU_MODE_CTRL_Type *base, const gpc_cm_run_sp_tran_config_t *config)
{
uint32_t tmp32 = base->CM_SP_CTRL;
tmp32 &= ~(GPC_CPU_MODE_CTRL_CM_SP_CTRL_CPU_SP_RUN_MASK);
if (true == config->enableRunTransition)
{
tmp32 |= GPC_CPU_MODE_CTRL_CM_SP_CTRL_CPU_SP_RUN_EN_MASK |
GPC_CPU_MODE_CTRL_CM_SP_CTRL_CPU_SP_RUN(config->setPointRun);
}
base->CM_SP_CTRL = tmp32;
}
// Run to Sleep
void GPC_CM_RequestSleepModeSetPointTransition(GPC_CPU_MODE_CTRL_Type *base, const gpc_cm_sleep_sp_tran_config_t *config)
{
… …
if (true == config->enableSleepTransition)
{
tmp32 |= GPC_CPU_MODE_CTRL_CM_SP_CTRL_CPU_SP_SLEEP_EN_MASK |
GPC_CPU_MODE_CTRL_CM_SP_CTRL_CPU_SP_SLEEP(config->setPointSleep); // Sleep下切到哪个SP
}
if (true == config->enableWakeupTransition)
{
tmp32 |= GPC_CPU_MODE_CTRL_CM_SP_CTRL_CPU_SP_WAKEUP_EN_MASK |
GPC_CPU_MODE_CTRL_CM_SP_CTRL_CPU_SP_WAKEUP(config->setPointWakeup) | // Wakeup的时候,如果要切到新的SP,指定该SP
GPC_CPU_MODE_CTRL_CM_SP_CTRL_CPU_SP_WAKEUP_SEL(config->wakeupSel); // Wakeup的时候,是返回原来的SP还是指定的SP
}
base->CM_SP_CTRL = tmp32;
}