超低功耗操作系統的設計經驗

收藏待读

超低功耗操作系統的設計經驗

導語    續航時長一直是智能手錶的最大痛點。目前的安卓智能手錶,在正常使用的情況下,最多使用1-2天(那些宣稱能使用5天以上的,其實要閹割很多功能,一般只能看時間和計步,與手環沒有什麼差別)。

如何解決這個問題?行業里沒有太好的方案。1.加大電池容量?手錶的個頭不可能太大,人們需要戴的是手錶而不是「手雷」。2.不用全觸摸的真彩屏?可以,那就用按鍵和低功耗的屏幕吧,反正佳明就是這樣,這樣的操作與顯示的效果,與幾十年前的電子錶有什麼區別呢。3.用運算量更小的CPU?那些豐富的安卓手錶應用就跑不起來了,還不如直接戴手環。行業里這幾年無論是卡西歐、摩托羅拉、三星還是蘋果,在智能手錶的續航時長上一直沒有實質性的突破。長期以來長續航與高顏值就是魚和熊掌的關係。

但軟硬結合的架構設計以及操作系統層面的自研,其實可以很好的解決這個問題。

本文從CPU的選取開始,然後介紹雙核架構的必要性,再進一步闡述自研OS的軟硬件架構 雙核通信的設計與實現 UI框架 其他省電優化的關鍵點,逐步勾勒出既高顏值又省電易用的智能手錶操作系統。

一、CPU的選取

突破口還是要從耗電的根本原因上挖掘。既然電池容量和密度在短時間內有明顯的天花板,那麼主要還是要從CPU以及屏幕的消耗着手。從產品的角度看,如果要顏值高,操控方便,那一定要上支持高分辨率和高亮度的屏幕,並且要帶有Touchpad。這樣從屏幕的維度去優化功耗,也會很受限。

那我們重點看一下CPU。無論是MTK的2601還是高通的2100,在保證512MRAM和其他一些周邊器件供電的情況下,待機底電流都會到 1mA 甚至更多。選取MTK的2601或者高通的2100,肯定達不到長續航且高顏值易操控的設計目標。為什麼?因為什麼功能都不用,5天下來也會消耗100-200毫安時的電量,留給用戶使用的電量極為有限。

一般情況下,智能手錶的電池容量在300-500毫安時之間,容量越大手錶的尺寸也就越大,這對於手錶外觀設計是一個極為挑戰的事情,所以當下電池容量不可能很大。佳明這樣的產品也只用200-300毫安時左右的電池,個頭已經很大了。

那如何選擇CPU?需要在滿足算力的前提下,盡量選低功耗的產品,在功耗和算力上做好平衡。比如需要考慮驅動起AMOLED屏幕。需要跑起哪些應用場景?是否需要考慮音樂播放等等。最高負荷的綜合應用場景是怎樣的?是不是跑步+GPS+心率+抬手亮屏+通知顯示+微信消息+音樂播放+屏幕顯示?滿足需求的最小CPU算力和RAM是多少?

二、雙核架構

只是選取了低功耗的CPU,是否就可以做到長續航呢?答案是否定的。

因為智能手錶有很多功能需要一直運行,比如計步、心率測量等功能,這些功能需要的運算量又不是特別大,但目前行業里還沒有針對智能手錶主流場景優化得非常好的CPU,這往往要求對其運算單元進行非常細緻的分層控制和功耗控制。功耗優化比較精細化的CPU是Apollo系列,可惜Apollo目前還不能完整驅動全智能手錶的大部分經典功能。所以雙核CPU架構是當下不得不面對的設計方向:一顆相對低功耗的大核,主打用戶操控和UI渲染;另外一顆極低功耗的小核,主打長時間運行的各種算法和緩存。

三、自研OS

要低功耗主CPU,還要雙核架構,行業里去哪裡找這樣的開源OS?這種情況下只能自己設計與實現。

我們從硬件架構開始着手,看看OS的架構應該是怎樣的。介紹完OS整體架構之後,我們會進一步介紹OS中的幾個關鍵設計(雙核通信,UI框架等)以及典型功耗問題的解決思路和方法(實戰經驗)。

1. 硬件架構

要滿足產品定義(全彩屏、觸屏操控、支持GPS、藍牙、wifi、離線獨立聽歌、跑步、騎行、游泳、睡眠、久坐、計步、心率、離線微信支付、多錶盤切換、微信消息瀏覽與提醒、日常使用5天以上等等),硬件架構應該大致如下:

超低功耗操作系統的設計經驗

圖裡的名詞縮寫解釋如下:

LCM + CTP :      LCD顯示模組 + 觸摸屏

XTAL:                 外部晶振

Diplexer:            天線共用器

MOSI :               主機輸入/從機輸出數據線

HRM :               心率模組

INT :                     中斷

MIPI、GPIO、SDIO、EMMC、WIFI、BT、UART、I2C、GSensor、GPS、RTC這些就不解釋了,是常見且標準的硬件模塊,網上可以方便查到。

這個硬件架構的核心思想就是讓更多的算法,運行在小核上。通過大量實踐,我們發現計步、手勢、久坐、睡眠、心率、GPS、游泳算法、跑步算法以及各種緩存邏輯,放在小核上運行,可以極大的減少大核的運行時間與次數(比如大核在需要展示某項運動的實時數據的時候才去請求小核上傳此刻的運算結果)。通過CPU主頻的限制,讓小核的功耗有明確的上限,這就有了天然的隔離和保障。如果只是放在大核運行,一是浪費CPU資源,增加喚醒和運行時間;二是有bug的時候,大核CPU主頻升高之後,很難快速定位是什麼原因導致的。

2.OS 架構

相應的OS架構大致如下:

超低功耗操作系統的設計經驗

我們解讀一下這個架構的一些要點和特色,超級省電的同時不失應用開發的靈活性和豐富性:

  • 大核與小核各自有一個OS在運行,兩個OS的中間層,硬件抽象層以及kernel非常近似,幾乎一致。

  • 硬件抽象層可以適配多個硬件平台。

  • 中間層也分層了三層,最下面是基礎的公共組件,比如藍牙,消息打包與解包的庫;中間層的中部圍繞着核間通信(IPC)展開,中間層的上部則是業務需要的各種Task,需要經常與IPC通信,並調用底層藍牙等接口。

  • 系統的中間層以及上層Task之間需要通過Message進行互相通訊,但要平衡好效率和解耦的關係。實戰中發現過度依賴Message通訊並不好,雖然表面上編譯和接口調用解耦了,但當消息多的時候系統性能會受影響,一些業務也不容易得到及時響應。尤其是存儲業務。讓讀寫消息滿天飛的存儲Task顯然不是一個好方案。

  • 本OS為實模式操作系統,雖然多Task,但是都沒有獨立的虛擬地址空間,可以節約不少內存管理和進程管理的額外RAM和CPU開銷。

  • UI Task僅有一個,負責繪製和上屏,並通過管理不同場景的上下文來繪製不同的「應用」。

  • 中間層還有輔助切換「應用」的Task,管理「應用」的生命周期,我們叫AMS Task。實際上通過UI Task和AMS Task,我們做到了讓不同的開發者開發不同的「應用」,本質上每個「應用」只是UI Task的一小部分。這是為什麼「應 用」需要打上引號的原因。這種設計方式讓應用開發者感受到「應用」開發是各自獨立的,也是節約RAM並讓OS超低功耗的關鍵一步。小系統支持「大應用」。很多用戶誤以為我們的系統就是安卓系統,UI效果參考下圖。

超低功耗操作系統的設計經驗

3. 雙核通信的設計方案

1) 雙核通信的硬件架構

雙核通信的硬件架構可以簡單用下圖來表示:

超低功耗操作系統的設計經驗

讀者可以注意一下圖中中斷信號的命名縮寫,其中TOS表示to slave, TOM表示to master。

2) 雙核通信的邏輯時序

邏輯時序如下圖:

超低功耗操作系統的設計經驗

圖中的SEQ是時序的英文縮寫。

大核的下載時序由大核中的Proxy Task管理,其他Task如果需要傳輸指令或者數據到小核,就會與Proxy Task通信,Proxy Task會通過上圖的時序邏輯完成一次通信過程。

大核的上傳時序由大核中的Stub Task管理,由StubTask接收從小核來的指令和數據,再分發給需要這些數據和指令的Task。

圖中的lock spi bus,wait TOS_ACK_PINto low, unlock spi bus這些流程是關鍵。研發過程中我們出現的大量穩定性問題與沒有正確實現這些流程強相關。下一節會詳細介紹這個深刻教訓。

3) 雙核通信過程中遇到的難題

在雙核通信模塊的開發過程中,遇到的難題莫過於雙核通信導致界面卡頓、功能無效的問題。比如:

在計步/心率錶盤界面左右滑動,概率性的UI卡住,操作無效;

在跑步過程中抬手亮屏查看運動數據的時候,概率性的UI卡住,運動記錄的更新停止;

騎行過程中划到心率界面,概率性的UI卡死

長按物理鍵停止游泳的時候,概率性的UI卡死,無法退出遊泳功能

對此我們在雙核通信的核心代碼中加入了各種離線日誌,並在UI框架上加入了No Response提示,以便在問題復現的時候,能夠立刻進行問題歸類,對日誌進行分析,嘗試定位問題原因。

得出的結論是,由於小核的Proxy Task(下載時序)被卡死,導致數據無法從一端發送到另一端,再加上雙核通信的數據發送是串行的,此次發送異常,導致整個雙核通信模塊功能無效,UI模塊在對雙核通信指令入隊的過程中,由於隊列一直處於Full狀態,也導致UI模塊長時間無響應,導致卡死。

對於這個問題,我們針對性地進行了幾次改動,前後經歷了一個月左右的時間:

3.1)首先我們懷疑是消息上傳/下載太過於頻繁造成的,故對一些在兩個系統之間交互得比較頻繁的消息進行了稀疏化,比如:

在計步錶盤、心率錶盤之間來回切換的時候,不斷有啟動/停止計步消息上報、啟動/停止心率數據上報、獲取心率曲線等消息在運作,針對這些消息,我們進行了稀疏化操作,做了時間閾值,在這個閾值範圍內不允許重複啟動與停止等類型的消息。

我們梳理了系統內各個業務,進行了一輪稀疏化處理,將問題復現幾率大幅降低,但治標不治本,測試部門的反饋結果,還是有低概率會發生卡死。

3.2)之後,我們懷疑是Touchpad事件過於頻繁,對消息隊列造成了影響,對此我們的解決方案是:

將Touchpad的Up/Down事件上報,修改為了手勢上報,比如左滑、右滑、長按、單擊等,大幅度的降低了Touchpad事件的數量,這個改動帶來的效果是提升了UI的流暢度,但是並未解決卡死的問題。

3.3)最後在偶然間通過補充了更多的日誌,發現了問題點,經過仔細梳理,找到了流程上的漏洞,才徹底解決了這個問題:

問題主要出現在兩個核間通信的時序上,兩個核的握手流程的漏洞,造成了死循環現象。大核完成了一次消息透傳後,通過拉高電平告訴小核,並開了while循環等待低電平到來,小核恢復狀態後通過拉低電平去通知大核,然而這個時候又輪到小核透傳消息,所以又把電平拉高了。由於時序的問題,這個電平拉高的操作搶在了大核的while循環(大核下載時序圖中wait TOM_INT_PIN to low這一步)之前就發生了,所以這個循環一直等不到低電平的到來,卡死的問題就這麼發生了。

因為卡死問題,我們重新梳理的時序與流程,在小核wait TOS_ACK_PIN to low之前加了鎖,在小核拉低TOM_INT_PIN電平之後再釋放鎖,這樣避免了握手過程中被TOM_INT_PIN電平被拉高的可能。

4) 消息封裝與透傳

上一節有聊到雙核通信的時序問題,這裡簡要介紹雙核通信中消息的封裝與打包拆包。雙核之間所有的數據與指令,我們都通過自定義消息來封裝與透傳。

雙核通信的消息封裝與透傳、解包邏輯如下:

超低功耗操作系統的設計經驗

通過一系列的MessageID與TransferID的映射和轉換,大核的Task可以和小核里運行的Task進行相互通信。Proxy Task和Stub Task中的一系列封裝,讓業務Task感受不到核間通信存在。

4.UI 框架

UI框架也是本次設計的核心。我們並沒有採用商用的方案,而是選取了libaroma這個開源框架(純c寫的UI框架庫),並在此基礎上自研了類似安卓的AMS和WMS子系統。這樣的設計思路主要考慮如下關鍵點:

  • UI框架是app群的關鍵基礎,每一行代碼都應該深度掌握。

  • 項目周期太緊張,沒有時間去談商用方案,另外成本是考慮點,研發節奏也是一個考慮點。

  • 完全開源框架方便定製和應對超低功耗的苛刻要求。超低功耗對RAM尺寸和CPU主頻有極為苛刻的要求。我們最複雜的場景所對應的RAM資源控制在了4MB以內,主頻控制在了208Mhz之下,這時候UI框架和繪製系統不深度掌握,是無法在短時間內完成項目的。另外libaroma本身是一個輕量級的GUI庫。

  • Libaroma還比較初級,不能滿足應用開發的需求,必須在此基礎上加上MVC框架以及消息分發機制,就是類安卓的AMS(Activity Manager Service),我們將AMS運行在了AMS Task之中;另外轉場動畫的缺失使得我們必須自己封裝窗口管理系統(WMS),我們放在了UI Task里。

  • AMS的封裝有利於app開發工作的解耦以及並行展開。

