久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開始

搜索
查看: 3259|回復(fù): 0
打印 上一主題 下一主題
收起左側(cè)

Bootloader+3App 基于STM32的IAP設(shè)計(jì)文檔

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:287737 發(fā)表于 2018-3-5 14:14 | 只看該作者 回帖獎(jiǎng)勵(lì) |倒序?yàn)g覽 |閱讀模式
IAP在線升級(jí)資料。
Bootloader+3App
1 簡(jiǎn)介
2 Bootloader實(shí)現(xiàn)原理
3  APP實(shí)現(xiàn)與配置
3.1  APP1程序起始地址設(shè)置方法
3.2  中斷向量表的偏移量設(shè)置
3.3  *bin文件生成
3.4  步驟總結(jié)
4 關(guān)鍵點(diǎn)
附件:

1 簡(jiǎn)介
IAP(In Application Programming)即在應(yīng)用編程,IAP是用戶自己的程序在運(yùn)行過程中對(duì)User Flash的部分區(qū)域進(jìn)行燒寫,目的是為了在產(chǎn)品發(fā)布后可以方便地通過預(yù)留的通信口對(duì)產(chǎn)品中的固件程序進(jìn)行更新升級(jí)。通常實(shí)現(xiàn)IAP功能時(shí),即用戶程序運(yùn)行中作自身的更新操作,需要在設(shè)計(jì)固件程序時(shí)編寫兩個(gè)項(xiàng)目代碼,第一個(gè)項(xiàng)目程序不執(zhí)行正常的功能操作,而只是通過某種通信方式(如USB、USART)接收程序或數(shù)據(jù),執(zhí)行對(duì)第二部分代碼的更新;第二個(gè)項(xiàng)目代碼才是真正的功能代碼。這兩部分項(xiàng)目代碼都同時(shí)燒錄在User Flash中,當(dāng)芯片上電后,首先是第一個(gè)項(xiàng)目代碼開始運(yùn)行,它作如下操作:
1)檢查是否需要對(duì)第二部分代碼進(jìn)行更新
2)如果不需要更新則轉(zhuǎn)到4)
3)執(zhí)行更新操作
4)跳轉(zhuǎn)到第二部分代碼執(zhí)行
第一部分代碼必須通過其它手段,如JTAG或ISP燒入;第二部分代碼可以使用第一部分代碼IAP功能燒入,也可以和第一部分代碼一起燒入,以后需要程序更新是再通過第一部分IAP代碼更新。
              我們將第一個(gè)項(xiàng)目代碼稱之為Bootloader程序,第二個(gè)項(xiàng)目代碼稱之為APP程序,他們存放在STM32 FLASH的不同地址范圍,一般從最低地址區(qū)開始存放Bootloader,緊跟其后的就是APP程序(注意,如果FLASH容量足夠,是可以設(shè)計(jì)很多APP程序的,本章我們討論3個(gè)APP程序的情況)。這樣我們就是要實(shí)現(xiàn)4個(gè)程序:Bootloader和3個(gè)APP。

