打印
[研电赛技术支持]

【GD32H757Z海棠派使用手册】第五讲 PMU-低功耗实验

[复制链接]
954|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 聚沃科技 于 2024-4-30 11:17 编辑


5.1 实验内容
通过本实验主要学习以下内容:
• PMU原理;
低功耗的进入以及退出操作;
5.2 实验原理
5.2.1 PMU结构原理
PMU即电源管理单元,其内部结构下图所示,由该图可知,GD32H7XX系列MCU具有三个电源域,包括VDD/VDDA电源域、0.9V电源域以及电池备份域,其中,VDD /VDDA域由电源直接供电。0.9V由内部LDO或者外部Vcore供电。在备份域中有一个电源切换器,当VDD/VDDA电源关闭时,电源切换器可以将备份域的电源切换到VBAT引脚,此时备份域由VBAT引脚(电池)供电。
1. VDD/VDDA电源域
VDD / VDDA 域包括 VDD 域和 VDDA 域两部分。 VDD 域包括 HXTAL(高速外部晶体振荡器)、 POR/ PDR(上电 / 掉电复位)、 FWDGT(独立看门狗定时器)和除 PC13PC14 PC15 之外的所有 PAD 等等。 VDDA 域包括 ADC / DACAD / DA 转换器)、 LPIRC4M(内部 4MHz RC振荡器)、 IRC64M(内部 64M RC 振荡器)、 IRC32K(内部 32KHz RC 振荡器) PLLs(锁相环)、 LVD(低电压检测器)、 VOVD0.9V 电压检测器)、 VAVDVDDA 电压检测器)、 TVD(温度电压检测器)和 BVDVBAK 电压检测器)等等。
POR / PDR(上电 / 掉电复位) 电路检测 VDD / VDDA 并在电压低于特定阈值时产生电源复位信号复位除备份域之外的整个芯片。下图显示了供电电压和电源复位信号之间的关系。 VPOR 表示上电复位的阈值电压, VPDR 表示掉电复位的阈值电压。迟滞电压 Vhyst 值约为 50mV。  
BOR 电路检测 VDD / VDDA 并在 BOR_TH 不为 0b11,同时电压低于选项字节的 BOR_TH 定义的阈值时产生电源复位信号复位除备份域之外的整个芯片。 POR / PDR(上电 / 掉电复位)电路处于检测状态,无论选项字节的 BOR_TH 是否为 0b11。 下图显示了供电电压和 BOR 复位信号之间的关系。 VBOR 表示 BOR 复位的阈值电压,该值在选项字节 BOR_TH中定义。迟滞电压 Vhyst 值为 100mV。  
LVD 的功能是检测 VDD / VDDA 供电电压是否低于低电压检测阈值,该阈值由电源控制寄存器 0PMU_CTL0)中的 LVDT[2:0]位进行配置。 LVD 通过 LVDEN 置位使能,位于电源控制状态寄存器(PMU_CS)中的 LVDF 位表示低电压事件是否出现,该事件连接至 EXTI 的第 16 线,用户可以通过配置 EXTI 的第 16 线产生相应的中断。下图显示了 VDD / VDDA  供电电压和 LVD 输出信号的关系。(LVD 中断信号依赖于 EXTI 16 线的上升或下降沿配置)。迟滞电压 Vhyst 值为 100mV。  

