Windows XP Windows 7 Windows 2003 Windows Vista Windows 綜合教學 Linux 系統教學
Windows 10 Windows 8 Windows 2008 Windows NT Windows Server 電腦軟體教學
您现在的位置: Windows教程網 >> Windows教程 >  >> Linux 系統教學 >> Linux 教學

STM32 啟動文件深度解析:從復位到 main() 的完整流程

編輯:Linux 教學

為什麼需要啟動文件?

許多嵌入式開發者習慣直接在 main() 開始編寫代碼,卻忽略了 MCU 上電後如何找到並執行 main()。事實上,編譯器分配的 main 入口地址並非固定絕對地址,微控制器無法直接從硬體定位。啟動文件(Startup Code)正是填補這一鴻溝的關鍵:它完成從「復位」到「開始執行 main()」之間的所有必要初始化配置,功能類比 Linux 的 Bootloader。

STM32 啟動文件選擇陷阱

MDK 建立專案時預設提供 STM32F10x.s,但這並非通用於所有 STM32 型號。該文件僅定義了 3 個 UART、4 個 Timer 的中斷向量,若使用 STM32F103ZET6(5 UART、8 Timer)卻沿用此文件,UART4/5 及 Timer5-8 的中斷將找不到入口,導致程序跑飛。正確做法是根據 Flash 容量選擇 ST 官方提供的三款啟動文件:

  • startup_stm32f10x_ld.s — 小容量(Flash ≤ 32KB)
  • startup_stm32f10x_md.s — 中容量(64KB ≤ Flash ≤ 128KB)
  • startup_stm32f10x_hd.s — 大容量(Flash ≥ 256KB)

啟動代碼核心結構剖析(以 stm32f10x_vector.s 為例)

1. 堆疊與堆區定義

Stack_Size   EQU 0x00000400
AREA STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem    SPACE Stack_Size
__initial_sp                  ; 堆疊頂地址標號

Heap_Size    EQU 0x00000400
AREA HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base                   ; 堆起始地址
Heap_Mem     SPACE Heap_Size
__heap_limit                  ; 堆結束地址
  • AREA 偽指令定義段屬性:NOINIT(不初始化,內存歸零)、READWRITE(可讀寫,放入 SRAM)、ALIGN=3(8 字節對齊)。
  • 標號(Label)本質等同 C 語言中的地址概念,標識一段內存空間的位置。

2. 中斷向量表建立

AREA RESET, DATA, READONLY
EXPORT __Vectors
__Vectors
DCD __initial_sp          ; 0x00: 堆疊頂指針
DCD Reset_Handler         ; 0x04: 復位中斷入口
DCD NMIException
DCD HardFaultException
...                       ; 後續各中斷向量
  • Cortex-M3 規定:起始地址存放堆疊頂(MSP),第二個字存放復位向量。若從 Flash(0x08000000)啟動,則 0x08000000 存 __initial_sp,0x08000004 存 Reset_Handler。
  • DCD 分配 32 位字空間,相當於 C 的函數指針數組。

3. 復位處理程序 Reset_Handler

Reset_Handler PROC
EXPORT Reset_Handler
...                       ; 可選:外部 SRAM 初始化(DATA_IN_ExtSRAM=1 時)
IMPORT __main
LDR R0, =__main
BX R0                     ; 跳轉至 C 庫初始化入口
ENDP

關鍵點:__main 並非用戶 main(),而是 C/C++ 標準庫的初始化例程,負責初始化堆疊、靜態數據段、全局構造函數,最後調用用戶 main()。

4. 用戶堆疊/堆初始化(__user_initial_stackheap)

IF :DEF:__MICROLIB
    EXPORT __initial_sp, __heap_base, __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
ENDIF
  • 非 MicroLIB 時,通過 __user_initial_stackheap 將堆疊/堆邊界傳遞給 C 庫(R0-R3 對應 heap_base, stack_top, heap_limit, stack_base)。
  • MicroLIB 則直接導出三個標號供庫函數使用。

Cortex-M3 vs ARM7/9 啟動差異

特性ARM7/9Cortex-M3
復位後 PC固定 0x00000000由 BOOT 引腳決定(0x20000000/0x08000000/內部 Bootloader)
中斷向量表位置可配置(VTOR)固定在啟動地址開頭
首要動作取指 0x00000000 執行復位 ISR自動讀取 [SP] 和 [SP+4] 跳轉復位處理程序

完整啟動流程總結

  1. 定義堆疊/堆大小,並在代碼區起始處建立中斷向量表(第一項堆疊頂,第二項復位入口)。
  2. 復位發生 → 硬件自動從向量表第二項取得 Reset_Handler 地址並跳轉執行。
  3. Reset_Handler 執行必要外設初始化(如外部 SRAM)→ 跳轉 __main。
  4. __main 初始化 C 運行環境(堆疊、.data/.bss 段、全局構造函數)→ 調用用戶 main()。
  5. 進入 C 世界,開始應用層邏輯。

常見問題排查

  • 中斷無法進入:檢查啟動文件中是否導出了對應的中斷向量,且 stm32f10x_it.c 定義的處理函數名稱是否與向量表一致。
  • 堆疊溢出:增大 Stack_Size 或檢查遞歸/大數組局部變量使用情況。
  • 多啟動文件共存:KEIL 通過「Include in Target Build」選項控制編譯哪個 .s 文件,圖標上無紅點者不參與編譯。
Copyright © Windows教程網 All Rights Reserved