MCU启动流程
MCU启动流程
- MCU启动流程
- 1 MCU的启动方式
- 2 MCU程序启动执行过程
- 3 启动过程的执行工作
- 4 keil调式过程验证
- 5 调试文件map
1 MCU的启动方式
单片机的启动方式,以stm32为例,如下:
不同的下载方式对应的不同的启动方式,stm32主要有三种启动方式:flash memory、system memory、Embedded SRAM
flash启动(最常用):stm32的flash能够擦写数十万次,用户通过JTAG或SWD模式,将程序下载至此,重新启动从此处启动
sytem memory (系统存储器启动):系统存储器是芯片内的一块特定的区域,系统存储器中预置了一段bootloader,bootloder将程序下载到flash区,通过flash启动
内嵌SRAM启动:从内存中直接启动代码,避免因小修改反复擦写flash内存,一般用于高速调试
2 MCU程序启动执行过程
MCU上电,根据BOOT的引脚(BOOT0、BOOT1)电平,来确定启动地址。一般地址是0x0000000,个别如stm32的启动地址是0x8000000(flahs区启动)。
stm32内部闪存的起始地址为0x8000000,程序从此处写入,中断向量表位于该位置,首先从0x8000000取出MSP的栈顶指针(设置堆栈),然后从中断向量表中取出复位中断向量,并执行复位中断程序来完成启动。
程序执行过程如图:
1、STM32复位后,会从地址为0x8000004处取出复位中断向量的地址,并跳转执行复位中断服务程序,如图1中标号1️⃣所示。
2、复位中断服务程序执行的最终结果是跳转至C程序的main函数,如上图中标号2️⃣所示,而main函数应该是一个死循环,是一个永不返回的函数。
3、在main函数执行的过程中,发生了一个中断请求,此时STM32的硬件机制会将PC指针强制指回中断向量表处,如图中标号3️⃣所示。
4、根据中断源进入相应的中断服务程序,如图1中标号5️⃣所示。
5、中断服务程序执行完毕后,程序再度返回至main函数中执行,如图中标号6️⃣所示。
3 启动过程的执行工作
启动过程主要完成两部分工作:硬件环境、软件环境
硬件环境操作:
初始化时钟:初始化内核时钟,主时钟和各个外设的时钟
关闭看门狗:看门狗用来检测应用程序异常跑飞而复位CPU,在初始化阶段,没有“喂狗“的动作,有可能导致CPU 不断的复位,此处需要关闭看门狗
建立中断向量表:中断向量表作为中断源的识别标志,可以形成相应的中断入口地址,或者中断服务程序的入口地址的偏移量和段基值。CPU利用中断向量表转入中断服务程序处理相关到事务
初始化堆栈:堆栈的作用就是保护现场(上下文),函数调用或中断发生时,将当前执行地址压栈,调用完再返回执行此次的地址。在启动阶段,初始化堆栈的寄存器、堆栈大小、起始地址等
内存初始化:选择内部或外部RAM
软件环境操作:
把RO、RW从它们的加载域复制到运行域
初始化ZI域
初始化堆栈指针:包括C库所需要的内存空间、程序执行的所需资源、C库初始化
4 keil调式过程验证
进入调试模式,首先进入一个启动文件starup_ARMCM4.s的启动文件,运行指示光标,会停在SystemInit上:
starup_ARMCM4.s代码的前面是:栈大小stack size设置、堆大小 heap size的设置、一堆中断向量表 Vect Table
当前运行所在处为Reset_Handle处,在执行main 之前还需要执行 SystemInit,SystemInit在system_ARMCM4.c文件中,如下跳转至system_ARMCM4.c中的SystemInit函数
执行完SystemInit,将执行__main函数
参考:单片机启动过程: main之前干了啥
5 调试文件map
xxx.map文件是一种通过编译得到的调试输出信息文件,通过map文件可以了解函数的大小,入口地址、变量、参数的大小位置等一些列信息,用于解决内存越界以及数据溢出等问题。
map文件是在配置页面的Linker Listing选项卡进行配置:
map文件分析:map文件主要分为5大类,如下:
Section Cross References:模块、段(入口)交叉引用
配置勾选----->Cross Reference
针对第四条内容:
startup_armcm4.o(RESET) refers to startup_armcm4.o(STACK) for __initial_sp
表示startup_armcm4.o中的RESET段引用了startup_armcm4.o中的STACK段中的一个全局变量(或函数)__initial_sp
Removing Unused input sections from the image:移除未调用模块
配置勾选----->Unused Section Info
显示的是编译时从映像中被移除的未调用模块,以及它们的大小及总体统计内容
Image Symbol Table:映射符号表
配置勾选----->Symbols
该部分显示符号映射表,包括两个部分:Local Symbol(局部变量)和Global Symbol(全局变量)
Memory Map of the image:内存(映射)分布
配置勾选----->Memory Map
Image Entry point : 0x000000c1 映射入口地址
Load Region LR_IROM1 (Base: 0x00000000, Size: 0x0000026c, Max: 0x00040000, ABSOLUTE):指加载区域位于LR_IROM1开始地址0x00000000,大小有0x0000026c,这块区域最大为0x00040000
Execution Region ER_IROM1 (Base: 0x08000000, Size: 0x00001188, Max: 0x00080000, ABSOLUTE)
Execution Region RW_IRAM1 (Exec base: 0x20000000, Load base: 0x00000268, Size: 0x00001068, Max: 0x00020000, ABSOLUTE)
首先就是映像的入口地址0x000000c1,然后可以知道加载域的起始地址,大小,最后知道执行域ROM和RAM的起始地址和大小,其中0x20000000是RAM起始地址,0x00000000是ROM起始地址,在这里也就是flash。一些被丢弃掉的数据,比如没有使用的变量被优化后是不会在表中显示出来的。
Image component sizes:存储组成大小
配置勾选----->Size Info
Code:代码数据
RO-data:指只读数据,除了内联数据之外的常量数据
RW-data:指可读写、已初始化变量
ZI-data:为初始化变量
上面显示的几个区域的总体占用大小,其中:
Code、Ro-data:位于FLASH
Rw-data、ZI-data:位于RAM中
RW-data已初始化的数据会存储在Flash中,上电会从FLASH搬移至RAM
Total ROM Size就是下载到flash中的程序大小