給你的代碼升個級?—IAP

1、什麼是IAP,爲何要IAP

IAP即爲In Application Programming(在應用中編程),通常狀況下,以STM32F10x系列芯片爲主控制器的設備在出廠時就已經使用J-Link仿真器將應用代碼燒錄了,若是在設備使用過程當中須要進行應用代碼的更換、升級等操做的話,則可能須要將設備返回原廠並拆解出來再使用J-Link從新燒錄代碼,這就增長了不少沒必要要的麻煩。站在用戶的角度來講,就是能讓用戶本身來更換設備裏邊的代碼程序而廠家這邊只須要提供給用戶一個代碼文件便可。編程

而IAP卻能很好的解決掉這個難題,一片STM32芯片的Code(代碼)區內通常只有一個用戶程序。而IAP方案則是將代碼區劃分爲兩部分,兩部分區域各存放一個程序,一個叫bootloader(引導加載程序),另外一個較user application(用戶應用程序)。bootloader在出廠時就固定下來了,在須要變動user application時只須要經過觸發bootloader對userapplication的擦除和從新寫入便可完成用戶應用的更換。如圖所示markdown

在程序執行初始進入bootloader,在bootloader裏面檢測條件是否被觸發(可經過按鍵是否被按下、串口是否接收到特定的數據、U盤是否插入等等),若是有則進行對user application進行擦除和從新寫入操做,若是沒有則直接跳轉到user application執行應用;若是有則進行擦除用戶代碼並從新寫入新的用戶代碼。app

2、STM32F103ZET6硬件條件

STM32F103ZET6的啓動方式有三種:內置FLASH啓動、內置SRAM啓動、系統存儲器ROM啓動,經過BOOT0和BOOT1引腳的設置能夠選擇從哪中方式啓動,這裏選擇內置的FLASH啓動。其FLASH的地址爲0x08000000—0x0807 FFFF,共512KB,這些都能從芯片數據手冊中直接獲得。而這裏首要的一個問題是中斷的問題。正常狀況下發生中斷的過程爲:發生中斷(中斷請求)到中斷向量表查找中斷函數入口地址跳轉到中斷函數執行中斷函數中斷返回。也就是說在STM32的內置的Flash中有一箇中斷向量表來存放各個中斷服務函數的入口地址,內置Flash的分配狀況大體以下圖。函數

在只有一個程序的狀況下,程序執行的走向應該如圖所示。ui

STM32F10x有一箇中斷向量表,這個中斷向量表存放在代碼開始部分的後4個字節處(即0x0800 0004),代碼開始的4個字節存放的是堆棧棧頂的地址,當發生中斷後程序經過查找該表獲得相應的中斷服務程序入口地址,而後再跳到相應的中斷服務程序中執行。上電後從0x08000004處取出復位中斷向量的地址,而後跳轉到復位中斷程序的入口(標號①所示),執行結束後跳轉到main函數中(標號②所示)。在執行main函數的過程當中發生中斷,則STM32強制將PC指針指回中斷向量表處(標號③所示),從中斷向量表中找到相應的中斷函數入口地址,跳轉到相應的中斷服務函數(標號④所示),執行完中斷函數後再返回到main函數中來(標號⑤所示)。spa

若在STM32F103x中使用IAP方案,則內置的Flash分配狀況大體以下圖。指針

在內置的Flash裏面添加一個BootLoader程序,BootLoader程序和user application各有一箇中斷向量表,假設BootLoader程序佔用的空間爲N+M字節,則程序的走向應該以下圖所示。code

上電初始程序依然從0x08000004處取出復位中斷向量地址,執行復位中斷函數後跳轉到IAP的main(標號①所示),在IAP的main函數執行完成後強制跳轉到0x08000004+N+M處(標號②所示),最後跳轉到新的main函數中來(標號③所示),當發生中斷請求後,程序跳轉到新的中斷向量表中取出新的中斷函數入口地址,再跳轉到新的中斷服務函數中執行(標號④⑤所示),執行完中斷函數後再返回到main函數中來(標號⑥所示)。orm

對於步驟④⑤,網友認爲是:「在main執行的過程當中,若是CPU獲得一箇中斷請求,PC指針仍強制跳轉到地址0x08000004中斷向量表處,而不是新的中斷向量表,如圖標號④所示,程序再根據咱們設置的中斷向量表偏移量,跳轉到對應中斷源新的中斷服務程序中,如圖標號⑤所示」。我對此的理解是:「當發生中斷後,程序從0x08000004(舊)處的中斷向量表中獲得相應的中斷服務函數入口地址,繼而跳轉到相應的中斷服務程序」。可是舊的中斷向量列表裏邊存放的是IAP程序中斷函數的入口地址,它是如何獲得user程序中斷函數的入口地址呢?因此我以爲此種說法是錯誤的。「當發生中斷時PC指針強制會跳轉到0x08000004處」這種說法並無錯,只是忽略了後續的一些知識要點而致使這個說法出現矛盾。flash

對於步驟④⑤我認爲的是,在main函數的執行過程當中,若是CPU獲得一箇中斷請求,PC指針原本應該跳轉到0x08000004處的中斷向量表,因爲咱們設置了中斷向量表偏移量爲N+M,所以PC指針被強制跳轉到0x08000004+N+M處的中斷向量表中獲得相應的中斷函數地址(待求證),再跳轉到相應新的中斷服務函數,執行結束後返回到main函數中來。

3、實現過程