2 Bootloader實(shí)現(xiàn)原理
我們先來(lái)看看STM32正常的程序運(yùn)行流程,如圖2.1所示:
圖2.1 STM32正常運(yùn)行流程圖
STM32的內(nèi)部閃存(FLASH)地址起始于0x08000000,一般情況下,程序文件就從此地址開始寫入。此外STM32是基于Cortex-M3內(nèi)核的微控制器,其內(nèi)部通過一張“中斷向量表”來(lái)響應(yīng)中斷,程序啟動(dòng)后,將首先從“中斷向量表”取出復(fù)位中斷向量執(zhí)行復(fù)位中斷程序完成啟動(dòng),而這張“中斷向量表”的起始地址是0x08000004,當(dāng)中斷來(lái)臨,STM32的內(nèi)部硬件機(jī)制亦會(huì)自動(dòng)將PC指針定位到“中斷向量表”處,并根據(jù)中斷源取出對(duì)應(yīng)的中斷向量執(zhí)行中斷服務(wù)程序。
在圖2.1中,STM32在復(fù)位后,先從0X08000004地址取出復(fù)位中斷向量的地址,并跳轉(zhuǎn)到復(fù)位中斷服務(wù)程序,如圖標(biāo)號(hào)①所示;在復(fù)位中斷服務(wù)程序執(zhí)行完之后,會(huì)跳轉(zhuǎn)到我們的main函數(shù),如圖標(biāo)號(hào)②所示;而我們的main函數(shù)一般都是一個(gè)死循環(huán),在main函數(shù)執(zhí)行過程中,如果收到中斷請(qǐng)求(發(fā)生重中斷),此時(shí)STM32強(qiáng)制將PC指針指回中斷向量表處,如圖標(biāo)號(hào)③所示;然后,根據(jù)中斷源進(jìn)入相應(yīng)的中斷服務(wù)程序,如圖標(biāo)號(hào)④所示;在執(zhí)行完中斷服務(wù)程序以后,程序再次返回main函數(shù)執(zhí)行,如圖標(biāo)號(hào)⑤所示。
當(dāng)加入IAP程序之后,程序運(yùn)行流程如圖2.2所示:
圖2.2  加入IAP之后程序運(yùn)行流程圖
在圖2.2所示流程中,STM32復(fù)位后,還是從0X08000004地址取出復(fù)位中斷向量的地址,并跳轉(zhuǎn)到復(fù)位中斷服務(wù)程序,在運(yùn)行完復(fù)位中斷服務(wù)程序之后跳轉(zhuǎn)到IAP的main函數(shù),如圖標(biāo)號(hào)①所示,此部分同圖2.1一樣;在執(zhí)行完IAP以后(即將新的APP代碼寫入STM32的FLASH,灰底部分。新程序的復(fù)位中斷向量起始地址為0X08000004+N+M),跳轉(zhuǎn)至新寫入程序的復(fù)位向量表,取出新程序的復(fù)位中斷向量的地址,并跳轉(zhuǎn)執(zhí)行新程序的復(fù)位中斷服務(wù)程序,隨后跳轉(zhuǎn)至新程序的main函數(shù),如圖標(biāo)號(hào)②和③所示,同樣main函數(shù)為一個(gè)死循環(huán),并且注意到此時(shí)STM32的FLASH,在不同位置上,共有兩個(gè)中斷向量表。
在main函數(shù)執(zhí)行過程中,如果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)⑤所示;在執(zhí)行完中斷服務(wù)程序后,程序返回main函數(shù)繼續(xù)運(yùn)行,如圖標(biāo)號(hào)⑥所示。
通過以上兩個(gè)過程的分析,我們知道IAP程序必須滿足兩個(gè)要求:
1) 新程序必須在IAP程序之后的某個(gè)偏移量為x的地址開始;
2) 必須將新程序的中斷向量表相應(yīng)的移動(dòng),移動(dòng)的偏移量為x;

3  APP實(shí)現(xiàn)與配置
              本章設(shè)計(jì)3個(gè)APP的情況,因?yàn)榫褪欠峙涞膄lash扇區(qū)不同,所以就舉例其中的一個(gè)。
3.1  APP1程序起始地址設(shè)置方法
              隨便打開一個(gè)之前的實(shí)例工程,點(diǎn)擊Options for Target?Target選項(xiàng)卡,如圖3.1所示:
圖3.1 FLASH APP1 Target選項(xiàng)卡設(shè)置
              默認(rèn)的條件下,圖中IROM1的起始地址(Start)一般為0X08000000,大小(Size)為0X80000,即從0X08000000開始的512K空間為我們的程序存儲(chǔ)。而圖中,我們?cè)O(shè)置起始地址(Start)為0X08010000,即偏移量為0X10000(64K字節(jié)),因而,留給APP用的FLASH空間(Size)只有0X80000-0X10000=0X70000(448K字節(jié))大小了。設(shè)置好Start和Szie,就完成APP1程序的起始地址設(shè)置。
              APP2則為0X08020000+0X60000;
              App3則為0X08030000+0X50000;
              其實(shí)就是為每個(gè)app程序分配了4k的空間。

3.2  中斷向量表的偏移量設(shè)置
              之前我們講解過,在系統(tǒng)啟動(dòng)的時(shí)候,會(huì)首先調(diào)用systemInit函數(shù)初始化時(shí)鐘系統(tǒng),同時(shí)systemInit還完成了中斷向量表的設(shè)置,我們可以打開systemInit函數(shù),看看函數(shù)體的結(jié)尾處有這樣幾行代碼:
              #ifdef VECT_TAB_SRAM
SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET;
/* Vector Table Relocation in Internal SRAM. */
#else
SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET;
/* Vector Table Relocation in Internal FLASH. */
#endif
從代碼可以理解,VTOR寄存器存放的是中斷向量表的起始地址。默認(rèn)的情況VECT_TAB_SRAM是沒有定義,所以執(zhí)行SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; 對(duì)于FLASH APP,我們?cè)O(shè)置為FLASH_BASE+偏移量0x10000,所以我們可以在FLASH APP的main函數(shù)最開頭處添加如下代碼實(shí)現(xiàn)中斷向量表的起始地址的重設(shè):
              SCB->VTOR = FLASH_BASE | 0x10000;
              如果是APP2可以設(shè)置為SCB->VTOR = FLASH_BASE | 0x20000;
              如果是APP3可以設(shè)置為SCB->VTOR = FLASH_BASE | 0x30000;
這樣,我們就完成了中斷向量表偏移量的設(shè)置。
3.3  *bin文件生成
不過MDK默認(rèn)生成的文件是.hex文件,并不方便我們用作IAP更新,我們希望生成的文件是.bin文件,這樣可以方便進(jìn)行IAP升級(jí)。這里我們通過MDK自帶的格式轉(zhuǎn)換工具fromelf.exe,來(lái)實(shí)現(xiàn).axf文件到.bin文件的轉(zhuǎn)換。該工具在MDK的安裝目錄\ARM\BIN40文件夾里面。
本章,我們通過在MDK點(diǎn)擊Options for Target?User選項(xiàng)卡,在Run User Programs After Build/Rebuild 欄,勾選Run#1和DOS16,并寫入:D:\Keil3.80a\ARM\BIN40\fromelf.exe  --bin -o  ..\OBJ\TEST.bin ..\OBJ\TEST.axf,如圖3.2所示:
圖3.2 *bin文件生成設(shè)置
通過這一步設(shè)置,我們就可以在MDK編譯成功之后,調(diào)用fromelf.exe(注意,我的MDK是安裝在D:\Keil3.80A文件夾下,如果你是安裝在其他目錄,請(qǐng)根據(jù)你自己的目錄修改fromelf.exe的路徑),根據(jù)當(dāng)前工程的TEST.axf(如果是其他的名字,請(qǐng)記住修改,這個(gè)文件存放在OBJ目錄下面,格式為xxx.axf),生成一個(gè)TEST.bin的文件。并存放在axf文件相同的目錄下,即工程的OBJ文件夾里面。在得到.bin文件之后,我們只需要將這個(gè)bin文件傳送給單片機(jī),即可執(zhí)行IAP升級(jí)。
3.4  步驟總結(jié)
1) 設(shè)置APP程序的起始地址和存儲(chǔ)空間大小

2) 設(shè)置中斷向量表偏移量

3) 設(shè)置編譯后運(yùn)行fromelf.exe,生成.bin文件.



4 關(guān)鍵點(diǎn)
1) IAP程序必須滿足兩個(gè)要求:
1.新程序必須在IAP程序之后的某個(gè)偏移量為x的地址開始;
2.必須將新程序的中斷向量表相應(yīng)的移動(dòng),移動(dòng)的偏移量為x;

2)STM32是按照半字讀寫數(shù)據(jù)到FLASH里面,所以串口收發(fā)數(shù)據(jù)時(shí),必須設(shè)置一個(gè)收發(fā)完成標(biāo)志,只有數(shù)據(jù)全部接受后方可執(zhí)行更新。而且接收完成到收發(fā)數(shù)據(jù)之間也必須設(shè)置一個(gè)延時(shí)才行。
3)必須先更新后執(zhí)行,程序中相應(yīng)的設(shè)置一個(gè)標(biāo)志位。Flag。
重點(diǎn):一定要為每個(gè)app分配好偏移地址。
//保留0X08000000~0X0800FFFF的空間為IAP使用
#define FLASH_APP1_ADDR                            0x08010000                //第一個(gè)應(yīng)用程序起始地址(存放在FLASH)
#define FLASH_APP2_ADDR                            0x08020000                            //第二個(gè)應(yīng)用程序起始地址(存放在FLASH)
#define FLASH_APP3_ADDR                            0x08030000                            //第三個(gè)應(yīng)用程序起始地址(存放在FLASH)            

