低功耗之停止模式
以RISC-V MCU CH32V307为例
1. 停止模式简介
停止模式是在内核深睡眠模式(SLEEPDEEP)基础上结合了外设的时钟控制机制,并可以让电压调节器运行在低功耗模式。
此模式下,高频时钟(HSE/HSI/PLL)被关闭,SRAM和寄存器内容保持,IO引脚状态保持。
该模式唤醒后,系统可继续运行,特别注意的是,此时默认系统时钟为内部 8MHz HSI,如有需要,可调用 SystemInit()
重新初始化时钟 。
停止模式下可工作的模块:
-
独立看门狗(IWDG)
-
实时时钟(RTC)
-
低频时钟(LSI/LSE)
该模式下的唤醒时间为 HSI RC唤醒时间(23.1 us) + 电压调节器从低功耗模式唤醒时间(53.6 us 如果开启),总共约 76.7us
此模式下,电压调节器处于低功耗模式的睡眠电流约为 34uA,电压调节器处于正常状态的睡眠电流约为 110.5uA。
:::tip
为了进一步降低功耗,建议将不用的 IO 引脚初始化为下拉输入模式。
:::
2. 进入停止模式
进入停止模式的步骤:
-
配置内核寄存器
PFIC_SCTLR
控制位SLEEPDEEP=1
-
如果需要配置调压器进入低功耗模式,将电源控制寄存器
PWR_CTLR
控制位PDDS = 0
,控制位LPDS=1
, -
执行
WFI
或WFE
指令
:::tip
-
如果正在进行闪存编程,直到对内存访问完成,系统才进入停止模式;
-
如果正在进行对APB 的访问,直到对APB 访问完成,系统才进入停止模式
:::
3. 退出停止模式
退出停止模式的条件:
-
任一外部中断 EXTI0~ EXTI21,需要在外部中断寄存器中设置
-
唤醒事件:
-
配置一个外部EXTI线为事件模式,当CPU从WFE唤醒后,因为对应事件线的挂起位没有被置位,不必清除相应外设的中断挂起位或PFIC中断通道挂起位。
-
在外设的控制寄存器使能一个中断,但不在PFIC中使能,同时需要使能寄存器
PFIC_SCTLR
控制位SEVONPEND
。当CPU从WFE唤醒后,需要清除相应外设的中断挂起位或PFIC中断通道挂起位。
-
:::caution
不支持WKUP引脚上升沿唤醒
:::
4. 参考代码
参考代码 - 中断/事件唤醒
#include "debug.h" void wakeup_init(void) { GPIO_InitTypeDef GPIO_InitStructure = {0}; EXTI_InitTypeDef EXTI_InitStructure = {0}; RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA |RCC_APB2Periph_AFIO , ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); /* GPIOA.3 ----> EXTI_Line3 */ GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource3); EXTI_InitStructure.EXTI_Line = EXTI_Line3; /* WFI - EXTI_Mode_Interrupt, WFE - EXTI_Mode_Event*/ EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure); /* when configured as event, no need to enable NVIC */ NVIC_SetPriority(EXTI3_IRQn,0x00); NVIC_EnableIRQ(EXTI3_IRQn); } int main(void) { /* Configure unused GPIO as IPD to reduce power consumption */ GPIO_InitTypeDef GPIO_InitStructure = {0}; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB| RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOD|RCC_APB2Periph_GPIOE, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_Init(GPIOC, &GPIO_InitStructure); GPIO_Init(GPIOD, &GPIO_InitStructure); GPIO_Init(GPIOE, &GPIO_InitStructure); /***************************************/ Delay_Init(); USART_Printf_Init(256000); wakeup_init(); printf("ch32v307 stop test\r\n"); Delay_Ms(2000); // NVIC->SCTLR |= (1<<1); /* set SLEEPONEXIT */ /* set regulator in low power mode,need enable rcc of pwr */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE); PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFI); // PWR_EnterSTOPMode(PWR_Regulator_ON, PWR_STOPEntry_WFI); printf("wakeup\r\n"); while(1) { printf("run in main loop\r\n"); Delay_Ms(1000); } } __attribute__((interrupt("WCH-Interrupt-fast"))) void EXTI3_IRQHandler(void) { if(EXTI_GetITStatus(EXTI_Line3)!=RESET) { SystemInit(); printf("exti3 interrupt\r\n"); EXTI_ClearITPendingBit(EXTI_Line3); /* Clear Flag */ } }
:::tip 当MCU处于停止模式或待机模式时,两线调试仿真接口是处于关闭状态,此时是无法用 WCH-Link 进行程序的下载。若唤醒配置不正确,MCU无法唤醒,此时就会和MCU失联。解决方式如下:
-
在主函数启动时加一个较长的延时函数,按住板子的复位键,使系统处于复位状态,然后点击 IDE 下载按钮,这时再释放复位键,这样MCU上电后执行延时函数期间对低功耗程序进行擦除。
-
选择启动方式,通过将BOOT0拉高,重新上电使MCU从SRAM启动,重新选择一个非睡眠程序下载,下载完成后将BOOT0拉低,然后重新上电即可重新下载程序。
:::
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?