?
一、環(huán)境介紹
二、 IAP介紹
IAP,全稱是“In-Application Programming”,中文解釋為“在程序中編程”。IAP是一種對(duì)通過(guò)微控制器的對(duì)外接口(如USART,IIC,CAN,USB,以太網(wǎng)接口甚至是無(wú)線射頻通道)對(duì)正在運(yùn)行程序的微控制器進(jìn)行內(nèi)部程序的更新的技術(shù)(注意這完全有別于ICP或者ISP技術(shù))。
ICP(In-Circuit Programming)技術(shù)即通過(guò)在線仿真器對(duì)單片機(jī)進(jìn)行程序燒寫(xiě),而ISP技術(shù)則是通過(guò)單片機(jī)內(nèi)置的bootloader程序引導(dǎo)的燒寫(xiě)技術(shù)。無(wú)論是ICP技術(shù)還是ISP技術(shù),都需要有機(jī)械性的操作如連接下載線,設(shè)置跳線帽等。若產(chǎn)品的電路板已經(jīng)層層密封在外殼中,要對(duì)其進(jìn)行程序更新無(wú)疑困難重重,若產(chǎn)品安裝于狹窄空間等難以觸及的地方,更是一場(chǎng)災(zāi)難。但若進(jìn)引入了IAP技術(shù),則完全可以避免上述尷尬情況,而且若使用遠(yuǎn)距離或無(wú)線的數(shù)據(jù)傳輸方案,甚至可以實(shí)現(xiàn)遠(yuǎn)程編程和無(wú)線編程。這絕對(duì)是ICP或ISP技術(shù)無(wú)法做到的。某種微控制器支持IAP技術(shù)的首要前提是其必須是基于可重復(fù)編程閃存的微控制器。STM32微控制器帶有可編程的內(nèi)置閃存,同時(shí)STM32擁有在數(shù)量上和種類上都非常豐富的外設(shè)通信接口,因此在STM32上實(shí)現(xiàn)IAP技術(shù)是完全可行的。
實(shí)現(xiàn)IAP技術(shù)的核心是一段預(yù)先燒寫(xiě)在單片機(jī)內(nèi)部的IAP程序。這段程序主要負(fù)責(zé)與外部的上位機(jī)軟件進(jìn)行握手同步,然后將通過(guò)外設(shè)通信接口將來(lái)自于上位機(jī)軟件的程序數(shù)據(jù)接收后寫(xiě)入單片機(jī)內(nèi)部指定的閃存區(qū)域,然后再跳轉(zhuǎn)執(zhí)行新寫(xiě)入的程序,最終就達(dá)到了程序更新的目的。
在STM32微控制器上實(shí)現(xiàn)IAP程序之前首先要回顧一下STM32的內(nèi)部閃存組織架構(gòu)和其啟動(dòng)過(guò)程。STM32的內(nèi)部閃存地址起始于0x8000000,一般情況下,程序文件就從此地址開(kāi)始寫(xiě)入。此外STM32是基于Cortex-M3內(nèi)核的微控制器,其內(nèi)部通過(guò)一張“中斷向量表”來(lái)響應(yīng)中斷,程序啟動(dòng)后,將首先從“中斷向量表”取出復(fù)位中斷向量執(zhí)行復(fù)位中斷程序完成啟動(dòng)。而這張“中斷向量表”的起始地址是0x8000004,當(dāng)中斷來(lái)臨,STM32的內(nèi)部硬件機(jī)制亦會(huì)自動(dòng)將PC指針定位到“中斷向量表”處,并根據(jù)中斷源取出對(duì)應(yīng)的中斷向量執(zhí)行中斷服務(wù)程序。最后還需要知道關(guān)鍵的一點(diǎn),通過(guò)修改STM32工程的鏈接腳本可以修改程序文件寫(xiě)入閃存的起始地址。
在STM32微控制器上實(shí)現(xiàn)IAP方案,除了常規(guī)的串口接收數(shù)據(jù)以及閃存數(shù)據(jù)寫(xiě)入等常規(guī)操作外,還需注意STM32的啟動(dòng)過(guò)程和中斷響應(yīng)方式。
下圖顯示了STM32常規(guī)的運(yùn)行流程:
?
?
圖解讀如下:
1、 STM32復(fù)位后,會(huì)從地址為0x8000004處取出復(fù)位中斷向量的地址,并跳轉(zhuǎn)執(zhí)行復(fù)位中斷服務(wù)程序。
2、 復(fù)位中斷服務(wù)程序執(zhí)行的最終結(jié)果是跳轉(zhuǎn)至C程序的main函數(shù),而main函數(shù)應(yīng)該是一個(gè)死循環(huán),是一個(gè)永不返回的函數(shù)。
3、 在main函數(shù)執(zhí)行的過(guò)程中,發(fā)生了一個(gè)中斷請(qǐng)求,此時(shí)STM32的硬件機(jī)制會(huì)將PC指針強(qiáng)制指回中斷向量表處。
4、 根據(jù)中斷源進(jìn)入相應(yīng)的中斷服務(wù)程序。
5、 中斷服務(wù)程序執(zhí)行完畢后,程序再度返回至main函數(shù)中執(zhí)行。
若在STM32中加入了IAP程序:
?
1、 STM32復(fù)位后,從地址為0x8000004處取出復(fù)位中斷向量的地址,并跳轉(zhuǎn)執(zhí)行復(fù)位中斷服務(wù)程序,隨后跳轉(zhuǎn)至IAP程序的main函數(shù)。
2、 執(zhí)行完IAP過(guò)程后(STM32內(nèi)部多出了新寫(xiě)入的程序,地址始于0x8000004+N+M)跳轉(zhuǎn)至新寫(xiě)入程序的復(fù)位向量表,取出新程序的復(fù)位中斷向量的地址,并跳轉(zhuǎn)執(zhí)行新程序的復(fù)位中斷服務(wù)程序,隨后跳轉(zhuǎn)至新程序的main函數(shù)。新程序的main函數(shù)應(yīng)該也具有永不返回的特性。同時(shí)應(yīng)該注意在STM32的內(nèi)部存儲(chǔ)空間在不同的位置上出現(xiàn)了2個(gè)中斷向量表。
3、 在新程序main函數(shù)執(zhí)行的過(guò)程中,一個(gè)中斷請(qǐng)求來(lái)臨,PC指針仍會(huì)回轉(zhuǎn)至地址為0x8000004中斷向量表處,而并不是新程序的中斷向量表,注意到這是由STM32的硬件機(jī)制決定的。
4、 根據(jù)中斷源跳轉(zhuǎn)至對(duì)應(yīng)的中斷服務(wù),注意此時(shí)是跳轉(zhuǎn)至了新程序的中斷服務(wù)程序中。
5、 中斷服務(wù)執(zhí)行完畢后,返回main函數(shù)。
二、hex文件與bin文件區(qū)別
Intel HEX文件是記錄文本行的ASCII文本文件,在Intel HEX文件中,每一行是一個(gè)HEX記錄,由十六進(jìn)制數(shù)組成的機(jī)器碼或者數(shù)據(jù)常量。Intel HEX文件經(jīng)常被用于將程序或數(shù)據(jù)傳輸存儲(chǔ)到ROM、EPROM,大多數(shù)編程器和模擬器使用Intel HEX文件。
很多編譯器的支持生成HEX格式的燒錄文件,尤其是Keil c。但是編程器能夠下載的往往是BIN格式,因此HEX轉(zhuǎn)BIN是每個(gè)編程器都必須支持的功能。HEX格式文件以行為單位,每行由“:”(0x3a)開(kāi)始,以回車鍵結(jié)束(0x0d,0x0a)。行內(nèi)的數(shù)據(jù)都是由兩個(gè)字符表示一個(gè)16進(jìn)制字節(jié),比如”01”就表示數(shù)0x01;”0a”,就表示0x0a。對(duì)于16位的地址,則高位在前低位在后,比如地址0x010a,在HEX格式文件中就表示為字符串”010a”。hex和bin文件格式
Hex文件,這里指的是Intel標(biāo)準(zhǔn)的十六進(jìn)制文件,也就是機(jī)器代碼的十六進(jìn)制形式,并且是用一定文件格式的ASCII碼來(lái)表示。具體格式介紹如下: Intel hex 文件常用來(lái)保存單片機(jī)或其他處理器的目標(biāo)程序代碼。它保存物理程序存儲(chǔ)區(qū)中的目標(biāo)代碼映象。一般的編程器都支持這種格式。 hex和bin文件格式Hex文件,這里指的是Intel標(biāo)準(zhǔn)的十六進(jìn)制文件,也就是機(jī)器代碼的十六進(jìn)制形式,并且是用一定文件格式的ASCII碼來(lái)表示。具體格式介紹如下: Intel hex 文件常用來(lái)保存單片機(jī)或其他處理器的目標(biāo)程序代碼。它保存物理程序存儲(chǔ)區(qū)中的目標(biāo)代碼映象。一般的編程器都支持這種格式。
三、使用Keil軟件完成hex文件轉(zhuǎn)bin文件
?
?
選項(xiàng)框里的代碼:
C:\app_setup\for_KEIL\ARM\ARMCC\bin\fromelf.exe --bin -o ./OBJECT/STM32_MD.bin ./OBJECT/STM32_MD.axf
解析如下:
C:\app_setup\for_KEIL\ARM\ARMCC\bin\fromelf.exe:是keil軟件安裝目錄下的一個(gè)工具,用于生成bin
--bin -o ./OBJECT/STM32_MD.bin :指定生成bin文件的目錄和名稱
./OBJECT/STM32_MD.axf :指定輸入的文件. 生成hex文件需要axf文件
新工程的編譯指令:
C:\Keil_v5\ARM\ARMCC\bin\fromelf.exe --bin -o ./obj/STM32HD.bin ./obj/STM32HD.axf
?
?
將該文件下載到STM32內(nèi)置FLASH,復(fù)位開(kāi)發(fā)板,即可啟動(dòng)程序。
四、 使用win hex軟件將bin文件搞成數(shù)組
?
?
生成數(shù)組之后,可以直接將數(shù)組編譯到程序里,然后使用STM32內(nèi)置FLASH編程代碼,將該程序燒寫(xiě)到內(nèi)置FLASH里,再?gòu)?fù)位開(kāi)發(fā)板即可運(yùn)行新的程序。
五、 Keil編譯程序大小計(jì)算
?
Program Size: Code=x RO-data=x RW-data=x ZI-data=x 的含義
- Code(代碼): 程序所占用的FLASH大小,存儲(chǔ)在FLASH.
2. RO-data(只讀的數(shù)據(jù)): Read-only-data,程序定義的常量,如const型,存儲(chǔ)在FLASH中。
3. RW-data(有初始值要求的、可讀可寫(xiě)的數(shù)據(jù)):
4. Read-write-data,已經(jīng)被初始化的變量,存儲(chǔ)在FLASH中。初始化時(shí)RW-data從flash拷貝到SRAM。
5. ZI-data:Zero-Init-data,未被初始化的可讀寫(xiě)變量,存儲(chǔ)在SRAM中。ZI-data不會(huì)被算做代碼里因?yàn)椴粫?huì)被初始化。
ROM(Flash) size = Code + RO-data + RW-data;
RAM size = RW-data + ZI-data
簡(jiǎn)單的說(shuō)就是在燒寫(xiě)的時(shí)候是FLASH中的被占用的空間為:Code+RO Data+RW Data
程序運(yùn)行的時(shí)候,芯片內(nèi)部RAM使用的空間為: RW Data + ZI Data
六、工程編譯信息與堆棧信息查看
?
對(duì)于沒(méi)有OS的程序,堆棧大小是在 startup.s 里設(shè)置的: Stack_Size EQU 0x00000800
對(duì)于使用用 uCos 的系統(tǒng),OS自帶任務(wù)的堆棧,在 os_cfg.h 里定義:
/* ——————— TASK STACK SIZE ———————- */
#define OS_TASK_TMR_STK_SIZE 128 /* Timer task stack size (# of OS_STK wide entries) */
#define OS_TASK_STAT_STK_SIZE 128 /* Statistics task stack size (# of OS_STK wide entries) */
#define OS_TASK_IDLE_STK_SIZE 128 /* Idle task stack size (# of OS_STK wide entries) */
用戶程序的任務(wù)堆棧,在 app_cfg.h 里定義:
#define APP_TASK_MANAGER_STK_SIZE 512
#define APP_TASK_GSM_STK_SIZE 512
#define APP_TASK_OBD_STK_SIZE 512
#define OS_PROBE_TASK_STK_SIZE 128
總結(jié):
1, 合理設(shè)置堆棧很重要
2, 多種方法結(jié)合,相互核對(duì)、校驗(yàn)
3, 盡量避免大數(shù)組,如果一定要用,盡量定義為 全局變量,使其不占用堆??臻g, 如果函數(shù)有重入可能性,則要注意保護(hù)。
七、實(shí)現(xiàn)STM32在線升級(jí)程序
7.1 升級(jí)的思路與步驟
1. 首先得完成STM32內(nèi)置FLASH編程操作
2. 將(升級(jí)的程序)新的程序編譯生成bin文件(編譯之前需要在Keil軟件里設(shè)置FLASH的起始位置)
3. 創(chuàng)建一個(gè)專門用于升級(jí)的boot程序(IAP Bootloader)
4. 使用網(wǎng)絡(luò)、串口、SD卡等方式接收到bin文件,再將bin文件燒寫(xiě)到STM32內(nèi)置FLASH里
5. 設(shè)置主堆棧指針
6. 將用戶代碼區(qū)第二個(gè)字(第4個(gè)字節(jié))為程序開(kāi)始地址(強(qiáng)制轉(zhuǎn)為函數(shù)指針)
7. 執(zhí)行函數(shù),進(jìn)行程序跳轉(zhuǎn)
7.2 待升級(jí)的程序FLASH起始設(shè)置
Bootloader的程序大小先固定為: 20KB,最好是越小越好,可以預(yù)留更加多的空間給APP程序使用。
20KB----->20480Byte-----> 0x5000 |
STM32內(nèi)置FLASH閃存的起始地址是: 0x08000000 ,大小是512KB。
現(xiàn)在將內(nèi)置FLASH閃存前20KB的空間留給Bootloader程序使用,后面剩下的空間就給APP程序使用。
APP程序的起始位置就可以設(shè)置為: 0x08000000+ 0x5000=0x08005000 剩余的大小就是: 512KB-20KB=492KB------>503808Byte-------->0x7B000 |
設(shè)置FLASH的起始位置(APP主程序):
?
中斷向量表偏移量設(shè)置
?
設(shè)置編譯bin文件
?
?
7.3 Bootloader的程序設(shè)置
//設(shè)置寫(xiě)入的地址,必須偶數(shù),因?yàn)閿?shù)據(jù)讀寫(xiě)都是按照2個(gè)字節(jié)進(jìn)行
#define FLASH_APP_ADDR 0x08005000 //應(yīng)用程序存放到FLASH中的起始地址
int main()
{
printf("UART1 OK.....\n");
printf("進(jìn)入IAP Bootloader程序!\n");
while(1)
{
key=KEY_Scanf();
if(key==1) //KEY1按下,寫(xiě)入STM32 FLASH
{
printf("正在更新IAP程序...............\n");
iap_write_appbin(FLASH_APP_ADDR,(u8*)app_bin_data,sizeof(app_bin_data));//燒寫(xiě)新的程序到內(nèi)置FLASH
printf("程序更新成功....\n");
iap_load_app(FLASH_APP_ADDR);//執(zhí)行FLASH APP代碼
}
}
}
/*
函數(shù)功能:跳轉(zhuǎn)到應(yīng)用程序段
appxaddr:用戶代碼起始地址.
*/
typedef void (*iap_function)(void); //定義一個(gè)函數(shù)類型的參數(shù).
void IAP_LoadApp(u32 app_addr)
{
//給函數(shù)指針賦值合法地址
jump2app=(iap_function)*(vu32*)(app_addr+4);//用戶代碼區(qū)第二個(gè)字為程序開(kāi)始地址(復(fù)位地址)
__set_MSP(*(vu32*)app_addr); //設(shè)置主堆棧指針
jump2app(); //跳轉(zhuǎn)到APP.
}
?
?
-
微控制器
+關(guān)注
關(guān)注
48文章
7596瀏覽量
151746 -
STM32
+關(guān)注
關(guān)注
2270文章
10915瀏覽量
356774 -
ISP
+關(guān)注
關(guān)注
6文章
478瀏覽量
51907 -
IIC
+關(guān)注
關(guān)注
11文章
302瀏覽量
38407 -
IAP
+關(guān)注
關(guān)注
2文章
164瀏覽量
24331
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論