这篇文章主要是分析stm32启动文件,启动文件是由汇编编写的,文件名为startup_stm32f40_41xxx.s。
启动文件做的工作:
启动文件最主要的功能就是初始化堆栈指针sp,执行复位程序进入C语言main函数
1.初始化堆栈空间大小,定义栈顶位置、堆起始位置等等
2.定义中断向量表,初始化sp指针
3.Reset_Handler复位函数定义
4.配置系统时钟,进入main函数
具体代码分析
Stack_Size EQU 0x00000400
AREA STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem SPACE Stack_Size
__initial_sp
在MDK帮助文档中可以查到EQU是宏定义的伪指令,它的作用就相当于C语言中的define,首先定义栈大小为1KB(0x00000400)。
栈的作用主要保存函数中的局部变量,函数调用过程中的形参,返回地址,因此在函数中如果有较多的局部变量,大型数组最好不要放在函数中定义,在这种情况下就要考虑栈大小是否充足,如果栈溢出了,那程序会出现跑飞,找不到返回地址。
AREA是告诉编译器汇编一个代码段或者数据段,STACK 表示段名,这个可以任意命名; NOINIT 表示不初始化; READWRITE 表示可读可写, ALIGN=3,表示按照 2^3对齐,即 8 字节对齐。
SPACE是分配一定大小的内存空间,单位为字节。
最后一句_initial_sp是栈顶指针,这里栈的生长方向是从高地址到低地址,所以栈初始地址就是在高地址位置。
Heap_Size EQU 0x00000200
AREA HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem SPACE Heap_Size
__heap_limit
这里是声明堆的大小,方法和栈类似,不同点在于_heap_base堆初始位置在内存分配之前,也就是低地址,_heap_limit是堆结束位置,堆的生长方向是从低地址向高地址。堆主要用于动态内存的分配。
__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
...
这里就是中断向量表的定义,中断向量表是储存在flash的0地址位置。向量表第一个位置保存的是栈顶地址,即 __initial_sp,这个值在stm32开始运行后会赋给栈指针sp。向量表第二个位置保存的是复位中断的地址,其函数名Reset_Handler就是地址,在后面有定义,这个地址值会赋给程序运行地址指针pc,然后就运行复位程序。
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT SystemInit
IMPORT __main
LDR R0, =SystemInit
BLX R0
LDR R0, =__main
BX R0
ENDP
复位程序会导入Systeminit和_main函数的地址,并由下面的汇编代码,运行Systeminit函数,这个函数是对系统时钟进行设置,然后运行_main函数,这个函数是对堆栈进行一些初始化工作,然后跳转到main函数,并且不在返回该位置。
整个过程就是先设置堆和栈的大小,并且设置相应的地址,然后定义中断向量表,最后定义复位函数,跳转到main函数。
来源:CSDN
作者:迷茫的小孩
链接:https://blog.csdn.net/qq_32020019/article/details/103669727