Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
STM32超低功耗
STM32超低功耗之移植 RT-Thread PM 组件原理分析
发布于 2021-06-25 22:08:42 浏览:1488
订阅该版
[tocm] ## 一, 认识 PM 组件 在上一篇的文章中,介绍了如何移植 RT-Thread PM 组件,PM 组件的作用是通过 RTOS 来统一的管理,超低功耗是一个细致的工作,所以在使用的时候必须要知道 PM 组件中每个 API 的实现及作用,才能最到功耗最优。 ## 二,PM 组件的工作原理 PM 的工作原理,可以从 RT-Thread 的文档中心来获取到,其中最为核心的部分就是下图 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210620215001528.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3doajEyMzk5OQ==,size_16,color_FFFFFF,t_70) 用户的调用 PM 的组件的 API 之后,来申请进入低功耗模式,如果当前没有工作进行,在线程运行到空闲任务的时候就会去尝试切换到对应的低功耗模式,如果对前面的内容还记得话,通过 WFI 进入低功耗模式后是会被 SYSTICK 唤醒的,所以这里根据进入不同的低功耗模式的时候,还要考虑是否要关闭 SYSTICK,关闭 SYSTICK 之后到达线程需要唤醒的时间的时候,系统的 TICK 值需要去补偿,所以在关闭 SYSTICK 的时候之前要启动 LPTIM ,还要得出 LPTIM 运行多长时间之后去唤醒 MCU,唤醒 MCU 之后还要把 SYSTICK 没有运行的这段时间的 OSTICK 补偿上。 ## 三,PM 组件的 API 实现 1. 选择睡眠模式 ``` static rt_uint8_t _pm_select_sleep_mode(struct rt_pm *pm) { int index; rt_uint8_t mode; mode = _pm_default_deepsleep; for (index = PM_SLEEP_MODE_NONE; index < PM_SLEEP_MODE_MAX; index ++) { if (pm->modes[index]) { mode = index; break; } } pm->sleep_mode = mode; return mode; } ``` 这个函数会在后面的源码分析时,经常出现,所以这里放在前面来说 这里主要时通过遍历的方式查找到本次申请将要进入的低功耗模式,这个结果会被记录在全局变量 `pm` 结构体中 如果遍历所有低功耗的类型都已经释放完毕则会进入 `_pm_default_deepsleep` 睡眠模式,这样将会导致某些外设无法使用 2. 请求进入低功耗模式 ``` void rt_pm_request(rt_uint8_t mode) { rt_base_t level; struct rt_pm *pm; if (_pm_init_flag == 0) return; if (mode > (PM_SLEEP_MODE_MAX - 1)) return; level = rt_hw_interrupt_disable(); pm = &_pm; if (pm->modes[mode] < 255) pm->modes[mode] ++; _pm_select_sleep_mode(pm); rt_hw_interrupt_enable(level); } ``` 检查 PM 组件是否已经初始化,检查申请的模式是否超出了当前支持最大的低功耗模式种类,在关中断的状态下申请要进入低功耗的模式的次数加 1 . 3. 释放休眠模式 ``` void rt_pm_release(rt_uint8_t mode) { rt_ubase_t level; struct rt_pm *pm; if (_pm_init_flag == 0) return; if (mode > (PM_SLEEP_MODE_MAX - 1)) return; level = rt_hw_interrupt_disable(); pm = &_pm; if (pm->modes[mode] > 0) pm->modes[mode] --; _pm_select_sleep_mode(pm); rt_hw_interrupt_enable(level); } ``` 检查 PM 组件是否已经初始化,检查申请的模式是否超出了当前支持最大的低功耗模式种类,在关中断的状态下申请要进入低功耗的模式的次数减 1 。 需要注意的是,PM 组件在初始化的时候会设置 `pm->modes[mode] = 0` 这样在 PM 组件启动之后,就会有一个默认的运行状态,如果这个时候直接使用 `pm_release 0` 将会导致进入深度睡眠模式,这个时候终端将无法使用。 4. 驱动层请求进入低功耗模式 ``` void rt_pm_module_request(uint8_t module_id, rt_uint8_t mode) { rt_base_t level; struct rt_pm *pm; if (_pm_init_flag == 0) return; if (mode > (PM_SLEEP_MODE_MAX - 1)) return; if (module_id > (PM_MODULE_MAX_ID - 1)) return; level = rt_hw_interrupt_disable(); pm = &_pm; pm->module_status[module_id].req_status = 0x01; if (pm->modes[mode] < 255) pm->modes[mode] ++; _pm_select_sleep_mode(pm); rt_hw_interrupt_enable(level); } ``` 检查 PM 组件是否已经初始化,检查申请的模式是否超出当前支持的最大的低功耗模式种类,在关中断的状态下标记当前模式下已经请求了当前要进入的低功耗模式。设置当前将要进入的低功耗模式次数加 1 5. 驱动层释放低功耗模式 ``` void rt_pm_module_release(uint8_t module_id, rt_uint8_t mode) { rt_ubase_t level; struct rt_pm *pm; if (_pm_init_flag == 0) return; if (mode > (PM_SLEEP_MODE_MAX - 1)) return; if (module_id > (PM_MODULE_MAX_ID - 1)) return; level = rt_hw_interrupt_disable(); pm = &_pm; if (pm->modes[mode] > 0) pm->modes[mode] --; if (pm->modes[mode] == 0) pm->module_status[module_id].req_status = 0x00; _pm_select_sleep_mode(pm); rt_hw_interrupt_enable(level); } ``` 检查 PM 组件是否已经初始化,检查释放的模式是否已经超出当前支持的最大的功耗模式种类,在关中断的状态下,请求进入低功耗模式的次数减少一次,设置当前模块请求状态为 0 6. 设置低功耗模块需要进入低功耗的时间 ``` void rt_pm_module_delay_sleep(rt_uint8_t module_id, rt_tick_t timeout) { rt_base_t level; struct rt_pm *pm; if (_pm_init_flag == 0) return; if (module_id > (PM_MODULE_MAX_ID - 1)) return; level = rt_hw_interrupt_disable(); pm = &_pm; pm->module_status[module_id].busy_flag = RT_TRUE; pm->module_status[module_id].timeout = timeout; pm->module_status[module_id].start_time = rt_tick_get(); rt_hw_interrupt_enable(level); } ``` 设置低功耗模块进入低功耗的时间,单位是 tick 7. 获取当前模块的运行模式 ``` rt_uint32_t rt_pm_module_get_status(void) { rt_uint8_t index = 0; struct rt_pm *pm; rt_uint32_t req_status = 0x00; pm = &_pm; for (index = 0; index < 32; index ++) { if (pm->module_status[index].req_status == 0x01) req_status |= 1<
= PM_MODULE_MAX_ID) break; } return req_status; } ``` 遍历查找当前模块为 1 的模式,然后返回 8. 获取当前的低功耗模式 ``` rt_uint8_t rt_pm_get_sleep_mode(void) { struct rt_pm *pm; pm = &_pm; return pm->sleep_mode; } ``` 返回当前的低功耗模式 ## 四,总结 主要讲解了 PM 组件在常用 API 及实现原理,可以看到更多 PM 组件仅仅是取到了标记的作用,真正的切换功耗模式是在空闲线程中进行的。这里也就切合了 RTOS 的使用习惯,RTOS 运行到了 IDEL 说明已经没有就绪任务了,说明任务的工作都已经结束,只有保证所有的任务的工作都执行完毕了,才可以降低系统的功耗,这里降低功耗才是有价值的,避免降低功耗导致执行效率的下降。
2
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
whj467467222
开源,分享,交流,共同进步
文章
32
回答
1222
被采纳
149
关注TA
发私信
相关文章
推荐文章
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
DMA
USB
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
I2C_IIC
ESP8266
UART
WIZnet_W5500
ota在线升级
cubemx
PWM
BSP
flash
freemodbus
packages_软件包
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
编译报错
中断
Debug
rt_mq_消息队列_msg_queue
keil_MDK
ulog
SFUD
msh
C++_cpp
MicroPython
本月问答贡献
三世执戟
7
个答案
1
次被采纳
KunYi
5
个答案
1
次被采纳
RTT_逍遥
4
个答案
1
次被采纳
xiaorui
1
个答案
1
次被采纳
JonasWen
1
个答案
1
次被采纳
本月文章贡献
出出啊
1
篇文章
3
次点赞
小小李sunny
1
篇文章
1
次点赞
张世争
1
篇文章
3
次点赞
crystal266
2
篇文章
2
次点赞
whj467467222
2
篇文章
2
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部