stm32 IAP 程序编写心得
stm32 IAP 程序編寫心得
- 前言
- IAP簡介及原理
- IAP設計過程
- 完整的IAP功能
- 功能的實現與遇到的問題
- 附錄:程序源碼
前言
大家好這里是小白,因為實在受不了一些網上代碼和某些開發板例程的荼毒,決定開個blog吐槽一下學習和工作中踩過的一些雷和遇到的一些坑。博主目前主要是做硬件和嵌入式設計的,主要使用的STM32F1XX和STM32F4XX并配合Inter的FPGA做一些程控和信號處理,具體行業就不多說了,有興趣可以點進我的頭像看一哈,或者私信我交流一些設計心得。
IAP簡介及原理
IAP是在線應用編程(In Application Programming)的簡稱,簡單來說IAP的目的就是實現在線刷程序。在剛開始學習STM32的時候,我們只能通過J-LINK或者ST-LINK實現程序燒寫,隨著學習的深入,我們也可能會接觸到使用ST官方的BOOTLOADER GUI進行程序下載,但是上述的這幾種方式在燒寫程序時要么需要使用特殊的下載工具,要么需要跳片改變STM32 boot0腳的狀態并使用專用的軟件,并不適合生產批量燒寫,因此就有了IAP這種下載方式。
IAP的原理在STM32資料手冊和很多博主都有介紹,有需要的朋友可以參考下面兩個資料:
STM32+IAP實現原理: https://blog.csdn.net/wzy15965343032/article/details/88545225.
正點原子STM32探索者開發板IAP: https://www.bilibili.com/video/BV1Rx411R75t?p=91.
理論上IAP可以實現包括USART,CAN,SPI,IIC等任意一種通訊方式實現在線編程。
廢話不多說直接說正題,由于工作需要,最近我也在編寫基于USART的IAP實現方案,參考了網上一些資料后總覺得不太理想,因此分享一下我在編寫IAP時遇到的一些問題以及解決方案。
IAP設計過程
目前我在網上找到兩個相關的IAP設計例程,都是基于ymodem協議的,一個就是正點原子的IAP串口實現方案,另一個不知道算不算官方的例程,看函數介紹寫的是MCD Application Team。
第一個例程我就不放了,大家可去正點原子官網下載。第二個例程采用的是超級終端控制的,但是需要上位機添加bin文件(這里我沒有找到相應的上位機,理論上可以使用老司機常用的那個SSCOM42,只不過字符輸入需要手動點擊發送),我會在文章末尾放上下載鏈接,大家可根據需求自行下載。
IAP設計過程本質上就是編寫兩段(或多段)代碼,一段是IAP代碼,另一段是實際的APP應用程序代碼,編寫完成后將IAP燒寫入STM32FLASH的最前端,再將APP應用程序編譯后生成bin文件。然后將IAP程序燒錄至FLASH中,隨后根據需要將要使用的應用程序的bin文件通過USART(通訊)的方式發送給單片機,并存入單片機的FLASH。注意這里的應用程序存放要偏移一定的地址,偏移大小是設置的IAP程序的大小,否則會擦除掉IAP程序導致跳轉失敗或者IAP僅能使用一次。
比如我使用的是stm32f407單片機,該單片機一共12個SECTOR共1MB的FLASH存儲空間,我一般是這樣分配的,SECTOR 0用于存放IAP代碼,SECTOR 1-SECTOR 4用于存放APP應用程序代碼(如果不夠可以往后擴展),SECTOR5-SECTOR 10用于存放需掉電保存的系統參數,最后SECTOR11存放一些關鍵的系統標志(這個后面會提到)。
APP應用程序我這里使用原子的UCOSII的移植例程,通過點亮兩個LED燈檢查IAP程序是否燒錄進去,APP應用程序需要設置FLASH地址,并且需要設置APP應用程序的中斷向量偏移。
最后再選擇MDK自帶的fromelf應用程序(在KEIL的安裝路徑下面,點擊后面的小文件夾添加),生成bin文件就可以使用上位機更新程序了。
這里注意 --bin - o…是手動添加的,OBJ后面的文件名是你的項目output文件名。如我的項目output名稱是UCOS-1,所以我這里應該填:
D:\Keil5\ARM\ARMCC\bin\fromelf.exe --bin -o …\OBJ\UCOS-1.bin …\OBJ\UCOS-1.axf
以上工作完成就可以使用上位機更新APP應用程序了,首先將IAP程序燒錄進單片機,打開串口助手,將你的電路板與電腦連接,選擇打開文件,將編譯好的bin文件添加,點擊發送文件,APP程序就寫入了相應的FLASH中。
完整的IAP功能
以上就是IAP編程的完整過程,也是原子開發板例程中具有的功能,但是正當我想測試的時候發現一個問題,原子的例程是通過按鍵實現跳轉的,而我設計的電路板,沒有按鍵!!
然后我又看了看原子例程代碼,想了想我的需求,發現這離我想要的IAP代碼功能還差很多,于是我決定掏出我的陳年老代碼重構一下改成IAP代碼。
相比于原子的開發歷程,我需要我的IAP程序具有以下幾個功能:
1.在IAP程序中,通過特定串口指令進入IAP模式,然后再添加和發送APP應用程序的bin文件,防止發送的數據,也被寫入FLASH。
2.可以實現APP應用程序跳轉回IAP程序,實現程序的重新燒錄,這一點也是通過特定的串口指令來實現的。
3.上電判斷是否已有APP應用程序,如果已有程序,自動跳轉APP程序運行。
4.由APP應用程序跳轉回IAP后,IAP程序判斷本次運行是重新上電還是由APP程序跳轉而來,如果是由APP跳轉而來,則用戶需要重新燒錄程序,先將已有的應用程序自動擦除,等待串口指令進入IAP模式。
具備了以上功能,IAP程序才算完整。
功能的實現與遇到的問題
以上功能并不難實現,有興趣的朋友可以試著自己做一下,我這里來簡單說一下我的做法。
1.首先針對第一點,設置一個串口指令標志位,只有收到了特定的指令(此處我設置的是十六進制A5 5A 31 42 0D),標志位置位,才可以開始接收bin文件,否則無論收到什么都顯示指令錯誤。
2.這個部分需要重點注意一下,我在測試跳轉回IAP的時候,原本是在APP應用程序其中一個LED_TASK中做了個計數,計數10次之后自動跳轉回IAP程序,到這里是沒有問題的,但當我再次發送bin文件時就發生了問題。
void led0_task(void *pdata) {u8 count = 0;while(1){LED0=0;delay_ms(80);LED0=1;delay_ms(920);if(count > 10){count = 0;printf("跳轉回IAP程序!\r\n");delay_ms(10);iap_load_app(STM32_FLASH_BASE);}else{count ++;}} }這里使用與IAP代碼里使用的iap_load_app()函數是可以跳轉回IAP代碼的,但是當我再次發送應用程序bin文件時,并沒有顯示跳轉APP程序,于是我掛了仿真器對IAP代碼進行仿真,發現在我再次發送bin文件時,系統發生了錯誤進入了死循環。
void HardFault_Handler(void) {/* Go to infinite loop when Hard Fault exception occurs */while (1){} }這個問題我試了好久,也沒有發現明顯的邏輯錯誤,就是找不到原因,于是我去網上查IAP的資料,發現大多數都是IAP功能的介紹,沒有什么具體示例。經過長時間查找,我終于看到了一篇文章,原來是我在跳轉回IAP程序之后沒有復位RCC時鐘和NVIC中斷,導致時鐘或中斷發生錯亂。所以在跳轉回IAP程序后,配置時鐘之前要添加RCC_DeInit()函數,在配置中斷前要添加NVIC_DeInit (),先將時鐘和中斷關閉之后再重新配置,當然這里也可以使用stm32庫函數里面的系統復位函數來讓程序重新從頭開始運行,我這里使用的就是這種方法(別問,問就是偷懶)。
if(Jump_IAP_FLAG){Jump_IAP_FLAG = 0;delay_ms(10);if(((*(vu32*)(STM32_FLASH_BASE + 4)) & 0xFF000000) == 0x08000000) //判斷代碼合法性{STMFLASH_Write(ADDR_CodeWriteFlag,IAPFlagBuf,2); //寫IAP跳轉標志位delay_ms(100);printf("Start Running IAP code!\r\n");NVIC_SystemReset(); //注意此處跳轉不是使用iap_load_app,而是將系統復位}else {printf("IAP code is illegal!\r\n"); }}3.解決了上述兩個問題,第三點和第四點就好實現了,正如前文所說,我在SECTOR11中的連續兩個地址存放了兩個標志量。
#define ADDR_CodeWriteFlag ((u32)0x080E1000) //IAP程序更新標志位存放地址,如果是0x55,說明已經有應用程序 #define ADDR_JumpToIAPFlag ((u32)0x080E1001) //IAP程序跳轉標志位,如果是0x55,說明是從APP跳轉回IAP程序在將bin文件寫入FLASH之后跳轉APP應用程序之前,連續從ADDR_CodeWriteFlag地址連續寫入兩個標志量0x55和0x00,跳轉之后如果系統復位或者重新上電,在運行IAP程序時會首先讀取ADDR_CodeWriteFlag地址是否等于0x55,如果等于則直接跳轉APP程序運行,如果不相等,等待用戶燒錄程序再繼續運行。
JumpToAPPFlag = FLASH_ReadWord(ADDR_CodeWriteFlag); //讀取APP寫入標志位,判斷是否已有程序 if(JumpToAPPFlag != 0x55) //判斷是否已有APP程序,如果已有,跳轉至APP程序運行 {} else {printf("There is an app code!\r\n");printf("Start running app code!\r\n");delay_ms(10);IAP_Load_AppCode(FLASH_APPCODE_ADDR); //執行FLASH APP代碼 }同樣由APP跳轉回IAP之前,我會重新在上述地址連續寫入0x00和0x55,這樣跳轉回IAP之后既不會再跳轉回APP,也可以判定ADDR_JumpToIAPFlag位的值,如果該位等于0x55,說明是從APP程序跳轉回來的,因此會先擦除存放APP代碼的扇區,這里我是用的是SECTOR1-SECTOR4。
if(JumpToIAPFlag == 0x55) //判斷是否從APP程序跳轉回來,如果是擦除已有APP程序 {STMFLASH_Erase(); JumpToIAPFlag = 0x00; //清跳轉標志位,防止不停擦除FLASH }以上就是我IAP編寫的歷程和一些心得,希望對大家有幫助吧,下面放上源碼,有需要的朋友自取,STM32F1系的單片機也可以使用,但是要修改一下各系統函數的初始化配置(F1和F4在配置上還是有少許區別的,這個有需求的話我也可以給大家開個貼交流一下)。
附錄:程序源碼
CSDN: https://download.csdn.net/download/suzuzhizhen/15611524?spm=1001.2014.3001.5503.
GitHub:https://github.com/baiyiqing-LC/stm32f4xx_usart_IAP
總結
以上是生活随笔為你收集整理的stm32 IAP 程序编写心得的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MFC学习笔记整理:002_腾讯游戏连连
- 下一篇: Flask+ZUI 开发小型工具网站 3