FreeRTOS的低功耗Tickless模式
FreeRTOS Tickless模式通过动态暂停系统心跳(Tick)中断,允许处理器在空闲时段进入更深层次、功耗极低的睡眠状态,并精确预测下一个任务唤醒时间点来设置单次长定时唤醒,从而最大限度地减少了因周期性Tick中断导致的无谓唤醒和功耗浪费,显著降低了系统在空闲时的平均功耗。最后,更多FreeRTOS干货欢迎加入嵌入式学习交流场地,里边分享项目/资料/面经等。
一、摘要
在电池供电的物联网(IoT)、可穿戴设备等嵌入式应用中,功耗优化至关重要。FreeRTOS 作为流行的实时操作系统,其传统的周期性系统心跳(tick)中断虽然简化了任务调度,却成为深度休眠的障碍——它频繁唤醒CPU,导致功耗居高不下。Tickless 模式正是 FreeRTOS 为突破这一瓶颈而设计的核心低功耗技术。Tickless 模式的核心思想在于打破“心跳”的周期性束缚。它允许处理器在系统空闲时,预测下一个需要执行任务或处理事件的时间点,并据此动态配置一个更长的休眠时间。在此期间,系统心跳中断被完全禁止,处理器得以进入更深层次、功耗更低的睡眠状态(如WFI、WFE或特定MCU的STOP/SLEEP模式)。只有当预测的唤醒时间到达,或更高优先级的外部中断发生时,处理器才会被唤醒。本文将基于STM32F103单片机来讲解如何使用FreeRTOS中的低功耗Tickless模式。
二、STM32F103的低功耗模式
F1的低功耗模式分为三种:睡眠模式、停止模式及待机模式。进入睡眠模式有两种指令:WFI(全称为wait for interrupt--等待中断)和 WFE(全称为wait for event--等待事件),CMSIS(Cortex 微控制器软件接口标准)提供了两个函数来操作指令 WFI 和 WFE,我们可以 直接使用这两个函数:__WFI 和__WFE。FreeRTOS 系统会使用 WFI 指令进入休眠模式。
如果使用 WFI 指令进入休眠模式的话那么任意一个中断都会将 MCU 从休眠模式中唤醒, 如果使用 WFE 指令进入休眠模式的话那么当有事件发生的话就会退出休眠模式,比如配置一个中断线为事件。当 STM32F103 处于休眠模式的时候 Cortex-M3 内核停止运行,但是其他外设运行正常, 比如 NVIC、SRAM 等。休眠模式的功耗比其他两个高,但是休眠模式没有唤醒延时,应用程 序可以立即运行。接下来本文后续将以STM32F103中三个低功耗模式中的睡眠模式作为讲解,因此其他两种模式可查阅--STM32中文参考手册V10第四章。
在睡眠模式下,在睡眠模式下,所有的I/O引脚都保持它们在运行模式时的状态。因此,无需重新初始化外设。
三、FreeRTOS中的Tickless模式降低功耗详解
一般而言,在RTOS中为了降低功耗。运行空闲任务时需要进入低功耗模式,在处理应用层任务时需要将处理器从低功耗模式中唤醒。一般会在空闲任务的钩子函数中执行低功耗相关处理,比如设置处理器进入低功耗模式、关闭其他外设时钟、降低系统主频等。
但FreeRTOS中的时钟是由滴答定时器(一般频率为1000Hz)来提供的,这会导致当处理器进入低功耗模式时会被滴答定时器中断频繁唤醒,导致低功耗模式作用大大降低。因此引入了Tickless模式--当处理器进入空闲任务周期 以后就关闭滴答定时器中断,只有当其他中断发生或者其他任务需要处理的时 候处理器才会被从低功耗模式中唤醒。但这将面临两个问题: 其一是关闭系统节拍中断会导致系统节拍计数器停止,系统时钟就会停止。 FreeRTOS 的系统时钟是依赖于系统节拍中断(滴答定时器中断)的,如果关闭了系统节拍中断的话就会导致系统时钟停止运行,这是绝对不允许的!解决方法为--记录下系统节拍中断的关闭时间,当系统节拍中断再次开启运行的时候补上这段时间,因此这段时间也称为补偿时间。这时候就需要另外一个定时器来记录这段补偿时间,而F103是继续采用滴答定时器来完成这个功能。
其二是当处理器进入睡眠模式之后,除了及时响应中断外,还需要响应应用层的就绪任务,但是中断可以唤醒睡眠模式,应用层任务却不能主动将处理器从睡眠中唤醒。为了解决上述问题,采用记录处理器在进入低功耗模式之前的待运行任务阻塞时间(也称为低功耗持续时间),FreeRTOS中提供了prvGetExpectedIdleTime()函数来获取这段时间,接下来讲解具体实现。
三、FreeRTOS的Tickless模式的具体实现
首先,要想使用 Tickless 模式,首先必须将 FreeRTOSConfig.h 中的宏 configUSE_TICKLESS_IDLE 设置为 1,代码如下:

还需要注意的是,在该内核裁剪文件中设置BASEPRI屏蔽优先级,必须保证屏蔽优先级低于唤醒中断的优先级,否则不能唤醒。如下图所示:

