一、什么是IAP,為什么要IAP
IAP即為In Application Programming(在應(yīng)用中編程),一般情況下,以STM32F10x系列芯片為主控制器的設(shè)備在出廠時(shí)就已經(jīng)使用J-Link仿真器將應(yīng)用代碼燒錄了,如果在設(shè)備使用過(guò)程中需要進(jìn)行應(yīng)用代碼的更換、升級(jí)等操作的話,則可能需要將設(shè)備返回原廠并拆解出來(lái)再使用J-Link重新燒錄代碼,這就增加了很多不必要的麻煩。站在用戶的角度來(lái)說(shuō),就是能讓用戶自己來(lái)更換設(shè)備里邊的代碼程序而廠家這邊只需要提供給用戶一個(gè)代碼文件即可。
而IAP卻能很好的解決掉這個(gè)難題,一片STM32芯片的Code(代碼)區(qū)內(nèi)一般只有一個(gè)用戶程序。而IAP方案則是將代碼區(qū)劃分為兩部分,兩部分區(qū)域各存放一個(gè)程序,一個(gè)叫bootloader(引導(dǎo)加載程序),另一個(gè)較user application(用戶應(yīng)用程序)。bootloader在出廠時(shí)就固定下來(lái)了,在需要變更user application時(shí)只需要通過(guò)觸發(fā)bootloader對(duì)userapplication的擦除和重新寫(xiě)入即可完成用戶應(yīng)用的更換。如圖所示
在程序執(zhí)行初始進(jìn)入bootloader,在bootloader里面檢測(cè)條件是否被觸發(fā)(可通過(guò)按鍵是否被按下、串口是否接收到特定的數(shù)據(jù)、U盤(pán)是否插入等等),如果有則進(jìn)行對(duì)user application進(jìn)行擦除和重新寫(xiě)入操作,如果沒(méi)有則直接跳轉(zhuǎn)到user application執(zhí)行應(yīng)用;如果有則進(jìn)行擦除用戶代碼并重新寫(xiě)入新的用戶代碼。
二、STM32F103ZET6硬件條件
STM32F103ZET6的啟動(dòng)方式有三種:內(nèi)置FLASH啟動(dòng)、內(nèi)置SRAM啟動(dòng)、系統(tǒng)存儲(chǔ)器ROM啟動(dòng),通過(guò)BOOT0和BOOT1引腳的設(shè)置可以選擇從哪中方式啟動(dòng),這里選擇內(nèi)置的FLASH啟動(dòng)。其FLASH的地址為0x08000000—0x0807 FFFF,共512KB,這些都能從芯片數(shù)據(jù)手冊(cè)中直接得到。而這里首要的一個(gè)問(wèn)題是中斷的問(wèn)題。
正常情況下發(fā)生中斷的過(guò)程為:發(fā)生中斷(中斷請(qǐng)求)到中斷向量表查找中斷函數(shù)入口地址跳轉(zhuǎn)到中斷函數(shù)執(zhí)行中斷函數(shù)中斷返回。也就是說(shuō)在STM32的內(nèi)置的Flash中有一個(gè)中斷向量表來(lái)存放各個(gè)中斷服務(wù)函數(shù)的入口地址,內(nèi)置Flash的分配情況大致如下圖。
在只有一個(gè)程序的情況下,程序執(zhí)行的走向應(yīng)該如圖所示。
STM32F10x有一個(gè)中斷向量表,這個(gè)中斷向量表存放在代碼開(kāi)始部分的后4個(gè)字節(jié)處(即0x0800 0004),代碼開(kāi)始的4個(gè)字節(jié)存放的是堆棧棧頂?shù)牡刂?,?dāng)發(fā)生中斷后程序通過(guò)查找該表得到相應(yīng)的中斷服務(wù)程序入口地址,然后再跳到相應(yīng)的中斷服務(wù)程序中執(zhí)行。上電后從0x08000004處取出復(fù)位中斷向量的地址,然后跳轉(zhuǎn)到復(fù)位中斷程序的入口(標(biāo)號(hào)①所示),執(zhí)行結(jié)束后跳轉(zhuǎn)到main函數(shù)中(標(biāo)號(hào)②所示)。
在執(zhí)行main函數(shù)的過(guò)程中發(fā)生中斷,則STM32強(qiáng)制將PC指針指回中斷向量表處(標(biāo)號(hào)③所示),從中斷向量表中找到相應(yīng)的中斷函數(shù)入口地址,跳轉(zhuǎn)到相應(yīng)的中斷服務(wù)函數(shù)(標(biāo)號(hào)④所示),執(zhí)行完中斷函數(shù)后再返回到main函數(shù)中來(lái)(標(biāo)號(hào)⑤所示)。
若在STM32F103x中使用IAP方案,則內(nèi)置的Flash分配情況大致如下圖
在內(nèi)置的Flash里面添加一個(gè)BootLoader程序,BootLoader程序和user application各有一個(gè)中斷向量表,假設(shè)BootLoader程序占用的空間為N+M字節(jié),則程序的走向應(yīng)該如下圖所示。
上電初始程序依然從0x08000004處取出復(fù)位中斷向量地址,執(zhí)行復(fù)位中斷函數(shù)后跳轉(zhuǎn)到IAP的main(標(biāo)號(hào)①所示),在IAP的main函數(shù)執(zhí)行完成后強(qiáng)制跳轉(zhuǎn)到0x08000004+N+M處(標(biāo)號(hào)②所示),最后跳轉(zhuǎn)到新的main函數(shù)中來(lái)(標(biāo)號(hào)③所示),當(dāng)發(fā)生中斷請(qǐng)求后,程序跳轉(zhuǎn)到新的中斷向量表中取出新的中斷函數(shù)入口地址,再跳轉(zhuǎn)到新的中斷服務(wù)函數(shù)中執(zhí)行(標(biāo)號(hào)④⑤所示),執(zhí)行完中斷函數(shù)后再返回到main函數(shù)中來(lái)(標(biāo)號(hào)⑥所示)。
對(duì)于步驟④⑤,網(wǎng)友認(rèn)為是:“在main執(zhí)行的過(guò)程中,如果CPU得到一個(gè)中斷請(qǐng)求,PC指針仍強(qiáng)制跳轉(zhuǎn)到地址0x08000004中斷向量表處,而不是新的中斷向量表,如圖標(biāo)號(hào)④所示,程序再根據(jù)我們?cè)O(shè)置的中斷向量表偏移量,跳轉(zhuǎn)到對(duì)應(yīng)中斷源新的中斷服務(wù)程序中,如圖標(biāo)號(hào)⑤所示”。我對(duì)此的理解是:“當(dāng)發(fā)生中斷后,程序從0x08000004(舊)處的中斷向量表中得到相應(yīng)的中斷服務(wù)函數(shù)入口地址,繼而跳轉(zhuǎn)到相應(yīng)的中斷服務(wù)程序”。但是舊的中斷向量列表里邊存放的是IAP程序中斷函數(shù)的入口地址,它是如何得到user程序中斷函數(shù)的入口地址呢?所以我覺(jué)得此種說(shuō)法是錯(cuò)誤的?!爱?dāng)發(fā)生中斷時(shí)PC指針強(qiáng)制會(huì)跳轉(zhuǎn)到0x08000004處”這種說(shuō)法并沒(méi)有錯(cuò),只是忽略了后續(xù)的一些知識(shí)要點(diǎn)而導(dǎo)致這個(gè)說(shuō)法出現(xiàn)矛盾。
對(duì)于步驟④⑤我認(rèn)為的是,在main函數(shù)的執(zhí)行過(guò)程中,如果CPU得到一個(gè)中斷請(qǐng)求,PC指針本來(lái)應(yīng)該跳轉(zhuǎn)到0x08000004處的中斷向量表,由于我們?cè)O(shè)置了中斷向量表偏移量為N+M,因此PC指針被強(qiáng)制跳轉(zhuǎn)到0x08000004+N+M處的中斷向量表中得到相應(yīng)的中斷函數(shù)地址(待求證),再跳轉(zhuǎn)到相應(yīng)新的中斷服務(wù)函數(shù),執(zhí)行結(jié)束后返回到main函數(shù)中來(lái)。
三、實(shí)現(xiàn)過(guò)程
STM32F103ZET6的Flash地址為0x08000000—0x0807 FFFF共512KB,把這512KB的空間分為兩塊,第一塊大小為32KB存放BootLoader程序,剩余的空間存放用戶程序(根據(jù)實(shí)際情況分配這兩塊空間的大小,BootLoader程序占用的空間越小越好,則BootLoader地址為0x08000000—0x08007fff,用戶程序地址為0x08008000—0x0807ffff。BootLoader流程圖大致應(yīng)該如下:
1、初始化時(shí)鐘
2、初始化中斷向量表地址
3、初始化按鍵(使用按鍵觸發(fā)方式,上電時(shí)如果按鍵被按下則進(jìn)行用戶程序更新操作)
4、初始化串口
5、檢測(cè)按鍵是否被按下,是則執(zhí)行步驟6,否則執(zhí)行步驟10
6、擦除用戶程序(擦除0x08008000—0x0807ffff地址空間Flash)
7、從串口讀取新的用戶代碼數(shù)據(jù),把代碼寫(xiě)入用戶程序空間
8、檢測(cè)串口數(shù)據(jù)接收完畢?是則執(zhí)行步驟9,否則跳回步驟7
9、用戶程序更新完畢,等待重新上電或硬件復(fù)位
10、跳轉(zhuǎn)到用戶程序(強(qiáng)制將PC指針跳轉(zhuǎn)到0x08008000+4處)
到這里首先要解決的問(wèn)題就有:
1、如何進(jìn)行對(duì)STM32的Flash進(jìn)行擦除和寫(xiě)入操作
2、中斷向量表偏移如何設(shè)置
3、如何改變代碼存放的地址空間(因?yàn)锽ootLoader要存放在0x08000000處,用戶程序要存放在0x08008000處,而默認(rèn)的代碼存放的地址空間為0x08000000)
4、怎么進(jìn)行PC指針的強(qiáng)制跳轉(zhuǎn),跳轉(zhuǎn)時(shí)需要做些什么
5、串口接收的用戶代碼數(shù)據(jù)是什么樣的代碼數(shù)據(jù),是一種什么樣的文件
問(wèn)題的解決:
1、使用STM32的固件庫(kù)函數(shù),只需調(diào)用幾個(gè)庫(kù)函數(shù)即可輕松解決,使用的固件庫(kù)為stm32f10x_flash.c文件,對(duì)Flash的操作過(guò)程簡(jiǎn)要為:Flash解鎖Flash擦除Flash寫(xiě)入Flash上鎖。
①解鎖:
FLASH_Unlock();//解鎖Flash FLASH_SetLatency(FLASH_Latency_2);//因?yàn)橄到y(tǒng)時(shí)鐘為72M所以要設(shè)置兩個(gè)時(shí)鐘周期的延時(shí)
②擦除:
for(i=0;i<240;i++) { if(FLASH_ErasePage(FLASH_ADDR+i*2048)?!=?FLASH_COMPLETE)//一定要判斷是否擦除成功 return?ERROR; }
說(shuō)明:FLASH_ErasePage(uint32_t Page_Address)即為Flash擦除操作,按頁(yè)擦除,每頁(yè)2KB,Page_Address為頁(yè)的起始地址,如0x08000000是第一頁(yè)起始地址,0x08000800為第二頁(yè)起始地址,這里的操作擦除了0x08008000—0x0807ffff地址空間的Flash。
③寫(xiě)入:
unsignedcharbuf[1024];//假設(shè)待寫(xiě)入的代碼數(shù)據(jù) unsignedshorttemp;//臨時(shí)數(shù)據(jù) for(i=0;i<512;i++) { ??temp?=?(buf[2*i+1]<<8)?|?buf[2*i];//2個(gè)字節(jié)整合為1個(gè)半字 ??if(FLASH_ProgramHalfWord(ADDR,temp)?!=?FLASH_COMPLETE)//判斷是否寫(xiě)入成功 ??{ ????????Return?ERROR; ??} ??ADDR?+=2;//地址要加2,因?yàn)槊看螌?xiě)入的是2個(gè)字節(jié)(1個(gè)半字) } ??
說(shuō)明:因?yàn)镾TM32的Flash寫(xiě)入為雙字節(jié)(1個(gè)半字)寫(xiě)入,F(xiàn)LASH_ProgramHalfWord(uint32_t Address, uint16_t Data)函數(shù)即為對(duì)地址為Address寫(xiě)入1個(gè)半字的Data,每次寫(xiě)入完成后地址要加2。
④上鎖:
FLASH_Lock();//Flash 上鎖,一個(gè)固件庫(kù)函數(shù)即可實(shí)現(xiàn)。
2、關(guān)于中斷向量表的偏移設(shè)置,對(duì)于BootLoader程序只需設(shè)置中斷向量表的指向在0x08000000處,對(duì)于用戶程序需要設(shè)置中斷向量表的指向在0x08008000處即可。
①在BootLoader程序的中斷向量表指向設(shè)置中應(yīng)有這么一句:
NVIC_SetVectorTable(NVIC_VectTab_FLASH,0x0);//設(shè)置中斷向量表指向
其中NVIC_VectTab_FLASH是個(gè)宏定義,的值為0x08000000。
②在用戶程序的中斷向量表指向設(shè)置用應(yīng)有這么一句:
NVIC_SetVectorTable(NVIC_VectTab_FLASH,0x8000);//設(shè)置中斷向量表指向
四、結(jié)束語(yǔ)
總的來(lái)說(shuō)STM32的IAP方案實(shí)現(xiàn)需要在進(jìn)行用戶程序之前加一段Bootloader程序,BootLoader程序的作用就是:
1、什么都不做,直接跳轉(zhuǎn)到用戶程序。
2、刪除原有的用戶程序,讀取*.bin文件數(shù)據(jù)并將數(shù)據(jù)重新寫(xiě)入新的用戶程序。對(duì)于用戶程序相比普通的編程只需要做三步改動(dòng)即可
3、改變中斷向量表。
4、改變代碼存放的地址空間
5、修改生成*.bin文件
使用通過(guò)UART的IAP方案并不是很好的選擇,這只是IAP方案的一個(gè)機(jī)制,因?yàn)槟苁褂肞C機(jī)通過(guò)串口升級(jí)程序,同樣能通過(guò)Jlink燒寫(xiě)程序,并且自定義的串口通訊協(xié)議在沒(méi)有校CRC校驗(yàn)的情況下不能及時(shí)發(fā)現(xiàn)數(shù)據(jù)傳輸過(guò)程發(fā)生的錯(cuò)誤。這里推薦使用SD卡(或U盤(pán))進(jìn)行用戶程序更新,將*.bin文件復(fù)制到SD卡(或U盤(pán))中,STM32再通過(guò)讀取SD卡(或U盤(pán))的*.bin文件進(jìn)行用戶程序更新,這也避免了STM32與PC笨重的通訊,只需插一個(gè)SD卡(或U盤(pán))更顯得人性化一些,但需要去弄懂STM32如何與SD卡(或U盤(pán))的通訊。
審核編輯:劉清
-
控制器
+關(guān)注
關(guān)注
112文章
16033瀏覽量
176658 -
存儲(chǔ)器
+關(guān)注
關(guān)注
38文章
7403瀏覽量
163395 -
STM32F103ZET6
+關(guān)注
關(guān)注
9文章
67瀏覽量
21045 -
STM32芯片
+關(guān)注
關(guān)注
0文章
38瀏覽量
4349
原文標(biāo)題:給你的代碼升個(gè)級(jí)?—IAP
文章出處:【微信號(hào):pzh_mcu,微信公眾號(hào):痞子衡嵌入式】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論