將底層操作系統(tǒng)放于閃存中有很多好處,例如設(shè)計(jì)人員可以隨時(shí)在現(xiàn)場將軟件新版本下載到閃存中對(duì)其進(jìn)行更新,但在下載過程中有一些因素需要注意,否則會(huì)造成系統(tǒng)崩潰的災(zāi)難性后果。本文介紹一種便利的軟件結(jié)構(gòu),它可以幫助工程師避免犯一些常見的錯(cuò)誤。
所有現(xiàn)場更新底層操作系統(tǒng)的方法都存在這樣一個(gè)問題,即假如升級(jí)內(nèi)容中存在缺陷,那么目標(biāo)系統(tǒng)可能需要花很大力氣才能更正,許多缺陷很簡單且顯而易見,但有些隱藏很深的缺陷只有在產(chǎn)品完成以后才能顯現(xiàn)出來。
用戶發(fā)現(xiàn)和處理缺陷的能力各有千秋,而更糟糕的是,他們往往不注意諸如“如果在編程過程中電源系統(tǒng)中斷系統(tǒng)將受到損壞”一類的警告,在系統(tǒng)更新過程中,他們很愿意重新啟動(dòng)其它功能系統(tǒng),然后再把“出了問題”的產(chǎn)品拿去維修。
所有設(shè)計(jì)完好的底層操作系統(tǒng)更新過程,都要能夠盡可能從用戶的錯(cuò)誤和其它災(zāi)難性事件中恢復(fù),做到這一點(diǎn)最好的方法就是采取可靠的底層操作系統(tǒng)更新策略,以完全避免這些問題。本文將討論這樣一種策略,它可以直接使用,但是也可以根據(jù)實(shí)際應(yīng)用的特性對(duì)它進(jìn)行修正。
微編程器
微編程器是對(duì)嵌入式系統(tǒng)在底層操作系統(tǒng)更新過程之前、過程中及之后運(yùn)行情況的一種系統(tǒng)級(jí)描述,這種對(duì)工作情形的描述有助于避免與其它底層操作系統(tǒng)下載方法有關(guān)的問題,小心對(duì)待這些過程可以消除很多其它的擔(dān)心。
采用微編程器的底層操作系統(tǒng)更新方法第一步是使嵌入式系統(tǒng)進(jìn)入下載發(fā)生時(shí)所期望的狀態(tài)。過渡到這個(gè)狀態(tài)可以采用好幾種方式,例如,它可以通過用戶按下設(shè)備控制界面上的“升級(jí)”鍵來完成,或者在系統(tǒng)探測到文件傳輸開始或結(jié)束時(shí)進(jìn)行,或者用其它方法。不管哪種情況,目標(biāo)系統(tǒng)都會(huì)意識(shí)到底層操作系統(tǒng)馬上要更新了,于是讓其它控制過程進(jìn)入安全和穩(wěn)定的停止?fàn)顟B(tài)。
下一步,目標(biāo)系統(tǒng)會(huì)收到一個(gè)叫做微編程器的應(yīng)用程序,微編程器將控制系統(tǒng),并開始接收新的應(yīng)用底層操作系統(tǒng),將它寫到閃存中。一切完成后,目標(biāo)系統(tǒng)就開始運(yùn)行新的底層操作系統(tǒng)。
采用微編程器下載底層操作系統(tǒng)的最大特點(diǎn)之一是它的靈活性,微編程器的執(zhí)行過程即使在底層操作系統(tǒng)開始更新前的最后一刻也可以更改,以便對(duì)系統(tǒng)進(jìn)行錯(cuò)誤糾正和改進(jìn)。
微編程器不會(huì)消耗目標(biāo)系統(tǒng)的資源,除非已開始進(jìn)行編程。此外,由于微編程器很小,所以目標(biāo)系統(tǒng)在更新過程開始時(shí)不需要龐大而復(fù)雜的通訊協(xié)議,只需簡單的文本文件傳輸就足夠了。
采用微編程器的底層操作系統(tǒng)更新其安全性一度是最引人注目的優(yōu)點(diǎn)。當(dāng)目標(biāo)系統(tǒng)的閃存芯片只用于存儲(chǔ)底層操作系統(tǒng)時(shí),系統(tǒng)將不會(huì)有對(duì)閃存芯片內(nèi)容進(jìn)行刪除和編程的代碼,除非實(shí)際過程中需要這樣。因此即使在程序失控的嚴(yán)重情況下,系統(tǒng)也不會(huì)意外地刪除它本身的底層操作系統(tǒng)。
然而,微編程器也有缺點(diǎn),它通常作為一個(gè)獨(dú)立的程序執(zhí)行,因此下載和傳輸?shù)侥繕?biāo)系統(tǒng)的代碼需要分開管理。處理程序組件時(shí)小心謹(jǐn)慎有助于減少后續(xù)工作量。
微編程器一般都載入RAM中運(yùn)行,這在某些微處理器結(jié)構(gòu)中是不可能的,尤其是古老的8051系列,雖然其結(jié)構(gòu)都是面向硬件的,但它的限制大過它所帶來的好處。
下載過程
程序1中的代碼顯示的是下載目標(biāo)系統(tǒng)和運(yùn)行微編程器所需要的功能。在這個(gè)例子中,目標(biāo)系統(tǒng)從某個(gè)I/O通道(也許是串口)接收文本形式的摩托羅拉S Record文件,將它譯碼并寫到RAM中,然后在傳輸結(jié)束時(shí)目標(biāo)系統(tǒng)跳轉(zhuǎn)到下載代碼啟動(dòng)微編程器。
注意programmer_buf[]存儲(chǔ)空間是自動(dòng)調(diào)整的,也就是說它在目標(biāo)系統(tǒng)的存儲(chǔ)單元里沒有固定的位置,這意味著新記錄的地址是相對(duì)的而不是絕對(duì)的,新代碼的位置是獨(dú)立的。如果匯編程序不能產(chǎn)生位置獨(dú)立的代碼,那么programmer_buf[]就要在存儲(chǔ)器中分配一個(gè)固定的位置,新記錄的地址也要留在那個(gè)位置。
假如目標(biāo)系統(tǒng)沒有資源可長期分配給programmer_buf[],則新來的微編程器內(nèi)容可以放在其它數(shù)據(jù)的上面。此時(shí),系統(tǒng)無論如何都要中斷其它操作,將RAM大部分空間留給微編程器。
基本微編程器
微型編程器的頂級(jí)代碼如程序2所示,這個(gè)代碼也可以從某些地方接收S Record文件并將其譯碼。微編程器將新接收到的數(shù)據(jù)記錄在閃存中,當(dāng)文件傳輸完成后重新啟動(dòng)系統(tǒng)。雖然過于簡單了些(用文本文件來傳輸大的程序也許不十分可靠),但這個(gè)代碼表示了微編程器的所有重要特征。
erase_flash()除了實(shí)際擦除閃存中的內(nèi)容外,它還管理簡單的數(shù)據(jù)結(jié)構(gòu),繼續(xù)跟蹤哪一段閃存中的數(shù)據(jù)需要擦除,哪一段已經(jīng)被擦除。S Record文件中經(jīng)常會(huì)出現(xiàn)數(shù)據(jù)雜亂無章的情況,這時(shí)數(shù)據(jù)結(jié)構(gòu)要通過is_section_erased()來檢查以防止閃存重復(fù)擦除。
只讀存儲(chǔ)器
不管如何修改采用微編程器的系統(tǒng)描述來適應(yīng)自己系統(tǒng)的要求,在最后執(zhí)行的時(shí)候還是會(huì)遇到一些常見的問題。
有些調(diào)試器特別是仿真器,將會(huì)與目標(biāo)處理器爭奪可寫入代碼的存儲(chǔ)空間。多數(shù)調(diào)試工具將代碼空間當(dāng)作是只讀的,當(dāng)它們探測到要寫入內(nèi)容時(shí),有些會(huì)產(chǎn)生錯(cuò)誤信息或簡單地不允許寫入。
一般來說,調(diào)試器保護(hù)代碼空間本身是好意,因?yàn)槌绦蛟谧陨泶a空間寫入數(shù)據(jù)通常會(huì)引發(fā)嚴(yán)重的程序錯(cuò)誤,除非那時(shí)正在進(jìn)行底層操作系統(tǒng)的更新。不幸的是調(diào)試器并不能夠判別出它們之間的區(qū)別。補(bǔ)救的方法是在調(diào)試器不會(huì)認(rèn)為是只讀的其它存儲(chǔ)空間里,對(duì)閃存芯片進(jìn)行“化名(alias)寄存”。
常用化名寄存方法很簡單,只需要將所選擇激活的器件存儲(chǔ)空間加倍,然后將指向“物理”地址區(qū)域的地址轉(zhuǎn)移到指向“化名”區(qū)域就行了,進(jìn)行轉(zhuǎn)移的最好的場所通常是閃存芯片驅(qū)動(dòng)器本身,如程序3中的假設(shè)write_flash()函數(shù)。
完整的編程器
采用微編程器方式的另一種方法是將微編程器的功能建在目標(biāo)系統(tǒng)中,即所謂的啟動(dòng)加載,而不是把將它下載到RAM作為底層操作系統(tǒng)更新過程的第一步。這種策略有它的優(yōu)點(diǎn),但是在閃存芯片擦除重新編程前需要將閃存中的編程器代碼復(fù)制到RAM中。換句話說,就是代碼在運(yùn)行的時(shí)候,要自己重新定位到RAM中的某一點(diǎn)上,然后才能擦除并寫到閃存芯片中。這種方法同樣需要涉及到的代碼是位置獨(dú)立的。





