STM32單片機Bootloader設計(上)

2022-01-01 樂創客

   STM32的啟動文件

STM32作為一款單片機,它的啟動方式很簡單,即當Boot配置了從內部Flash啟動模式之後,一上電程序就會從0x8000000地址處開始執行文件,因此我們在使用Keil設置程序起始地址的時候,需要將這個Flash地址設置成0x8000000,只有將這個地址設置成0x8000000,生成的hex文件才可以被正常燒錄到此地址,單片機上電之後才可以正常啟動。而如果使用J-Flash工具燒寫Hex文件時,這個地址會自動根據Hex文件解析出來。然而如果當你燒寫二進位Bin文件時,還需要手動將單片機的起始地址制定出來,關於Hex文件和Bin文件的異同點,這個又是可以長篇大論一番了,我們下次特別寫文章來講。

圖1 Keil設置起始地址和空間

STM32啟動文件

;********************* (C) COPYRIGHT 2017 STMicroelectronics ********************;* File Name          : startup_stm32l151xb.s;* Author             : MCD Application Team;* Description        : STM32L151XB Devices vector for MDK-ARM toolchain.;*                      This module performs:;*                      - Set the initial SP;*                      - Set the initial PC == Reset_Handler;*                      - Set the vector table entries with the exceptions ISR ;*                        address.;*                      - Configure the system clock;*                      - Branches to __main in the C library (which eventually;*                        calls main()).;*                      After Reset the Cortex-M3 processor is in Thread mode,;*                      priority is Privileged, and the Stack is set to Main.;********************************************************************************;*;* Copyright (c) 2017 STMicroelectronics. All rights reserved.;*;* This software component is licensed by ST under BSD 3-Clause license,;* the "License"; You may not use this file except in compliance with the;* License. You may obtain a copy of the License at:;*                        opensource.org/licenses/BSD-3-Clause;*;*******************************************************************************;* <<< Use Configuration Wizard in Context Menu >>>;; Amount of memory (in bytes) allocated for Stack; Tailor this value to your application needs; <h> Stack Configuration;   <o> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>; </h>
Stack_Size EQU 0x00000400
AREA STACK, NOINIT, READWRITE, ALIGN=3Stack_Mem SPACE Stack_Size__initial_sp

; <h> Heap Configuration; <o> Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>; </h>
Heap_Size EQU 0x00000200
AREA HEAP, NOINIT, READWRITE, ALIGN=3__heap_baseHeap_Mem SPACE Heap_Size__heap_limit
PRESERVE8 THUMB

