FreeRTOS长时间低功耗休眠后唤醒延迟过高问题咨询
FreeRTOS长时间低功耗休眠后唤醒延迟过高问题
(交叉发布于Electrical Engineering Stack Exchange)
问题描述
应用场景要求处理器最长可在低功耗模式下休眠12小时,随后响应中断请求唤醒,当前遇到FreeRTOS唤醒耗时过长的问题。
硬件与基础实现信息:
- 主控为Microchip/Atmel SAM4L(Cortex-M4)芯片
- 使用AST子系统记录处理器休眠时长
- 通过BPM子系统的
bpm_sleep()函数进入RETENTION模式完成休眠
当前休眠唤醒流程:
- 进入休眠前,调用
vTaskSuspendAll()禁用调度器 - 唤醒后,先计算处理器的实际休眠时长,调用
vTaskJumpTime()更新FreeRTOS时间基准,随后调用xTaskResumeAll()重启调度器
核心问题
xTaskResumeAll()会针对休眠期间错过的每一个系统tick(数值由vTaskJumpTime()记录),逐次调用xTaskIncrementTick()。实测休眠1小时后唤醒约需12秒,对应要执行360万次xTaskIncrementTick()调用。
曾考虑修改FreeRTOS的xTaskIncrementTick()函数,使其支持单次跳转多个tick,但优先希望采用官方标准方案降低维护风险,寻找可规避该长唤醒延迟的合规实现方式。
解决方案
该问题是FreeRTOS低功耗适配的典型场景,无需修改内核核心逻辑,采用官方标准方案即可解决:
- 弃用自行实现的
vTaskSuspendAll()+vTaskJumpTime()休眠逻辑,直接使用FreeRTOS原生Tickless Idle机制。官方Tickless模式原生支持任意时长tick跳过,不存在逐tick补偿的循环开销:进入低功耗前内核自动计算下一个到期任务的时间点,配置低功耗定时器在该时间点唤醒;若被外部中断提前唤醒,内核直接读取低功耗定时器计数值,一次性完成tick补偿,仅做一次到期任务遍历,哪怕休眠12小时,唤醒过程耗时也在毫秒级。 - 针对SAM4L平台RETENTION模式做针对性适配:
- 将
configUSE_TICKLESS_IDLE配置为2,自定义端口层低功耗实现。默认Cortex-M架构的Tickless实现基于SysTick,而SysTick在RETENTION模式下断电,无法保持计时,需要将低功耗计时源切换为当前使用的AST外设,实现portSUPPRESS_TICKS_AND_SLEEP()宏完成休眠流程控制。 - 自定义休眠流程中无需手动调用
vTaskSuspendAll(),内核进入Tickless休眠前会自动完成调度器锁定、到期任务时间计算等操作;唤醒后读取AST记录的实际休眠时长,转换为tick单位后调用官方APIvTaskStepTick()完成一次性时间补偿即可,该接口为官方原生提供的多tick跳转接口,不会循环调用xTaskIncrementTick()。
- 将
- 适配注意事项:RETENTION模式下部分外设会断电,唤醒后需要先在
portSUPPRESS_TICKS_AND_SLEEP()的唤醒分支中恢复必要硬件上下文,再执行tick补偿与调度恢复流程。 - 根因说明:当前使用的
vTaskJumpTime()不属于FreeRTOS官方标准API,属于第三方移植新增的接口,其内部逐tick补偿的逻辑是导致唤醒延迟过高的根本原因,替换为官方标准流程即可完全规避该问题。
内容的提问来源于stack exchange,提问作者harry courtice
相关产品推荐
相关产品推荐

