STM32 Bootloader基於ymodem傳輸協議串口IAP升級詳解


硬件:stm32f103cbt6
軟件:STM32F10x_StdPeriph_Lib_V3.5.0


1 預備知識

基於標准外設庫(STM32F10x_StdPeriph_Lib_V3.5.0)的IAP升級相關資料可以參考 IAP ST官方資料匯總

STM32升級的三種方式:IAP,ICP,ISP;具體有什么區別可以自行Google

本文需要實現STM32的Bootloader(后面Bootloader/IAP不加以區分),文件傳輸基於ymodem協議通過串口進行傳輸,這里參考了ST官方的DEMO —— STM32F10xxx in-application programming using the USART AN2557,在此基礎上做了部分修改,增加了延時啟動的功能,最終可以實現想要的效果。

在這里插入圖片描述
整體架構分為兩個部分;BootloaderApplication,具體如下圖所示;

在這里插入圖片描述

由上圖可知,STM32內置的Flash被分成了兩個部分,分別用來保存BootloaderApplication程序,這里有兩個有兩個FLASH起始地址0x80000000x8003000

為什么是0x8000000這個地址呢?而不是其他地址呢?
這是由M3內核硬件上的設計就已經這么做了,人為設計好了,可以參考M3內核權威指南;

0x8003000這個地址則是由我們自己來規定的,這個地址的范圍必須在0x80000000x8020000之間,所以一般根據Bootloader程序的最終大小,在這范圍之間取一個比較合理的值即可。如下圖所示;

在這里插入圖片描述

注意:本文使用的stm32f103cb,屬於中等大小Flash,128K = 0x20000,所以地址范圍是0x8000000~0x8020000;

2 Bootloader

2.1 啟動流程

這里的Bootloader即為IAP程序,它具備以下幾個功能;

  • 支持文件傳輸;本文基於ymodem協議通過串口通訊接收或發送的bin文件;當然也可以通過I2CSPIUSBWiFi藍牙等等進行文件傳輸;
  • 對內置Flash進行讀寫,擦除和編程;
  • 啟動Application程序;

前面分析STM32啟動文件的時候,我們可以知道,正常一個系統的啟動流程,可以參考《STM32 標准庫V3.5啟動文件startup_stm32f10xxx.s分析》
在這里插入圖片描述

由該圖可以知道程序正常啟動流程;以下表格一四個向量是必須的,從圖中也可以了解到;

地址 異常編號
0x0800_0000 - MSP 的初始值
0x0800_0004 1 復位向量(PC 初始值)
0x0800_0008 2 NMI 服務例程的入口地址
0x0800_000C 3 硬 fault 服務例程的入口地址

2.2 校驗跳轉地址是否有效

在主函數中可以看到如下程序;甚是不解和迷茫;沉思一會兒才恍然大悟;

    /* Test if user code is programmed starting from address "ApplicationAddress" */
   if (((*(__IO uint32_t*)ApplicationAddress) & 0x2FFE0000 ) == 0x20000000)
   { 
      /* Jump to user application */
      JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4);
      Jump_To_Application = (pFunction) JumpAddress;
      /* Initialize user application's Stack Pointer */
      __set_MSP(*(__IO uint32_t*) ApplicationAddress);
      Jump_To_Application();
    }

本文中ApplicationAddress = 0x8000000
那么*(__IO uint32_t*)ApplicationAddress)則是這個地址中所保存的值,由表格一可以知道,程序起始地址的第一個向量地址保存的棧頂的,因此,地址0x800_00000x800_3000中保存的值都是指向棧頂,如下圖所示;
在這里插入圖片描述

棧是在RAM上分配,因此RAM的有效范圍要做一個檢測,棧頂地址和0x2FFE0000做與運算可以推算出,要校驗的RAM范圍是0x2000_0000—0x2001_FFFF,所以RAM大小是128K,官方DEMO默認使用HD高密度系列,所以是128K,本文是CBT6,20K的RAM,則需要改成0x2FFFB000

    /* Test if user code is programmed starting from address "ApplicationAddress" */
   if (((*(__IO uint32_t*)ApplicationAddress) & 0x2FFFB000 ) == 0x20000000)
   { 
      /* Jump to user application */
      JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4);
      Jump_To_Application = (pFunction) JumpAddress;
      /* Initialize user application's Stack Pointer */
      __set_MSP(*(__IO uint32_t*) ApplicationAddress);
      Jump_To_Application();
    }

計算方式:
20K = 20*1024= 0x5000
0x2FFF_FFFF - (0x5000 - 1) = 0x2FFF_B000

2.3 Keil工程IAP的相關設置

2.3.1 修改Flash地址

在這里插入圖片描述
設置程序起始地址0x800000和大小0x3000
在這里插入圖片描述

設置Debug工具燒寫時Flash的起始地址0x800000和大小0x3000

在這里插入圖片描述

2.3.2 使用自己的鏈接腳本

該項為選配,與上述配置二選一即可,如果仍然想使用自己的鏈接腳本,在Option-->Linker下將Use Memort Layout from Target Dialog選項勾選去掉,然后選擇自己的鏈接腳本,如下圖進行配置;
在這里插入圖片描述

參考ARMCC的鏈接腳本編寫方法,可以自己編寫的srt文件,參考ARM分散加載技術;

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