; Vector Table Mapped to Address 0 at Reset AREA RESET, DATA, READONLY EXPORT __Vectors EXPORT __Vectors_End EXPORT __Vectors_Size
__Vectors DCD __initial_sp ; Top of Stack DCD Reset_Handler ; Reset Handler DCD NMI_Handler ; NMI Handler DCD HardFault_Handler ; Hard Fault Handler DCD MemManage_Handler ; MPU Fault Handler DCD BusFault_Handler ; Bus Fault Handler DCD UsageFault_Handler ; Usage Fault Handler DCD 0 ; Reserved DCD 0 ; Reserved DCD 0 ; Reserved DCD 0 ; Reserved DCD SVC_Handler ; SVCall Handler DCD DebugMon_Handler ; Debug Monitor Handler DCD 0 ; Reserved DCD PendSV_Handler ; PendSV Handler DCD SysTick_Handler ; SysTick Handler
; External Interrupts DCD WWDG_IRQHandler ; Window Watchdog DCD PVD_IRQHandler ; PVD through EXTI Line detect DCD TAMPER_STAMP_IRQHandler ; Tamper and Time Stamp DCD RTC_WKUP_IRQHandler ; RTC Wakeup DCD FLASH_IRQHandler ; FLASH DCD RCC_IRQHandler ; RCC DCD EXTI0_IRQHandler ; EXTI Line 0 DCD EXTI1_IRQHandler ; EXTI Line 1 DCD EXTI2_IRQHandler ; EXTI Line 2 DCD EXTI3_IRQHandler ; EXTI Line 3 DCD EXTI4_IRQHandler ; EXTI Line 4 DCD DMA1_Channel1_IRQHandler ; DMA1 Channel 1 DCD DMA1_Channel2_IRQHandler ; DMA1 Channel 2 DCD DMA1_Channel3_IRQHandler ; DMA1 Channel 3 DCD DMA1_Channel4_IRQHandler ; DMA1 Channel 4 DCD DMA1_Channel5_IRQHandler ; DMA1 Channel 5 DCD DMA1_Channel6_IRQHandler ; DMA1 Channel 6 DCD DMA1_Channel7_IRQHandler ; DMA1 Channel 7 DCD ADC1_IRQHandler ; ADC1 DCD USB_HP_IRQHandler ; USB High Priority DCD USB_LP_IRQHandler ; USB Low Priority DCD DAC_IRQHandler ; DAC DCD COMP_IRQHandler ; COMP through EXTI Line DCD EXTI9_5_IRQHandler ; EXTI Line 9..5 DCD 0 ; Reserved DCD TIM9_IRQHandler ; TIM9 DCD TIM10_IRQHandler ; TIM10 DCD TIM11_IRQHandler ; TIM11 DCD TIM2_IRQHandler ; TIM2 DCD TIM3_IRQHandler ; TIM3 DCD TIM4_IRQHandler ; TIM4 DCD I2C1_EV_IRQHandler ; I2C1 Event DCD I2C1_ER_IRQHandler ; I2C1 Error DCD I2C2_EV_IRQHandler ; I2C2 Event DCD I2C2_ER_IRQHandler ; I2C2 Error DCD SPI1_IRQHandler ; SPI1 DCD SPI2_IRQHandler ; SPI2 DCD USART1_IRQHandler ; USART1 DCD USART2_IRQHandler ; USART2 DCD USART3_IRQHandler ; USART3 DCD EXTI15_10_IRQHandler ; EXTI Line 15..10 DCD RTC_Alarm_IRQHandler ; RTC Alarm through EXTI Line DCD USB_FS_WKUP_IRQHandler ; USB FS Wakeup from suspend DCD TIM6_IRQHandler ; TIM6 DCD TIM7_IRQHandler ; TIM7 __Vectors_End
__Vectors_Size EQU __Vectors_End - __Vectors
AREA |.text|, CODE, READONLY
; Reset handler routineReset_Handler PROC EXPORT Reset_Handler [WEAK] IMPORT __main IMPORT SystemInit LDR R0, =SystemInit BLX R0 LDR R0, =__main BX R0 ENDP
; Dummy Exception Handlers (infinite loops which can be modified)
NMI_Handler PROC EXPORT NMI_Handler [WEAK] B . ENDPHardFault_Handler\ PROC EXPORT HardFault_Handler [WEAK] B . ENDPMemManage_Handler\ PROC EXPORT MemManage_Handler [WEAK] B . ENDPBusFault_Handler\ PROC EXPORT BusFault_Handler [WEAK] B . ENDPUsageFault_Handler\ PROC EXPORT UsageFault_Handler [WEAK] B . ENDPSVC_Handler PROC EXPORT SVC_Handler [WEAK] B . ENDPDebugMon_Handler\ PROC EXPORT DebugMon_Handler [WEAK] B . ENDPPendSV_Handler PROC EXPORT PendSV_Handler [WEAK] B . ENDPSysTick_Handler PROC EXPORT SysTick_Handler [WEAK] B . ENDP
Default_Handler PROC
EXPORT WWDG_IRQHandler [WEAK] EXPORT PVD_IRQHandler [WEAK] EXPORT TAMPER_STAMP_IRQHandler [WEAK] EXPORT RTC_WKUP_IRQHandler [WEAK] EXPORT FLASH_IRQHandler [WEAK] EXPORT RCC_IRQHandler [WEAK] EXPORT EXTI0_IRQHandler [WEAK] EXPORT EXTI1_IRQHandler [WEAK] EXPORT EXTI2_IRQHandler [WEAK] EXPORT EXTI3_IRQHandler [WEAK] EXPORT EXTI4_IRQHandler [WEAK] EXPORT DMA1_Channel1_IRQHandler [WEAK] EXPORT DMA1_Channel2_IRQHandler [WEAK] EXPORT DMA1_Channel3_IRQHandler [WEAK] EXPORT DMA1_Channel4_IRQHandler [WEAK] EXPORT DMA1_Channel5_IRQHandler [WEAK] EXPORT DMA1_Channel6_IRQHandler [WEAK] EXPORT DMA1_Channel7_IRQHandler [WEAK] EXPORT ADC1_IRQHandler [WEAK] EXPORT USB_HP_IRQHandler [WEAK] EXPORT USB_LP_IRQHandler [WEAK] EXPORT DAC_IRQHandler [WEAK] EXPORT COMP_IRQHandler [WEAK] EXPORT EXTI9_5_IRQHandler [WEAK] EXPORT TIM9_IRQHandler [WEAK] EXPORT TIM10_IRQHandler [WEAK] EXPORT TIM11_IRQHandler [WEAK] EXPORT TIM2_IRQHandler [WEAK] EXPORT TIM3_IRQHandler [WEAK] EXPORT TIM4_IRQHandler [WEAK] EXPORT I2C1_EV_IRQHandler [WEAK] EXPORT I2C1_ER_IRQHandler [WEAK] EXPORT I2C2_EV_IRQHandler [WEAK] EXPORT I2C2_ER_IRQHandler [WEAK] EXPORT SPI1_IRQHandler [WEAK] EXPORT SPI2_IRQHandler [WEAK] EXPORT USART1_IRQHandler [WEAK] EXPORT USART2_IRQHandler [WEAK] EXPORT USART3_IRQHandler [WEAK] EXPORT EXTI15_10_IRQHandler [WEAK] EXPORT RTC_Alarm_IRQHandler [WEAK] EXPORT USB_FS_WKUP_IRQHandler [WEAK] EXPORT TIM6_IRQHandler [WEAK] EXPORT TIM7_IRQHandler [WEAK]
WWDG_IRQHandlerPVD_IRQHandlerTAMPER_STAMP_IRQHandlerRTC_WKUP_IRQHandlerFLASH_IRQHandlerRCC_IRQHandlerEXTI0_IRQHandlerEXTI1_IRQHandlerEXTI2_IRQHandlerEXTI3_IRQHandlerEXTI4_IRQHandlerDMA1_Channel1_IRQHandlerDMA1_Channel2_IRQHandlerDMA1_Channel3_IRQHandlerDMA1_Channel4_IRQHandlerDMA1_Channel5_IRQHandlerDMA1_Channel6_IRQHandlerDMA1_Channel7_IRQHandlerADC1_IRQHandlerUSB_HP_IRQHandlerUSB_LP_IRQHandlerDAC_IRQHandlerCOMP_IRQHandlerEXTI9_5_IRQHandlerTIM9_IRQHandlerTIM10_IRQHandlerTIM11_IRQHandlerTIM2_IRQHandlerTIM3_IRQHandlerTIM4_IRQHandlerI2C1_EV_IRQHandlerI2C1_ER_IRQHandlerI2C2_EV_IRQHandlerI2C2_ER_IRQHandlerSPI1_IRQHandlerSPI2_IRQHandlerUSART1_IRQHandlerUSART2_IRQHandlerUSART3_IRQHandlerEXTI15_10_IRQHandlerRTC_Alarm_IRQHandlerUSB_FS_WKUP_IRQHandlerTIM6_IRQHandlerTIM7_IRQHandler
B .
ENDP
ALIGN
;*******************************************************************************; User Stack and Heap initialization;******************************************************************************* IF :DEF:__MICROLIB EXPORT __initial_sp EXPORT __heap_base EXPORT __heap_limit ELSE IMPORT __use_two_region_memory EXPORT __user_initial_stackheap __user_initial_stackheap
LDR R0, = Heap_Mem LDR R1, =(Stack_Mem + Stack_Size) LDR R2, = (Heap_Mem + Heap_Size) LDR R3, = Stack_Mem BX LR
ALIGN
ENDIF
END
;************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE*****

