目录
一、前言
下面主要讲解从上电复位到 main 函数的过程。主要有以下步骤:
- 初始化堆栈指针:
SP = __initial_sp
、PC = Reset_Handler
- 初始化中断向量表
- 配置系统时钟
- 调用 C 库函数
_main
初始化用户堆栈,然后进入main
函数
二、STM32 的启动模式
启动模式决定了中断向量表的位置,STM32 有三种启动模式:
- 主闪存存储器启动:从 STM32 内置的 Flash 启动( 0 x 08000000 − 0 x 0807 F F F F 0x0800 0000-0x0807 FFFF 0x08000000−0x0807FFFF),一般我们使用 JTAG 或者 SWD 模式下载程序时,就是下载到这个里面,重启后也直接从这启动程序。以
0x08000000
对应的内存为例,则该块内存既可以通过0x00000000
操作也可以通过0x08000000
操作,且都是操作的同一块内存。 - 系统存储器启动:从系统存储器启动( 0 x 1 F F F F 000 − 0 x 1 F F F F 7 F F 0x1FFFF000-0x1FFF F7FF 0x1FFFF000−0x1FFFF7FF),这种模式启动的程序功能是由厂家设置的。一般来说,我们选用这种启动模式时,是为了从串口下载程序,因为在厂家提供的 ISP 程序中,提供了串口下载程序的固件,可以通过这个 ISP 程序将用户程序下载到系统的 Flash 中。以
0x1FFFFFF0
对应的内存为例,则该块内存既可以通过0x00000000
操作也可以通过0x1FFFFFF0
操作,且都是操作的同一块内存。 - 片上 SRAM 启动:从内置 SRAM 启动( 0 x 20000000 − 0 x 3 F F F F F F F 0x2000 0000-0x3FFFFFFF 0x20000000−0x3FFFFFFF),既然是 SRAM,自然也就没有程序存储的能力了,这个模式一般用于程序调试。SRAM 只能通过
0x20000000
进行操作,与上述两者不同。从 SRAM 启动时,需要在应用程序初始化代码中重新设置向量表的位置。
我们可以选择设置 BOOT0 和 BOOT1 的引脚电平状态,来选择复位后的启动模式,如下表:
BOOT1 | BOOT0 | 自举模式 | 自举空间 |
---|---|---|---|
x | 0 | 主 Flash | 选择主 Flash 作为自举空间 |
0 | 1 | 系统存储器 | 选择系统存储器作为自举空间 |
1 | 1 | 嵌入式 SRAM | 选择嵌入式 SRAM 作为自举空间 |
启动模式只决定程序烧录的位置,加载完程序之后会有一个重映射(映射到 0x00000000
地址位置);真正产生复位信号的时候,CPU 还是从开始位置执行
值得注意的是 STM32 上电复位以后,代码区都是从 0x00000000
开始的,三种启动模式只是将各自存储空间的地址映射到 0x00000000
中。
三、STM32 启动文件分析
下面针对 startup_stm32f40_41xxx.s
文件进行简单的分析。
1、栈 Stack
Stack_Size EQU 0x00000400
AREA STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem SPACE Stack_Size
__initial_sp
这段代码的含义如下:开辟栈的大小为 0X00000400
(1KB),名字为 STACK, NOINIT
即不初始化,可读可写, ALIGN=3
表示 8(2^3)字节对齐。
栈的作用是用于局部变量,函数调用,函数形参等的开销,栈的大小不能超过内部 SRAM 的大小。如果编写的程序比较大,定义的局部变量很多,那么就需要修改栈的大小。
EQU
:宏定义的伪指令,相当于等于,类似于 C 中的 define。AREA
:告诉汇编器汇编一个新的代码段或者数据段。STACK 表示段名,这个可以任意命名;NOINIT 表示不初始化;READWRITE 表示可读可写,ALIGN=3,表示按照 2 3 2^3 23 对齐,即 8 字节对齐。SPACE
:用于分配一定大小的内存空间,单位为字节。这里指定大小等于 Stack_Size。- 标号
__initial_