一、復位電路
在瞭解啟動檔案之前需要明白STM32的復位中斷流程,STM32的復位分為上電覆位和手動復位,復位的電路圖如下所示:
注意: 圖中的復位電路是低電平復位,有的MCU是高電平復位。
-
上電覆位:顧名思義,上電覆位就是STM32通電時,硬體自動復位的過程。從復位電路中可知,當晶片剛通電時電容兩端沒離子存在,所以處於充電過程,此時復位引腳等同於接地,這一過程成為上電覆位。
-
手動復位:手動復位是通過按鍵強行將復位引腳拉低,使晶片產生復位中斷。
二、啟動檔案分析準備
-
STM32的啟動檔案字尾是".s"的檔案,開啟專案是可以看到專案中有一個startup_stm32f103xb.s的檔案,如下圖所示:
開啟檔案後可以很清晰的看到STM32的啟動流程,不過這裡需要一些簡單的彙編知識。沒學過彙編的小夥伴也不用怕,我們只需要簡單的分析即可,這裡只分析流程不進行彙編指令的編寫。
-
啟動檔案中常用的彙編指令
指令 作用 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的指令,是編譯器的
-
啟動流程
(1) 硬體上電覆位。
(2) 初始化指標 SP=_initial_sp 和 PC == Reset_Handler。
(3) 執行復位中斷服務程式。
三、啟動檔案的作用
- 初始化堆疊指標SP;
- 初始化程式計數器指標 PC;
- 設定堆、棧的大小;
- 設定異常向量表的入口;
- 配置外部SRAM作為資料儲存器(這個由使用者配置,一般的開發板沒有外部SRAM)
- 設定C庫的分支入口__main(最終呼叫mian函式)
- 使用庫函式專案時,啟動檔案還呼叫了SystemInit函式配置系統時鐘。
四、啟動程式碼詳解
-
開闢棧(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放置,表示棧的結束機制,棧是從高往低使用,所以結束地址就是棧頂地址。
-
開闢堆(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:表示堆的結束地址
-
檔案屬性定義
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個標號宣告為可被外部引用,主要提供給聯結器用於連線庫檔案或其他檔案
-
中斷向量表
__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程式計數器,之後就開始執行中斷服務程式。
-
定義可讀程式碼段
AREA |.text|, CODE, READONLY
- AREA:定義一個名為.test的可讀程式碼段
-
復位程式
; 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。
-
中斷復位子程式
; 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:如果外部檔案中定義了此中斷函式,優先使用外部檔案中的中斷函式,反之使用當前中斷函式。
- ".":表示無限迴圈
- 如果我們在使用某個外設的時候,開啟了某個中斷,但是又忘記編寫配套的中斷服務程式需或者函式名寫錯時,當相應的中斷產生時,程式就會跳轉到啟動檔案預先寫好的空中斷函式中,並且在這個空函式中無限迴圈,即程式就死在這裡。
-
使用者堆疊初始化
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