STM32F103ZET6的Flash地址爲0x08000000—0x0807 FFFF共512KB,把這512KB的空間分爲兩塊,第一塊大小爲32KB存放BootLoader程序,剩餘的空間存放用戶程序(根據實際狀況分配這兩塊空間的大小,BootLoader程序佔用的空間越小越好,則BootLoader地址爲0x08000000—0x08007fff,用戶程序地址爲0x08008000—0x0807ffff。BootLoader流程圖大體應該以下:

  • 一、初始化時鐘
  • 二、初始化中斷向量表地址
  • 三、初始化按鍵(使用按鍵觸發方式,上電時若是按鍵被按下則進行用戶程序更新操做)
  • 四、初始化串口
  • 五、檢測按鍵是否被按下,是則執行步驟6,不然執行步驟10
  • 六、擦除用戶程序(擦除0x08008000—0x0807ffff地址空間Flash)
  • 七、從串口讀取新的用戶代碼數據,把代碼寫入用戶程序空間
  • 八、檢測串口數據接收完畢?是則執行步驟9,不然跳回步驟7
  • 九、用戶程序更新完畢,等待從新上電或硬件復位
  • 十、跳轉到用戶程序(強制將PC指針跳轉到0x08008000+4處)

到這裏首先要解決的問題就有:

  • 一、如何進行對STM32的Flash進行擦除和寫入操做
  • 二、中斷向量表偏移如何設置
  • 三、如何改變代碼存放的地址空間(由於BootLoader要存放在0x08000000處,用戶程序要存放在0x08008000處,而默認的代碼存放的地址空間爲0x08000000)
  • 四、怎麼進行PC指針的強制跳轉,跳轉時須要作些什麼
  • 五、串口接收的用戶代碼數據是什麼樣的代碼數據,是一種什麼樣的文件

問題的解決:

一、使用STM32的固件庫函數,只需調用幾個庫函數便可輕鬆解決,使用的固件庫爲stm32f10x_flash.c文件,對Flash的操做過程簡要爲:Flash解鎖Flash擦除Flash寫入Flash上鎖。

①解鎖:

FLASH_Unlock();//解鎖Flash
FLASH_SetLatency(FLASH_Latency_2);//由於系統時鐘爲72M因此要設置兩個時鐘週期的延時
複製代碼

②擦除:

for(i=0;i<240;i++)
{
if(FLASH_ErasePage(FLASH_ADDR+i*2048) != FLASH_COMPLETE)//必定要判斷是否擦除成功
return ERROR;
}
複製代碼

說明:FLASH_ErasePage(uint32_t Page_Address)即爲Flash擦除操做,按頁擦除,每頁2KB,Page_Address爲頁的起始地址,如0x08000000是第一頁起始地址,0x08000800爲第二頁起始地址,這裏的操做擦除了0x08008000—0x0807ffff地址空間的Flash。

③寫入:

unsigned char buf[1024]; //假設待寫入的代碼數據
unsigned short temp; //臨時數據
for(i=0;i<512;i++)
{
  temp = (buf[2*i+1]<<8) | buf[2*i];//2個字節整合爲1個半字
  if(FLASH_ProgramHalfWord(ADDR,temp) != FLASH_COMPLETE)//判斷是否寫入成功
  {
        Return ERROR;
  }
  ADDR +=2;//地址要加2,由於每次寫入的是2個字節(1個半字)
}
  
複製代碼

說明:由於STM32的Flash寫入爲雙字節(1個半字)寫入,FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data)函數即爲對地址爲Address寫入1個半字的Data,每次寫入完成後地址要加2。

④上鎖:

FLASH_Lock(); //Flash 上鎖,一個固件庫函數便可實現。
複製代碼

二、關於中斷向量表的偏移設置,對於BootLoader程序只需設置中斷向量表的指向在0x08000000處,對於用戶程序須要設置中斷向量表的指向在0x08008000處便可。

①在BootLoader程序的中斷向量表指向設置中應有這麼一句:

NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0); //設置中斷向量表指向
複製代碼

其中NVIC_VectTab_FLASH是個宏定義,的值爲0x08000000。

②在用戶程序的中斷向量表指向設置用應有這麼一句:

NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x8000);//設置中斷向量表指向
複製代碼

4、結束語

總的來講STM32的IAP方案實現須要在進行用戶程序以前加一段Bootloader程序,BootLoader程序的做用就是:

一、什麼都不作,直接跳轉到用戶程序。

二、刪除原有的用戶程序,讀取*.bin文件數據並將數據從新寫入新的用戶程序。 對於用戶程序相比普通的編程只須要作三步改動便可

三、改變中斷向量表。

四、改變代碼存放的地址空間

五、修改生成*.bin文件

使用經過UART的IAP方案並非很好的選擇,這只是IAP方案的一個機制,由於能使用PC機經過串口升級程序,一樣能經過Jlink燒寫程序,而且自定義的串口通信協議在沒有校CRC校驗的狀況下不能及時發現數據傳輸過程發生的錯誤。這裏推薦使用SD卡(或U盤)進行用戶程序更新,將*.bin文件複製到SD卡(或U盤)中,STM32再經過讀取SD卡(或U盤)的*.bin文件進行用戶程序更新,這也避免了STM32與PC笨重的通信,只需插一個SD卡(或U盤)更顯得人性化一些,但須要去弄懂STM32如何與SD卡(或U盤)的通信。

默認標題_橫版二維碼_2021-05-29-0.png

相關文章
相關標籤/搜索