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