返回列表 发新帖我要提问本帖赏金: 50.00元(功能说明)

[资料干货] 电源管理单元PMU讲解

[复制链接]
 楼主| 虚幻的是灵魂 发表于 2024-9-7 11:45 | 显示全部楼层 |阅读模式
<
本帖最后由 虚幻的是灵魂 于 2024-9-7 12:02 编辑

#申请原创# @21ic小喇叭 @21小跑堂
一、PMU

PMU全称Power Management Unit,电源管理单元。

1、电源域

总共有三大电源域,包括VDD / VDDA域,1.2V域和备份域。

2、VDD/VDDA域

VDD/VDDA域如下图:

提供PMU 常规电源供应以下模块的供电:

  • 看门狗
  • 主频晶振
  • 内部晶振
  • ADC和DAC
  • LDO电源转换
  • 上电复位
  • 锁相环

3、备份域

备份域如下图:

备份域提供以下供电:

  • 外部低频时钟晶振
  • RTC
  • 上电复位
  • 电源转换

4、1.2V域

1.2V域如下图所示:

这个作用域主要提供:

  • AHB高速总线的供电
  • APB外设总线的供电
  • 内存
  • Cortex-M4的供电

二、模式介绍
1、省电模式

总共有三个省电模式:

  • 睡眠模式
  • 深度睡眠模式
  • 待机模式

2、睡眠模式

睡眠模式时,会关闭 1.2V域中的 Cortex-M4的供电。

3、深度睡眠模式

进入深度模式时,会关闭 1.2V域中的所有供电;同时关闭VDD/VDDA域中的HXTALIRC16MPLLs

4、待机模式

进入待机模式时,会关闭1.2V域中的所有供电;同时关闭VDD/VDDA域中的LDO、IRC16M、HXTAL、PLLs;

几种模式总结
模式 睡眠 深度睡眠 待机
描述 仅关闭 CPU 时钟 1、关闭 1.2V 电源域的所有时钟;2、关闭 IRC16M、HXTAL和 PLL 1、关闭 1.2V 电源域的供电;2、关闭 IRC16M、HXTAL和 PLL
LDO状态 开启(正常功耗,正常驱动模式) 开启(正常功耗或低功耗模式,正常驱动或低驱动模式) 关闭
配置 SLEEPDEEP=0 SLEEPDEEP=1,STBMOD =0 SLEEPDEEP=1,STBMOD=1,WURST=1
进入指令 WFI或 WFE WFI或 WFE WFI或 WFE
唤醒 若通过 WFI 进入,则任何中断均可唤醒;若通过 WFE 进入,则任何事件(或SEVONPEND=1时的中断)均可唤醒。 若通过 WFI进入,来自 EXTI的任何中断可唤醒;若通过WFE 进入,来自 EXTI 的任何事件(或 SEVONPEND =1 时的中断)可唤醒 1、NRST 引脚;2、WKUP 引脚;3、FWDGT 复位;4、RTC
唤醒延迟 IRC16M 唤醒时间,如果 LDO 处于低功耗模式,需增加 LDO 唤醒时间 上电序列

三、WFI和WFE指令
在ARM架构中,WFI(Wait For Interrupt)和 WFE(Wait For Event)是用于使处理器进入低功耗状态的指令。这两个指令主要用于在空闲时暂停处理器的执行,以节省功耗。

1、WFI指令:

WFI 指令使处理器进入等待中断状态。当处理器执行到 WFI 时,它会进入低功耗模式,直到有一个中断请求到达,将处理器唤醒。在等待中断期间,处理器会停止执行指令,以减少功耗。

2、WFE指令:

WFE 指令与 WFI 类似,但它不仅能够等待中断,还能够等待事件。事件是由外部设备或其他处理器触发的信号。当执行到 WFE 时,处理器会进入低功耗模式,直到有中断或事件到达,将处理器唤醒。与 WFI 不同,WFE 可以等待中断或事件中的任何一个。

四、案例需求

说明:
  • 让LED1 每间隔一段时间闪烁(500ms)
  • 通过串口切换 省电模式



说明:
  • 为KEY2配置外部中断按键,按下时LED2自动切换开关


说明:
  • 为PA0配置外部中断按键,按下时LED3自动切换开关

五、模式初始化1、睡眠模式
  1. static void sleep_mode() {
  2.     // 电池管理单元时钟
  3.     rcu_periph_clock_enable(RCU_PMU);
  4.     // 进入睡眠模式
  5.     pmu_to_sleepmode(WFI_CMD);

  6. }
