当STM32上电时,无论哪种启动模式,程序都将会从地址0x0000 0000开始执行,三种启动模式只是将各自存储空间映射到地址0x0000 0000。事实上,原存储空间的内容仍然被保留,也就是说从地址0x0000 0000和原存储地址都可以开始访问程序。
1) Flash启动,将Flash地址0x0800 0000映射到0x0000 0000,这样启动以后程序相当于是从0x0800 0000开始的,这是我们最常用的模式;
2) SRAM启动,将SRAM地址0x2000 0000映射到0x0000 0000,这样启动以后程序相当于是从0x2000 0000开始的;
3) 系统存储器启动,将系统存储器地址0x1FFF F000映射到0x0000 0000,这样启动以后就相当于从0x1FFF F000开始执行的,值得注意的是这个系统存储器里面存储的其实是STM32自带的Bootloader代码,其实是一个官方的IAP,它提供了可以通过UART1接口将用户的代码下载到Flash中的功能,下载完以后再切换到从Flash中启动就可以正常运行了。
02 启动文件
STM32同其它
单片机和DSP一样,虽然是从main函数开始编程的,其实上电后并不是从main函数开始执行的,在进入main函数之前,STM32的CPU会最先设置SP(栈指针)、PC(程序计数器指针),然后执行“启动文件”,这个启动文件就是工程文件夹中的startup_stm32xxxx.s文件。
启动文件由汇编编写,是系统上电复位后第一个执行的程序。主要做了以下工作:
1、初始化堆栈指针SP=_ini
tial_sp
2、初始化程序计数器指针PC =Reset_Handler
3、初始化中断向量表
4、配置系统时钟
5、调用C库函数__main(__main并不是main函数)初始化用户堆栈,从而最终调用main函数去到C的世界
03 上电启动流程
我们以Flash启动模式为例。上电后,地址0x0800 0000开始的程序被映射到地址0x0000 0000,然后程序从0x0000 0000开始执行。
CPU会从地址0x0000 0000读取32位长度的值,并赋值给栈指针SP;然后从地址0x0000 0004读取32位长度的值复制给程序计数器指针PC,程序将会从PC指针内容处开始执行。
为了验证这一点,我们用在线
仿真的方式查看地址0x0000 0000开始的数据:
想了解启动映射过程的朋友可以在这里分别查看地址0x0000 0000和地址0x08000 0000开始的存储区域,会发现两个完全是复制粘贴的关系。
那么由上图可以看出SP=0x20000738,PC=0x08000165,也就是说程序会从地址0x08000165开始执行。
打开map文件,查看0x08000165这个地址处放的是什么程序?
可以看到这里是复位入口地址Reset_Handler,这个入口地址在前面提到的“启动文件”startup_stm32xxxx.s中会有定义。打开工程中的启动文件,找到Reset_Handler的位置:
这段函数将会首先调用SystemInit函数对系统时钟进行初始化配置,这个函数可以在system_stm32fxxx.c中找到。然后会继续调用__main库函数(__main并不是main函数),主要的功能是软件设置SP、加载.data.bss并初始化栈区。
在执行到__main函数的最后,会跳转到mian()函数,这时便来到了我们的C语言环境。
原作者:雷 I 神 iFTrue未来已来