声明:本次涉及到的地址等信息,都是与(一)文章https://blog.csdn.net/weixin_52803467/article/details/141360184一样。两个文章可以接连看比较好。
1、启动模式
我们经常使用的启动方式有两种,一种是把程序烧写到FLASH区域,程序从FLASH区域开始运行,一种是把程序烧写到RAM运行。前者掉电后,再次启动,会保留上次程序。后者掉电后,之前的程序就没有了哦。
2、启动流程
经过(一)的学习,我们知道运行的第一个程序是从启动文件开始的。程序存储的第一个内容就是向量表。向量表第一个地址(__initial_sp),存储的是堆栈地址。第二个地址内容存储的是复位中断函数(Reset_Handler)的地址。
假如:我们现在把代码下载到了内部FLASH中。也就是说程序是从0x0800_0000开始的。那么我们现在看看程序到底是怎么存储的。
使用KEIL软件Debug调试:
点击调试->点击Memory->弹出:
开始读数据:
地址: 数据(4字节) 实际内容
0x0800_0000 08 06 00 20 0x2000_0608
0x0800_0004 45 01 00 08 0x0800_0145
有同学可能会问,明明0x0800_0000地址内容是 08_06_00_20 为什么最后实际数据是0x2000_0608?因为STM32芯片使用的是小端存储【低位数据存储在低地址,高位数据存储在高地址】。
OK!来看看0x2000_0608,0x0800_0145是什么吧??
上面有说过,0x0800_0000地址存储的是__initial_sp,0x0800_0004存储的是Reset_Handler。我们来验证一下看看是不是吧。
(1)点击xxxx.map文件
(2)查找__initial_sp
可以看到__initial_sp内容就是0x2000_0608。至于为什么是0x2000_0608可以看看(一)。
- 查找Reset_Handler
可以看到Reset_Handler地址就是0x0800_0145。
总结一下:程序开始从0x0800_0000处取出堆栈指针MSP(MCU寄存器)的初始值,接着开始执行0x0800_0004地址内容,去执行Reset_Handler函数。在Reser_Handler函数中先执行System_init()函数,执行进入main函数中,执行我们写的主程序。详细内容可看(一)。