Bios工程師手邊事—battery

公司的電池又出問題了。對於電池,只是解決問題的話,不會困難。但將整個電池的知識點串連起來,卻不是件輕鬆的事。

電池部分可以分成二塊來看待:

1,ECBIOS讀取電池,並處理

2,SYSTEMBIOS寫ASL代碼,提供給驅動

附:驅動和EC溝通,報給內核

 

嵌入式BIOS部分

嵌入式BIOS工程師做電池,手邊的事情一般有:

1,偵測電池插拔動作

一般有兩種方式來作這個功能:

(1)通過一根GPIO PIN的電平高低來檢測,需要提前去抖;

(2)通過ADC控制器來偵測電池溫度,其實在軟件的眼中,不管溫度還是阻值或者其它什麼東西,都是電壓。我們可以通過電壓是否在一定的範圍內來確定電池是否存在。

 

2,獲取電池信息

EC獲取電池信息,要通過讀SMART BATTERY IC的寄存器來獲取。比較重要的寄存器有:

BatteryCurrent

電池電流

BatteryVoltage

電池電壓

DesignCapacity

電池設計容量

RemainingCapacity

電池現有容量

FullChargeCapacity

電池滿充容量

RSOC

電池現有容量百分比

CycleCount

電池跑的CYCLE數

BatteryStatus

電池狀態

 

CycleCount的值代表了電池使用的程度;RemainingCapacity和FullChargeCapacity的比值就是WINDOWS顯示的百分比,由於算法的原因,可能和RSOC不一致;而電池剩餘時間可以通過BatteryCurrent和RemainingCapacity的比值得到。

讀取這些寄存器需要遵循SMBUS協議。

 

3,電池充放電

(1)當AC和電池均存在,而batteryStatus的FULLY_CHARGED位沒置1時,要充電。充電IC一般接受DAC或SMBUS的通信方式。

(2)其餘情況下,不應充電。

(3)電池充放電過程中,要點亮一些指示燈給終端用戶使用。

 

4,通知ACPI驅動更新電池信息

電池信息的傳遞需要通過62/66端口來實現。EC代碼的一般做法是用256 BYTE的內存來作爲ECRAM或ECSpace,HOST端驅動或應用會通過約定的時序來讀取。

當電池拔出時,我們應該將ECRAM有關電池部分清0,然後通過SCI中斷髮送Q事件號來通知電池驅動來讀取電池信息。

當電池插入時,我們不應立即通知電池驅動來獲取電池信息,因爲此時還沒有讀電池信息,我們最好要第一次讀完電池信息後,再通知驅動來更新電池信息。如果不這樣做,電池圖標就會指示錯誤。SYSTEM BIOS爲了避免這種情況出現,也可以利用線程SLEEP的方式來繞過這段時間。

在電池充放電過程中,我們可以實時讀取RSOC的值,一旦RSOC值有變化,我們就可以通知電池驅動更新電池信息。

 

5,電池Learning功能的輔助性設計

一般來講,主板都會設計留出電源開關來給EC使用,EC利用這些開關來決定當前系統使用交流電或是電池,EC不會主動調用這些開關,而是把它們封裝做成接口提供給HOST端使用。

這種靈活的設計主要爲電池Learning功能使用。我們可以通過操作系統層面上應用調用EC的接口,或是直接在BIOS層面調用EC的接口來做電池 Learning功能。

 

6,電池保護功能

電池在充放電過程中,有時會產生過壓過流或過溫現象,這種現象會對電池造成危害。EC工程師可以在電源工程師的設定規則下,來做一些保護功能,當達到臨界點時,要停些充電或關機。

 

 

 

 

 

SYSTEM BIOS部分

SystemBIOS工程師做電池,手邊的事情一般有:

1, 在DeviceEC ASL中加入電池相產信息的字段。然後在QEvent加三個事件來通知電池驅動更新電池信息。這三個事件通知的時機分別是:

(1)   電池插入

(2)   電池拔出

(3)   電池百分比改變

(4)   AC插入和拔出

電池插入和拔出的事件:

Method(_QXX)

{

     Sleep(5)        //此處防止EC BIOS代碼考慮不全面

     Notify(BATT,0x80)

     Sleep(5)        //此處防止讀取數據時,時序錯亂

Notify(BATT,0x81)

}

電池百分比改變事件:

Method(_QYY)

{

     Notify(BATT,0x80)

}

AC插拔事件:

Method(_QZZ)

{

     Notify(ACAD,0x80)   //通知AC狀態改變

     Sleep(5)       

     Notify(BATT,0x80)

     Sleep(5)       

Notify(BATT,0x81)

     Notify(EveryCPU)    //_CST,讓操作系統重新決定CPU省電策略

}

