寄存器映射
- 什么是寄存器
- 寄存器映射
- 寄存器映射的实现方法
- 寄存器地址计算
- 通过结构体完成寄存器映射
- 总结
上期我们复习了C语言的一些知识,现在我们来学习什么是寄存器映射
什么是寄存器
如果你有学习过51单片机,那么你一定对配寄存器这个环节相当熟悉了,那么,我们之前配了那么久的寄存器,到底什么是寄存器呢?
寄存器是CPU内部用来存放数据的一些小型存储区域,用来暂时存放参与运算的数据和运算结果,其本质也是一种存储器。
寄存器映射
给具有特殊功能的内存块的首地址取一个具有特殊意义名称的过程就叫做寄存器映射
对于我们的STM32单片机,它的总线宽度为32位,那么STM32的单片机寻址范围就是:2^32 = 4GB。但是我们知道:STM32的FLASH大小一般都会控制在几MB之内,而SRAM更是只有几百KB,远远达不到我们计算出来的4GB,这是为什么呢?
我们这里计算出来的4GB实际上是单片机的寻址范围,而不是其真实的物理内存,真正的内存还需要我们人为去分配。
如图所示的存储器,它具有19根地址线,地址的范围就是2^19 = 512k,我们可以将它映射到STM32的寻址范围内,使其成为STM32内部真实存在的物理地址。在这个过程中,映射的方法可以是多样的。 而对于没有进行映射的地址,在实际开发的过程中是无法访问的。
STM32存储器功能划分如下表
存储块 | 功能 | 地址 |
Block0 | Code(Flash) | 0x0000 0000 ~ 0x1FFF FFFF |
Block1 | SRAM | 0x2000 0000 ~ 0x3FFF FFFF |
Block 2 | 片上外设 | 0x4000 0000 ~ 0x5FFF FFFF |
Block3~Block5 | 保留 | 0x6000 0000 ~ 0xBFFF FFFF |
Block6 | 没用到 | 0xC000 0000 ~ 0xDFFF FFFF |
Block7 | Crotex M4 内核外设 | 0xE000 0000 ~ 0xFFFF FFFF |
这只是一个整体的划分,对于更加详细的内容,大家可以自行查阅参考手册。
寄存器映射的实现方法
前面我们介绍到寄存器其本质也是存储器,那么寄存器的映射方法也是一样的,而由于我们STM32中的寄存器是32位寄存器,恰好于数据总线的宽度一致,所以,对于每一个寄存器,在STM32单片机上都会有一个确定的地址。
那这么来计算这个地址呢?
寄存器地址计算
为了方便编写代码及使用,我们将寄存器地址分为三个部分:
1、总线基地址(BUS_BASE_ADDR)
2,外设基于总线基地址的偏移量(PERIPH_OFFSET)
3,寄存器相对外设基地址的偏移量(REG_OFFSET)
寄存器地址 = BUS_BASE_ADDR + PERIPH_OFFSET + REG_OFFSET
可能这样讲有点抽象,下面我来举个栗子,我们来找一下GPIOB_ODR寄存器的地址
通过查阅手册,我们GPIOB是挂载在AHB1总线上的,
再次查阅手册,得到AHB1总线基地址为0x4002 0000;
再次翻阅手册,发现GPIOB相对于AHB1的偏移量为0x0400
最后,继续翻阅手册,得到GPIOB_ODR相对于GPIOB的偏移量为0x14;
所以:
我们得到了GPIOB_ODR的地址为:0x4002 0000 + 0x0400 + 0x14 = 0x4002 0414
通过结构体完成寄存器映射
但如果我们每次需要对寄存器进行操作时,都来像这样查手册的话,我们开发的效率将会非常低下,通过使用结构体,可以很方便的实现对寄存器的映射:
typedef struct
{
__IO uint32_t MODER; /*!< GPIO port mode register, Address offset: 0x00 */
__IO uint32_t OTYPER; /*!< GPIO port output type register, Address offset: 0x04 */
__IO uint32_t OSPEEDR; /*!< GPIO port output speed register, Address offset: 0x08 */
__IO uint32_t PUPDR; /*!< GPIO port pull-up/pull-down register, Address offset: 0x0C */
__IO uint32_t IDR; /*!< GPIO port input data register, Address offset: 0x10 */
__IO uint32_t ODR; /*!< GPIO port output data register, Address offset: 0x14 */
__IO uint32_t BSRR; /*!< GPIO port bit set/reset register, Address offset: 0x18 */
__IO uint32_t LCKR; /*!< GPIO port configuration lock register, Address offset: 0x1C */
__IO uint32_t AFR[2]; /*!< GPIO alternate function registers, Address offset: 0x20-0x24 */
} GPIO_TypeDef;
#define PERIPH_BASE 0x40000000UL //
#define AHB1PERIPH_BASE (PERIPH_BASE + 0x00020000UL) //AHB1基地址
#define GPIOB_BASE (AHB1PERIPH_BASE + 0x0400UL)
#define GPIOB ((GPIO_TypeDef *) GPIOB_BASE) //将GPIOB的基地址转化为结构体指针,方便对GPIOB寄存器的操作。
这样,我们就实现了对STM32单片机GPIOB中每一个寄存器的映射,其他外设的寄存器也是采用这种方法映射的。
总结
下面是本期用到的资料图片,为了方便查阅,将其截图附上。
数据手册 53/149
数据手册 15/149