最近在研究freeRTOS的低功耗特性,平台是STM32F429控制器,低功耗是现在电子消费类产品的一大要求,尤其是对手机,手环这类便携类产品,大家如果对这方面感兴趣可以交流一下,废话少说,直接上菜一、先从F429的低功耗模式说起
1、F4的三种模式:
F4系列的控制器有三种低功耗状态,分别是休眠状态、stop状态以及standby状态
休眠状态:内核(包括MPU)停止工作,外设(定时器、时钟等)仍然在工作,退出睡眠模式后程序从停止处继续执行,该模式类似于人在睡觉,大脑已经停止思考,但心脏脉搏仍在跳动
stop状态:内核包括1.2V区域的所有时钟停止运作,PLLs, HSI 和HSE RC oscillators被失能,计数器和寄存器的内容不变,并且在该模式下电压和内部FLASH也可以通过软件事先的配置进入低功耗模式,当内部flash进入低功耗模式时,那么在退出该模式后也会有相应的启动延时,故对实时性要求高的系统对是否试FLASH进入低功耗模式应慎重,退出该模式后程序从停止处开始执行,
sdandby状态:功耗最低状态,在STOP状态的基础上,电压调节器失能,除backup区域,SRAM以及寄存器的值全部丢失,故退出该状态后,系统类似于复位
2、F4如何进入睡眠模式和stop模式以及如何退出
关于这个问题一张表格就可很清晰的说明,如下:
<ignore_js_op>
硬件部分就说这么多吧,想要详细的了解朋友就要去看数据手册了
二、freeRTOS的低功耗原理
一句话概括就是实时改变滴答时钟的中断频率
我们知道,操作系统都有一个滴答时钟,以一定的频率产生定时器中断,freeRTOS使用systick时钟产生滴答时钟,在操作系统的运行过程中,大部分时间可能在运行空闲任务,也就是这个时候无事可干,那么如果我们能在无事可干的时间让系统进入睡眠或者停止模式,那么系统的功耗是不是就会降下去呢,答案是肯定的,那么我们每次进入空闲任务之后就让系统休眠,直至产生滴答时钟中断被唤醒,在中断服务函数中查看是不是有需要运行的任务运行,但是我们一般的滴答时钟周期设置为10ms,也就是说不管有没有任务运行,必须10ms醒过来检测一次
但是freeRTOS不满足于这样,他想到了一个更“省电”的方法:原理如下,当我们开启freeRTOS的低功耗模式后,系统会在空闲模式中计算出下一次某一个应用任务开始运行的时间,那么freeRTOS就设置SYSTICKD的重装值,使之恰好在这个时间点产生滴答时钟中断,然后“睡觉”,直至中断发生推出睡眠,从而进行任务的切换,这样系统就只需要在必须醒来的时候醒来进行任务切换,而不必每10ms就醒过来检测一次,那么是不是可以美美的睡上一觉呢
问题:如果需要睡眠的时间太长,超过了systick所能产生的最大时钟周期怎么办?
答:freeRTOS提出了解决方案,那就是使用普通定时器作为滴答时钟,通过改变其分频数来达到systick不能达到的的时钟周期
三、freertos低功耗具体的实现过程
1、找到空闲函数static portTASK_FUNCTION( prvIdleTask, pvParameters ),我们截取部分代码,并用红色字体标出重要的点
<font color="#ff0000"> #if ( configUSE_TICKLESS_IDLE != 0 ) //点1</font>
{
TickType_t xExpectedIdleTime;
/* It is not desirable to suspend then resume the scheduler on
each iteration of the idle task.Therefore, a preliminary
test of the expected idle time is performed without the
scheduler suspended.The result here is not necessarily
valid. */
<font color="#ff0000"> xExpectedIdleTime = prvGetExpectedIdleTime(); //点2</font>
if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP )
{
vTaskSuspendAll();
{
/* Now the scheduler is suspended, the expected idle
time can be sampled again, and this time its value can
be used. */
configASSERT( xNextTaskUnblockTime >= xTickCount );
xExpectedIdleTime = prvGetExpectedIdleTime();
if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP )
{
traceLOW_POWER_IDLE_BEGIN();
<font color="#ff0000"> portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime ); //点3</font>
traceLOW_POWER_IDLE_END();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
( void ) xTaskResumeAll();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
点1:这是一个条件编译选择项,configUSE_TICKLESS_IDLE 为低功耗的宏开关,设为1时开启低功耗模式
点2:prvGetExpectedIdleTime()用于计算从现在到下一个任务运行的时间,也就是可以睡大觉的时间
点3:portSUPPRESS_TICKS_AND_SLEEP()通过xExpectedIdleTime参数调整systick的重装值然后开始“睡大觉”等待下一次唤醒,这个函数可以认真研读一下,比较巧妙
四:freeRTOS的省电效果
在F429开发板上面,我验证了一下freeRTOS低功耗的省电效果,我的工程是建立两个任务,一个任务是让led1灯以500ms亮灭,另一个任务是让led2灯以1000ms亮灭
首先是关闭低功耗特性,使程序运行,发现电流在125mA~134mA,注意,单纯的看这个数据没有意义,我们需要和低功耗模式系下进行比较,因为开发板上面还有其他的芯片,功耗也是不可忽略的
接下来通过相关配置开启freeRTOS睡眠模式,发现电流在99mA~111mA之间,比正常工作模式减少了25mA左右
置位SLEEPDEEP位,使freeRTOS进入stop模式,发现电流在88mA~96mA之间比正常工作模式减少了40mA左右
从上面的3组数据看出,freeRTOS的低功耗模式效果相当明显,减少的40mA对某些电子产品来说是非常重要的,当然我们这只是粗略的进行验证,freeRTOS还提供了接口函数configPRE_SLEEP_PROCESSING( xModifiableIdleTime );和configPOST_SLEEP_PROCESSING( xExpectedIdleTime );,这两个函数的位置分别位于_wfi指令前面和后面,用户可以在进入睡眠之前通过configPRE_SLEEP_PROCESSING( xModifiableIdleTime )函数对控制器的外设进行配置,以达到最优的省电效果,退出睡眠模式后通过configPOST_SLEEP_PROCESSING(xModifiableIdleTime)对之前配置的外设进行还原
低功耗这个东西是一个很灵活的东西,在硬件层面和软件层面都可以不断地优化从而使功耗不断降低。