嵌入式IAP开发笔记之一:面向STM32的BootLoader程序
對(duì)于很多人來(lái)說(shuō),BootLoader并不是一個(gè)陌生的詞,甚至?xí)?jīng)常用到它。因?yàn)樵诤芏嗲闆r下我們都需要BootLoader程序,比如我們需要對(duì)系統(tǒng)在線升級(jí)時(shí)就需要它,還有當(dāng)我們需要在外部存儲(chǔ)器中運(yùn)行程序時(shí)也需要用到它。在這里我們就來(lái)設(shè)計(jì)一個(gè)應(yīng)用于STM32系列MCU的BootLOader程序。
1、BootLoader的基本原理
既然我們想要實(shí)現(xiàn)一個(gè)面向STM32的BootLOader程序,那么首先我們必須來(lái)了解一下BootLOader程序的基本原理。
顧名思義,BootLOader程序肯定是要實(shí)現(xiàn)系統(tǒng)的引導(dǎo),這是BootLOader程序的基本功能。對(duì)于STM32系列MCU來(lái)說(shuō),系統(tǒng)啟動(dòng)后都會(huì)從內(nèi)部Flash存儲(chǔ)器的起始地址開(kāi)始執(zhí)行程序。然后進(jìn)入應(yīng)用程序并按既定的順序執(zhí)行下去,這時(shí)BootLoader與應(yīng)用程序是一體的,具體如圖所示:
但有些時(shí)候,我們希望應(yīng)用程序并不是直接運(yùn)行,如我們希望對(duì)系統(tǒng)實(shí)現(xiàn)IAP的時(shí)候;或者我們希望應(yīng)用程序并不在我們的內(nèi)部Flash中運(yùn)行;又或者應(yīng)用程序雖然在內(nèi)部Flash運(yùn)行,但我們希望應(yīng)用程序從我們指定的內(nèi)部Flash地址運(yùn)行等等。在這些時(shí)候我們就需要一個(gè)單獨(dú)的BootLoader程序。系統(tǒng)首先啟動(dòng)BootLoader程序,系統(tǒng)準(zhǔn)備就緒后進(jìn)入到應(yīng)用程序執(zhí)行,具體如圖所示:
在上圖中,我們實(shí)際上將應(yīng)用程序存儲(chǔ)在內(nèi)部Flash的指定位置,這樣做當(dāng)然是為了實(shí)現(xiàn)我們某種需求,如系統(tǒng)IAP。當(dāng)然我們也可以讓?xiě)?yīng)用程序存儲(chǔ)于外部Flash中,然后BootLoader程序跳轉(zhuǎn)到外部Flash去執(zhí)行應(yīng)用程序,不過(guò)前提是外部Flash內(nèi)購(gòu)執(zhí)行程序。具體過(guò)程如下:
當(dāng)然,這只是一種示例,對(duì)于不同的存儲(chǔ)器我們只需要修改地址就可以了。至于在BootLoader程序中要實(shí)現(xiàn)的功能就看使用情況了。原則上我們可以添加我們?nèi)我庀胍墓δ?#xff0c;如硬件檢測(cè)、系統(tǒng)升級(jí)等等。
2、目標(biāo)BootLoader設(shè)計(jì)
我們的目標(biāo)是實(shí)現(xiàn)一個(gè)面向STM32的BootLoader程序。那么接下來(lái)我們就設(shè)計(jì)如何實(shí)現(xiàn)一個(gè)面向STM32的BootLoader程序。
2.1、Flash規(guī)劃
我們以STM32F407IGT6為目標(biāo)MCU,這款MCU具有1M的Flash和192K的SRAM。我們將Flash劃分為2個(gè)部分,一個(gè)是啟動(dòng)程序區(qū)(0x0800 0000 - 0x0800 3FFF )大小為16K Bytes,剩下的為應(yīng)用程序區(qū)(0x0800 4000 - 0x080F FFFF)。具體分配如下圖:
我們讓BootLoader程序占用16K的存儲(chǔ)空間。但它是可以操作整個(gè)Flash存儲(chǔ)空間的。
2.2、BootLoader程序結(jié)構(gòu)
我們來(lái)考慮一下BootLoader程序的結(jié)構(gòu)問(wèn)題。我們?cè)O(shè)計(jì)BootLoader程序的主要目的就是為了對(duì)應(yīng)用程序進(jìn)行升級(jí)。那么在BootLoader程序中主要需要實(shí)現(xiàn)哪些功能呢?有幾個(gè)方面是必須要包括的,一是基本的配置,如時(shí)鐘等,我們?cè)谥鞒绦蛑袑?shí)現(xiàn);二是對(duì)Flash的操作,我們升級(jí)應(yīng)用程序肯定會(huì)對(duì)Flash進(jìn)行查處和寫(xiě)入操作;三是跳轉(zhuǎn)控制程序,我們最終是需要去執(zhí)行應(yīng)用程序的,跳轉(zhuǎn)功能必不可少。當(dāng)然根據(jù)不同的需求可能會(huì)有其它的需要。具體如下圖所示:
上圖中,我們除了簽署的三項(xiàng)基本實(shí)現(xiàn)外,還添加了IAP文件的獲取功能。這部分功能也是需要的,但在不同的模式下可能會(huì)有較大區(qū)別。因?yàn)楂@取文件的方式可以是各類(lèi)通訊如以太網(wǎng)口、串口等。也可以是各類(lèi)存儲(chǔ)器,如SD卡、U盤(pán)等。所以這一功能雖然必不可少但實(shí)現(xiàn)方式則非常靈活,在后續(xù)實(shí)現(xiàn)中,我們具體問(wèn)題具體分析。
3、目標(biāo)BootLoader實(shí)現(xiàn)
我們已經(jīng)確定了Flash的劃分,也基本明白了BootLoader的基本工作流程。在接下來(lái)我就來(lái)討論一下究竟怎么實(shí)現(xiàn)一個(gè)BootLoader程序。
3.1、BootLoader編碼
我們知道芯片上電時(shí)先運(yùn)行BootLoader程序,然后跳轉(zhuǎn)到應(yīng)用程序區(qū)執(zhí)行應(yīng)用程序。所以我們?cè)诰帉?xiě)B(tài)ootLoader程序時(shí)我們首先判斷系統(tǒng)是否有IAP的需求,如果有IAP請(qǐng)求則進(jìn)入IAP模式,完成后再跳轉(zhuǎn)到應(yīng)用程序執(zhí)行,如果沒(méi)有IAP請(qǐng)求則直接跳轉(zhuǎn)到應(yīng)用程序執(zhí)行。具體流程如下:
關(guān)于IAP的處理在不同的情況下會(huì)有不同的處理方式,在這里我們主要看一看跳轉(zhuǎn)控制程序。首先定義應(yīng)用程序的首地址并聲明一個(gè)函數(shù)指針類(lèi)型。具體如下:
#define? ApplicationAddress? 0x08004000??? //應(yīng)用程序首地址定義
typedef void (*pFunction)(void);??????? //定義跳轉(zhuǎn)函數(shù)指針類(lèi)型
可能有人要問(wèn)問(wèn)什么定義這樣一個(gè)函數(shù)指針類(lèi)型,因?yàn)槲覀冏罱K是跳轉(zhuǎn)到Reset_Handler函數(shù),所以必須要一個(gè)可以指向這個(gè)函數(shù)的函數(shù)指針。接下來(lái)我們就可以實(shí)現(xiàn)跳轉(zhuǎn)程序了。
/*跳轉(zhuǎn)到應(yīng)用程序處理函數(shù)*/ static void JumpToApplication(void) {uint32_t StackAddr;?????????? //應(yīng)用程序棧地址uint32_t ResetVector;???????? //應(yīng)用程序中斷向量表的地址pFunction JumpToApp;????????? //定義跳轉(zhuǎn)函數(shù)指針__set_PRIMASK(1);??? //關(guān)閉全局中斷StackAddr = *(__IO uint32_t*)ApplicationAddress;????????????? //0x08004000;ResetVector = *(__IO uint32_t*)(ApplicationAddress + 4);????? //0x08004004;if((StackAddr&0x2FFC0000)==0x20000000)??????? //檢查棧頂?shù)刂肥欠窈戏?{__set_MSP(StackAddr);???? ??????????????????//初始化應(yīng)用程序棧指針JumpToApp = (pFunction)ResetVector;???????????JumpToApp();} }3.2、應(yīng)用程序處理
實(shí)現(xiàn)了BootLoader的編碼后,要想正確的跳轉(zhuǎn)到App運(yùn)行,我們還需要對(duì)App作相應(yīng)的修改。重要的修改有2處。如果應(yīng)用程序是裸機(jī)程序則在配置時(shí)鐘前我們需要打開(kāi)全局中端。
/*開(kāi)啟全局中斷,在BootLoader中關(guān)閉的*/
? __set_PRIMASK(0);
同時(shí),還需要修改中端向量表的偏移量地址。對(duì)于我們所使用的STM32F07可直接在system_stm32f4xx.c文件中修改就可以了。
#define VECT_TAB_OFFSET? 0x4000 /*!< Vector Table base offset field.
實(shí)現(xiàn)了上述修改并不能達(dá)到我們想要的目的,我們還需要在開(kāi)發(fā)環(huán)境中做必要的修改。以我們使用的IAR EWARM V8.4為例。修改icf文件中對(duì)中斷向量表和Flash存儲(chǔ)區(qū)域的設(shè)定。具體如下圖:
完成上述配置后我們下載應(yīng)用程序和BootLoader程序就可以實(shí)現(xiàn)正確的跳轉(zhuǎn)了。
4、小結(jié)
本篇中,我們只是實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的BootLoader程序。下載到目標(biāo)MCU后實(shí)現(xiàn)了跳轉(zhuǎn),應(yīng)用程序也正常運(yùn)行,說(shuō)明我們的設(shè)計(jì)是正確的,后續(xù)可在次基礎(chǔ)上添加各種功能實(shí)現(xiàn)相應(yīng)的IAP應(yīng)用。
需要注意的是在BootLoader程序中我們關(guān)閉了全局中斷,在應(yīng)用程序初始化系統(tǒng)時(shí)鐘之前一定要記得打開(kāi)全局中斷,否則SystemTick不能工作會(huì)產(chǎn)生硬件故障(hardfault)。不過(guò)如果App是運(yùn)行在RTOS上,則打開(kāi)中斷可能會(huì)出錯(cuò),這一點(diǎn)需要注意。
歡迎關(guān)注:
總結(jié)
以上是生活随笔為你收集整理的嵌入式IAP开发笔记之一:面向STM32的BootLoader程序的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Modbus协议栈开发笔记之五:Modb
- 下一篇: LwIP应用开发笔记之八:LwIP无操作