STM32启动过程——STM32F1系列

STM32启动过程

1、MDK 编译生成文件简介

MDK 编译工程,会生成一些中间文件(如**.o**、.axf.map等),最终生成hex文件

  • MDK编译过程文件共11种:
文件类型说明
.o可重定向对象文件,每个**.c**/.s文件编译都会生成一个**.o** 文件
.axf可执行对象文件,由**.o** 文件链接生成,仿真时需要用到此文件
.hexINTEL Hex格式文件,用于下载到MCU运行,由**.axf**文件转换而来
.crf交叉引用文件,包含浏览信息(定义、标识符、引用)
.d由 ARMCC/GCC 编译生产的依赖文件,每个.o 文件,都有一个对应的.d 文件
.dep整个工程的依赖文件
.lnpMDK 生成的链接输入文件,用于命令输入
.lstC 语言或汇编编译器生成的列表文件
.htm链接生成的列表文件
.build_log.htm最近一次编译工程时的日志记录文件
.map链接器生成的列表文件/MAP文件,对分析程序存储占用情况非常有用

2、MAP文件浅析

2.1 MAP文件概念和作用

MAP文件是MDK编译代码后产生的,集程序、数据及IO空间的一种映射列表文件。简单说就是包括了:各种**.c**文件、函数、符号等的地址、大小、引用关系等信息

  • 作用:分析各**.c文件占用FLASHRAM**的大小,方便优化代码

2.2 MAP文件组成

组成部分简介
程序段交叉引用关系描述各文件之间函数调用关系
删除映像未使用的程序段描述工程中未用到而被删除的冗余程序段/数据
映像符号表描述各符号(程序段/数据)在存储器中的地址、类型、大小等
映像内存分布图描述各个程序段在存储器中的地址及占用大小
映像组件大小给出整个映像代码(.o)占用空间汇总信息
  • 映像符号表及映像组件大小中的一些概念:
基础概念简介
Section描述映像文件的代码或数据块,我们简称程序段
RORead Only 的缩写,包括只读数据(RO data)和代码(RO code)两部分内容,占用 FLASH 空间
RWRead Write 的缩写,包含可读写数据(RW data,有初值,且不为 0),占用 FLASH(存储初值)和 RAM(读写操作)
ZIZero initialized 的缩写,包含初始化为 0 的数据(ZI data),占用 RAM 空间。
.text相当于 RO code
.constdata相当于 RO data
.bss相当于 ZI data
.data相当于 RW data

3、STM32启动模式

M3/M4/M7等内核复位后,做的第一件事:

  1. 从地址0x0000 0000处取出堆栈指针MSP的初始值,即SP = _initial_sp
  2. 从地址0x0000 0004处取出程序计数器指针PC的初始值,即PC = Reset_Handler

STM32F1系列为例:

在系统复位后,SYSCLK的第 4 个上升沿,BOOT引脚的值将被锁存,内核复位后的起始地址和中断向量表的位置被重映射

BOOT1BOOT0启动模式0x0000 0000映射地址0x0000 0004映射地址
x0FLASH0x0800 00000x0800 0004
01Bootloader0x1FFF F0000x1FFF F004
11SRAM0x2000 00000x2000 0004
  1. 通过 boot 引脚设置可以将中断向量表定位于 FLASH 区,即起始地址为 0x0800 0000,同时复位后 PC 指针位于 0x0800 0004
  2. 通过 boot 引脚设置可以将中断向量表定位于系统存储器内置 Bootloader 区,即起始地址为 0x1FFF F000,同时复位后 PC 指针位于 0x1FFF F004
  3. 通过 boot 引脚设置可以将中断向量表定位于 SRAM 区,即起始地址为 0x2000 0000,同时复位后 PC 指针位于 0x2000 0004

4、STM32启动过程

内部FLASH启动为例:

在这里插入图片描述

4.1 启动文件介绍

启动文件主要做了以下工作:

  1. 初始化堆栈指针 SP = _initial_sp

    _initial_sp从地址0x0800 0000获取

  2. 初始化程序计数器指针 PC = Reset_Handler

    Reset_Handler从地址0x0800 0004获取

  3. 设置堆的大小Heap_Size、栈的大小Stack_Size

  4. 初始化中断向量表 __Vectors定义

  5. 调用初始化函数 如:调用 SystemInit 函数(可选)

  6. 调用标准 C 库中的 __main 函数初始化用户堆栈,最终调用 main 函数

4.2 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 [WEAK]Reset_Handler函数可以在外部调用;若此函数在别处重新定义,则此处函数定义失效

  • IMPORT __mainIMPORT SystemInit:声明**__main函数、SystemInit函数来自外部文件,类似于 C 中的extern**

  • LDR R0,=SystemInit
    BLX R0
    

    SystemInit函数首地址到R0寄存器中,然后跳转到R0寄存器对应的地址,即调用SystemInit函数

  • LDR R0,=__main
    BX R0
    

    取**__main函数首地址到R0寄存器中,然后跳转到R0寄存器对应的地址,即==调用__main**函数==

4.3 堆栈简介

内存作用
栈(Stack)编译器自动分配和释放,存放函数参数、局部变量等
堆(Heap)人为手动分配和释放,如:malloc、calloc、realloc等
Stack_Size		EQU		0x0000 0400

				AREA	STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem		SPACE	Stack_Size
__initial_sp
  • 栈的定义

    • Stack_Size EQU 0x0000 0400:给常量0x0000 0400取个别名,常量的别名是 Stack_Size,类似于 C 中的define

    • AREA STACK, NOINIT, READWRITE, ALIGN=3:汇编一个新的代码段或者数据段,

      STACK为段名,可以任意命名

      NOINIT 表示不初始化

      READWRITE 表示可读可写

      ALIGN=3表示按照2的3次幂对齐,即 8 字节对齐

    • Stack_Mem SPACE Stack_Size:分配大小为 Stack_Size 字节连续的存储单元给栈空间

    • __initial_sp:紧挨着 SPACE 放置,表示栈的结束地址,栈是从高往低生长,所以结束地址就是栈顶地址

Heap_Size		EQU		0x0000 0200

				AREA	HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem		SPACE	Heap_Size
__heap_limit
				PRESERVE8
				THUMB
  • 堆的定义

    • Heap_Size EQU 0x0000 0200:给常量0x0000 0200取个别名,常量的别名是 Stack_Size,类似于 C 中的define

    • AREA STACK, NOINIT, READWRITE, ALIGN=3与栈的意义相同

    • Heap_Mem SPACE Heap_Size:分配大小为 Heap_Size 字节连续的存储单元给堆空间

    • __heap_base
      __heap_limit
      

      __heap_base表示堆的起始地址,__heap_limit 表示堆的结束地址。堆和栈的生长方向相反的,堆是由低向高生长,而栈是从高往低生长

    • PRESERVE8:指示编译器按照 8 字节对齐

    • THUMB:指示编译器之后的指令为 THUMB 指令

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值