嵌入式IAP開發筆記之一:面向STM32的BootLoader程序


  對於很多人來說,BootLoader並不是一個陌生的詞,甚至會經常用到它。因為在很多情況下我們都需要BootLoader程序,比如我們需要對系統在線升級時就需要它,還有當我們需要在外部存儲器中運行程序時也需要用到它。在這里我們就來設計一個應用於STM32系列MCU的BootLOader程序。

1BootLoader的基本原理

  既然我們想要實現一個面向STM32的BootLOader程序,那么首先我們必須來了解一下BootLOader程序的基本原理。

  顧名思義,BootLOader程序肯定是要實現系統的引導,這是BootLOader程序的基本功能。對於STM32系列MCU來說,系統啟動后都會從內部Flash存儲器的起始地址開始執行程序。然后進入應用程序並按既定的順序執行下去,這時BootLoader與應用程序是一體的,具體如圖所示:

 

  但有些時候,我們希望應用程序並不是直接運行,如我們希望對系統實現IAP的時候;或者我們希望應用程序並不在我們的內部Flash中運行;又或者應用程序雖然在內部Flash運行,但我們希望應用程序從我們指定的內部Flash地址運行等等。在這些時候我們就需要一個單獨的BootLoader程序。系統首先啟動BootLoader程序,系統准備就緒后進入到應用程序執行,具體如圖所示:

 

  在上圖中,我們實際上將應用程序存儲在內部Flash的指定位置,這樣做當然是為了實現我們某種需求,如系統IAP。當然我們也可以讓應用程序存儲於外部Flash中,然后BootLoader程序跳轉到外部Flash去執行應用程序,不過前提是外部Flash內購執行程序。具體過程如下:

 

  當然,這只是一種示例,對於不同的存儲器我們只需要修改地址就可以了。至於在BootLoader程序中要實現的功能就看使用情況了。原則上我們可以添加我們任意想要的功能,如硬件檢測、系統升級等等。

2、目標BootLoader設計

  我們的目標是實現一個面向STM32的BootLoader程序。那么接下來我們就設計如何實現一個面向STM32的BootLoader程序。

2.1Flash規划

  我們以STM32F407IGT6為目標MCU,這款MCU具有1M的Flash和192K的SRAM。我們將Flash划分為2個部分,一個是啟動程序區(0x0800 0000 - 0x0800 3FFF )大小為16K Bytes,剩下的為應用程序區(0x0800 4000 - 0x080F FFFF)。具體分配如下圖:

 

  我們讓BootLoader程序占用16K的存儲空間。但它是可以操作整個Flash存儲空間的。

2.2BootLoader程序結構

  我們來考慮一下BootLoader程序的結構問題。我們設計BootLoader程序的主要目的就是為了對應用程序進行升級。那么在BootLoader程序中主要需要實現哪些功能呢?有幾個方面是必須要包括的,一是基本的配置,如時鍾等,我們在主程序中實現;二是對Flash的操作,我們升級應用程序肯定會對Flash進行查處和寫入操作;三是跳轉控制程序,我們最終是需要去執行應用程序的,跳轉功能必不可少。當然根據不同的需求可能會有其它的需要。具體如下圖所示:

 

  上圖中,我們除了簽署的三項基本實現外,還添加了IAP文件的獲取功能。這部分功能也是需要的,但在不同的模式下可能會有較大區別。因為獲取文件的方式可以是各類通訊如以太網口、串口等。也可以是各類存儲器,如SD卡、U盤等。所以這一功能雖然必不可少但實現方式則非常靈活,在后續實現中,我們具體問題具體分析。

3、目標BootLoader實現

  我們已經確定了Flash的划分,也基本明白了BootLoader的基本工作流程。在接下來我就來討論一下究竟怎么實現一個BootLoader程序。

3.1BootLoader編碼

  我們知道芯片上電時先運行BootLoader程序,然后跳轉到應用程序區執行應用程序。所以我們在編寫BootLoader程序時我們首先判斷系統是否有IAP的需求,如果有IAP請求則進入IAP模式,完成后再跳轉到應用程序執行,如果沒有IAP請求則直接跳轉到應用程序執行。具體流程如下:

 

  關於IAP的處理在不同的情況下會有不同的處理方式,在這里我們主要看一看跳轉控制程序。首先定義應用程序的首地址並聲明一個函數指針類型。具體如下:

  #define  ApplicationAddress  0x08004000    //應用程序首地址定義

  typedef void (*pFunction)(void);        //定義跳轉函數指針類型

  可能有人要問問什么定義這樣一個函數指針類型,因為我們最終是跳轉到Reset_Handler函數,所以必須要一個可以指向這個函數的函數指針。接下來我們就可以實現跳轉程序了。

 1 /*跳轉到應用程序處理函數*/
 2 static void JumpToApplication(void)
 3 {
 4   uint32_t StackAddr;           //應用程序棧地址
 5   uint32_t ResetVector;         //應用程序中斷向量表的地址
 6  
 7   pFunction JumpToApp;          //定義跳轉函數指針
 8  
 9   __set_PRIMASK(1);    //關閉全局中斷
10  
11   StackAddr = *(__IO uint32_t*)ApplicationAddress;              //0x08004000;
12   ResetVector = *(__IO uint32_t*)(ApplicationAddress + 4);      //0x08004004;
13  
14   if((StackAddr&0x2FFC0000)==0x20000000)        //檢查棧頂地址是否合法.
15   {
16     __set_MSP(StackAddr);                       //初始化應用程序棧指針
17  
18     JumpToApp = (pFunction)ResetVector;           
19     JumpToApp();
20   }
21 }

3.2、應用程序處理

  實現了BootLoader的編碼后,要想正確的跳轉到App運行,我們還需要對App作相應的修改。重要的修改有2處。如果應用程序是裸機程序則在配置時鍾前我們需要打開全局中端。

  /*開啟全局中斷,在BootLoader中關閉的*/

    __set_PRIMASK(0);

  同時,還需要修改中端向量表的偏移量地址。對於我們所使用的STM32F07可直接在system_stm32f4xx.c文件中修改就可以了。

  #define VECT_TAB_OFFSET  0x4000 /*!< Vector Table base offset field.

  實現了上述修改並不能達到我們想要的目的,我們還需要在開發環境中做必要的修改。以我們使用的IAR EWARM V8.4為例。修改icf文件中對中斷向量表和Flash存儲區域的設定。具體如下圖:

 

  完成上述配置后我們下載應用程序和BootLoader程序就可以實現正確的跳轉了。

4、小結

  本篇中,我們只是實現了一個簡單的BootLoader程序。下載到目標MCU后實現了跳轉,應用程序也正常運行,說明我們的設計是正確的,后續可在次基礎上添加各種功能實現相應的IAP應用。

  需要注意的是在BootLoader程序中我們關閉了全局中斷,在應用程序初始化系統時鍾之前一定要記得打開全局中斷,否則SystemTick不能工作會產生硬件故障(hardfault)。不過如果App是運行在RTOS上,則打開中斷可能會出錯,這一點需要注意。

歡迎關注:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM