STM32启动文件分析

STM32启动文件分析

  • 前言
  • 启动文件解析
    • 1. 堆和栈的初始化
    • 2. 初始化中断向量表
    • 3. 复位中断函数
    • 4. 其余中断函数
    • 5. 堆和栈的初始化
  • 启动文件用到的ARM指令表

前言

  • STM32的启动文件是用汇编编写的,以.S作为文件后缀。
  • 对于同系列不同型号的SOC进行工程适配时,一般只需要更改SOC型号、SOC宏定义及启动文件即可。

启动文件解析

1. 堆和栈的初始化

STM32启动文件分析_第1张图片

STM32启动文件分析_第2张图片

  伪指令 EQU 作用是将一个确定的数值赋给一个变量名。
  伪指令 AREA 用于定义数据和代码段。
  伪指令 SPACE 用于分配一段连续的内存空间。

所以这一部分的操作就是:

  1. 定义 堆/栈 的大小,分别为 Stack_SizeHeap_Size
  2. 定义 堆/栈 段,不初始化,可读可写,以8字节对齐
  3. 堆/栈 段分配之前所定义大小的连续内存空间,分别命名为 Heap_MemStack_Mem
  4. 紧跟其后的 __initial_sp 用来表示栈顶地址,而 __heap_base 用来表示堆的起始地址,__heap_limit 用来表示堆的结束地址

  - 栈为向下生长,堆为向上生长,所以需要决定的是栈顶地址、堆的起始和结束地址。
  - 栈的作用主要是局部变量,函数调用,函数形参等的开销,栈的大小不能超过内部SRAM的大小。如果编写的程序规模比较大,定义的局部变量很多,那么就对应需要增加栈的大小,否则会产生内存溢出导致硬件错误。
  - 堆主要用来动态内存的分配,像malloc()函数申请的内存就在堆里,在STM32中使用较少。



2. 初始化中断向量表

  1. 首先定义一个 数据段,段名为 RESET只读 ,用于存放接下来这段代码
  2. 通过 EXPORT 指令引出 __Vectors__Vectors_End__Vectors_Size 三个标号供外部使用,这三个标号分别表示中断向量表的 起始地址、结束地址和规模大小
  3. 开始定义中断向量表,__Vectors 标号记录向量表的起始地址。
  4. 通过 DCD 指令(申请一段连续的字储存空间并分配初始值)来初始化中断向量表。

  中断向量表里存放的其实就是一个个中断服务的函数地址。中断向量表里的第一个存放的是SP(堆栈指针)地址,第二个是复位程序的地址。ARM规定程序上电后,先加载SP和PC:从0地址处加载SP,从偏移为4的地址加载PC。
  也就是说上电之后通过第一条向量加载SP,通过第二条向量加载PC,而第二条向量指向复位程序 Reset_Handler ,于是系统通过复位程序之后进入用户程序。

STM32启动文件分析_第3张图片

      __Vectors_End 表示中断向量表的结束地址
      __Vectors_Size 通过计算得出:结束地址-起始地址

STM32启动文件分析_第4张图片



3. 复位中断函数

  复位中断函数最主要由两部分组成:
    1. 系统初始化
    2. 运行环境初始化并进入用户函数

STM32启动文件分析_第5张图片

  依旧是通过 AREA 关键词先定义一个代码段,只读,名为 “.text”。
  然后使用两个 IMPORT 关键词导入 “SystemInit” 和 “__main” 两个标号。
    - “SystemInit” 是官方编写的系统初始化函数,主要作用时初始化时钟设置,
    - “__main” 是C库函数,主要是初始化C运行环境,并最终引导跳转到用户函数 “main()”,
  跳转 SystemInit 时使用的是带返回的跳转指令 BLX ,而跳转 “__main” 时则是不带返回的跳转指令 BX ,因为最终会引导进入用户函数 “main()”。



4. 其余中断函数

  这些函数大多数都是空的,并且通过 [WEAK] 关键词修饰,当外部定义了该标号则优先使用外部的标号。
  子程序内部只有一条 “B .” 跳转指令,这条指令等同于 “while(1)”,也就是会让程序在此死循环。
  系统中断一一列出,除了复位函数之外,都是这样的空函数。

STM32启动文件分析_第6张图片

      而外部中断函数则是统一列在 Default_Handler 之中。而在末尾也是同样的 “B .” 跳转指令。

STM32启动文件分析_第7张图片

  这些中断服务函数的使用方法都是通过 [WEAK] 关键字来进行:在外部使用相同标号编写函数之后,触发中断时就会直接跳到外部自己编写的中断服务函数之中,从而完成相关功能。
  需要注意的是,如果打开了某个中断而 没有编写对应中断服务函数 或是 函数名没有对应上给定的标号,就会导致程序跑入预先写好的空函数中死循环跑死。



5. 堆和栈的初始化

  堆和栈的初始化可以通过C库函数来进行,如果定义了 MICROLIB 则程序引出3个堆栈起始结束的地址标号给C库函数进行初始化。如果没有使用C库函数,则通过下面一段程序进行堆和栈的初始化

STM32启动文件分析_第8张图片



启动文件用到的ARM指令表

STM32启动文件分析_第9张图片

你可能感兴趣的:(STM32系列,嵌入式,stm32,单片机)