Chinaunix首页 | 论坛 | 博客
  • 博客访问: 3003496
  • 博文数量: 674
  • 博客积分: 17881
  • 博客等级: 上将
  • 技术积分: 4849
  • 用 户 组: 普通用户
  • 注册时间: 2010-03-17 10:15
文章分类

全部博文(674)

文章存档

2013年(34)

2012年(146)

2011年(197)

2010年(297)

分类: LINUX

2011-11-30 15:54:33

嵌入式CPU低功耗模式

低功耗已经是衡量一个嵌入式系统的重要指标。作为嵌入式系统的核心,嵌入式CPU的功耗则对整个系统起着重要的作用。一般而言,嵌入式CPU都有工作模式与低功耗模式,而低功耗模式又可进一步分为空闲模式、休眠模式、睡眠模式等。进入低功耗模式后,CPU的功耗会降低很多。外部中断发生时,又可以将CPU唤醒。

一个嵌入式系统开始运行后,当系统进入IDLE状态,就可以让CPU进入低功耗模式。让CPU尽可能多地处于低功耗模式,可以大大降低系统的功耗。

然而,即使系统处于IDLE而且没有别的工作要做,系统实时时钟的中断也会不停地唤醒CPU,从而增加系统功耗。因此,可以考虑对系统实时时钟的中断进行修改,从而减少对系统功耗的影响。


系统实时时钟与功耗的关系分析

系统实时时钟是现代多任务嵌入式操作系统的重要组成部分,因此我们需要先讨论一下嵌入式操作系统与系统实时时钟的关系。在目前的嵌入式系统中,系统实时时钟一般是一个硬件循环计数器。当硬件计数器计到一定数值时会向CPU发出中断。

嵌入式操作系统一般都支持多任务、优先级和时间片调度。

当嵌入式操作系统运行起来后,一般都有一个IDLE任务,它的优先级最低,而其他任务的优先级都应该比它高。在优先级调度机制中,只有当系统中其他高优先级任务都处于阻塞状态时,它才有机会运行。时间片调度机制只对同优先级的任务有效。也就是说,不同优先级的任务之间是不会按时间片调度轮转的,而是按优先级来调度的。因此当系统进入IDLE任务时,可以认为系统中没有工作需要CPU来做,系统为IDLE状态。

当时间片调度机制开启后,嵌入式操作系统就会根据时间片来调度任务。也就是当一个时间片用完后,要运行调度器来决定下一个时间片的归属。时间片的基本单位是系统tick,以系统实时时钟为基础。当系统实时时钟中断产生时,CPU会将系统tick加1。每当系统tick增加n(一个时间片)时,嵌入式操作系统将启用调度器进行时间片调度。因此,当时间片调度机制开启后,就需要系统tick的实时更新和调度器的定时运行,也就需要实时时钟中断以很高的频率定时产生。

如果关闭时间片调度机制,则任务之间只需要按照优先级来调度,这样就不需要计算时间片,也就是系统tick不用实时更新,实时时钟的中断也不必以很高的频率产生,从而降低系统在空闲时的功耗。调度器不用定时运行,也可以节省系统开销。这样就有可能考虑延长实时时钟的中断间隔。关闭时间片调度后,系统就只有优先级调度。这就要求系统的所有任务要主动阻塞,而不要期待调度器把同优先级的其他任务调度出CPU而让自己运行。在目前流行的嵌入式操作系统中,一般都提供了很多主动阻塞的机制。

延长实时时钟中断间隔后,需要考虑的问题有两个,一是系统tick,另一个是系统delay。

系统tick是实时时钟和操作系统之间的接口,操作系统与时间相关的模块和API(应用程序接口)基本都是基于tick的。在一般系统中,tick是操作系统最小的计时单位,实时时钟的中断是每个tick一次。延长实时时钟中断间隔后,系统tick就会长时间不增加,因此怎样保证系统tick的准确性就是最基本的问题。

系统delay是操作系统中一种重要的阻塞机制,它主要用于让一个任务主动让出使用CPU的一段时间。通常系统delay是基于系统实时时钟的,基本单位是tick。当调用delay时,API函数会首先得到当前系统tick,然后加上需要delay的时间,形成一个未来的delay时间点,再将任务挂到系统的delay队列上。因此delay队列上的所有任务都对应一个自己的delay时间点。当系统tick超过某个任务的delay时间点时,该任务就应该醒来。这就需要实时时钟的中断来唤醒CPU,并运行调度器让delay的任务重新进入就绪队列。如果实时时钟中断间隔延长,系统tick就会很长时间不增加,很难保证delay的准确性。另外,delay时间到达后,也无法唤醒任务。

