ARM32开发——(二十四)电源管理单元

1. 重点

  • 了解什么是电池管理单元PMU
  • 了解ARM32中的电源域
  • 了解几种省电模式

2. 主要内容

2.1 PMU

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

2.2 电源域

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

2.2.1 VDD/VDDA域

VDD/VDDA域如下图:

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

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

备份域如下图:

备份域提供以下供电:

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

1.2V域如下图所示:

这个作用域主要提供:

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

2.3 省电模式

总共有三个省电模式:

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

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

2.3.2 深度睡眠模式

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

2.3.3 待机模式

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

2.3.4 几种模式总结

2.4 WFI和WFE指令

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

2.4.1 WFI指令

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

2.4.2 WFE指令

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

2.5 案例需求

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

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

  • 为PA0配置外部中断按键,按下时LED1自动切换开关
2.5.1 模式初始化
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();
}
2.5.2 源码
#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();
  }
}
2.5.3 注意

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

  1. 串口的抢占优先级不能设置为0,否则系统无法正常睡眠,或不能正常唤醒
  2. 深度睡眠的外部中断的抢占优先级需要设置为0或1 (比串口高),否则无法正常唤醒
  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值