【正点原子STM32】STM32启动过程浅析(MAP文件、STM32启动过程、启动模式、Reset_Handler函数、__initial_sp堆栈的起始地址、堆栈)

一、MAP文件浅析

  • MAP文件概念和作用
  • MAP文件组成
  • MAP文件实操

二、STM32启动过程

  • 2.1、STM32启动模式(F1/F4/F7/H7)(也称自举模式)
    • STM32启动模式(F1)
    • STM32启动模式(F4)
    • STM32启动模式(F7)
    • STM32启动模式(H7)
  • 2.2、STM32启动过程(内部FLASH启动为例)
    • 启动文件介绍
    • Reset_Handler函数介绍
    • 堆栈简介
    • STM32启动过程图解

三、总结


参考资料:STM32 MAP文件浅析.pdf、STM32 启动文件浅析.pdf、Cortex-M3权威指南(中文).pdf
路径:战舰 V4\资料\1,入门资料\STM32 MAP文件浅析.pdf、STM32 启动文件浅析.pdf
   战舰 V4\资料\8,STM32参考资料\Cortex-M3权威指南(中文).pdf


一、MAP文件浅析

【正点原子STM32】STM32启动过程浅析(MAP文件、STM32启动过程、启动模式、Reset_Handler函数、__initial_sp堆栈的起始地址、堆栈)_第1张图片
MAP文件(Memory Map File)是编译器生成的连接地图文件,提供了有关程序在内存中的布局信息。MAP文件包含了代码、数据、堆栈等在内存中的地址分配情况,以及每个模块的大小等信息。在MDK(Keil Microcontroller Development Kit)编译过程中,MAP文件对于分析程序存储占用情况非常有用。

以下是MAP文件的一些关键信息:

  1. 模块列表:

    • 显示了每个编译单元(源文件)生成的目标模块的详细信息,包括模块名称、起始地址、长度等。
  2. 内存段信息:

    • 描述了程序的内存布局,包括代码段、数据段、堆栈等的起始地址和长度。
  3. 符号表:

    • 包含了程序中使用的所有符号(变量、函数等)的地址和大小。
  4. 存储占用情况:

    • 显示了每个内存段(如FLASH、RAM)的占用情况,包括已使用空间、未使用空间等。
  5. 调用图:

    • 提供了函数之间的调用关系,可以帮助分析程序的执行流程。

通过分析MAP文件,开发者可以了解程序的内存布局,查看各个模块的存储占用情况,优化代码,解决内存溢出等问题。

MAP文件概念和作用

【正点原子STM32】STM32启动过程浅析(MAP文件、STM32启动过程、启动模式、Reset_Handler函数、__initial_sp堆栈的起始地址、堆栈)_第2张图片
MAP文件(Memory Map File)是在编译过程中由链接器生成的一种文件,用于描述程序在内存中的布局和各个模块的分配情况。以下是MAP文件的主要概念和作用:

  1. 概念:

    • 内存映射: 将程序的各个部分(代码、数据、堆栈等)映射到目标设备的物理内存地址上。
    • 地址空间: 描述程序在内存中的布局,通常包括FLASH、RAM等区域,每个区域都有起始地址和长度。
    • 符号表: 记录了程序中使用的符号(变量、函数等)的地址和大小。
  2. 作用:

    • 存储占用分析: 提供了每个模块(源文件、库文件等)在内存中的占用情况,包括代码段、数据段等的大小和地址。
    • 符号信息: 列出了程序中定义和引用的符号,有助于了解各个符号在内存中的分布情况。
    • 调用关系: 提供了函数之间的调用关系,有助于理解程序的执行流程。
    • 优化代码: 开发者可以根据MAP文件分析结果,对代码进行优化,减小存储占用,提高执行效率。

MAP文件是在调试和优化阶段非常有用的工具,通过分析这些信息,开发者可以更好地理解程序在内存中的分布,从而优化代码、解决内存相关问题。

MAP文件组成

【正点原子STM32】STM32启动过程浅析(MAP文件、STM32启动过程、启动模式、Reset_Handler函数、__initial_sp堆栈的起始地址、堆栈)_第3张图片
MAP文件通常由以下几个主要部分组成:

  1. 程序段交叉引用关系:

    • 描述各个源文件(.c、.s等)之间的函数调用关系。
    • 列出了函数之间的引用关系,帮助理解程序的调用流程。
  2. 删除映像未使用的程序段:

    • 描述工程中未使用的、被删除的冗余程序段(函数/数据)。
    • 帮助开发者了解工程中存在的冗余代码,有助于优化代码。
  3. 映像符号表:

    • 描述各个符号在存储器中的地址、类型、大小等信息。
    • 包括函数、变量等的地址和占用大小。
  4. 映像内存分布图:

    • 描述各个程序段(函数)在存储器中的地址及占用大小。
    • 显示了程序在FLASH和RAM等存储器中的布局。
  5. 映像组件大小:

    • 汇总整个映像代码(.o文件)占用的空间信息。
    • 给出了程序的总体大小、代码段大小、数据段大小等信息。

