STM32啟動檔案

2022-05-30 15:01:46

一、復位電路

在瞭解啟動檔案之前需要明白STM32的復位中斷流程,STM32的復位分為上電覆位和手動復位,復位的電路圖如下所示:

注意: 圖中的復位電路是低電平復位,有的MCU是高電平復位。

  • 上電覆位:顧名思義,上電覆位就是STM32通電時,硬體自動復位的過程。從復位電路中可知,當晶片剛通電時電容兩端沒離子存在,所以處於充電過程,此時復位引腳等同於接地,這一過程成為上電覆位。

  • 手動復位:手動復位是通過按鍵強行將復位引腳拉低,使晶片產生復位中斷。

二、啟動檔案分析準備

  1. STM32的啟動檔案字尾是".s"的檔案,開啟專案是可以看到專案中有一個startup_stm32f103xb.s的檔案,如下圖所示:

    開啟檔案後可以很清晰的看到STM32的啟動流程,不過這裡需要一些簡單的組合知識。沒學過組合的小夥伴也不用怕,我們只需要簡單的分析即可,這裡只分析流程不進行組合指令的編寫。

  2. 啟動檔案中常用的組合指令

    指令 作用
    EQU 定義字元常數,相當於C語言的 define
    AREA 組合一個新的程式碼段或資料段
    SPACE 分配記憶體空間
    PRESERVE8 當前檔案堆疊需按照 8 位元組對其
    EXPORT 宣告全域性屬性,可被外部檔案使用
    DCD 以字為單位分配記憶體,要求4位元組對齊,並初始化這些記憶體
    PROC 定義子程式,與 ENOP 成對使用,表示子程式結束
    WEAK 弱定義,如果外部檔案宣告了一個標號,則優先使用外部檔案定義的標號,如果外部檔案沒有定義,則使用當前位置的標號
    IMPORT 宣告標號來自外部檔案,跟 C 語言中的 EXTERN 關鍵字類似
    B 跳轉到一個標號
    END 到達檔案的末尾,檔案結束
    IF,ELSE,ENDIF 組合條件分支語句
    LDR 從記憶體中載入字到一個暫存器中
    BL 跳轉到由暫存器/標號給出的地址,並把跳轉前的下條指令地址儲存到 LR
    BLX 跳轉到由暫存器給出的地址,並根據暫存器的LSE確定處理器的狀態,還要把跳轉前的下條指令地址儲存到LR
    BX 跳轉到由暫存器/標號給出的地址,不用返回

    注意: ALIGN是編譯器對指令或者資料的存放地址進行對齊,一般需要跟一個立即數,預設表示 4 位元組對齊。需要注意的是:這個不是ARM的指令,是編譯器的

  3. 啟動流程
    (1) 硬體上電覆位。
    (2) 初始化指標 SP=_initial_sp 和 PC == Reset_Handler。
    (3) 執行復位中斷服務程式。

三、啟動檔案的作用

  1. 初始化堆疊指標SP;
  2. 初始化程式計數器指標 PC;
  3. 設定堆、棧的大小;
  4. 設定異常向量表的入口;
  5. 設定外部SRAM作為資料記憶體(這個由使用者設定,一般的開發板沒有外部SRAM)
  6. 設定C庫的分支入口__main(最終呼叫mian函數)
  7. 使用庫函數專案時,啟動檔案還呼叫了SystemInit函數設定系統時鐘。

