STM32完全学习——存储器映像
一、STM32存储器映像
1、STM32是32位的CPU,数据总线是32位的,地址总线也是32位的。两个可以不一样,也可以一样,可以访问的地址容量的4GB(2^32Byte),STM32是内存与IO统一编址的。
2、STM32的实际地址安排:
0X0000 0000——0X0800 0000 128MB 映射区 ,映射到闪存或系统内存,取决于引导引脚
0X0800 0000——0X0801 FFFF 128KB Flash memory 主存储块(用户闪存存储器)
0X1FFF F000——0X1FFF F7FF 2KB System memery 系统存储器
0X1FFF F800——0X1FFF F80F 16Byte Option Bytes 选择字节
二、STM32位带(bit-band)操作
将别名存储器区的字,映射到位带存储区的位。在别名存储区写入一个字具有对位带的目标执行读-改-写操作的相同效果,在STM32F10x里,外设寄存器和SRAM都被映射到一个位带区里。也就是说,我们现在有一个外设的寄存器,它里面有32位,我们如果要改其中的某一位,就必须将32位,都读出来,然后改完这一位,在写回去。这是因为STM32并不支持按位操作,因此现在的位带操作就相当,将这个寄存器的32位的每一位,都映射到一个32位的寄存器里面,也就相当于以前一个寄存器只占1个字,现在映射完之后,每个寄存器都会映射到32个寄存器里面,当我们想要改寄存器中的某一位时,我们只需要对他的映射区的32位,全部写入1或者0,就达到了修改这一位的目的,这样我们就省略了一些步骤,提高了程序的运行效率。虽然这样操作使占的空间大了,但是对于我们想要按位来操作寄存器明显更加的方便了。
下面的映射公式给出了别名区中的每个字是如何对应到位带区的相应位的:
下面对上面的公式符号进行进一步说明:左边就是寄存器中的某一位映射之后的地址,bit_band_base就是这个寄存器也就是这个外设对应的起始地址,byte_offset就是这个外设对应的地址的偏移量,bit_number就是想要映射的这一位在第几位。因为STM32中每一个地址对应的是8个bit,也就是说,每个32位的其实地址和下一个32位的起始地址差4,这也就是bit_number乘4的原因,又因为每个寄存器有32位,因此这里给偏移量要乘以32.下面我们以GPIOA作为例子来进行计算:
GPIOA的GPIOA_CRL寄存器的地址 | 这个寄存器映射后每一位对应的地址 |
0X4001 0800 | 偏移量是800+寄存器的偏移地址, 这个寄存器的偏移地址是0x00 |
bit0 的计算公式 0X4002 0000 = 0X4001 0000 + 0X800 * 32 + 0 * 4 | |
bit0 | 0X4002 0000 |
bit1 | 0X4002 0004 |
bit2 | 0X4002 0008 |
bit3 | 0X4002 000C |
bit4 | 0X4002 0010 |
bit5 | 0X4002 0014 |
bit6 | 0X4002 0018 |
bit7 | 0X4002 001C |
bit8 | 0X4002 0020 |
bit9 | 0X4002 0024 |
bit10 | 0X4002 0028 |
bit11 | 0X4002 002C |
bit12 | 0X4002 0030 |
bit13 | 0X4002 0034 |
bit14 | 0X4002 0038 |
bit15 | 0X4002 003C |
bit16 | 0X4002 0040 |
bit17 | 0X4002 0044 |
bit18 | 0X4002 0048 |
bit19 | 0X4002 004C |
bit20 | 0X4002 0050 |
bit21 | 0X4002 0054 |
bit22 | 0X4002 0058 |
bit23 | 0X4002 005C |
bit24 | 0X4002 0060 |
bit25 | 0X4002 0064 |
bit26 | 0X4002 0068 |
bit27 | 0X4002 006C |
bit28 | 0X4002 0070 |
bit29 | 0X4002 0074 |
bit30 | 0X4002 0078 |
bit31 | 0X4002 007C |
下面我们再来计算他相邻的一个寄存器
GPIOA的GPIOA_CRH寄存器的地址 | 这个寄存器映射后每一位对应的地址 |
0X4001 0800 | 偏移量是800+寄存器的偏移地址, 这个寄存器的偏移地址是0x04 |
bit0 | 0X4002 0080 |
bit1 | 0X4002 0084 |
bit2 | 0X4002 0088 |
bit3 | 0X4002 008C |
bit4 | 0X4002 0090 |
bit5 | 0X4002 0094 |
bit6 | 0X4002 0098 |
bit7 | 0X4002 009C |
bit8 | 0X4002 00A0 |
bit9 | 0X4002 00A4 |
bit10 | 0X4002 00A8 |
bit11 | 0X4002 00AC |
bit12 | 0X4002 00B0 |
bit13 | 0X4002 00B4 |
bit14 | 0X4002 00B8 |
bit15 | 0X4002 00BC |
bit16 | 0X4002 00C0 |
bit17 | 0X4002 00C4 |
bit18 | 0X4002 00C8 |
bit19 | 0X4002 00CC |
bit20 | 0X4002 00D0 |
bit21 | 0X4002 00D4 |
bit22 | 0X4002 00D8 |
bit23 | 0X4002 00DC |
bit24 | 0X4002 00E0 |
bit25 | 0X4002 00E4 |
bit26 | 0X4002 00E8 |
bit27 | 0X4002 00EC |
bit28 | 0X4002 00F0 |
bit29 | 0X4002 00F4 |
bit30 | 0X4002 00F8 |
bit31 | 0X4002 00FC |
我们通过观察这两个寄存器映射到位带区的地址可以发现,他们这些相邻的寄存器和寄存器里面相邻的位,在位带区里面也都是相邻的,你理解了,这里就能帮助你理解那个公式,因为他要做到一一映射,因为里面相当于有两个变量一个是不同的寄存器得映射到不同的位置,另一个变量是同一个寄存器的不同位要映射到不同的位置,就相当于有两个变量,那为什么偏移量要乘以32呢?这是因为每一个寄存器都有32位。由于每个寄存器的偏移量是加4,因此每次给偏移量乘以32,就会产生一个4*32大小的一块地址,然后由于每个字都要占4个地址,因此这块空间刚好可以放下32位中的每个bit,那为什么每一个不同的bit位要乘以4呢,这是因为每一个地址加1,只能岔开8个bit的大小,而一个位要占32个bit因此地址就得乘以4。这样才不会重合。地址是按字节进行编址的。地址每加1,偏移的大小就是一个字节。要想产生4个字节,地址的偏移量就是4。
三、STM32的启动模式
(1)用户闪存存储器是给我们设计用来放置用户写的代码,我们烧录程序就是烧录到了这里,正常状态下STM32从这里启动
(2)系统存储器区在非常规情况下使用,用来实现ISP功能的。
(3)内嵌SRAM区,这种也是非常规的,用来实现调试器调试功能的。
四、ISP和IAP
(1)ISP就是in-system programming (在系统烧录,在系统编程),就是现在我们使用的这种烧录的方法。一般ISP都是PC机通过串口吧bin文件直接isp到单片机内部flash中
(2)IAP就是in-application programming(在应用编程,在应用烧录,在线升级),IAP的核心是用户需要在自己的应用程序中去操作单片机内部flash的控制器和寄存器,实现对内部flash的烧录功能,然后IAP的时候用户程序通过串口(usb,网络)来接收PC发送过来的bin/hex文件,然后将之烧录到内部的falsh中去完成IAP。完成后再次启动后就会从用户存储器区执行,更新就会起效果。一般实现IAP需要人为的将用户存储器分为2部分:bootloader+app将IAP的功能放到bootloader中,用户需要更新的代码放到app中就可以啦。