这些信息有助于开发者深入了解程序在内存中的布局和分布情况,通过MAP文件,可以更好地进行代码优化、查找冗余代码、解决内存相关的问题。

MAP文件实操

学会分析:哪个.c占用flash 和ram比较大,以便针对性的优化

map 文件的 MDK 设置

【正点原子STM32】STM32启动过程浅析(MAP文件、STM32启动过程、启动模式、Reset_Handler函数、__initial_sp堆栈的起始地址、堆栈)_第4张图片
【正点原子STM32】STM32启动过程浅析(MAP文件、STM32启动过程、启动模式、Reset_Handler函数、__initial_sp堆栈的起始地址、堆栈)_第5张图片
设置好 MDK 以后,我全编译当前工程,当编译完成后(无错误),就会生成.map 文件。在 MDK 里面打开 .map 文件的方法如图所示:
【正点原子STM32】STM32启动过程浅析(MAP文件、STM32启动过程、启动模式、Reset_Handler函数、__initial_sp堆栈的起始地址、堆栈)_第6张图片

  1. 先确保工程编译成功(无错误)。
  2. 双击 LED,打开.map 文件。
  3. map 文件打开成功。

二、STM32启动过程

2.1、STM32启动模式(F1/F4/F7/H7)(也称自举模式)

【正点原子STM32】STM32启动过程浅析(MAP文件、STM32启动过程、启动模式、Reset_Handler函数、__initial_sp堆栈的起始地址、堆栈)_第7张图片
启动模式,也被称为自举模式(bootstrapping mode),是指在单片机复位后执行的初始化和启动操作。对于STM32和许多其他微控制器,启动模式包括以下几个关键步骤:

  1. 取出堆栈指针 MSP 的初始值:

    • 从地址0x0000 0000处读取的第一个字(32位)是堆栈指针的初始值。这个值表示了栈的初始位置。
  2. 取出程序计数器指针 PC 的初始值:

    • 从地址0x0000 0004处读取的第二个字是程序计数器的初始值,即复位向量。这个值指示了执行程序的起始地址。
  3. 地址映射:

    • 注意到芯片厂商可能会将0x0000 0000和0x0000 0004地址映射到其他地址。这是由于一些芯片允许在不同的启动模式下加载不同的固件。这样,启动模式可以选择不同的起始地址。

在STM32中,这些初始值是由芯片上的启动加载器(Bootloader)提供的,该加载器通常存储在固定的引导区域中。通过在这个引导区域中设置不同的启动模式标志位,可以选择加载不同的程序或固件。

这个启动过程确保了在复位后,程序能够正确地开始执行,并且栈和程序计数器都被正确初始化。

STM32启动模式(F1)

【正点原子STM32】STM32启动过程浅析(MAP文件、STM32启动过程、启动模式、Reset_Handler函数、__initial_sp堆栈的起始地址、堆栈)_第8张图片

STM32启动模式(F4)

【正点原子STM32】STM32启动过程浅析(MAP文件、STM32启动过程、启动模式、Reset_Handler函数、__initial_sp堆栈的起始地址、堆栈)_第9张图片

STM32启动模式(F7)

【正点原子STM32】STM32启动过程浅析(MAP文件、STM32启动过程、启动模式、Reset_Handler函数、__initial_sp堆栈的起始地址、堆栈)_第10张图片

STM32启动模式(H7)

【正点原子STM32】STM32启动过程浅析(MAP文件、STM32启动过程、启动模式、Reset_Handler函数、__initial_sp堆栈的起始地址、堆栈)_第11张图片

2.2、STM32启动过程(内部FLASH启动为例)

