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