云计算百科
云计算领域专业知识百科平台

STM32L4移植 rt-thread PM组件详解

一、STM32L4 的低功耗模式简介

STM32L4 系列微控制器专为低功耗应用设计,提供多种低功耗模式以满足不同应用场景的需求。主要模式包括运行模式、低功耗运行模式、睡眠模式、低功耗睡眠模式、停止模式、低功耗停止模式和待机模式。

运行模式(Run Mode)

在运行模式下,所有外设和内核正常工作,功耗相对较高。通过动态电压调节(DVC)和频率调节(如 MSI、HSI、HSE)可优化功耗。典型电流消耗为 100 µA/MHz(CoreMark 测试)。

低功耗运行模式(Low Power Run Mode)

此模式下,CPU 以较低频率运行(通常为 2 MHz),部分外设关闭,电压调节器处于低功耗状态。典型电流消耗为 30 µA/MHz,适用于需要实时响应但功耗敏感的场景。

睡眠模式(Sleep Mode)

CPU 停止运行,但外设和时钟保持活动状态。可通过中断或事件唤醒。典型电流消耗为 10 µA/MHz(外设活动时)。

低功耗睡眠模式(Low Power Sleep Mode)

与睡眠模式类似,但电压调节器切换到低功耗状态,进一步降低功耗。典型电流消耗为 5 µA/MHz。

停止模式(Stop Mode)

内核和大部分外设时钟关闭,仅保留部分关键外设(如 RTC、LCD)活动。唤醒时间较短(约 5 µs)。典型电流消耗为 1 µA(保留 SRAM)。

低功耗停止模式(Low Power Stop Mode)

电压调节器关闭,仅保持极低功耗状态。SRAM 内容可保留,唤醒时间稍长(约 10 µs)。典型电流消耗为 0.5 µA。

待机模式(Standby Mode)

最低功耗模式,仅备份域(如 RTC、备份寄存器)保持供电。SRAM 和寄存器内容丢失,唤醒需复位。典型电流消耗为 0.1 µA(无 RTC)。

下面是各个模式之间的状态转换图:
在这里插入图片描述

二、影响系统功耗的因素

尽管 STM32L476 的低功耗模式很多,但本质上并不复杂,理解它的原理有助于我们移植驱动,同时更好的在产品中选择合适的模式。
最终决定 STM32L476 系统功耗的主要是三个因素:稳压器(voltage regulator)、CPU 工作频率、芯片自身低功耗的处理,下面分别对三个因素进行阐述。

1、稳压器

L4 使用两个嵌入式线性稳压器为所有数字电路、待机电路以及备份时钟域供电,分别是主稳压器(main regulator,下文简称 MR)和低功耗稳压器(low-power regulator,下文简称 LPR)。稳压器在复位后处于使能状态,根据应用模式,选择不同的稳压器对 Vcore 域供电。其中,MR 的输出电压可以由软件配置为不同的范围(Range 1 和 Rnage 2)。