【正点原子STM32】STM32启动过程浅析(MAP文件、STM32启动过程、启动模式、Reset_Handler函数、__initial_sp堆栈的起始地址、堆栈)_第12张图片
STM32启动过程的步骤详细说明:

  1. Reset复位:

    • 当STM32芯片上电或复位时,处理器会进入复位状态,即复位向量。在复位状态下,处理器会执行一系列初始化步骤来确保正常运行。
  2. 获取MSP值0X0800 0000:

    • 复位向量的第一个字(32位)包含堆栈指针(MSP - Main Stack Pointer)的初始值。处理器将该值加载到堆栈指针寄存器(SP)中。
  3. 获取PC值0X0800 0004:

    • 复位向量的第二个字包含程序计数器(PC - Program Counter)的初始值,即复位向量。处理器将该值加载到程序计数器寄存器(PC)中。
  4. Reset_Handler:

    • 复位向量中的复位向量指向Reset_Handler。这是一个特殊的函数,由启动文件(通常是startup_stm32xxx.s)提供。Reset_Handler 会执行一些处理器的基本初始化,然后跳转到 main 函数。
  5. 启动文件 startup_stm32xxx.s:

    • 启动文件是一个汇编文件,包含处理器初始化和启动的汇编代码。它负责初始化数据段、BSS 段、调用系统初始化等。
  6. main函数:

    • 一旦启动文件执行完毕,它将跳转到 main 函数。在 main 函数中,用户可以编写他们的应用程序代码。

这个启动过程确保了在复位后,程序能够正确地开始执行。内部FLASH启动是默认的启动模式,但STM32芯片通常支持其他启动模式,例如通过串口或外部存储器引导。在这种情况下,复位向量和启动文件可能会有所不同。

启动文件介绍

【正点原子STM32】STM32启动过程浅析(MAP文件、STM32启动过程、启动模式、Reset_Handler函数、__initial_sp堆栈的起始地址、堆栈)_第13张图片
对STM32启动过程的这些关键步骤概述。以下是对每个步骤的一些进一步的解释:

  1. 初始化MSP:

    • MSP(Main Stack Pointer)是处理器的主堆栈指针,指向主堆栈区的顶部。在启动时,它的初始值通常是存储在复位向量表的第一个位置(0x0800 0000)的值。这个值通常是设备的系统内存(RAM)的顶部。
  2. 初始化PC:

    • PC(Program Counter)是处理器的程序计数器,指向要执行的下一条指令的内存地址。在启动时,PC 的初始值存储在复位向量表的第二个位置(0x0800 0004)。这个值通常是 Reset_Handler 函数的地址,它是启动文件中的一个特殊函数。
  3. 设置堆栈大小:

    • 堆栈和堆是两个不同的内存区域。在启动时,通常设置堆栈大小和堆大小。这些值由链接脚本(.ld 文件)定义,然后由链接器使用。
  4. 初始化中断向量表:

    • 中断向量表是一系列指向中断服务例程(ISR)的指针。在启动时,这些指针的初始值存储在复位向量表中。__Vectors 是一个包含这些指针的数组。
  5. 调用初始化函数:

    • SystemInit 函数是一个可选的函数,用于执行系统级的初始化。这可能包括设置系统时钟、中断优先级等。
  6. 调用 __main:

    • __main 是标准 C 库函数,它执行一系列的设置,并最终调用 main 函数。在用户代码中,main 函数是程序的起始点。

这些步骤确保了在复位后,处理器能够按照预期的方式执行程序。这个过程是由启动文件和链接脚本控制的,具体的细节可能会因设备型号和编译环境而有所不同。

Reset_Handler函数介绍

【正点原子STM32】STM32启动过程浅析(MAP文件、STM32启动过程、启动模式、Reset_Handler函数、__initial_sp堆栈的起始地址、堆栈)_第14张图片
这段汇编代码是 Cortex-M 处理器的启动代码,主要完成了以下几个步骤:

  1. 导出 Reset_Handler 函数: EXPORT 关键字用于标明 Reset_Handler 函数是一个全局可见的标识符,可以被其他模块引用。

  2. 声明 __main 和 SystemInit 函数: IMPORT 关键字用于声明 __mainSystemInit 函数,这两个函数通常是由编译器生成的。

  3. 加载 SystemInit 函数的地址到 R0 寄存器: 使用 LDR 指令将 SystemInit 函数的地址加载到 R0 寄存器。

  4. 通过 BLX 指令调用 SystemInit 函数: BLX 指令用于调用函数,这里将通过 R0 寄存器中的地址调用 SystemInit 函数。这个函数通常包含了系统初始化的相关操作。

  5. 加载 __main 函数的地址到 R0 寄存器: 使用 LDR 指令将 __main 函数的地址加载到 R0 寄存器。

  6. 通过 BX 指令跳转到 __main 函数: BX 指令用于跳转到指定地址的子程序,这里将跳转到 __main 函数,即 C 语言程序的入口点。

  7. 定义 Reset_Handler 过程结束: ENDP 关键字用于表示 Reset_Handler 过程的结束。

  8. 弱定义标记: WEAK 关键字表示这是一个弱定义,如果在其他地方有相同的函数定义,链接器可以选择其中一个。在这里,如果系统提供了自定义的 SystemInit 函数,它将被使用;否则,使用默认的 SystemInit 函数。

