Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
PM组件
RT-Thread
RT-Thread PM框架使用答疑 -- 02
发布于 2021-12-05 19:26:07 浏览:1527
订阅该版
[tocm] [RT-Thread 电源管理与功耗调优系列 - 目录](https://club.rt-thread.org/ask/article/3419.html) [RT-Thread PM组件2.0更新版 -- 使用指南](https://club.rt-thread.org/ask/article/3323.html) [RT-Thread PM组件2.0更新版 -- 介绍](https://club.rt-thread.org/ask/article/3244.html) [RT-Thread PM框架使用答疑 -- 01](https://club.rt-thread.org/ask/article/3198.html) [RT-Thread PM框架使用答疑 -- 02](https://club.rt-thread.org/ask/article/3201.html) [RT-Thread PM2.0 应用 -- 平台适配篇](https://club.rt-thread.org/ask/article/2517.html) [RT-Thread IDLE线程栈过小引起的调试异常](https://club.rt-thread.org/ask/article/292.html) [RT-Thread 使能PM组件](https://club.rt-thread.org/ask/article/2287.html) [实践:RT-Thread PM管理实战 系列](https://club.rt-thread.org/ask/article/2282.html) [进阶:RT-Thread精通PM功耗调优 系列](https://club.rt-thread.org/ask/article/2296.html) [上手:产品功耗管理与调优经验分享 系列](https://club.rt-thread.org/ask/article/2707.html) ## 前言 - 本篇为【篇一】的继续,从实际使用RT-Thread PM框架的经验总结出发,顺便解答部分用户问题的疑问、疑点 - RT-Thread PM框架现为PM2.0(姑且这么称呼),近期会继续更新 - 很多初次接触【功耗管理】的用户,对如何管理功耗,并不清楚,如何利用PM框架的API,也不太清楚 ## PM框架的运行 - 在STM32L4系列的BSP上,开启了PM框架,貌似可以直接运行,当然,这是框架运行,并没有直接管理自己的系统功耗,毕竟产品的功耗,不只是管理MCU本身的功耗,片外外设或模块,如LCD、TP、BT等,都是耗电大户。 - 其他的BSP,开启了PM框架,发现,根本没有任何的效果,原来,框架的运行,需要平台的适配,PM框架初始化等。 > PM框架开启后,发现【深睡眠】无法唤醒的问题分析 - 硬件平台是:NUCLEO-L476ZG STM32L4系列的MCU,发现开启PM框架后,无法唤醒 - 深睡眠这里是STM32L4系列的【STOP2】模式,这个模式的特点是中断可以唤醒,Lptimer的中断,也可以唤醒 - 默认lptimer已经开启,PM框架开启后,如果有定时器,如500ms的`rt_thread_mdelay(500)`,会在进入深睡眠前,把定时器的超时【剩余】时间,设置到lptimer,并开启lptimer,保证系统定时器的深睡眠下的唤醒,这就是tickless功能。如果一段时间,系统空闲,就进入睡眠,系统工作的时候,就会唤醒工作,工作完,又进入睡眠。 - 确认lptimer配置是否准确:发现配置正确 - 软件调试,确认PM框架进入深睡眠的代码,确认正确 - 【发现问题】进入深睡眠后,系统唤醒了,但是,异常了,唤醒后的时钟不准确 - 【解决思路】STM32L4系列的STOP模式,唤醒后时钟要重新配置(外设的寄存器等配置保留),MCU的内核与大部分外设的时钟停掉了。等于STOP模式唤醒后,需要重新配置(初始化)一下系统的时钟。这里时钟配置在:board.c中的:`SystemClock_ReConfig`中实现,发现:`SystemClock_MSI_ON();`这个配置影响了,所以,注释掉这个配置,系统工作正常了。 > PM框架开启后,通过msh串口命令手动更改模式,不生效 - `pm_request` 这个命令,后面的参数是【睡眠模式】 ```c PM_SLEEP_MODE_NONE = 0, PM_SLEEP_MODE_IDLE, PM_SLEEP_MODE_LIGHT, PM_SLEEP_MODE_DEEP, PM_SLEEP_MODE_STANDBY, PM_SLEEP_MODE_SHUTDOWN, ``` - 如请求:IDLE模式,执行:`pm_request 1`,这里的1 代表了 PM_SLEEP_MODE_IDLE 这个【宏】的值 - 如请求:LIGHT模式,执行:`pm_request 2`,这里的2 代表了 PM_SLEEP_MODE_LIGHT这个【宏】的值 - 如请求:NONE模式,执行:`pm_request 0`,这里的0,代表了 PM_SLEEP_MODE_NONE 这个【宏】的值 - 如上使用:`pm_request 2 `,则使用:`pm_release 2` 释放请求 > PM框架,使用带【模块ID】的睡眠请求与释放命令 ```c enum pm_module_id { PM_NONE_ID = 0, PM_POWER_ID, PM_BOARD_ID, PM_BSP_ID, PM_MAIN_ID, PM_PMS_ID, PM_PMC_ID, PM_TASK_ID, PM_SPI_ID, PM_I2C_ID, PM_UART_ID, PM_CAN_ID, PM_ETH_ID, PM_SENSOR_ID, PM_LCD_ID, PM_KEY_ID, PM_TP_ID, PM_MODULE_MAX_ID, /* enum must! */ }; ``` - PM框架的pm.h,默认定义了一些【电源模块ID】,这些可以直接使用 - 如果用户想定义自己的模块ID,需要配置:【PM_HAS_CUSTOM_CONFIG】,并自己建一个文件`pm_cfg.h`,在这个文件里,定义自己的各个模块ID。 - 如 PM_SPI_ID 请求 IDLE模式,命令:`pm_module_request 8 1`,这里的8,是PM_SPI_ID【宏】的值, 1 代表睡眠模式:PM_SLEEP_MODE_IDLE,可以通过pm_dump 命令查看。 ```c msh >pm_module_request 8 1 msh >pm_dump | Power Management Mode | Counter | Timer | +-----------------------+---------+-------+ | None Mode | 1 | 0 | | Idle Mode | 2 | 0 | | LightSleep Mode | 0 | 0 | | DeepSleep Mode | 0 | 1 | | Standby Mode | 0 | 0 | | Shutdown Mode | 0 | 0 | +-----------------------+---------+-------+ pm current sleep mode: None Mode pm current run mode: Normal Speed | module | busy | start time | timeout | +--------+------+------------+-----------+ | 0002 | 0 | 0x00000000 | 0x00000000 | | 0008 | 0 | 0x00000000 | 0x00000000 | +--------+------+------------+-----------+ msh > ``` - 释放 PM_SPI_ID 请求的 IDLE模式,命令:`pm_module_release 8 1`,这里的8,是PM_SPI_ID【宏】的值, 1 代表睡眠模式:PM_SLEEP_MODE_IDLE,可以通过pm_dump 命令查看。 - 注意引用计数:请求几次,就要释放几次,才能真正的释放这个电源模式。如上面,IDLE模式被请求了两次,需要释放两次 ```c msh >pm_module_release 8 1 msh >pm_dump | Power Management Mode | Counter | Timer | +-----------------------+---------+-------+ | None Mode | 1 | 0 | | Idle Mode | 1 | 0 | /* 这里引用计数-1 */ | LightSleep Mode | 0 | 0 | | DeepSleep Mode | 0 | 1 | | Standby Mode | 0 | 0 | | Shutdown Mode | 0 | 0 | +-----------------------+---------+-------+ pm current sleep mode: None Mode pm current run mode: Normal Speed | module | busy | start time | timeout | +--------+------+------------+-----------+ | 0002 | 0 | 0x00000000 | 0x00000000 | | 0008 | 0 | 0x00000000 | 0x00000000 | +--------+------+------------+-----------+ msh >pm_module_release 8 1 msh >pm_du pm_dump msh >pm_dump | Power Management Mode | Counter | Timer | +-----------------------+---------+-------+ | None Mode | 1 | 0 | | Idle Mode | 0 | 0 | /* 这里引用计数为0了 */ | LightSleep Mode | 0 | 0 | | DeepSleep Mode | 0 | 1 | | Standby Mode | 0 | 0 | | Shutdown Mode | 0 | 0 | +-----------------------+---------+-------+ pm current sleep mode: None Mode pm current run mode: Normal Speed | module | busy | start time | timeout | +--------+------+------------+-----------+ | 0002 | 0 | 0x00000000 | 0x00000000 | +--------+------+------------+-----------+ /* 电源模块ID 0008,释放了 */ ``` ## PMS 电源管理 - 按键唤醒示例:系统进入深睡眠(DEEP),通过按键中断唤醒并请求指定的电源模式 - 【NUCLEO-L476RG】开发板,只有一个用户的按键,引脚为:【PC13】,换算成RT-Thread PIN num,为:`16 + 16 + 13 = 45` - Key 代码如下: ```c #include "key.h" #include
#define DBG_ENABLE #define DBG_SECTION_NAME "key" #define DBG_LEVEL DBG_LOG #include
#define PIN_KEY0 45 /* PC13 32+13=45 */ void key0_irq_callback(void *parameter) { static uint8_t key0_status = 0x00; key0_status ^= 0x01; if(key0_status == 0x00) rt_pm_module_release(PM_BOARD_ID, PM_SLEEP_MODE_IDLE); /* 按键释放IDLE模式,再次进入深睡眠 */ else rt_pm_module_request(PM_BOARD_ID, PM_SLEEP_MODE_IDLE); /* 按键唤醒,请求IDLE模式 */ LOG_D("[key0_irq]\n"); } /* 按键初始化,配置中断,默认上拉,下降沿触发中断 */ void key_gpio_init(void) { LOG_D("key_gpio_init.\n"); /* set key pin mode to input */ LOG_D("PIN_KEY0=%d\n", PIN_KEY0); rt_pin_mode(PIN_KEY0, PIN_MODE_INPUT_PULLUP); /* set interrupt mode and attach interrupt callback function */ rt_pin_attach_irq(PIN_KEY0, PIN_IRQ_MODE_FALLING, key0_irq_callback, RT_NULL); /* enable interrupt */ rt_pin_irq_enable(PIN_KEY0, PIN_IRQ_ENABLE); } ``` - 测试验证:按键一次,进入深睡眠,此时串口shell无法输入命令,再次按键,系统唤醒,shell命令正常输入 - 反复测试,发现电源模式的切换正常 - LED在【深睡眠】下闪烁,说明系统lptimer工作正常,系统tickless模式正常 ## PM适配到其他平台 - 实际项目中,PM框架,已经在多个平台做了适配 - 适配主要实现的文件为: - drv_pm.c :实现【睡眠函数 sleep】,初始化PM框架 ```c /** * This function will put STM32L4xx into sleep mode. * * @param pm pointer to power manage structure */ static void sleep(struct rt_pm *pm, uint8_t mode) { switch (mode) { case PM_SLEEP_MODE_NONE: break; case PM_SLEEP_MODE_IDLE: pm_bsp_enter_idle(pm); break; case PM_SLEEP_MODE_LIGHT: pm_bsp_enter_light(pm); break; case PM_SLEEP_MODE_DEEP: pm_bsp_enter_deepsleep(pm); break; case PM_SLEEP_MODE_STANDBY: pm_bsp_enter_standby(pm); break; case PM_SLEEP_MODE_SHUTDOWN: pm_bsp_enter_shutdown(pm); break; default: RT_ASSERT(0); break; } } ``` - drv_lptim.c :实现lptimer功能(用于tickless),用于系统tick补偿,因为深睡眠下,系统的systick可能无法工作。 - pms.c :用户的电源管理,用于细化外设开关的管理、定时器的管理、引脚管理等 ```c void pm_bsp_enter_idle(struct rt_pm *pm) { __WFI(); } void pm_bsp_enter_light(struct rt_pm *pm) { if (pm->run_mode == PM_RUN_MODE_LOW_SPEED) { /* Enter LP SLEEP Mode, Enable low-power regulator */ HAL_PWR_EnterSLEEPMode(PWR_LOWPOWERREGULATOR_ON, PWR_SLEEPENTRY_WFI); } else { /* Enter SLEEP Mode, Main regulator is ON */ HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI); } } void bsp_DisableSystick(void) { /* Disable SysTick */ SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; } void bsp_enableSystick(void) { /* Disable SysTick */ SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; } void pm_bsp_enter_deepsleep(struct rt_pm *pm) { /* Enter STOP 2 mode */ HAL_PWREx_EnterSTOP2Mode(PWR_STOPENTRY_WFI); //SystemClock_80M(); SystemClock_ReConfig(pm->run_mode); } void pm_bsp_enter_standby(struct rt_pm *pm) { /* Enter STANDBY mode */ HAL_PWR_EnterSTANDBYMode(); } void pm_bsp_enter_shutdown(struct rt_pm *pm) { /* Enter SHUTDOWNN mode */ HAL_PWREx_EnterSHUTDOWNMode(); } void pms_debug_disable(void) { HAL_PWREx_DisablePullUpPullDownConfig(); HAL_DBGMCU_DisableDBGStopMode(); HAL_DBGMCU_DisableDBGSleepMode(); HAL_DBGMCU_DisableDBGStandbyMode(); } void pms_debug_enable(void) { HAL_DBGMCU_EnableDBGStopMode(); HAL_DBGMCU_EnableDBGSleepMode(); HAL_DBGMCU_EnableDBGStandbyMode(); } ``` - 注意,如果系统没有lptimer,也就是说,系统在【深睡眠】下,任何定时器都无法使用,可以尝试RTC alarm唤醒 - 如果不需要lptimer定时器唤醒,lptimer功能可以关闭,注意系统【睡眠】时的systick,下次【唤醒】后,不会补偿,接着跑,类似于整个睡眠期间是【冻结】的。 - 关闭lptimer: ```c int drv_pm_hw_init(void) { static const struct rt_pm_ops _ops = { sleep, run, 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; /* ******PM框架不启用lptimer */ /* initialize system pm module */ rt_system_pm_init(&_ops, timer_mask, RT_NULL); return 0; } ``` ## PM框架的更新 - 最近根据实际需要,更新了PM框架,近期会合入RT-Thread master,优化【电源模块ID】管理,优化睡眠逻辑,提供更方便的API,用于管理复杂产品的电源管理 - 当然,PM组件的持续发展离不开【大家】的使用、建议、经验积累与分享,若大家有PM组件使用上的问题、建议,可以积极提出。 - 开启【深睡眠】,可能软件无法【下载程序】,可以唤醒MCU再下载,或者重启下载,注意开机不要立即让系统进入【深睡眠】。 ![2021-12-05_170856.png](https://oss-club.rt-thread.org/uploads/20211205/64b6f6dd25f3e4822c7223dcd762e03b.png.webp) - 如上,说明系统进入【深睡眠】,下载需要按键唤醒或【复位】系统 ## 小结 - 本篇主要关注PM框架的使用相关的问题 - 只有多动手调试与实践,才会正确的使用,让功耗管理更【简单】 ## 测试工程 - `https://gitee.com/zhangsz0516/nucleo_l476rg_pm.git`
3
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
张世争
学以致用
文章
131
回答
813
被采纳
177
关注TA
发私信
相关文章
1
RT-THREAD在STM32H747平台上移植lwip
2
正点原子miniSTM32开发板读写sdcard
3
反馈rtt串口驱动对低功耗串口lpuart1不兼容的问题
4
Keil MDK 移植 RT-Thread Nano
5
RT1061/1052 带 RTT + LWIP和LPSPI,有什么坑要注意吗?
6
RT thread HID 如何收发数据
7
求一份基于RTT系统封装好的STM32F1系列的FLASH操作程序
8
RT-Thread修改项目名称之后不能下载
9
rt-studio编译c++
10
有木有移植rt-thread(nano)到riscv 32位MCU上
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
I2C_IIC
ESP8266
UART
WIZnet_W5500
ota在线升级
PWM
cubemx
flash
freemodbus
BSP
packages_软件包
潘多拉开发板_Pandora
定时器
ADC
flashDB
GD32
socket
编译报错
中断
Debug
rt_mq_消息队列_msg_queue
SFUD
msh
keil_MDK
ulog
C++_cpp
MicroPython
本月问答贡献
xusiwei1236
8
个答案
2
次被采纳
踩姑娘的小蘑菇
1
个答案
2
次被采纳
用户名由3_15位
7
个答案
1
次被采纳
bernard
4
个答案
1
次被采纳
RTT_逍遥
3
个答案
1
次被采纳
本月文章贡献
聚散无由
2
篇文章
15
次点赞
catcatbing
2
篇文章
5
次点赞
Wade
2
篇文章
3
次点赞
Ghost_Girls
1
篇文章
6
次点赞
YZRD
1
篇文章
2
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部