知不足而奋进 望远山而前行
目录
前言
在嵌入式系统中,有效的电池管理和低功耗模式对于延长设备电池寿命至关重要。电池管理单元(PMU)及其相关的电源域和省电模式是实现这一目标的关键组成部分。本文将深入探讨PMU的功能、ARM32中的电源域结构,以及几种常见的省电模式。此外,我们还将了解如何通过在不同省电模式之间切换来优化系统功耗,同时保持系统的响应能力和功能完整性。
学习目标
- 了解什么是电池管理单元PMU
- 了解ARM32中的电源域
- 了解几种省电模式
学习内容
PMU
PMU全称Power Management Unit,电源管理单元。
电源域
总共有三大电源域,包括VDD / VDDA域,1.2V域和备份域。
VDD/VDDA域
VDD/VDDA域如下图:
提供PMU 常规电源供应以下模块的供电:
- 看门狗
- 主频晶振
- 内部晶振
- ADC和DAC
- LDO电源转换
- 上电复位
- 锁相环
备份域
备份域如下图:
备份域提供以下供电:
- 外部低频时钟晶振
- RTC
- 上电复位
- 电源转换
1.2V域
1.2V域如下图所示:
这个作用域主要提供:
- AHB高速总线的供电
- APB外设总线的供电
- 内存
- Cortex-M4的供电
省电模式
总共有三个省电模式:
- 睡眠模式
- 深度睡眠模式
- 待机模式
睡眠模式
睡眠模式时,会关闭 1.2V域 中的 Cortex-M4的供电。
深度睡眠模式
进入深度模式时,会关闭 1.2V域 中的所有供电 ;同时关闭VDD/VDDA域中的HXTAL``IRC16M``PLLs
待机模式
进入待机模式时,会关闭1.2V域 中的所有供电 ;同时关闭VDD/VDDA域 中的LDO、IRC16M、HXTAL、PLLs;
几种模式总结
WFI和WFE指令
在ARM架构中,WFI(Wait For Interrupt)和 WFE(Wait For Event)是用于使处理器进入低功耗状态的指令。这两个指令主要用于在空闲时暂停处理器的执行,以节省功耗。
WFI指令:
WFI 指令使处理器进入等待中断状态。当处理器执行到 WFI 时,它会进入低功耗模式,直到有一个中断请求到达,将处理器唤醒。在等待中断期间,处理器会停止执行指令,以减少功耗。
WFE指令:
WFE 指令与 WFI 类似,但它不仅能够等待中断,还能够等待事件。事件是由外部设备或其他处理器触发的信号。当执行到 WFE 时,处理器会进入低功耗模式,直到有中断或事件到达,将处理器唤醒。与 WFI 不同,WFE 可以等待中断或事件中的任何一个。
案例需求
- 让LED1 每间隔一段时间闪烁(500ms)
- 通过串口切换 省电模式
- 为KEY2配置外部中断按键,按下时LED1自动切换开关
- 为PA0配置外部中断按键,按下时LED1自动切换开关
模式初始化
static void sleep_mode() {
// 电池管理单元时钟
rcu_periph_clock_enable(RCU_PMU);
// 进入睡眠模式
pmu_to_sleepmode(WFI_CMD);
}
static void deepsleep_mode() {
// 电池管理单元时钟
rcu_periph_clock_enable(RCU_PMU);
// 进入深度睡眠模式
pmu_to_deepsleepmode(PMU_LDO_LOWPOWER, PMU_LOWDRIVER_ENABLE, WFI_CMD);
// 把主频设置回来
SystemInit();
}
static void standby_mode() {
// 电池管理单元时钟
rcu_periph_clock_enable(RCU_PMU);
// 清理待机模式标记
pmu_flag_clear(PMU_FLAG_RESET_STANDBY);
// 启用唤醒引脚
pmu_wakeup_pin_enable();
// 进入待机模式
pmu_to_standbymode();
}
源码
#include "gd32f4xx.h"
#include "systick.h"
#include <stdio.h>
#include <string.h>
#include "main.h"
#include "USART0.h"
#include "EXTI.h"
void EXTI_on_trig(exti_line_enum linex){
if(linex == EXTI_1){
printf("Key Trig\n");
}
}
void sleep_mode(){ // 睡眠模式
// PMU -> RCU
rcu_periph_clock_enable(RCU_PMU);
printf("sleepmode1\n");
// sleep mode
pmu_to_sleepmode(WFI_CMD);
printf("sleepmode2\n");
}
void deepsleep_mode(){ // 深度睡眠模式
// PMU -> RCU
rcu_periph_clock_enable(RCU_PMU);
printf("deepsleep 1\n");
// deepsleep
pmu_to_deepsleepmode(PMU_LDO_LOWPOWER, PMU_LOWDRIVER_ENABLE, WFI_CMD);
// 把主频设置回来
SystemInit();
printf("deepsleep 2\n");
}
void standby_mode(){ // 待机模式
// PMU -> RCU
rcu_periph_clock_enable(RCU_PMU);
/* 清理待机模式标记 */
pmu_flag_clear(PMU_FLAG_RESET_STANDBY);
/* 启用唤醒按钮 enable PMU wakeup pin */
pmu_wakeup_pin_enable();
printf("standby 1\n");
// standby待机模式
pmu_to_standbymode();
printf("standby 2\n");
}
void USART0_on_recv(uint8_t* data, uint32_t len) {
printf("recv: %s\n", data);
switch(data[0]){
case 0x00: // 睡眠模式
sleep_mode();
break;
case 0x01: // 深度睡眠模式
deepsleep_mode();
break;
case 0x02: // 待机模式
standby_mode();
break;
default:
break;
}
}
static void GPIO_config(){
// 初始化GPIO PB2
rcu_periph_clock_enable(RCU_GPIOB);
gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_2);
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, GPIO_PIN_2);
}
static void delay(){
uint32_t i = 50000000;
while(i--){
__NOP();
}
}
int main(void)
{
nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);
// systick_config();
USART0_init();
EXTI_init();
GPIO_config();
printf("Main Init\n");
while(1)
{
// 让PB2切换亮灭
gpio_bit_toggle(GPIOB, GPIO_PIN_2);
// delay_ms(500);
// 使用自己的睡眠函数
delay();
}
}
注意:
中断优先级配置为NVIC_PRIGROUP_PRE2_SUB2情况下:
- 串口的抢占优先级不能设置为0,否则系统无法正常睡眠,或不能正常唤醒
- 深度睡眠的外部中断的抢占优先级需要设置为0或1 (比串口高),否则无法正常唤醒
总结
电池管理单元(PMU)作为电源管理的核心,负责调控各种电源域,包括VDD/VDDA域、1.2V域和备份域。不同的电源域为系统的不同部分提供电源支持,保证了系统在不同工作模式下的正常运行。为了降低功耗,ARM架构中引入了几种省电模式,如睡眠模式、深度睡眠模式和待机模式,每种模式在不同场景下可以有效地降低系统的能耗。通过合理选择和配置这些省电模式,开发人员可以根据具体需求优化设备的能效和电池寿命,从而提升整体系统的性能和可靠性。