Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
PM电源管理
低功耗
华大_小华单片机HC32
移植PM到HC32L196
发布于 2024-03-16 11:15:07 浏览:401
订阅该版
[tocm] 我准备移植HC32L196的PM2.0驱动 LPUart作为consol,使用LPTimer1作为PM的低功耗定时器 LPUart和LPTimer都使用RCL时钟源 # 问题: 我创建一个lptimer,超时时间2s,在回调函数里翻转LED,设备开机后5s后进入深度睡眠 从功耗上看,5s后确认进入深度睡眠了,但是5s内闪烁频率还没问题,5s后**闪烁周期不是2s**,而是一个**无规律的闪烁**, 正常应该是2s灭,2s亮,但是现象是可能亮了200ms,灭了3s,又亮5s,又灭500ms,完全没有规律。 但是如果我不进入深度睡眠,在正常模式和轻度睡眠模式下,定时器都可以正常2s超时中断,非常准 感觉是drv_lptim.c驱动问题,导致pm.c中,计算timeout_tick或者delta_tick出的问题,因为hc32l196的lptimer是超时后,把arr的值写到cnt,然后向上计数超时,类似51单片机的定时器,但是水平有限,不知道怎么改,拜托大神??? # 代码: 主要是两个文件,drv_lptim.c和drv_pm.c drv_lptime.c内容: ```c #include
#include
#include
#define LPTIMER_HANDLER M0P_LPTIMER1 #define SysctrlPeripheralLpTim SysctrlPeripheralLpTim1 void LpTim1_IRQHandler(void) { if (TRUE == Lptim_GetItStatus(LPTIMER_HANDLER)) { Lptim_ClrItStatus(LPTIMER_HANDLER); // 清除LPTIMER0的中断标志位 } } /** * This function get current count value of LPTIM * * @return the count vlaue */ rt_uint32_t lptim_get_current_tick(void) { return LPTIMER_HANDLER->CNT - LPTIMER_HANDLER->ARR; } /** * This function get the max value that LPTIM can count * * @return the max count */ rt_uint32_t lptim_get_tick_max(void) { return (0xFFFF); } /** * This function start LPTIM with reload value * * @param reload The value that LPTIM count down from * * @return RT_EOK */ rt_err_t lptim_start(rt_uint32_t reload) { Lptim_Cmd(LPTIMER_HANDLER, FALSE); // 关闭LPTIMER0 LPTIMER_HANDLER->ARR = 0xffff - reload + 1; Lptim_Cmd(LPTIMER_HANDLER, TRUE); // 使能LPTIMER0 return (RT_EOK); } /** * This function stop LPTIM */ void lptim_stop(void) { Lptim_Cmd(LPTIMER_HANDLER, FALSE); // 关闭LPTIMER0 } /** * This function get the count clock of LPTIM * * @return the count clock frequency in Hz */ rt_uint32_t lptim_get_countfreq(void) { return 38400 / 32; } /** * This function initialize the lptim */ int hw_lptim_init(void) { stc_lptim_cfg_t stcLptCfg; DDL_ZERO_STRUCT(stcLptCfg); //Sysctrl_ClkSourceEnable(SysctrlClkXTL, TRUE); Sysctrl_SetRCLTrim(SysctrlRclFreq38400); Sysctrl_ClkSourceEnable(SysctrlClkRCL, TRUE); ///< 使能LPTIM0 外设时钟 Sysctrl_SetPeripheralGate(SysctrlPeripheralLpTim, TRUE); stcLptCfg.enPrs = LptimPrsDiv32; stcLptCfg.enGate = LptimGateLow; stcLptCfg.enGatep = LptimGatePLow; stcLptCfg.enTcksel = LptimRcl; stcLptCfg.enTogen = LptimTogEnLow; stcLptCfg.enCt = LptimTimerFun; stcLptCfg.enMd = LptimMode2; stcLptCfg.u16Arr = 65535; Lptim_Init(LPTIMER_HANDLER, &stcLptCfg); Lptim_ClrItStatus(LPTIMER_HANDLER); // 清除中断标志位 Lptim_ConfIt(LPTIMER_HANDLER, TRUE); // 允许LPTIMER中断 EnableNvic(LPTIM_0_1_IRQn, IrqLevel0, TRUE); return 0; } INIT_DEVICE_EXPORT(hw_lptim_init); ``` drv_pm.c内容 ```c /* * Copyright (c) 2006-2023, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2019-05-06 Zero-Free first version */ #include
#include
//#include
#include
static void uart_console_reconfig(void) { struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT; rt_device_control(rt_console_get_device(), RT_DEVICE_CTRL_CONFIG, &config); rt_device_close(rt_console_get_device()); rt_device_open(rt_console_get_device(), RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_STREAM); } /** * 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: Lpm_GotoSleep(FALSE); break; case PM_SLEEP_MODE_LIGHT: Lpm_GotoSleep(FALSE); break; case PM_SLEEP_MODE_DEEP: Lpm_GotoDeepSleep(FALSE); break; case PM_SLEEP_MODE_STANDBY: Lpm_GotoDeepSleep(FALSE); break; case PM_SLEEP_MODE_SHUTDOWN: Lpm_GotoDeepSleep(FALSE); break; default: RT_ASSERT(0); break; } } static uint8_t run_speed[PM_RUN_MODE_MAX][2] = { {24, 0}, {16, 1}, {8, 2}, {4, 3}, }; static void run(struct rt_pm *pm, uint8_t mode) { static uint8_t last_mode; static char *run_str[] = PM_RUN_MODE_NAMES; if (mode == last_mode) return; last_mode = mode; /* 2. 根据RUN模式切换时钟频率(HSI) */ switch (mode) { case PM_RUN_MODE_HIGH_SPEED: rt_hw_board_clock_init(SysctrlRchFreq24MHz); break; case PM_RUN_MODE_NORMAL_SPEED: rt_hw_board_clock_init(SysctrlRchFreq16MHz); break; case PM_RUN_MODE_MEDIUM_SPEED: rt_hw_board_clock_init(SysctrlRchFreq8MHz); break; case PM_RUN_MODE_LOW_SPEED: rt_hw_board_clock_init(SysctrlRchFreq4MHz); break; default: break; } /* 4. 更新外设时钟 */ uart_console_reconfig(); /* Re-Configure the Systick time */ SysTick_Configuration(); rt_kprintf("switch to %s mode, frequency = %d MHz\n", run_str[mode], run_speed[mode][0]); } /** * This function caculate the PM tick from OS tick * * @param tick OS tick * * @return the PM tick */ static rt_tick_t pm_tick_from_os_tick(rt_tick_t tick) { rt_uint32_t freq = lptim_get_countfreq(); return (freq * tick / RT_TICK_PER_SECOND); } /** * This function caculate the OS tick from PM tick * * @param tick PM tick * * @return the OS tick */ static rt_tick_t os_tick_from_pm_tick(rt_uint32_t tick) { static rt_uint32_t os_tick_remain = 0; rt_uint32_t ret, freq; freq = lptim_get_countfreq(); ret = (tick * RT_TICK_PER_SECOND + os_tick_remain) / freq; os_tick_remain += (tick * RT_TICK_PER_SECOND); os_tick_remain %= freq; return ret; } /** * This function start the timer of pm * * @param pm Pointer to power manage structure * @param timeout How many OS Ticks that MCU can sleep */ static void pm_timer_start(struct rt_pm *pm, rt_uint32_t timeout) { RT_ASSERT(pm != RT_NULL); RT_ASSERT(timeout > 0); if (timeout != RT_TICK_MAX) { /* Convert OS Tick to pmtimer timeout value */ timeout = pm_tick_from_os_tick(timeout); if (timeout > lptim_get_tick_max()) { timeout = lptim_get_tick_max(); } /* Enter PM_TIMER_MODE */ lptim_start(timeout); } } /** * This function stop the timer of pm * * @param pm Pointer to power manage structure */ static void pm_timer_stop(struct rt_pm *pm) { RT_ASSERT(pm != RT_NULL); /* Reset pmtimer status */ lptim_stop(); } /** * This function calculate how many OS Ticks that MCU have suspended * * @param pm Pointer to power manage structure * * @return OS Ticks */ static rt_tick_t pm_timer_get_tick(struct rt_pm *pm) { rt_uint32_t timer_tick; RT_ASSERT(pm != RT_NULL); timer_tick = lptim_get_current_tick(); return os_tick_from_pm_tick(timer_tick); } /** * This function initialize the power manager */ 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; /* 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; } INIT_BOARD_EXPORT(drv_pm_hw_init); ``` timer_app.c ```c /* * Copyright (c) 2006-2021, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2018-08-07 Tanek first implementation * 2019-05-06 Zero-Free adapt to the new power management interface */ #include
#include
#include
#define LED_PIN GET_PIN(C, 8) #ifndef RT_USING_TIMER_SOFT #error "Please enable soft timer feature!" #endif #define TIMER_APP_DEFAULT_TICK (RT_TICK_PER_SECOND * 2) #ifdef RT_USING_PM static void _timeout_entry(void *parameter) { static rt_uint8_t state = 0; rt_kprintf("current tick: %ld\n", rt_tick_get()); if(state == 0) { rt_pin_write(LED_PIN, PIN_LOW); state = 1; }else { rt_pin_write(LED_PIN, PIN_HIGH); state = 0; } } static struct rt_lptimer lptimer; static int timer_app_init(void) { rt_lptimer_init(&lptimer, "timer_app", _timeout_entry, RT_NULL, TIMER_APP_DEFAULT_TICK, RT_TIMER_FLAG_PERIODIC); //if (timer1 != RT_NULL) { rt_lptimer_start(&lptimer); /* keep in timer mode */ //rt_pm_request(PM_SLEEP_MODE_DEEP); return 0; } } INIT_APP_EXPORT(timer_app_init); #endif /* RT_USING_PM */ ```
查看更多
1
个回答
默认排序
按发布时间排序
johnzhy
2024-03-16
这家伙很懒,什么也没写!
我自己解决了。 1、灯无规律亮灭,是因为我的lpuart的rx初始化为浮空了,但是测功耗的时候需要把串口工具拔掉,不然功耗不准,拔掉之后浮空引脚导致会误触发串口中断,所以产生了无规律的现象,把串口rx配置为上拉解决。 2、针对lptimer特性,我感觉pm是通过读取当前cnt的值,来判断时间过去了多久,所以修改get_tick函数,把数加回去,drv_lptim.c中的lptim_get_current_tick函数 ```c rt_uint32_t lptim_get_current_tick(void) { return LPTIMER_HANDLER->CNT - LPTIMER_HANDLER->ARR + 0xffff - LPTIMER_HANDLER->ARR; } ``` # 不过有个新问题: timer_app已经可以正常工作了,2s LED翻转,但是当我通过lpuart给consol发送数据时,串口接收中断唤醒cpu,理论上即使唤醒了,定时器的超时时间还没到,cpu继续睡眠就行 但是实际现象是: 每次我回车,LED都会翻转,我持续回车,LED就持续翻转,我停止输入,LED就继续以2s翻转。 也就是外部中断唤醒竟然触发了lptimer的超时,这是什么原因呢,该怎么解决
撰写答案
登录
注册新账号
关注者
0
被浏览
401
关于作者
johnzhy
这家伙很懒,什么也没写!
提问
1
回答
1
被采纳
0
关注TA
发私信
相关问题
1
STM32F103的低功耗
2
最近用rtthread系统下AD采样并低功耗,中断响应不及时
3
rt-thread低功耗休眠应用问题请教
4
关于RTT对低功耗的支持
5
RT-Thread怎么休眠实现低功耗。
6
RT-Thread V3.0支持的低功耗,OS会自行进入吗?
7
关于RTThread3.0低功耗休眠模式
8
RTT3.0的bsp包中哪些MCU自带低功耗定时器?
9
关于低功耗上次说针对L4出个BSP的,怎么迟迟不见呀
10
低功耗问题。
推荐文章
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
如何在master上的BSP中添加配置yml文件
2
使用百度AI助手辅助编写一个rt-thread下的ONVIF设备发现功能的功能代码
3
RT-Thread 发布 EtherKit开源以太网硬件!
4
rt-thread使用cherryusb实现虚拟串口
5
《C++20 图形界面程序:速度与渲染效率的双重优化秘籍》
热门标签
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
ESP8266
I2C_IIC
WIZnet_W5500
UART
ota在线升级
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
Debug
编译报错
msh
SFUD
keil_MDK
rt_mq_消息队列_msg_queue
ulog
C++_cpp
at_device
本月问答贡献
踩姑娘的小蘑菇
7
个答案
3
次被采纳
a1012112796
13
个答案
2
次被采纳
张世争
9
个答案
2
次被采纳
rv666
5
个答案
2
次被采纳
用户名由3_15位
11
个答案
1
次被采纳
本月文章贡献
程序员阿伟
9
篇文章
2
次点赞
hhart
3
篇文章
4
次点赞
大龄码农
1
篇文章
5
次点赞
RTT_逍遥
1
篇文章
2
次点赞
ThinkCode
1
篇文章
1
次点赞
回到
顶部
发布
问题
分享
好友
手机
浏览
扫码手机浏览
投诉
建议
回到
底部