1.启动文件startup_stm32f429xx.s
启动文件主要工作:
1、初始化堆栈指针 SP=_initial_sp
2、初始化 PC指针=Reset_Handler
3、初始化中断向量表
4、配置系统时钟
5、调用 C库函数_main 初始化用户堆栈,从而最终调用main 函数去C的世界
1.1.Stack-栈
Stack_Size EQU 0x400;
AREA STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem SPACE Stack_Size
__initial_sp
开辟栈的大小为0X00000400(1KB),名字为STACK,8(2^3)字节对齐。栈的作用是用于局部变量,函数调用,函数形参等的开销。标号__initial_sp紧挨着SPACE语句放置,表示栈的结束地址,即栈顶地址,栈是由高向低生长的。
1.2.Heap-堆
Heap_Size EQU 0x200;
AREA HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem SPACE Heap_Size
__heap_limit
开辟堆的大小为0X00000200(512字节),名字为HEAP,NOINIT,8(2^3)字节对齐。__heap_base表示对的起始地址,__heap_limit表示堆的结束地址。堆是由低向高生长的,跟栈的生长方向相反。堆主要用来动态内存的分配,malloc()函数申请的内存就在堆上面。
1.3.向量表
; Vector Table Mapped to Address 0 at Reset
AREA RESET, DATA, READONLY
EXPORT __Vectors
EXPORT __Vectors_End
EXPORT __Vectors_Size
定义一个数据段,名字为 RESET,可读。并声明 __Vectors、__Vectors_End 和
__Vectors_Size这三个标号具有全局属性,可供外部的文件调用。
__Vectors为向量表起始地址, __Vectors_End 为向量表结束地址,两个相减即可算出向量表大小。向量表从FLASH的0地址开始放置,以4字节为一个单位,地址0存放的是栈顶地址,0X04存放的是复位程序的地址,以此类推。
1.4.复位程序
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT SystemInit
IMPORT __main
LDR R0, =SystemInit
BLX R0
LDR R0, =__main
BX R0
ENDP
复位子程序是系统上电后第一个执行的程序,调用SystemInit 函数初始化系统时钟,然后调用 C库函数_mian。
SystemInit和__main这两个函数均来自外部的文件。SystemInit()在system_STM32F4xx.c库文件定义。主要作用是配置系统时钟,这里调用这个函数之后,F429的系统时钟配被配置为16M(时钟源HSI)。__main 是一个标准的C库函数,主要作用是初始化用户堆栈,最终调用main函数去到C的世界。
1.5.中断服务程序
在启动文件里面已经帮我们写好所有中断的中断服务函数,这些函数都是空的,真正的中断复服务程序需要在外部的C文件里重新实现,这里只是提前占了一个位置而已。
;*******************************************************************************
; 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
判断是否定义了__MICROLIB ,如果定义了则赋予标号__initial_sp(栈顶地址)、__heap_base(堆起始地址)、__heap_limit(堆结束地址)全局属性,可供外部文件调用。如果没有定义(实际的情况就是我们没定义__MICROLIB)则使用默认的C库,然后初始化用户堆栈大小,这部分有C库函数__main 来完成,当初始化完堆栈之后就调用main函数。
2.启动模式设置接口
一般如果想用用串口下载代码,则必须配置BOOT0为 1,BOOT1为0,而如果想让STM32一按复位键就开始跑代码,则需要配置 BOOT0为0,BOOT1随便设置都可以。
3.启动流程
- 上电后执行启动文件startup_stm32f429xx.s,初始化堆栈指针,PC指针,中断向量表,调用 C库函数_main。
- 调用HAL_Init()初始化HAL库,此时默认配置为16M的HIS时钟源;HAL_Init()里设置Systick的中断优先级,初始化Systick(1ms一次中断)。
- 调用自己的时钟初始化函数和延时初始化函数。