转自:http://blog.csdn.net/qq_30479727/article/details/63352897
一、STM32 程序下载与Bootloader
三种启动模式如下表:
(截图与stm32中文参考资料)
1、从主闪存存储器启动,即从STM32内置的Flash启动,BOOT0=0,BOOT1=X, 一般我们使用JTAG或者SWD模式下载程序时,就是下载到这个里面,复位(软件复位、手动复位、硬件自动复位)后也直接从这启动程序。不需要使用到系统存储区的Bootloader程序。
2、从系统存储器启动,即STM32的ISP了。B00T0=1,B00T1=0,由于串口不能直接把程序下载到内置的flash里面,所以需要使用到ST公司内嵌于系统存储区(flash的某一部分的地址被编为0x1FFF_F000-0x1FFF_F7FF,这就是所谓的系统存储器\区)的Bootloader来引导把程序下载到flash里面。程序下载完成后还需要配置BOOT[1:0]引脚为BOOT0=0,BOOT1=X(即从主闪存存储器启动),复位后启动程序(手动复位或者使用硬件自动复位电路)。下图是关于STM32F10xxx的Bootloader的一些信息
截图来自文档AN26062
截图来自文档AN26062
截图来自正点原子开发板
3、从内置SRAM启动。内置SRAM,既然是SRAM,自然也就没有程序存储的能力了,这个模式一般用于程序调试。假如我只修改了代码中一个小小的地方,然后就需要重新擦除整个Flash,比较的费时,可以考虑从这个模式启动代码(也就是STM32的内存中),用于快速的程序调试,等程序调试完成后,在将程序下载到SRAM中。
二、STM32启动分析
预备知识:
DCD指令:用于分配一片连续的字存储单元(32bit),并将表达式的值初始化给该字存储单元,类似于C中定义数组并初始化。比如: DCD 0 的意思是:分配一个字存储单元,并将该单元初始化为0。
分析:
在STM32的启动文件中可以看到有如下代码:
EXPORT __Vectors
__Vectors
DCD __initial_sp ; Top of Stack
DCD Reset_Handler
DCD NMIException
DCD HardFaultException
DCD MemManageException
DCD BusFaultException
DCD UsageFaultException
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD SVCHandler
DCD DebugMonitor
DCD 0 ; Reserved
DCD OSPendSV
……
这一段是分配STM32的中断向量表。从DCD后面表达式的名称可以看出第一个字存储单元分配给了栈顶,其值为__initial_sp。第二个字分配给了复位地址,其值为Reset_Handler,后面接着分配给其他异常或中断。
这里的Reset_Handler,NMIException等,其实是一个地址值,也就是中断处理函数的入口地址。在函数实现时,由编译器分配一个地址值。
那么这里就有两个问题。
第一个是为什么是这样的分配顺序?
第二个是DCD后面表达式的值,即各个中断函数的地址值如Reset_Handler,NMIException是如何分配的?
第一个问题的答案好找,我们参考《STM32参考手册》:
可以看到,启动文件中的向量表的分配的顺序是按照固定的规则来的。
第二个问题。随意打开一份编译过的工程,工程配置如下:
我们可以看到.map文件有这样一段:
同时使用J-Link打开.hex文件可以看到
从hex档,我们可以看到Flash的起始区域0x8000000的内容为
0x20000660
0x0800027D
0x08000281
0x08000283
……
刚好可以和map文件对应,也刚好可以和启动文件的向量表对应。
按照Cortex-M3权威指南,在复位后,有如下动作:
我这里是选择从flash启动,根据寄存器映射,Address从0x00000000映射到0x08000000。所以hex档的内容刚好满足复位序列的设定。
由此从启动文件到.map文件再到.hex文档,再到CM3复位启动的脉络就理清了。