稳压器应用场合
MR(Range 1 Vcore = 1.2V,用于运行模式、睡眠模式和停止模式0,MR 未 Vcore 域提供全功率
MR(Range 2) Vcore = 1.0V,使用的场景同上
LPR 用于低功耗运行模式、低功耗休眠模式、停止模式 1、停止模式2
OFF Standby 和 Shutdown 模式下,MR 和 LPR 都被关闭

2、CPU 工作频率

通过降低 CPU 的主频达到降低功耗的目的: MR 工作在 Range 1 正常模式时,SYSCLK 最高可以工作在 80M; MR 工作在 Range 2 时,SYSCLK 最高不能超过 26 M; 低功耗运行模式和低功耗休眠模式,即 Vcore 域由 LPR 供电,SYSCLK 必须小于 2M。

3、芯片本身的低功耗处理

芯片本身定义了一系列的休眠模式,如 Sleeep、Stop、Standby 和 Shutdown,前面的四种模式功耗逐渐降低,实质是芯片内部通过关闭外设和时钟来实现。

三、移植的具体实现

    上文简要说明 STM32 的低功耗模式和工作原理,下面介绍 RT-Thread PM 的功能和移植接口。
    RT-Thread 低功耗管理系统从设计上分离运行模式和休眠模式,独立管理,运行模式用于变频和变电压,休眠调用芯片的休眠特性。对于多数芯片和开发来说,可能并不需要考虑变频和变电压,仅需关注休眠模式。
    STM32 L4 系列的芯片有运行模式和低功耗运行模式的概念,同时 MR 还有 Range 2 模式,可用于变频场景。
    PM 组件的底层功能都是通过struct rt_pm_ops结构体里的函数完成:

/**
* low power mode operations
*/

struct rt_pm_ops
{
void (*sleep)(struct rt_pm *pm, uint8_t mode);
void (*run)(struct rt_pm *pm, uint8_t mode);
void (*timer_start)(struct rt_pm *pm, rt_uint32_t timeout);
void (*timer_stop)(struct rt_pm *pm);
rt_tick_t (*timer_get_tick)(struct rt_pm *pm);
};

1、配置工程

开启 Env 工具,进入潘多拉开发板的 BSP 目录(rt-thread\\bsp\\stm32\\stm32l475-atk-pandora),在 Env 命令行里输入 menuconfig 进入配置界面配置工程。
配置 PM 组件:勾选 BSP 里面的RT-Thread Components —> Device Drivers —> [*] Using Power Management device drivers:

在这里插入图片描述配置内核选项:使用 PM 组件需要更大的 IDLE 线程的栈,这里使用了1024 字节。例程里还使用 Software timer,所以我们还需要开启相应的配置
在这里插入图片描述
配置完成,保存并退出配置选项,输入命令scons –target=mdk5生成 mdk5 工程;

2、移植休眠模式

移植休眠模式仅需关注 sleep 接口,根据 PM 用户手册相关介绍,首先将 RT-Thread 的休眠模式和 STM32 的模式作一个转换:

RT-ThreadSTM32描述
PM_SLEEP_MODE_NONE Run 正常运行模式,不进行任何降功耗的措施
PM_SLEEP_MODE_IDLE Run 正常运行模式,可选择 WFI(等待中断唤醒)和WFE(等待事件唤醒),此处暂不处理
PM_SLEEP_MODE_LIGHT Sleep 轻度睡眠模式,执行 ST 的 Sleep 模式
PM_SLEEP_MODE_DEEP Stop2 深度睡眠模式,执行 ST 的 Stop2 模式
PM_SLEEP_MODE_STANDBY Standby 待机模式,执行 ST 的 Standby 模式
PM_SLEEP_MODE_SHUTDOWN Shutdown 停止模式,执行 ST 的 Shtudown 模式

下面是具体实现:

#include <board.h>
#include <rtthread.h>
#include <rtdevice.h>

static void sleep(struct rt_pm *pm, uint8_t mode)
{
switch (mode)
{
case PM_SLEEP_MODE_NONE:
break;

case PM_SLEEP_MODE_IDLE:
// __WFI();
break;

case PM_SLEEP_MODE_LIGHT:
/* Enter SLEEP Mode, Main regulator is ON */
HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);
break;

case PM_SLEEP_MODE_DEEP:
/* Enter STOP 2 mode */
HAL_PWREx_EnterSTOP2Mode(PWR_STOPENTRY_WFI);
break;

case PM_SLEEP_MODE_STANDBY:
/* Enter STANDBY mode */
HAL_PWR_EnterSTANDBYMode();
break;

case PM_SLEEP_MODE_SHUTDOWN:
/* Enter SHUTDOWNN mode */
HAL_PWREx_EnterSHUTDOWNMode();
break;

default:
RT_ASSERT(0);
break;
}
}

int rt_hw_pm_init(void)
{
static const struct rt_pm_ops _ops =
{
sleep,
RT_NULL,
RT_NULL,
RT_NULL,
RT_NULL
};

rt_uint8_t timer_mask = 0;

/* Enable Power Clock */
__HAL_RCC_PWR_CLK_ENABLE();

/* initialize system pm module */
rt_system_pm_init(&_ops, timer_mask, RT_NULL);

return 0;
}

INIT_BOARD_EXPORT(rt_hw_pm_init);

目前为止,ST 的休眠模式已经初步加入了,能够满足部分的应用场景。打开命令行,输入请求/释放休眠模式命令,可以观察到功耗显著降低。

3、移植时间补偿接口

某些情况下,我们可能需要系统在空闲时进入 Stop 模式,以达到更低的将功耗效果。L476 Stop 2 模式下的电流可以达到 1.6 uA 左右,ST 手册上对 Stop2 模式的描述如下:

