现在正在进行项目预研,需要各模块在空闲时进入待机模式,MCU选择sleep mode。
MCU节电模式
MCU支持三种节电模式Sleep mode、Deep-sleep mode、Standby mode
根据datasheet描述,在sleep mode下,只有CPU核心的时钟是关闭的,其他所有外设继续运行,任何中断/事件都可以唤醒系统。
MCU的Sleep mode
进入Sleep mode
执行WFI(等待中断)或WFE(等待事件)指令可进入Sleep mode,根据SCR中SLEEPONEXIT位的设置,可以通过两种方案选择进入Sleep mode:
- 立即Sleep mode:如果SLEEPONEXIT位清零,MCU将执行WFI或WFE指令立即进入Sleep mode
- 退出时Sleep mode:如果SLEEPONEXIT位置1,MCU将在退出优先级最低的ISR时立即进入Sleep mode
退出Sleep mode
如果使用WFI指令进入Sleep mode,则NVIC确认的任意外设中断都会将MCU从Sleep mode唤醒。
如果使用WFE指令进入Sleep mode,MCU将在有事件发生时立即退出Sleep mode。唤醒事件可通过以下方式产生:
- 在外设的控制寄存器使能一个中断,但不再NVIC中使能,同时使能SCR中的SEVONPEND位。当MCU从WEF恢复时,需要清除相应外设的中断挂起位和外设NVIC中断通道挂起位(在NVIC中断清除挂起寄存器中)。
- 配置一个外部或内部EXTI线为事件模式。当MCU从WFE恢复时,因为对应时间线的挂起位没有被置位,不必清除相应外设的中断挂起位或NVCI中断通道挂起位。
由于没有在进入/退出中断时浪费时间,此模式下的唤醒时间最短。
进入和退出立即进入Sleep mode
立即进入 | 说明 |
---|---|
进入模式 | WFI(等待中断)或WFE(等待事件),且: -SLEEPDEEP = 0及 -SLEEPONEXIT = 0 |
退出模式 | 如果使用WFI退出:中断唤醒 如果使用WFE退出:事件唤醒 |
唤醒延迟 | 无 |
进入和退出退出时进入Sleep mode
退出时 | 说明 |
---|---|
进入模式 | WFI(等待中断),且: -SLEEPDEEP = 0 及 -SLEEPONEXIT= 1 |
退出模式 | 中断唤醒 |
唤醒延迟 | 无 |
代码实现
void PWR_EnterSleepMode()
{
__WFI();
}
注:默认情况下,__WFI()指令就会让MCU进入Sleep mode。
关于SCR的SLEEPONEXIT位和SLEEPDEEP位,根据源码中的注释
SLEEPONEXIT:在退出时进入Sleep mode,所以SLEEPONEXIT位置零
SLEEPDEEP:低功耗进入Deep Sleep的请求,所以SLEEPDEEP位置零
在PWR_EnterSTOPMode()函数中,SLEEPDEEP位置1,再调用__WFI()实际上进入的是Deep-sleep mode
void PWR_EnterSTOPMode(uint32_t PWR_Regulator, uint8_t PWR_STOPEntry)
{
uint32_t tmpreg = 0;
/* Check the parameters */
assert_param(IS_PWR_REGULATOR(PWR_Regulator));
assert_param(IS_PWR_STOP_ENTRY(PWR_STOPEntry));
/* Select the regulator state in STOP mode ---------------------------------*/
tmpreg = PWR->CR;
/* Clear PDDS and LPDS bits */
tmpreg &= CR_DS_MASK;
/* Set LPDS, MRLVDS and LPLVDS bits according to PWR_Regulator value */
tmpreg |= PWR_Regulator;
/* Store the new value */
PWR->CR = tmpreg;
/* Set SLEEPDEEP bit of Cortex System Control Register */
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
/* Select STOP mode entry --------------------------------------------------*/
if(PWR_STOPEntry == PWR_STOPEntry_WFI)
{
/* Request Wait For Interrupt */
__WFI();
}
else
{
/* Request Wait For Event */
__WFE();
}
/* Reset SLEEPDEEP bit of Cortex System Control Register */
SCB->SCR &= (uint32_t)~((uint32_t)SCB_SCR_SLEEPDEEP_Msk);
}