1、.s啟動文件解析
STM32的啟動文件(一般是.s匯編文件,如startup_stm32f407xx.s
)是STM32上電后執行的第一段代碼,承擔著“系統初始化化引導員”的角色。
它的主要作用是設置初始化棧指針(SP
)、程序計數器(PC
)、定義向量表、跳轉到C庫中__main
函數,最終調用用戶main
函數。
1.1、棧和堆的初始化配置
定義棧和堆的大小,并指定分配內存空間。
Stack_Size EQU 0x400AREA STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem SPACE Stack_Size
__initial_spHeap_Size EQU 0x200AREA HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem SPACE Heap_Size
__heap_limit
1.2、向量表
定義儲存中斷服務程序地址的數組,即中斷向量表。
__Vectors DCD __initial_sp ; Top of StackDCD Reset_Handler ; Reset HandlerDCD NMI_Handler ; NMI Handler...
1.3、復位處理程序
Reset_Handler
是復位處理程序,當MCU復位時,程序會跳轉到這里執行。其中主要包括SystemInit
函數和__main
函數。
Reset_Handler PROCEXPORT Reset_Handler [WEAK]IMPORT SystemInitIMPORT __mainLDR R0, =SystemInitBLX R0LDR R0, =__mainBX R0ENDP
1.4、其它中斷處理程序
這里都是默認的異常處理程序,如非屏蔽中斷(NMI)、硬故障(HardFault)等。可以在用戶程序中重新定義這些中斷處理程序,例如,在main.c中定義void SysTick_Handler(void)
會覆蓋啟動文件中的弱定義。
1.5、用戶棧和堆初始化
如果使用 MicroLIB,則導出棧頂指針、堆基地址和堆限制地址。否則,導入 __use_two_region_memory
符號,并定義__user_initial_stackheap
函數,用于初始化用戶棧和堆。
這里是用于初始化棧和堆的內存布局,并根據不同的工具鏈和庫配置提供相應的接口。
IF :DEF:__MICROLIBEXPORT __initial_spEXPORT __heap_baseEXPORT __heap_limitELSEIMPORT __use_two_region_memoryEXPORT __user_initial_stackheap__user_initial_stackheapLDR R0, = Heap_MemLDR R1, =(Stack_Mem + Stack_Size)LDR R2, = (Heap_Mem + Heap_Size)LDR R3, = Stack_MemBX LRALIGNENDIF
- 1、MicroLIB分支
- 適用于Flash/RAM較小的場景(如F1系列)。
- 減小代碼體積。
- 直接通過全局變量管理堆和棧,無需函數調用開銷。
- 2、標準庫
- 適用于需要完整的C庫功能的場景(如
malloc()
,printf()
)。 - 通過
__user_initial_stackheap
函數動態配置堆和棧,支持更靈活的內存管理。 - 雙區域模型避免棧和堆的沖突(如棧溢出導致覆蓋堆數據)
- 適用于需要完整的C庫功能的場景(如
2、STM32啟動流程
- 1、復位:當 STM32 微控制器復位時,處理器從地址 0 處讀取棧頂指針(SP)的值,并將其加載到 SP 寄存器中。
- 2、跳轉到復位處理程序:接著從地址 4 處讀取復位處理程序的地址,并將其加載到程序計數器(PC)中,程序跳轉到
Reset_Handler
執行。 - 3、系統初始化:在
Reset_Handler
中,首先調用SystemInit
函數進行系統時鐘等硬件配置的初始化。 - 4、進入 C 庫啟動函數:然后調用
__main
函數,__main
函數會完成一些初始化工作,如全局變量的初始化等,最終調用用戶的main
函數。 - 5、用戶程序執行:程序進入用戶的
main
函數,開始執行用戶編寫的代碼。 - 6、異常處理:當發生異常或中斷時,處理器會根據向量表中的地址跳轉到相應的異常處理程序執行。
3、常見使用技巧
- 1、增大棧內存,解決棧溢出問題
- 2、重映射中斷向量表(IAP升級或雙程序)
- 3、裁剪啟動流程,適配應用場景。