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