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

一、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和 PLL1、关闭 1.2V 电源域的供电;2、关闭 IRC16M、HXTAL和 PLL
LDO状态开启(正常功耗,正常驱动模式)开启(正常功耗或低功耗模式,正常驱动或低驱动模式)关闭
配置SLEEPDEEP=0SLEEPDEEP=1,STBMOD =0SLEEPDEEP=1,STBMOD=1,WURST=1
进入指令WFI或 WFEWFI或 WFEWFI或 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、睡眠模式

复制
static void sleep_mode() {

    // 电池管理单元时钟

    rcu_periph_clock_enable(RCU_PMU);

    // 进入睡眠模式

    pmu_to_sleepmode(WFI_CMD);

 

}

2、深度睡眠模式

复制
static void deepsleep_mode() {

    // 电池管理单元时钟

    rcu_periph_clock_enable(RCU_PMU);

    // 进入深度睡眠模式

    pmu_to_deepsleepmode(PMU_LDO_LOWPOWER, PMU_LOWDRIVER_ENABLE, WFI_CMD);

 

}

3、待机模式

复制
static void standby_mode() {

    // 电池管理单元时钟

    rcu_periph_clock_enable(RCU_PMU);

                pmu_wakeup_pin_enable();

    // 进入待机模式

                pmu_to_standbymode();

}

源码:

复制
 

#include "gd32f4xx.h"

#include "systick.h"

#include <stdio.h>

#include "main.h"

#include "Usart0.h"

 

 

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);

 

}

 

static void standby_mode() {

    // 电池管理单元时钟

    rcu_periph_clock_enable(RCU_PMU);

                pmu_wakeup_pin_enable();

    // 进入待机模式

                pmu_to_standbymode();

}

 

void Usart0_on_recv(uint8_t* data, uint32_t len) {

    printf("recv: %s\r\n", data);

 

    if(data[0] == 0x00) {

        printf("sleep mode \r\n");

        sleep_mode();

    } else if(data[0] == 0x01) {

        printf("deepsleep mode \r\n");

        deepsleep_mode();

                                SystemInit();

    } else if(data[0] == 0x02) {

        printf("standby mode \r\n");

        standby_mode();

    } 

}

 

static void EXTI0_config() {

    uint32_t extix = EXTI_0;

    uint32_t extix_irq = EXTI0_IRQn;

    uint32_t extix_irq_pre = 1;

    uint32_t extix_irq_sub = 1;

 

    uint32_t extix_trig = EXTI_TRIG_BOTH;

 

    uint32_t extix_port_rcu = RCU_GPIOA;

    uint32_t extix_port = GPIOA;

    uint32_t extix_pin = GPIO_PIN_0;

    uint32_t extix_src_port = EXTI_SOURCE_GPIOA;

    uint32_t extix_src_pin = EXTI_SOURCE_PIN0;

 

    /*************** gpio ****************/

    // PA0,

    // 时钟初始化

    rcu_periph_clock_enable(extix_port_rcu);

    // 配置GPIO模式

    gpio_mode_set(extix_port, GPIO_MODE_INPUT, GPIO_PUPD_NONE, extix_pin);

 

    /*************** exti ****************/

    // 时钟配置

    rcu_periph_clock_enable(RCU_SYSCFG);

    // 配置中断源

    syscfg_exti_line_config(extix_src_port, extix_src_pin);

    // 中断初始化

    exti_init(extix, EXTI_INTERRUPT, extix_trig);

 

    // 配置中断优先级

    nvic_irq_enable(extix_irq, extix_irq_pre, extix_irq_sub);

    // 使能中断

    exti_interrupt_enable(extix);

    // 清除中断标志位

    exti_interrupt_flag_clear(extix);

}

 

static void EXTI1_config() {

    uint32_t extix = EXTI_1;

    uint32_t extix_irq = EXTI1_IRQn;

    uint32_t extix_irq_pre = 1;

    uint32_t extix_irq_sub = 1;

 

    uint32_t extix_trig = EXTI_TRIG_BOTH;

 

    uint32_t extix_port_rcu = RCU_GPIOD;

    uint32_t extix_port = GPIOD;

    uint32_t extix_pin = GPIO_PIN_1;

    uint32_t extix_src_port = EXTI_SOURCE_GPIOD;

    uint32_t extix_src_pin = EXTI_SOURCE_PIN1;

 

    /*************** gpio ****************/

    // PA0,

    // 时钟初始化

    rcu_periph_clock_enable(extix_port_rcu);

    // 配置GPIO模式

    gpio_mode_set(extix_port, GPIO_MODE_INPUT, GPIO_PUPD_NONE, extix_pin);

 

    /*************** exti ****************/

    // 时钟配置

    rcu_periph_clock_enable(RCU_SYSCFG);

    // 配置中断源

    syscfg_exti_line_config(extix_src_port, extix_src_pin);

    // 中断初始化

    exti_init(extix, EXTI_INTERRUPT, extix_trig);

 

    // 配置中断优先级

    nvic_irq_enable(extix_irq, extix_irq_pre, extix_irq_sub);

    // 使能中断

    exti_interrupt_enable(extix);

    // 清除中断标志位

    exti_interrupt_flag_clear(extix);

}

 

void EXTI0_IRQHandler() {

    // 判断寄存器状态

    if(SET == exti_interrupt_flag_get(EXTI_0)) {

        if(gpio_input_bit_get(GPIOA, GPIO_PIN_0) == SET)

        {

            /* 按键按下操作的功能 */

            gpio_bit_toggle(GPIOG, GPIO_PIN_3);

            printf("PA0 press!\r\n");

        } else {

            /* 按键松开操作的功能 */

            printf("PA0 release!\r\n");

        }

    }

    // 清除中断标志位

    exti_interrupt_flag_clear(EXTI_0);

}

 

void EXTI1_IRQHandler() {

    // 判断寄存器状态

    if(SET == exti_interrupt_flag_get(EXTI_1)) {

        if(gpio_input_bit_get(GPIOD, GPIO_PIN_1) == SET)

        {

            gpio_bit_toggle(GPIOD, GPIO_PIN_7);

            printf("key2 press!\r\n");

        } else {

            /* 按键松开操作的功能 */

            printf("key2 release!\r\n");

        }

    }

    // 清除中断标志位

    exti_interrupt_flag_clear(EXTI_1);

}

 

 

int main(void)

{

    systick_config();

    Usart0_init();

                EXTI0_config();

                EXTI1_config();

                

                // LED1

    rcu_periph_clock_enable(RCU_GPIOE);

    gpio_mode_set(GPIOE, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_3);

    gpio_output_options_set(GPIOE, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, GPIO_PIN_3);

                // LED2

                rcu_periph_clock_enable(RCU_GPIOD);

    gpio_mode_set(GPIOD, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_7);

    gpio_output_options_set(GPIOD, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, GPIO_PIN_7);

                // LED3

                rcu_periph_clock_enable(RCU_GPIOG);

    gpio_mode_set(GPIOG, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_3);

    gpio_output_options_set(GPIOG, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, GPIO_PIN_3);

 

    while(1) {

        gpio_bit_toggle(GPIOE, GPIO_PIN_3);

        delay_1ms(500);

    }

}


 

注意:

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

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



六、总结

 

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

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

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


---------------------
作者:虚幻的是灵魂
链接:https://bbs.21ic.com/icview-3400864-1-1.html
来源:21ic.com
此文章已获得原创/原创奖标签,著作权归21ic所有,任何人未经允许禁止转载。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值