把Bootloader玩出花
上面我所講的都是BL最基礎(chǔ)的一些內(nèi)容,是我們實(shí)現(xiàn)BL所必須了解的。BL真正的亮點(diǎn)在于多種多樣的固件數(shù)據(jù)獲取方式。
BL的實(shí)現(xiàn)與延伸(串口傳輸固件)
前面我講到過(guò)兩個(gè)BL應(yīng)用的實(shí)例,一個(gè)是串口傳輸固件文件,一個(gè)是SD卡拷貝固件文件。它們是在實(shí)際工程中經(jīng)常被用到的兩種BL形式。
這里著重對(duì)前一個(gè)實(shí)例的實(shí)現(xiàn)細(xì)節(jié)進(jìn)行講解剖析,因?yàn)樗浅>哂械湫鸵饬x,如圖
這個(gè)流程圖提出了3個(gè)問(wèn)題:
串口通信協(xié)議是如何實(shí)現(xiàn)的?
為什么獲取到上位機(jī)傳來(lái)的固件數(shù)據(jù),不是直接寫(xiě)入到APP區(qū),而是先暫存,還要校驗(yàn)?
對(duì)固件數(shù)據(jù)是如何實(shí)現(xiàn)校驗(yàn)的?
第一個(gè)問(wèn)題,串口通信協(xié)議以及文件傳輸實(shí)現(xiàn)的相關(guān)內(nèi)容略顯繁雜,在以后的文章會(huì)專(zhuān)門(mén)進(jìn)行講解。
第二個(gè)問(wèn)題:經(jīng)過(guò)串口傳輸最終由單片機(jī)接收到的固件數(shù)據(jù)是可能出現(xiàn)差錯(cuò)的,而有錯(cuò)誤的固件冒然直接寫(xiě)入到APP區(qū),是一定運(yùn)行不起來(lái)的。所以,我們要對(duì)數(shù)據(jù)各幀進(jìn)行暫存,等全部傳輸完成后,對(duì)其進(jìn)行整體校驗(yàn),以保證固件數(shù)據(jù)的絕對(duì)正確。
針對(duì)第三個(gè)問(wèn)題,我們要著重探討一下。
一個(gè)文件從發(fā)送方傳輸?shù)浇邮辗?,如何確定它是否存在錯(cuò)誤?
通常的做法在文件中加入校驗(yàn)碼,接收方對(duì)數(shù)據(jù)按照相同的校驗(yàn)碼計(jì)算方法計(jì)算得到校驗(yàn)碼,將之與文件中的校驗(yàn)碼進(jìn)行對(duì)比,一致則說(shuō)明傳輸無(wú)誤,如圖。
上圖是對(duì)固件文件的補(bǔ)齊以及追加校驗(yàn)碼的示意。
為什么要對(duì)文件補(bǔ)齊?嵌入式程序經(jīng)過(guò)交叉編譯生成的可燒錄文件,比如 BIN,多數(shù)情況下都不是128、256、512或1024的整數(shù)倍。這就會(huì)導(dǎo)致在傳輸?shù)臅r(shí)候,最后一幀數(shù)據(jù)的長(zhǎng)度不足整幀,就會(huì)產(chǎn)生一個(gè)數(shù)據(jù)尾巴。
取整補(bǔ)齊是解決數(shù)據(jù)尾巴最直接的方法。這一操作是在上位機(jī)上完成的,通常是編寫(xiě)一個(gè)小軟件來(lái)實(shí)現(xiàn)。這個(gè)小軟件同時(shí)會(huì)將校驗(yàn)碼追加到固件文件末尾。這個(gè)校驗(yàn)碼可以使用校驗(yàn)和(Checksum)或者 CRC,一般是 16 位或 32 位,如圖,通過(guò)一個(gè)小軟件實(shí)現(xiàn)對(duì)固件文件補(bǔ)齊和添加校驗(yàn)碼。
又有人會(huì)問(wèn):“要把整個(gè)固件暫存下來(lái),再作校驗(yàn),那得需要額外的存儲(chǔ)空間吧,外擴(kuò)ROM(FlashROM或EEPROM)?”
是的。如果想節(jié)省成本,我們也可以不暫存,傳輸時(shí)直接燒寫(xiě)到APP區(qū)。這是有風(fēng)險(xiǎn)的,但是一般來(lái)說(shuō)問(wèn)題不大(STC和STM32的串口ISP其實(shí)也都是實(shí)時(shí)燒寫(xiě),并不暫存)。
因?yàn)樵趥鬏數(shù)倪^(guò)程中,傳輸協(xié)議對(duì)數(shù)據(jù)的正確性是有一定保障的,它會(huì)對(duì)每一幀數(shù)據(jù)進(jìn)行校驗(yàn),失敗的話會(huì)有重傳,連續(xù)失敗可能會(huì)直接終止傳輸。所以說(shuō),一般只要傳輸能夠完成,基本上數(shù)據(jù)正確性不會(huì)有問(wèn)題。
但是,仍然建議對(duì)固件進(jìn)行整體校驗(yàn),在成本允許的情況下適當(dāng)擴(kuò)大ROM容量。同時(shí),固件暫存還有一個(gè)另外的好處,在APP區(qū)中的固件受到損壞的時(shí)候,比如固件意外丟失或IAP時(shí)不小心擦除了APP區(qū),此時(shí)我們還可以從暫存固件恢復(fù)回來(lái)(完備的BL會(huì)包含固件恢復(fù)的功能)。
其實(shí)也不必非要外擴(kuò)ROM,如果固件體積比較小的話,我們可以把單片機(jī)的片上ROM砍成兩半來(lái)用,用后一半來(lái)作固件暫存。將片上ROM劃分為3部分:
我們將片上ROM劃分為3部分,分別用于存儲(chǔ) BL、APP 固件以及暫存固件。比如我們使用 STM32F103RBT6,它一共有128KB 的 ROM,可以劃分為 16K/56K/56K。
有些產(chǎn)品對(duì)成本極為敏感。我就有過(guò)這樣的開(kāi)發(fā)經(jīng)歷,當(dāng)時(shí)使用的單片機(jī)是 STM32F103C8T6,片上ROM總?cè)萘繛?4K,固件大小為48K,BL為12K。在通過(guò)BL進(jìn)行固件燒寫(xiě)時(shí)根本沒(méi)有多余的ROM進(jìn)行固件暫存。我使用了一招“狗尾續(xù)貂”,如圖
我無(wú)意中了解到 STM32F103C8T6 與 RBT6 的晶元是同一個(gè)。只是因?yàn)橛行?a href="http://www.www27dydycom.cn/v/tag/137/" target="_blank">芯片后 64KB 的ROM性能不佳或有瑕疵,而被限制使用了。我實(shí)際測(cè)試了一下,確實(shí)如此。
但是后 64K ROM 的使用是有前提的,也就是需要事先對(duì)其好壞進(jìn)行驗(yàn)證。如果是好的,則暫存校驗(yàn),再寫(xiě)入APP區(qū);而如果是壞的,那么就直接在固件傳輸時(shí)實(shí)時(shí)寫(xiě)入APP區(qū)(這個(gè)辦法我屢試不爽,還沒(méi)有發(fā)現(xiàn)后64K有壞的)。
以上振南所介紹的是一種“騷操作”,根本上還是有一定的風(fēng)險(xiǎn)的,ST 官方有聲明過(guò),對(duì)后 64K ROM 的質(zhì)量不作保證,所以還是要慎用。
10米之內(nèi)隔空燒錄
這個(gè)“隔空燒錄”源于我的一個(gè) IoT 項(xiàng)目,它是對(duì)空調(diào)的外機(jī)進(jìn)行工況監(jiān)測(cè)。大家知道,空調(diào)外機(jī)的安裝那可不是一般人能干的,它要不就在樓頂,要不就在懸窗上。這給硬件升級(jí)嵌入式程序帶來(lái)很大的困難。
所以,我實(shí)現(xiàn)了“隔空燒錄”的功能,其實(shí)它就是串口BL應(yīng)用的一個(gè)延伸,如圖所示,通過(guò)藍(lán)牙串口模塊實(shí)現(xiàn)“隔空燒錄”。
“隔空燒錄確實(shí)牛,但是總要抱著一個(gè)電腦,這不太方便吧?!贝_實(shí)是!還記得前面我提過(guò)的AVRUBD通信協(xié)議嗎?它的上位機(jī)軟件是有手機(jī)版的。這樣我們只要有手機(jī),就能“隔空燒錄”了,如圖,手機(jī)連接藍(lán)牙串口模塊實(shí)現(xiàn)“手機(jī)隔空燒錄”。
“哪個(gè)APP?快告訴我名字”,別急,藍(lán)牙串口助手安卓版,下圖是正在傳輸固件的界面。
AVRUBD其實(shí)是對(duì) Xmodem 協(xié)議的改進(jìn),這個(gè)我們放在專(zhuān)門(mén)的文章進(jìn)行詳細(xì)講解。
BL的分散燒錄
我們知道BL的核心功能其實(shí)就是程序燒錄。那你有沒(méi)有遇到過(guò)比較復(fù)雜的情況,如圖所示,一個(gè)系統(tǒng)(產(chǎn)品)中有多個(gè)部件需要燒錄固件。
這種情況是有可能遇到的。主 MCU+CPLD+通信協(xié)處理器+采集協(xié)處理器就是典型的復(fù)雜系統(tǒng)架構(gòu)。這種產(chǎn)品在批量生產(chǎn)階段,燒錄程序是非常繁瑣的。首先需要維護(hù)多個(gè)固件,再就是需要一個(gè)個(gè)給每一個(gè)部件進(jìn)行燒寫(xiě),燒寫(xiě)方式可能還不盡相同。所以我引入了一個(gè)機(jī)制,叫“BL的分散燒錄”。
首先,我們將所有的固件拼裝成一個(gè)大固件(依次數(shù)據(jù)拼接),并將這個(gè)大固件預(yù)先批量燒錄到外擴(kuò) ROM 中,比如spiFlash;再將主MCU預(yù)先燒錄好BL;然后進(jìn)行SMT焊接。
PCBA生產(chǎn)出來(lái)之后,只要一上測(cè)試工裝(首次上電),BL會(huì)去外擴(kuò)ROM中讀取大固件,并從中分離出各個(gè)小固件,分別以相應(yīng)的接口燒錄到各個(gè)部件中去。配合工裝的測(cè)試命令,直接進(jìn)行自檢。
這樣做,批量化生產(chǎn)是非常高效的。當(dāng)然,這個(gè) BL 開(kāi)發(fā)起來(lái)也會(huì)有一定難度,最大問(wèn)題可能還是各個(gè)部件燒錄接口的實(shí)現(xiàn)(有些部件的燒錄協(xié)議是比較復(fù)雜的,比如 STM32 的 SWD 或者 ESP8266 的 SLIP)。
BL沒(méi)有最好的,只有最適合自己的。通常來(lái)說(shuō),我們并不會(huì)把BL設(shè)計(jì)得非常復(fù)雜,原則上它應(yīng)該盡量短小精煉,以便為APP區(qū)節(jié)省出更多的ROM空間。畢竟不能喧賓奪主,APP才是產(chǎn)品的主角。
不走尋常路的BL
Bootpatcher
我來(lái)問(wèn)大家一個(gè)問(wèn)題:“Bootloader在 ROM 中的位置一定是在 APP 區(qū)前面嗎?”很顯然不是,AVR 就是最好的例子。那如果我們限定是 STM32 呢?似乎是的。上電復(fù)位一定是從0X08000000位置開(kāi)始運(yùn)行的,而且BL一定是先于APP運(yùn)行的。
在某些特殊的情況下,如果 APP 必須要放在0X08000000位置上的話,請(qǐng)問(wèn)還有辦法實(shí)現(xiàn)BL串口燒錄嗎?要知道APP在運(yùn)行的時(shí)候,是不能 IAP 自己的程序存儲(chǔ)器的(就是自己能自己擦出重新燒錄新固件)。請(qǐng)看圖,BL位于APP之后稱(chēng)之為Bootpatcher。
APP運(yùn)行時(shí),想要重新燒錄自身,它可以直接跳轉(zhuǎn)到后面的BL上,BL運(yùn)行起來(lái)之后開(kāi)始接收固件文件,暫存校驗(yàn)OK之后,將固件寫(xiě)入到前面的APP區(qū)。然后跳轉(zhuǎn)到 0X08000000,或者直接重啟。這樣新的APP就運(yùn)行起來(lái)了。
這個(gè)位于 APP 后面的 BL,我們稱(chēng)之為 Bootpatcher(意為啟動(dòng)補(bǔ)?。5沁@種作法是有風(fēng)險(xiǎn)的,一旦 APP 區(qū)燒錄失敗,那產(chǎn)品就變磚了。所以這種方法一般不用。
APP反燒BL
前面我們都是在講BL燒錄APP,那如果BL需要升級(jí)怎么辦呢?用 JLINK。不錯(cuò),不過(guò)有更直接的方法,如圖,APP燒錄BL區(qū)。
這是一種逆向思維,我們?cè)?APP 程序中也實(shí)現(xiàn)接收固件文件,暫存校驗(yàn),然后將其燒錄到 BL 區(qū)。這種作法與Bootpatcher 同理,也是有一定風(fēng)險(xiǎn)的,但一般都沒(méi)有問(wèn)題。
最后
OK,本系列文章對(duì)BL進(jìn)行了詳盡的剖析講解,應(yīng)該做到了深入淺出,包含基本的原理,以及實(shí)例的實(shí)現(xiàn),還有一些知識(shí)的擴(kuò)展。希望能夠?qū)Υ蠹耶a(chǎn)生啟發(fā),在實(shí)際的工作中將這些知識(shí)付諸實(shí)踐。
審核編輯:黃飛
?
評(píng)論