在上图中,需要设置系统可管理的优先级为7,因为我的唤醒中断源的优先级为6,保证唤醒中断源优先级高于屏蔽优先级。
在使能Tickless模式之后,当FreeRTOS运行到空闲任务时,会调用如下代码块去处理低功耗功能。

首先,第一行代码是在第三节提到的获取待运行任务阻塞时间函数,其关键源码如下:

其中,xTickCount是时钟节拍计数。
接下来判断运行时间是否大于宏configEXPECTED_IDLE_TIME_BEFORE_SLEEP,该宏默认为2个时钟节拍,代表是低功耗的最低持续时间,当然你也可以定义的更低,但是如果只有一个时钟节拍的低功耗持续时间,这没有意义。
接下来调用函数portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime ),该函数用来完成具体的低功耗工作,关键源码如下所示,稍微有点长:
如上图所示的MaximumPossibleSuppressedTicks代表低功耗的最长持续时间,以时钟节拍为单位。其值是0xffffff/(72000000/1000)≈233(滴答定时器为24位向下计数寄存器)。最后一行代码是停止滴答定时器。

如上图,接下来需要根据待运行任务的阻塞时间去重新计算滴答定时器的重装值reload,这样在时间到达以后会触发滴答定时器中断,即可从睡眠模式中唤醒,达到应用层任务唤醒睡眠模式的目的。这个重装值位ulReloadValue,为当前的滴答定时器计数值加上待运行时间×一个时钟节拍的reload值(ulTimerCountsForOneTick=72M/1000,这是因为滴答定时器频率为1000Hz,则一次节拍的reload值为72M/1000)。最后关闭中断,为了延迟ISR的执行。

如上图,接下来判断当前是否存在就绪任务,如果存在,不可执行低功耗模式,需重新启动滴答定时器。

否则,可以执行低功耗模式,如上图:设置滴答定时器,然后调用configPRE_SLEEP_PROCESSING( xModifiableIdleTime );函数,这是一个宏,由用户自行编写。主要是进入低功耗模式前的准备工作,如关闭系统时钟等操作,可以写在任意一个.c文件下,比如笔者的定义低功耗准备函数如下图所示(需要注意的是在低功耗处理函数中,不能关闭唤醒中断源的时钟再恢复,否则会导致无法检测到中断):

想要成功跑成功该函数,还需要在内核裁剪文件下进行配置,如下图:

继续回到if( xModifiableIdleTime > 0 )的位置继续讲解,如果低功耗持续时间大于0,则调用__wfi();函数去进入睡眠模式。
当发生中断时,需要去判断是滴答定时器中断唤醒还是其他中断唤醒,代码如下所示:

如果是滴答定时器唤醒的,可以看到补偿时间为任务待运行时间,如果是其他中断唤醒的,补偿时间为实际消耗时间。根据原理我们知道,Tickless模式需要用滴答定时器去记录唤醒时间,用于时间补偿;并且,还需要设置滴答定时器的初值为解除阻塞时间,方便被应用层任务唤醒。因此代码如下:先去关闭滴答定时器(此时远保留原来的时钟节拍计数值XtickCount),再去设置滴答定时器的初值为未关闭时钟前的当前reload值+阻塞时间(已换算成reload值);设置好以后,等待进入空闲任务,此时可以开启低功耗处理,先将定时器初值设置好,然后开启中断功能。接下来去调用WFI指令进入睡眠。
接下来等待唤醒。有两种唤醒方式,一种是滴答定时器中断(应用层任务唤醒),另外一种是其他外部中断唤醒;根据两种唤醒方式的不同,时间补偿值也 不同,当滴答定时器中断唤醒时,时间补偿值刚好为阻塞时间;如果是其他中断唤醒的,那么此时的补偿时间肯定小于阻塞时间,因为外部中断发生了,代表此时滴答定时器中断还没发生,因此,此时的唤醒时间绝对小于阻塞时间;因此,此时的时间补偿值为阻塞时间减去滴答定时器的当前计数值(需要注意滴答定时器是一个24位倒数的计数器!),由于倒数,比如10递减到5,那么消耗的时间就是10-5;
最后,将时间补偿值补系统时钟,即XTickCount加时间补偿值,如下图:

其中,15处的关键源码为xTickCount += xTicksToJump;即给 FreeRTOS 的系统时钟节拍计数器 xTickCount 加上补偿时间。到此,这个处理具体的低功耗工作函数源码讲解完毕。
总结
FreeRTOS Tickless模式通过动态暂停系统心跳(Tick)中断,允许处理器在空闲时段进入更深层次、功耗极低的睡眠状态,并精确预测下一个任务唤醒时间点来设置单次长定时唤醒,从而最大限度地减少了因周期性Tick中断导致的无谓唤醒和功耗浪费,显著降低了系统在空闲时的平均功耗。
最后,更多FreeRTOS干货欢迎加入嵌入式学习交流场地,里边分享项目/资料/面经等。
参考文献
[1] FreeRTOS开发手册_V1.1.
openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。
更多推荐


所有评论(0)