想要了解什么是寄存器只需要搞懂俩个问题就可以了,1、什么是存储器映射,2、什么是寄存器映射带着这俩个问题阅读本文章。
一、什么是存储器映射
在这张系统框图中的被驱动单元Flash、和ABH到APB的桥(片上外设)这些功能部件共同排列在一个4GB的地址空间中。我们在进行编程的时候,可以通过找到他们的地址找到他们,进行操作它们。
存储器本身不具备地址信息,它的地址是由芯片厂商或用户分配,给存储器分配地址的过程叫做存储器映射。
在这4GB的地址空间上,ARM公司已经把他平均分成了8个小块,每块512MB,每小块也规定了用途,512MB是很大了,芯片厂商在设计各种外设的时候一般都用不完,只用了其中一部分而已。
上图是STM32F1系列的存储器映射表下图是一个功能分类
序号 | 用途 | 地址范围 |
Block 0 | Code | 0x0000 0000 ~ 0x1FFF FFFF |
Block 1 | SRAM | 0x2000 0000 ~ 0x3FFF FFFF |
Block 2 | 片上外设 | 0x4000 0000 ~ 0x5FFF FFFF |
Block 3 | FSMC的bank1~bank2 | 0x6000 0000 ~ 0x7FFF FFFF |
Block 4 | FSMC的bank3~bank4 | 0x8000 0000 ~ 0x9FFF FFFF |
Block 5 | FSMC寄存器 | 0xA000 0000 ~ 0xBFFF FFFF |
Block 6 | 没有使用 | 0xC000 0000 ~ 0xDFFF FFFF |
Block 7 | Cortex-M3内部外设 | 0xE000 0000 ~ 0xFFFF FFFF |
这里我们只对相对重要的内部区域功能进行详解
1、存储器Block 0内部区域功能划分
区块 | 用途说明 | 地址范围 |
Block 0 | 预留 | 0x1FFE C008 ~ 0x1FFF FFFF |
选择字节:用于配置读写保护、BOR级别、软件/硬件看门狗以及器件处于待机或者停止模式下的复位。当芯片不小心被锁住后,可以从RAM里启动来修改这部分相应的寄存器位 | 0x1FFE F800 ~ 0x1FFF F80F | |
系统存储器:这里存储的是ST公司出厂时烧录好的isp自举程序(Boot Loader),用户无法改动。串口下载的时候需要用到这一部分程序 | 0x1FFE F000 ~ 0x1FFF F80F | |
预留 | 0x0808 F000 ~ 0x1FFF F7FF | |
Flash:程序存放处 | 0x0800 0000 ~ 0x0807 FFFF | |
预留 | 0x0008 0000 ~ 0x07FF FFFF | |
为Flash、系统存储器、SARM的别名 | 0x0000 0000 ~ 0x0007 FFFF |
Block 0主要用于设计片内的Flash,前面使用的STM32F103R6的Flash时512KB。属于大容量,想要在芯片上集成更大的Flash或者SRAM都意味着芯片成本的增加,往往片内集成的Flash都不会太大。
2 、存储器Block 1内部区域功能划分
Block 1用于设计片内的SRAM。
区块 | 用途说明 | 地址范围 |
Block 1 | 预留 | 0x2001 0000 ~ 0x3FFF FFFF |
SRAM(程序变量及堆栈) | 0x2000 0000 ~ 0x2000 FFFF |
3、存储器Block 2内部区域功能划分
Block 2用于设计片上外设,根据外设总线速度的不同,Block被分成了APB和AHB俩部分,其中APB又被分为APB1和APB2。
区块 | 用途说明 | 地址范围 |
Block 2 | APB1总线外设 | 0x4000 0000 ~ 0x4000 77FF |
APB2总线外设 | 0x4001 0000 ~ 0x4001 3FFF | |
AHB总线外设 | 0x4001 8000 ~ 0x5003 FFFF |
二、什么是寄存器
我们在前面说了这么多,铺垫这么多就是为了解释这一句话给有特定功能的内存单元取一个别名,这个别名就是我们经常说的寄存器。
三、寄存器映射
我们前面介绍到存储器本身没有地址,给存储器分配地址的过程叫做存储器映射。那么寄存器就是这个给已经分配好地址的有特定功能的内存单元 取别名的过程就叫寄存器映射。
我们前面介绍了外设会由厂商分配地址,我们通过查询STM32FXX手册 https://pan.baidu.com/s/1sk1_DSbL5ZV33I7zqzJEsg
提取码:pyj1
这我放了手册的链接,可以通过绝对地址来访问内存单元来配置外设,关注后面我会介绍如何通过手册来查询绝对地址和进行寄存器编程,不多说上代码。
*(unsigned int*)(0x4001 0800)=0xffff;
//GPIOA端口全部输出高电平
0x4001 0800在我们看来是GPIOA端口ODR(端口输出寄存器)的地址,但是在编译器看来,这只是一个普通的变量,所以我们要让编译器也要让它认为是一个指针也就是地址,我们就得进行强制类型转换,把它转换成指针既(unsigned int*)(0x4001 0x800),然后对这个指针进行解引用操作也就是*操作。
通过绝对地址访问内存单元的话不好记忆且容易出错,我们可以通过寄存器的方式来操作。也就是我们常说的寄存器编程。
#define GPIO_ODR *(unsigned int*)(0x4001 0800)
GPIOA_ODR = 0xff;
关注后面我会介绍如何通过手册来查询绝对地址和进行寄存器编程,后面还会有时钟篇和所有外设的编程详细介绍和编程。