如今,幾乎所有可聯網的電子設備都支持遠程升級(OTA)功能,OTA 一是讓電子設備能夠支持更多的功能,二是能夠修復一些應用程序中的漏洞。
前文中,我們在 2nd Bootloader 中實現了類似 ISP 的下載的功能,上位機如果基于 Ymodem 協議,通過 2nd Bootloader 下載應用程序到 Flash 中,其實就可以實現簡單的 OTA 功能,但是,這樣的 OTA 卻是不安全的:無法保證升級過程中,若出現意外情況,打斷升級后,微控制器還能夠執行原有的應用程序。健全的 OTA,需要保證微控制器即使在升級失敗之后,也依然能夠按照升級之前的應用程序繼續工作。
?設計
升級應用程序這個需求其實通過前文實現的 ISP 就能實現,而 OTA 升級失敗后,依然能夠執行升級前的應用程序,才是 OTA 升級的難點。
OTA 為什么會升級失?。坑腥缦驴赡埽?/p>
OTA 升級過程中,意外斷開網絡,固件包接收不完整。
OTA 升級過程中,設備突然斷電,固件包接收不完整。
OTA 升級過程中,設備突然斷電,接收到的固件包未寫入到 Flash 中。
如果要保證 OTA 升級失敗后,原有的應用程序還能夠正常運行,就需要讓接收到的固件包,不能直接覆蓋到原有的固件中。因此,我們需要把 Flash 空間一分為二,分別是執行區域和備份區域,執行區域存儲的是當前微控制器可執行的固件,2nd Bootloader 會引導微控制器跳轉到這塊區域執行應用程序,而備份區域就是存放將要下載的新固件,如圖1所示:
圖1 Flash 空間劃分
還需要將 OTA 的過程分為兩個大的步驟:
固件下載過程
固件更新過程
固件下載過程中,微控制器 會把接收到的固件保存到備份區域,如圖2所示。
圖2 固件包存儲在備份區域
固件更新過程中,微控制器 會把備份區域的固件復制到執行區域中如圖3所示。
圖3 固件包轉移到執行區域
由于固件包存儲在備份區域,固件下載過程中再怎么失敗,也影響不到執行區域的固件,所以應用程序能夠正常運行。
然后問題來了,當備份區域的固件下載好后,該怎么轉移到執行區域上呢?其流程如圖4所示:
圖4 備份區域內容復制到執行區域
是不是很簡單,但如果在固件更新的過程中斷電,固件復制到一半怎么辦?
因此,我們需要在 Flash 中保存一些信息,讓微控制器復位后,在執行應用程序前,都先檢查下固件是否已經復制完畢。
我們在執行區域和備份區域的末尾分別上寫一些內容,來驗證執行區域內容的完整性,存放這些內容的區域可稱為信息塊,如圖5所示。
圖5 在各區域末尾添加信息塊存儲區
信息塊的大小至少是 Flash 的最小擦除單位,以保證擦除信息塊時不影響其它內容。大多數常見的 QSPI Flash 的最小擦除單位大小是 4KB,片內 Flash 是 1KB,因此這個信息塊的大小可按照 4KB 大小設計,執行區域和備份區域各一個,共計 8KB 大小。
信息塊中包含以下信息:
固件版本,用于判斷備份區域的固件是否為新的固件,是否執行固件更新操作
固件大小,需要復制備份區域多少內容到執行區域
信息塊內容的校驗值,建議使用是 CRC 校驗,而不建議使用 BCC 校驗,目的是證明這個信息塊的內容可信,保證信息塊的完整性
為什么說不建議使用 BCC 校驗呢?一般來說,Flash 擦除信息后,讀取的數據一般是 0xFF,如果使用 BCC 校驗,其校驗值只能是 0x00 或 0xFF,如果是 0xFF,則又與擦除后的 Flash 中的數據相同,起不到校驗的效果,而 0x00 又容易碰撞到別的數據。
一般來說,上位機發送過來的文件中不包含版本號信息,那如何進行版本號管理呢?可在微控制器中自行管理:當新的固件下載好后,其版本號按照如圖6方式管理:
圖6 版本號管理
當 2nd Bootloader 進入到 ISP 模式后,會執行固件下載的過程,從外界接收新的固件,隨后復位微控制器,進入執行應用程序的模式。
固件下載過程的流程圖如圖7 所示:
圖7 固件下載過程
當 2nd Bootloader 進入到執行應用程序的模式后,并不會直接運行應用程序,而是執行固件更新過程,將備份區域的新固件復制到執行區域,待固件更新過程完畢后,才會執行應用程序。
事實上,每次 2nd Bootloader 進入到執行應用程序的模式后,都會執行固件更新過程,固件更新包括了檢查是否下載了新固件和是否已經完成復制新固件到執行區域兩部分內容,如果沒有新的固件包在備份區域的話,固件更新程序就會提前結束,直接執行應用程序。
固件更新過程如圖8所示:
圖8 固件更新過程
?過程分析
為了保證 OTA 過程的安全,我們需要保證備份區域和執行區域至少有一個固件是完整的,這樣,當備份區域的固件破壞時,我們能夠保證執行區域的固件還能用,而執行區域的固件損壞時,還能從備份區域恢復過來。
那怎么確定某區域的固件是完整的呢?
通過圖7和圖8可知,不管是下載固件到備份區域,還是復制備份區域固件到執行區域,只要有寫固件的操作,都會先將對應區域的信息塊進行擦除,直到寫固件完成,才會把新的信息塊寫入到指定區域。因此,我們可以通過信息塊是否完整來判斷該區域的固件是否完整,信息塊的校驗值是驗證信息塊完整性的保證。
不管是人事檔案,學生檔案,還是黨員檔案,在檔案袋上都會貼有密封條,并且蓋有部門的紅章,這個密封條就是證明檔案內容完整性的保證。Flash 中的固件,就相當于檔案袋里面的內容,信息塊就相當于檔案袋上的封條,版本號相當于封條上的日期,校驗值相當于封條上的紅章,擦除信息塊的過程,相當于給 Flash 進行撕封條的操作,而寫入信息塊的過程,就相當于給 Flash進行貼封條的過程,通過這個封條,就能夠證明 Flash 中的內容是完整的。
有了“封條”證明固件的完整性,還需要確定什么時候才能拆“封條”:
拆封條的原則就是:保證兩個區域至少有一個固件是完整的。因此,在擦除其中一個區域的信息塊時,需要查看另一個區域的信息塊是否完整,只有另一個區域的信息塊是完整的,才能夠擦除本區域信息塊的內容。
在固件下載的過程中,如果發現執行區域的信息塊不完整,那就暫時還不能擦除本區域的信息塊,需先執行固件更新過程,將備份區域的固件寫入到執行區域,在寫入執行區域的信息塊后,才能繼續擦除備份區域的信息塊。一般來說,執行區域的信息塊如果不完整,則說明該設備在上次固件更新過程中,意外掉電,固件更新失敗。
在固件更新的過程中,如果備份區域的信息塊不完整,則說明固件還沒有下載成功,自然是不能繼續進行固件更新的,就得跳過固件更新的過程。如果備份區域的固件版本小于(一般不會小于)或等于執行區域的固件版本,則說明備份區域的固件和執行區域的固件一樣,沒有必要固件更新,也要跳過固件更新的過程。只有備份區域的信息塊完整,且固件版本大于執行區域時,或者執行區域沒有完整的信息塊時,才可以擦除執行區域的信息塊,對執行區域的內容進行寫操作。
有一種情況,執行區域和備份區域是都沒有完整的固件的,那就是產品硬件生產完成后,還沒有燒錄程序的時候。
當產品硬件生產完成后,微控制器內部只有一個 2nd Bootloader,進入到固件下載的過程時發現,執行區域沒有完整的信息塊,再跳轉到執行固件更新過程,但固件更新過程發現備份區域也沒有完整的信息塊,2nd Bootloader 傻眼了,咋哪都沒有完整固件呢?
因此,在固件下載過程中,若發現執行區域和備份區域都沒有完整信息塊時,還是得允許向備份區域寫固件。
當意外出現在任何沒有操作 Flash 的時候,再次上電后,不影響應用程序的正常執行,不影響固件更新,也不影響固件下載的過程;當意外出現在對備份區域的 Flash 操作時,執行區域的固件還能夠正常執行,也不影響重新執行固件下載的過程。當意外出現在對執行區域的 Flash 操作時,再次上電后,重新進行固件更新,應用程序還是能夠正常運行。所以,這個完整的 OTA 過程,處處安全。
?測試
根據本文講述的過程,實現帶 OTA 功能的 2nd Bootloader,進行驗證。
下載新的固件前效果,如圖9所示:
圖9 下載新固件前的應用程序
下載固件過程中中斷下載,通過觀察應用程序打印的時間可知,微控制器會繼續執行更新固件前的應用程序,如圖10所示:
圖10 Ymodem 升級失敗后的應用程序
當固件下載成功后,在進入應用程序前,立刻按下復位按鍵,產生一次固件更新失敗的事件,隨后釋放復位按鍵,觀察通過應用程序打印的時間可以發現,新的固件在再次復位之后,依然進行了更新,如圖11所示:
圖11 固件更新失敗后,再次復位程序
?結語
本文主要針對 OTA 升級的流程進行了講解,把 OTA 升級的過程拆分為固件下載和固件更新兩個過程,每個過程都想辦法保證設備復位后,執行區域總有可用固件,保障 OTA 過程中如果發生意外,不至于讓設備變 “磚”。
OTA 升級的方法不僅僅只有串口一種,我們還可以使用 I2C 接口,SPI 接口升級固件,如果支持 USB Device,那么 微控制器微控制器可以模擬成為一個 U 盤,插在電腦上,將二進制文件放到這個 U 盤中更新固件,如果支持 USB Host,則可以將固件放到 U 盤中,微控制器讀取 U 盤中的數據更新固件,或者將 U 盤換成 SD 卡…… 實現 OTA 功能的方法極多。
當 OTA 的方法越來越多時,2nd Bootloader 也隨之變得臃腫起來。其實,我們也可以把 OTA 的大部分內容做到應用程序中,僅將備份區域的應用程序轉移到執行區域這個核心功能保留到 2nd Bootloader 中,并且提供對備份區域 Flash 擦除和寫操作的 API 即可,應用程序中的 OTA 功能,將會把下載到的新固件通過 2nd Bootloader 提供的 API 寫入到備份區域,隨后復位 MCU,讓 2nd Bootloader 將新固件再轉移到執行區域即可。
為了減少下載新固件所需的流量,其固件包可能進行了壓縮處理,而解壓過程可以放在上位機中,讓上位機發送給微控制器的固件就是經過解壓后的固件包;或者可以放在應用程序中,在應用程序中進行解壓后寫入到 Flash 中,或者放在 2nd Bootloader 中,從備份區域放到執行區域時再進行解壓;第三種方法雖然可以減少備份區域占用的空間,但需要將壓縮算法確定好,永久不會再進行改動——2nd Bootloader 雖然靈活,但就像微控制器廠商出廠微控制器前,將 1st Bootloader 固化到微控制器中那樣,2nd Bootloader 只能在產品廠商將產品出廠前寫入到微控制器中,產品一旦售出,就不像應用程序可以通過 OTA 升級了,除非進行產品召回,否則就沒有修改的可能,因此,放在 2nd Bootloader 中的代碼,一定要謹慎對待。
審核編輯:劉清
評論
查看更多