附件:
函數(shù)一:寫入指定起始地址的FLASH空間
//appxaddr:應(yīng)用程序的起始地址
//appbuf:應(yīng)用程序CODE.
//appsize:應(yīng)用程序大小(字節(jié)).
void iap_write_appbin(u32 appxaddr,u8 *appbuf,u32 appsize)
{
              u16 t;
              u16 i=0;
              u16 temp;
              u32 fwaddr=appxaddr;//當(dāng)前寫入的地址
              u8 *dfu=appbuf;
              for(t=0;t<appsize;t+=2)
              {                                                                                       
                            temp=(u16)dfu[1]<<8;
                            temp+=(u16)dfu[0];               
                            dfu+=2;//偏移2個(gè)字節(jié)
                            iapbuf[i++]=temp;                 
                            if(i==1024)
                            {
                                          i=0;
                                          STMFLASH_Write(fwaddr,iapbuf,1024);            
                                          fwaddr+=2048;//偏移2048  16=2*8.所以要乘以2.
                            }
              }
              if(i)STMFLASH_Write(fwaddr,iapbuf,i);//將最后的一些內(nèi)容字節(jié)寫進(jìn)去.
}
函數(shù)二:跳轉(zhuǎn)執(zhí)行FLASH
//跳轉(zhuǎn)到應(yīng)用程序段
//appxaddr:用戶代碼起始地址.
void iap_load_app(u32 appxaddr)
{                 
              if(((*(vu32*)appxaddr)&0x2FFE0000)==0x20000000)              //檢查棧頂?shù)刂肥欠窈戏?
              {
                            jump2app=(iapfun)*(vu32*)(appxaddr+4);                            //用戶代碼區(qū)第二個(gè)字為程序開始地址(復(fù)位地址)                           
                            MSR_MSP(*(vu32*)appxaddr);                                                                      //初始化APP堆棧指針(用戶代碼區(qū)的第一個(gè)字用于存放棧頂?shù)刂?
                            jump2app();                                                                                                                              //跳轉(zhuǎn)到APP.
              }
}
函數(shù)三:串口中斷服務(wù)函數(shù)
              if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)//接收到數(shù)據(jù)
              {            
                  //USART_SendData(USART1, 'r');
                            res=USART_ReceiveData(USART1);
                            if(USART_RX_CNT<USART_REC_LEN)
                            {
                                          USART_RX_BUF[USART_RX_CNT]=res;
                                          USART_RX_CNT++;
                            }
              }


全局變量:
u8 USART_RX_BUF[USART_REC_LEN] __attribute__ ((at(0X20001000)));//串口接收緩沖,最大USART_REC_LEN個(gè)字節(jié),起始地址為0X20001000.
u16 USART_RX_STA=0;                     //接收狀態(tài)標(biāo)記               
u16 USART_RX_CNT=0;              //接收的字節(jié)數(shù)





分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏2 分享淘帖 頂 踩
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

手機(jī)版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表
主站蜘蛛池模板: 中文成人无字幕乱码精品 | 久久久精品一区二区三区 | 亚洲一区三区在线观看 | 成人a免费 | 极品粉嫩国产48尤物在线播放 | 一区二区三区高清在线观看 | 第一色在线 | 日韩一区二区黄色片 | 一区二区三区成人 | 亚洲精品一区二区三区蜜桃久 | 久久99精品久久久久久国产越南 | 精品一区精品二区 | 成人精品视频 | 精品一区二区三区在线观看国产 | 亚洲成人免费 | 久久精彩| 国产精品日韩欧美一区二区三区 | 日本精品一区二区三区视频 | 欧美日韩亚洲国产 | 91免费看片| 人人人人干 | 五月香婷婷 | 国产日韩欧美91 | 成人伊人网 | www.黄色网| 97福利在线 | 亚洲视频中文 | 久久成人国产精品 | 日本视频一区二区三区 | 成人免费视频在线观看 | 免费黄色在线 | 日韩免费三级 | 免费观看一级毛片 | 青久草视频 | 日韩精品一区二区三区老鸭窝 | 神马影院一区二区三区 | 日韩电影一区 | 精品视频一区在线 | 欧美日韩国产精品一区 | 亚洲高清视频在线 | 久久亚洲春色中文字幕久久久 |