Stop 2 模式基于 Cortex-M4 深度睡眠模式与外设时钟门控。在 Stop 2 模式下, Vcore 域中的所有时钟都会停止, PLL、 MSI、 HSI16 和 HSE 振荡器也被禁止。一些带有唤醒功能(I2C3 和 LPUART)的外设可以开启 HSI16 以获取帧,如果该帧不是唤醒帧,也可以在接收到帧后关闭 HSI16。SRAM1、 SRAM2、 SRAM3 和寄存器内容将保留,所有 I/O 引脚的状态与运行模式下相同。

根据手册可知,Stop 2 模式会关闭系统时钟,当前的 OS Tick 基于内核的 Systick 定时器。那么在系统时钟停止后,OS Tick 也会停止,对于某些依赖 OS Tick 的应用,在进入 Stop 2 模式,又被中断唤醒后,就会出现问题,因此需要在系统唤醒后,对 OS Tick 进行补偿。Stop 2 模式下,绝大多数外设都停止工作,仅低功耗定时器 1(LP_TIM1)选择 LSI 作为时钟源后,仍然能正常运行,所以选择 LP_TIM1 作为 Stop 2 模式的时间补偿定时器。

休眠的时间补偿需要实现三个接口,分别用于启动低功耗定时器、停止定时器、唤醒后获取休眠的 Tick,下面是具体的实现:

static void pm_timer_start(struct rt_pm *pm, rt_uint32_t timeout)
{
RT_ASSERT(pm != RT_NULL);
RT_ASSERT(timeout > 0);

/**
* 当超时为 RT_TICK_MAX 时,表明系统此时没有依赖 OS Tick 的应用,
* 因此不启动低功耗定时器,避免超时唤醒而增加系统功耗
*/

if (timeout != RT_TICK_MAX)
{
/* Convert OS Tick to pmtimer timeout value */
timeout = stm32l4_pm_tick_from_os_tick(timeout);
if (timeout > stm32l4_lptim_get_tick_max())
{
timeout = stm32l4_lptim_get_tick_max();
}

/* Enter PM_TIMER_MODE */
stm32l4_lptim_start(timeout);
}
}

static void pm_timer_stop(struct rt_pm *pm)
{
RT_ASSERT(pm != RT_NULL);

/* Reset pmtimer status */
stm32l4_lptim_stop();
}

static rt_tick_t pm_timer_get_tick(struct rt_pm *pm)
{
rt_uint32_t timer_tick;

RT_ASSERT(pm != RT_NULL);

timer_tick = stm32l4_lptim_get_current_tick();

return stm32l4_os_tick_from_pm_tick(timer_tick);
}

int rt_hw_pm_init(void)
{
static const struct rt_pm_ops _ops =
{
sleep,
RT_NULL,
pm_timer_start,
pm_timer_stop,
pm_timer_get_tick
};

rt_uint8_t timer_mask = 0;

/* Enable Power Clock */
__HAL_RCC_PWR_CLK_ENABLE();

/* initialize timer mask */
timer_mask = 1UL << PM_SLEEP_MODE_DEEP;

/* initialize system pm module */
rt_system_pm_init(&_ops, timer_mask, RT_NULL);

return 0;
}

休眠时间补偿的移植相对并不复杂,根据 Tick 配置低功耗定时器超时,唤醒后获取实际休眠时间并转换为OS Tick,告知 PM 组件即可。另外,从 Stop 2 模式唤醒后,默认会切换到内部的 MSI 时钟,通常需要重新配置时钟树。

4、移植运行模式

STM32L476 的运行模式移植主要是通过改变CPU 频率 和 稳压器,让其工作在 MR Range 2 或者 LP_RUN 模式,两个模式切换都会触发 CPU 频率改变的操作,这是一个比较危险的操作。

/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2019-02-05 gw first version
* 2019-05-05 Zero-Free Adding multiple configurations for system clock frequency
*/

#include <board.h>
#include <rtconfig.h>
#include <drv_common.h>

void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};

#ifdef BSP_USING_ONCHIP_RTC
/**Configure LSE Drive Capability
*/

HAL_PWR_EnableBkUpAccess();
__HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_LOW);
#endif
/**Initializes the CPU, AHB and APB busses clocks
*/

RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLM = 1;
RCC_OscInitStruct.PLL.PLLN = 10;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV7;
RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/**Initializes the CPU, AHB and APB busses clocks
*/

RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
| RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
{
Error_Handler();
}
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART2;
PeriphClkInit.Usart2ClockSelection = RCC_USART2CLKSOURCE_PCLK1;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
/**Configure the main internal regulator output voltage
*/

if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK)
{
Error_Handler();
}
}