首先讓我們來看下STM32啟動文件,當MCU上電復位之後,整個程序會跳轉到以0x8000000為基址,偏移0的地址處,即還是0x8000000。但是STM32的0x8000000地址處存放的並不是整個晶片的第一句指令,而是整個晶片的堆棧初始化程序,如圖2所示。

圖2 0x8000000偏移0地址處的堆棧初始化程序指針

由於STM32的地址空間都是4位元組對齊的,因此這個棧頂指針的存放空間為4位元組,所以STM32復位之後跳轉的地址應該是0x8000000基址偏移4個字節,即0x8000004。如同3所示。

圖3 STM32復位跳轉地址

圖3中的程序非常淺顯易懂,第136和137行,即將程序跳轉到SystemInit處,這是個C語言函數,定義在「system_stm32l1xx.c」文件裡,它的目的就是對中斷向量表起始地址進行指定,也就是圖2中的「__Vector」處。當然CM3內核和CM0內核關於SCB(系統控制塊)的定義有些許差別,CM0不在本文討論中,但是CM3和CM4的中斷向量表映射機制還是很相似的。

圖4 SystemInit函數映射中斷向量表

圖4中我們可以看到,SCB中關於Vector的地址是通過符號FLASH_BASE和VECT_TAB_OFFSET計算出來的,我們可以找到關於它們的定義,如圖5所示。