要保证系统tick的准确性,就要求系统tick被获得时,通过实时时钟硬件计数器的值计算出当前的系统tick。同时,还需要保证主动获取和实时时钟中断之间的同步。而对于系统delay,则需要修改硬件计数器的计数值,使其为系统delay队列上最小delay时间点的delay时间。这样,可以利用硬件计数器来准确控制delay的准确性,并且利用中断来及时调度任务。


在I.MX51上的解决方案

ECOS是一款轻量级嵌入式操作系统,它的内核微小、紧凑,支持多任务,具有优先级和时间片调度机制。

多媒体芯片I.MX51基于ARM Cortex-A8核,支持ARM提供的低功耗功能。ARM执行指令WFI后,会进入睡眠状态。在睡眠模式下,ARM的时钟被关闭,ARM只消耗极低的功耗来维护自身的状态,即启用SRPG(State retaining power gate)。当有中断发生时,ARM会被唤醒,恢复时钟,重新开始执行。

本文针对上述操作系统和I.MX51进行实时时钟系统修改。

I.MX51提供了多个硬件计数器,本文采用其中的GPT作为实时时钟。GPT是一个循环计数器,可以设置最大为0xffffffff的计数值,每个时钟计数值减1,当计数值减到0时触发中断,时钟为32kHz。GPT的计数值可以在任意时刻被ARM读取,读取不影响计数。

当IDLE任务运行时,IDLE执行WFI指令,让ARM进入低功耗模式。如果有设备产生中断,ARM就会被唤醒,处理中断以及所需的任务调度,任务运行。

基于前面的分析,本文对ECOS的时间片调度和实时时钟系统进行修改。对于时间片调度机制,在ECOS的配置文件中将其关闭。对于实时时钟,则延长它的中断间隔。系统tick在两种情况下会被更新,一种是调用ECOS API读系统tick时,另一种是GPT产生中断时。

当ECOS启动后,将GPT的计数值设为最大,这样GPT会需要很长时间才会产生一次中断。在这期间,系统tick只会在ECOS API主动读取时才会更新。系统tick的更新通过读取硬件计数器的计数值计算出来。在ECOS系统的实时时钟类中增加一个变量pre_hardware_count,用于记录上一次读取的硬件计数器的值。当每次系统API读取tick时,当前硬件计数器的值与上一次读取时硬件计数器的值之差就是两次读取之间已经过去的tick数。当实时时钟产生中断时,即硬件计数器计到0,将此变量清零。这样,就可以保证每次读取系统tick时,能得到一个准确的系统tick值。

当有任务要主动延时一段时间,即调用系统delay API时,ECOS的API函数会计算出该任务的delay时间点,将该任务挂入系统delay队列。然后遍历系统delay队列,找出队列中的最小delay时间点,把该delay时间点对应的delay时间写入GPT,让GPT来控制delay时间。delay时间到后,GPT会产生中断,ECOS将中断处理程序分为两部分——ISR(中断服务程序)和DSR(中断服务滞后程序)。在ISR中将硬件计数器设为最大值。然后在DSR中增加系统tick,将超时的任务重新挂入就绪队列,并且再次找出系统delay队列上的最小delay时间点,写入硬件计数器。如果系统delay队列为空,则不对硬件计数器再进行操作,保持ISR中写入的最大值。最后ECOS会运行调度器,如果超时的任务具有最高优先级,那么它就会得到运行,任务被唤醒。这样也就可以保证系统delay的准确性与及时性。

图1     实时时钟修改流程图

图1是修改实时时钟后系统tick、delay以及调度器相关的流程图。表1是在I.MX51上的实验数据。可以看出,修改了时间片调度和实时时钟后,不论ARM工作在哪个电压点,系统IDLE时的功耗都降低了约9/10。因此,延长实时时钟中断间隔能极大降低系统功耗。
表1       在I.MX51上的实验数据


其他系统的类似方法

当前流行的嵌入式操作系统Linux和WinCE也都在讨论如何修改系统实时时钟中断方式,以降低系统功耗。对于Linux系统,有一个Less Watts项目,实现tickless idle,即无tick的idle,其实就是修改实时时钟的中断方式。WinCE则提供了可变系统时钟节拍(Variable Tick Scheduler),在进入IDLE状态前改变系统时钟节拍,在预期的时间段里,使IDLE状态不会被无谓的系统时钟中断唤醒。


结语

可以看出,通过修改实时时钟中断方式,可以使CPU在IDLE状态下长时间处于低功耗模式,降低系统功耗。相信未来这项功能会成为嵌入式操作系统必备的一个功能。

阅读(1516) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~