陳藝芃,林飛浪,郭大鳴,陳飛明
(1.武漢郵電科學(xué)研究院,湖北武漢 430074;2.烽火通信科技股份有限公司,湖北武漢 430073;3.武漢紡織大學(xué),湖北 武漢 430073)
在嵌入式板級應(yīng)用的開發(fā)過程中,系統(tǒng)設(shè)備的軟件代碼不是一次開發(fā)就能夠完成的,需要進行多次的修改、更新和壓縮操作來完善。針對測試人員在測試過程中發(fā)現(xiàn)的一些問題和客戶在使用過程中提出的一些新的功能需求,軟件開發(fā)人員需要提供一種合理的代碼升級方式以便對設(shè)備進行在線升級。
嵌入式設(shè)備軟件升級通常采用移植一個適用于該系統(tǒng)的獨立BootLoader的方式,BootLoader 指啟動引導(dǎo)程序,是系統(tǒng)加電后運行的第一段軟件代碼,通過這段代碼,可以初始化硬件設(shè)備,建立內(nèi)存空間的映射圖,以便為最終調(diào)用操作系統(tǒng)內(nèi)核提供正確的環(huán)境[1-2]。使用這種方式存在的問題是升級前需要將MCU 片內(nèi)Flash 舊版本擦除,為新版本的寫入釋放空間,這勢必導(dǎo)致設(shè)備停機[3-5]。
近年來常用的Bank Swap 方式可以解決上述問題。Bank Swap是ST公司對旗下的STM32F4、STM32F7系列芯片提供的MCU 片內(nèi)Dual Bank Flash 進行交換的方式,它在執(zhí)行程序的同時可對另一個Bank 進行擦除和編程操作。利用這個特性,可實現(xiàn)在線程序更新。在嵌入式設(shè)備軟件初版代碼的開發(fā)過程中,初始代碼可能會較為龐大,對于比較復(fù)雜的設(shè)備,需要很大的運行內(nèi)存容量,而Bank Swap 方式要將MCU 片內(nèi)Flash 分為兩部分運行,可用運存容量減半,直接采用Bank Swap 方式可能會影響開發(fā)過程中對軟件的調(diào)試。
針對上述問題,文中設(shè)計了一種將獨立BootLoader和Bank Swap 結(jié)合的方案。在開發(fā)初期先使用BootLoader+APP的方式過渡,并設(shè)計BootLoader+APP的版本,使其具備升級轉(zhuǎn)換成Bank Swap 模式的功能。待開發(fā)后期壓縮工程的目標(biāo)文件小于1M(STM32F4 片內(nèi)Flash 容量為2 M),通過修改程序中的標(biāo)識位完成模式切換,即可以實現(xiàn)不停機升級操作,滿足所有開發(fā)需求的同時將外部Flash 棄用,可以停止對片外BootLoader的維護,減少運維工作量。
對于STM32平臺的啟動引導(dǎo)和代碼升級,常用的方式是采用BootLoader+APP的方式。在此可以移植一個適用于該系統(tǒng)的獨立BootLoader,將MCU片內(nèi)Flash劃分為BootLoader 區(qū)和User Code 區(qū)[6]。BootLoader用于實現(xiàn)通過某種通信方式(如USB、USART)接收程序或數(shù)據(jù),執(zhí)行對APP 代碼的更新,通常存儲于Flash的起始地址(0x08000000)。User Code 區(qū)運行的是產(chǎn)品實現(xiàn)業(yè)務(wù)邏輯正常運行的APP 代碼,該部分代碼存儲在片內(nèi)Flash 中的BootLoader 區(qū)之后,需要進行相對的地址偏移;而緩存的升級數(shù)據(jù)可以存儲在片外Flash 中,以節(jié)約內(nèi)部存儲空間。獨立BootLoader 模式升級數(shù)據(jù)流向圖如圖1 所示。
圖1 獨立BootLoader模式升級數(shù)據(jù)流向圖
圖1 箭頭所指為數(shù)據(jù)流向,在APP 中接收升級數(shù)據(jù)并緩存到外部Flash。升級時MCU 重啟進入BootLoader,BootLoader 檢查是否需要更新,若需要更新,則讀取緩存在外部Flash的升級數(shù)據(jù)包,進行后續(xù)升級動作,引導(dǎo)代碼進入應(yīng)用區(qū);若BootLoader沒有檢測到需要更新,開始檢測應(yīng)用區(qū)代碼是否完整,如果完整則引導(dǎo)進入應(yīng)用區(qū),否則停留在Boot中,提示上位機等待BootLoader 引導(dǎo)程序進入應(yīng)用區(qū)運行[7-9]。應(yīng)用接收到升級命令,在Flash 做一個升級動作標(biāo)記,記錄升級的版本等信息。重啟MCU 進入BootLoader 進行升級。
近年來利用Bank Swap 方式進行軟件升級也越發(fā)普遍。對于STM32F4 系列的MCU,可以通過配置Dual Bank和Dual Boot 項,改變RWW 特性,從而實現(xiàn)Bank Swap 方式,以解決上述問題[10]。
配置成Dual Bank 模式后,片內(nèi)Flash的地址將重新編排。如圖2 所示,Bank1的地址為0x08000 000~0x080FFFFF,Bank2的地址為0x08100000~0x081FFFFF,扇區(qū)的數(shù)量從12 增加到了24,均勻分配于兩個Bank 之中。每個Bank 中對應(yīng)扇區(qū)的容量都為之前的一半,Dual Bank 模式時讀寫的最小單元為128 bit,也是Single Bank的一半。
圖2 切換Dual Boot模式Flash分區(qū)示意圖
將Single Bank 轉(zhuǎn)變成Dual Bank 是通過縱向劃分實現(xiàn)的。讀取寬度由8 words 變成了4 words。如圖3 所示,將Flash 控制器的地址線和數(shù)據(jù)線由一組分成兩組,高位一組,低位一組,這樣就可以實現(xiàn)在一個Bank 執(zhí)行讀操作時,對另一個Bank 進行寫操作。
圖3 Dual Boot模式Flash的劃分方式圖
另外需要注意的是模式轉(zhuǎn)換前,存儲數(shù)據(jù)地址的變動。假設(shè)Sector1 中存儲著連續(xù)的256 bit 數(shù)據(jù),由于采用縱向劃分,在劃分過程中高地址被重新編排,分別存儲到Sector1和Sector13的對應(yīng)位置中,跟原來的地址不再連續(xù),導(dǎo)致Flash 保存的內(nèi)容被完全打亂了。即使切換前只使用到MCU 片內(nèi)Flash的前半部分,也需要在模式切換后將原有的數(shù)據(jù)擦除并重新燒錄到設(shè)定的Bank 中。
當(dāng)Flash配置成Dual Bank模式時,STM32F4 可以實現(xiàn)Dual Boot 模式,即雙啟動方式。程序可以選擇從Bank1啟動,也可從Bank2啟動。這個操作是由保存在片內(nèi)MCU的System Memory中的BootLoader 實現(xiàn)的,BootLoader 判斷到當(dāng)前是Dual Bank 模式且配置Dual Boot 選項,則根據(jù)用戶配置的啟動地址,選擇從Bank1 啟動或者從Bank2 啟動。
RWW(Read-While-Write,RWW)是指在系統(tǒng)做運行讀取操作的同時支持擦除寫入操作的特性。由圖4 可以看出,當(dāng)使用Single Bank 模式時,對Flash的寫操作會導(dǎo)致其他讀操作被掛起,程序停止執(zhí)行。而Dual Bank 模式中,可以在一個Bank的程序執(zhí)行過程中對另一個Bank 執(zhí)行寫操作。
圖4 RWW特性示意圖
Bank Swap 方式利用Dual Bank 中的RWW 特性,在實現(xiàn)升級的同時其他任務(wù)可以繼續(xù)運行,不影響系統(tǒng)正常功能的運轉(zhuǎn),并保證了升級期間片內(nèi)另一個Bank 舊版本的完整性。
鑒于上述分析,結(jié)合工程實際需要,考慮到防止User Code 在開發(fā)初期超出單Bank 最大容量的可能(STM32F4 片內(nèi)Flash 容量為2 M),最終決定選擇獨立BootLoader和Bank Swap 結(jié)合的方案。在開發(fā)初期先使用BootLoader+APP的方式過渡,并將此獨立BootLoader的版本設(shè)計為具備升級轉(zhuǎn)換成Bank Swap模式的功能。待開發(fā)后期壓縮工程的目標(biāo)文件小于1M,通過修改程序中的標(biāo)識位完成模式切換,升級操作完全在MCU 片內(nèi)進行,通過Bank 切換即可以實現(xiàn)不停機升級操作。更新為Bank Swap 穩(wěn)定版后可以停止對片外BootLoader的維護,減少運維工作量。
將Flash 配置成Dual Bank 模式,片內(nèi)Flash 地址進行重新編排。通過Flash_OPTCR 寄存器配置User Option Byte 中的nDBANK=0。Option Byte 不能直接寫,需要通過Flash_OPTCR 寄存器來操作。
配置Dual Bank 模式完成后,即可開啟Dual Boot模式。通過Flash_OPTCR 寄存器,配置Option Byte中的nDBOOT=0,即可配置成Dual Boot 模式。
Flash 配置成兩個Bank后,可實現(xiàn)Bank之間直接進行地址交換的功能。配置SYSCFG_MEMRMP寄存器中的SWP_FB,來選擇是否交換。當(dāng)SWP_FB的值為0 時,Bank1的基地址為0x08000000,Bank2的基地址為0x08 100000;當(dāng)SWP_FB的值為1 時,兩個Bank的基地址對換。由此可以看出,無論從哪個Bank 啟動,都能保證起始基地址為0x08000000。
獨立BootLoader模式業(yè)務(wù)流程如圖5所示??梢钥闯鯞ootLoader和APP是互斥的,BootLoader運行時APP不運行,APP運行時BootLoader不運行。APP 接收完升級數(shù)據(jù)后,自身無法更新自身的代碼,必須重啟進入BootLoader才能完成APP代碼的更新[11]。App 在Flash 中的某個位置記錄升級動作,然后重啟進入BootLoader,BootLoader檢查Flash中相應(yīng)位置的標(biāo)志位,如需升級,則讀取代碼緩存區(qū)的新版本程序,對APP 進行更新,更新完成后清空該標(biāo)志位。
圖5 獨立BootLoader模式業(yè)務(wù)流程圖
將新程序?qū)懭險ser Code 區(qū),發(fā)生斷電等意外時,APP 可能不完整,下次啟動BootLoader 后會對APP的完整性進行檢查,如果發(fā)現(xiàn)APP 不完全(這種情況多數(shù)是上次升級刷機時,沒有完成Flash的寫操作便被中斷導(dǎo)致的,那么升級包緩存區(qū)還保留著升級程序),則檢查升級包緩存區(qū)的升級文件是否完整[12]。如果完整,則將其再次恢復(fù)到APP 代碼區(qū),否則停留在BootLoader,并主動請求升級。
為執(zhí)行BootLoader 升級模式轉(zhuǎn)換為Bank Swap模式的指令,在代碼中增加了一個標(biāo)識,每次升級的時候,BootLoader 識別該標(biāo)識,如果沒有轉(zhuǎn)換成Swap方式的需求,則按原設(shè)計,將代碼升級到User Code區(qū);假如有轉(zhuǎn)換成Bank Swap 模式的需求,則將代碼更新到Bank2,同時設(shè)置boot address 啟動地址為Bank2的起始地址,確認(rèn)設(shè)置為Dual Boot 模式,然后重啟進入Bank2 運行新程序。新程序應(yīng)當(dāng)具備Swap Bank 模式的升級能力。
升級為Swap 模式后,進入Bank2 運行,便切換到Bank Swap 模式了,此后,新的業(yè)務(wù)流程如圖6 所示。在Bank Swap 模式中,程序也是永遠運行于起始地址是0x8000000的片內(nèi)Flash 中,但有可能是Bank1,也有可能是Bank2,因為執(zhí)行Bank Swap 操作后,Bank2的起始地址也是0x8000000。因此,升級的過程中,新程序總是燒錄在地址0x8100000 中,經(jīng)過Swap,0x8100000 所屬的Bank的地址便會變成0x8000000。需要在程序中通過讀取Option Byte 中的某些位的值來判斷當(dāng)前程序運行在哪個Bank,如BOOT_ADD0 寄存器或者SWP_BF的值。
圖6 Bank Swap模式業(yè)務(wù)流程圖
Bank Swap 操作是System Memory 中的固件Boot Loader 完成的,這個BootLoader是STM32自帶的[13]。只需要配置代碼的啟動地址和Flash的Dual Boot 模式,System Memory 中的BootLoader 會完成Bank Swap操作,并引導(dǎo)程序到指定的Bank 運行。
按照上述方案,采用以STM32F429IIT6 為核心設(shè)計的一個電源監(jiān)控系統(tǒng)為例,通過網(wǎng)管對系統(tǒng)進行升級驗證。
如圖7 所示,準(zhǔn)備好Tftp 服務(wù)器以及需要分別先后燒錄的兩個bin 文件[14]。為了更明顯地感知升級完成的現(xiàn)象,文中使用同一個工程,改變osdelay 參數(shù)將LED 測試燈閃爍的頻率設(shè)置成不一樣的值,0100.bin 為LED 快閃燒錄到地址0x8000000,閃爍延時設(shè)為300 ms;0101.bin 為LED 慢閃燒錄到地址0x8100000,閃爍延時設(shè)為2 000 ms。
圖7 Tftp傳輸工具和bin文件
打開Tftp 客戶端設(shè)置界面會自動地讀取本地的IP 地址,在下方添加主機信息和端口號以及想要傳輸?shù)腷in 文件所在的位置,如圖8 所示[15-16]。
圖8 Tftp傳輸參數(shù)填寫
使用SecureCRT 接收設(shè)備側(cè)串口上報的信息,如圖9 所示??梢钥吹皆谏壡跋到y(tǒng)運行在Bank1 中,點擊Tftp 中的Put 傳輸新文件,設(shè)備執(zhí)行更新命令,檢查CRC 校驗后自動識別非運行Bank(Bank2)的Flash 地址,寫入更新信息并完成檢查。在升級過程中設(shè)備正常運行,LED的閃爍頻率并未發(fā)生變化。重啟后串口提示系統(tǒng)已經(jīng)切換到Bank2中運行,LED的閃爍頻率也明顯降低,說明設(shè)備成功完成升級。
圖9 SecureCRT接收的串口信息
重復(fù)上述操作將0100.bin 文件燒錄進Bank1 中,升級過程中LED 持續(xù)慢閃,重啟后閃爍變快,恢復(fù)為初始頻率。說明此時系統(tǒng)可以在不影響運行的情況下,完成Read-While-Write 升級工作。
為了驗證設(shè)備在Bank Swap 模式下升級過程中出現(xiàn)的異常停機情況不會影響設(shè)備更新前運行程序的完整性,在升級期間拔掉設(shè)備與主機間的通信線,此時升級中斷。重新上電后發(fā)現(xiàn)監(jiān)控單元上的軟件為上一次的版本信息,與網(wǎng)管上待升級版本的信息不一致,說明升級失敗后監(jiān)控單元自動退回到升級前的版本運行,沒有被升級所破壞。
該文以STM32F4 軟件升級的現(xiàn)實案例為背景,為實現(xiàn)升級過程中不打斷設(shè)備運行的RWW 特性,以及升級異常時具有自動退回到升級前版本的能力,同時兼顧開發(fā)初期代碼量較大影響調(diào)試的現(xiàn)實問題,設(shè)計了一種獨立BootLoader 與Bank Swap 相結(jié)合的方案。獨立BootLoader 方案能提供更大的容量供User Code 使用,作為開發(fā)期間的過渡;而Bank Swap 方案使用System Memory 中自帶的BootLoader啟動,不需要開發(fā)和維護獨立的BootLoader,可以最終實現(xiàn)RWW 特性以及升級失敗時保護的功能。兩種模式間通過標(biāo)志位實現(xiàn)切換。最后通過Tftp 進行升級,通過LED 燈的運行狀態(tài)以及串口上報的信息,驗證了Bank的切換功能以及升級過程中系統(tǒng)可以正常運行的特性,實現(xiàn)了系統(tǒng)的設(shè)計要求。該設(shè)計對于嵌入式板級應(yīng)用的開發(fā)升級具有較大的意義。