四、啟動程式碼詳解

  1. 開闢棧(stack)空間,用於區域性變數、函數呼叫、函數的引數等使用。棧的大小不能超過內部SRAM大小。

    Stack_Size		EQU     0x400
    
            AREA    STACK, NOINIT, READWRITE, ALIGN=3
    Stack_Mem       SPACE   Stack_Size
    __initial_sp
    
    • EQU:表示宏定義的偽指令,偽指令並不會生成二進位制程式程式碼,也不會引起變數空間分配。0x400表示棧大小,注意這裡是以位元組為單位。
    • AREA:開闢一段可讀寫的資料空間,段名為stack,按照 8 位元組對齊。AREA後面的關鍵字表示這個段的屬性。
      (1) STACK:表示這個段的名字,可以任意命名。
      (2) NOINIT:表示此資料段不需要填入初始化資料。
      (3) READWRITE:表示此段可讀寫。
      (4) ALIGN=3:表示首地址按照 2 的 3次方對齊,也就是按照8位元組對齊。
    • SPACE 這行指令告訴組合器給STACK段分配0x400位元組的連續記憶體空間。
    • __initial_sp緊挨SPACE放置,表示棧的結束機制,棧是從高往低使用,所以結束地址就是棧頂地址。
  2. 開闢堆(heap)空間,主要用於動態記憶體分配,也就是malloc、calloc、realloc等函數分配的變數空間是在堆上。

    Heap_Size      EQU     0x200
    
            AREA    HEAP, NOINIT, READWRITE, ALIGN=3
    __heap_base
    Heap_Mem        SPACE   Heap_Size
    __heap_limit
    
    • __heap_base:表示堆的開始地址
    • __heap_limit:表示堆的結束地址
  3. 檔案屬性定義

    PRESERVE8
    THUMB
    
        ; Vector Table Mapped to Address 0 at Reset
    AREA    RESET, DATA, READONLY
    EXPORT  __Vectors
    EXPORT  __Vectors_End
    EXPORT  __Vectors_Size
    
    • PRESERVE8:指定當前檔案保持堆疊 8 位元組對齊
    • THUMB:表示後面的指令是 THUMB 指令集,CM4 採用的是 THUMB - 2指令集
    • AREA:定義一塊程式碼段,唯讀,段名是RESET。READONLY表示唯讀,預設就表示程式碼段了
    • EXPORT:語句將3個標號宣告為可被外部參照,主要提供給聯結器用於連線庫檔案或其他檔案
  4. 中斷向量表

    __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_IRQHandler          ; Tamper
                DCD     RTC_IRQHandler             ; RTC
                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_2_IRQHandler          ; ADC1_2
                DCD     USB_HP_CAN1_TX_IRQHandler  ; USB High Priority or CAN1 TX
                DCD     USB_LP_CAN1_RX0_IRQHandler ; USB Low  Priority or CAN1 RX0
                DCD     CAN1_RX1_IRQHandler        ; CAN1 RX1
                DCD     CAN1_SCE_IRQHandler        ; CAN1 SCE
                DCD     EXTI9_5_IRQHandler         ; EXTI Line 9..5
                DCD     TIM1_BRK_IRQHandler        ; TIM1 Break
                DCD     TIM1_UP_IRQHandler         ; TIM1 Update
                DCD     TIM1_TRG_COM_IRQHandler    ; TIM1 Trigger and Commutation
                DCD     TIM1_CC_IRQHandler         ; TIM1 Capture Compare
                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     USBWakeUp_IRQHandler       ; USB Wakeup from suspend
    __Vectors_End
    __Vectors_Size  EQU  __Vectors_End - __Vectors
    
    • __Vectors:為向量表其實地址
    • __Vectors_End:為向量表結束地址
    • __Vectors_Size:為向量表的大小。
    • DCD:表示分配1個4位元組的空間。每行DCD都會生成一個4位元組的二進位制程式碼。中斷向量表存放的實際上是中斷服務程式的入口地址,當異常(也就是中斷實踐)發生時,CPU的中斷系統會將相應的入口地址賦值給PC程式計數器,之後就開始執行中斷服務程式。
  5. 定義可讀程式碼段

    AREA    |.text|, CODE, READONLY
    
    • AREA:定義一個名為.test的可讀程式碼段
  6. 復位程式

    ; Reset handler
    Reset_Handler    PROC
                 EXPORT  Reset_Handler             [WEAK]
    IMPORT  __main
    IMPORT  SystemInit
                 LDR     R0, =SystemInit
                 BLX     R0
                 LDR     R0, =__main
                 BX      R0
                 ENDP
    
    • 復位子程式是系統上電後第一個執行的程式,呼叫SystemInit()函數初始化系統時鐘,然後呼叫C庫函數__main。
  7. 中斷復位子程式

    ; Dummy Exception Handlers (infinite loops which can be modified)
    
    NMI_Handler     PROC
                    EXPORT  NMI_Handler                [WEAK]
                    B       .
                    ENDP
    HardFault_Handler\
                    PROC
                    EXPORT  HardFault_Handler          [WEAK]
                    B       .
                    ENDP
    MemManage_Handler\
                    PROC
                    EXPORT  MemManage_Handler          [WEAK]
                    B       .
                    ENDP
    BusFault_Handler\
                    PROC
                    EXPORT  BusFault_Handler           [WEAK]
                    B       .
                    ENDP
    UsageFault_Handler\
                    PROC
                    EXPORT  UsageFault_Handler         [WEAK]
                    B       .
                    ENDP
    SVC_Handler     PROC
                    EXPORT  SVC_Handler                [WEAK]
                    B       .
                    ENDP
    DebugMon_Handler\
                    PROC
                    EXPORT  DebugMon_Handler           [WEAK]
                    B       .
                    ENDP
    PendSV_Handler  PROC
                    EXPORT  PendSV_Handler             [WEAK]
                    B       .
                    ENDP
    SysTick_Handler PROC
                    EXPORT  SysTick_Handler            [WEAK]
                    B       .
                    ENDP
    
    Default_Handler PROC
    
                    EXPORT  WWDG_IRQHandler            [WEAK]
                    EXPORT  PVD_IRQHandler             [WEAK]
                    EXPORT  TAMPER_IRQHandler          [WEAK]
                    EXPORT  RTC_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_2_IRQHandler          [WEAK]
                    EXPORT  USB_HP_CAN1_TX_IRQHandler  [WEAK]
                    EXPORT  USB_LP_CAN1_RX0_IRQHandler [WEAK]
                    EXPORT  CAN1_RX1_IRQHandler        [WEAK]
                    EXPORT  CAN1_SCE_IRQHandler        [WEAK]
                    EXPORT  EXTI9_5_IRQHandler         [WEAK]
                    EXPORT  TIM1_BRK_IRQHandler        [WEAK]
                    EXPORT  TIM1_UP_IRQHandler         [WEAK]
                    EXPORT  TIM1_TRG_COM_IRQHandler    [WEAK]
                    EXPORT  TIM1_CC_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  USBWakeUp_IRQHandler       [WEAK]
    
    WWDG_IRQHandler
    PVD_IRQHandler
    TAMPER_IRQHandler
    RTC_IRQHandler
    FLASH_IRQHandler
    RCC_IRQHandler
    EXTI0_IRQHandler
    EXTI1_IRQHandler
    EXTI2_IRQHandler
    EXTI3_IRQHandler
    EXTI4_IRQHandler
    DMA1_Channel1_IRQHandler
    DMA1_Channel2_IRQHandler
    DMA1_Channel3_IRQHandler
    DMA1_Channel4_IRQHandler
    DMA1_Channel5_IRQHandler
    DMA1_Channel6_IRQHandler
    DMA1_Channel7_IRQHandler
    ADC1_2_IRQHandler
    USB_HP_CAN1_TX_IRQHandler
    USB_LP_CAN1_RX0_IRQHandler
    CAN1_RX1_IRQHandler
    CAN1_SCE_IRQHandler
    EXTI9_5_IRQHandler
    TIM1_BRK_IRQHandler
    TIM1_UP_IRQHandler
    TIM1_TRG_COM_IRQHandler
    TIM1_CC_IRQHandler
    TIM2_IRQHandler
    TIM3_IRQHandler
    TIM4_IRQHandler
    I2C1_EV_IRQHandler
    I2C1_ER_IRQHandler
    I2C2_EV_IRQHandler
    I2C2_ER_IRQHandler
    SPI1_IRQHandler
    SPI2_IRQHandler
    USART1_IRQHandler
    USART2_IRQHandler
    USART3_IRQHandler
    EXTI15_10_IRQHandler
    RTC_Alarm_IRQHandler
    USBWakeUp_IRQHandler
    
                    B       .
    
                    ENDP
    
    
    • WEAK:如果外部檔案中定義了此中斷函數,優先使用外部檔案中的中斷函數,反之使用當前中斷函數。
    • ".":表示無限迴圈
    • 如果我們在使用某個外設的時候,開啟了某個中斷,但是又忘記編寫配套的中斷服務程式需或者函數名寫錯時,當相應的中斷產生時,程式就會跳轉到啟動檔案預先寫好的空中斷函數中,並且在這個空函數中無限迴圈,即程式就死在這裡。
  8. 使用者堆疊初始化

                   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
    
    • ALIGN:對指令或者資料存放的地址進行對齊,後面會跟一個立即數。預設表示4位元組對齊。
    • __user_initial_stackheap:初始化棧和堆(使用預設C庫時,由__main函數進行呼叫)
    • 如果使用微庫時,呼叫__MICROLIB部分的程式,反之使用預設的C庫,然後初始化使用者堆疊大小。微庫的使用如下圖所示:

參考文獻

STM32啟動檔案————startup_stm32f10x_hd.s:https://wenku.baidu.com/view/3275eee00ba1284ac850ad02de80d4d8d15a0198.html