这段代码是启动文件中的一部分,它负责初始化系统,并跳转到主程序的入口点。

堆栈简介

【正点原子STM32】STM32启动过程浅析(MAP文件、STM32启动过程、启动模式、Reset_Handler函数、__initial_sp堆栈的起始地址、堆栈)_第15张图片
堆栈是在程序运行时动态分配和管理内存的两个主要区域。这两个区域分别是:

  1. 栈(Stack):

    • 由编译器自动分配和释放。
    • 用于存放函数参数、局部变量等。
    • 具有后进先出(LIFO)的结构,即最后入栈的数据最先出栈。
    • 栈的大小在编译时就已经确定,通常比较有限,如果函数调用层次太深或者局部变量较多,可能导致栈溢出。
  2. 堆(Heap):

    • 由程序员负责手动分配和释放。
    • 通过动态内存分配函数(如malloc、calloc、realloc等)进行操作。
    • 用于存储程序运行时动态分配的数据。
    • 堆的大小通常比栈大得多,但使用不当可能导致内存泄漏或者堆碎片问题。

在嵌入式系统开发中,尤其是对于资源有限的系统,合理管理栈和堆的大小是很重要的。太小的栈可能导致栈溢出,而太小的堆可能导致动态内存分配失败。在确定栈和堆的大小时,需要考虑程序的复杂性、函数调用深度、局部变量和动态内存需求等因素。

STM32启动过程图解

【正点原子STM32】STM32启动过程浅析(MAP文件、STM32启动过程、启动模式、Reset_Handler函数、__initial_sp堆栈的起始地址、堆栈)_第16张图片
在嵌入式系统中,Reset_Handler 是一个特殊的函数,它是系统复位后执行的第一个函数。该函数负责初始化系统,设置堆栈和跳转到主函数(通常是 main 函数)。下面是一个简单的 Reset_Handler 函数的例子:

Reset_Handler PROC
    EXPORT Reset_Handler [WEAK]
    IMPORT __main
    IMPORT SystemInit

    LDR R0, =SystemInit
    BLX R0

    LDR R0, =__main
    BX R0
    ENDP

在这个例子中:

  • EXPORT 表示将 Reset_Handler 函数标记为可被外部调用。
  • IMPORT 表示引入外部定义的函数,这里是 __mainSystemInit
  • LDR R0, =SystemInitSystemInit 函数的地址加载到寄存器 R0
  • BLX R0 调用 SystemInit 函数。
  • 接着调用 __main 函数,通常在该函数中会进入到用户编写的 main 函数。

关于 __initial_sp,它是初始化堆栈指针的一个符号。在 ARM Cortex-M 处理器中,启动代码通常将 __initial_sp 设置为堆栈的起始地址。在链接脚本中,你可能会看到类似如下的定义:

__initial_sp = 0x20020000; /* 堆栈的起始地址,具体值根据实际情况而定 */

这个地址指向的是堆栈的起始位置,即堆栈的最高地址。在 Reset_Handler 函数中,会将这个地址加载到堆栈指针寄存器 MSP(Main Stack Pointer)中,从而初始化堆栈。这个过程通常在 SystemInit 函数中完成。

总的来说,Reset_Handler 负责系统的初始化,包括设置堆栈和调用主函数,而 __initial_sp 是堆栈的初始地址。这两者通常在启动文件(startup 文件)中定义和使用。

【正点原子STM32】STM32启动过程浅析(MAP文件、STM32启动过程、启动模式、Reset_Handler函数、__initial_sp堆栈的起始地址、堆栈)_第17张图片

三、总结

【正点原子STM32】STM32启动过程浅析(MAP文件、STM32启动过程、启动模式、Reset_Handler函数、__initial_sp堆栈的起始地址、堆栈)_第18张图片
【正点原子STM32】STM32启动过程浅析(MAP文件、STM32启动过程、启动模式、Reset_Handler函数、__initial_sp堆栈的起始地址、堆栈)_第19张图片
【正点原子STM32】STM32启动过程浅析(MAP文件、STM32启动过程、启动模式、Reset_Handler函数、__initial_sp堆栈的起始地址、堆栈)_第20张图片

你可能感兴趣的:(STM32,stm32,MAP文件内存占用优化,STM32启动模式也称自举模式,Reset_Handler函数,__initial_sp栈顶,STM32启动过程,启动文件)