为提高 ADC DAC 的精度,可将独立的外部参考电压连接至 ADC / DAC 引脚 VREF+ / VREF-。  
VDDA模拟电压检测器(VAVD)用于检测 VDDA电源电压是否低于电源控制寄存器(PMU_CTL0)中 VAVDVC[1:0]位域选择的编程阈值。通过置位 VAVDEN 位能够使能 VAVDPMU_CS 寄存器中的 VAVDF 位指示 VDDA 高于或低于指定的 VAVD 阈值,如果 VAVDF 置位能够产生对应的事件,这个事件在内部连接到 EXTI 16。如果通过 EXTI 寄存器使能,可以产生一个中断。  
和备份域电压阈值监测类似,通过与温度高、低两个阈值水平比较可以来监测结温。PMU_CTL1寄存器中 TEMPH TEMPL 标志指示设备温度是否高于或低于阈值。可以通过 PMU_CTL1寄存器中的 VBTMEN 位使能 / 关闭温度电压阈值监测。使能后,温度阈值监测将增加功耗。温度阈值监测可以用来触发执行温度控制任务的相关的程序。只有 PMU_CTL1 寄存器中的VBTMEN 位置位,温度阈值监测才有效。  
TEMPH TEMPL 唤醒中断可用于 RTC 触发信号。
2. 0.9V电源域
主要功能包括 Cortex®-M7 内核逻辑、 AHB / APB 外设、备份域和 VDD / VDDA 域的 APB 接口。当 0.9V 电压上电后, POR 将在 0.9V 域中产生一个复位序列,复位完成后,如果要进入指定的省电模式,须先配置相关的控制位,之后一旦执行 WFI WFE 指令,设备便进入该省电模式。  
使用 SMPS 降压稳压器和 LDO,可以设置 0.9V 电源域的供电电源。不同配置可提供七种有效的 0.9V 电源域供电模式。
注意:基于供电稳定性以及芯片散热考虑,目前推荐采用模式6旁路模式进行供电。在旁路供电模式下内部SMPSLDO是关闭状态,内部VcoreVcore引脚进行供电,Vcore引脚外接0.9V电源。如下图所示。
3. 电池备份域
电池备份域由内部电源切换器来选择 VDD 供电或 VBAT(电池)供电,然后由 VBAK 为备份域供电,该备份域包含 RTC(实时时钟)、 LXTAL(低速外部晶体振荡器), BPOR(备份域上电复位)和 BREG,以及 PC13 PC15 3 BKP PAD。为了确保备份域中寄存器的内容及 RTC正常工作,当 VDD 关闭时, VBAT 引脚可以连接至电池或其他备份电源供电。电源切换器是由VDD / VDDA 域掉电复位电路控制的。对于没有外部电池的应用,建议将 VBAT 引脚通过 100nF 的外部陶瓷去耦电容连接到 VDD 引脚上。  
注意: 由于PC13PC15引脚是通过电源切换器供电的,电源切换器仅可通过小电流,因此当PC13PC15GPIO口在输出模式时,其工作的速度不能超过2MHz(最大负载为30Pf)。
若读者有在VDD掉电情况下RTC继续工作的应用需求,需要VBAT引脚外接电池并使用LXTAL外部低频晶振,这样在VDD掉电的情况下,VBAT供电将会由VDD切换到VBATLXTALRTC均可正常工作,后续VDD上电后同步RTC寄存器即可获取正确的RTC时间。
5.2.2 低功耗模式
GD32H7xx系列MCU具有三种低功耗模式,分别为睡眠模式、深度睡眠模式和待机模式。
睡眠模式与 Cortex®-M7 SLEEPING 模式相对应。在睡眠模式下,仅关闭 Cortex®-M7 的时钟。如需进入睡眠模式,只要清除 Cortex®-M7 系统控制寄存器中的 SLEEPDEEP 位,并执行一条 WFI WFE 指令即可。如果睡眠模式是通过执行 WFI 指令进入的,任何中断都可以唤醒系统。如果睡眠模式是通过执行 WFE 指令进入的,任何唤醒事件都可以唤醒系统(如果SEVONPEND 1,任何中断都可以唤醒系统,请参考 Cortex®-M7 技术手册)。由于无需在进入或退出中断上消耗时间,该模式所需的唤醒时间最短。  
深度睡眠模式与 Cortex®-M7 SLEEPDEEP 模式相对应。在深度睡眠模式下, 0.9V 域中的所有时钟全部关闭, LPIRC4MIRC64MHXTAL PLLs 也全部被禁用。进入深度睡眠模式之前,先将 Cortex®-M7 系统控制寄存器的 SLEEPDEEP 位置 1,再将 PMU_CTL0 寄存器的LPMOD 位配置为 0b1,然后执行 WFI WFE 指令即可进入深度睡眠模式。如果睡眠模式是通过执行 WFI 指令进入的,任何来自 EXTI 的中断可以将系统从深度睡眠模式中唤醒。如果睡眠模式是通过执行 WFE 指令进入的,任何来自 EXTI 的事件可以将系统从深度睡眠模式中唤醒(如果 SEVONPEND 1,任何来自 EXTI 的中断都可以唤醒系统,请参考 Cortex®-M7 技术手册)。  
待机模式是基于 Cortex®-M7 SLEEPDEEP 模式实现的。在待机模式下,整个 0.9V 域全部停止供电, LDO 关闭,同时包括 LPIRC4MIRC64MHXTAL PLLs 也会被关闭。进入待机模式前,先将 Cortex®-M7 系统控制寄存器的 SLEEPDEEP 位置 1,再将 PMU_CTL0 寄存器的 LPMOD 位域配置为 0b1,再清除 PMU_CS 寄存器的 WUF 位,然后执行 WFI WFE指令,系统进入待机模式, PMU_CS 寄存器的 STBF 位状态表示 MCU 是否已进入待机模式。待机模式有四个唤醒源,包括来自 NRST 引脚的外部复位, RTC 闹钟, FWDGT 复位, WKUP引脚的上升沿。待机模式可以达到最低的功耗,但唤醒时间最长。另外,一旦进入待机模式,SRAM 0.9V 电源域寄存器的内容都会丢失。退出待机模式时,会发生上电复位,复位之后Cortex®-M7 将从 0x00000000 地址开始执行指令代码。  
低功耗模式相关数据可参考下表,不同的低功耗模式是通过关闭不同时钟以及电源来实现的,关闭的时钟和电源越多,MCU所进入的睡眠模式将会越深,功耗也会越低,带来的唤醒时间也会越长,其唤醒源也会越少。
各种睡眠模式下的功耗可以参考数据手册描述,睡眠模式下相较于同主频模式下的运行模式功耗减少约50%,深度睡眠和待机模式功耗更低,如下表所示,深度睡眠模式下功耗常温典型值为2-3ma
注意:由于深度睡眠模式具有较低的功耗,唤醒后继续从断点处执行,因而具有更广泛的应用场景,但需注意若需达到较一致的MCU深度睡眠功耗,需要将系统中未使用的MCU引脚均配置为模拟输入状态,包括芯片内部未引出的pad
Note:中间为典型数值。
5.3 硬件设计
本例程stanby的唤醒使用到了PA0唤醒引脚,其电路如下所示。
5.4 代码解析
本例程实现deepsleep以及standby的进入以及唤醒测试,首先我们来看下主函数,如下所示。该主函数首先配置了驱动初始化、打印和LED函数,并打印Example of Low Power Test Demo。之后查询是否进入过Standby模式,如果进入过Standby模式,表示当前状态为standby唤醒后的复位,则打印A reset event from Standby mode has occurred,并翻转LED2,因而验证standby唤醒的时候,其现象可观察到LED2的翻转。之后使能wakeup引脚的唤醒以及USER按键的初始化,此时将wakeup KEY配置为中断模式。在while1)中,查询USER KEY按下的时间,如果按下超过3S,则打印Entering Standby Mode.并进入standby模式,如果USER KEY按下不超过3S,则打印Enter Deepsleep mode.并进入Deepsleep模式,从deepsleep模式唤醒后需要重新配置时钟,打印Exit Deepsleep mode.并翻转LED1Standby的唤醒使用PA0 wakeup引脚,deepsleep的唤醒可使用任何EXTI中断,本实例中使用wakeup按键中断唤醒。
C
int main(void)
{
        rcu_periph_clock_enable(RCU_PMU);
    driver_init();
    //注册按键扫描
    driver_tick_handle[0].tick_value=10;   
    driver_tick_handle[0].tick_task_callback=key_scan_10ms_callhandle;
   
   
        bsp_uart_init(&BOARD_UART);                                                                                                                                   /* 板载UART初始化 */
    printf_log("Example of Low Power Test Demo.\r\n");

        delay_ms(2000);
        bsp_led_group_init();  
        
        /* 判断是否进入过Stanby模式 */
        if(pmu_flag_get(PMU_FLAG_STANDBY)==SET)
        {
                  printf_log("A reset event from Standby mode has occurred.\r\n");
                  bsp_led_toggle(&LED2);
          pmu_flag_clear(PMU_FLAG_STANDBY);
        }

        /* 配置PA0 Wakeup唤醒功能 */
        pmu_wakeup_pin_enable(PMU_WAKEUP_PIN0);
        WKUP_KEY.key_gpio->gpio_mode = INT_HIGH;
        WKUP_KEY.key_gpio->int_callback = WKUP_KEY_IRQ_callback;
    bsp_key_group_init();
        nvic_irq_enable(EXTI0_IRQn,0,0);
        
        while (1)
        {
                /* 检测KEY1按键是否被按下,如果按下,进入standby模式 */
        if(USER_KEY.press_timerms >= PRESS_3000MS)
        {
             USER_KEY.press_timerms=PRESS_NONE;
                         printf_log("Entering Standby Mode.\r\n");
                         bsp_led_toggle(&LED2);
                         pmu_to_standbymode();
                }
                /* 检测KEY2按键是否被按下,如果按下,进入Deepsleep模式 */
        if(USER_KEY.press_timerms >= PRESS_50MS)
        {
             USER_KEY.press_timerms=PRESS_NONE;
                         printf_log("Enter Deepsleep mode.\r\n");
                         bsp_led_toggle(&LED1);
            
             bsp_lcd_backlight_off();
             pmu_to_deepsleepmode(WFI_CMD);
             bsp_lcd_backlight_on();
                         printf_log("Exit Deepsleep mode.\r\n");
                         bsp_led_toggle(&LED1);
                }
        }
}
5.5 实验结果
将本实验历程烧录到海棠派开发板中,按下user key按键超过3S,松开后MCU将进入standby模式,并打印Entering Standby Mode.,然后按下wakeup按键,将从stanby模式唤醒,打印A reset event from Standby mode has occurred.并翻转LED2,之后短按USER KEY,将打印Enter Deepsleep mode.进入deepsleep模式,然后按下wakeup按键将从deepsleep模式下唤醒,唤醒后重新配置时钟,打印Exit Deepsleep mode.并将LED1翻转。
本教程由GD32 MCU方案商聚沃科技原创发布,了解更多GD32 MCU教程,关注聚沃科技官网,GD32MCU技术交流群:859440462

