Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
RT-Thread进阶之低功耗PM组件应用笔记
发布于 2020-05-28 17:00:28 浏览:4110
订阅该版
* 本帖最后由 Aladdin-Wang 于 2020-5-28 17:03 编辑 * **STM32L4 移植 PM****STM32L4 的低功耗模式简介:**STM32L4系列 是 ST 公司推出的一款超低功耗的 Crotex-M4 内核的 MCU,支持多个电源管理模式,其中最低功耗 Shutdown 模式下,待机电流仅 30 nA。ST 公司 把 L4系列 的电管管理分为很多种,但各个模式的并非功耗逐级递减的特点,下面是各个模式之间的状态转换图:![FastAdmin](https://img-blog.csdnimg.cn/20200528101720917.png)尽管 STM32L4系列 的低功耗模式很多,但本质上并不复杂,理解它的原理有助于我们移植驱动,同时更好的在产品中选择合适的模式。最终决定 STM32L4系列 系统功耗的主要是三个因素:稳压器(voltage regulator)、CPU 工作频率、芯片自身低功耗的处理,下面分别对三个因素进行阐述。 * 稳压器L4 使用两个嵌入式线性稳压器为所有数字电路、待机电路以及备份时钟域供电,分别是主稳压器(main regulator,下文简称 MR)和低功耗稳压器(low-power regulator,下文简称 LPR)。稳压器在复位后处于使能状态,根据应用模式,选择不同的稳压器对 Vcore 域供电。其中,MR 的输出电压可以由软件配置为不同的范围(Range 1 和 Rnage 2)。稳压器 应用场合 [table=98%] [tr][td]稳压器[/td][td]应用场合[/td][/tr] [tr][td]MR(Range 1)[/td][td]Vcore = 1.2V,用于运行模式、睡眠模式和停止模式0,MR 未 Vcore 域提供全功率[/td][/tr] [tr=rgb(248, 248, 248)][td]MR(Range 2)[/td][td]Vcore = 1.0V,使用的场景同上[/td][/tr] [tr][td]LPR[/td][td]用于低功耗运行模式、低功耗休眠模式、停止模式 1、停止模式2[/td][/tr] [tr=rgb(248, 248, 248)][td]OFF[/td][td]Standby 和 Shutdown 模式下,MR 和 LPR 都被关闭[/td][/tr] [/table]* CPU 工作频率通过降低 CPU 的主频达到降低功耗的目的:MR 工作在 Range 1 正常模式时,SYSCLK 最高可以工作在 80M;MR 工作在 Range 2 时,SYSCLK 最高不能超过 26 M;低功耗运行模式和低功耗休眠模式,即 Vcore 域由 LPR 供电,SYSCLK 必须小于 2M。 * 芯片本身的低功耗处理芯片本身定义了一系列的休眠模式,如 Sleeep、Stop、Standby 和 Shutdown,前面的四种模式功耗逐渐降低,实质是芯片内部通过关闭外设和时钟来实现。 **配置工程**配置 PM 组件:![FastAdmin](https://img-blog.csdnimg.cn/20200526165436512.png)配置内核选项:使用 PM 组件需要更大的 IDLE 线程的栈,这里使用了1024 字节![FastAdmin](https://img-blog.csdnimg.cn/20200528101546886.png)在空闲线程中会调用rt_system_power_manager接口来进入低功耗模式:![FastAdmin](https://img-blog.csdnimg.cn/20200528152744667.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3NpbmF0XzMxMDM5MDYx,size_16,color_FFFFFF,t_70)/** * This function will enter corresponding power mode. */ void rt_system_power_manager(void) { rt_uint8_t mode; if (_pm_init_flag == 0) return; /* CPU frequency scaling according to the runing mode settings */ _pm_frequency_scaling(&_pm); /* Low Power Mode Processing */ mode = _pm_select_sleep_mode(&_pm); _pm_change_sleep_mode(&_pm, mode); } 保存后,可以看到pm.c已经被添加到了工程:![FastAdmin](https://img-blog.csdnimg.cn/20200528102823275.png)然后添加PM组件的设备驱动,驱动的最新地址:[https://gitee.com/sunwancn/rt-thread/tree/pm-ports-stm32-new/](https://gitee.com/sunwancn/rt-thread/tree/pm-ports-stm32-new/)拷贝如下四个文件到工程的drivers文件夹下:![FastAdmin](https://img-blog.csdnimg.cn/20200528145755889.png)本项目选择的是使用RTC作为STOP后的时间补偿,所以需要打开rtc设备和所使用的宏:![FastAdmin](https://img-blog.csdnimg.cn/20200528145927754.png)
查看更多
4
个回答
默认排序
按发布时间排序
Aladdin-Wang
认证专家
2020-05-28
这家伙很懒,什么也没写!
[i=s] 本帖最后由 Aladdin-Wang 于 2020-5-28 17:04 编辑 [/i] 应用示例: 此程序主要实现开机后经过10秒后进入 STOP 模式,然后每经过5秒 SLEEP 模式和 STOP 模式互相切换,如此循环往复,同时经过一个循环后,切换 MCU 的运行频率,验证运行的稳定性。并且打开了回调和中断唤醒,在进入睡眠和唤醒后会分别熄灭和点亮LED灯,在睡眠时间可以通过外部中断唤醒: /* * Copyright (c) 2006-2018, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2018-11-06 SummerGift first version */ #include
#include
#include
#include
#define LOG_TAG "PM.test" #define LOG_LVL LOG_LVL_DBG #include
/* defined the LED0 pin: PB13 */ #define LED0_PIN GET_PIN(C, 6) #define MCU_IRQ_WAKE_PIN GET_PIN(C, 9) static RTC_HandleTypeDef hrtc; static RTC_TimeTypeDef curtime = {0}; static RTC_TimeTypeDef alarmtime = {0}; static RTC_AlarmTypeDef alarm = {0}; static struct rt_semaphore wake_sem; static rt_uint8_t sleep_mode = PM_SLEEP_MODE_DEEP; /* STOP 模式 */ static rt_uint8_t run_mode = PM_RUN_MODE_NORMAL_SPEED; static rt_uint32_t get_interval(void); static void get_rtc_time(RTC_TimeTypeDef *time); static rt_uint8_t mode_loop(void); static rt_uint8_t issleep = 0; /* 中断回调函数 */ static void MCU_IRQ_WAKE(void *args) { if(issleep) { rt_kprintf("MCU_IRQ_WAKE!\n"); rt_sem_release(&wake_sem); issleep = 0; } } static void pm_botify(uint8_t event, uint8_t mode, void *data) { if(event == RT_PM_ENTER_SLEEP && mode == PM_SLEEP_MODE_DEEP) { rt_pin_write(LED0_PIN, PIN_HIGH); issleep = 1; } else if (event == RT_PM_EXIT_SLEEP && mode == PM_SLEEP_MODE_DEEP ) { rt_pin_write(LED0_PIN, PIN_LOW); } } int pm_test(void) { hrtc.Instance = RTC; rt_sem_init(&wake_sem, "wake_sem", 0, RT_IPC_FLAG_FIFO); rt_pm_notify_set(pm_botify,0); /* 按键0引脚为输入模式 */ rt_pin_mode(MCU_IRQ_WAKE_PIN, PIN_MODE_INPUT_PULLDOWN); /* 绑定中断,上升沿模式,回调函数名为beep_on */ rt_pin_attach_irq(MCU_IRQ_WAKE_PIN, PIN_IRQ_MODE_RISING, MCU_IRQ_WAKE, RT_NULL); /* 使能中断 */ rt_pin_irq_enable(MCU_IRQ_WAKE_PIN, PIN_IRQ_ENABLE); rt_thread_mdelay(10000); #ifdef RT_USING_PM /* 申请低功耗模式 */ rt_pm_request(sleep_mode); #endif get_rtc_time(&curtime); if (sleep_mode == PM_SLEEP_MODE_STANDBY) { /* 设置休眠,闹钟 20 秒后唤醒,简化版闹钟,只支持 1分钟内有效 */ alarmtime.Hours = curtime.Hours; alarmtime.Minutes = curtime.Minutes; alarmtime.SubSeconds = curtime.SubSeconds; alarmtime.Seconds = curtime.Seconds + 20; if (alarmtime.Seconds >= 60) { alarmtime.Seconds -= 60; alarmtime.Minutes ++; if (alarmtime.Minutes >= 60) alarmtime.Minutes -= 60; } alarm.Alarm = RTC_ALARM_A; alarm.AlarmTime = alarmtime; alarm.AlarmTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE; alarm.AlarmTime.StoreOperation = RTC_STOREOPERATION_RESET; alarm.AlarmMask = RTC_ALARMMASK_DATEWEEKDAY | RTC_ALARMMASK_HOURS; alarm.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_NONE; alarm.AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_DATE; alarm.AlarmDateWeekDay = 0x1; /* 开启闹钟 */ HAL_RTC_SetAlarm_IT(&hrtc, &alarm, RTC_FORMAT_BIN); } while (1) { /* 开始进入低功耗模式 */ rt_sem_take(&wake_sem, rt_tick_from_millisecond(5000)); /* 退出低功耗模式 */ rt_kprintf("Sleep %d ms\n", get_interval()); #ifdef RT_USING_PM /* 申请正常模式 */ rt_pm_request(PM_SLEEP_MODE_NONE); #endif rt_thread_mdelay(5000); rt_kprintf("Wakeup %d ms\n", get_interval()); /* 运行模式切换 */ rt_pm_run_enter(mode_loop()); #ifdef RT_USING_PM rt_pm_release(PM_SLEEP_MODE_NONE); #endif } return RT_EOK; } //MSH_CMD_EXPORT(pm_test, PM TEST); static rt_uint32_t get_interval(void) { rt_uint32_t seconds; rt_uint32_t last_seconds = curtime.Seconds; rt_uint32_t last_subseconds = curtime.SubSeconds; get_rtc_time(&curtime); if (curtime.Seconds < last_seconds) seconds = 60 + curtime.Seconds - last_seconds; else seconds = curtime.Seconds - last_seconds; return (rt_uint32_t)(seconds * 1000 + ((int32_t)last_subseconds - (int32_t)curtime.SubSeconds) * 1000 \ / (int32_t)(((RTC->PRER & RTC_PRER_PREDIV_S) >> RTC_PRER_PREDIV_S_Pos) + 1U)); } static void get_rtc_time(RTC_TimeTypeDef *time) { rt_uint32_t st, datetmpreg; HAL_RTC_GetTime(&hrtc, time, RTC_FORMAT_BIN); datetmpreg = RTC->DR; if (HAL_RCC_GetPCLK1Freq() < 32000U * 7U) { st = time->SubSeconds; HAL_RTC_GetTime(&hrtc, time, RTC_FORMAT_BIN); datetmpreg = RTC->DR; if (st != time->SubSeconds) { HAL_RTC_GetTime(&hrtc, time, RTC_FORMAT_BIN); datetmpreg = RTC->DR; } } (void)datetmpreg; } rt_uint8_t mode_loop(void) { rt_uint8_t mode = 1; run_mode++; switch (run_mode) { case 0: case 1: case 2: case 3: mode = run_mode; break; case 4: mode = 2; break; case 5: mode = 1; break; case 6: mode = run_mode = 0; break; } return mode; } 运行效果: ![](https://img-blog.csdnimg.cn/20200528155147377.png)
Aladdin-Wang
认证专家
2020-05-28
这家伙很懒,什么也没写!
原文地址:[https://blog.csdn.net/sinat_31039061/article/details/106356068](https://blog.csdn.net/sinat_31039061/article/details/106356068)
whj467467222
认证专家
2020-05-28
开源,分享,交流,共同进步
PM组件还没具体玩过,L4是由LPTIME的,是不是也可以用lptime是实现tick的补偿
Aladdin-Wang
认证专家
2020-06-01
这家伙很懒,什么也没写!
>PM组件还没具体玩过,L4是由LPTIME的,是不是也可以用lptime是实现tick的补偿 --- 可以用lptim
撰写答案
登录
注册新账号
关注者
1
被浏览
4.1k
关于作者
Aladdin-Wang
这家伙很懒,什么也没写!
提问
5
回答
39
被采纳
7
关注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组件
最新文章
1
【RT-Thread】【ci】【scons】将ci.attachconfig.yml和scons结合使用
2
Rt-thread中OTA下载后,bootloader不搬程序
3
ulog 日志 LOG_HEX 输出时间改为本地日期时间
4
在RT-Thread Studio中构建前执行python命令
5
研究一了一段时间RTT,直接标准版上手太难,想用nano,但又舍不得组件
热门标签
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
篇文章
2
次点赞
Ghost_Girls
1
篇文章
6
次点赞
YZRD
1
篇文章
2
次点赞
回到
顶部
发布
问题
分享
好友
手机
浏览
扫码手机浏览
投诉
建议
回到
底部