我们日常使用的嵌入式应用程序开发中都是编写C/C++语言,我们平时编辑一个工程的话,只用从main函数开始编辑,单片机程序也是从这个函数开始进行执行的。但是单片机上电后是如何寻找到并执行main函数的呢?我们其实都会在心里有一个答案:"启动文件",还记得我们当初配置第一个stm32工程的时候在工程中添加过一个startup_stm32f10x_hd.s的文件,这个文件的作用就是负责执行从"复位"到开始执行main函数中间的启动过程,下面我将对这个文件和stm32的相关知识进行阐述。
首先了解一下stm32的三种启动方式:在每个STM32的芯片上都有两个管脚BOOT0和BOOT1,这两个管脚在芯片复位时的电平状态决定了芯片复位后从哪个区域开始执行程序,见下表:BOOT1=x BOOT0=0 从用户闪存FLASH启动,这是正常的工作模式。BOOT1=0 BOOT0=1 从系统存储器启动,这种模式启动的程序功能由厂家设置。BOOT1=1 BOOT0=1 从内置SRAM启动,这种模式可以用于调试。
而Cortex-M3/4内核规定,起始地址必须存放堆顶指针,而第二个地址则必须存放复位中断入口向量地址,这样在Cortex-M3/4内核复位后,会自动从起始地址的下一个32位空间取出复位中断入口向量,跳转执行复位中断服务程序。而启动文件的编写正是按着这个规定来的,下面我将对启动文件的代码进行分析。
我挑选了我们常用的startup_stm32f40_41xxx.s进行源码分析,该文件可以分成以下五个典型部分:
1.堆栈空间定义;
2.存放中断向量表;
3.复位中断函数(Reset_Handler);
4.其它中断异常服务函数,以及弱[WEAK]声明;
5.将堆栈地址传递给库函数,利用库函数初始化堆栈,和库函数自身初始化。
01堆栈空间的定义
如下图所示,定义了栈大小Stack_Size = 0X400,即1024个字节;堆大小Heap_Size = 0X200, 512个字节。还定义了三个标号:__initial_sp(栈顶)、__heap_base(堆起