2, 添加DeviceBattery ASL代碼。

裏面主要注意兩個Method:_BIF和_BST

我們可以看到,_BST的package裏有Battery Remaining Capacity字段,根據_QYY事件中的代碼,我們可以推斷出電池的Notify Value 0x80就是更新_BST的package。

這個需要細心和耐心,對照ACPI SPEC和EC SPACE空間,一點點地給電池驅動報數據。

值得一提的是,和SLEEP一樣,爲了防止數據讀取錯誤,我們也可以在此添加Mutex。Sleep是通過線程休眠來達到延時的目的,而Mutex則是通過互斥量來阻止兩段代碼爭資源。我也分不清誰優誰劣,不過爲了防止錯誤發生,做項目中儘量兩者兼用。

 

 

附:驅動部分

    爲了搞明白我們的接口怎麼被操作系統獲取的,我特地讀了下Linux3.18.2驅動。由於不專業,所以還請各位同仁斧正。

    有關battery部分的驅動,有兩個比較重要的文件:

    Drivers\acpi\sbs.c

    Drivers\acpi\battery.c

 

    首先在sbs.c中:

我們可以看到驅動入品函數爲:acpi_sbs_init(void)調用acpi_bus_register_driver(&acpi_sbs_driver),Acpi_sbs_driver.ops.add = acpi_sbs_add,Acpi_sbs_add會調用acpi_battery_add(sbs, id),acpi_battery_add調用power_supply_register(&sbs->device->dev,&battery->bat),

battery->bat.get_property= acpi_sbs_battery_get_property;

    我們知道,Linux系統中,power_supply_regiter會註冊Power設備,而根文件系統顯示電池相關信息是由acpi_sbs_battery_get_property()提供的,所以我們就需要在硬件相關部分,將我們讀取到的信息提供給acpi_sbs_battery_get_property()所需的變量。而讀取硬件信息相關代碼就在battery.c中。

 

    在battery.c文件中:

    入口函數爲acpi_battery_init(),調用async_schedule(acpi_battery_init_async, NULL),acpi_battery_init_async()調用acpi_bus_register_driver(&acpi_battery_driver),acpi_battery.driver.ops.add= acpi_battery_add,acpi_battery_add()中賦值battery->pm_nb.notifier_call =battery_notify,battery_notify()調用acpi_battery_get_info()和

acpi_battery_get_state(),而這兩個函數會通過acpi_evaluate_object(battery->device->handle,"_BST",NULL, &buffer)

acpi_evaluate_object(battery->device->handle,name,NULL, &buffer)將讀到的電池信息放到acpi_battery結構體變量中,而該結構體變量會被sbs.c的acpi_sbs_battery_get_property()使用。至於怎麼讀到電池信息,這部分內容會涉及到ec.c中的內容,就不再展開了。

    對於Linux驅動實在太不專業,去描述這些的時候讓我想到《聖經》的馬太福音第一章前幾節,我就用這幾節內容來結束battery內容吧。

1:1 亞伯拉罕的後裔,大衛的子孫,耶穌基督的家譜,

1:2 亞伯拉罕生以撒,以撒生雅各,雅各生猶大和他的弟兄,
1:3 猶大從她瑪氏生法勒斯和謝拉,法勒斯生希斯崙,希斯崙生亞蘭,
1:4 亞蘭生亞米拿達,亞米拿達生拿順,拿順生撒門,
1:5 撒門從喇合氏生波阿斯,波阿斯從路得氏生俄備得,俄備得生耶西,
1:6 耶西生大衛王。大衛從烏利亞的妻子生所羅門,
1:7 所羅門生羅波安,羅波安生亞比雅,亞比雅生亞撒,
1:8 亞撒生約沙法,約沙法生約蘭,約蘭生烏西亞,
1:9 烏西亞生約坦,約坦生亞哈斯,亞哈斯生希西家,
1:10 希西家生瑪拿西,瑪拿西生亞們,亞們生約西亞。
1:11 百姓被遷到巴比倫的時候,約西亞生耶哥尼雅和他的弟兄。
1:12 遷到巴比倫之後,耶哥尼雅生撒拉鐵,撒拉鐵生所羅巴伯,
1:13 所羅巴伯生亞比玉,亞比玉生以利亞敬,以利亞敬生亞所,
1:14 亞所生撒督,撒督生亞金,亞金生以律,
1:15 以律生以利亞撒,以利亞撒生馬但,馬但生雅各,
1:16 雅各生約瑟,就是馬利亞的丈夫。那稱爲基督的耶穌,是從馬利亞生的。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章