QT上位機給STM32設備串口IAP升級固件
目錄
廢話不多說看看效果先
1,實現原理
應用編程IAP(In-Application-Programming)是應用在Flash程序存儲器的一種編程模式,它可以在應用程序正常運行的情況下,通過調用特定的IAP程序對另外一段程序Flash空間進行讀/寫操作,甚至可以控制對某段、某頁甚至某個字節的讀/寫操作。主要用於數據存儲和固件升級。對於IAP應用,通常會有兩個程序,第一個程序Bootloader程序不執行正常功能,只是通過某種方式(串口,usb,SD卡)接收第二個程序,並進行更新。第二個程序APP程序是執行的主體,用於實現應用功能。
對於stm32閃存模塊,主要由主存儲器、信息塊和閃存存儲器接口寄存器三部分構成。
主存儲器,該部分用來存放代碼和數據常數(如 const 類型的數據)。對於大容量產品,其被劃分爲 256 頁,每頁 2K 字節。注意, 小容量和中容量產品則每頁只有 1K 字節。看出主存儲器的起始地址就是 0X08000000, B0、 B1 都接GND 的時候,就是從 0X08000000開始運行代碼的。
信息塊,該部分分爲 2 個小部分,其中啓動程序代碼,是用來存儲 ST 自帶的啓動程序,用於串口下載代碼,當 B0 接 V3.3, B1 接 GND的時候,運行的就是這部分代碼。用戶選擇字節,則一般用於配置寫保護、讀保護等功能,本章不作介紹。
閃存存儲器接口寄存器,該部分用於控制閃存讀寫等,是整個閃存模塊的控制機構。
對主存儲器和信息塊的寫入由內嵌的閃存編程/擦除控制器(FPEC)管理;編程與擦除的高電壓由內部產生。
對於flash的讀寫的流程
這裏要特別留意一個閃存等待時間,因爲 CPU 運行速度比 FLASH 快得多, STM32F103的 FLASH 最快訪問速度≤24Mhz,如果 CPU 頻率超過這個速度,那麼必須加入等待時間,比如我們一般使用72Mhz的主頻,那麼FLASH等待週期就必須設置爲 2,該設置通過 FLASH_ACR寄存器設置。
2,程序流程
編程流程
1、檢查 FLASH_CR 的 LOCK 是否解鎖,如果沒有則先解鎖,(向KEYR寄存器中寫入特定序列KEY1和KEY2)
(實際中需要查看當前要寫入的扇區是否有數據,如果有數據,則需要進行擦除操作,然後再進行下面的步驟)
2、檢查 FLASH_SR 寄存器的 BSY 位,以確認沒有其他正在進行的編程操作
3、設置 FLASH_CR 寄存器的 PG 位爲’1’,用於表示接下來進行寫操作
4、在指定的地址寫入要編程的半字
5、等待 BSY 位變爲’0’,表示編程完成
6、讀出寫入的地址並驗證數據
我們在 STM32 的 FLASH 編程的時候,要先判斷縮寫地址是否被擦除了
下面介紹頁擦除過程
讀出被擦除的頁並做驗證
1、檢查 FLASH_CR 的 LOCK 是否解鎖,如果沒有則先解鎖(向KEYR寄存器中寫入特定序列KEY1和KEY2)
2、檢查 FLASH_SR 寄存器的 BSY 位,以確認沒有其他正在進行的閃存操作
3、設置 FLASH_CR 寄存器的 PER 位爲’1’,用於表示進行頁擦除操作
4、用 FLASH_AR 寄存器選擇要擦除的頁
5、置 FLASH_CR 寄存器的 STRT 位爲‘1’表示開始一次擦除操作
6、等待 BSY 位變爲’ 0’
讀出被擦除的頁並做驗證
我們來了解下stm32的程序運行流程,如下圖所示
程序運行的地址從0x08000000(FLASH)開始運行
1程序開始運行後,從中斷向量表中取出復位中斷向量,並執行服務程序。
2執行完中斷向量程序會跳轉至主main函數入口執行,並在死循環中一直執行。
3當在主函數中發生中斷時間時,系統強制PC指針指向對應中斷向量表對應位置。
4PC指針在中斷向量表處取出中斷服務程序入口地址,並跳轉至對應位置執行。
5中斷服務程序執行完成後,PC指針跳回發生中斷時系統在main函數中的位置,繼續往下執行。
當加入IAP應用後stm32的程序流程變爲下圖所示
程序運行的地址從0x08000000(FLASH)開始運行
1程序開始運行後,從中斷向量表中取出復位中斷向量,並執行服務程序。執行完中斷向量程序會跳轉至Bootloader程序main函數入口執行。
2在main中系統檢查是否需要對第二部分代碼進行更新,如果需要則執行更新操作,如果不需要則跳過更新操作,跳轉至APP程序的入口
3在APP程序入口首先進入重新映射的中斷向量口,根據新的中斷復位向量,執行復位中斷程序,然後跳轉至APP程序main入口。
4當在主函數中發生中斷時間時,系統強制PC指針指向對應中斷向量表對應位置(這裏還是強制跳轉到地址0x0800004中斷向量表位置,而不是APP程序的中斷向量表)。
兩個注意點:
1) 新程序必須在 IAP 程序之後的某個偏移量爲 x 的地址開始;
2) 必須將新程序的中斷向量表相應的移動,移動的偏移量爲 x;
對於程序的設置
IAP程序
通過串口設置程序的接收
根據要求設置存儲APP程序的地址
APP程序
設置程序存儲區,與數據存儲區 在Target->Read/Only Memory Areas-> IROM與IRAM處設置,這裏APP程序的存儲首地址設爲0x08010000,大小爲0x70000(即前0x10000爲存放IAP程序)
設置中斷向量表偏移地址SCB->VTOR = FLASH_BASE | 0x10000;
生成BIN文件
3,關鍵代碼解析
STM32F103的IAP關鍵代碼:
int main(void)
{
uint32_t tick1;
tick1 = SysTick_GetCurrent();
MCU_Init();
AreaFlagFirstLoadInit();
NVIC_SetVectorTable(NVIC_VectTab_FLASH,0x8000000); //iap初始都從0x8000000開始運行
printf("init success\r\n");
__enable_irq();
while(1)
{
iapLoop();
if((remainSend == 0x00) && (upgradeDoneFlag == 0xaa55aa55))
{
(currentAreaNum==areaA) ? (FlashDestination=ApplicationAddress_A) : (FlashDestination=ApplicationAddress_B);
if(((*(__IO uint32_t*)FlashDestination) & 0x2FFE0000 ) == 0x20000000) //binÎļþÉý¼¶
{
printf("Execute user APP1 Program upgradeDoneFlag=%x\r\n",upgradeDoneFlag);
USART_Cmd(USART1, DISABLE);
__disable_irq();
JumpAddress = *(__IO uint32_t*) (FlashDestination + 4);
Jump_To_Application = (pFunction) JumpAddress;
MSR_MSP(*(vu32*)FlashDestination);
Jump_To_Application();
}
else
{
if(SysTick_GetLapse(tick1)>1000)
{
printf("ÎÞFLASHÓ¦ÓóÌÐò,ÎÞ·¨Ö´ÐÐ!\r\n");
tick1 = SysTick_GetCurrent();
}
}
}
}
}
uint8_t AreaFlagFirstLoadInit(void)
{
uint8_t ret = 0;
STMFLASH_Read(ADDR_FLASH_LAST_PAGE,&upgradeDoneFlag,1);
FLASH_Unlock();
if(upgradeDoneFlag==0xffffffff || upgradeDoneFlag==0x00000000)
{
upgradeDoneFlag = 0xaa55aa55;
FLASH_ProgramWord(ADDR_FLASH_LAST_PAGE,0xaa55aa55);
}
STMFLASH_Read(AREA_NUM_ADDR,¤tAreaNum,1);
if(currentAreaNum == 0xffffffff || currentAreaNum==0x00000000)
{
printf("ÇøÓò±ê־λ³õʼ»¯");
currentAreaNum = areaA;
if(FLASH_COMPLETE!=FLASH_ProgramWord(AREA_NUM_ADDR,areaA))
{
printf("ÇøÓòA±ê־λÉϵç³õʼ»¯Ê§°Ü");
ret = 1;
}
}
FLASH_Lock();
switch(currentAreaNum)
{
case areaA:
addrCur = ApplicationAddress_B;
break;
case areaB:
addrCur = ApplicationAddress_A;
break;
default:
break;
}
printf("addrCur=%x currentAreaNum=%x upgradeDoneFlag=%x\n",addrCur,currentAreaNum,upgradeDoneFlag);
return ret;
}
IAP程序中
4,相關工具及代碼