STM32的IAP功能應用
背景
在做的那個路燈專案,協議裡面有個線上遠端升級功能,而且由於交付工期態趕,我們並不能在工期前完全實現好全部協議內容,只能有針對性地去實現幾個功能,然後剩下功能區遠端升級,這個遠端是通過onenet按照一定幀格式來下發bin檔案來做到的。
IAP簡介
IAP :在編程式設計的簡介,使用者自己的程式在執行過程中對User Flash的部分割槽域進行燒寫,目的是為了在產品釋出後可以方便地通過預留的通訊口對產品中的韌體程式進行更新升級。
明白IAP原理必須先了解STM32的啟動過程,在我們一般應用開發過程中,都是從main函式開始。那麼在微控制器開機執行的第一條程式碼真的是從main函式開始的嗎?其實不是,可以想一下,C語言的執行是需要堆疊環境的,在我們的main函式中我們並沒有手動建立堆疊環境,所以在main函式之前一定是有一段程式碼幫我們建立了堆疊環境,其實這段程式碼不僅僅幫我們建立了堆疊環境,還做了很多其他的事情,這段程式碼就是:
Reset_Handler PROC EXPORT Reset_Handler [WEAK] IMPORT __main IMPORT SystemInit LDR R0, =SystemInit ;跳轉到SystemInit 函式中 BLX R0 LDR R0, =__main ;跳轉到__main函式中,這是MDK內建的一個函式,這個函式中會跳到main函式中 BX R0 ENDP
在stm32上電一瞬間,系統從Reset_Handler向量表來取指,然後進入SystemInit執行,再到__main函式,最後到main函式,大工告成。
在這個過程中有個至關重要的過程發生在SystemInit中了,就是中斷向量表的建立…為什麼說他重要?下面再講
SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */
正常的MCU程式在此就可以正常運行了。但是IAP通常將程式碼分為兩個區域bootloader和app部分,IAP程式在這裡開始與正常程式不一樣了。
我的兩部分程式碼功能部分大概是
bootloader:引導、在需要升級程式的時候進行升級、跳轉到app程式
app:執行業務程式碼、在接收到升級BIN檔案時,將其找到合適位置進行儲存,然後軟體復位
在IAP程式中我們一般會配置一個eeprom,在eeprom某個位置存放Update_flag,如果Update_flag顯示不需要升級就直接跳過升級,執行到app首地址,app首地址存放的是堆疊指標,首地址+4是app的Reset_Handler函式,然後直接執行app的SystemInit,重新建立向量表對映,然後執行app的main函式,大功告成。
其實 建設向量表對映操作就是 填充向量表偏移暫存器,不論在任何程式碼中,STM32的中斷向量表的相對位置是固定的,第一個存放的是堆疊指標,第二個是復位地址。。但是第一個向量的絕對地址是可以改變的,就是向量表的絕對地址可以變,相對於起始地址向量表地址是不變的。在IAP程式碼中如果發生中斷,首先會取出向量表偏移地址(SCB->VTOR ),然後根據中斷號來計算得到中斷服務例程的入口,進一步跳轉,之前沒有強調是因為沒有重定位向量表的時候,向量表偏移地址都是零。
在很多其他介紹IAP的部落格中關於這部分介紹都有誤,看下圖
這個中斷請求步驟5和步驟6都是不對的…,這個問題仔細想了一下,最後在Cortex M3權威指南中找到了答案,看圖
下面貼一張實際工作流程圖
過段時間來貼程式碼,其實也可以用flash來模擬eeprom,只要不衝突就ok,還有防止誤操作應該還要校驗版本號,釋出者金鑰之後才能真正的去擦除flash升級韌體(防止誤操作),需要自己手動修改BIN檔案等。