STM32 IAP固件升級(一)


章節說明

STM32 IAP固件升級實驗分為一下的章節(加粗的字體是本章節的內容):

一、Flash和RAM的區域划分、工程建立、程序分散加載、程序燒寫
二、Stm32 bootloader、application、firmware 程序的分析和編寫
三、使用DMA收發串口的不定長數據
四、通信協議的設計
五、STM32 IAP程序的設計
六、上位機的程序的編寫

一、Flash區域的划分

1.區域划分

  • 實驗使用的是 STM32F103VET6型號的MCU。這個單片機的型號的內部flash的大小是512Kb, RAM的大小是64Kb。
  • 因為一般使用的都是flash的啟動方式(即flash 的起始地址0x0800 0000被映射到 0x0000 0000。STM32的啟動方式可以查看《STM32中文參考手冊》) 所以flash的區域划分如下:

2. flash 分區說明

  • 0x0800 00000x0800 b7FF 地址的flash塊划分給bootloader,大小是46kb
  • 0x0800 B8000x0800 BFFF 的flash塊划分為參數表(parameters),大小是2Kb
  • 0x0800 C0000x0804 3FFF 的flash塊划分為應用程序區 (application),大小是224Kb
  • 0x0804 40000x0807 BFFF 的flash塊划分為程序升級區 (update region),大小跟應用程序區一樣 224kb
  • 0x0807 C0000x0807 FFFF 的flash塊划分為固件區(firmware),大小是16Kb

3. 每個分區作用

  • bootloader 啟動加載程序,主要用來加載和啟動應用程序,還有更新應用程序
  • parameters 主要用來記錄信息,bootloader 和 application 的信息交互
  • application 應用程序區,主要用來實現所需要的業務的程序
  • update region 程序更新區,主要存放更新下載的程序,當然也可以直接下載到 application 區,但是如果更新失敗了,應用程序就不能執行了。所以單獨划分一塊區域,存放更新下載的序,更新完后再覆蓋到application然后復位運行
  • firmware 固件區,主要存放一些函數接口,用戶可以通過函數指針直接調用。像tiny-4412、smart210、esp32等這些板子的芯片在irom里面都提供了一些函數接口,通過地址可以直接調用這些函數。

二、RAM內存的划分

1、區域划分

RAM(內存)的起始地址是 0x2000 0000,大小是64Kb。在實驗主要將它划分為兩塊。一塊是從 0x2000 00000x2000 FBFF 大小是63Kb。另一塊是從 0x2000 FC000x2001 0000 大小是 1Kb,划分如下圖

2、區域的作用

  • 63Kb這塊內存區域主要是用於 bootloaderapplication 應用程序的可讀可寫段(RW),未初始化或者初始化為0的數據段(ZI)、堆空間、棧空間
  • 1kb這塊內存區域主要是用於 firmware 區域的可讀可寫段(RW),未初始化或者初始化為0的數據段(ZI)
  • 注意:firmware因為沒有初始化堆,所以不能使用malloc這類堆內存管理函數。

3、簡單說明

  • 因為STM32的flash 是norflash 讀的時候可以像內存一樣讀,但是寫的時候不能像內存那樣子寫,所以這些 RW 段 ZI 段都是加載到內存里。加載到哪里,這是由分散加載文件.sct文件(和鏈接腳本一個意思)里面說明。至於怎么加載 ,stm32 函數庫的start_up.s文件的__main 到 main函數的過程就是加載數據到RAM空間。后面再介紹.sct文件

三、工程建立

工程中需要三個project,分別是 bootloader application firmware 如下圖:

四、分散加載

因為程序存放在不同的區域了,並且每段區域的程序是獨立的,所以在鏈接每個程序的時候需要告訴連接器,程序怎么放,程序加載啟動的時候又應該怎么加載,堆區和棧區的位置這些都要告訴鏈接器。我們可以通過分散加載文件.sct 文件來告訴鏈接器。下面來看一下這個文件

1.原來的分散加載文件

; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************
;LR_IROM1 段名/域名
;0x08000000 程序加載的起始地址
;0x00080000 加載域的大小
LR_IROM1 0x08000000 0x00080000  {    ; load region size_region
  ;ER_IROM1 執行域的名稱  
  ;0x08000000 程序的執行起始地址
  ;0x00080000 執行域的大小
  ;一般程序是在 flash 里面運行的所以 程序的執行地址等於加載地址,如果想要讓程序運行在RAM中,執行地址修改為RAM的地址
  ER_IROM1 0x08000000 0x00080000  {  ; load address = execution address
   ;下面就是指定某些段怎么鏈接了
   *.o (RESET, +First)   ;鏈接的時候最先存放的是 所有.o文件的RESET段,緊跟的是First段(RESET段在start_up.s文件中有定義)
   *(InRoot$$Sections)   ;然后存放 __main 到 main的這段代碼,這段代碼主要是將flash的RW和ZI段加載到RAM中
   .ANY (+RO)            ;緊跟着的是所有文件的只讀數據(RO段),一般是向量表、代碼段和常量(字符串常量,和const修飾的數據)
  }
;RW_IRAM1 可讀可寫數據的段名
;0x20000000起始地址  
;0x00010000大小
  RW_IRAM1 0x20000000 0x00010000  {  ; RW data
   .ANY (+RW +ZI);緊接着的是(RW段),(ZI)段
  }
}

Region的名稱可以自己定義或者修改,重要的是地址要分配對就可以了。
Heart_of_Eagle這位博主有一篇比較詳細的博文值得參考,不過不是MDK的sct文件的,原理都是大同小異
MDK也是有詳細的幫助文檔,不過是純英文的,想用好sct可以閱讀里面的內容
1.

2.

2.修改bootloader的分散加載文件

根據上面的flash和RAM的划分修改sct加載文件,如下代碼塊:

; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************
;因為bootloader是第一個啟動的程序,而且機器上電復位的時候是從0x0800 0000開始執行(因為被映射到了0x0000 0000)地址
;所以bootloader加載域的起始地址和執行地址都是0x0800 0000
; 0x0000B800域的大小(46kb)也是通過上面的設計的分區來填寫
LR_IROM1 0x08000000 0x0000B800  {    ; load region size_region
  ER_IROM1 0x08000000 0x0000B800  {  ; load address = execution address
   ;里面段的存放位置使用默認的就可以
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
  }
; 0x20000000 這個也是根據上面的RAW的分區填寫,
;0x0000FC00 大小是 63Kb
  RW_IRAM1 0x20000000 0x0000FC00  {  ; RW data
   ;段的存放位置使用默認的就可以了
   .ANY (+RW +ZI)
  }
}

3.修改application的分散加載文件

修改如下,跟bootloader一樣,就不啰嗦了

; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************
LR_IROM1 0x0800C000 0x00038000  {    ; load region size_region
  ER_IROM1 0x0800C000 0x00038000  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
  }
  RW_IRAM1 0x20000000 0x0000FC00  {  ; RW data    0x0000FC00
   .ANY (+RW +ZI)
  }
}

4.修改firmware的分散加載文件

*(InRoot$$Sections) 被注釋掉了,因為 firmware 的程序是沒有 __mainmain 函數部分的代碼的。下一章節寫程序的時候會有講解。其他的內容也跟bootloader文件差不多,上面的分區來寫就可以了

; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************

LR_IROM1 0x0807C000 0x00004000  {    ; load region size_region
  ER_IROM1 0x0807C000 0x00004000  {  ; load address = execution address
   *.o (RESET, +First)
   ;*(InRoot$$Sections) 
   .ANY (+RO)
  }
  RW_IRAM1 0x2000FC00 0x00000400  {  ; RW data  
   .ANY (+RW +ZI)
  }
}

5. 注意事項

在MDK的默認設置里,鏈接的時候是不使用分散加載文件的 xxx.sct 文件。要使用 xxx.sct 文件需要將下面的設置去掉

五、程序的下載設置

  • 由於本章還沒實現IAP這部分的程序,所以 bootloaderapplicationfirmware的程序都是使用燒寫器來燒寫到falsh的不同區域。所以需要設置一下。
  • 設置的地址跟大小也是根據上面的flash分區來設置的。
  • 主要設置MDK里面的 Debug -> Flash Download 的這兩個地方,設置完這里就可以用Jlink將不同的程序燒寫到不同的區域了。
  • 下圖是 bootloader 的設置,其他兩個也是根據實際來設置

六、實驗現象

說了這么多先來個實驗現象吧, 對於下面的程序分析和編寫就下一章再寫了。
工程文件已經上傳到碼雲---->點我project!!!
代碼可能存在問題,有問題可以留言討論。

  1. hello bootloader 是在bootloader運行的時候打印出來的,打印完后就跳到應用程序執行了
  2. num = 10num1 = 0 這兩個值是通過函數指針調用firmware固件區的函數接口來獲取的
  3. 打印完上面的兩個值之后循環打印hello app
    現象如下圖:


免責聲明!

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



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