启动模式
首先我们先看一下启动模式
启动流程
RESET->获取MSP值,获取PC值->Reset_Handler
在cortex-M3权威指南中是这样讲的:
下面两个图片可以先不看
现在讲一下MSP和SP是什么
MSP是复位向量的第一个字(32位)包含堆栈指针(MSP - Main Stack Pointer)的初始值。处理器将该值加载到堆栈指针寄存器(SP)中。简单地说,就是一会要分配的栈的起始地址。因为 CM3 使用的是向下生长的满栈,所以 MSP 的初始值必须是堆栈内存的末地址加 1。 举例来说,如果你的栈区域在 0x20000388‐0x20000787 之间,那么 MSP 的初始值就必须是0x20000788。
Reset_Handler: 一个特殊的函数,由启动文件(通常是startup_stm32xxx.s)提供。Reset_Handler 会执行一些处理器的基本初始化,然后跳转到 main 函数。
启动文件解析
参考正点原子的STM32启动浅析,启动文件的关键步骤如下
现在来看一下startup_stm32f103xb.s
中断向量定义表
前几段声明了__Vectors(向量起始地址)、__Vectors_End (向量结束地址)和 __Vectors_Size (向量大小)三个标号具有全局性(EXPORT),可被外部的文件使用。
61行注释说了这一个是,栈顶指针,这里如果是在内部FLASH运行,就是0x08000000。DCD表示以四字节对齐分配内存,那么下个地址是 0x0800 0004,存放的是 Reset_Handler 中断函数入口地址。这里也说明函数其实就是一个地址。这里截图不完整,在ST公司的参考手册9.1.2中断和异常向量中有完整的向量表。
122-124行是计算范围
126行是定义一个段命为.text,只读的代码段,在 CODE 区。
129行之后就是程序的实现了
第一个就是Reset_Handler
两个函数均来自外部的文件。
133 行 LDR 表示从存储器中加载字到一个存储器中。SystemInit 是一个标准的库函数,
在 system_stm32f1xx.c 文件中定义,主要作用是配置系统时钟、还有就是初始化 FSMC/FMC
总线上外挂的 SRAM(可选),前面说配置外部 SRAM 作为数据存储器(可选)就是这个。
134 行 BLX 表示跳转到由寄存器给出的地址,并根据寄存器的 LSE 确定处理器的状态,
还要把跳转前的下条指令地址保存到 LR。
135 行把__main 的地址给 R0。__main 是一个标准的 C 库函数,主要作用是初始化用
户堆栈和变量等,最终调用 main 函数去到 C 的世界。这就是为什么我们写的程序都有一
个 main 函数的原因,如果不调用__main,那么程序最终就不会调用我们 C 文件里面的
main,也就无法正常运行。__main和main不是一个东西
136 行 BX 表示跳转到由寄存器/标号给出的地址,不用返回。这里表示切换到__main
地址,最终调用 main 函数,不返回,进入 C 的世界。
137 行 ENDP 表示子程序结束
都有WEAK声明。所以真正的中断服务函数需要我们在外部实现。