STM32啟動檔案深度解析
阿新 • • 發佈:2019-01-26
STM32啟動過程全面解析,包括啟動過程的介紹、啟動程式碼的陳列以及深入解析。相對於ARM上一代的主流ARM7/ARM9核心架構,新一代Cortex核心架構的
啟動方式有了比較大的變化。ARM7/ARM9核心的控制器在復位後,CPU會從儲存空間的絕對地址0x000000取出第一條指令執行復位中斷服務程式的方式啟動,
即固定了復位後的起始地址為0x000000(PC = 0x000000)同時中斷向量表的位置並不是固定的。而Cortex-M3核心則正好相反,有3種情況:
1、 通過boot引腳設定可以將中斷向量表定位於SRAM區,即起始地址為0x2000000,同時復位後PC指標位於0x2000000處;
2、 通過boot引腳設定可以將中斷向量表定位於FLASH區,即起始地址為0x8000000,同時復位後PC指標位於0x8000000處;
3、 通過boot引腳設定可以將中斷向量表定位於內建Bootloader區,本文不對這種情況做論述;
Cortex-M3核心規定,起始地址必須存放堆頂指標,而第二個地址則必須存放復位中斷入口向量地址,這樣在Cortex-M3核心復位後,會自動從起始地址的
下一個32位空間取出復位中斷入口向量,跳轉執行復位中斷服務程式。對比ARM7/ARM9核心,Cortex-M3核心則是固定了中斷向量表的位置而起始地址是可變
化的。
有了上述準備只是後,下面以STM32的f2xx韌體庫提供的啟動檔案“startup_stm32f2xx.s”為模板,對STM32的啟動過程做一個簡要而全面的解析。
;******************** (C) COPYRIGHT 2011 STMicroelectronics ********************
;* File Name : startup_stm32f2xx.s
;* Author : MCD Application Team
;* Version : V1.0.0
;* Date : 18-April-2011
;* Description : STM32F2xx devices vector table 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
;* - Branches to __main in the C library (which eventually
;* calls main()).
;* After Reset the CortexM3 processor is in Thread mode,
;* priority is Privileged, and the Stack is set to Main.
;* <<< Use Configuration Wizard in Context Menu >>>
;*******************************************************************************
; THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
; WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME.
; AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
; INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
; CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
; INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
;*******************************************************************************
; 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;定義棧空間大小為0x00000400,此語句等價於C:#define Stack_Size 0x00000400
AREA STACK, NOINIT, READWRITE, ALIGN=3;定義棧,,可讀寫,8位元組對齊
Stack_Mem SPACE Stack_Size;開闢一段大小為Stack_Size的記憶體空間作為棧
__initial_sp;標號__initial_sp,表示棧空間頂地址
; <h> Heap Configuration
; <o> Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>
Heap_Size EQU 0x00000200;定義堆空間大小為0x00000200個位元組
AREA HEAP, NOINIT, READWRITE, ALIGN=3;定義堆,,可讀寫,8位元組對齊
__heap_base ;標號__heap_base,表示堆空間起始地址
Heap_Mem SPACE Heap_Size;開闢一段大小為Heap_Size的記憶體空間作為堆。
__heap_limit ;標號__heap_limit,表示堆空間結束地址
PRESERVE8;告訴編譯器以8位元組對齊
THUMB;告訴編譯器使用THUMB指令集
; Vector Table Mapped to Address 0 at Reset
AREA RESET, DATA, READONLY;定義只讀資料段,實際上是在CODE區(假設STM32從FLASH啟動,則此中斷向量表起始地址即為0x8000000)
EXPORT __Vectors;將標號__Vectors宣告為全域性標號,這樣外部檔案就可以使用這個標號
EXPORT __Vectors_End;
EXPORT __Vectors_Size;
;建立中斷向量表
__Vectors DCD __initial_sp ; Top of Stack,存放於FLASH中的0x8000000地址處
DCD Reset_Handler ; Reset Handler,存放於FLASH中的0x8000004地址處
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 detection
DCD TAMP_STAMP_IRQHandler ; Tamper and TimeStamps through the EXTI line
DCD RTC_WKUP_IRQHandler ; RTC Wakeup through the EXTI line
DCD FLASH_IRQHandler ; FLASH
DCD RCC_IRQHandler ; RCC
DCD EXTI0_IRQHandler ; EXTI Line0
DCD EXTI1_IRQHandler ; EXTI Line1
DCD EXTI2_IRQHandler ; EXTI Line2
DCD EXTI3_IRQHandler ; EXTI Line3
DCD EXTI4_IRQHandler ; EXTI Line4
DCD DMA1_Stream0_IRQHandler ; DMA1 Stream 0
DCD DMA1_Stream1_IRQHandler ; DMA1 Stream 1
DCD DMA1_Stream2_IRQHandler ; DMA1 Stream 2
DCD DMA1_Stream3_IRQHandler ; DMA1 Stream 3
DCD DMA1_Stream4_IRQHandler ; DMA1 Stream 4
DCD DMA1_Stream5_IRQHandler ; DMA1 Stream 5
DCD DMA1_Stream6_IRQHandler ; DMA1 Stream 6
DCD ADC_IRQHandler ; ADC1, ADC2 and ADC3s
DCD CAN1_TX_IRQHandler ; CAN1 TX
DCD CAN1_RX0_IRQHandler ; CAN1 RX0
DCD CAN1_RX1_IRQHandler ; CAN1 RX1
DCD CAN1_SCE_IRQHandler ; CAN1 SCE
DCD EXTI9_5_IRQHandler ; External Line[9:5]s
DCD TIM1_BRK_TIM9_IRQHandler ; TIM1 Break and TIM9
DCD TIM1_UP_TIM10_IRQHandler ; TIM1 Update and TIM10
DCD TIM1_TRG_COM_TIM11_IRQHandler ; TIM1 Trigger and Commutation and TIM11
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 ; External Line[15:10]s
DCD RTC_Alarm_IRQHandler ; RTC Alarm (A and B) through EXTI Line
DCD OTG_FS_WKUP_IRQHandler ; USB OTG FS Wakeup through EXTI line
DCD TIM8_BRK_TIM12_IRQHandler ; TIM8 Break and TIM12
DCD TIM8_UP_TIM13_IRQHandler ; TIM8 Update and TIM13
DCD TIM8_TRG_COM_TIM14_IRQHandler ; TIM8 Trigger and Commutation and TIM14
DCD TIM8_CC_IRQHandler ; TIM8 Capture Compare
DCD DMA1_Stream7_IRQHandler ; DMA1 Stream7
DCD FSMC_IRQHandler ; FSMC
DCD SDIO_IRQHandler ; SDIO
DCD TIM5_IRQHandler ; TIM5
DCD SPI3_IRQHandler ; SPI3
DCD UART4_IRQHandler ; UART4
DCD UART5_IRQHandler ; UART5
DCD TIM6_DAC_IRQHandler ; TIM6 and DAC1&2 underrun errors
DCD TIM7_IRQHandler ; TIM7
DCD DMA2_Stream0_IRQHandler ; DMA2 Stream 0
DCD DMA2_Stream1_IRQHandler ; DMA2 Stream 1
DCD DMA2_Stream2_IRQHandler ; DMA2 Stream 2
DCD DMA2_Stream3_IRQHandler ; DMA2 Stream 3
DCD DMA2_Stream4_IRQHandler ; DMA2 Stream 4
DCD ETH_IRQHandler ; Ethernet
DCD ETH_WKUP_IRQHandler ; Ethernet Wakeup through EXTI line
DCD CAN2_TX_IRQHandler ; CAN2 TX
DCD CAN2_RX0_IRQHandler ; CAN2 RX0
DCD CAN2_RX1_IRQHandler ; CAN2 RX1
DCD CAN2_SCE_IRQHandler ; CAN2 SCE
DCD OTG_FS_IRQHandler ; USB OTG FS
DCD DMA2_Stream5_IRQHandler ; DMA2 Stream 5
DCD DMA2_Stream6_IRQHandler ; DMA2 Stream 6
DCD DMA2_Stream7_IRQHandler ; DMA2 Stream 7
DCD USART6_IRQHandler ; USART6
DCD I2C3_EV_IRQHandler ; I2C3 event
DCD I2C3_ER_IRQHandler ; I2C3 error
DCD OTG_HS_EP1_OUT_IRQHandler ; USB OTG HS End Point 1 Out
DCD OTG_HS_EP1_IN_IRQHandler ; USB OTG HS End Point 1 In
DCD OTG_HS_WKUP_IRQHandler ; USB OTG HS Wakeup through EXTI
DCD OTG_HS_IRQHandler ; USB OTG HS
DCD DCMI_IRQHandler ; DCMI
DCD CRYP_IRQHandler ; CRYP crypto
DCD HASH_RNG_IRQHandler ; Hash and Rng
__Vectors_End
__Vectors_Size EQU __Vectors_End - __Vectors
AREA |.text|, CODE, READONLY ;只讀程式碼段
; Reset handler
Reset_Handler PROC;復位中斷服務程式,PROC…ENDP結構表示程式的開始和結束
EXPORT Reset_Handler [WEAK] ;聲明覆位中斷向量Reset_Handler為全域性屬性,這樣外部檔案就可以呼叫此復位中斷服務
IMPORT SystemInit;宣告SystemInit標號
IMPORT __main;宣告__main標號
LDR R0, =SystemInit;跳轉到SystemInit地址執行
BLX R0;
LDR R0, =__main;跳轉__main地址執行
BX R0
ENDP
; 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 TAMP_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_Stream0_IRQHandler [WEAK]
EXPORT DMA1_Stream1_IRQHandler [WEAK]
EXPORT DMA1_Stream2_IRQHandler [WEAK]
EXPORT DMA1_Stream3_IRQHandler [WEAK]
EXPORT DMA1_Stream4_IRQHandler [WEAK]
EXPORT DMA1_Stream5_IRQHandler [WEAK]
EXPORT DMA1_Stream6_IRQHandler [WEAK]
EXPORT ADC_IRQHandler [WEAK]
EXPORT CAN1_TX_IRQHandler [WEAK]
EXPORT CAN1_RX0_IRQHandler [WEAK]
EXPORT CAN1_RX1_IRQHandler [WEAK]
EXPORT CAN1_SCE_IRQHandler [WEAK]
EXPORT EXTI9_5_IRQHandler [WEAK]
EXPORT TIM1_BRK_TIM9_IRQHandler [WEAK]
EXPORT TIM1_UP_TIM10_IRQHandler [WEAK]
EXPORT TIM1_TRG_COM_TIM11_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 OTG_FS_WKUP_IRQHandler [WEAK]
EXPORT TIM8_BRK_TIM12_IRQHandler [WEAK]
EXPORT TIM8_UP_TIM13_IRQHandler [WEAK]
EXPORT TIM8_TRG_COM_TIM14_IRQHandler [WEAK]
EXPORT TIM8_CC_IRQHandler [WEAK]
EXPORT DMA1_Stream7_IRQHandler [WEAK]
EXPORT FSMC_IRQHandler [WEAK]
EXPORT SDIO_IRQHandler [WEAK]
EXPORT TIM5_IRQHandler [WEAK]
EXPORT SPI3_IRQHandler [WEAK]
EXPORT UART4_IRQHandler [WEAK]
EXPORT UART5_IRQHandler [WEAK]
EXPORT TIM6_DAC_IRQHandler [WEAK]
EXPORT TIM7_IRQHandler [WEAK]
EXPORT DMA2_Stream0_IRQHandler [WEAK]
EXPORT DMA2_Stream1_IRQHandler [WEAK]
EXPORT DMA2_Stream2_IRQHandler [WEAK]
EXPORT DMA2_Stream3_IRQHandler [WEAK]
EXPORT DMA2_Stream4_IRQHandler [WEAK]
EXPORT ETH_IRQHandler [WEAK]
EXPORT ETH_WKUP_IRQHandler [WEAK]
EXPORT CAN2_TX_IRQHandler [WEAK]
EXPORT CAN2_RX0_IRQHandler [WEAK]
EXPORT CAN2_RX1_IRQHandler [WEAK]
EXPORT CAN2_SCE_IRQHandler [WEAK]
EXPORT OTG_FS_IRQHandler [WEAK]
EXPORT DMA2_Stream5_IRQHandler [WEAK]
EXPORT DMA2_Stream6_IRQHandler [WEAK]
EXPORT DMA2_Stream7_IRQHandler [WEAK]
EXPORT USART6_IRQHandler [WEAK]
EXPORT I2C3_EV_IRQHandler [WEAK]
EXPORT I2C3_ER_IRQHandler [WEAK]
EXPORT OTG_HS_EP1_OUT_IRQHandler [WEAK]
EXPORT OTG_HS_EP1_IN_IRQHandler [WEAK]
EXPORT OTG_HS_WKUP_IRQHandler [WEAK]
EXPORT OTG_HS_IRQHandler [WEAK]
EXPORT DCMI_IRQHandler [WEAK]
EXPORT CRYP_IRQHandler [WEAK]
EXPORT HASH_RNG_IRQHandler [WEAK]
WWDG_IRQHandler
PVD_IRQHandler
TAMP_STAMP_IRQHandler
RTC_WKUP_IRQHandler
FLASH_IRQHandler
RCC_IRQHandler
EXTI0_IRQHandler
EXTI1_IRQHandler
EXTI2_IRQHandler
EXTI3_IRQHandler
EXTI4_IRQHandler
DMA1_Stream0_IRQHandler
DMA1_Stream1_IRQHandler
DMA1_Stream2_IRQHandler
DMA1_Stream3_IRQHandler
DMA1_Stream4_IRQHandler
DMA1_Stream5_IRQHandler
DMA1_Stream6_IRQHandler
ADC_IRQHandler
CAN1_TX_IRQHandler
CAN1_RX0_IRQHandler
CAN1_RX1_IRQHandler
CAN1_SCE_IRQHandler
EXTI9_5_IRQHandler
TIM1_BRK_TIM9_IRQHandler
TIM1_UP_TIM10_IRQHandler
TIM1_TRG_COM_TIM11_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
OTG_FS_WKUP_IRQHandler
TIM8_BRK_TIM12_IRQHandler
TIM8_UP_TIM13_IRQHandler
TIM8_TRG_COM_TIM14_IRQHandler
TIM8_CC_IRQHandler
DMA1_Stream7_IRQHandler
FSMC_IRQHandler
SDIO_IRQHandler
TIM5_IRQHandler
SPI3_IRQHandler
UART4_IRQHandler
UART5_IRQHandler
TIM6_DAC_IRQHandler
TIM7_IRQHandler
DMA2_Stream0_IRQHandler
DMA2_Stream1_IRQHandler
DMA2_Stream2_IRQHandler
DMA2_Stream3_IRQHandler
DMA2_Stream4_IRQHandler
ETH_IRQHandler
ETH_WKUP_IRQHandler
CAN2_TX_IRQHandler
CAN2_RX0_IRQHandler
CAN2_RX1_IRQHandler
CAN2_SCE_IRQHandler
OTG_FS_IRQHandler
DMA2_Stream5_IRQHandler
DMA2_Stream6_IRQHandler
DMA2_Stream7_IRQHandler
USART6_IRQHandler
I2C3_EV_IRQHandler
I2C3_ER_IRQHandler
OTG_HS_EP1_OUT_IRQHandler
OTG_HS_EP1_IN_IRQHandler
OTG_HS_WKUP_IRQHandler
OTG_HS_IRQHandler
DCMI_IRQHandler
CRYP_IRQHandler
HASH_RNG_IRQHandler
B .
ENDP
ALIGN
;*******************************************************************************
; User Stack and Heap initialization
;*******************************************************************************
IF :DEF:__MICROLIB;IF…ELSE…ENDIF結構,判斷是否使用DEF:__MICROLIB(此處為不使用)
EXPORT __initial_sp;若使用DEF:__MICROLIB,則將__initial_sp,__heap_base,__heap_limit亦即棧頂地址,堆始末地址賦予全域性屬性,使外部程式可以使用
EXPORT __heap_base
EXPORT __heap_limit
ELSE
IMPORT __use_two_region_memory ;定義全域性標號__use_two_region_memory
EXPORT __user_initial_stackheap ;宣告全域性標號__user_initial_stackheap,這樣外程式也可呼叫此標號
__user_initial_stackheap;標號__user_initial_stackheap,表示使用者堆疊初始化程式入口
LDR R0, = Heap_Mem;分別儲存棧頂指標和棧大小,堆始地址和堆大小至R0,R1,R2,R3暫存器
LDR R1, =(Stack_Mem + Stack_Size)
LDR R2, = (Heap_Mem + Heap_Size)
LDR R3, = Stack_Mem
BX LR
ALIGN
ENDIF
END;程式完畢
;******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE*****
以上便是STM32的啟動程式碼的完整解析,接下來對幾個小地方做解釋:
1、 AREA指令:偽指令,用於定義程式碼段或資料段,後跟屬性標號。其中比較重要的一個標號為“READONLY”或者“READWRITE”,其中 “READONLY”表示該段為只讀屬性,
聯絡到STM32的內部儲存介質,可知具有隻讀屬性的段保存於FLASH區,即0x8000000地址後。而 “READONLY”表示該段為“可讀寫”屬性,可知“可讀寫”段保存於SRAM
區,即0x2000000地址後。由此可以從第43、54行程式碼知道,堆疊段位於SRAM空間。從第64行可知,中斷向量表放置與FLASH區,而這也是整片啟動程式碼中最先被放進
FLASH區的資料。因此可以得到一條重要的資訊:0x8000000地址存放的是棧頂地址__initial_sp,0x8000004地址存放的是復位中斷向量 Reset_Handler(STM32使
用32位匯流排,因此儲存空間為4位元組對齊)。
2、 DCD指令:作用是開闢一段空間,其意義等價於C語言中的地址符“&”。因此從第69行開始建立的中斷向量表則類似於使用C語言定義了一個指標陣列,其每一個成員
都是一個函式指標,分別指向各個中斷服務函式。
3、 標號:前文多處使用了“標號”一詞。標號主要用於表示一片記憶體空間的某個位置,等價於C語言中的“地址”概念。地址僅僅表示儲存空間的一個位置,從C語言的角
度來看,變數的地址,陣列的地址或是函式的入口地址在本質上並無區別。
4、 第178行中的__main標號並不表示C程式中的main函式入口地址,因此第181行也並不是跳轉至main函式開始執行C程式。__main標號表示C/C++標準實時庫函式裡的
一個初始化子程式__main的入口地址。該程式的一個主要作用是初始化堆疊(對於程式清單一來說則是跳轉 __user_initial_stackheap標號進行初始化堆疊的),
並初始化映像檔案,最後跳轉C程式中的main函式。這就解釋了為何所有的C 程式必須有一個main函式作為程式的起點——因為這是由C/C++標準實時庫所規定的——並
且不能更改,因為C/C++標準實時庫並不對外界開放原始碼。因此,實際上在使用者可見的前提下,程式在第182行後就跳轉至.c檔案中的main函式,開始執行C程式了。
至此可以總結一下STM32的啟動檔案和啟動過程。首先對棧和堆的大小進行定義,並在程式碼區的起始處建立中斷向量表,其第一個表項是棧頂地址,第二個表項是復位
中斷服務入口地址。然後在復位中斷服務程式中跳轉到C/C++標準實時庫的__main函式,完成使用者堆疊等的初始化後,跳轉.c檔案中的 main函式開始執行C程式。假設
STM32被設定為從內部FLASH啟動(這也是最常見的一種情況),中斷向量表起始地位為0x8000000,則棧頂地址存放於0x8000000處,而復位中斷服務入口地址存放於
0x8000004處。當STM32遇到復位訊號後,則從0x80000004處取出復位中斷服務入口地址,繼而執行復位中斷服務程式,然後跳轉__main函式,最後進入mian函式,來
到C的世界。
注:
1.資料定義( Data Definition )偽指令
資料定義偽指令一般用於為特定的資料分配儲存單元,同時可完成已分配儲存單元的初始化。DCD ( DCDU ) 用於分配一片連續的字儲存單元並用指定的資料初始化。
語法格式:
標號 DCD (或 DCDU ) 表示式
DCD (或 DCDU )偽指令用於分配一片連續的字儲存單元並用偽指令中指定的表示式初始化。其中,表示式可以為程式標號或數字表達式。 DCD 也可用 “ & ” 代替。
啟動方式有了比較大的變化。ARM7/ARM9核心的控制器在復位後,CPU會從儲存空間的絕對地址0x000000取出第一條指令執行復位中斷服務程式的方式啟動,
即固定了復位後的起始地址為0x000000(PC = 0x000000)同時中斷向量表的位置並不是固定的。而Cortex-M3核心則正好相反,有3種情況:
1、 通過boot引腳設定可以將中斷向量表定位於SRAM區,即起始地址為0x2000000,同時復位後PC指標位於0x2000000處;
2、 通過boot引腳設定可以將中斷向量表定位於FLASH區,即起始地址為0x8000000,同時復位後PC指標位於0x8000000處;
3、 通過boot引腳設定可以將中斷向量表定位於內建Bootloader區,本文不對這種情況做論述;
Cortex-M3核心規定,起始地址必須存放堆頂指標,而第二個地址則必須存放復位中斷入口向量地址,這樣在Cortex-M3核心復位後,會自動從起始地址的
下一個32位空間取出復位中斷入口向量,跳轉執行復位中斷服務程式。對比ARM7/ARM9核心,Cortex-M3核心則是固定了中斷向量表的位置而起始地址是可變
化的。
有了上述準備只是後,下面以STM32的f2xx韌體庫提供的啟動檔案“startup_stm32f2xx.s”為模板,對STM32的啟動過程做一個簡要而全面的解析。
;******************** (C) COPYRIGHT 2011 STMicroelectronics ********************
;* File Name : startup_stm32f2xx.s
;* Author : MCD Application Team
;* Version : V1.0.0
;* Date : 18-April-2011
;* Description : STM32F2xx devices vector table 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
;* - Branches to __main in the C library (which eventually
;* calls main()).
;* After Reset the CortexM3 processor is in Thread mode,
;* priority is Privileged, and the Stack is set to Main.
;* <<< Use Configuration Wizard in Context Menu >>>
;*******************************************************************************
; THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
; WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME.
; AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
; INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
; CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
; INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
;*******************************************************************************
; 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;定義棧空間大小為0x00000400,此語句等價於C:#define Stack_Size 0x00000400
AREA STACK, NOINIT, READWRITE, ALIGN=3;定義棧,,可讀寫,8位元組對齊
Stack_Mem SPACE Stack_Size;開闢一段大小為Stack_Size的記憶體空間作為棧
__initial_sp;標號__initial_sp,表示棧空間頂地址
; <h> Heap Configuration
; <o> Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>
Heap_Size EQU 0x00000200;定義堆空間大小為0x00000200個位元組
AREA HEAP, NOINIT, READWRITE, ALIGN=3;定義堆,,可讀寫,8位元組對齊
__heap_base ;標號__heap_base,表示堆空間起始地址
Heap_Mem SPACE Heap_Size;開闢一段大小為Heap_Size的記憶體空間作為堆。
__heap_limit ;標號__heap_limit,表示堆空間結束地址
PRESERVE8;告訴編譯器以8位元組對齊
THUMB;告訴編譯器使用THUMB指令集
; Vector Table Mapped to Address 0 at Reset
AREA RESET, DATA, READONLY;定義只讀資料段,實際上是在CODE區(假設STM32從FLASH啟動,則此中斷向量表起始地址即為0x8000000)
EXPORT __Vectors;將標號__Vectors宣告為全域性標號,這樣外部檔案就可以使用這個標號
EXPORT __Vectors_End;
EXPORT __Vectors_Size;
;建立中斷向量表
__Vectors DCD __initial_sp ; Top of Stack,存放於FLASH中的0x8000000地址處
DCD Reset_Handler ; Reset Handler,存放於FLASH中的0x8000004地址處
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 detection
DCD TAMP_STAMP_IRQHandler ; Tamper and TimeStamps through the EXTI line
DCD RTC_WKUP_IRQHandler ; RTC Wakeup through the EXTI line
DCD FLASH_IRQHandler ; FLASH
DCD RCC_IRQHandler ; RCC
DCD EXTI0_IRQHandler ; EXTI Line0
DCD EXTI1_IRQHandler ; EXTI Line1
DCD EXTI2_IRQHandler ; EXTI Line2
DCD EXTI3_IRQHandler ; EXTI Line3
DCD EXTI4_IRQHandler ; EXTI Line4
DCD DMA1_Stream0_IRQHandler ; DMA1 Stream 0
DCD DMA1_Stream1_IRQHandler ; DMA1 Stream 1
DCD DMA1_Stream2_IRQHandler ; DMA1 Stream 2
DCD DMA1_Stream3_IRQHandler ; DMA1 Stream 3
DCD DMA1_Stream4_IRQHandler ; DMA1 Stream 4
DCD DMA1_Stream5_IRQHandler ; DMA1 Stream 5
DCD DMA1_Stream6_IRQHandler ; DMA1 Stream 6
DCD ADC_IRQHandler ; ADC1, ADC2 and ADC3s
DCD CAN1_TX_IRQHandler ; CAN1 TX
DCD CAN1_RX0_IRQHandler ; CAN1 RX0
DCD CAN1_RX1_IRQHandler ; CAN1 RX1
DCD CAN1_SCE_IRQHandler ; CAN1 SCE
DCD EXTI9_5_IRQHandler ; External Line[9:5]s
DCD TIM1_BRK_TIM9_IRQHandler ; TIM1 Break and TIM9
DCD TIM1_UP_TIM10_IRQHandler ; TIM1 Update and TIM10
DCD TIM1_TRG_COM_TIM11_IRQHandler ; TIM1 Trigger and Commutation and TIM11
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 ; External Line[15:10]s
DCD RTC_Alarm_IRQHandler ; RTC Alarm (A and B) through EXTI Line
DCD OTG_FS_WKUP_IRQHandler ; USB OTG FS Wakeup through EXTI line
DCD TIM8_BRK_TIM12_IRQHandler ; TIM8 Break and TIM12
DCD TIM8_UP_TIM13_IRQHandler ; TIM8 Update and TIM13
DCD TIM8_TRG_COM_TIM14_IRQHandler ; TIM8 Trigger and Commutation and TIM14
DCD TIM8_CC_IRQHandler ; TIM8 Capture Compare
DCD DMA1_Stream7_IRQHandler ; DMA1 Stream7
DCD FSMC_IRQHandler ; FSMC
DCD SDIO_IRQHandler ; SDIO
DCD TIM5_IRQHandler ; TIM5
DCD SPI3_IRQHandler ; SPI3
DCD UART4_IRQHandler ; UART4
DCD UART5_IRQHandler ; UART5
DCD TIM6_DAC_IRQHandler ; TIM6 and DAC1&2 underrun errors
DCD TIM7_IRQHandler ; TIM7
DCD DMA2_Stream0_IRQHandler ; DMA2 Stream 0
DCD DMA2_Stream1_IRQHandler ; DMA2 Stream 1
DCD DMA2_Stream2_IRQHandler ; DMA2 Stream 2
DCD DMA2_Stream3_IRQHandler ; DMA2 Stream 3
DCD DMA2_Stream4_IRQHandler ; DMA2 Stream 4
DCD ETH_IRQHandler ; Ethernet
DCD ETH_WKUP_IRQHandler ; Ethernet Wakeup through EXTI line
DCD CAN2_TX_IRQHandler ; CAN2 TX
DCD CAN2_RX0_IRQHandler ; CAN2 RX0
DCD CAN2_RX1_IRQHandler ; CAN2 RX1
DCD CAN2_SCE_IRQHandler ; CAN2 SCE
DCD OTG_FS_IRQHandler ; USB OTG FS
DCD DMA2_Stream5_IRQHandler ; DMA2 Stream 5
DCD DMA2_Stream6_IRQHandler ; DMA2 Stream 6
DCD DMA2_Stream7_IRQHandler ; DMA2 Stream 7
DCD USART6_IRQHandler ; USART6
DCD I2C3_EV_IRQHandler ; I2C3 event
DCD I2C3_ER_IRQHandler ; I2C3 error
DCD OTG_HS_EP1_OUT_IRQHandler ; USB OTG HS End Point 1 Out
DCD OTG_HS_EP1_IN_IRQHandler ; USB OTG HS End Point 1 In
DCD OTG_HS_WKUP_IRQHandler ; USB OTG HS Wakeup through EXTI
DCD OTG_HS_IRQHandler ; USB OTG HS
DCD DCMI_IRQHandler ; DCMI
DCD CRYP_IRQHandler ; CRYP crypto
DCD HASH_RNG_IRQHandler ; Hash and Rng
__Vectors_End
__Vectors_Size EQU __Vectors_End - __Vectors
AREA |.text|, CODE, READONLY ;只讀程式碼段
; Reset handler
Reset_Handler PROC;復位中斷服務程式,PROC…ENDP結構表示程式的開始和結束
EXPORT Reset_Handler [WEAK] ;聲明覆位中斷向量Reset_Handler為全域性屬性,這樣外部檔案就可以呼叫此復位中斷服務
IMPORT SystemInit;宣告SystemInit標號
IMPORT __main;宣告__main標號
LDR R0, =SystemInit;跳轉到SystemInit地址執行
BLX R0;
LDR R0, =__main;跳轉__main地址執行
BX R0
ENDP
; 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 TAMP_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_Stream0_IRQHandler [WEAK]
EXPORT DMA1_Stream1_IRQHandler [WEAK]
EXPORT DMA1_Stream2_IRQHandler [WEAK]
EXPORT DMA1_Stream3_IRQHandler [WEAK]
EXPORT DMA1_Stream4_IRQHandler [WEAK]
EXPORT DMA1_Stream5_IRQHandler [WEAK]
EXPORT DMA1_Stream6_IRQHandler [WEAK]
EXPORT ADC_IRQHandler [WEAK]
EXPORT CAN1_TX_IRQHandler [WEAK]
EXPORT CAN1_RX0_IRQHandler [WEAK]
EXPORT CAN1_RX1_IRQHandler [WEAK]
EXPORT CAN1_SCE_IRQHandler [WEAK]
EXPORT EXTI9_5_IRQHandler [WEAK]
EXPORT TIM1_BRK_TIM9_IRQHandler [WEAK]
EXPORT TIM1_UP_TIM10_IRQHandler [WEAK]
EXPORT TIM1_TRG_COM_TIM11_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 OTG_FS_WKUP_IRQHandler [WEAK]
EXPORT TIM8_BRK_TIM12_IRQHandler [WEAK]
EXPORT TIM8_UP_TIM13_IRQHandler [WEAK]
EXPORT TIM8_TRG_COM_TIM14_IRQHandler [WEAK]
EXPORT TIM8_CC_IRQHandler [WEAK]
EXPORT DMA1_Stream7_IRQHandler [WEAK]
EXPORT FSMC_IRQHandler [WEAK]
EXPORT SDIO_IRQHandler [WEAK]
EXPORT TIM5_IRQHandler [WEAK]
EXPORT SPI3_IRQHandler [WEAK]
EXPORT UART4_IRQHandler [WEAK]
EXPORT UART5_IRQHandler [WEAK]
EXPORT TIM6_DAC_IRQHandler [WEAK]
EXPORT TIM7_IRQHandler [WEAK]
EXPORT DMA2_Stream0_IRQHandler [WEAK]
EXPORT DMA2_Stream1_IRQHandler [WEAK]
EXPORT DMA2_Stream2_IRQHandler [WEAK]
EXPORT DMA2_Stream3_IRQHandler [WEAK]
EXPORT DMA2_Stream4_IRQHandler [WEAK]
EXPORT ETH_IRQHandler [WEAK]
EXPORT ETH_WKUP_IRQHandler [WEAK]
EXPORT CAN2_TX_IRQHandler [WEAK]
EXPORT CAN2_RX0_IRQHandler [WEAK]
EXPORT CAN2_RX1_IRQHandler [WEAK]
EXPORT CAN2_SCE_IRQHandler [WEAK]
EXPORT OTG_FS_IRQHandler [WEAK]
EXPORT DMA2_Stream5_IRQHandler [WEAK]
EXPORT DMA2_Stream6_IRQHandler [WEAK]
EXPORT DMA2_Stream7_IRQHandler [WEAK]
EXPORT USART6_IRQHandler [WEAK]
EXPORT I2C3_EV_IRQHandler [WEAK]
EXPORT I2C3_ER_IRQHandler [WEAK]
EXPORT OTG_HS_EP1_OUT_IRQHandler [WEAK]
EXPORT OTG_HS_EP1_IN_IRQHandler [WEAK]
EXPORT OTG_HS_WKUP_IRQHandler [WEAK]
EXPORT OTG_HS_IRQHandler [WEAK]
EXPORT DCMI_IRQHandler [WEAK]
EXPORT CRYP_IRQHandler [WEAK]
EXPORT HASH_RNG_IRQHandler [WEAK]
WWDG_IRQHandler
PVD_IRQHandler
TAMP_STAMP_IRQHandler
RTC_WKUP_IRQHandler
FLASH_IRQHandler
RCC_IRQHandler
EXTI0_IRQHandler
EXTI1_IRQHandler
EXTI2_IRQHandler
EXTI3_IRQHandler
EXTI4_IRQHandler
DMA1_Stream0_IRQHandler
DMA1_Stream1_IRQHandler
DMA1_Stream2_IRQHandler
DMA1_Stream3_IRQHandler
DMA1_Stream4_IRQHandler
DMA1_Stream5_IRQHandler
DMA1_Stream6_IRQHandler
ADC_IRQHandler
CAN1_TX_IRQHandler
CAN1_RX0_IRQHandler
CAN1_RX1_IRQHandler
CAN1_SCE_IRQHandler
EXTI9_5_IRQHandler
TIM1_BRK_TIM9_IRQHandler
TIM1_UP_TIM10_IRQHandler
TIM1_TRG_COM_TIM11_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
OTG_FS_WKUP_IRQHandler
TIM8_BRK_TIM12_IRQHandler
TIM8_UP_TIM13_IRQHandler
TIM8_TRG_COM_TIM14_IRQHandler
TIM8_CC_IRQHandler
DMA1_Stream7_IRQHandler
FSMC_IRQHandler
SDIO_IRQHandler
TIM5_IRQHandler
SPI3_IRQHandler
UART4_IRQHandler
UART5_IRQHandler
TIM6_DAC_IRQHandler
TIM7_IRQHandler
DMA2_Stream0_IRQHandler
DMA2_Stream1_IRQHandler
DMA2_Stream2_IRQHandler
DMA2_Stream3_IRQHandler
DMA2_Stream4_IRQHandler
ETH_IRQHandler
ETH_WKUP_IRQHandler
CAN2_TX_IRQHandler
CAN2_RX0_IRQHandler
CAN2_RX1_IRQHandler
CAN2_SCE_IRQHandler
OTG_FS_IRQHandler
DMA2_Stream5_IRQHandler
DMA2_Stream6_IRQHandler
DMA2_Stream7_IRQHandler
USART6_IRQHandler
I2C3_EV_IRQHandler
I2C3_ER_IRQHandler
OTG_HS_EP1_OUT_IRQHandler
OTG_HS_EP1_IN_IRQHandler
OTG_HS_WKUP_IRQHandler
OTG_HS_IRQHandler
DCMI_IRQHandler
CRYP_IRQHandler
HASH_RNG_IRQHandler
B .
ENDP
ALIGN
;*******************************************************************************
; User Stack and Heap initialization
;*******************************************************************************
IF :DEF:__MICROLIB;IF…ELSE…ENDIF結構,判斷是否使用DEF:__MICROLIB(此處為不使用)
EXPORT __initial_sp;若使用DEF:__MICROLIB,則將__initial_sp,__heap_base,__heap_limit亦即棧頂地址,堆始末地址賦予全域性屬性,使外部程式可以使用
EXPORT __heap_base
EXPORT __heap_limit
ELSE
IMPORT __use_two_region_memory ;定義全域性標號__use_two_region_memory
EXPORT __user_initial_stackheap ;宣告全域性標號__user_initial_stackheap,這樣外程式也可呼叫此標號
__user_initial_stackheap;標號__user_initial_stackheap,表示使用者堆疊初始化程式入口
LDR R0, = Heap_Mem;分別儲存棧頂指標和棧大小,堆始地址和堆大小至R0,R1,R2,R3暫存器
LDR R1, =(Stack_Mem + Stack_Size)
LDR R2, = (Heap_Mem + Heap_Size)
LDR R3, = Stack_Mem
BX LR
ALIGN
ENDIF
END;程式完畢
;******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE*****
以上便是STM32的啟動程式碼的完整解析,接下來對幾個小地方做解釋:
1、 AREA指令:偽指令,用於定義程式碼段或資料段,後跟屬性標號。其中比較重要的一個標號為“READONLY”或者“READWRITE”,其中 “READONLY”表示該段為只讀屬性,
聯絡到STM32的內部儲存介質,可知具有隻讀屬性的段保存於FLASH區,即0x8000000地址後。而 “READONLY”表示該段為“可讀寫”屬性,可知“可讀寫”段保存於SRAM
區,即0x2000000地址後。由此可以從第43、54行程式碼知道,堆疊段位於SRAM空間。從第64行可知,中斷向量表放置與FLASH區,而這也是整片啟動程式碼中最先被放進
FLASH區的資料。因此可以得到一條重要的資訊:0x8000000地址存放的是棧頂地址__initial_sp,0x8000004地址存放的是復位中斷向量 Reset_Handler(STM32使
用32位匯流排,因此儲存空間為4位元組對齊)。
2、 DCD指令:作用是開闢一段空間,其意義等價於C語言中的地址符“&”。因此從第69行開始建立的中斷向量表則類似於使用C語言定義了一個指標陣列,其每一個成員
都是一個函式指標,分別指向各個中斷服務函式。
3、 標號:前文多處使用了“標號”一詞。標號主要用於表示一片記憶體空間的某個位置,等價於C語言中的“地址”概念。地址僅僅表示儲存空間的一個位置,從C語言的角
度來看,變數的地址,陣列的地址或是函式的入口地址在本質上並無區別。
4、 第178行中的__main標號並不表示C程式中的main函式入口地址,因此第181行也並不是跳轉至main函式開始執行C程式。__main標號表示C/C++標準實時庫函式裡的
一個初始化子程式__main的入口地址。該程式的一個主要作用是初始化堆疊(對於程式清單一來說則是跳轉 __user_initial_stackheap標號進行初始化堆疊的),
並初始化映像檔案,最後跳轉C程式中的main函式。這就解釋了為何所有的C 程式必須有一個main函式作為程式的起點——因為這是由C/C++標準實時庫所規定的——並
且不能更改,因為C/C++標準實時庫並不對外界開放原始碼。因此,實際上在使用者可見的前提下,程式在第182行後就跳轉至.c檔案中的main函式,開始執行C程式了。
至此可以總結一下STM32的啟動檔案和啟動過程。首先對棧和堆的大小進行定義,並在程式碼區的起始處建立中斷向量表,其第一個表項是棧頂地址,第二個表項是復位
中斷服務入口地址。然後在復位中斷服務程式中跳轉到C/C++標準實時庫的__main函式,完成使用者堆疊等的初始化後,跳轉.c檔案中的 main函式開始執行C程式。假設
STM32被設定為從內部FLASH啟動(這也是最常見的一種情況),中斷向量表起始地位為0x8000000,則棧頂地址存放於0x8000000處,而復位中斷服務入口地址存放於
0x8000004處。當STM32遇到復位訊號後,則從0x80000004處取出復位中斷服務入口地址,繼而執行復位中斷服務程式,然後跳轉__main函式,最後進入mian函式,來
到C的世界。
注:
1.資料定義( Data Definition )偽指令
資料定義偽指令一般用於為特定的資料分配儲存單元,同時可完成已分配儲存單元的初始化。DCD ( DCDU ) 用於分配一片連續的字儲存單元並用指定的資料初始化。
語法格式:
標號 DCD (或 DCDU ) 表示式
DCD (或 DCDU )偽指令用於分配一片連續的字儲存單元並用偽指令中指定的表示式初始化。其中,表示式可以為程式標號或數字表達式。 DCD 也可用 “ & ” 代替。
用 DCD 分配的字儲存單元是字對齊的,而用 DCDU 分配的字儲存單元並不嚴格字對齊。
以上內容源於網路資料以及個人理解的整理。