需要注意的是:BootLoader下載新程序后并不擦除自己(BootLoader程序還在),下次啟動(dòng)依然先運(yùn)行BootLoader程序,又可以選擇性的更新或者不更新程序,所以BootLoader就是用來(lái)管理單片機(jī)程序的更新。
__initial_spTop就是棧指針,Reset_Handler是復(fù)位向量。這里只顯示了16個(gè)向量,CortexM3單片機(jī)的話總共有256個(gè)向量,也就是從棧指針的地址開(kāi)始有1KB的區(qū)域?qū)儆谥袛嘞蛄勘怼?/div>
單片機(jī)啟動(dòng)默認(rèn)先運(yùn)行BootLoader
,所以默認(rèn)的中斷向量表位置是BootLoader
的中斷向量表。為了App
可以正常運(yùn)行,下載完App
后,我們還需要把中斷向量表重新定位到App
程序那里。根據(jù)《CortexM3
權(quán)威指南》,介紹一下怎樣重定位中斷向量表。
3.2.2 設(shè)置中斷向量表偏移Cortex-M3
單片機(jī)有一個(gè)管理中斷向量表的寄存器,叫做向量表偏移量寄存器(VTOR)
(地址:0xE000_ED08
)。具體可以看看截圖:
STM332
程序的起始地址一般在0x08000000
。所以BootLoader
程序是在0x08000000
,不是在0x00000000
是因?yàn)?/font>STM32的重映射技術(shù)(不符合Cortex-M3的設(shè)計(jì),有點(diǎn)搞另類的感覺(jué))。所以BootLoader的中斷向量表在0x08000000那里。如果我們的App程序起始地址在0x08070000,并且App的中斷向量表在起始地址,那么BootLoader程序下載App后,為了App程序能正確運(yùn)行,開(kāi)始App程序的運(yùn)行后第一步,就要把中斷向量表重定位到0x08070000那里。
具體實(shí)現(xiàn)下面會(huì)再介紹,接下來(lái)介紹分散加載文件相關(guān)內(nèi)容。
3.3 分散加載文件相關(guān)這一節(jié)涉及的內(nèi)容主要屬于分散加載文件,大家具體上網(wǎng)了解,這里只是介紹了能夠?qū)崿F(xiàn)BootLoader的一小部分。
3.3.1 C語(yǔ)言的函數(shù)地址我們知道C語(yǔ)言的函數(shù)名就是函數(shù)的地址,并且STM32單片機(jī)ROM的起始地址是在0x08000000,那么使用編譯器編譯程序的話(這里使用的是RVMDK),函數(shù)的地址默認(rèn)都在以0x08000000為首的一段ROM里面了。比如我們一個(gè)函數(shù)Delay(),它的地址可以是0x08000167(CortexM3中函數(shù)的地址0bit位一般是1),也就是Delay函數(shù)的代碼在0x08000167,C語(yǔ)言函數(shù)調(diào)用Delay時(shí),就是執(zhí)行0x08000167的代碼。
3.3.2 BootLoader占用的ROM我們需要注意的問(wèn)題是,如果不修改程序默認(rèn)的起始地址的話,那么BootLoader和新App程序的起始地址都是0x08000000,也就是他們重疊了(代碼重疊),這樣的話肯定相互之間有影響,程序是不能正常工作的。
這里的解決方法是,BootLoader程序依然占用0x08000000為首的那段ROM,因?yàn)?/font>STM32的默認(rèn)就是從0x08000000運(yùn)行程序的。保持BootLoader程序先能正確運(yùn)行。然后App使用除BootLoader占用ROM以外的空間。這里需要知道BootLoader到底占用了多少ROM,很簡(jiǎn)單,查看MAP文件就行了。這里以我的BootLoader的MAP文件為例說(shuō)明一下,看截圖:
Memory Map of the image
Image Entry point :0x08000131
Load Region LR_IROM1 (Base: 0x08000000,Size: 0x00006da4, Max: 0x00080000, ABSOLUTE)
Execution Region ER_IROM1 (Base: 0x08000000, Size: 0x00006d54, Max:0x00080000, ABSOLUTE)
主要是這句話“Base:0x08000000, Size: 0x00006da4, Max: 0x00080000”,這句話說(shuō)明了我的BootLoader程序是從0x08000000開(kāi)始,占用了0x00006DA4大小。只要我們的App不要和BootLoader程序占用的空間沖突就可以了。我的App程序的起始地址選擇為0x08070000,不與BootLoader程序沖突。具體怎么修改ROM起始地址,下面介紹。
3.3.3 修改ROM起始地址編譯新程序的時(shí)候,我們要修改程序的起始地址,我的修改方法如下(開(kāi)發(fā)環(huán)境是RVMDK):打開(kāi)TargetOption...,切換到Target選項(xiàng)卡,如下
修改IROM1的起始地址和長(zhǎng)度:
比如,為了不產(chǎn)生地址沖突,我將起始地址0x08000000修改成0x0807000,將ROM長(zhǎng)度0x80000修改成0x10000。如下圖所示(左圖為修改前、右圖為修改后):
注意:BootLoader程序是不需要修改的,只是App需要修改(App就是使用BootLoader下載的程序)。
3.4 hex文件和bin文件3.4.1 hex文件平時(shí)我們用j-Link或者串口下載程序的話,都是打開(kāi)hex文件下載的,因?yàn)?/font>hex文件包含地址信息,下載程序的時(shí)候知道程序下載到ROM的哪個(gè)區(qū)域。從另一個(gè)角度上說(shuō),也就是hex文件是不能直接寫(xiě)進(jìn)ROM的,一邊寫(xiě)需要一邊轉(zhuǎn)換(解碼出地址信息,將對(duì)應(yīng)內(nèi)容寫(xiě)入ROM)。
3.4.2 bin文件bin文件的話,很好理解,是直接的可執(zhí)行代碼。也就是bin文件的內(nèi)容跟下載ROM里面的內(nèi)容是一樣的。bin文件是沒(méi)有包含地址信息的,所以在下載之前要知道bin文件是要下載到ROM的那個(gè)區(qū)域。
我們的BootLoader下載的是bin文件,直接寫(xiě)進(jìn)STM32的Flash里面,地址信息的話就是上一節(jié)的IROM,0x08070000,從0x08070000開(kāi)始連續(xù)寫(xiě)入,中間不間斷。
3.5 Bin文件生成默認(rèn)情況下編譯后生成的是hex文件,不過(guò)很輕松可以生成bin文件。介紹具體怎么生成bin文件,工具的話是使用fromelf.exe(目錄一般是在Keil安裝目錄里面,本人的fromelf.exe目錄是在C:\Keil\ARM\ARMCC\bin),我們是使用fromelf工具將axf文件轉(zhuǎn)換為bin文件。
熟悉命令行的同學(xué)可能會(huì)選擇直接敲命令,不過(guò)這里介紹使用RVMDK提供的用戶命令(編譯時(shí)可以自動(dòng)生成bin,省去每次生成bin文件都要敲命令的過(guò)程)。
打開(kāi)TargetOption...,切換到User選項(xiàng)卡,如下
主要是在運(yùn)行用戶命令,Run#1
具體命令是(記得在Run#1前打勾,才會(huì)在編譯后執(zhí)行用戶命令生成bin文件):
C:\Keil\ARM\ARMCC\bin\fromelf.exe
--bin
-o
.\Output\MY_STM32.bin
.\Output\MY_STM32.axf
命令可以分為五部分,簡(jiǎn)化后是fromelf --bin -o xxx.bin xxx.axf,需要注意的是命令的五個(gè)部分之間要有空格。還需要說(shuō)明的是路徑問(wèn)題,這里的路徑都是相對(duì).uvproj文件的,下面是我的目錄(注意MY_STM32.uvproj文件和Output文件夾)。

我的bin文件和axf文件都在Output文件夾里面,并且路徑是相對(duì)MY_STM32.uvproj的,Output文件夾里的bin文件(MY_STM32.bin)相對(duì)于MY_STM32.uvproj應(yīng)該寫(xiě)成“.\Output\MY_STM32.bin”。
l 第一部分
這部分是fromelf.exe文件的路徑,根據(jù)自己的安裝目錄而變。我這里因?yàn)?/font>Keil是安裝在C盤的,所以我的路徑如下所示。
參考命令:C:\Keil\ARM\ARMCC\bin\fromelf.exe
l 第二部分
這部分是固定的,--bin表示生成bin文件。
參考命令:--bin
l 第三部分
這部分也是固定的,-o表示輸出。
參考命令:-o
l 第四部分
這部分是生成文件的目錄和文件名,我是輸出在Output文件夾的,也就是bin文件在Output文件夾里面。
參考命令:.\Output\MY_STM32.bin
l 第五部分
這部分是axf文件的目錄和文件名,我們的bin文件是根據(jù)axf文件生成的,也就是說(shuō)axf文件相當(dāng)于輸入,bin文件相當(dāng)于輸出。我的axf文件也在Output文件夾的。
參考命令:.\Output\MY_STM32.axf
介紹了這些基本知識(shí)后,我們可以來(lái)實(shí)現(xiàn)BootLoader了。
4. 分幾步實(shí)現(xiàn)BootLoader有了前面的基礎(chǔ)知識(shí)后,應(yīng)該是比較容易理解BootLoader需要怎么實(shí)現(xiàn)了。這一章,我們分幾個(gè)步驟,一步一步實(shí)現(xiàn)BootLoader。
4.1 跑FAT文件系統(tǒng)我們的BootLoader是從SD卡更新程序的,把在電腦上編譯后的App程序,也就是bin文件,復(fù)制到SD卡中,然后讓單片機(jī)讀取相應(yīng)的bin文件,就可以實(shí)現(xiàn)程序的更新。需要注意的是,App程序需要修改ROM的起始地址,再編譯,并且要生成bin文件才支持正常下載。
我跑的文件系統(tǒng)是FATFS_R0.07c,很經(jīng)典的一個(gè)版本。如果大家對(duì)文件系統(tǒng)方面不了解的話,請(qǐng)自己網(wǎng)上查找教程,或者說(shuō)很多同學(xué)對(duì)這一步應(yīng)該已經(jīng)很熟悉啦。
只要單片機(jī)上實(shí)現(xiàn)讀取bin文件,結(jié)合Flash寫(xiě)入程序,就可以實(shí)現(xiàn)程序更新。下面介紹讀寫(xiě)Flash。
4.2 讀寫(xiě)Flash程序要實(shí)現(xiàn)BootLoader,還有一個(gè)前提是可以寫(xiě)入Flash了。如果是STM32單片機(jī)的話是很容易實(shí)現(xiàn)的,因?yàn)槲覀冇泄俜綆?kù)。本人使用的是3.0.0版本,參考官方例程,很容易實(shí)現(xiàn)Flash的讀寫(xiě),這里同樣是為了實(shí)現(xiàn)BootLoader簡(jiǎn)單介紹一下。
4.2.1 Flash寫(xiě)入步驟l 解鎖Flash
l 擦除Flash
l 寫(xiě)入Flash
l 驗(yàn)證讀寫(xiě)是否正確
4.2.2 讀寫(xiě)Flash調(diào)用的庫(kù)函數(shù)l voidFLASH_Unlock(void) Flash解鎖
l FLASH_Status FLASH_ErasePage(uint32_tPage_Address) Flash擦除
l FLASH_Status FLASH_ProgramWord(uint32_t Address, uint32_tData) Flash寫(xiě)入
4.2.3 實(shí)現(xiàn)Flash讀寫(xiě)稍微封裝一下STM32的官方庫(kù)函數(shù),就能實(shí)現(xiàn)Flash的讀寫(xiě),并驗(yàn)證讀寫(xiě)是否正確,具體我實(shí)現(xiàn)的接口函數(shù)為以下截圖,大家可以參考一下:
來(lái)到這里,我們可以實(shí)現(xiàn)在bin文件寫(xiě)入Flash了,寫(xiě)入完后,就要跳轉(zhuǎn)到App程序執(zhí)行了,接下來(lái)繼續(xù)介紹。
4.3 跳轉(zhuǎn)到新程序運(yùn)行 這一節(jié)要結(jié)合上面提到過(guò)的,Cortex-M3啟動(dòng)做了什么事情,然后我們的BootLoader下載App程序后,App程序就需要做同樣的事情。主要有三個(gè)步驟,其中BootLoader程序需要做的是:
l 跳轉(zhuǎn)到復(fù)位向量
App需要做的是:
l 重定位中斷向量表
l 設(shè)置棧指針
4.3.1 跳轉(zhuǎn)到復(fù)位向量BootLoader程序需要做的是跳轉(zhuǎn)到復(fù)位向量,具體實(shí)現(xiàn)可以參考以下代碼。
( (void (*)()) (Reset))(); //跳轉(zhuǎn)到復(fù)位向量
注意( (void (*)()) (Reset) )();是一去就不返回的,執(zhí)行完這條語(yǔ)句,單片機(jī)就直接跳轉(zhuǎn)到App程序運(yùn)行的,所以BootLoader程序下載完App后,做一些簡(jiǎn)單的處理(根據(jù)自己的應(yīng)用,也可以不做任何處理),就用這條語(yǔ)句跳轉(zhuǎn)到App執(zhí)行。
4.3.2 App開(kāi)始運(yùn)行BootLoader跳轉(zhuǎn)到App后,App需要做的是先設(shè)置棧指針,然后重定位中斷向量表地址,具體可以參考以下代碼。
__set_MSP( Msp); //設(shè)置棧指針
NVIC_SetVectorTable( base, offset); //重定位中斷向量表
其中Msp是棧指針,也就是中斷向量表第一個(gè)字的內(nèi)容,我們這里的內(nèi)容是*((uint32_t)(0x08070000) )。
base是中斷向量表的基地址,一般情況下就是ROM的起始地址,這里是0x08070000。
至此,BootLoader實(shí)現(xiàn)步驟完了,相信熟悉了這幾個(gè)步驟后,大家可以自己給自己的單片機(jī)寫(xiě)個(gè)BootLoader。順便說(shuō)一下,Cortex-M4的BootLoader跟Cortex-M3幾乎是一樣的。我在STM32上的實(shí)現(xiàn)完全是參考自己上次在飛思卡爾Cortex-M4上的實(shí)現(xiàn)。下面說(shuō)一下我的主函數(shù)吧,我們?cè)倏纯淳唧w的BootLoader流程,再熟悉一下BootLoader。
5.Bootloader具體流程 先看看我的主函數(shù),再啰嗦一下具體流程,可能有的同學(xué)已經(jīng)有點(diǎn)厭煩啦,其實(shí)感覺(jué)有點(diǎn)多余。
5.1 主函數(shù)流程先看截圖。
主函數(shù)的流程如下所示:
l 時(shí)鐘初始化
l LED初始化(無(wú)關(guān)緊要)
l 調(diào)試接口初始化(無(wú)關(guān)緊要)
l Flash初始化(解鎖Flash)
l FAT初始化(掛載文件系統(tǒng))
l 我們的BootLoader(重點(diǎn),下面展開(kāi)繼續(xù)介紹)
l 主循環(huán)(實(shí)際不會(huì)運(yùn)行到這里)
然后在具體講解BootLoader_FromSDCard函數(shù),這就是我們的重點(diǎn),傳說(shuō)中STM32的BootLoader從SD卡更新固件。
5.2 BootLoader流程老樣子,先上截圖:
具體流程如下所示:
l 打開(kāi)bin文件,檢查文件打開(kāi)是否正確
l 設(shè)置Flash下載起始地址(App程序起始地址)
l 讀取bin文件,檢查讀取是否正確
l 獲取棧指針SP和復(fù)位向量PC
l 進(jìn)入循環(huán)(這里是第5步),條件為如果讀取bin文件字節(jié)數(shù)不為零
l 將讀取到的bin寫(xiě)入Flash,并判寫(xiě)入狀態(tài)
l 調(diào)整Flash地址,根據(jù)寫(xiě)入字節(jié)調(diào)整
l 繼續(xù)讀取bin文件,檢查讀取是否正確,回到5繼續(xù)循環(huán)
來(lái)到這里已經(jīng)是退出循環(huán)了,也就是說(shuō)我們已經(jīng)將bin寫(xiě)入Flash完成了,準(zhǔn)備跳轉(zhuǎn)到新程序運(yùn)行
5.3 跳轉(zhuǎn)到新程序流程其實(shí)上面已經(jīng)講過(guò)了,這里繼續(xù)啰嗦,截圖:
l 重定位中斷向量
l 設(shè)置棧指針
l 跳轉(zhuǎn)到復(fù)位向量(開(kāi)始運(yùn)行App程序)
說(shuō)明一下,在這里重定位中斷向量其實(shí)是多余的,App程序執(zhí)行初始化后,又回到STM32初始狀態(tài),所以在App程序中需要執(zhí)行重定位中斷向量表操作,具體同以上操作相同。
啰嗦了又一遍,BootLoader完全結(jié)束,感謝大家都支持啦~
附錄A 主函數(shù)
#include "main.h"
int main(void)
{
SystemInit(); //配置系統(tǒng)時(shí)鐘為72M
LED_GPIO_Config(); //初始化LED端口
Debug_TraceIOEnable(); //使能調(diào)試printf的IO口
Flash_Init(); //初始化Flash
FAT_Init(); //初始化文件系統(tǒng)
BootLoader_FromSDCard(); //Bootloader從SD卡更新固件
while(1)
{
LED_StatShow( FuncErr); //LED顯示Bootloader狀態(tài)
}
}
附錄B 更新說(shuō)明
l 版本:V1.01
l 時(shí)間:2014-4-8
l 作者:coolweedman
l 更新:說(shuō)明Bootloader程序和App程序需要配合才能實(shí)現(xiàn)BootLoader,App程序需要重定位中斷向量表
l 特別感謝:網(wǎng)友cary_yingj的研究和分享
參考文獻(xiàn)
[1] 《CM3權(quán)威指南CnR2》Joseph Yiu 著 宋巖 譯
[2] ST官方庫(kù)3.0.0
[3] 《C和指針》KennethA. Reek著 徐波譯
[4] FATFS文件系統(tǒng)
[5] 其他互聯(lián)網(wǎng)資料
作者: srz1play 時(shí)間: 2016-7-28 16:39
不錯(cuò)的
作者: messicss 時(shí)間: 2016-8-25 21:57
贊一個(gè)!
作者: yunqingabc 時(shí)間: 2016-10-17 22:06
感謝樓主分享的文章,專門注冊(cè)個(gè)號(hào),頂貼!
作者: yq97723997 時(shí)間: 2016-10-17 22:50
謝謝分享了
作者: zhslcd 時(shí)間: 2016-10-20 09:52
21icbbs 上有這些資料
作者: zuiyunge 時(shí)間: 2016-12-12 08:56
不錯(cuò),紫薯,補(bǔ)丁
作者: XIAOXIAOYU 時(shí)間: 2016-12-20 18:13
寫(xiě)的不錯(cuò)!多謝樓主!
作者: 白努力 時(shí)間: 2016-12-22 17:26
很好學(xué)習(xí)了
作者: dzxqyt 時(shí)間: 2017-1-7 15:06
感謝樓主分享的文章,專門注冊(cè)個(gè)號(hào),頂貼!
作者: 35mickey 時(shí)間: 2017-10-10 19:29
看完樓主的帖子,思路非常清晰,受益匪淺
作者: a370306531 時(shí)間: 2018-3-2 21:06
感謝分享,,,,
作者: zhangchangsheng 時(shí)間: 2018-3-28 13:56
贊一個(gè)!
作者: 神出沒(méi) 時(shí)間: 2020-7-4 09:50
寫(xiě)的不錯(cuò),不過(guò)想請(qǐng)教個(gè)問(wèn)題。有些程序是在APP中有一個(gè)系統(tǒng)升級(jí)的選項(xiàng),點(diǎn)進(jìn)去,找到SD卡的固件進(jìn)行升級(jí)。這樣是不是bootloader和APP是二合一的,flash空間夠用嗎,這種是怎么實(shí)現(xiàn)的?有人這樣做嗎,求教
作者: MikeCai 時(shí)間: 2020-7-6 15:01
感恩樓主分享,學(xué)習(xí)收藏
歡迎光臨 (http://www.torrancerestoration.com/bbs/) |
Powered by Discuz! X3.1 |