圖5 FLASH_BASE和VECT_TAB_OFFSET的定義

通過圖5中的計算,正好可以得出整個中斷向量表被映射到了0x8000000地址處。

    STM32的FLASH分配

前面的大段文章內容中,頻繁提及了一個關鍵的數值,即0x8000000,那麼這個0x8000000到底是怎麼來的呢?這個數值並不是平白無故拍腦袋想出來的。之前我們就說過,ARM體系的存儲器結構是其一大特色,而這個0x8000000正是整個STM32內置FLASH的起始地址。我們隨便打開一份STM32的數據手冊,在存儲器章節裡面就可以看到STM32全部的存儲器定義。如圖6所示。

圖6 STM32內部FLASH的起始地址

   STM32的Bootloader思路

拋開所有的Bootloader高級功能來說,我們設計STM32 Bootloader的主要目的有兩個,第一個為方便程序燒寫和更新,第二個目前是從Bootloader程序中跳轉(引導)用戶的應用程式。這兩個目的中,對於Bootloader來說程序跳轉尤其重要,因為程序跳轉成不成功將會嚴重影響整個用戶程序的運行狀態。因而,怎麼跳,何時跳,跳到哪裡,則是下篇文章的著重討論部分。

前面一個FLASH燒寫,可以根據自己的特殊要求來定製,只要嚴格安裝HEX文件指定的地址和數據的關係,一般不會出錯。

本文分析了STM32啟動時比較重要的一些定義和函數跳轉,下篇將會開始著手設計一個STM32 Bootloader。

