低功耗之睡眠模式

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

参考代码
#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 */
    }
}

 

 

posted @ 2022-06-30 17:36  喵喵喵mmm  阅读(353)  评论(0)    收藏  举报