1,固件升級方案綜述
單片機的固件升級方式有很多種。1、ICP:簡單說就是在單片機開發(fā)時使用燒錄器升級程序,比如使用J-Link燒錄單片機程序。2、ISP:在單片機內部實現(xiàn)了基于通信接口(如串口、I2C、SPI等等)的FLASH引導程序,配合廠家提供的燒錄軟件工具或自行開發(fā)的軟件實現(xiàn)程序燒錄。3、IAP:是指單片機程序開發(fā)好之后在運行過程中由外部用戶發(fā)起的在線升級,這種升級方式一般由用戶自行設計升級方案,方案靈活性和自由度較高,在智能家居、汽車電子、物聯(lián)網設備中常用的OTA即空中下載技術原理也與之類似。
2,劃分FALSH存儲區(qū)域
在STM32系列單片機中,程序存儲在內部FLASH中,按照不同的單片機型號FLASH大小有所不同,有64KB、128KB、512KB等等。以STM32F407VET6系列單片機為例,內置FLASH大小為512KB,存儲地址為0x08000000-0x0807FFFF。單片機每次程序復位時從0x08000000的位置開始執(zhí)行主程序,如果不做IAP則這512KB空間都可以用來存儲用戶編寫的APP程序。
若要實現(xiàn)IAP功能則必須將FLASH空間劃分為幾個部分,每部分都存儲一個可以獨立運行的程序文件(可以理解為幾個獨立的單片機工程):
1、引導程序,每次復位時程序默認執(zhí)行此程序,在接下來的執(zhí)行過程中可以跳轉到用戶編寫的程序,因此這部分程序是固化在以0x08000000為起始的區(qū)域中。在引導程序中可以對電路系統(tǒng)作出一些自檢和初始化檢查的工作,因此該程序又稱為bootloader或boot程序,需要注意的是在設計bootloader時要提前規(guī)定好程序空間的大小,比如規(guī)定程序存儲區(qū)域為0x08000000-0x8007FFF,則bootlader程序存儲空間為32KB,編寫boot程序時要注意這一點
2、用戶需要升級的新程序,這部分包含了用戶的業(yè)務代碼,復雜的運算邏輯和算法實現(xiàn)均在這一部分完成,稱為APP程序,該部分程序一般存儲在bootloader區(qū)域之后的FLASH中。用一個不是特別恰當?shù)睦宇惐萣ootloader和APP:bootloader相當于電腦組裝時的BIOS,APP則相當于操作系統(tǒng),電腦開機時首先運行BIOS,完成后跳轉運行到操作系統(tǒng)。
3、升級之前的老版APP備份。這部分相當于電腦系統(tǒng)更新前對老系統(tǒng)的備份,一旦在升級過程中發(fā)生錯誤需要還原到備份系統(tǒng),防止系統(tǒng)升級失敗成磚。同樣的APP與APP備份將剩余的FLASH平分,以上述booloader為例,APP程序及其備份所占區(qū)域為:(512-32)/2=240KB,因此編寫的APP程序編譯后的占用的FLASH空間不得超過240KB,這一點可以通過查驗.map文件確認,對于不同F(xiàn)LASH大小的芯片可以類比以上計算方法確認自己的程序大小上限(在此插入一句,改變編譯器的優(yōu)化等級可以改變最后的程序大小,但是高的優(yōu)化等級對程序編寫規(guī)范要求更高,因此優(yōu)化等級應該在一開始設計APP之前就確定好,中途變更會帶來不可預測的問題)。
以STM32F407VET6單片機為例劃分后的FALSH存儲框圖如下所示:
3,BOOTLADER設計
根據(jù)上面的描述,bootloader主要有完成以下功能:
1、系統(tǒng)自檢
2、實現(xiàn)APP程序跳轉
3、升級過程中接收APP文件并存儲到對應的FLASH區(qū)域
功能1、3對于不同的系統(tǒng)要求不同,自檢的內容以及實現(xiàn)文件傳輸?shù)奈锢韺?a target="_blank">接口和鏈路協(xié)議不同,不在此過多描述。下面主要給出APP跳轉的部分代碼:
#define APP_ADDR 0x08008000 //應用程序起始地址 typedef void (*pFunction)(void); //重定義pFunction為void(*)(void)函數(shù)指針類型void jump(void){ uint32_t APP_ADDR_Buff=0; //緩存APP地址數(shù)值 uint32_t APP_ADDR_Value=0; //APP地址的內容 uint32_t Jump_ADDR; //跳轉的目標地址 pFunction Jump_APP; //跳轉的目標函數(shù)指針 APP_ADDR_Buff = APPLICATION_ADDRESS; //用戶程序的首地址 APP_ADDR_Value = (*(volatile uint32_t*)APP_ADDR_Buff);//取出首地址里面的值 if (( APP_ADDR_Value & 0x2FFE0000 ) == 0x20000000) //判斷APP首地址里面存的棧頂?shù)刂分凳欠窈戏?{ DISABLE_INTERRUPTS(); //關總中斷,使用不同的庫寫法不同,不可直接復制 RCC_DeInit();//將外設RCC寄存器重設為缺省值,使用不同的庫寫法不同,不可直接復制 Jump_ADDR = *(volatile uint32_t*)(APP_ADDR_Buff + 4);//APP起始地址第二個字為程序開始地址(新程序復位地址) //指針函數(shù)指向用戶程序地址,也就是PC指針goto到用戶程序起始地址 Jump_APP = (pFunction)Jump_ADDR; //取出程序地址給指針函數(shù) __set_MSP(*(volatile uint32_t*)APP_ADDR_Buff); //初始化APP的堆棧指針 Jump_APP(); //執(zhí)行指針函數(shù),實現(xiàn)程序跳轉 } else { ErrorHandle(); //拋出異常 }}int main(void){
SystemInit();//系統(tǒng)時鐘初始化 SYSInit(); //系統(tǒng)初始化 delay_ms(200); if(ReadProgramAPPFlag()) //如果需要更新APP { APP_FlashWrite(); //接收APP文件數(shù)據(jù),并將APP程序存儲到指定位置 if(APP_Check()) //APP文件校驗通過,將新的APP程序更新到備份區(qū)域 APP_Backup(); else //否則恢復備份區(qū) APP_Restore(); ResetProgramAPPFlag(); //對完成升級的標志復位 } jump(); //正常情況下運行到這一步時APP區(qū)域已經正確寫入程序文件 while(1); }
其中ReadProgramDoneFlag()是判斷程序應該是先接收升級文件再跳轉還是直接跳轉的標志,在APP中如果有升級需求則對這個標志置位,在bootloader中完成文件接收之后對標志復位,需要注意的是這個標志位不是全局變量也不是局部變量,要保證程序跳轉,初始化堆棧之后這個標志的值不受影響,因此該標志變量最佳選擇是寫在外部EEPROM或內置FLASH中,讀寫標志的操作其實是對EEPROM或FLASH的讀寫。
4,編寫APP程序
APP程序中實現(xiàn)了用戶的業(yè)務代碼,和由APP跳轉回bootloader的邏輯,實際的操作還是對上文中程序存儲Flag的讀寫,這部分邏輯實現(xiàn)的流程圖如下圖所示:
由于APP程序對應的是另外一個工程文件,因此在工程設置中要將FLASH的偏移地址向下移動,空出bootlader的區(qū)域,比如上文中bootloader區(qū)域是0x08000000-0x08008000,因此APP工程的FLASH起始地址是0x8008000,偏移量是0x8000,這一點非常重要。
-
單片機
+關注
關注
6067文章
44992瀏覽量
650616 -
STM32
+關注
關注
2293文章
11032瀏覽量
365081 -
IAP
+關注
關注
2文章
165瀏覽量
25054
發(fā)布評論請先 登錄
使用STM32單片機實現(xiàn)IAP的詳細資料說明

如何使用CPUID和AES算法實現(xiàn)STM32單片機的固件升級

8051系列單片機固件升級iap

關于STM32單片機的IAP實現(xiàn)

STM32 IAP升級固件與上位機例程

評論