深入解析STM32启动文件startup_stm32xx.s的运行原理和汇编细节

使用过STM32的人都将运行程序写在main主函数中,那单片机是如何执行转到main函数中进行任务那,本章节进行对STM32单片机启动文件进行代码讲解,STM32不同版本芯片的启动文件大致都是一样的,F1,F4或者使用HAL库生成的原理都是一样的,本篇文章使用STM32F4,库函数进行启动文件的讲解。

从工程文件中找到startup_stm32xx.s文件,即单片机上电后执行的第一段程序

大致分为几个步骤:

初始化堆栈指针;

初始化PC指针;

初始化中断向量表;

配置系统时钟;

调用库函数_main初始化用户堆栈,从而进入主函数main();

整体的流程就是这样的 文章到这里就结束了,撤退!

撤退

不闹了我怕有人揍我,正文开始了(startup_stm32xx.s汇编运行讲解)

首先对STM32启动模式进行一下介绍

        因为启动模式是决定向量表的位置,STM32有三种启动模式

        1. 主闪存存储器(Main Flash memory)启动

        从STM32内置的Flash启动(0x0800 0000-0x0807 FFFF),一般我们使用J下载器下载程序时,就是下载到这个里面,重启后也直接从这启动程序。该块内存既可以通过0x00000000 操作也可以通过0x08000000 操作的同一块内存。

        2. 系统存储器(System memory)启动

        从系统存储器启动(0x1FFFF000 – 0x1FFF F7FF),这种模式启动的程序功能是由厂家设置的。我们选择系统存储器的时候可以从串口下载程序,在厂家设置芯片是可以支持用户使用用户程序下载到系统的Flash中。以该块内存既可以通过0x00000000 操作也可以通过0x1FFFFFF0操作同一块内存。

        3. 片上SRAM(Embedded SRAM)启动

        从内置SRAM启动(0x2000 0000-0x3FFFFFFF),既然是SRAM,那块区域也就没有存储程序能力,这个模式用于程序调试。SRAM 只能通过0x20000000进行操作,这个需要注意从SRAM 启动时,需要在应用程序初始化代码中重新设置向量表的位置。

    通过上述选择启动模式主要是决定程序烧录的位置,但实际上单片机启动后是从0x00000000开始的。

对启动文件进行分析startup_stm32xx.s

stm32的启动文件内部都为汇编,我会对每一步进行讲解

1.Stack栈

        栈主要是对局部变量,函数形参,函数调用等开销,栈大小设置不可以超过SRAM的大小,当局部变量等较大时,可以对栈的大小进行修改。

        

第41行:EQU是个伪指令 类似于C语言中的define 表示开辟栈的空间为0x00000400

第43行:AREA伪指令表示要定义一个代码段或者数据段 后面的内容指的是 段名为STACK;不进行初始化NOINIT;可读可写READWRITE,按照八字节对齐ALIGN=3

第44行:SPACE分配大小为Stack_Size长度的连续内存空间

第45行:__initial_sp表示栈顶地址

2.Heep堆

        堆主要是负责动态内存的分配,例如使用malloc()动态分配内存

第52行:和上面描述的堆一样 EQU 表示开辟空间为 0x00000200

第55行:AREA伪指令表示要定义一个代码段或者数据段 后面的内容指的是 段名为HEAP;不进行初始化NOINIT;可读可写READWRITE,按照八字节对齐ALIGN=3

第56行:SPACE分配大小为Heap_Size长度的连续内存空间

第57行:__heap_limit表示堆结束地址

PRESERVE8表示堆栈按照八字节对齐 THUMB表示兼容THUMB指令

3.向量表

        向量表是个WODR数组,每个下标都对应一个异常。

这里举例一小部分随着芯片功能硬件功能增多对应的向量表内的内容也会增加,可以对比一下F1和F4的向量表区别,以及不同版本不同引脚的STM32启动文件向量表内的内容

第64行:定义代码段,名字为RESET,READONIY表示只读

第65-67行:EXPORT可以将元素申引用作外部引用 __Vectors、__Vectors_End 和__Vectors_Size 也就拥有了全局属性

第69行:__Vectors 表示向量表起始地址,DCD 表示分配 1 个 4 字节的空间,当异常(也即是中断事件)发生时,CPU 的中断系统会将相应的入口地址赋值给 PC 程序计数器,之后就开始执行中断服务程序。在69行之后,依次定义了中断服务程序的入口地址。

第170行:__Vectors_End 为向量表结束地址。

第172行:__Vectors_Size则是向量表的大小,向量表的大小是通过__Vectors 和__Vectors_End 相减得到的。

4.复位程序

        复位程序是单片机上电后执行的第一个程序

        

第177行:定义了一个服务程序,PROC为程序开始

第178行:使用EXPORT将Reset_Handler申明为可被外部引用,后面WEAK表示弱定义

第179行:IMPORT表示外部引用 SystemInit(),在system_stm32f4xx.c中可以找到

第180行:__main 是一个标准的 C 库函数,主要作用是初始化用户堆栈,该流程就是进入我们自己写的主函数main()中

第182-185行:LDR表示从存储器中加载SystemInit、__main到一个寄存器R0的地址中,BLX跳转到R0寄存器地址,把跳转前的下一条指令保存LR,BX同样表示跳转到R0但是不会进行保存

第186行:ENDP表示程序结束

5.中断服务程序

        这时候就有人会疑惑,为什么还有中断服务程序,中断服务程序不是我们自己在程序中写的么,但这里确实是需要我们去写的中断服务程序,但是不在启动文件里面,只是说在启动文件中预先将中断服务函数保存了下来,里面并没有东西,真正的中断服务还是需要我们在外部进行自己编写的。

        

PROC、EXPORT、ENDP在文章前面都有进行讲解都是一样的,B代表的是跳转,这里跳转后面有个·’.‘代表无限循环

对应的函数在stm32f4xx_it.c中可以看到

6.堆栈初始化

这里主要是设置IROM和IRAM大小的,在启动文件里面根据这里定义计算起始地点和长度

iF为判断 通过MICROLIB的定义与否决定了堆栈的初始化方式。

剩余的汇编语言在上面都有讲解结合来看就可以了

R0,R1,R2,R3部分为计算堆栈区域

ENDIF表示结束判断 END表示程序结束

同时对startup_stm32xx.s文件讲解也END了

参考文章:https://blog.csdn.net/m0_56694518/article/details/135032170

作者:真可可

物联沃分享整理
物联沃-IOTWORD物联网 » 深入解析STM32启动文件startup_stm32xx.s的运行原理和汇编细节

发表评论