2、深度睡眠模式
  1. static void deepsleep_mode() {
  2.     // 电池管理单元时钟
  3.     rcu_periph_clock_enable(RCU_PMU);
  4.     // 进入深度睡眠模式
  5.     pmu_to_deepsleepmode(PMU_LDO_LOWPOWER, PMU_LOWDRIVER_ENABLE, WFI_CMD);

  6. }
3、待机模式
  1. static void standby_mode() {
  2.     // 电池管理单元时钟
  3.     rcu_periph_clock_enable(RCU_PMU);
  4.                 pmu_wakeup_pin_enable();
  5.     // 进入待机模式
  6.                 pmu_to_standbymode();
  7. }
源码:

  1. #include "gd32f4xx.h"
  2. #include "systick.h"
  3. #include <stdio.h>
  4. #include "main.h"
  5. #include "Usart0.h"


  6. static void sleep_mode() {
  7.     // 电池管理单元时钟
  8.     rcu_periph_clock_enable(RCU_PMU);
  9.     // 进入睡眠模式
  10.     pmu_to_sleepmode(WFI_CMD);

  11. }

  12. static void deepsleep_mode() {
  13.     // 电池管理单元时钟
  14.     rcu_periph_clock_enable(RCU_PMU);
  15.     // 进入深度睡眠模式
  16.     pmu_to_deepsleepmode(PMU_LDO_LOWPOWER, PMU_LOWDRIVER_ENABLE, WFI_CMD);

  17. }

  18. static void standby_mode() {
  19.     // 电池管理单元时钟
  20.     rcu_periph_clock_enable(RCU_PMU);
  21.                 pmu_wakeup_pin_enable();
  22.     // 进入待机模式
  23.                 pmu_to_standbymode();
  24. }

  25. void Usart0_on_recv(uint8_t* data, uint32_t len) {
  26.     printf("recv: %s\r\n", data);

  27.     if(data[0] == 0x00) {
  28.         printf("sleep mode \r\n");
  29.         sleep_mode();
  30.     } else if(data[0] == 0x01) {
  31.         printf("deepsleep mode \r\n");
  32.         deepsleep_mode();
  33.                                 SystemInit();
  34.     } else if(data[0] == 0x02) {
  35.         printf("standby mode \r\n");
  36.         standby_mode();
  37.     }
  38. }

  39. static void EXTI0_config() {
  40.     uint32_t extix = EXTI_0;
  41.     uint32_t extix_irq = EXTI0_IRQn;
  42.     uint32_t extix_irq_pre = 1;
  43.     uint32_t extix_irq_sub = 1;

  44.     uint32_t extix_trig = EXTI_TRIG_BOTH;

  45.     uint32_t extix_port_rcu = RCU_GPIOA;
  46.     uint32_t extix_port = GPIOA;
  47.     uint32_t extix_pin = GPIO_PIN_0;
  48.     uint32_t extix_src_port = EXTI_SOURCE_GPIOA;
  49.     uint32_t extix_src_pin = EXTI_SOURCE_PIN0;

  50.     /*************** gpio ****************/
  51.     // PA0,
  52.     // 时钟初始化
  53.     rcu_periph_clock_enable(extix_port_rcu);
  54.     // 配置GPIO模式
  55.     gpio_mode_set(extix_port, GPIO_MODE_INPUT, GPIO_PUPD_NONE, extix_pin);

  56.     /*************** exti ****************/
  57.     // 时钟配置
  58.     rcu_periph_clock_enable(RCU_SYSCFG);
  59.     // 配置中断源
  60.     syscfg_exti_line_config(extix_src_port, extix_src_pin);
  61.     // 中断初始化
  62.     exti_init(extix, EXTI_INTERRUPT, extix_trig);

  63.     // 配置中断优先级
  64.     nvic_irq_enable(extix_irq, extix_irq_pre, extix_irq_sub);
  65.     // 使能中断
  66.     exti_interrupt_enable(extix);
  67.     // 清除中断标志位
  68.     exti_interrupt_flag_clear(extix);
  69. }

  70. static void EXTI1_config() {
  71.     uint32_t extix = EXTI_1;
  72.     uint32_t extix_irq = EXTI1_IRQn;
  73.     uint32_t extix_irq_pre = 1;
  74.     uint32_t extix_irq_sub = 1;

  75.     uint32_t extix_trig = EXTI_TRIG_BOTH;

  76.     uint32_t extix_port_rcu = RCU_GPIOD;
  77.     uint32_t extix_port = GPIOD;
  78.     uint32_t extix_pin = GPIO_PIN_1;
  79.     uint32_t extix_src_port = EXTI_SOURCE_GPIOD;
  80.     uint32_t extix_src_pin = EXTI_SOURCE_PIN1;

  81.     /*************** gpio ****************/
  82.     // PA0,
  83.     // 时钟初始化
  84.     rcu_periph_clock_enable(extix_port_rcu);
  85.     // 配置GPIO模式
  86.     gpio_mode_set(extix_port, GPIO_MODE_INPUT, GPIO_PUPD_NONE, extix_pin);

  87.     /*************** exti ****************/
  88.     // 时钟配置
  89.     rcu_periph_clock_enable(RCU_SYSCFG);
  90.     // 配置中断源
  91.     syscfg_exti_line_config(extix_src_port, extix_src_pin);
  92.     // 中断初始化
  93.     exti_init(extix, EXTI_INTERRUPT, extix_trig);

  94.     // 配置中断优先级
  95.     nvic_irq_enable(extix_irq, extix_irq_pre, extix_irq_sub);
  96.     // 使能中断
  97.     exti_interrupt_enable(extix);
  98.     // 清除中断标志位
  99.     exti_interrupt_flag_clear(extix);
  100. }

  101. void EXTI0_IRQHandler() {
  102.     // 判断寄存器状态
  103.     if(SET == exti_interrupt_flag_get(EXTI_0)) {
  104.         if(gpio_input_bit_get(GPIOA, GPIO_PIN_0) == SET)
  105.         {
  106.             /* 按键按下操作的功能 */
  107.             gpio_bit_toggle(GPIOG, GPIO_PIN_3);
  108.             printf("PA0 press!\r\n");
  109.         } else {
  110.             /* 按键松开操作的功能 */
  111.             printf("PA0 release!\r\n");
  112.         }
  113.     }
  114.     // 清除中断标志位
  115.     exti_interrupt_flag_clear(EXTI_0);
  116. }

  117. void EXTI1_IRQHandler() {
  118.     // 判断寄存器状态
  119.     if(SET == exti_interrupt_flag_get(EXTI_1)) {
  120.         if(gpio_input_bit_get(GPIOD, GPIO_PIN_1) == SET)
  121.         {
  122.             gpio_bit_toggle(GPIOD, GPIO_PIN_7);
  123.             printf("key2 press!\r\n");
  124.         } else {
  125.             /* 按键松开操作的功能 */
  126.             printf("key2 release!\r\n");
  127.         }
  128.     }
  129.     // 清除中断标志位
  130.     exti_interrupt_flag_clear(EXTI_1);
  131. }


  132. int main(void)
  133. {
  134.     systick_config();
  135.     Usart0_init();
  136.                 EXTI0_config();
  137.                 EXTI1_config();
  138.                
  139.                 // LED1
  140.     rcu_periph_clock_enable(RCU_GPIOE);
  141.     gpio_mode_set(GPIOE, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_3);
  142.     gpio_output_options_set(GPIOE, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, GPIO_PIN_3);
  143.                 // LED2
  144.                 rcu_periph_clock_enable(RCU_GPIOD);
  145.     gpio_mode_set(GPIOD, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_7);
  146.     gpio_output_options_set(GPIOD, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, GPIO_PIN_7);
  147.                 // LED3
  148.                 rcu_periph_clock_enable(RCU_GPIOG);
  149.     gpio_mode_set(GPIOG, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_3);
  150.     gpio_output_options_set(GPIOG, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, GPIO_PIN_3);

  151.     while(1) {
  152.         gpio_bit_toggle(GPIOE, GPIO_PIN_3);
  153.         delay_1ms(500);
  154.     }
  155. }


注意:

中断优先级配置为NVIC_PRIGROUP_PRE2_SUB2情况下:

  • 串口的抢占优先级不能设置为0,否则系统无法正常睡眠
  • 深度睡眠的外部中断的抢占优先级必须设置为0或1,否则无法正常唤醒


六、总结


普通睡眠:任何中断都会唤醒。

深度睡眠: 唤醒中断睡眠优先级要高一些。

待机: 会重启,不会走下面。





  

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×

打赏榜单

21小跑堂 打赏了 50.00 元 2024-10-10
理由:恭喜通过原创审核!期待您更多的原创作品~~

评论

从MCU的硬件电源管理单元切入,解析不同工作状态下的供电方式,同时从实例出发,延时不同低功耗模式下代码的配置。  发表于 2024-10-10 15:45
王栋春 发表于 2024-9-7 21:54 | 显示全部楼层
没有接触过类似知识,围观了解一下。   
咕咕呱呱孤寡 发表于 2024-9-9 08:41 | 显示全部楼层
感谢分享,学习了解
您需要登录后才可以回帖 登录 | 注册

本版积分规则

15

主题

118

帖子

2

粉丝
快速回复 在线客服 返回列表 返回顶部