LR_IROM1 0x08000000 0x00003000  {    ; load region size_region
  ER_IROM1 0x08000000 0x00003000  {  ; load address = execution address
    *.o (RESET, +First)
    *(InRoot$$Sections)
    .ANY (+RO)
    .ANY (+XO)
  }
  RW_IRAM1 0x20000000 0x00005000  {  ; RW data
    .ANY (+RW +ZI)
  }
}

如果用的gcc工具鏈,則要編寫gcc的鏈接腳本ld文件;

2.3.3 下載固件

配置完成之后進行Build,然后通過SWD的方式先下載固件,進行實驗;

在這里插入圖片描述

3 Application

3.1 啟動流程

用戶的Application需要在IAP啟動完成后,才能正常執行;具體啟動過程,比正常應用的啟動多了一個IAP啟動的過程,並最終通過IAP引導進入Application;具體如下圖所示;
白色部分為IAP;
灰色部分為Application;

在這里插入圖片描述

圖中的0x8000004+N+M 就等於0x8003004,所以Application的啟動地址需要進行修改,另外還有其他需要修改的地方,下面會詳細指出。

3.2 IAP中的引導部分

參考IAP中的引導程序;

#define ApplicationAddress 0x8003000
      /* Jump to user application */
      JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4);
      Jump_To_Application = (pFunction) JumpAddress;
      /* Initialize user application's Stack Pointer */
      __set_MSP(*(__IO uint32_t*) ApplicationAddress);
      Jump_To_Application();

可以發現的是SP的值為0x8003000,指向棧頂,而0x8003004則為ResetHander的地址,系統會進行復位,然后開始Application正常啟動流程;

3.3 關於 VTOR

VTOR是向量表偏移量寄存器,它將用來告訴CPU,從Flash的哪個地方去取向量地址,第一個要取的是MSP的值,然后就是復位向量地址ResetHandler,如果這里設置錯誤,那么程序是無法正常啟動的。下面是標准庫中與其相關的代碼片段;

__IO uint32_t VTOR;  /*!< Offset: 0x08 Vector Table Offset Register */

/*!< FLASH base address in the alias region */
#define FLASH_BASE ((uint32_t)0x08000000)

/*!< Vector Table base offset field. This value must be a multiple of 0x200. */
#define VECT_TAB_OFFSET 0x0 

/* Vector Table Relocation in Internal FLASH. */
SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; 

所以Application中還需要修改VECT_TAB_OFFSET的值為0x3000;

參考M3權威指南:

如果需要動態地更改向量表,則對於任何器件來說,向量表的起始處都必須包含以下向量:

  • 主堆棧指針(MSP)的初始值
  • 復位向量
  • NMI
  • 硬 fault 服務例程
    后兩者也是必需的,因為有可能在引導過程中發生這兩種異常。可以在 SRAM 中開出一塊空間用於存儲向量表。在引導期間先填寫好各向量,然后在引導完成后,就可以啟用內存中的新向量表,從而實現向量可動態調整的能力。

3.4 Keil工程設置

3.4.1 Flash地址設置

IAP工程設置類似,這里的Application是另一個Keil工程,同樣的需要對Flash進行設置,如下圖所示;

在這里插入圖片描述
這里Application工程的Flash地址偏移了0x3000,正是之前Bootloader所占用的Flash空間大小,這里和VTOR的設置也必須保持一致;

在這里插入圖片描述

3.4.2 hex2bin

配置工程最終生成hex文件,如下圖所示;

在這里插入圖片描述

最終我們需要使用的是bin文件,所以,這里需要使用將hex文件轉成bin文件,本文使用hex2bin的工具;配置工程運行之后執行轉換文件的腳本;

在這里插入圖片描述
create_bin.bat

echo %cd%
set ROOT_PATH=.\..\..
set SRC=%ROOT_PATH%\..\Project\STM32F10x_StdPeriph_Template\MDK-ARM\STM3210B-EVAL\*.hex
set TOOL=%ROOT_PATH%\..\Bin\hex2bin.exe

if exist %SRC% (%TOOL% %SRC%)
exit

copy_firmware.bat

echo %cd%

set ROOT_PATH=.\..\..
set HEX_FILE=%ROOT_PATH%\..\Project\STM32F10x_StdPeriph_Template\MDK-ARM\STM3210B-EVAL\*.hex
set BIN_FILE=%ROOT_PATH%\..\Project\STM32F10x_StdPeriph_Template\MDK-ARM\STM3210B-EVAL\*.bin
set DST_DIR=%ROOT_PATH%\..\Firmware\
if exist %HEX_FILE% (XCOPY /Y /S /F %HEX_FILE% %DST_DIR%)
if exist %BIN_FILE% (XCOPY /Y /S /F %BIN_FILE% %DST_DIR%)
exit

最終在Build之后,可以在Firmware中找到STM321-APP.bin,這個文件就是要用來IAP程序進行串口下載的程序。

3.4.3 用戶程序串口下載測試

SecureCRT軟件支持ymodem協議,可以安裝該軟件,打開串口連接,設置ymodem的協議;
打開菜單選項:OptionsSession Options,配置如下;

在這里插入圖片描述
為了便於測試,在STM32F1-APP進行串口發送以下信息,便於觀察APP是否正常啟動;

usart_printf(" \r\n STM32F1-APP start running*******************");

打開連接的串口,並根據終端提示進行操作,最終下載固件STM32F1-APP成功,並成功運行;

在這里插入圖片描述

4 附件

stm32f10x-bootloader


免責聲明!

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



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