单片机的本质是在操作寄存器
下图为stm32f4的总线矩阵(STM32F4x7-Datasheet的第19页),其中主控总线有8条,被控总线有7条,主设备和从设备通过各自的总线两两相交连接,图中两条总线相交且为圆圈的地方,表示这两条总线对应的主设备可以访问从设备,如I总线(指令总线),只有跟 M0、M2和M6这三根被控总线交叉的时候才有圆圈,就表示I总线只能跟这三根被控总线通信,这样就可以知道stm32f4的启动有三种分别是FLASH、内部SRAM、外部存储FSMC。
总线矩阵用于主控总线之间的访问仲裁管理,仲裁采用循环调度算法。有了总线矩阵,就可以让主设备和从设备进行并行访问,提升了访问效率,同时也降低了功耗。需要注意的是,虽然总线矩阵使得多个主设备可以并行访问不同的从设备,但在一个定义的时间段内,只有一个主设备拥有总线矩阵的控制权,如果有多个主设备同时出现总线请求时就得进行仲裁。所以有了总线仲裁器,就能保证每个时刻只有一个主设备通过总线矩阵对从设备进行访问。
注意并非所有主设备访问从设备都得经过总线矩阵,如上图中,有些主设备和从设备间有直通通道。

内部 Flash ICode 总线
Flash:写好的程序编译之后都是一条条指令(二进制代码)和常量或常变量存放在FLASH
内部 Flash DCode 总线
主要内部 SRAM1 (112 KB)
内部SRAM:常说的电脑内存条,程序函数内部的局部变量和全局变量,堆(malloc分配)栈(局部变量)等的开销都是基于内部的SRAM。内核通过 DCode 总线来访问它
辅助内部 SRAM2 (16 KB)
AHB1 外设(包括 AHB-APB 总线桥和 APB 外设)
两个AHB/APB桥在AHB和2个APB总线间提供同步连接。APB1操作速度限于42MHz,APB2操作于全速(最高84MHz),上面挂载着 STM32 各种各样的特色外设。我们经常说的 GPIO、串口、I2C、SPI 这些外设就挂载在这两条总线上,这个是我们学习 STM32 的重点,就是要学会编程这些外设去驱动外部的各种设备。
AHB2 外设
FSMC(Flexible static memory controller)
FSMC是灵活的静的存储器控制器,通过FSMC我们可以扩展内存,如外部的SRAM,NANDFLASH 和 NORFLASH。但有一点要注意的是,FSMC 只能扩展静态的内存,即名称里面的 S:static,不能是动态的内存,比如 SDRAM 就不能扩展。

1、ICode、DCode、System
2、FLASH连接总线
3、SRAM 连接总线
4、高速外设连接总线 AHB1/AHB2/AHB3
5、连接“桥”的总线
这些“高速总线”直接与“总线矩阵”连接在一起,其实这些高速总线实际上就是“总线矩阵”的延伸,或者说就是总线矩阵的一部分。
我们这里说“片内外设”时,暂都不包含 ROM(FLASH)和 SRAM。
高速外设
由于高速外设实在是太多了,一个总线不够,所以分了三个,分别是 AHB1/AHB2/AHB3,所有“高速外设”寄存器组分批挂接在 AHB1/AHB2/AHB3 上。
低速外设
“低速外设”的速度比较低,不能直接挂在“总线矩阵”上,所以先经过“桥”后再引出“低速总线”,挂在低速总线上。由于“低速外设”比较多,所以就分了两个低速总线,分别是 APB1/APB2,所有的“低速外
设”分批挂接在 APB1/APB2 上。
芯片内CPU的地址总线决定芯片能访问的存储空间大小,Cortex-M4的地址总线32根
1根地址线:可传输的地址为0和1,理论上可以访问2个字节
2根地址线:可以传输地址为 00、01、10、11,理论上可以访问 4 个字节
3 个地址线:可以传输的地址为 000、001、010、011、100、101、110、111,理论上可以访问 8 个字节。
32 根地址线:可以产生 00000000 00000000 00000000 00000000、…、11111111 11111111 11111111 11111111的 232个地址,范围刚好为 4G,所以我们就说Cortex-M4的32 根地址线,理论上可以访问4G字节的存储器空间。Cortex-M4地址是从0x0000 0000到0xFFFF FFFF,这就是4GB的存储空间。
32根地址线可以传输4G个地址信号,每个地址信号访问一个字节,4G地址信号则可以访问4G个字节,所以理论上的可访问范围为4G
插入一个64位系统的小知识
64位系统使用64位地址线的最大寻址空间为2的64次方bytes,计算后其可寻址空间达到了18446744073709551616 Bytes,即16384PB(PebiByte)或16777216TB(TebiByte)。但是,很多64位CPU使用40位地址线,最大寻址空间仅为1TB,加之别的种种原因,目前Windows 7 64位版最大仅能使用192GB内存,Windows 8 64位版最大仅能使用512GB内存。不过尽管系统所能支持的内存有这么大,但主板和CPU的限制导致一般的电脑所支持的内存最大只有16GB而已。
被控单元的FLASH,RAM和各类片上外设,这些功能部件共同排列在一个 4GB 的地址空间内,每个外设都有自己独有地址。我们在编程的时候,可以通过他们的地址找到他们,然后来操作他们
存储器本身没有地址,给存储器分配地址的过程叫存储器映射

STM32F407细分了Cortex-M4存储器映射,具体如下面两张图所示

下图是STM32F4x7-Datasheet的第54页

在 block 0 中我们看到除了Flash用来存储代码以外还有很多别的东西,比如Boot pins用来控制开机、System memory等。
在 block 1 中我们 512MB 的 SRAM 其实真正使用的也只有 128KB。
在 block 2 中是外设,也是我们最需要深入学习的部分之一,起始地址是 0x4000 0000。细看我们没有找到具体外设,看到的却是APB1、APB2、AHB1、AHB2、AHB3等。这是因为外设实在太多了,我们需要根据不同需求进行分装,具体的内容可以看下图(STM32F4x7-Datasheet的第16页)

在存储器 block 2 这块区域,也就是地址从0x4000 000—0x5FFF FFF这块区域,设计的是片上外设,它们以四个字节为一个单元,共32bit,每一个单元对应不同的功能,当我们控制这些单元时就可以驱动外设工作。可以找到每个单元的起始地址,然后通过C语言指针的操作方式来访问这些单元,如果每次都是通过这种地址的方式来访问,不仅不好记忆还容易出错,这时我们可以根据每个单元功能的不同,以功能为名给这个内存单元取一个别名,这个别名就是我们经常说的寄存器,这个给已经分配好地址的有特定功能的内存单元取别名的过程就叫寄存器映射。

访问方法1

访问方法2
我们访问GPIOA的控制寄存器组时、直接使用宏定义好 GPIO_TypeDef 类型的指针,而且指针指向 GPIOA端口的首地址,这样我们直接用宏GPIOA访问改外设的任意一个寄存器。(stm32f407xx.h”已经封装了所有的外设)
typedef struct {
uint32_t MODER; /*Address offset: 0x00 */
uint32_t OTYPER; /*Address offset: 0x04 */
uint32_t OSPEEDR; /*Address offset: 0x08 */
uint32_t PUPDR; /*Address offset: 0x0C */
uint32_t IDR; /*Address offset: 0x10 */
uint32_t ODR; /*Address offset: 0x14 */
uint32_t BSRR; /*Address offset: 0x18 */
uint32_t LCKR; /*Address offset: 0x1C */
} GPIO_TypeDef;
#define GPIOA_BASE ( (unsigned int ) 0x40020000 )
#define GPIOA ((GPIO_TypeDef *) GPIOA_BASE)
GPIOA->MODER = 0x20 ;
GPIOA->OSPEEDR = 0x16 ;