使用特权

评论回复
沙发
键盘手没手| | 2024-5-31 23:26 | 只看该作者
本帖最后由 键盘手没手 于 2024-6-1 09:05 编辑

基本的框架

#include "stm32f4xx.h"
#include "stdio.h"

void SystemClock_Config(void);
void GPIO_Init(void);
void EXTI_Init(void);
void EXTI0_IRQHandler(void);
void EXTI9_5_IRQHandler(void);
void standby_mode(void);
void deepsleep_mode(void);

int main(void) {
    HAL_Init();
    SystemClock_Config();
    GPIO_Init();
    EXTI_Init();

    printf("Press USER KEY for Standby mode.\r\n");

    while (1) {
        // Main program loop
    }
}

void SystemClock_Config(void) {
    // Configure system clock
    // Add your code here
}

void GPIO_Init(void) {
    // Configure GPIO for LEDs and buttons
    // Add your code here
}

void EXTI_Init(void) {
    // Configure EXTI for user key and wakeup button
    // Add your code here
}

void EXTI0_IRQHandler(void) {
    // Handle user key press
    // Add your code here
}

void EXTI9_5_IRQHandler(void) {
    // Handle wakeup button press
    // Add your code here
}

void standby_mode(void) {
    printf("Entering Standby Mode.\r\n");

    // Configure GPIO and other peripherals for Standby mode
    // Add your code here

    HAL_PWR_EnterSTANDBYMode();
}

void deepsleep_mode(void) {
    printf("Enter Deepsleep mode.\r\n");

    // Configure GPIO and other peripherals for Deep Sleep mode
    // Add your code here

    HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);

    printf("Exit Deepsleep mode.\r\n");
}

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

81

主题

101

帖子

2

粉丝