下面是心率界面初始化的一段示例代碼,這些回調涉及了界面的生命周期的管理,很像安卓的activity。

LIBAROMA_CONTEXTlibaroma_hrm_context =

{

.on_create =hrm_on_create,

.on_resume =hrm_on_resume,

.on_pause =hrm_on_pause,

.on_destroy =hrm_on_destroy,

.on_start =hrm_on_start ,

.on_finger =hrm_on_finger,

.event_handler =hrm_event_handler,

…

};

為了減少調度負擔,我們的OS是基於實模式的操作系統,儘管如此,通過我們 自己封裝的AMS+libaroma,應用開發者開發app的感受與虛模式的操作系統很接近,彼此之間互不影響,耦合的地方被我們藏了起來。

AMS Task可以大致用下圖來表現,藍色虛線框內主要依賴libaroma提供的控件來擴展和繪製。每個「應用」都有自己的activity stack,所有「應用」的activity stack統一用LRUcache來管理,應對有限RAM資源的惡劣環境。

超低功耗操作系統的設計經驗

基於這個app框架,開發了不少「應用」:

幾十種錶盤、天氣、通知、音樂、各種跑步app、健走、游泳、騎行、微信支付、秒錶、倒計時、睡眠、設置、籃球直播等等,複雜一些的應用2000-3000行代碼,簡單一些的幾百行就可以。相對比較複雜的,是吃CPU以及內存資源的音樂app和跑步聽歌的場景,這時候需要打開GPS記錄跑步軌跡,同時心率監測和音樂播放在同時進行,用戶還在這個時候有可能收到微信通知以及進行抬手亮屏以查看跑步狀態,切歌和閱讀微信消息的操作。複雜場景下雙核的威力就更能顯現出來。

5. 功耗收斂

要使自研OS低功耗且穩定,除了因地制宜的硬件與軟件設計之外,還需針對硬件電路,器件驅動以及OS層的各種問題進行聯合排查和優化。核心方法就是通過針對性的測試以及相關的摘件實驗來縮小範圍,然後通過軟硬件的設計、代碼與電路的走查等方式抓住根本原因。下面是一些典型問題的經驗總結。

1)大核CPU運行功耗過高

現象描述:主CPU從休眠狀態喚醒、功耗過高,運行狀態的下功耗也比較高。

分析方法:自研PCB與供應商開發板硬件相對比

問題根因:某些所選用的電容器件容值不對

解決方案:更換電容。

2)心率測量後功耗增加

現象描述:自動心率開啟後,功耗增加200uA。

分析方法:硬件研發走查相關電路設計。

原因分析:心率IC的中斷信號為上升沿出發,上升沿觸發的中斷不應該加上拉電阻。

解決方案:去掉心率IC 中斷信號上面的上拉電阻。

3)BLE 在鏈接狀態下的功耗過高

現象描述:手錶在連接Android手機或者IOS手機時,無法待機、功耗較高

分析方法:通過測試進行排查,縮小範圍,如果不連接藍牙的時候,或者在藍牙傳輸的時候,沒有功耗明顯過高的情況。所以懷疑是藍牙在非傳輸狀態下的通訊周期長短的問題。這個在很多產品中都有類似的經歷。

原因分析:BLE 連接間隔時間較短,BLE持續的通訊導致功耗過高。

解決方案:動態調節BLE的連接間隔時間,在需要BLE通訊時將連接間隔調低,數據傳輸完成後,將連接間隔調高,讓系統休眠下去。

就是在ble的各種狀態下要設置好正確的連接間隔。

如下的示例代碼中,紅色部分不能少了:

static bt_status_t bt_app_common_event_callback(bt_msg_type_t msg, bt_status_t status, void *buff)   {    ……    switch (msg)    {        ……        case BT_GAP_LE_CONNECT_IND:   /* 0x1000000a */            {                bt_gap_le_connection_ind_t *connection_ind = (bt_gap_le_connection_ind_t *)buff;                ble_conn_handle = connection_ind->connection_handle;                gattc_disc(FIRST_TIME_DISC);                global_ble_status = broadcast_ble_status(BLE_STATUS_CONNECTED);                            ble_app_stop_advertise_data();

     ble_update_connection_interval(ble_conn_handle,BLE_CONN_LOW_POWER);
           }            break;              ……            ……

4)手錶設置了密碼過後,功耗增加

現象描述:在手機APP 上面設置了手錶密碼之後,手錶的功耗增加2mA

分析方法:通過代碼分析過程中涉及的所有硬件器件的狀態。在這個過程中,相關代碼打開了Capsensor這個硬件器件。

原因分析:Capsensor 設置的模式為full-power mode ,這種模式下的功耗過高。

解決方案:將Capsensor 設置為low-power mode。

備註:由於後期測試Capsensor 測量不準,最終改為了HRM 紅外去檢測佩戴狀態

5)開始游泳後,功耗增加

現象描述:進入游泳模式,滅屏測試2分鐘後,手錶電流在3.xmA,可是退出遊泳模式後回到錶盤,手錶待機電流功耗仍然3.xmA

分析方法:將游泳算法屏蔽掉,問題消失。所以將問題定位在游泳算法的退出機制。

原因分析:游泳算法被disable的時候沒有正確置空游泳識別函數(之前是通過設置回調函數的方式掛載游泳識別函數),導致系統認為游泳識別的函數一直在被掛載,從而不停的執行游泳識別函數。

如下是修改前後的示例代碼(看加減號提示的那幾行):

pace_algo_task.c Case ALGO_CONFIG_DISALBE: {     endSwim(swimCallback); -    Algorithm_select(ALGORITHM_SELECT_SWIM,0);

+    SWIMDetectCallBackRegister(NULL);

+    Algorithm_select(ALGORITHM_SELECT_SWIM,0); } Break; Default;

6)使用過程中功耗增加200uA

現象描述:放置一段時間、高耗電場景後、或者插入充電器開機,待機功耗增加

分析方法:測試的時候經常發現插拔usb會有這個現象。通過摘件的方式把電量計 IC去掉的時候,發現問題消失。於是將問題目標縮小到電量計IC上。然後請供應商來一起幫助進一步分析和定位。

原因分析:電量計 IC 驅動軟件的初始化問題。

解決辦法:修改電量計IC的初始化代碼

四、總結一下

我們內部大量的功耗測試與驗收數據證明了這種設計的有效性,項目落地之後大量的用戶反饋也充分證明了這個低功耗高顏值方案的價值。在我們發佈4個多月後某世界頂級廠商也發佈了類似的產品。

如何做到?除了常規的硬件器件選型和硬件設計之外,本文總結的經驗如下:

1.CPU選取需要儘可能平衡好功耗與算力的關係

2.雙核架構需要引入,充分利用小核做更多算法與緩存工作,也有利於解耦

3.通過自研OS,可以將算力和RAM節約到極致。踏踏實實花7-8個月寫大概30萬行代碼,可以收斂到穩定狀態

4.做好雙核通信的設計與實現,解決穩定性和通信效率問題

5.選擇合適的UI框架,設計與封裝AMS Task,應用開發可以獨立展開,事半功倍

6.根據器件的軟硬件特性,需要從器件硬件電路,驅動和OS幾個層面一起全面走查,逐一排查和解決功耗問題。

五、作者介紹

黃石柱 :真時科技研發副總裁,騰訊移動客戶端與操作系統技術專家

特別感謝如下同學,他們為操作系統的設計與實現付出了大量的智慧和心血,為此次總結提供了不少的寶貴意見和參考素材。

1.張巨廣

騰訊車聯網系統架構師,真時科技操作系統研發負責人

2.秦耕

真時科技操作系統研發負責人,騰訊操作系統研發高級工程師

3.馬偉富

真時科技驅動軟件高級工程師,TCL驅動軟件高級工程師

4.張一凡

真時科技操作系統高級工程師,UI框架主設計師

如果您覺得我們的內容還不錯,就請轉發到朋友圈,和小夥伴一起分享吧~

超低功耗操作系統的設計經驗

原文 :

相關閱讀

免责声明:本文内容来源于mp.weixin.qq.com,已注明原文出处和链接,文章观点不代表立场,如若侵犯到您的权益,或涉不实谣言,敬请向我们提出检举。