嵌入式Linux經驗談(五):嵌入式Linux支援省電功能的方法
本文作者:admin
點擊:
2009-10-15 00:00
前言:
「節能省碳」是當前世界文明的大趨勢,電子產品更是講究省電功能。但如果晶片和硬體不支援省電功能,光靠Linux是無法達到省電目的的。因為軟體畢竟只是一堆可以驅動硬體的程式碼,如果硬體本來就不行,就別想用軟體去改變硬體。這是很簡單的道理,可惜很多人不了解。因此,本文不強調「嵌入式Linux的省電功能」,以免「鳩佔鵲巢」,而是闡明嵌入式Linux具有一些方法或邏輯可以使硬體發揮省電的功能。
省電的等級
在微軟的http://msdn.microsoft.com/en-us/library/ms798270.aspx網站中有定義四種睡眠(sleep)狀態:S1、S2、S3、S4。此外,S0是正常開機模式,也就是最耗電的狀態;S5是關機(shoutdown)模式,也就是最省電的狀態。在這四種睡眠狀態中,可以再細區分為:睡眠狀態(S1、S2、S3)和冬眠狀態(S4)。
雖然,這是一般PC的省電定義,但也適用於嵌入式系統。只是不同產牌SoC的省電狀態不盡相同,有些有支援S4,有些沒有;有些甚至只支援S1、S2而已,雖然在他們的技術規格書中,有載明說可以支援S3(這可能是晶片的bug造成的)。
簡言之,S1、S2、S3、S4都沒有讓存在於SDRAM中的資料消失。它們之中,唯獨S4會回頭執行「起始程式(boot code)」,但不會造成電源重置(power reset),只會讓系統回到睡眠之前的正常狀態,因此所有應用程式都可以繼續被執行,且資料都沒有遺失。這樣講似乎很神奇,但實際工作卻非常複雜。首先,SoC要有專門提供給冬眠使用的暫存器(register)以儲存在系統清醒(wake up)後恢復運行的正確位址、以及指定和設定可以喚醒系統的GPIO腳位。進入冬眠後,當系統從頭執行起始程式時,該程式必須讀得到這些暫存器的值,唯有如此,透過程式計數器(program counter)才能回到冬眠前的正確位址。這有點像「回到未來」的情節吧!
一般而言,支援冬眠狀態的省電晶片的設計門檻在於:如何讓系統能夠從頭執行起始程式,也就是所謂的「冬眠重置(hibernate reset)」。很多失敗的案例都是發生在:系統進入冬眠後,就永遠休眠、無法清醒了。
S3的觀念和S4類似,但它不會回頭去執行起始程式,因此省電效果沒有S4好,不過喚醒恢復的速度比S4快。它的設計門檻也和S4一樣,很多失敗的案例都是發生在:一旦系統進入S3模式,就永遠休眠、無法清醒了,無論使用者按了多少次喚醒中斷鍵。設計晶片時,要實現S3模式,並不需要像S4一樣需要額外的暫存器。一般的做法是在進入休眠時,利用程式跳至SRAM中,當系統醒來時,再從SRAM跳回到SDRAM中。為何要用SRAM?這是因為在休眠時,SDRAM裡面的資料和程式碼是被凍結的,也就是說,程式無法被執行。不過,SRAM的中斷呼叫位址必須是CPU定義和讀得到的,否則於喚醒時,程式無法在SRAM內繼續被執行,直到跳回SDRAM中。此外,也有人使用外接的NOR FLASH來取代SRAM。SDRAM的資料之所以不會消失,是因為休眠時SDRAM處於「自我刷新(self-refresh)」模式,且SDRAM的時脈也變慢了。當系統恢復清醒後,SDRAM也回復至「自動刷新(auto-refresh)」模式。所以,S1、S2、S3也被通稱為「suspend to ram」或「suspend2ram」,有別於S4的「hibernate」。這裡的ram就是指SDRAM。
S1和S2都是屬於較不省電的模式。雖然,此時CPU處於閒置狀態----因為CPU的時脈被關閉了----但只要按下喚醒中斷鍵,CPU就會馬上清醒過來。
程式技巧
以Linux程式實現硬體省電功能,除S4狀態以外,一般而言,都具有下列三大步驟:
首先,在Linux kernel原始碼中,有許多針對不同SoC設計的pm.c程式,這個pm.c就是為特定SoC量身打造的電源管理程式。這些SoC包含:AT91、OMAP1、OMAP2、PNX4008、PXA、S3C2410、S3C2412、SA1100、HP6xx、Blackfin…等。程式設計者可以從中挑選一個比較接近自家SoC的pm.c,然後修改之,這過程就叫做「移植(porting)」。
pm.c裡面定義了許多針對特定SoC的電源管理函式。例如:可令系統進入S1或S2或S3或S4狀態的函式。這些函式透過pm_set_ops( )跟Linux kernel註冊。而Linux kernel的電源管理主程式位於./kernel/power/main.c中,pm_set_ops( )的程式內容也在此main.c中。
第二步,是選定一個GPIO腳位當作喚醒中斷來源,並設計它的中斷服務常式(ISR)。當按下此GPIO按鍵時,必須能產生IRQ中斷,致使系統清醒過來。
第三步,是每個Linux裝置驅動程式裡面都會有suspend( )和resume( )函式,前者讓系統休眠,後者喚醒系統。在這兩個函式中,一般都是空白的。程式設計者的任務就是要去填寫這些空白,讓所有週邊硬體都能夠跟著Linux休眠和被喚醒。