启动模式
我们知道的复位方式有三种:上电复位,硬件复位和软件复位。当产生复位,并且离开复位状态后, CM33 内核做的第一件事就是读取下列两个 32 位整数的值:
(1) 从地址 0x0000 0000 处取出堆栈指针 MSP 的初始值,该值就是栈顶地址。
(2) 从地址 0x0000 0004 处取出程序计数器指针 PC 的初始值, 该值指向复位后执行的第一条指令。下面用示意图表示,如图所示。
上述过程中,内核是从 0x0000 0000 和 0x0000 0004 两个的地址获取堆栈指针 SP 和程序计数器指针 PC。 事实上, 0x0000 0000 和 0x0000 0004 两个的地址可以被重映射到其他的地址空间。 例如: 我们将 0x0800 0000 映射到 0x0000 0000,即从内部 FLASH 启动, 那么内核会从地址 0x0800 0000 处取出堆栈指针 MSP 的初始值,从地址 0x0800 0004 处取出程序计数器指针PC 的初始值。 CPU 会从 PC 寄存器指向的地址空间取出的第 1 条指令开始执行程序,就是开始执行复位中断服务程序 Reset_Handler。
将 0x0000 0000 和 0x0000 0004 两个的地址重映射到其它地址空间,就是启动模式选择。对于 STM32H5 的启动模式(也称自举模式),我们看表 进行分析。
2, 启动引脚(BOOT0) 的电平: 0:低电平; 1:高电平。
由表可以看到, STM32H5的启动地址是由BOOT0引脚电平状态和NSBOOTADD[31:8]或 SECBOOTADD[31:8]选项字节共同决定的。 它们总共可以分为 4 个组合,下面分别来介绍一下:
1,产品状态在 Open 的情况下, BOOT0 引脚电平为低时,启动地址由用户选项字节NSBOOTADD[31:8]来决定。 ST 出厂默认的启动地址为 0x0800 0000, 这个情况就是我们最常用的了。
2,产品状态在任意模式下, BOOT0 引脚电平为高时,用户选项字节 NSBOOTADD[31:8]此时不起作用,启动地址在 ST 官方的 Bootloader 程序开始启动。此时可以用 ST 官方默认的接口,如: USART、 I2C、 I3C、 SPI、 FDCAN、 USB_FS 等下载程序。
3,产品状态在 Provisioning 的情况下, 此时 BOOT0 引脚和用户选项字节 NSBOOTADD[31:8]不起作用, 程序从 RSS(根安全服务) 启动。
4,产品状态在 Provisioned、 Closed、 Locked 的情况下, BOOT0 引脚电平为低时,启动地址由用户选项字节 NSBOOTADD[31:8]来决定, ST 出厂默认的启动地址是 0x0800 0000。
启动文件分析
STM32 启动文件由 ST 官方提供,在官方的 STM32Cube 固件包里,对于 STM32H562 系列芯片的启动文件,我们选用的是 startup_stm32h562xx.s 这个文件。 启动文件用汇编编写,是系统上电复位后第一个执行的程序。启动文件主要做了以下工作:
1、初始化堆栈指针 SP = _initial_sp
2、初始化程序计数器指针 PC = Reset_Handler
3、设置堆和栈的大小
4、初始化中断向量表
5、配置外部 SRAM 作为数据存储器(可选)
6、配置系统时钟,通过调用 SysteMinit 函数(可选)
7、调用 C 库中的 _main 函数初始化用户堆栈,最终调用 main 函数
启动文件中的一些指令
上表,列举了 STM32 启动文件的一些汇编和编译器指令
启动文件代码讲解
(1)栈空间的开辟栈空间的开辟
源码含义:开辟一段大小为 0x0000 0800(2KB)的栈空间, 段名为 STACK,
NOINIT 表示不初始化;
READWRITE 表示可读可写; ALIGN=3,表示按照 2^3 对齐,即 8 字节对齐。
AREA 汇编一个新的代码段或者数据段。SPACE 分配内存指令,分配大小为 Stack_Size 字节连续的存储单元给栈空间。__initial_sp 紧挨着 SPACE 放置,表示栈的结束地址,栈是从高往低生长,所以结束地址就是栈顶地址。
栈主要用于存放局部变量,函数形参等,属于编译器自动分配和释放的内存,栈的大小不能超过内部 SRAM 的大小