#ifdef RT_USING_PM

void SystemClock_MSI_ON(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

/* Initializes the CPU, AHB and APB busses clocks */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI;
RCC_OscInitStruct.MSIState = RCC_MSI_ON;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
RT_ASSERT(0);
}

RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_MSI;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK)
{
Error_Handler();
}
}

void SystemClock_MSI_OFF(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};

RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI;
RCC_OscInitStruct.HSIState = RCC_MSI_OFF;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; /* No update on PLL */
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
}

void SystemClock_80M(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_ClkInitTypeDef RCC_ClkInitStruct;

/**Initializes the CPU, AHB and APB busses clocks */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = 16;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLM = 1;
RCC_OscInitStruct.PLL.PLLN = 10;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV7;
RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}

/**Initializes the CPU, AHB and APB busses clocks
*/

RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
| RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
{
Error_Handler();
}
}

void SystemClock_24M(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_PeriphCLKInitTypeDef PeriphClkInit;

/** Initializes the CPU, AHB and APB busses clocks */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = 16;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLM = 1;
RCC_OscInitStruct.PLL.PLLN = 12;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV7;
RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV8;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB busses clocks */
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
| RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK)
{
Error_Handler();
}
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART2;
PeriphClkInit.Usart2ClockSelection = RCC_USART2CLKSOURCE_PCLK1;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
}

void SystemClock_2M(void)
{
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_OscInitTypeDef RCC_OscInitStruct = {0};

/* MSI is enabled after System reset, update MSI to 2Mhz (RCC_MSIRANGE_5) */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI;
RCC_OscInitStruct.MSIState = RCC_MSI_ON;
RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_5;
RCC_OscInitStruct.MSICalibrationValue = RCC_MSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
/* Initialization Error */
Error_Handler();
}

/* Select MSI as system clock source and configure the HCLK, PCLK1 and PCLK2
clocks dividers */

RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_MSI;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
{
/* Initialization Error */
Error_Handler();
}
}

/**
* @brief Configures system clock after wake-up from STOP: enable HSI, PLL
* and select PLL as system clock source.
* @param None
* @retval None
*/

void SystemClock_ReConfig(uint8_t mode)
{
SystemClock_MSI_ON();

switch (mode)
{
case PM_RUN_MODE_HIGH_SPEED:
case PM_RUN_MODE_NORMAL_SPEED:
SystemClock_80M();
break;
case PM_RUN_MODE_MEDIUM_SPEED:
SystemClock_24M();
break;
case PM_RUN_MODE_LOW_SPEED:
SystemClock_2M();
break;
default:
break;
}

// SystemClock_MSI_OFF();
}

#endif

按下复位按键重启开发板,打开终端软件,我们可以看到有定时输出日志:

\\ | /
RT Thread Operating System
/ | \\ 4.0.1 build May 9 2019
2006 2019 Copyright by rtthread team
msh >current tick: 2001
current tick: 4002
current tick: 6003
current tick: 8004

我们可以在msh里输入pm_dump命令观察PM组件的模式状态:

pm_dump
| Power Management Mode | Counter | Timer |
++++
| None Mode | 0 | 0 |
| Idle Mode | 1 | 0 |
| LightSleep Mode | 1 | 0 |
| DeepSleep Mode | 1 | 1 |
| Standby Mode | 0 | 0 |
| Shutdown Mode | 0 | 0 |
++++
pm current sleep mode: Idle Mode
pm current run mode: Normal Speed
msh >

以上的输出说明,PM 组件里 Idle、Light Sleep、Deep Sleep 都被请求了一次,现在正处于空闲模式(Idle Mode)。

我们依次输入命令pm_release 1和pm_release 2 手动释放 Idle 和 Light Sleep 模式后,将进入Deep Sleep Mode。进入Deep Sleep Mode之后会定时唤醒,shell 还是一直在输出:

msh />pm_release 1
msh />
msh />current tick: 8023
current tick: 10024
current tick: 12025

msh />pm_release 2
msh />
msh />current tick: 14026
current tick: 16027
current tick: 18028
current tick: 20029
current tick: 22030
current tick: 24031

我们可以通过功耗仪器观察功耗的变化。下图是基于 Monsoon Solutions Inc 的 Power Monitor 的运行截图,可以看到随着模式变化,功耗明显变化:
在这里插入图片描述

在这里插入图片描述

赞(0)
未经允许不得转载:网硕互联帮助中心 » STM32L4移植 rt-thread PM组件详解
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!