设计知识点补充在前:
1.关于存储器映射、存储器重映射、内存映射、地址映射、地址转换等计算机专业名词详解
参考见 关于存储器映射、存储器重映射、内存映射、地址映射、地址转换等计算机专业名词详解_Vincent_Song的博客-CSDN博客
2.哈佛结构和冯诺依曼结构的区别
一、存储器结构不同
- 冯·诺依曼结构:冯·诺依曼结构又称作普林斯顿体系结构,冯·诺依曼结构是一种将程序指令存储器和数据存储器合并在一起的存储器结构。
- 哈佛结构: 哈佛结构是一种将程序指令存储和数据存储分开的存储器结构,使用两个独立的存储器模块,分别存储指令和数据,每个存储模块都不允许指令和数据并存。
二、总线不同
- 冯·诺依曼结构:冯·诺依曼结构没有总线,CPU与存储器直接关联。
- 哈佛结构:哈佛结构使用独立芹燃好的两条总线,分别作为CPU与每个存储器之间的专用通信路径,而这两条总线之间毫无关联。
三、执行效率不同
- 冯·诺依曼结构:冯·诺依曼结构其程序指令和数据指令执行时不可以预先读取下一条指令,需要依次读取,执行效率较低。
- 哈佛结构:哈佛结构其程序指令和数据指令执行时可以预先读取下一条指令,具有较高的执行效率。
具体区别可参考冯诺依曼与哈佛结构的区别_哈弗结构与冯诺依曼结构的区别_时光小渣渣的博客-CSDN博客
STM32采用了哈佛结构。
在编译的过程中,编译工具链会将所有用户编写的代码转换成计算机可以识别的指令
1.具体流程
MCU芯片上电以后会触发复位异常,并且会跳转到中断向量表特定的偏移位置,获取里面的内容进行执行。(触发异常->中断向量表->用户程序)
具体:
- MCU芯片上电以后会触发复位异常,会去一个叫做中断向量表的地方,一般在存储器的0地址位置。找到中断向量表后,处理器会根据触发的异常\中断类型进行一定的位置偏移(0x04),获取里面的内容进行执行。
- 我们修改复位异常(即复位中断处理函数)里面的内容,就可以让处理器去执行我们指定的操作。
2、启动配置中断向量表
硬件电路(以野火STM32F103ZET6为例),我们可以配置BOOT引脚的不同电平来选择开发板的启动状态
总结如下
- 系统复位后,STM32内核会从STM32地址空间的0x0地址获取中断向量表。但我们可以通过不同的映射,如将FLASH和系统存储器在STM32地址空间的位置映射到0x0地址位置,这样系统就会从FLASH存储器或者系统存储器自身的起始位置来访问到中断向量表。通过映射机制我们就可以将中断向量表放在FLASH里或者系统存储器里。
3.在STM32启动文件中分析启动步骤
从描述中可知启动过程为:
(1)设置堆栈指针
(2)设置PC指针的值(指向当前运行的指令增加8的位置,具体可查看arm体系架构,参考《arm cortex-M3权威指南》)
(3)配置中断向量表的入口
(4)配置系统时钟
(5)调用C库函数__main,从而初始化堆栈,最终会跳转我们自己编写的main函数中
下面我们就从启动文件的代码中分析启动过程
- 首先分配堆栈大小和设置堆栈指针
- 然后将中断向量表位置映射到0x00并分配空间,其中起始位置为堆栈顶的地址
其中DCD会为指定中断\异常分配一个字(4Byte)的空间
在启动之后, CPU从地址0x0000 0000获取堆栈顶的地址,并从启动 存储器的0x0000 0004(Reset_Handler)指示的地址开始执行代码。
- 接着也是最后来到Reset_Handler函数
- 先将Reset_Handler函数导出,后面的[WEAK]弱定义代表用户可以自己重新定义Reset_Handler函数,且优先调用
- 然后导入__main和SystemInit函数
- 最后就分别进入SystemInit函数里配置系统时钟和进入__main中最终调用我们自己定义的main函数了
我们点击跳转到SystemInit,会发现跳转到了C源文件里的SystemInit函数里
为什么会跳转到SystemInit函数里,这是因为在之前第一步以及初始化好堆栈了,这样C语言的运行环境搭建完成,此时STM32已经装载好了栈指针,可以进行C语言的函数跳转了
关于__main和SystemInit函数的具体内容就不介绍了,SystemInit的介绍可以通过system_stm32fxx.c查看,__main的介绍可以查看帮助文档