低功耗之睡眠模式
以RISC-V MCU CH32V307为例
1. 睡眠模式简介
睡眠模式下,所有的IO引脚都保持它们在运行模式时的状态。
所有的外设时钟都正常工作。进入睡眠前,尽量关闭无用的外设时钟,以降低功耗。
该模式唤醒所需的时间最短,几乎不耗时间,约 2~3 us。
此模式下,以144MHz运行时,使能所有外设时的睡眠电流约15.1mA,关闭所有外设的睡眠电流约4.1mA(除了唤醒中断引脚时钟和电源模块时钟)。
2. 进入睡眠模式
2.1 Sleep_Now模式
-
配置内核寄存器
PFIC_SCTLR控制位SLEEPDEEP=0 -
执行
WFI或WFE指令
2.2 Sleep_On_Exit模式
-
配置内核寄存器
PFIC_SCTLR控制位SLEEPDEEP=0 -
执行
WFI睡眠指令时,配置PFIC_SCTLR控制位SLEEPONEXIT=1,系统唤醒后控制器离开中断服务函数时,继续进入低功耗模式 -
执行
WFI指令
3. 退出睡眠模式
3.1 Sleep_Now模式
-
任意中断,具体可参考中断向量表
-
唤醒事件:
-
配置一个外部或内部EXTI线为事件模式,当CPU从WFE唤醒后,因为对应事件线的挂起位没有被置位,不必清除相应外设的中断挂起位或PFIC中断通道挂起位。
-
在外设的控制寄存器使能一个中断,但不在PFIC中使能,同时需要使能寄存器
PFIC_SCTLR控制位SEVONPEND。当CPU从WFE唤醒后,需要清除相应外设的中断挂起位或PFIC中断通道挂起位。
-
3.2 Sleep_On_Exit模式
-
任意中断,具体可参考中断向量表
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) { Delay_Init(); USART_Printf_Init(256000); wakeup_init(); printf("ch32v307 sleep test\r\n"); Delay_Ms(2000); // NVIC->SCTLR |= (1<<1); /* set SLEEPONEXIT */ // NVIC->SCTLR |= (1<<4); /* set SEVONPEND */ /* wait for interrupt, wakeup pin configured as EXTI_Mode_Interrupt */ __WFI(); /* wait for event, wakeup pin configured as EXTI_Mode_Event */ // __WFE(); printf("wakeup\r\n"); // printf("NVIC pending %ld\r\n",NVIC_GetPendingIRQ(EXTI3_IRQn)); // printf("EXTI pend %d\r\n",EXTI_GetFlagStatus(EXTI3_IRQn)); // NVIC_ClearPendingIRQ(EXTI3_IRQn); // EXTI_ClearFlag(EXTI3_IRQn); 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) { printf("exti3 interrupt\r\n"); EXTI_ClearITPendingBit(EXTI_Line3); /* Clear Flag */ } }
浙公网安备 33010602011771号