IAP升级
相關(guān)資料:https://blog.csdn.net/elikang/article/details/86082960
IAP升級(jí)的原理這里就不介紹了。
1. 修改代碼實(shí)現(xiàn)IAP+Ymodem
基于stm32官方提供的demo工程 STM32F10x_AN2557_FW_V3.3.0
提取出IAP和Ymodem文件,并修改Ymodem代碼,從標(biāo)準(zhǔn)庫到HAL庫。
1.1 首先,從demo中找到執(zhí)行框架,并將其封裝在新建的文件IAP.c中。
#include "main.h" #include "Define.h"/* Flash user program offset */uint32_t BlockNbr = 0; uint32_t UserMemoryMask = 0; //掩碼,用于檢測FLASH是否有寫保護(hù) __IO uint32_t FlashProtection = 0; //讀寫+不被編譯器優(yōu)化pFunction Jump_To_Application; uint32_t JumpAddress;extern uint8_t file_name[FILE_NAME_LENGTH]; extern uint32_t FlashDestination;extern int32_t Ymodem_Receive (uint8_t *); extern uint8_t Ymodem_Transmit (uint8_t *,const uint8_t* , uint32_t ); extern void Int2Str(uint8_t* str, int32_t intnum);uint8_t tab_1024[1024] ={0};/*** @brief Download a file via serial port* @param None* @retval None*/ void SerialDownload(void) {uint8_t Number[10] = " ";int32_t Size = 0;printf("Waiting for the file to be sent ... (press 'a' to abort)\n\r");Size = Ymodem_Receive(&tab_1024[0]);if (Size > 0){printf("\n\n\r Programming Completed Successfully!\n\r--------------------------------\r\n Name: %s",file_name);Int2Str(Number, Size);printf("\n\r Size: %s Bytes\r\n",Number);printf("-------------------\n");}else if (Size == -1){printf("\n\n\rThe image size is higher than the allowed space memory!\n\r");}else if (Size == -2){printf("\n\n\rVerification failed!\n\r");}else if (Size == -3) //收到取消{printf("\r\n\nAborted by user.\n\r");}else{printf("\n\rFailed to receive the file!\n\r");} }/*** @brief Display the Main Menu on to HyperTerminal在超級(jí)終端上顯示主菜單* @param None* @retval None*/ void Main_Menu(void) {uint8_t key = 0;/* Get the number of block (4 or 2 pages) from where the user program will be loaded 獲取塊(4或2頁)的數(shù)目 ,用戶程序?qū)闹屑虞d的(0x8003000-0x8000000)>>12 = 3*/BlockNbr = (FlashDestination - 0x08000000) >> 12;//8/* Compute the mask to test if the Flash memory, where the user program will beloaded, is write protected 計(jì)算掩碼以測試加載用戶程序的閃存是否有寫保護(hù)*/ #if defined (STM32F10X_MD) || defined (STM32F10X_MD_VL)UserMemoryMask = ((uint32_t)~((1 << BlockNbr) - 1)); #else /* USE_STM3210E_EVAL */if (BlockNbr < 62){UserMemoryMask = ((uint32_t)~((1 << BlockNbr) - 1));}else{UserMemoryMask = ((uint32_t)0x80000000);} #endif /* (STM32F10X_MD) || (STM32F10X_MD_VL) *//* Test if any page of Flash memory where program user will be loaded is write protected 測試將加載程序用戶的閃存頁是否有寫保護(hù)*/if (((uint32_t)(READ_REG(FLASH->WRPR)) & UserMemoryMask) != UserMemoryMask){FlashProtection = 1;}else{FlashProtection = 0;}printf("\r\n================== Main Menu ============================\r\n\n");printf(" Download Image To the STM32F10x Internal Flash ------- 1\r\n\n");printf(" Upload Image From the STM32F10x Internal Flash ------- 2\r\n\n");printf(" Execute The New Program ------------------------------ 3\r\n\n");if(FlashProtection != 0){printf(" Disable the write protection ------------------------- 4\r\n\n");}printf("==========================================================\r\n\n");while (1){key = getchar();//功能選項(xiàng)if (key == 0x31){/* Download user application in the Flash */printf("--> Download user application in the Flash\n\r");SerialDownload();}else if (key == 0x32){/* Upload user application from the Flash *///SerialUpload();printf("上傳\n\r");}else if (key == 0x33){printf("跳轉(zhuǎn)\n\r");JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4);/* Jump to user application */Jump_To_Application = (pFunction) JumpAddress;/* Initialize user application's Stack Pointer */__set_MSP(*(__IO uint32_t*) ApplicationAddress);Jump_To_Application();}else if ((key == 0x34) && (FlashProtection == 1)){/* Disable the write protection of desired pages */HAL_FLASH_Unlock();printf("解鎖FLASH\n\r");}else{if (FlashProtection == 0){printf("Invalid Number ! ==> The number should be either 1, 2 or 3\r");}else{printf("Invalid Number ! ==> The number should be either 1, 2, 3 or 4\r");} }} }1.2 其次,提取出Ymodem.c文件,并對其中的一些函數(shù)進(jìn)行修改。
下面是Ymodem.c文件修改前后的對比。最開始是要修改包含的頭文件。main.h文件中包括HAL的Flash函數(shù)。Define.h文件中則是定義了Flash操作相關(guān)的宏定義常量。
下面一段是自己加的注釋,實(shí)則并沒有改變代碼語句。在使用串口終端和設(shè)備進(jìn)行交互時(shí),用戶鍵盤輸入的命令字等會(huì)在這段代碼處被識(shí)別。
下面是傳輸過程中,將數(shù)據(jù)包寫入到Flash的操作。這里將標(biāo)準(zhǔn)庫的函數(shù)用HAL庫函數(shù)來替代。修改前最好理解一下這里的前后文。
下面是注釋信息,Ymodem協(xié)議,等待過程中,一直打印‘C’。
1.3 最后,添加一個(gè)宏定義頭文件,用于放置地址信息等定義。
應(yīng)用程序的起始地址和boot代碼的設(shè)定大小有關(guān)。這里給boot代碼劃分32K的代碼空間。
#define ApplicationAddress 0x8008000 //boot 32K #define FLASH_IMAGE_SIZE (uint32_t) (FLASH_SIZE - (ApplicationAddress - 0x08000000))//這里實(shí)際上是RCT6 256KB的flash#define PAGE_SIZE (0x800) /* 2 Kbytes */#define FLASH_SIZE (0x40000) /* 256K Byte *//* Exported macro ------------------------------------------------------------*/ /* Common routines */ #define IS_AF(c) ((c >= 'A') && (c <= 'F')) #define IS_af(c) ((c >= 'a') && (c <= 'f')) #define IS_09(c) ((c >= '0') && (c <= '9')) #define ISVALIDHEX(c) IS_AF(c) || IS_af(c) || IS_09(c) #define ISVALIDDEC(c) IS_09(c) #define CONVERTDEC(c) (c - '0')#define CONVERTHEX_alpha(c) (IS_AF(c) ? (c - 'A'+10) : (c - 'a'+10)) #define CONVERTHEX(c) (IS_09(c) ? (c - '0') : CONVERTHEX_alpha(c))#define SerialPutString(x) Serial_PutString((uint8_t*)(x))#define FILE_NAME_LENGTH (256) #define FILE_SIZE_LENGTH (16)typedef void (*pFunction)(void);1.4 在將上述三個(gè)文件準(zhǔn)備好之后,就是如何使用。下面是boot工程的main函數(shù)片段。
(1)初始化外設(shè)。
(2)打印boot信息
(3)判斷是否需要進(jìn)入boot模式,(按鍵被按下,則進(jìn)入boot,未被按下,則直接跳轉(zhuǎn)到app)
(4)如果按鍵被按下,則進(jìn)入IAP升級(jí)框架。(Main_Menu函數(shù))
2. 代碼框架分析
2.1 IAP框架
略(稍后補(bǔ)充)。
2.2 Ymodem協(xié)議介紹
略(稍后補(bǔ)充)。
3. 關(guān)于使用。
3.1 Bootloader
boot工程配置如下圖所示。
另外,keil編譯生成的是hex文件,需要添加指令才可以生成bin文件。如下圖所示。編譯完成后會(huì)生成Boot.bin文件。
上面用到的Hexbin.bat是一個(gè)腳本文件,內(nèi)容如下。因?yàn)轫?xiàng)目需求,有兩個(gè)版本的代碼同時(shí)存在。該腳本會(huì)判斷兩個(gè)版本代碼的生成目錄是否存在。如果不存在,則創(chuàng)建HexBinE1和HexBinE2文件夾。
通過fromelf.exe工具將hex文件轉(zhuǎn)成bin文件,再移動(dòng)到創(chuàng)建的文件夾中。
用戶可根據(jù)自己的需求修改該腳本。
3.2 Application
app工程配置如下圖所示。重要注意點(diǎn)是,工程配置的地址以及中斷向量表的地址。這里的配置相當(dāng)于讓出前面32K的空間,給boot使用。
同樣關(guān)于如何生成bin文件,也需要進(jìn)行如下圖所示的操作。以E2版本為例。
這里的HexBin.bat腳本內(nèi)容如下。判斷文件夾是否存在,生成bin文件,移動(dòng)到文件夾中。
這里的BuildAction.exe是使用Qt編寫的合成工具,用于將Boot.bin和APP_E2.bin合成為一個(gè)bin文件。
其中的配置文件ini內(nèi)容如下。用戶可根據(jù)自己的需求更改。
還有一個(gè)注意點(diǎn)是BuildAction.exe工具需要一個(gè)頭文件sys_cfg.h,用以定義版本號(hào)。內(nèi)容如下。
#define DEBUG_ENABLE 0 // 調(diào)試使能(停用:0 /啟用:1) // 應(yīng)用層軟件版本號(hào),4個(gè)ASCII字符,臨時(shí)版本0.XX,正式版本E.XX 格式:45 2E 30 31 #define APPVIRSION_BYTE0 0x32 #define APPVIRSION_BYTE1 0x2E #define APPVIRSION_BYTE2 0x30 #define APPVIRSION_BYTE3 0x37總結(jié)
- 上一篇: 常见协议RFC对应表
- 下一篇: PQ8.05硬盘分区图文教程