相關焦點

  • STM32單片機的Bootloader詳解(1)
    本質上IAP和單片機內部固化的ISP程序一樣,都是負責幫你把新程序下進單片機的FLASH。那為什麼還需要IAP呢?        舉個例子,ISP的啟動一般需要硬體控制BOOT0,因此對於加USB轉TTL和三極體電容電阻等組成自動下載電路這種燒錢做法一般做產品肯定是不提倡的。
  • STM32單片機的Bootloader詳解(2)
    總不能需要編輯個文檔就買一套Word吧,總不能學個單片機花數十萬買MDK和AD授權吧。一定程度上這些也是大多數人需求。這裡關於故意引導用戶習慣養成、低價&盜版擠壓壟斷軟體市場壟斷等等的話題我們就不談了。        那麼如果你不想你做的產品輕輕鬆鬆被人家複製,你就需要花一點功夫了。
  • ARM、單片機、stm32、51單片機、和開發板的概念、區別及包含關係
    全球超過95%的智慧型手機採用ARM架構,ARM設計了大量的高性價比、耗能低的精簡指令集計算(RISC)處理器。這裡的ARM指的是處理器。處理器也是CPU的意思,所以ARM處理器就是CPU的意思。ARM公司不生產晶片、生產CPU.是一個32位精簡指令集處理器架構,ARM處理器包含以下幾個系列的處理器產品以及其它廠商實現的基於ARM體系結構的處理器。
  • 【C++開發Stm32-環境搭建】 Stm32f103c8t6支持Arduino庫開發
    那就用C Plus Plus來寫stm32單片機代碼吧!藉助Arduino的庫,輕鬆使用面向對象的思想開發單片機。本教程分享stm32支持Arduino庫開發的環境搭建。開始上開發板和燒錄器!!接著就是編程開發了。
  • 如何在keil中仿真stm32單片機
    一、序言在學習51單片機的時候,經常會使用keil+protues的方式來做一些實驗,這樣的模擬仿真為我們節省了很多硬體和時間成本
  • 深入分析STM32單片機的RAM和FLASH
    作為單片機內部一個重要組成部分,存儲器佔有很重要的地位,今天就來聊聊我對於單片機的內部存儲器RAM和FLASH的一些認識和理解。    存儲器是單片機結構的重要組成部分,存儲器是用來存儲編譯好的程序代碼和數據的,有了存儲器單片機系統才具有記憶功能。按照存儲介質的特性,可以分「易失性存儲器」和「非易失性存儲器」兩類。
  • 詳解STM32單片機的堆棧
    學習STM32單
  • STM32與Arduino問答集
    v=TePglhSkghg           stm32duino 支持包:https://github.com/rogerclarkmelbourne/Arduino_STM32         2.如何上傳代碼到你的板上:                   a.通過串口適配器(TTL電平:3.3V):http://stm32duino.com
  • STM32系統bootloader應用
    嵌入式開發中,經常需要bootloader進行程序固件升級和系統維護,所以bootloader是必不可少的功能。
  • STM32 與 Arduino
    stm32duino 對常見的 MCU 做了廣泛的支持,開發板之間的不同大都體現在 MCU 的外圍電路上,去複製同 MCU 的文件夾改動量會小很多。2、讓加入的自定義配置與 Arduino 關聯。下面以 ATMega 單片機(Arduino 原生支持的單片機)為例,說下怎樣在 VSCode 下開發 Arduino(以 Ubuntu 系統為例)。下面的截圖裡看到了 platformio,因為 Sugar 在 Ubuntu 上的 VSCode 下同時裝了 platformio 和 Arduino 兩個組件。但使用的是 Arduino 與 platformio 無關。
  • 預熱 | 萬眾期待的單片機、Linux二合一的STM32MP157開發板亮相
    均支持於100ask_stm32mp157_pro硬體開發平臺,廣泛應用於生活的各種智能場景。百問網STM32mp157開發板GUI演示視頻我們為什麼要做STM32mp157開發板?從教學角度看硬體描述Cortex M4跑單片機、RTOS,用keil開發,跟STM32F103一模一樣Cortex A7*2跑Linux,可以引入SMP的知識,以覆蓋單CPU系統的知識GPU可以實現更炫的GUI效果,可以跑一些AI算法從做產品角度看硬體描述MPU+MCU需要單片機+Linux的場合,用STM32MP157就可以實現GPU可以實現更炫的GUI效果,可以跑一些AI算法性價比高作為多核異構的晶片
  • STM32單片機輕鬆入門與實踐 — 暢學單片機
    STM32的優勢來源於兩路高級外設總線-APB結構,其中一根告訴APB,可以達到CPU的運行頻率,連接到該總線上的外設能以更高的速度運行。        本課程是STM32單片機學習者從入門到深入的一套經典視頻教程,以初學者為對象,從零開始手把手教你學習單片機,循序漸進地基於理論講解並結合實驗項目實戰開發,講解當前最熱門的STM32單片機的C程序設計!
  • STM32下載程序新思路--使用串口下載STM32程序
    注意:STM32F1系列單片機RX/TX分別對應單片機上的PA9/PA10兩個引腳,在使用單片機(第一次下載)時需要將單片機上的BOOT0\BOOT1進行接地處理。有一個跳帽,插上就行了。ISP 簡介:ISP(In-System Programming)在系統可編程,指電路板上的空白器件可以編程寫入最終用戶代碼, 而不需要從電路板上取下器件,已經編程的器件也可以用 ISP 方式擦除或再編程。ISP 的時候需要用到(bootloader)自舉程序,自舉程序存儲在 STM32 器件的內部自舉ROM 存儲器(系統存儲器)中。
  • 這樣學習STM32單片機,從菜鳥到牛人很簡單!
    我想說,為了學習單片機而去學習單片機的思路不對。你問,如何系統地入門學習stm32呢?
  • 如何讓開源LED電子時鐘屏跑起Bootloader和OTA升級
    APP和download區是採用1:1的方式,還有bootloader分區一般設計為16K到32K,顯然這樣256K的內部FLASH不能滿足要求,所以需要使用外部FLASH,設計分區表為:內部flash的前32K為bootloader分區,剩餘的內部FLASH (256-32 = 224)224K為APP分區,download分區設在外部flash區。
  • STM32單片機和51單片機有何區別?
    在我們自己的個人電腦中,CPU、RAM、ROM、I/O這些都是單獨的晶片,然後這些晶片被安裝在一個主板上,這樣就構成了我們的PC主板,進而組裝成電腦。而單片機將這些都集中在了一個晶片上。應用最廣泛的8位單片機,當然也是初學者們最容易上手學習的單片機。
  • STM32單片機最小系統詳解
    在最小系統保證正確的基礎上,可以依次添加其他功能模塊或器件,使之單片機具有實際功能。STM32單片機最小系統包括一個復位電路和一個時鐘電路。如下圖1所示。圖中復位電路使用的是上電復位電路,STM32單片機NRST引腳輸入低電平,則發生復位。
  • 當Arduino遇上STM32
    Arduino;不過Atmega328所屬的AVR單片機,終究還是老點了,算起來差不多是20年前的主流了,現在流行的是ARM,今天我們就來聊一款Arduino與STM32邂逅的產物——Olimexino STM32。
  • 手把手教學《60天學會stm32單片機培訓班》今日更新知識點260+
    以下200+知識點,僅僅是《60天學會stm32單片機培訓班》眾多知識點中的一小部分,還有一大批知識點我們會持續更新,敬請關注。1.什麼是單片機?有什麼用?都用在我們生活中什麼地方?2.什麼是掩膜單片機?究竟可以做到多小?3.單片機有什麼特點?價格?功耗等等。。。4.單片機由什麼組成?5.什麼是外設?
  • u-boot和bootloader的區別
    今天就來簡單講講 u-boot 和 bootloader 的內容以及區別。比Bootloader從字面上來看就是啟動加載的意思。用過電腦的都知道,windows開機時會首先加載bios,然後是系統內核,最後啟動完畢。那麼bootloader就相當於手機的bios,它在手機啟動的時候根據基帶初始化硬體,然後引導系統內核,直到系統啟動。