前言
隨著各種便攜嵌入式設備性能的日益提高,功能日益豐富,其電源緊張的問題也日益突出,國內(nèi)新推出的某些具有PDA等多種功能的智能電話在密集使用下只能維持半天,多數(shù)攝像機和數(shù)碼相機在一次充電后都只有一個小時左右的累積工作時間。Linux作為一個開放源代碼的操作系統(tǒng),擁有非常豐富的軟件資源和平臺支持,這使得嵌入式系統(tǒng)開發(fā)的周期大大縮短,越來越多的商用和通用嵌入式系統(tǒng)都采用Linux作為軟件平臺。因此有必要對Linux系統(tǒng)的電源管理機制進行深入研究。
Linux內(nèi)核電源管理機制分析
Linux作為一個強大而成熟的操作系統(tǒng),本身提供了一套從用戶空間到系統(tǒng)空間的,由上而下的軟件電源管理機制。
電源管理子系統(tǒng)
Linux內(nèi)核實現(xiàn)了一個電源管理子系統(tǒng)用于統(tǒng)一管理每個設備。源代碼pm.h和pm.c中定義和實現(xiàn)了主要的接口函數(shù)。如表1所示。
通過這些接口函數(shù)就可以將自己的硬件設備納入電源管理子系統(tǒng)使其成為系統(tǒng)電源管理的一部分。這需要在編寫設備驅(qū)動程序的時候完成下面的工作:
1)在初始化驅(qū)動時,使用pm_ regiSTer對設備的每個實例( instance)進行注冊;在清除驅(qū)動時使用pm_unregister來取消設備的注冊。
(2)在對硬件進行操作之前調(diào)用pm_access (這樣會保證設備已被喚醒并且處于ready狀態(tài)) 。
(3)編寫自己的pm _callback函數(shù)。開發(fā)人員應該在設備或系統(tǒng)進入suspend狀態(tài)時保留設備和系統(tǒng)的上下文到安全的地方,并在設備或系統(tǒng)re -sume時恢復其上下文,使之能夠繼續(xù)運行,編寫pm_callback函數(shù)是驅(qū)動實現(xiàn)設備電源管理的重點。
(4)當設備不在被使用的時候調(diào)用pm_dev_idle函數(shù),這個操作是可選的,可以增強設備idle狀態(tài)的監(jiān)測能力。
電源管理設備
將設備加入到電源管理子系統(tǒng)后,該設備就已經(jīng)有了處理電源管理請求的能力,但是系統(tǒng)的電源管理行為并不會主動發(fā)生。因此還需要一個電源管理設備來接受用戶請求,產(chǎn)生電源管理行為。這里所指的設備并不是一個真實的硬件設備,而是一個在Linux系統(tǒng)空間里接受用戶控制的虛擬設備,它可以是一個簡單的字符型設備。有了這個設備,就可以方便的實現(xiàn)來自于用戶空間的電源管理請求和方案。Linux電源管理行為過程如圖1所示。
圖1 Linux電源管理行為過程
Linux的電源管理機制在iPAQ上的應用
iPAQ是康柏公司(現(xiàn)在已和惠普公司合并)推出的基于StrONgARM CPU 的高性能掌上電腦,不僅提供了卓越的個人信息管理工具,還集成了較為強大的多媒體功能和其他娛樂功能。Linux 2.4的內(nèi)核已經(jīng)被成功的移植到上面,基于Linux系統(tǒng)眾多的應用軟件也已經(jīng)或正在被移植。
iPAQ硬件耗電量分析
要實現(xiàn)對iPAQ 耗電量的有效調(diào)節(jié),就必須清楚各個硬件耗電量,從而確定出需要管理和調(diào)節(jié)的對象。iPAQ上的各種硬件的耗電量比例如圖2所示。
圖2 iPAQ上的各種硬件的耗電量比例
可見,F(xiàn)rontlight、LCD、SDRAM、Audio、CPU等是主要的耗電設備,應該盡可能的減少這些設備的工作時間和強度,以減少耗電量,其關鍵步驟如下:首先,開啟SDRAM的自動節(jié)能模式。iPAQ所使用的SA -1110支持SDRAM的自動節(jié)能模式;在這種模式中,當內(nèi)存不被使用時, CPU 將關閉輸入到內(nèi)存的時鐘信號,內(nèi)存停止工作;這樣將減少大約190mW的功率。
接著,調(diào)節(jié)顯示驅(qū)動??梢赃x擇( 1)在必要的時候關閉背光; ( 2)降低LCD的刷新率。LCD在正常情況下刷新率是60Hz,通過調(diào)節(jié)LCD 定時器可以調(diào)節(jié)LCD的刷新率使其低于60Hz。降低LCD刷新率后,可以減少SDRAM,總線的使用和減少功耗; (3)在不使用屏幕的時候關閉LCD控制器。
隨后,降低時鐘頻率。SA - 1110的時鐘頻率可以在57. 3MHz到214. 8MHz之間動態(tài)調(diào)節(jié)。降低CPU時鐘頻率可以減少CPU本身的功耗,同時也能減少時鐘由CPU提供的其他硬件的功耗。例如: SA- 1110工作在最低頻率時可比工作在最高頻率時減少100mW到200mW的功耗。
最后,關閉音頻芯片。在不使用聲音的時候,盡量關閉音頻芯片,并保持CPU 到音頻芯片的低輸入。
通過Linux電源管理機制及上層應用實現(xiàn)對iPAQ電源管理和耗電量調(diào)節(jié)
確定了要調(diào)控的對象和方法后,需要通過L inux的電源管理機制和上層應用軟件來實現(xiàn)對這些硬件設備的控制。這包括編寫CPU電源管理代碼、外設驅(qū)動程序及電源管理代碼、電源管理設備實現(xiàn)代碼和用戶空間控制應用代碼。
(1)實現(xiàn)SA - 1110進入Sleep電源模式的代碼
SA -1110有Normal, Idle, Sleep 等幾種電源模式,其中在Sleep模式下, SA -1110具有最小的電力消耗。由于SA -1110 進入Sleep 模式后,到外設和SDRAM的時鐘將停止,多數(shù)的寄存器信息將丟失。因此需要事先將重要的寄存器值保存到內(nèi)存中,并將SDRAM設置為自刷新模式,以保持SDRAM中的數(shù)據(jù)。當SA -1110 收到硬件中斷等喚醒源退出Sleep模式后不會接著執(zhí)行先前未執(zhí)行的指令,而是回到初始狀態(tài)去執(zhí)行啟動代碼。因此為了讓CPU在喚醒后能夠持續(xù)的工作,需要將返回代碼的地址保存到PowerManager Scratch Pad Register ( PSPR)寄存器中,使得啟動代碼能讓CPU重新跳到返回代碼的地址處,執(zhí)行返回代碼從而回到睡眠前的工作。[!--empirenews.page--]
SA - 1110進入Sleep模式的代碼片斷如下:
extern void cpu_sa1110_resume ( voi
d) ; /3 SA - 1110返回函數(shù)3 /
extern int cpu_sa1110_do_suspend ( void) ; /3 SA - 1110睡眠函數(shù)3 /
int sa1110_suspend ( void)
{
. . .
cli ( ) ; /3 關閉中斷3 /
sys_ctx. osmr0 = OSMR0; /3 保存重要的寄存器3 /
. . .
sys_ctx. p sdr = PSDR;
. . .
PSPR = virt_to_phys ( cpu_sa1100_resume) ; /3 設置返回函數(shù)地址3 /
cpu_sa1110_do_suspend ( ) ; /3 進入睡眠3 //3 退出睡眠3 /
GPDR = sys_ctx. gpdr; /3 恢復寄存器3 /
GRER = sys_ctx. grer;
GFER = sys_ctx. gfer;
GAFR = sys_ctx. gafr;
. . .
sti ( ) ; /3 啟動中斷3 /
return 0;
}
(2)實現(xiàn)各個外設的電源管理代碼
利用Linux內(nèi)核提供電源管理子系統(tǒng),可以將iPAQ中的每個需要實現(xiàn)電源管理的外部設備納入統(tǒng)一的管理。這需要在各個設備的驅(qū)動程序中使用電源管理子系統(tǒng)的接口函數(shù)(如2. 1所描述)和實際的硬件操作代碼,這里將以顯示設備為例:
/3 SA - 1110 frame buffer電源管理請求處理函數(shù)3 /
static int sa1110fb_pm_callback ( struct pm_dev 3 pm_dev, pm
_request_t req, void
3 data)
{
struct sa1110fb_info 3 fbi = pm_dev - > data;
if ( req = = PM_SUSPEND | | req = = PM_RESUME) {
int state = ( int) data;
if ( state = = 0) {
set_ctrlr_ state ( fbi, C_ENABLE) ; /3 進入D0 模式,開啟LCD控制器3 /
} else {
set_ctrlr_state ( fbi, C_D ISABLE) ; /3 進入D1 - D3模式關閉LCD 控制器. 3 /
} }
return 0;
}
/3 SA - 1110 frAME buffer驅(qū)動初始化函數(shù)3 /
int __init sa1110fb_init ( void)
{
struct sa1110fb_info 3 fbi;
int ret;
. . .
/3 在電源管理子系統(tǒng)中注冊3 /
fbi - > pm = pm _ register ( PM _SYS_DEV, PM _SYS_VGA,
sa1110fb_pm_callback) ;
if ( fbi - > pm)
fbi - > pm - > data = fbi; /3 設置私有數(shù)據(jù)3 / . . .
return ret;
}
3)實現(xiàn)電源管理設備
這個設備實際是用于接受用戶空間程序的控制所用,所以只需要簡單的實現(xiàn)“ioctl”調(diào)用就可以了。
/3 ioctl調(diào)用方法3 /
static int do_ioctl ( struct inode 3 inode, struct file 3 filp, u_int
cmd, u_long arg)
{ . . .
switch ( cmd) {
case APM_ IOC_STANDBY: {
pm_send_all ( PM_SUSPEND, ( void 3 ) 2) ; /3 外設掛起3 /
; } break;
case APM_ IOC_RESUME: {
pm_send_all ( PM_RESUME, ( void 3 ) 0) ; /3 外設喚醒3 /
} break;
case APM_ IOC_SUSPEND: { [!--empirenews.page--]
pm_send_all ( PM_SUSPEND, ( void 3 ) 2) ; /3 外設掛起3 /
sa1110_suspend ( ) ; /3 CPU進入休眠模式3 /
/3 CP
U醒來,繼續(xù)執(zhí)行3 /
pm_send_all ( PM_RESUME, ( void 3 ) 0) ; /3 喚醒外設3 /
} break;
default:
return - EINVAL;
}
return 0;
}
最后,使用命令“mknod /dev/ apm c 254 0”,可以在文件系統(tǒng)中建立起該設備的訪問節(jié)點。該節(jié)點名為/dev/ apm,是一個字符設備(c) ,主設備號為254,此設備號為0。
(4)編寫用戶空間電源管理程序
用戶可以在適當?shù)臅r候選擇是否改變CPU的時鐘頻率和顯示刷新率,是否關閉某些外部設備,是否使整個系統(tǒng)進入睡眠模式等等。這只需要使用系統(tǒng)調(diào)用“ioctl”對電源管理設備( /dev/ apm)發(fā)送命令就可以了。
int fd;
. . .
fd = open ( " /dev/ apm" , O_RDONLY) ; /3 打開電源管理設備3 /
ioctl ( fd, APM_ IOC_SUSPEND,NULL) ; /3 發(fā)送電源管理命令3 /
close ( fd) ; /3 關閉電源管理設備3 /
實現(xiàn)iPAQ電源管理前后耗電量比較
實現(xiàn)電源管理以前:開啟LCD, CPU 處于空閑狀態(tài),大多數(shù)其他芯片關閉,功耗為470mW。實現(xiàn)電源管理以后:在電源管理前的基礎上開啟SDRAM 的自動節(jié)能模式,功耗下降到280mW。然后降低LCD刷新率到30Hz, 功耗下降到238mW。再把CPU頻率降低到57. 3MHz,功耗下降到172mW。最后關閉LCD,功耗下降到98mW??梢?,通過本文方案的調(diào)節(jié)和優(yōu)化, iPAQ的耗電量確實可以得到有效地改善,最大優(yōu)化后的耗電量僅為優(yōu)化前的五分之一,從而大大提高了iPAQ的電池使用時間。
結論
在嵌入式設備中,電源管理是一個硬件和軟件相結合的系統(tǒng)工程。本文介紹了已有的節(jié)能方法和Linux電源管理的機制, 并且以iPAQ 為例通過Linux的電源管理機制和上層應用軟件,設計和實現(xiàn)了一個較完整和有效的電源管理方案,為眾多基于Linux系統(tǒng)的嵌入式設備的電源管理提供了一個有用的參考。