金華網(wǎng)站開發(fā)公司北京seo邢云濤
0 工具準備
Keil uVision5
Cortex M3權威指南(中文)
STM32參考手冊
1 在線升級(IAP)設計思路
為了實現(xiàn)STM32的在線升級(IAP)功能,通常會將STM32的FLASH劃分為BOOT和APP兩個部分,BOOT就是引導APP的引導程序,當我們需要在線升級時就可以通過BOOT來實現(xiàn)。BOOT和APP在FLASH中的分布如下:
原理分析:
(1)當STM32復位后會跳轉到FLASH首地址,也就是0x08000000的位置,讀取1-4Byte獲取主堆棧指針初始值(棧頂值)并設置,然后讀取5-8Byte獲取復位中斷服務函數(shù)入口地址并執(zhí)行,進入BOOT程序
(2)BOOT程序根據(jù)用戶選擇升級APP或者跳轉到APP
(2.1)如果用戶選擇升級APP則擦除APP所在扇區(qū),按照一定協(xié)議將APP程序復制到FLASH的APP扇區(qū)
(2.2)如果用戶選擇跳轉到APP,首先關閉全局中斷及清除中斷掛起標志,設置主堆棧指針,跳轉到APP的復位中斷服務函數(shù)**(相當于做了(1)中內(nèi)核干的事情)**
2 BOOT設計
這里介紹一下BOOT跳轉到APP函數(shù)的設計思路:
void Jump_to_APP(void)
{uint32_t i=0;void (*SysMemBootJump)(void);/* 關閉全局中斷 */__disable_irq();/* 關閉滴答定時器,復位到默認值 */SysTick->CTRL = 0;SysTick->LOAD = 0;SysTick->VAL = 0;/* 設置所有時鐘到默認狀態(tài),使用HSI時鐘 */RCC_DeInit();/* 關閉所有中斷,清除所有中斷掛起標志 */for (i = 0; i < 8; i++){NVIC->ICER[i]=0xFFFFFFFF;NVIC->ICPR[i]=0xFFFFFFFF;}/* 使能全局中斷 */__enable_irq();/* 跳轉到系統(tǒng)BootLoader,首地址是MSP,地址+4是復位中斷服務程序地址 */SysMemBootJump = (void (*)(void)) (*((uint32_t *) (FLASH_APP_ADDR + 4)));/* 設置主堆棧指針 */__set_MSP(*(uint32_t *)FLASH_APP_ADDR);/* 跳轉到APP */SysMemBootJump();/* 跳轉成功的話,不會執(zhí)行到這里,用戶可以在這里添加代碼 */while (1){}
}
相關知識:
(1)涉及到的NVIC寄存器
(1.1)NVIC->ICER,中斷失能寄存器,寫入1失能中斷
(1.2)NVIC->ICPR,中斷掛起清除寄存器,寫入1清除中斷掛起
(2)APP二進制文件含義
bin文件:
Byte1-4:0x20014168
Byte5-8:0x080101A1
Byte9-12:0x08012D75
Byte13-16:0x08012851
map文件:
__initial_sp 0x20014168 Data 0 startup_stm32f40xx.o(STACK)
Reset_Handler 0x080101a1 Thumb Code 8 startup_stm32f40xx.o(.text)
NMI_Handler 0x08012d75 Thumb Code 2 stm32f4xx_it.o(i.NMI_Handler)
HardFault_Handler 0x08012851 Thumb Code 8 stm32f4xx_it.o(i.HardFault_Handler)
可以看到,APP工程的bin文件含義如下:
Byte1-4:0x20014168 主堆棧指針初始值(棧頂值)
Byte5-8:0x080101A1 復位中斷服務函數(shù)地址
Byte9-12:0x08012D75 NMI中斷服務函數(shù)地址
Byte13-16:0x08012851 HardFault中斷服務函數(shù)地址
該部分的定義在STM32的參考手冊上也可以看到:
其實,我們只需要關注主堆棧指針初始值(棧頂值)和復位中斷服務函數(shù)地址即可。如果想要了解APP前幾個byte的全部內(nèi)容,可以參看STM32參考手冊的“STM32F405xx/07xx 和 STM32F415xx/17xx 的向量表”。
弄清楚了上述的寄存器使用方法和APP的bin文件內(nèi)容后,接下來BOOT中跳轉到APP的操作原理就一目了然了:
(1)關閉全局中斷,避免被打斷
(2)關閉滴答定時器,復位到默認值,為后面的APP營造一個純凈的環(huán)境
(3)設置所有時鐘到默認狀態(tài),為后面APP營造一個純凈的環(huán)境
(4)關閉所有中斷同時清除所有中斷掛起標志,避免APP使能中斷后異常觸發(fā)等情況
(5)使能全局中斷,避免APP部分沒有打開全局中斷
(6)函數(shù)指針指向APP的復位中斷服務函數(shù)(也就是APP的第5-8Byte)
(7)設置主堆棧指針(也就是APP的前4Byte)
(8)跳轉到APP
以上有2個地方需要特別注意:
(1)APP的復位中斷服務函數(shù)地址是APP的第5-8Byte
(2)APP的主堆棧指針初始值(棧頂值)是APP的前4Byte
3 APP設計
APP設計時只需要修改工程的flash起始地址以及中斷向量偏移地址寄存器即可。
(1)修改FLASH起始地址
如果我們的APP存放在FLASH的0x8010000開始的位置,則將FLASHA的起始地址修改為0x8010000即可。
(2)修改中斷向量偏移地址
BOOT下我們的中斷向量偏移地址為0x08000000和默認值一樣無須特別設置,APP下由于FLASH起始地址被修改到0x8010000,因此需要將中斷向量偏移地址設置為0x1000:
#define VECT_TAB_OFFSET 0x10000
相關寄存器如下:
當STM32發(fā)生了中斷需要響應時,內(nèi)核會根據(jù)向量表偏移量寄存器的值在相應的FLASH空間找到異常服務函數(shù)入口地址(中斷服務函數(shù)入口地址保存工作由編譯器完成)。上電后的向量表如下:
假設我們設置的VTOR的值為0x8010000,在發(fā)生了硬錯誤時,會跳轉到0x8010000+0x0000000C的位置找到硬錯誤中斷服務函數(shù)地址并執(zhí)行。這也是我們?yōu)槭裁葱枰贏PP中設置VTOR的原因(BOOT里已經(jīng)默認設置為0x0x8000000),保證我們的中斷能夠正確執(zhí)行。
4 總結
(1)APP程序需要修改FLASH起始地址和向量表偏移量寄存器,以便內(nèi)核能夠在中斷發(fā)生時進入正確的中斷服務函數(shù)
(2)BOOT程序跳轉到APP的過程實際上就是模擬內(nèi)核的操作
(3)BOOT跳轉到APP之前一定要失能所有中斷、清除所有中斷掛起標志,營造一個純凈的環(huán)境