存储映射
stm32f40xx的存储映射图
这幅图很重要,至于为什么,我还没编好。
![在这里插入图片描述](https://img-blog.csdnimg.cn/596383ec2b0843deb983f17d3b5fd21d.png)
STM32存储空间有多大?
芯片能访问的存储空间有多大?为什么?
这个是由芯片内 CPU 的地址总线的数量决来定的,STM32 芯片内部的地址总线为32 根,1根地址线,可以传输的地址为0和1,那么理论上就可以访问2个字节。2根地址线,可以传输地址为00、01、10、11,理论上可以访问 4 个字节。32根地址线可以访问2^32个地址,理论上可以访问4G字节的存储器空间。
但是平时我们用的单片机真的会有4G那么大的存储空间么?
答案当然不是。一个小小的单片机怎么可能有4GB的存储空间!,这个4GB的是STM32理论分配的地址空间。也就是说实际上并不是有这么大的存储单元。可以看到有很多预留的地址,这些地址并没有给他分配存储单元。
所有的存储器都是与地址线连着的,但是实际上如果你只接了一个 1M 的存储器,而且是从0地址开始映射的,那么32 根地址线所产生的0~1M 的地址信号其实才是有意义的,因为这些地址信号才有对应真实的存储器,而所产生的1M 以上地址信号其实并无意义,因为并不对应真实的存储器。
STM32中的32是32根地址线的意思吗?
STM32是32位单片机,每次处理数据都是32bit的形式,所以stm32位带操作把寄存器的某个bit膨胀为32位就是为了能够快速进行操作。
STM32 内部的寄存器大小也都是 32 位的,刚好等于位宽。
某个芯片是 32 位的,但是它的地址线完全可以只有 16 根、或者 8 根。
什么是存储器映射
STM32的所有片上外设其实都可以看作寄存器,所以所有的这些存储器都需要被映射,只是理论上的4G范围远远大与实际的存储器空间,也就说实际的存储器空间并没有4G。很多都是reserved。
存储器本身没有地址,给存储器分配地址的过程叫存储器映射。
在存储器Block2这块区域,也就是地址从0x4000000—0x5FFFFFF这块区域,这是片上外设对应的区域,以四个字节为一个单元,共32bit,一般来说STM32描述外设的寄存器是32bit的。
我们用c语言设定这些寄存器的值,就可以控制这些单元时就可以驱动外设工作。链接: 操作寄存器
启动时的地址重映射
单片机的自举就是单片机的启动,我们说,单片机程序基本都是从0地址出开始运行的,F429的0x00000000-0x001FFFFF地址映射了到什么存储器上,那么就从该存储器上读取指令,开始运行。
至于说0x00000000-0x001FFFFF到底映射在了什么存储器上,这个要看F429 芯片 BOOT1、BOOT0这两个引脚的电平值,说白了就是,通过BOOT1和BOOT0 引脚的电平值,可以选择将0x00000000-0x001FFFFF映射到不同的存储器上。
![在这里插入图片描述](https://img-blog.csdnimg.cn/82456d692895471ebb6608e6ed007328.png)
但是我们可以看到 无论哪种方式好像都需要将启动这部分地址(1MB)映射到不同的位置。
STM32片内的FLASH分成两部分:主存储块、信息块。主存储块(主Flash)用于存储程序,我们写的程序一般存储在这里。信息块又分成两部分:系统存储器(系统FLASH)、选项字节。系统存储器存储用于存放在系统存储器自举模式下的启动程序(BootLoader),当使用ISP方式加载程序时,就是由这个程序执行。这个区域由芯片厂写入BootLoader,然后锁死,用户是无法改变这个区域的。选项字节存储芯片的配置信息及对主存储块的保护信息。
![在这里插入图片描述](https://img-blog.csdnimg.cn/fc28d63907e64bb0bebeeb3ca6e81344.png)
如果是选择从主Flash启动,那么在调试或者下载的时候会把代码下载到0x08000000-0x081F FFFF这个实际地址,而CPU运行时**,会把0x00000000-0x001F FFFF对应的地址指向实际的主Flash。**
疑问:下载时,能不能使用 0x0000 0000 地址来下载?
答:这个不行,因为下载时还没有使用boot引脚进行选择,0x0000 0000 - 0x001F FFFF 还没有被重映射到flash上,只能使用 0x0800 0000来下载。
ARM芯片的地址重映射解释
个人理解:把地址理解为指针,就是重新把这个指针指向别的实际位置。
也就是输入一个地址,经过设置后,地址解释器把它指向了别的物理地址。比如设置BOOT的主Flash模式,输入0x0000 0000地址解释器解释成0x0800 0000。
普通单片机如下图所示,输入量是地址,输出的是对应地址上存储的数据,中间方式暂且不论,可以理解为,输入一个地址,存储器会给我们一个数据。![在这里插入图片描述](https://img-blog.csdnimg.cn/40d7b115d42240d3a6d37e17bb7382ba.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/6cd6335accce458ab639e1e145df0cb2.png)
ARM芯片与普通单片机在存储器地址方面的不同在于:ARM芯片中有些物理存储单元的地址可以根据设置变换。就是说一个物理存储单元现在对应一个地址,经过设置以后,这个存储单元就对应了另外一个地址了。
![在这里插入图片描述](https://img-blog.csdnimg.cn/81a589bcd14e4e2fad6576e7ccd70660.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/dcb7003202c14c9ca374251fe36a3dbc.png)
特别的一种提高代码执行效率的方式
通过改变地址映射提高代码效率
![在这里插入图片描述](https://img-blog.csdnimg.cn/7041a807c5ed455ca6a9ccff4097f1ca.png)
上图是ARM芯片的另外一种映射方式。这个映射是通过修改startup.s启动文件进行的。目的是提高应用程序异常相应的速度。当我们把应用程序存放在片内FLASH的时候,异常向量表存放在0x00000000-0x0000 003f。每次发生异常,CPU从0x00000000~0x0000003F地址上取异常向量。
步骤 1:
先把0x00000000-0x0000003F(FLASH)存储单元内的异常向量表复制 到0x40000000~0x4000003F(片内RAM的最低端64个字节的存储单元)范围内存储单元中。
步骤 2:
把0x40000000-0x4000003F范围内存储单元地址重新映射到0x00000000-0x0000003F地址范围。 这样做了以后,当异常发生的时候,CPU取异常向量就是从RAM区中的异常向量表中区,速度快了。
这时如果复位中断发生,CPU从地址0x00000000取指令,但此时由于已经过地址重新映射,这个0x00000000被地址转换器转换成0x40000000,CPU实际上是取的RAM区中0x400000000这个存储单元内的指令(异常向量)。 当然用户可以不进行这种映射。片内FLASH中0x00000000~0x0000003F存储单元具有一模一样的异常向量表。只不过不进行这种处理,异常相应速度慢一点。但是这种速度上的差别很多情况下是不必要在意的。
具体如何修改,再议。