Tickless(低功耗空闲模式)
我的理解(精髓): 把正常的 SysTick 关掉,然后看延时链表,默认做法是把 SysTick 重装到 N ms 后一次性唤醒,或者把下一个要唤醒的时间写到 RTC / 低功耗定时器里倒计时,时间到了再中断唤醒,或者就事件唤醒。
实现逻辑
- 所有任务阻塞:当前没有就绪任务,系统自动切入空闲任务运行
- 空闲任务运行
- 判断是否允许睡眠:
eTaskConfirmSleepModeStatus()- 确认系统可否进入低功耗(若还有定时器/事件将唤醒,则禁止睡眠)
- 停止 SysTick:防止每 1ms 的周期中断打断睡眠
- 查阅延时链表,算出距下一个要唤醒任务还剩多少时间(期望睡眠时长 N ms)
portNVIC_SYSTICK_CTRL_REG &= ~portNVIC_SYSTICK_ENABLE_BIT关闭周期中断
- 设置 SysTick 为 N ms 后唤醒
portNVIC_SYSTICK_LOAD_REG = ulReloadValue写重装值portNVIC_SYSTICK_CURRENT_VALUE_REG = 0清计数,从 0 重新数
- 睡前钩子:
configPRE_SLEEP_PROCESSING(xIdleTime)(GPIO 拉低、关外设、电源管理等自定义动作) - 默认休眠函数:
vPortSuppressTicksAndSleep(xExpectedIdleTime)按期望休眠时长执行策略 - 执行睡眠:
__WFI()或HAL_PWR_EnterSTOPMode()(或写入 RTC/LPTIM 倒计时后入睡)
唤醒
- 非 Tickless 唤醒
- 依赖固定的 SysTick 周期中断(如每 1ms 一次)
- 即便没有任务运行,CPU 也会被强制唤醒检查任务,无法长时间深睡,功耗较高
- Tickless 唤醒
- 中断唤醒:低功耗定时器/RTC 到期中断,或外部硬件事件中断唤醒 CPU
- 唤醒后钩子:
configPOST_SLEEP_PROCESSING(xExpectedIdleTime)(恢复外设、日志等) - 判断是否为 SysTick 唤醒
- Tick 补偿:读取实际休眠经过时间,
vTaskStepTick(ulCompleteTickPeriods)一次补齐 OS 丢掉的 Tick,防止时间跳变 - 恢复 SysTick:
portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_ENABLE_BIT - 恢复调度:唤醒到期任务,继续执行业务逻辑