串口IAP实验
IAP,即在應用編程。很多單片機都支持這個功能,STM32也不例外。在之前的FLASH模擬EEPROM實驗里面,我們學習了STM32的FLASH自編程,本章我們將結合FLASH自編程的知識,通過STM32的串口實現一個簡單的IAP功能。fficeffice" />
48.1 IAP簡介???
IAP(In Application Programming)即在應用編程,IAP是用戶自己的程序在運行過程中對User Flash的部分區域進行燒寫,目的是為了在產品發布后可以方便地通過預留的通信口對產品中的固件程序進行更新升級。 通常實現IAP功能時,即用戶程序運行中作自身的更新操作,需要在設計固件程序時編寫兩個項目代碼,
第一個項目程序不執行正常的功能操作,而只是通過某種通信方式(如USB、USART)接收程序或數據,執行對第二部分代碼的更新;第二個項目代碼才是真正的功能代碼。這兩部分項目代碼都同時燒錄在User Flash中,當芯片上電后,首先是第一個項目代碼開始運行,它作如下操作:
1)檢查是否需要對第二部分代碼進行更新
2)如果不需要更新則轉到4)
3)執行更新操作
4)跳轉到第二部分代碼執行
第一部分代碼必須通過其它手段,如JTAG或ISP燒入;第二部分代碼可以使用第一部分代碼IAP功能燒入,也可以和第一部分代碼一起燒入,以后需要程序更新是再通過第一部分IAP代碼更新。
我們將第一個項目代碼稱之為Bootloader程序,第二個項目代碼稱之為APP程序,他們存放在STM32 FLASH的不同地址范圍,一般從最低地址區開始存放Bootloader,
緊跟其后的就是APP程序(注意,如果FLASH容量足夠,是可以設計很多APP程序的,本章我們只討論一個APP程序的情況)。這樣我們就是要實現2個程序:Bootloader和APP。
STM32的APP程序不僅可以放到FLASH里面運行,也可以放到SRAM里面運行,本章,我們將制作兩個APP,一個用于FLASH運行,一個用于SRAM運行。
我們先來看看STM32正常的程序運行流程,如圖48.1.1所示:
?
圖48.1.1 STM32正常運行流程圖
?????? STM32的內部閃存(FLASH)地址起始于0x08000000,一般情況下,程序文件就從此地址開始寫入。此外STM32是基于Cortex-M3內核的微控制器,其內部通過一張“中斷向量表”
來響應中斷,程序啟動后,將首先從“中斷向量表”取出復位中斷向量執行復位中斷程序完成啟動,而這張“中斷向量表”的起始地址是0x08000004,當中斷來臨,STM32的內部硬
件機制亦會自動將PC指針定位到“中斷向量表”處,并根據中斷源取出對應的中斷向量執行中斷服務程序。
?????? 在圖48.1.1中,STM32在復位后,先從0X08000004地址取出復位中斷向量的地址,并跳轉到復位中斷服務程序,如圖標號①所示;在復位中斷服務程序執行完之后,會跳轉到我們
的main函數,如圖標號②所示;而我們的main函數一般都是一個死循環,在main函數執行過程中,如果收到中斷請求(發生重中斷),此時STM32強制將PC指針指回中斷向量表處,如圖標號③所示;然后,根據中斷源進入相應的中斷服務程序,如圖標號④所示;在執行完中斷服務程序以后,程序再次返回main函數執行,如圖標號⑤所示。
?????? 當加入IAP程序之后,程序運行流程如圖48.1.2所示:
?
?????? 在圖48.1.2所示流程中,STM32復位后,還是從0X08000004地址取出復位中斷向量的地址,并跳轉到復位中斷服務程序,在運行完復位中斷服務程序之后跳轉到IAP的main函數,
如圖標號①所示,此部分同圖48.1.1一樣;在執行完IAP以后(即將新的APP代碼寫入STM32的FLASH,灰底部分。新程序的復位中斷向量起始地址為0X08000004+N+M),跳轉至
新寫入程序的復位向量表,取出新程序的復位中斷向量的地址,并跳轉執行新程序的復位中斷服務程序,隨后跳轉至新程序的main函數,如圖標號②和③所示,同樣main函數為一個
死循環,并且注意到此時STM32的FLASH,在不同位置上,共有兩個中斷向量表。
?????? 在main函數執行過程中,如果CPU得到一個中斷請求,PC指針仍強制跳轉到地址0X08000004中斷向量表處,而不是新程序的中斷向量表,如圖標號④所示;程序再根據我們設置
的中斷向量表偏移量,跳轉到對應中斷源新的中斷服務程序中,如圖標號⑤所示;在執行完中斷服務程序后,程序返回main函數繼續運行,如圖標號⑥所示。
?????? 通過以上兩個過程的分析,我們知道IAP程序必須滿足兩個要求:
本章,我們有2個APP程序,一個為FLASH的APP,程序在FLASH中運行,另外一個位SRAM的APP,程序運行在SRAM中,圖48.1.2雖然是針對FLASH APP來說的,但是在
SRAM里面運行的過程和FLASH基本一致,只是需要設置向量表的地址為SRAM的地址。
1.APP程序起始地址設置方法
隨便打開一個之前的實例工程,點擊Options for TargetàTarget選項卡,如圖48.1.3所示:
圖48.1.3 FLASH APP Target選項卡設置
?????? 默認的條件下,圖中IROM1的起始地址(Start)一般為0X08000000,大小(Size)為0X80000,即從0X08000000開始的512K空間為我們的程序存儲(因為我們的STM32F103ZET6的
FLASH大小是512K)。而圖中,我們設置起始地址(Start)為0X08010000,即偏移量為0X10000(64K字節),因而,留給APP用的FLASH空間(Size)只有0X80000-0X10000=0X70000
(448K字節)大小了。設置好Start和Szie,就完成APP程序的起始地址設置。
?????? 這里的64K字節,需要大家根據Bootloader程序大小進行選擇,比如我們本章的Bootloader程序為22K左右,理論上我們只需要確保APP起始地址在Bootloader之后,
并且偏移量為0X200的倍數即可(相關知識,請參考:http://www.openedv.com/posts/list/392.htm)。這里我們選擇64K(0X10000)字節,留了一些余量,方便Bootloader以后的升級修改。
?????? 這是針對FLASH APP的起始地址設置,如果是SRAM APP,那么起始地址設置如圖48.1.4所示:
?
圖48.1.4 SRAM APP Target選項卡設置
?????? 這里我們將IROM1的起始地址(Start)定義為:0X20001000,大小為0XA000(40K字節),即從地址0X20000000偏移0X1000開始,存放APP代碼。因為整個STM32F103ZET6的
SRAM大小為64K字節,所以IRAM1(SRAM)的起始地址變為0X2000B000(0x20001000+0xA000=0X2000B000),大小只有0X5000(20K字節)。這樣,整個STM32F103ZET6的SRAM
分配情況為:最開始的4K給Bootloader程序使用,隨后的40K存放APP程序,最后20K,用作APP程序的內存。這個分配關系大家可以根據自己的實際情況修改,不一定和我們這里的設
置一模一樣,不過也需要注意,保證偏移量為0X200的倍數(我們這里為0X1000)。
?????? 2.中斷向量表的偏移量設置方法
?????? 之前我們講解過,在系統啟動的時候,會首先調用systemInit函數初始化時鐘系統,同時systemInit還完成了中斷向量表的設置,我們可以打開systemInit函數,看看函數體的結尾處有這樣幾行代碼:
#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寄存器存放的是中斷向量表的起始地址。默認的情況VECT_TAB_SRAM是沒有定義,所以執行SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; ?
對于FLASH APP,我們設置為FLASH_BASE+偏移量0x10000,所以我們可以在FLASH APP的main函數最開頭處添加如下代碼實現中斷向量表的起始地址的重設:
SCB->VTOR = FLASH_BASE | 0x10000;
?????? 以上是FLASH APP的情況,當使用SRAM APP的時候,我們設置起始地址為:SRAM_bASE+0x1000,同樣的方法,我們在SRAM APP的main函數最開始處,添加下面代碼:
SCB->VTOR = SRAM_BASE | 0x1000;
?????? 這樣,我們就完成了中斷向量表偏移量的設置。
通過以上兩個步驟的設置,我們就可以生成APP程序了,只要APP程序的FLASH和SRAM大小不超過我們的設置即可。不過MDK默認生成的文件是.hex文件,并不方便我
們用作IAP更新,我們希望生成的文件是.bin文件,這樣可以方便進行IAP升級(至于為什么,請大家自行百度HEX和BIN文件的區別!)。這里我們通過MDK自帶的格式轉換
工具fromelf.exe,來實現.axf文件到.bin文件的轉換。該工具在MDK的安裝目錄\ARM\BIN40文件夾里面。
fromelf.exe轉換工具的語法格式為:fromelf [options] input_file。其中options有很多選項可以設置,詳細使用請參考光盤《mdk如何生成bin文件.pdf》.
本章,我們通過在MDK點擊Options for TargetàUser選項卡,在Run User Programs After Build/Rebuild 欄,勾選Run#1和DOS16,并寫入:D:\Keil3.80a\ARM\BIN40\fromelf.exe? --bin -o? ..\OBJ\TEST.bin ..\OBJ\TEST.axf ,如圖48.1.6所示:
?
?????? 通過這一步設置,我們就可以在MDK編譯成功之后,調用fromelf.exe(注意,我的MDK是安裝在D:\Keil3.80A文件夾下,如果你是安裝在其他目錄,請根據你
自己的目錄修改fromelf.exe的路徑),根據當前工程的TEST.axf(如果是其他的名字,請記住修改,這個文件存放在OBJ目錄下面,格式為xxx.axf),生成一個
TEST.bin的文件。并存放在axf文件相同的目錄下,即工程的OBJ文件夾里面。在得到.bin文件之后,我們只需要將這個bin文件傳送給單片機,即可執行IAP升級。
?????? 最后再來APP程序的生成步驟:
對于在FLASH里面運行的APP程序,我們可以按照圖48.1.3的設置。對于SRAM里面運行的APP程序,我們可以參考圖48.1.4的設置。
這一步按照上面講解,重新設置SCB->VTOR的值即可。
通過在User選項卡,設置編譯后調用fromelf.exe,根據.axf文件生成.bin文件,用于IAP更新。?
以上3個步驟,我們就可以得到一個.bin的APP程序,通過Bootlader程序即可實現更新。
大家可以打開我們光盤的兩個APP工程,熟悉這些設置。
48.2 硬件設計
本章實驗(Bootloader部分)功能簡介:開機的時候先顯示提示信息,然后等待串口輸入接收APP程序(無校驗,一次性接收),在串口接收到APP程序
之后,即可執行IAP。如果是SRAM APP,通過按下KEY0即可執行這個收到的SRAM APP程序。如果是FLASH APP,則需要先按下WK_UP按鍵,將串口接
收到的APP程序存放到STM32的FLASH,之后再按KEY2既可以執行這個FLASH APP程序。通過KEY1按鍵,可以手動清除串口接收到的APP程序。DS0用于指示程序運行狀態。
本實驗用到的資源如下:
這些用到的硬件,我們在之前都已經介紹過,這里就不再介紹了。
48.3 軟件設計
本章,我們總共需要3個程序:1,Bootloader;2,FLASH APP;3)SRAM APP;其中,我們選擇之前做過的RTC實驗(在第二十章介紹)來做為FLASH APP程序
(起始地址為0X08010000),選擇觸摸屏實驗(在第三十一章介紹)來做SRAM APP程序(起始地址為0X20001000)。Bootloader則是通過TFTLCD顯示實驗(在第
十八章介紹)修改得來。本章,關于SRAM APP和FLASH APP的生成比較簡單,我們就不細說,請大家結合光盤源碼,以及48.1節的介紹,自行理解。本章軟件設計僅針對Bootloader程序。
打開本實驗工程,可以看到我們增加了IAP組,在組下面添加了iap.c文件以及其頭文件isp.h。打開iap.c, 代碼如下:
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "stmflash.h"
#include "iap.h"???? ?
iapfun jump2app;
u16 iapbuf[1024];
//appxaddr:應用程序的起始地址
//appbuf:應用程序CODE.
//appsize:應用程序大小(字節).
void iap_write_appbin(u32 appxaddr,u8 *appbuf,u32 appsize)
{
?????? u16 t;
?????? u16 i=0;
?????? u16 temp;
?????? u32 fwaddr=appxaddr;//當前寫入的地址
?????? u8 *dfu=appbuf;
?????? for(t=0;t<appsize;t+=2)
?????? {??????????????????????????????????????? ???
????????????? temp=(u16)dfu[1]<<8;
????????????? temp+=(u16)dfu[0];????? ?
????????????? dfu+=2;//偏移2個字節
????????????? 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);//將最后的一些內容字節寫進去.?
}
//跳轉到應用程序段
//appxaddr:用戶代碼起始地址.
void iap_load_app(u32 appxaddr)
{
?????? if(((*(vu32*)appxaddr)&0x2FFE0000)==0x20000000)????? //檢查棧頂地址是否合法.
?????? {
????????????? jump2app=(iapfun)*(vu32*)(appxaddr+4);????????
//用戶代碼區第二個字為程序開始地址(復位地址)?????????
????????????? MSR_MSP(*(vu32*)appxaddr);???????????????????????????????
//初始化APP堆棧指針(用戶代碼區的第一個字用于存放棧頂地址)
????????????? jump2app();??? //跳轉到APP.
?????? }
}
?????? 該文件總共只有2個函數,其中,iap_write_appbin函數用于將存放在串口接收buf里面的APP程序寫入到FLASH。iap_load_app函數,則用于跳轉到APP程序運行,
其參數appxaddr為APP程序的起始地址,程序先判斷棧頂地址是否合法,在得到合法的棧頂地址后,通過MSR_MSP函數(該函數在sys.c文件)設置棧頂地址,
最后通過一個虛擬的函數(jump2app)跳轉到APP程序執行代碼,實現IAPàAPP的跳轉。
?????? 打開iap.h代碼如下:
#ifndef __IAP_H__
#define __IAP_H__
#include "sys.h"???
typedef? void (*iapfun)(void);???? //定義一個函數類型的參數.??
#define FLASH_APP1_ADDR??????????? 0x080010000? ????
//第一個應用程序起始地址(存放在FLASH)
//保留0X08000000~0X0800FFFF的空間為Bootloader使用?? ??
void iap_load_app(u32 appxaddr);???????????????????????????????????????????????? //跳轉到APP程序執行
void iap_write_appbin(u32 appxaddr,u8 *appbuf,u32 applen);?? //在指定地址開始,寫入bin
#endif
?????? 這部分代碼比較簡單,。本章,我們是通過串口接收APP程序的,我們將usart.c和usart.h做了稍微修改,在usart.h中,我們定義USART_REC_LEN為55K字節,
也就是串口最大一次可以接收55K字節的數據,這也是本Bootloader程序所能接收的最大APP程序大小。然后新增一個USART_RX_CNT的變量,用于記錄接收到
的文件大小,而USART_RX_STA不再使用。打開usart.c,可以看到我們修改USART1_IRQHandler部分代碼如下:
//串口1中斷服務程序
//注意,讀取USARTx->SR能避免莫名其妙的錯誤?? ????
u8 USART_RX_BUF[USART_REC_LEN] __attribute__ ((at(0X20001000)));
//接收緩沖,最大USART_REC_LEN個字節,起始地址為0X20001000.???
//接收狀態
//bit15, 接收完成標志
//bit14, 接收到0x0d
//bit13~0,???? 接收到的有效字節數目
u16 USART_RX_STA=0;?????? ?????? //接收狀態標記???? ?
u16 USART_RX_CNT=0;?????????????????? //接收的字節數???? ?
void USART1_IRQHandler(void)
{
?????? u8 res;????
#ifdef OS_CRITICAL_METHOD
//如果OS_CRITICAL_METHOD定義了,說明使用ucosII了.
?????? OSIntEnter();???
#endif
?????? if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)//接收到數據
?????? {????
????????????? res=USART_ReceiveData(USART1);
????????????? if(USART_RX_CNT<USART_REC_LEN)
????????????? {
???????????????????? USART_RX_BUF[USART_RX_CNT]=res;
???????????????????? USART_RX_CNT++;????????????????? ???????????????????????????????????????????????????????????? ?????
????????????? }
?????? }
#ifdef OS_CRITICAL_METHOD ?????
//如果OS_CRITICAL_METHOD定義了,說明使用ucosII了.
?????? OSIntExit();? ???????????????????????????????????????????????????????????????????????????? ?
#endif
}
?????? 這里,我們指定USART_RX_BUF的地址是從0X20001000開始,該地址也就是SRAM APP程序的起始地址!然后在USART1_IRQHandler函數里面,將串口發
送過來的數據,全部接收到USART_RX_BUF,并通過USART_RX_CNT計數。代碼比較簡單,我們就不多說了。
最后我們看看main函數如下:
int main(void)
{???????????
?????? u8 t,key;
?????? u16 oldcount=0;???? //老的串口接收數據值
?????? u16 applenth=0;???? //接收到的app代碼長度
?????? u8 clearflag=0;
?????? uart_init(256000);? ??? //串口初始化為256000
?????? delay_init();??? ?? ? ????? //延時初始化
?????? LCD_Init();??? ??????? //液晶初始化
?????? LED_Init();?????????? ? ??? //初始化與LED連接的硬件接口
????? KEY_Init();????????????????? //按鍵初始化 ??????
POINT_COLOR=RED;//設置字體為紅色
?????? LCD_ShowString(60,50,200,16,16,"Warship STM32");????
?????? LCD_ShowString(60,70,200,16,16,"IAP TEST");?????
?????? LCD_ShowString(60,90,200,16,16,"ATOM@ALIENTEK");
?????? LCD_ShowString(60,110,200,16,16,"2012/9/24");?
?????? LCD_ShowString(60,130,200,16,16,"WK_UP:Copy APP2FLASH");
?????? LCD_ShowString(60,150,200,16,16,"KEY1:Erase SRAM APP");
?????? LCD_ShowString(60,170,200,16,16,"KEY0:Run SRAM APP");
?????? LCD_ShowString(60,190,200,16,16,"KEY2:Run FLASH APP");
?????? POINT_COLOR=BLUE;
?????? //顯示提示信息
?????? POINT_COLOR=BLUE;//設置字體為藍色 ?
?????? while(1)
?????? {
?????? ????? if(USART_RX_CNT)
????????????? {
???????????????????? if(oldcount==USART_RX_CNT)
//新周期內,沒有收到任何數據,認為本次數據接收完成.
???????????????????? {
??????????????????????????? applenth=USART_RX_CNT;
??????????????????????????? oldcount=0;
??????????????????????????? USART_RX_CNT=0;
??????????????????????????? printf("用戶程序接收完成!\r\n");
??????????????????????????? printf("代碼長度:%dBytes\r\n",applenth);
???????????????????? }else oldcount=USART_RX_CNT;????????????????????
????????????? }
????????????? t++; delay_ms(10);
????????????? if(t==30)
????????????? {
???????????????????? LED0=!LED0; t=0;
???????????????????? if(clearflag)
???????????????????? {
??????????????????????????? clearflag--;
??????????????????????????? if(clearflag==0)LCD_Fill(60,210,240,210+16,WHITE);//清除顯示
???????????????????? }
????????????? }???? ? ??? ?
????????????? key=KEY_Scan(0);
????????????? if(key==KEY_UP)
????????????? {
???????????????????? if(applenth)
???????????????????? {
??????????????????????????? printf("開始更新固件...\r\n");?????
??????????????????????????? LCD_ShowString(60,210,200,16,16,"Copying APP2FLASH...");
?????????????????????????? if(((*(vu32*)(0X20001000+4))&0xFF000000)==0x08000000)
//判斷是否為0X08XXXXXX.
??????????????????????????? {???? ??????
iap_write_appbin(FLASH_APP1_ADDR,USART_RX_BUF,
applenth); //更新FLASH代碼??
?????????????????????????????????? LCD_ShowString(60,210,200,16,16,"Copy APP Successed!!");
?????????????????????????????????? printf("固件更新完成!\r\n");??????
??????????????????????????? }else
??????????????????????????? {
?????????????????????????????????? LCD_ShowString(60,210,200,16,16,"Illegal FLASH APP!? ");?????? ??
?????????????????????????????????? printf("非FLASH應用程序!\r\n");
??????????????????????????? }
??????????????????? }else
???????????????????? {
??????????????????????????? printf("沒有可以更新的固件!\r\n");
??????????????????????????? LCD_ShowString(60,210,200,16,16,"No APP!");
???????????????????? }
???????????????????? clearflag=7;//標志更新了顯示,并且設置7*300ms后清除顯示??????? ?
????????????? }
????????????? if(key==KEY_DOWN)
????????????? {
???????????????????? if(applenth)
???????????????????? {?????????????????????????????????????????????????????????????????????????????????????????????????????????????
??????????????????????????? printf("固件清除完成!\r\n");???
??????????????????????????? LCD_ShowString(60,210,200,16,16,"APP Erase Successed!");
??????????????????????????? applenth=0;
???????????????????? }else
???????????????????? {
??????????????????????????? printf("沒有可以清除的固件!\r\n");
??????????????????????????? LCD_ShowString(60,210,200,16,16,"No APP!");
???????????????????? }
???????????????????? clearflag=7;//標志更新了顯示,并且設置7*300ms后清除顯示????????????????????????????????????????????????????????
????????????? }
????????????? if(key==KEY_LEFT)
????????????? {
???????????????????? printf("開始執行FLASH用戶代碼!!\r\n");
???????????????????? if(((*(vu32*)(FLASH_APP1_ADDR+4))&0xFF000000)==0x08000000)
//判斷是否為0X08XXXXXX.
???????????????????? {????
??????????????????????????? iap_load_app(FLASH_APP1_ADDR);//執行FLASH APP代碼
???????????????????? }else
???????????????????? {
??????????????????????????? printf("非FLASH應用程序,無法執行!\r\n");
??????????????????????????? LCD_ShowString(60,210,200,16,16,"Illegal FLASH APP!");??? ??
???????????????????? }????????????????????????????????????????????????????????????
???????????????????? clearflag=7;//標志更新了顯示,并且設置7*300ms后清除顯示 ?
????????????? }
????????????? if(key==KEY_RIGHT)
????????????? {
???????????????????? printf("開始執行SRAM用戶代碼!!\r\n");
???????????????????? if(((*(vu32*)(0X20001000+4))&0xFF000000)==0x20000000)
//判斷是否為0X20XXXXXX.
???????????????????? {????
??????????????????????????? iap_load_app(0X20001000);//SRAM地址
???????????????????? }else
???????????????????? {
??????????????????????????? printf("非SRAM應用程序,無法執行!\r\n");
??????????????????????????? LCD_ShowString(60,210,200,16,16,"Illegal SRAM APP!");???? ??
???????????????????? }????????????????????????????????????????????????????????????
???????????????????? clearflag=7;//標志更新了顯示,并且設置7*300ms后清除顯示
????????????? }????????????????????????? ??
????????????? ?
?????? }?? ?????? ???
}
?????? 該段代碼,實現了串口數據處理,以及IAP更新和跳轉等各項操作。Bootloader程序就設計完成了,但是一般要求bootloader程序越小越好(給APP省空間嘛),
所以,本章我們把一些不需要用到的.c文件全部去掉,最后得到工程截圖如圖48.3.1所示:
?
?
圖48.3.1 Bootloader 工程截圖
?????? 從上圖可以看出,雖然去掉了一些不用的.c文件,但是Bootloader大小還是有22K左右,比較大,主要原因是液晶驅動和printf占用了比較多的flash,如果大家
想進一步刪減,可以去掉LCD顯示和printf等,不過我們在本章為了演示效果,所以保留了這些代碼。
????? 至此,本實驗的軟件設計部分結束。
?????? FLASH APP和SRAM APP兩部分代碼,我們在實驗目錄下提供了兩個實驗供大家參考,不過要提醒大家,根據我們的設置,FLASH APP的起始地址必須是0X08010000,而SRAM APP的起始地址必須是0X20001000。
48.4 下載驗證
在代碼編譯成功之后,我們下載代碼到ALIENTEK戰艦STM32開發板上,得到,如圖48.4.1所示:
?
圖48.4.1 IAP程序界面
此時,我們可以通過串口,發送FLASH APP或者SRAM APP到戰艦STM32開發板,如圖48.4.2所示:
圖48.4.2 串口發送APP程序界面
?????? 先用串口調試助手的打開文件按鈕(如圖標號1所示),找到APP程序生成的.bin文件,然后設置波特率為256000(為了提高速度,Bootloader程序將波特率被設置為256000了),
最后點擊發送文件(圖中標號3所示),將.bin文件發送給戰艦STM32開發板。
?????? 在收到APP程序之后,我們就可以通過KEY0/KEY2運行這個APP程序了(如果是FLASH APP,則先需要通過WK_UP將其存入對應
總結