RISC-V MCU 应用教程之低功耗之睡眠模式

以RISC-V MCU CH32V307为例

1. 睡眠模式简介

睡眠模式下,所有的IO引脚都保持它们在运行模式时的状态。

所有的外设时钟都正常工作。进入睡眠前,尽量关闭无用的外设时钟,以降低功耗。

该模式唤醒所需的时间最短,几乎不耗时间,约 2~3 us。

此模式下,以144MHz运行时,使能所有外设时的睡眠电流约15.1mA,关闭所有外设的睡眠电流约4.1mA(除了唤醒中断引脚时钟和电源模块时钟)。

2. 进入睡眠模式

2.1 Sleep_Now模式

  • 配置内核寄存器 PFIC_SCTLR 控制位 SLEEPDEEP=0

  • 执行WFIWFE指令

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. 参考代码

 
 1 #include "debug.h"
 2 
 3 void wakeup_init(void)
 4 {
 5     GPIO_InitTypeDef GPIO_InitStructure = {0};
 6     EXTI_InitTypeDef EXTI_InitStructure = {0};
 7 
 8     RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA |RCC_APB2Periph_AFIO , ENABLE);
 9 
10     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
11     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
12     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
13     GPIO_Init(GPIOA, &GPIO_InitStructure);
14 
15     /* GPIOA.3 ----> EXTI_Line3 */
16     GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource3);
17     EXTI_InitStructure.EXTI_Line = EXTI_Line3;
18 
19     /* WFI - EXTI_Mode_Interrupt, WFE - EXTI_Mode_Event*/
20     EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; 
21 
22     EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
23     EXTI_InitStructure.EXTI_LineCmd = ENABLE;
24     EXTI_Init(&EXTI_InitStructure);
25 
26     /* when configured as event, no need to enable NVIC */
27     NVIC_SetPriority(EXTI3_IRQn,0x00);
28     NVIC_EnableIRQ(EXTI3_IRQn);
29 
30 }
31 
32 int main(void)
33 {
34     Delay_Init();
35     USART_Printf_Init(256000);
36 
37     wakeup_init();
38 
39     printf("ch32v307 sleep test\r\n");
40     Delay_Ms(2000);
41 
42     // NVIC->SCTLR |= (1<<1); /* set SLEEPONEXIT */
43     // NVIC->SCTLR |= (1<<4); /* set SEVONPEND */ 
44 
45     /* wait for interrupt, wakeup pin configured as EXTI_Mode_Interrupt */
46     __WFI();
47 
48      /* wait for event, wakeup pin configured as EXTI_Mode_Event */
49     // __WFE();  
50 
51     printf("wakeup\r\n");
52 
53     // printf("NVIC pending %ld\r\n",NVIC_GetPendingIRQ(EXTI3_IRQn));
54     // printf("EXTI pend %d\r\n",EXTI_GetFlagStatus(EXTI3_IRQn));
55 
56     // NVIC_ClearPendingIRQ(EXTI3_IRQn);
57     // EXTI_ClearFlag(EXTI3_IRQn);
58 
59     while(1)
60     {
61         printf("run in main loop\r\n");
62         Delay_Ms(1000);
63     }
64 }
65 
66 
67 __attribute__((interrupt("WCH-Interrupt-fast")))
68 void EXTI3_IRQHandler(void)
69 {
70     if(EXTI_GetITStatus(EXTI_Line3)!=RESET)
71     {
72         printf("exti3 interrupt\r\n");
73         EXTI_ClearITPendingBit(EXTI_Line3);     /* Clear Flag */
74     }
75 }

 

 
posted @ 2022-06-29 17:21  Zhu_zzzzzz  阅读(315)  评论(0)    收藏  举报