STM32 HAL库开发学习3.STM32启动浅析
- 一、STM32启动模式(也称自举模式)
-
- [1. MSP与PC指针赋值](#1. MSP与PC指针赋值)
- [2. F1系列的启动模式:](#2. F1系列的启动模式:)
- [3. F4系列启动模式](#3. F4系列启动模式)
- [4. F7系列启动模式](#4. F7系列启动模式)
- [5. H7系列启动模式](#5. H7系列启动模式)
- 二、STM32启动过程
-
- [1. MSP 栈顶地址](#1. MSP 栈顶地址)
- [2. PC值](#2. PC值)
- [3. Reset_Handler](#3. Reset_Handler)
- [4. 启动文件内容](#4. 启动文件内容)
- [5. 堆栈](#5. 堆栈)
- [6. 中断向量表](#6. 中断向量表)
- 三、STM32启动过程图解
一、STM32启动模式(也称自举模式)
1. MSP与PC指针赋值
STM32 系列微控制器中的 M3、M4、M7 内核在经历复位操作之后,会率先从特定的内存地址 0x0000 0000 处尝试获取堆栈指针 MSP 的初始值。此初始值具有极为关键的意义,它明确界定了栈顶在内存中的具体位置,为后续程序运行时的函数调用、局部变量存储以及中断处理等操作建立起至关重要的栈空间基础架构。
然后,内核从0x0000 0004处取出程序计数器PC的初始值,该初始值指向的是复位向量所对应的复位处理程序的入口地址(名称为Reset_Handler),这一步明确了程序即将开始执行的具体起始点,使得处理器能够准确地跳转到复位处理程序中,进而开启一系列诸如初始化系统时钟、配置外设、设置中断相关参数等系统初始化操作。
2. F1系列的启动模式:
- 系统复位后,SYSCLK的第4个上升沿,BOOT引脚的值锁存;
- 启动模式选择引脚。
BOOT1 | BOOT0 | 启动模式 | 0x00000000映射地址 | 0x00000004映射地址 |
---|---|---|---|---|
x | 0 | 主闪存存储器 | 0x08000000 | 0x08000004 |
0 | 1 | 系统存储器, ST Boot Loader | 0x1FFFF000 | 0x1FFFF004 |
1 | 1 | 内置 SRAM | 0x20000000 | 0x20000000 |
系统存储器启动时,内嵌的自举程序存放在系统存储区,由ST在生产线上写入,用于通过可用的串行接口对闪存储器进行重新编程。
- 对于小容量、中容量和大容量的产品而言,可以通过UART1接口启用自举程序。
- 对于互联型产品而言,可以通过以下某个接口启用自举程序:USART1、USART2(重映像的)、CAN2(重映像的)或USB OTG全速接口的设备模式(通过固件更新DFU协同)。
- USART接口依靠内部8MHz振荡器(HSI)运行。CAN和USB接口只能当外部8MHz、14.7456MHz或25MHz时钟(HSE)时运行。
3. F4系列启动模式
与F1系列基本一致,注意的是:
如果使用内置 SRAM, 可以使用FSMC重映射到外部的SRAM,可以通过SYSCFG_MEMRMP 寄存器配置。
4. F7系列启动模式
BOOT | 启动地址选项字节 | 启动模式 |
---|---|---|
0 | BOOT_ADD0[15:0] | 由用户选项字节 BOOT_ADD0[15:0] 决定启动地址,ST出厂默认的启动地址为:位于0x0200 0000的ITCM上的FLASH |
1 | BOOT_ADD1[15:0] | 由用户选项字节 BOOT_ADD1[15:0] 决定启动地址,ST出厂默认的启动地址为:位于0x0010 0000的系统自举程序 |
Flash选项控制寄存器(FLASH_OPTCR1)----BOOT_ADDx[15:0] 对应地址位 [29:14] |
- BOOT_ADDx = 0x0000: 从 ITCM RAM (0x0000 0000)启动
- BOOT_ADDx = 0x0040: 从系统存储器 (0x0010 0000) 启动
- BOOT_ADDx = 0x0080: 从ITCM 接口上的FLASH(0x0020 0000)启动
- BOOT_ADDx = 0x2000: 从 AXIM 接口上的 FLASH(0x0800 0000)启动
- BOOT_ADDx = 0x8000: 从 DTCM RAM(0x2000 0000)启动
- BOOT_ADDx = 0x8004: 从 SRAM1(0x2001 0000)启动
- BOOT_ADDx = 0x8013: 从 SRAM2(0x2004 C000)启动
x=0/1, 出厂时,BOOT_ADD0=0x0080, BOOT_ADD1 = 0x0040
5. H7系列启动模式
BOOT | 启动地址选项字节 | 启动模式 |
---|---|---|
0 | BOOT_ADD0[15:0] | 由用户选项字节BOOT_ADD0[15:0]决定启动地址,ST出厂默认的启动地址为:0x0800 0000的Flash地址 |
1 | BOOT_ADD1[15:0] | 由用户选项字节 BOOT_ADD1[15:0]决定启动地址,ST出厂默认的启动地址为: 0x1FF0 0000的系统存储器地址 |
二、STM32启动过程
以内部Flash启动为例。
1. MSP 栈顶地址
当芯片配置为从主闪存启动(例如 BOOT0 = 0,BOOT1 = x)时,存储控制器会自动将起始地址 0x00000000 映射到主闪存的起始物理地址(通常是 0x08000000)。这是通过芯片内部的硬连线和一些基本的逻辑电路来实现的,这些电路会根据启动模式引脚(BOOT0 和 BOOT1)的状态来确定初始的地址映射关系。
这是MSP值就是 0x0800 0000。
2. PC值
内核第二步获取PC的初始值。 这个PC的初始值指向的就是 Reset_Handler。
Reset_Handler定义在启动文件: startup_stm32xxx.S 里。
3. Reset_Handler
Reset_Handler执行一些初始化,再去调用 main函数。
asm
Reset_Handler PROC
EXPORT Reset_Handler [WEAK] ; WEAK 意思允许其它地方重新定义
IMPORT __main ; 声明来自外部的函数
IMPORT SystemInit
LDR R0, =SystemInit ; 调用函数 SystemInit
BLX R0
LDR R0, =__main ; 调用 __main
BX R0
ENDP
4. 启动文件内容
- 初始化MSP 指针 从 0x0800 0000 获取
- 初始化PC 从0x0800 0004 获取
- 设置堆栈大小 Heap_Size(堆), Stack_Size(栈)
- 初始化中断向量表 __Vectors 定义
- 调用初始化函数,可选的,如调用 SystemInit 函数
- 调用 __main
- 调用 main
5. 堆栈
- 栈(Stack):由编译器自动分配和释放,存放函数参数、局部变量等
- 堆(Heap):由malloc,calloc,realloc等 程序分配和释放
asm
Stack_Size EQU 0x400
AREA STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem SPACE Stack_Size
__initial_sp
; <h> Heap Configuration
; <o> Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>
Heap_Size EQU 0x200
AREA HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem SPACE Heap_Size
__heap_limit
6. 中断向量表
从__Vectors 里开始。
中断向量表里面的很多个DCD结构。
asm
__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
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD SVC_Handler ; SVCall Handler
DCD DebugMon_Handler ; Debug Monitor Handler
DCD 0 ; Reserved
DCD PendSV_Handler ; PendSV Handler
DCD SysTick_Handler ; SysTick Handler
; External Interrupts
由于 __initial sp是指向 0x0800 0000,后面每一项偏移4个字节。
每一项是一个函数名,(函数名就是函数的地址)。
三、STM32启动过程图解
从图上可以看出,启动时从0x0800 0000获取 MSP地址,就是栈顶地址,即: 0x2000 0788。
然后 0x0800 0004放的是PC指针,程序到 0x0800 01CD执行引导代码,即Reset_Hander函数。
对于这些地址值,在 .map 文件里也可以找到其地址。
本文学习资源来自 正点原子HAL开发 官方教程。