关于STM32的IAP超详细图文解说
IAP是In Application Programming的首字母縮寫,IAP是用戶自己的程序在運行過程中對User Flash的部分區(qū)域進行燒寫,目的是為了在產(chǎn)品發(fā)布后可以方便地通過預留的通信口對產(chǎn)品中的固件程序進行更新升級。
?
以上是IAP的官方解釋,通俗一點來說,iap就是一個專門用來升級應用程序的程序。
首先,為什么存在IAP?
在產(chǎn)品不能進行直接燒寫時,例如已經(jīng)包裝好了外殼,或已經(jīng)發(fā)到了客戶手里等不能接觸,只能通過iap來更新應用程序的功能。
其次,IAP是怎么工作的,它和APP有什么關聯(lián),共用的外設怎么分配?
我們知道單片機的執(zhí)行位置是PC指針所指的地方,如下圖所示,它指向IAP時,則運行IAP的代碼,此時所有的外設自然都服務于IAP,指向APP時同理。
上圖的每個方框代表flash上的一塊區(qū)域,可以是一個或多個扇區(qū),IAP工程生成的bin文件最后就燒寫在我們指定給它的flash區(qū)域中,APP的bin文件同理。
當執(zhí)行IAP中的各個函數(shù)時,PC指針就會在這個區(qū)域中跳來跳去(其實各個函數(shù)的地址在map文件中也能看到),
當執(zhí)行IAP中的跳轉到APP的指令時,PC就指向了APP的區(qū)域,繼續(xù)在那一塊區(qū)域跳來跳去。
下面我用cubemx + stm32f4 來舉個栗子,詳細說明iap具體怎么實現(xiàn)跳轉
IAP實例
使用cubemx ,配置好串口1和時鐘,生成iap和app兩個工程,app工程需要更改執(zhí)行起始地址,本例中app改為了0x8010000,具體如何更改也很簡單,可以參考我的另一篇文章,如何修改stm32起始執(zhí)行地址。
先做好串口重定向,跳轉函數(shù),跳轉地址宏,代碼如下:
/* USER CODE BEGIN Includes */ #include "stdio.h" /* USER CODE END Includes */ /* USER CODE BEGIN 0 */ int fputc(int ch, FILE *f) {HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);return ch; }#define APP_FLASH_ADDR 0x8010000 typedef unsigned int u32;typedef void (*iapfun)(void); //定義一個函數(shù)類型的參數(shù). iapfun jump2app; void iap_load_app(u32 appxaddr) {printf("iap jump to app,addr:%08x\r\n",appxaddr);jump2app=(iapfun)*(u32*)(appxaddr+4); //用戶代碼區(qū)第二個字為程序開始地址(復位地址) __set_MSP(*(u32*)appxaddr); //初始化APP堆棧指針(用戶代碼區(qū)的第一個字用于存放棧頂?shù)刂?jump2app(); } /* USER CODE END 0 */main函數(shù)中改動代碼如下
/* USER CODE BEGIN 2 */printf("iap demo\r\n");iap_load_app(APP_FLASH_ADDR);printf("iap demo end\r\n");//正常情況下,永遠不會執(zhí)行這行以及下面的代碼。/* USER CODE END 2 */tips1:關于jump指令
定義函數(shù)指針類型的參數(shù),方便閱讀,如果想緊湊一點可以參考下方代碼一樣可以跳轉,不論哪種寫法,流程是一樣的,
1,*(u32*)? ?>>? ?取0x8010000處的第二字的內(nèi)容,也就是tips2中的08012ccd
2, ((void(*)())? ?>>? ?將08012ccd強轉為無返回無入?yún)⒌暮瘮?shù)指針,
3,執(zhí)行函數(shù)指針,也就是執(zhí)行地址為08012ccd的函數(shù)
void iap_load_app(u32 appxaddr) {printf("iap jump to app,addr:%08x\r\n",appxaddr);//jump2app=(iapfun)*(u32*)(appxaddr+4); //用戶代碼區(qū)第二個字為程序開始地址(復位地址) __set_MSP(*(u32*)appxaddr); //初始化APP堆棧指針(用戶代碼區(qū)的第一個字用于存放棧頂?shù)刂?//jump2app(); ((void(*)())(*(u32*)(appxaddr+4)))();}tip2:為什么不是跳轉到0x8010000,set_msp又是什么鬼?
我們先來看看app燒寫成功之后,0x8010000處是什么樣子的,如下圖
可以看到第一個字是20000570其實是棧頂?shù)刂?#xff0c;那其他的又是什么,我們再來看兩張圖
一張是APP的啟動文件中的中斷向量表,另一張是APP編譯后的map文件所打印出來的各函數(shù)的地址,時間關系沒有框全,但我們將幾張圖的序號對應起來看,不難發(fā)現(xiàn),其實用戶代碼開始幾個字,是按順序對應的棧頂?shù)刂?#xff0c;Reset_Handler地址等。
當我們從IAP跳轉到第二個字也就是Reset_Handler之后,會執(zhí)行SystemInit來初始化時鐘,后面的__iar_program_start是iar的一條內(nèi)部指令,對C的運行,以及全局變量等做初始化操作,一系列準備工作就緒之后再進入main.c函數(shù),執(zhí)行APP代碼,至此,跳轉成功完成。
結果展示
先附上APP的代碼
/* USER CODE BEGIN 2 */printf("diy8 demo\r\n");/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){HAL_Delay(1000);printf("uart test\r\n");/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */再看來自串口的打印信息
由圖可知,跳轉成功,IAP中的iap demo end也確實沒有執(zhí)行打印,end。
總結
以上是生活随笔為你收集整理的关于STM32的IAP超详细图文解说的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: wav转mp3怎么转?
- 下一篇: 【小白向】如何更换文件夹图标