电子产品如何使用IAP方式升级程序
目錄
1、ICP、ISP和IAP的概念
2、IAP升級(jí)程序的原理
3、IAP升級(jí)程序的流程
4、IAR環(huán)境下IAP的實(shí)現(xiàn)
4.1、BootLoader程序設(shè)計(jì)
4.2、User Application程序設(shè)計(jì)
4.3、IAR地址配置及文件輸出
5、拓展:解析HEX文件
1、ICP、ISP和IAP的概念
在項(xiàng)目開(kāi)發(fā)過(guò)程中通常使用SWD、JTAG等工具進(jìn)行程序燒錄和仿真,若產(chǎn)品節(jié)點(diǎn)較少還是比較方便,但是當(dāng)設(shè)備節(jié)點(diǎn)量產(chǎn)時(shí),就需要使用IAP的方式進(jìn)行程序燒錄。
簡(jiǎn)單說(shuō)明幾個(gè)概念I(lǐng)CP、ISP和IAP。
ICP In-circuit programmer
ICP:在電路編程,MCU內(nèi)部不需要有程序,上電就能夠?qū)Τ绦虼鎯?chǔ)區(qū)域進(jìn)行編程,例如平時(shí)使用JTAG、SWD等方式。
ISP?In-system?programer
ISP:在系統(tǒng)編程,通過(guò)MCU專(zhuān)用的串行編程接口進(jìn)行編程,MCU需要具有運(yùn)行的外部條件,例如有晶振等。
例如STM32通過(guò)設(shè)置BOOT引腳設(shè)置對(duì)應(yīng)啟動(dòng)模式,然后通過(guò)串口等對(duì)內(nèi)部Flash進(jìn)行升級(jí),可以說(shuō)這種方式就是廠(chǎng)家在芯片內(nèi)部固化了一個(gè)BootLoader程序。
IAP In-application?programer?
IAP:在應(yīng)用編程,開(kāi)發(fā)者設(shè)計(jì)BootLoader程序,通過(guò)串口、CAN、以太網(wǎng)等通信方式實(shí)現(xiàn)程序升級(jí)。
2、IAP升級(jí)程序的原理
通常一塊MCU芯片的Code(代碼)區(qū)內(nèi)只有一個(gè)用戶(hù)程序,而IAP方案則是將代碼區(qū)劃分為兩部分,兩部分區(qū)域各存放一個(gè)程序,一個(gè)為BootLoader(引導(dǎo)加載程序),另一個(gè)為User Application(用戶(hù)應(yīng)用程序)。
BootLoader在出廠(chǎng)時(shí)就固定下來(lái)了,在需要變更User Application時(shí)只需要通過(guò)觸發(fā)BootLoader對(duì)User Application的擦除和重新寫(xiě)入即可完成用戶(hù)應(yīng)用的更換。
程序執(zhí)行初始化后首先會(huì)進(jìn)入BootLoader,在BootLoader里面檢測(cè)條件是否被觸發(fā)(可通過(guò)按鍵是否被按下、串口是否接收到特定的數(shù)據(jù)、U盤(pán)是否插入等),如果有則進(jìn)行對(duì)User Application進(jìn)行擦除和重新寫(xiě)入操作新程序,如果沒(méi)有則直接跳轉(zhuǎn)到BootLoader執(zhí)行User Application。
3、IAP升級(jí)程序的流程
假設(shè)設(shè)備僅有User Application,以STM32F103ZET6為例,其啟動(dòng)方式有三種:內(nèi)置FLASH啟動(dòng)、內(nèi)置SRAM啟動(dòng)、系統(tǒng)存儲(chǔ)器ROM啟動(dòng)。通過(guò)BOOT0和BOOT1引腳的設(shè)置可以選擇從哪中方式啟動(dòng),這里選擇內(nèi)置的FLASH啟動(dòng),STM32F103ZET6?FLASH的地址為0x08000000—0x0807FFFF,共512KB。
通常STM32發(fā)生中斷的過(guò)程為以下五步:
1、發(fā)生中斷(中斷請(qǐng)求);
2、到中斷向量表查找中斷函數(shù)入口地址;
3、跳轉(zhuǎn)到中斷函數(shù);
4、執(zhí)行中斷函數(shù);
5、中斷返回。
也就是說(shuō),STM32的內(nèi)置的Flash中有一個(gè)中斷向量表來(lái)存放各個(gè)中斷服務(wù)函數(shù)的入口地址,內(nèi)置Flash的分配情況如下圖所示:
所以當(dāng)只有一個(gè)程序的情況下(僅有User Applicatio時(shí)),程序執(zhí)行的走向如下所示:
解析上圖:
STM32F103ZET6有一個(gè)中斷向量表,這個(gè)中斷向量表存放在代碼開(kāi)始部分的后4個(gè)字節(jié)處(即0x08000004),代碼開(kāi)始的4個(gè)字節(jié)存放的是堆棧棧頂?shù)牡刂?#xff0c;當(dāng)發(fā)生中斷后程序通過(guò)查找該表得到相應(yīng)的中斷服務(wù)程序入口地址,然后再跳到相應(yīng)的中斷服務(wù)程序中執(zhí)行。
設(shè)備上電后從0x08000004處取出復(fù)位中斷向量的地址,然后跳轉(zhuǎn)到復(fù)位中斷程序的入口(標(biāo)號(hào)①所示),執(zhí)行結(jié)束后跳轉(zhuǎn)到main函數(shù)中(標(biāo)號(hào)②所示)。在執(zhí)行main函數(shù)的過(guò)程中發(fā)生中斷,則STM32強(qiáng)制將PC指針指回中斷向量表處(標(biāo)號(hào)③所示),從中斷向量表中找到相應(yīng)的中斷函數(shù)入口地址,跳轉(zhuǎn)到相應(yīng)的中斷服務(wù)函數(shù)(標(biāo)號(hào)④所示),執(zhí)行完中斷函數(shù)后再返回到main函數(shù)中來(lái)(標(biāo)號(hào)⑤所示)。
下面要講正題了。
若將STM32F103ZET6在內(nèi)置的Flash里面添加User Application和BootLoader程序,則Flash分配情況大致如下圖所示:
此時(shí),User Application和BootLoader程序各有一個(gè)中斷向量表,假設(shè)BootLoader程序占用的空間為N+M字節(jié),則程序的走向應(yīng)該如下圖所示:
解析上圖:
設(shè)備上電初始程序依然從0x08000004處取出復(fù)位中斷向量地址,執(zhí)行復(fù)位中斷函數(shù)后跳轉(zhuǎn)到IAP的main(標(biāo)號(hào)①所示),在IAP的main函數(shù)執(zhí)行完成后(在BootLoader里面檢測(cè)條件是否被觸發(fā)(可通過(guò)按鍵是否被按下、串口是否接收到特定的數(shù)據(jù)、U盤(pán)是否插入等),如果有則進(jìn)行對(duì)User Application進(jìn)行擦除和重新寫(xiě)入操作新程序,如果沒(méi)有則直接跳轉(zhuǎn)到BootLoader執(zhí)行User Application)強(qiáng)制跳轉(zhuǎn)到0x08000004+N+M處(標(biāo)號(hào)②所示),最后跳轉(zhuǎn)到新的main函數(shù)中來(lái)(標(biāo)號(hào)③所示),當(dāng)發(fā)生中斷請(qǐng)求后,程序跳轉(zhuǎn)到新的中斷向量表中取出新的中斷函數(shù)入口地址,再跳轉(zhuǎn)到新的中斷服務(wù)函數(shù)中執(zhí)行(標(biāo)號(hào)④⑤所示),執(zhí)行完中斷函數(shù)后再返回到main函數(shù)中來(lái)(標(biāo)號(hào)⑥所示)。
4、IAR環(huán)境下IAP的實(shí)現(xiàn)
以IAR環(huán)境為例,簡(jiǎn)單講述IAP的實(shí)現(xiàn)步驟。這里MCU以華大HC32L130為例,因?yàn)槭褂玫腗CU不同,所以實(shí)現(xiàn)的細(xì)節(jié)也不一致,但是基本上官方都會(huì)提供Demo例程。
本示例Flash分配情況為:BootLoader地址:0x00000000~0x00000DFF,User Application地址:0x00001000~0x0000FFFF。
4.1、BootLoader程序設(shè)計(jì)
第1步:設(shè)計(jì)總體架構(gòu),包含三個(gè)功能函數(shù):檢測(cè)BootLoader標(biāo)志程序、IAP配置程序和IAP燒錄功能程序。
/*********************************************************************************** \brief IAP 主函數(shù)**** \param None**** \retval int32_t Return value, if needed********************************************************************************/
int32_t main(void)
{IAP_UpdateCheck();IAP_Init();IAP_Main();
}
第2步:檢查BootPara標(biāo)記區(qū)數(shù)據(jù)值,判斷是否需要升級(jí)APP程序,若需要升級(jí)則才會(huì)執(zhí)行IAP_Init()和IAP_Main()函數(shù),否則會(huì)直接跳轉(zhuǎn)到User Application程序。
/*********************************************************************************** \brief 檢查BootPara標(biāo)記區(qū)數(shù)據(jù)值,判斷是否需要升級(jí)APP程序.**** \param None**** \retval None********************************************************************************/
void IAP_UpdateCheck(void)
{uint32_t u32AppFlag;u32AppFlag = *(__IO uint32_t *)BOOT_PARA_ADDRESS; //讀出BootLoader para區(qū)標(biāo)記值if (APP_FLAG != u32AppFlag) //如果標(biāo)記值不等于A(yíng)PP_FLAG,表示不需要升級(jí)APP程序{IAP_JumpToApp(APP_ADDRESS); //則直接跳轉(zhuǎn)至APP}
}
第3步:IAP_Init()函數(shù)的實(shí)現(xiàn),主要包括外圍模塊初始化和IAP通信協(xié)議標(biāo)志初始化。
/*********************************************************************************** \brief IAP 初始化**** \param [in] None**** \retval None********************************************************************************/
void IAP_Init(void)
{PreiModule_Init();Modem_RamInit();
}/*********************************************************************************** \brief CPU外圍模塊初始化**** \param [in] None**** \retval None********************************************************************************/
void PreiModule_Init(void)
{HC32_SetSystemClockToRCH22_12MHz();HC32_InitUart();HC32_InitCRC();HC32_InitTIM();HC32_InitFlash(FLASH_CONFIG_FREQ_22_12MHZ);
}/*********************************************************************************** \brief modem文件中相關(guān)變量參數(shù)初始化**** \param [out] None** \param [in] None**** \retval None********************************************************************************/
void Modem_RamInit(void)
{ uint32_t i;enFrameRecvStatus = FRAME_RECV_IDLE_STATUS; //幀狀態(tài)初始化為空閑狀態(tài)for (i=0; i<FRAME_MAX_SIZE; i++){u8FrameData[i] = 0; //幀數(shù)據(jù)緩存初始化為零}u32FrameDataIndex = 0; //幀緩存數(shù)組索引值初始化為零
}
第4步:IAP_Main()函數(shù)的實(shí)現(xiàn),主要包含對(duì)User Application程序更新處理。
/*********************************************************************************** \brief IAP APP程序升級(jí)主函數(shù).**** \param None**** \retval None********************************************************************************/
void IAP_Main(void)
{en_result_t enRet;while (1){enRet = Modem_Process(); //APP程序更新處理if (Ok == enRet){IAP_ResetConfig(); //復(fù)位所有外設(shè)模塊if (Error == IAP_JumpToApp(APP_ADDRESS)) //如果跳轉(zhuǎn)失敗{while(1);}}}
}/*********************************************************************************** \brief 上位機(jī)數(shù)據(jù)幀解析及處理**** \param [in] None **** \retval Ok APP程序升級(jí)完成,并接受到跳轉(zhuǎn)至APP命令** \retval OperationInProgress 數(shù)據(jù)處理中** \retval Error 通訊錯(cuò)誤********************************************************************************/
en_result_t Modem_Process(void)
{uint8_t u8Cmd, u8FlashAddrValid, u8Cnt, u8Ret;uint16_t u16DataLength, u16PageNum, u16Ret;uint32_t u32FlashAddr, u32FlashLength, u32Temp;if (enFrameRecvStatus == FRAME_RECV_PROC_STATUS) //有數(shù)據(jù)幀待處理, enFrameRecvStatus值在串口中斷中調(diào)整{u8Cmd = u8FrameData[PACKET_CMD_INDEX]; //獲取幀指令碼if (PACKET_CMD_TYPE_DATA == u8FrameData[PACKET_TYPE_INDEX]) //如果是數(shù)據(jù)指令{u8FlashAddrValid = 0u;u32FlashAddr = u8FrameData[PACKET_ADDRESS_INDEX] + //讀取地址值(u8FrameData[PACKET_ADDRESS_INDEX + 1] << 8) +(u8FrameData[PACKET_ADDRESS_INDEX + 2] << 16) +(u8FrameData[PACKET_ADDRESS_INDEX + 3] << 24);if ((u32FlashAddr >= (FLASH_BASE + BOOT_SIZE)) && (u32FlashAddr < (FLASH_BASE + FLASH_SIZE))) //如果地址值在有效范圍內(nèi){u8FlashAddrValid = 1u; //標(biāo)記地址有效}}switch (u8Cmd) //根據(jù)指令碼跳轉(zhuǎn)執(zhí)行{case PACKET_CMD_HANDSHAKE : //握手幀 指令碼u8FrameData[PACKET_RESULT_INDEX] = PACKET_ACK_OK; //返回狀態(tài)為:正確Modem_SendFrame(&u8FrameData[0], PACKET_INSTRUCT_SEGMENT_SIZE); //發(fā)送應(yīng)答幀給上位機(jī)break;case PACKET_CMD_ERASE_FLASH : //擦除flash 指令碼if ((u32FlashAddr % FLASH_SECTOR_SIZE) != 0) //如果擦除地址不是頁(yè)首地址{u8FlashAddrValid = 0u; //標(biāo)記地址無(wú)效}if (1u == u8FlashAddrValid) //如果地址有效{u32Temp = u8FrameData[PACKET_DATA_INDEX] + //獲取待擦除flash尺寸(u8FrameData[PACKET_DATA_INDEX + 1] << 8) +(u8FrameData[PACKET_DATA_INDEX + 2] << 16) +(u8FrameData[PACKET_DATA_INDEX + 3] << 24);u16PageNum = FLASH_PageNumber(u32Temp); //計(jì)算需擦除多少頁(yè)for (u8Cnt=0; u8Cnt<u16PageNum; u8Cnt++) //根據(jù)需要擦除指定數(shù)量的扇區(qū){u8Ret = Flash_EraseSector(u32FlashAddr + (u8Cnt * FLASH_SECTOR_SIZE));if (Ok != u8Ret) //如果擦除失敗,反饋上位機(jī)錯(cuò)誤代碼{u8FrameData[PACKET_RESULT_INDEX] = PACKET_ACK_ERROR;break;}}if (Ok == u8Ret) //如果全部擦除成功,反饋上位機(jī)成功{u8FrameData[PACKET_RESULT_INDEX] = PACKET_ACK_OK;}else //如果擦除失敗,反饋上位機(jī)錯(cuò)誤超時(shí)標(biāo)志{u8FrameData[PACKET_RESULT_INDEX] = PACKET_ACK_TIMEOUT;}}else //地址無(wú)效,反饋上位機(jī)地址錯(cuò)誤{u8FrameData[PACKET_RESULT_INDEX] = PACKET_ACK_ADDR_ERROR;}Modem_SendFrame(&u8FrameData[0], PACKET_INSTRUCT_SEGMENT_SIZE); //發(fā)送應(yīng)答幀到上位機(jī)break;case PACKET_CMD_APP_DOWNLOAD : //數(shù)據(jù)下載 指令碼if (1u == u8FlashAddrValid) //如果地址有效{u16DataLength = u8FrameData[FRAME_LENGTH_INDEX] + (u8FrameData[FRAME_LENGTH_INDEX + 1] << 8)- PACKET_INSTRUCT_SEGMENT_SIZE; //獲取數(shù)據(jù)包中的數(shù)據(jù)長(zhǎng)度(不包含指令碼指令類(lèi)型等等)if (u16DataLength > PACKET_DATA_SEGMENT_SIZE) //如果數(shù)據(jù)長(zhǎng)度大于最大長(zhǎng)度{u16DataLength = PACKET_DATA_SEGMENT_SIZE; //設(shè)置數(shù)據(jù)最大值}u8Ret = Flash_WriteBytes(u32FlashAddr, (uint8_t *)&u8FrameData[PACKET_DATA_INDEX], u16DataLength); //把所有數(shù)據(jù)寫(xiě)入flashif (Ok != u8Ret) //如果寫(xiě)數(shù)據(jù)失敗 {u8FrameData[PACKET_RESULT_INDEX] = PACKET_ACK_ERROR; //反饋上位機(jī)錯(cuò)誤 標(biāo)志}else //如果寫(xiě)數(shù)據(jù)成功{u8FrameData[PACKET_RESULT_INDEX] = PACKET_ACK_OK; //反饋上位機(jī)成功 標(biāo)志}}else //如果地址無(wú)效{u8FrameData[PACKET_RESULT_INDEX] = PACKET_ACK_ADDR_ERROR; //反饋上位機(jī)地址錯(cuò)誤}Modem_SendFrame(&u8FrameData[0], PACKET_INSTRUCT_SEGMENT_SIZE); //發(fā)送應(yīng)答幀到上位機(jī)break;case PACKET_CMD_CRC_FLASH : //查詢(xún)flash校驗(yàn)值 指令碼if (1u == u8FlashAddrValid) //如果地址有效{u32FlashLength = u8FrameData[PACKET_DATA_INDEX] + (u8FrameData[PACKET_DATA_INDEX + 1] << 8) +(u8FrameData[PACKET_DATA_INDEX + 2] << 16) +(u8FrameData[PACKET_DATA_INDEX + 3] << 24); //獲取待校驗(yàn)flash大小if ((u32FlashLength + u32FlashAddr) > (FLASH_BASE + FLASH_SIZE)) //如果flash長(zhǎng)度超出有效范圍{u8FrameData[PACKET_RESULT_INDEX] = PACKET_ACK_FLASH_SIZE_ERROR; //反饋上位機(jī)flash尺寸錯(cuò)誤}else{u16Ret = Cal_CRC16(((unsigned char *)u32FlashAddr), u32FlashLength);//讀取flash指定區(qū)域的值并計(jì)算crc值u8FrameData[PACKET_FLASH_CRC_INDEX] = (uint8_t)u16Ret; //把crc值存儲(chǔ)到應(yīng)答幀u8FrameData[PACKET_FLASH_CRC_INDEX+1] = (uint8_t)(u16Ret>>8);u8FrameData[PACKET_RESULT_INDEX] = PACKET_ACK_OK; //反饋上位機(jī)成功 標(biāo)志}}else //如果地址無(wú)效{u8FrameData[PACKET_RESULT_INDEX] = PACKET_ACK_ADDR_ERROR; //反饋上位機(jī)地址錯(cuò)誤}Modem_SendFrame(&u8FrameData[0], PACKET_INSTRUCT_SEGMENT_SIZE+2); //發(fā)送應(yīng)答幀到上位機(jī)break;case PACKET_CMD_JUMP_TO_APP : //跳轉(zhuǎn)至APP 指令碼Flash_EraseSector(BOOT_PARA_ADDRESS); //擦除BOOT parameter 扇區(qū)u8FrameData[PACKET_RESULT_INDEX] = PACKET_ACK_OK; //反饋上位機(jī)成功Modem_SendFrame(&u8FrameData[0], PACKET_INSTRUCT_SEGMENT_SIZE); //發(fā)送應(yīng)答幀到上位機(jī)return Ok; //APP更新完成,返回OK,接下來(lái)執(zhí)行跳轉(zhuǎn)函數(shù),跳轉(zhuǎn)至APPcase PACKET_CMD_APP_UPLOAD : //數(shù)據(jù)上傳if (1u == u8FlashAddrValid) //如果地址有效{u32Temp = u8FrameData[PACKET_DATA_INDEX] +(u8FrameData[PACKET_DATA_INDEX + 1] << 8) +(u8FrameData[PACKET_DATA_INDEX + 2] << 16) +(u8FrameData[PACKET_DATA_INDEX + 3] << 24); //讀取上傳數(shù)據(jù)長(zhǎng)度if (u32Temp > PACKET_DATA_SEGMENT_SIZE) //如果數(shù)據(jù)長(zhǎng)度大于最大值{u32Temp = PACKET_DATA_SEGMENT_SIZE; //設(shè)置數(shù)據(jù)長(zhǎng)度為最大值}Flash_ReadBytes(u32FlashAddr, (uint8_t *)&u8FrameData[PACKET_DATA_INDEX], u32Temp); //讀flash數(shù)據(jù)u8FrameData[PACKET_RESULT_INDEX] = PACKET_ACK_OK; //反饋上位機(jī)成功 標(biāo)志Modem_SendFrame(&u8FrameData[0], PACKET_INSTRUCT_SEGMENT_SIZE + u32Temp);//發(fā)送應(yīng)答幀到上位機(jī)}else //如果地址無(wú)效{u8FrameData[PACKET_RESULT_INDEX] = PACKET_ACK_ADDR_ERROR; //反饋上位機(jī)地址錯(cuò)誤 標(biāo)志Modem_SendFrame(&u8FrameData[0], PACKET_INSTRUCT_SEGMENT_SIZE); //發(fā)送應(yīng)答幀到上位機(jī)}break;case PACKET_CMD_START_UPDATE : //啟動(dòng)APP更新(此指令正常在A(yíng)PP程序中調(diào)用)u8FrameData[PACKET_RESULT_INDEX] = PACKET_ACK_OK; //反饋上位機(jī)成功 標(biāo)志Modem_SendFrame(&u8FrameData[0], PACKET_INSTRUCT_SEGMENT_SIZE); //發(fā)送應(yīng)答幀到上位機(jī)break;}enFrameRecvStatus = FRAME_RECV_IDLE_STATUS; //幀數(shù)據(jù)處理完成,幀接收狀態(tài)恢復(fù)到空閑狀態(tài)}return OperationInProgress; //返回,APP更新中。。。
}
4.2、User Application程序設(shè)計(jì)
在本示例User Application中,觸發(fā)BootLoader更新程序的標(biāo)志在串口接收中實(shí)現(xiàn)。
//UART0中斷函數(shù)
void Uart0_IRQHandler(void)
{if(Uart_GetStatus(M0P_UART0, UartRC)) //UART0數(shù)據(jù)接收{(diào)Uart_ClrStatus(M0P_UART0, UartRC); //清中斷狀態(tài)位u8RxData[u8RxCnt] = Uart_ReceiveData(M0P_UART0); //接收數(shù)據(jù)字節(jié)u8RxCnt++; if(u8RxCnt>=18){u8RxCnt = 0;if ((u8RxData[0]==0x6D)&&(u8RxData[1]==0xAC)&&(u8RxData[6]==0x26)&&(u8RxData[16]==0xA6)&&(u8RxData[17]==0xDA)) //是APP更新幀{for(uint32_t i=0;i<18;i++){Uart_SendDataPoll(M0P_UART0,u8TxData[i]); //查詢(xún)方式發(fā)送數(shù)據(jù)}//boot para區(qū)域?qū)憳?biāo)記值,通知BootLoader要更新程序了Flash_SectorErase(0xF00);Flash_WriteWord(0xF00, 0x12345678);NVIC_SystemReset(); //軟件復(fù)位MCU} }}if(Uart_GetStatus(M0P_UART0, UartTC)) //UART0數(shù)據(jù)發(fā)送{Uart_ClrStatus(M0P_UART0, UartTC); //清中斷狀態(tài)位}}
4.3、IAR地址配置及文件輸出
最后還需要簡(jiǎn)答配置下IAR環(huán)境。
第1步:確定輸出的Linker配置地址,因?yàn)樾枰谶@里程序修改地址。
第2步:找到Linker配置文件,修改BootLoader程序地址:0x00000000~0x00000DFF,User Application程序地址:0x00001000~0x0000FFFF。
第3步:找到User Application程序的配置文件(后綴為.s的文件),添加程序中斷向量偏移長(zhǎng)度:0x00001000,和BootLoader程序配置文件相比有兩處不同之處,如下所示:
第4步:將這兩個(gè)程序按照ICP方式(SWD、JTAG等)燒錄后,此后就可以使用IAP方式通過(guò)串口燒錄HEX文件程序或者BIN文件程序。輸出及燒錄HEX文件程序或者BIN文件程序方式如下圖所示:
5、拓展:解析HEX文件
HEX文件可以通過(guò)UltraEdit、Notepad++、記事本等工具打開(kāi),用Notepad++打開(kāi)之后會(huì)看到以下數(shù)據(jù)內(nèi)容:
使用Notepad++打開(kāi)后會(huì)不同含義的數(shù)據(jù)其顏色不同。每行數(shù)據(jù)都會(huì)有一個(gè)冒號(hào)開(kāi)始,后面的數(shù)據(jù)由:數(shù)據(jù)長(zhǎng)度、地址、標(biāo)識(shí)符、有效數(shù)據(jù)、校驗(yàn)數(shù)據(jù)等構(gòu)成。以上圖的第一行為例,進(jìn)行解析:
第1個(gè)字節(jié)10,表示該行具有0x10個(gè)數(shù)據(jù),即16個(gè)字節(jié)的數(shù)據(jù);
第2、3個(gè)字節(jié)3E00,表示該行的起始地址為0x3E00;
第4個(gè)字節(jié)00,表示該行記錄的是數(shù)據(jù);
第5-20個(gè)字節(jié),表示的是有效數(shù)據(jù);
第21個(gè)字節(jié)EB,表示前面數(shù)據(jù)的校驗(yàn)數(shù)據(jù),校驗(yàn)方法:0x100-前面字節(jié)累加和;
其中,第4個(gè)字節(jié)具有5種類(lèi)型:00-05,含義如下:
| 字段 | 含義 |
| 00 | 表示后面記錄的是數(shù)據(jù) |
| 01 | 表示文件結(jié)束 |
| 02 | 表示擴(kuò)展段地址 |
| 03 | 表示開(kāi)始段地址 |
| 04 | 表示擴(kuò)展線(xiàn)性地址 |
| 05 | 表示開(kāi)始線(xiàn)性地址 |
單片機(jī)的hex文件以00居多,都用來(lái)表示數(shù)據(jù)。hex文件的結(jié)束部分如下圖所示:
最后一行的01表示文件結(jié)束了,最后的FF表示校驗(yàn)數(shù)據(jù),由0x100-0x01=0xFF得來(lái)。
資源下載:IAR環(huán)境下STM32+IAP方案的實(shí)現(xiàn)
總結(jié)
以上是生活随笔為你收集整理的电子产品如何使用IAP方式升级程序的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 有源晶振和无源晶振的区别
- 下一篇: 力扣(LeetCode)刷题,简单+中等