1 引言
目前,各种嵌入式设备为我们的生活带来了方便,其功能越来越强大,随之而来电源问题成为大家关注的焦点。目前嵌入式终端都采用电池供电,其寿命受电池寿命约束,而电池技术远远滞后于处理器技术的发展速度[1]。例如笔记本电脑充满电后的使用时间平均在六小时左右,大屏幕智能手机的工作时间一般不超过两天。因此如何降低嵌入式终端功耗,延长其使用寿命成为嵌入式系统进一步发展的瓶颈。
本文以应用十分广泛的嵌入式高性能ARM架构芯片S3C2440为例,从软件设计角度出发,以嵌入式Linux操作系统为例,修改嵌入式终端的启动加载程序Bootloader、嵌入式Linux内核,完全实现了动态电源管理技术,最大程度延长终端寿命。
2 动态电源管理介绍
动态电源管理(Dynamic Power Management,DPM)通过管理系统负载,调节系统状态达到节能目的,这些调节是在系统运行时动态进行的,而不像传统电源管理技术一样需要人工干预。DPM包括动态电压调节(Dynamic Voltage Scaling,DVS)技术,即在系统空闲时调节供电电压与处理器运行频率达到节能目的。类似的理念可以应用到外围设备,即当外围设备处于空闲状态时,降低其运行速度、供电电压,直至将其关闭等。
文献[2,3]阐述的电源管理技术,事实上就是APM,只实现了设备的睡眠与重启等功能,不能在系统运行时动态的管理各个设备状态,从而无法将功耗最小化。
2.1 DPM原理探究
CMOS数字电路的电路功耗构成有三部分,分别是静态功耗、动态功耗、短路功耗。相对动态功耗而言,短路功耗与静态功耗可与忽略不计。动态功耗是指,电容充放电功耗和短路功耗,是由电路的翻转造成的,其计算公式为:
(1)
E为CMOS电路动态功耗,为CMOS芯片的负载电容,V是电路供电电压,是CMOS芯片时钟频率。从式(1)可见,CMOS电路中动态功耗与电路工作频率成线性关系,与电路工作电压呈二次平方关系。因此可以想到降低系统功耗的方法:在系统允许情况下,降低信号频率与工作电压。这两种方法可以结合使用,例如在系统无负载的情况下,关闭不工作的负载;在系统工作负载不高的情况下,降低CPU工作电压或频率。
3 DPM底层代码实现
DPM提供一种操作系统级别电源管理机制,即在系统运行时根据负载、工作量的大小,在实时调整系统参数的同时满足系统工作最低要求,从而实现细粒度、智能化的电源管理,以达到最大可能节能的目的[4]。DPM涉及几个重要概念:操作点,即电源管理的一组配置数据,其一旦确定,能源消耗率和系统性能即确定;操作状态,即系统运行状态;操作策略,即电源管理的高级抽象,负责把操作状态映射到操作点上;操作类,代表一组操作点,状态切换时操作策略选取其中满足状态的第一个操作点作为有效操作点。DPM是一种典型的按照机制与策略分开的模式设计的,它由底层启动加载程序、linux内核、外设驱动程序相配合实现底层DPM机制,而所有策略完全由用户空间的应用程序去实现。
3.1 修改启动加载程序
为实现嵌入式终端支持睡眠状态需修改代码。当上层应用程序发出系统休眠指令,linux内核会保存当前工作状态以备实现唤醒操作。当RTC时钟定时唤醒系统时,CPU从睡眠模式唤醒的过程与reset系统类似,若错误执行reset代码将导致系统无法正常工作而死机,为解决此问题特修改启动加载程序Bootloader(Uboot为例)源码。修改Bootloader中Start.S,在SDRAM初始化后加入以下代码:
ldr r1,=0x560000B4 /* 检查是否是睡眠唤醒*/
ldr r0, [r1]
tst r0, #0x02
beq IsSleep /*若是睡眠唤醒则跳转*/
ldr r0, =0x560000B4 /*开始唤醒 */
mov r1, #0x2
str r1, [r0]
subs r1, r1, #1
…
mov pc, r1 /*跳回睡眠前位置继续执行*/
IsSleep: …
3.2 DPM操作点设定
本文以ARM架构芯片S3C2440为例进行DPM设计。操作点可以由一些参数描述:CPIU核心电压、CPU频率和bus频率、外设状态等。DPM系统可以由一组规则和过程定义,即当电源管理事件发生时将系统从一个操作点无缝切换到另一个。本文设定6个操作点,实现动态选择操作点,如表1所示。
1.Idle操作点下断开CPU内核时钟,仅提供时钟给HCLK、PCLK,Sleep操作点下则断开所有时钟;
2.PLL VCO根据S3C2440datasheet设定。
3.CAS latency:在READ命令触发到第一次数据输出之间的时间,后面数字代表时钟周期的个数。
3.3 修改嵌入式linux内核
为实现DPM,在内核层需要修改大量代码。
(1) 设置RTC唤醒中断源
S3C2440处理器睡眠模式的唤醒信号需要由外部中断EINT[15:0]或RTC闹铃中断产生。根据设计需求,使用RTC定时中断作为唤醒中断源,并在DPM运行期间动态调整RTC定时时间。需要修改Linux内核代码(本文以Linux2.6.30为例)。
arch/arm/plat-s3c24xx/irq.c如下:
unsigned long s3c_irqwake_intallow=1L<< (IRQ_RTC - IRQ_EINT0) | 0xfL;
/*屏蔽所有EINT中断*/
unsigned long s3c_irqwake_intmask =0xffffffffL;
unsigned long s3c_irqwake_eintallow = 0x0000fff0L;
unsigned long s3c_irqwake_eintmask = 0xffffffffL;
(2) 外设驱动程序电源管理支持
嵌入式终端电源管理DPM必须要修改外设驱动程序,首先通过platform_device_register 函数将设备连接到总线,然后通过platform_driver_register函数绑定总线上设备与操作函数集,进而利用系统的总线驱动方法进入休眠[8][9]。核心的休眠和恢复方法定义在数据结构struct bus_type中。
struct bus_type {
int (*suspend)(struct device *dev, pm_message_t state);
int (*suspend_late)(struct device *dev, pm_message_t state);
int (*resume_early)(struct device *dev);
int (*resume)(struct device *dev); }
3.4 内核框架代码
内核框架代码是DPM核心,包括dpm_choose_opt(寻找适当操作点)、dpm_set_opt(使操作点生效)、dpm_enter_state(把某状态置为新状态)、dpm_resync(让新状态生效)、dpm_set_os(切换到新状态运行)等操作函数。限于篇幅只介绍函数dpm_choose_opt的实现过程及DPM重要概念的结构体实现。
3.4.1 函数dpm_choose_opt()介绍
dpm_choose_opt(struct dpm_policy *policy,int state)
{ struct dpm_opt *opt = NULL; }
/*对于单个操作点:是否满足约束条件?满足则选择并切换,否则判断是否要强制转换。如果是则转换,否则切换失败*/
if (policy->classopt[state].opt)
{ opt = policy->classopt[state].opt;
if (opt->flags & DPM_OP_FORCE)
dpm_force_off_constrainers(opt);
else if (! dpm_check_constraints(opt))
opt = NULL;
dpm_active_class = NULL; }
/*对于一组操作点,从列表中找到第一个满足约束的操作点,找到了选择,否则切换失败*/
else { int i;
for (i = 0; i < policy->classopt[state].class->nops; i++){
if(dpm_check_constraints(policy->classopt[state].class->ops[i]))
{opt= policy->classopt[state].class->ops[i]; break;}}
dpm_active_class = policy->classopt[state].class;}
return opt; }
3.4.2 DPM操作点实现
(1) DPM操作点结构体实现
/* 操作点结构体*/
struct dpm_opt {
char *name; /* 操作点名称 */
struct list_head list;/* 操作点链表头指针 */ dpm_md_pp_t pp[DPM_PP_NBR];/* 初始化参数 */
struct dpm_md_opt md_opt; /* 与硬件相关参数*/
int constrained; /*约束条件*/
struct dpm_stats stats; /* 统计数据 */
};
用户层调用函数dpm_create_opt()可以创建新操作点。
(2)DPM类的实现
/*一组被映射到某操作状态的操作点(即类)的内部实现*/
struct dpm_class {
char *name; /* 类名 */
struct list_head list; /* 类链表头指针*/
struct dpm_opt *opt; /*被选中的操作点 */
struct dpm_stats stats; /* 统计数据*/
};
用户层调用函数dpm_create_class ()可以创建新操作点类。
(3) DPM策略的实现
/*内部电源管理策略实现*/
struct dpm_policy {
char *name; /* 策略名 */
struct list_head list; /* 策略
链表头指针*/
struct dpm_class *classes[DPM_STATES]; /* 策略组 */
struct dpm_stats stats; /* 统计数据 */
};
用户层调用函数dpm_create_policy()可以创建新的DPM策略
4 DPM用户层管理策略实现
图1即用户层DPM策略程序流程图示例。终端开机后同时开始处理任务,在普通模式下,根据任务量动态变化挑选操作点,任务增加则选择处理器频率较高的Normal1(见表1)操作点,任务减少则选择Normal2操作点(任务量大小由单个任务处理所需时间长短衡量)。图1中虚线框中内容表示动态调整CPU工作频率。本文设计利用RTC定时作为睡眠模式的唤醒中断源。如果系统连续三次唤醒后无任务,则增加RTC睡眠时间,反之连续三次唤醒后任务量较大,则减少RTC睡眠时间,这样就可以根据任务量多少动态调节系统睡眠时间。
5 实验结果与分析
实验平台是天嵌公司嵌入式开发板TQ2440,通过将5V直流稳压器改为电池供电(三节1.5V串联),测试对比,在电池电量相同、工作任务相同(播放同一个MP3歌曲,间断五分钟后继续播放,如此重复)情况下,对比使用DPM策略及不使用DPM策略下其工作寿命,以此验证DPM策略有效性。实验结果如表2所示。
采用DPM时,开发板工作在正常状态时可以动态选择不同工作点,调节CPU工作电压及频率;当开发板无任务时,采用可变阈值的DPM超时策略改变系统工作状态;对于不采用DPM策略的开发板只有正常工作状态,且不支持动态调整CPU电压及频率,故其寿命有所降低。数据对比如图4,采用DPM策略的开发板工作寿命是不采用DPM策略的121%。
6 结束语
本文基于ARM9架构处理芯片S3C2440、嵌入式Linux操作系统,设计适合本系统的DPM操作点,修改启动加载程序、Linux内核等实现了动态电源管理,实验结果证明动态电源管理技术在高性能嵌入式终端上节能效果显著。
参考文献:
[1] Lahiri K,Raghunathan A,Dey S,Panigrahi D.Battery-driven system design:A new frontier in low power design[C]//Design Automation Conference Proc,2002:261 - 267.
[2] 邢向磊,周余,都思丹.基于嵌入式Linux系统的电源管理软件[J].开发研究与设计技术.2010,36(1):253-255.
[3] 周建政,吕柏权.基于Linux嵌入式的电源管理的研究[J].仪表技术.2008(1):59-61.
[4] 周建政,吕柏权.基于Linux嵌入式的电源管理的研究[J].仪表技术.2008(1):59-61.