图2 STM32芯片存储器映射
注1
STM32中,I-Code Bus与D-Code Bus默认映射到0x00000000 ~ 0x1FFFFFFF内存地址段;AHB系统总线默认映射到0x20000000 ~ 0xDFFFFFFF和0xE0100000 ~ 0xFFFFFFFF两个内存地址段;APB外设总线默认映射到0xE0040000 ~ 0xE00FFFFF内存地址段,但由于TPIU、ETM以及ROM表占用部分空间,实际可用地址区间为0xE0042000~0xE00FF000
二、寄存器映射
寄存器映射是在存储器映射的基础上进行的。
以STM32为例,操作硬件本质上就是操作寄存器。在存储器片上外设区域,四字节为一个单元,每个单元对应不同的功能。当我们控制这些单元时就可以驱动外设工作,我们可以找到每个单元的起始地址,然后通过C 语言指针的操作方式来访问这些单元。但若每次都是通过这种方式访问地址,不好记忆且易出错。这时我们可以根据每个单元功能的不同,以功能为名给这个内存单元取一个别名,这个别名实质上就是寄存器名字。给已分配好地址(通过存储器映射实现)的有特定功能的内存单元取别名的过程就叫寄存器映射。
图3 寄存器映射
下面以GPIO寄存器CRL为例,先给出CRL定义如下:
typedef struct
{
__IO uint32\_t CRL;
__IO uint32\_t CRH;
__IO uint32\_t IDR;
__IO uint32\_t ODR;
__IO uint32\_t BSRR;
__IO uint32\_t BRR;
__IO uint32\_t LCKR;
} GPIO_TypeDef;
在实际使用时,会有GPIOA->CRL=0x0000 0000这种写法,表示将16进制数0赋值给GPIOA的CRL寄存器所在的存储单元。而GPIOA->CRL就构造了一个寄存器映射。具体过程如下:
#define PERIPH_BASE ((uint32_t)0x40000000)
这里属于存储器级别的映射,将外设基地址映射到0x40000000,可对应图2
#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)
这里对外设基地址进行偏移量为0x10000的地址偏移,偏移到APB2总线对应外设区。
#define GPIOA_BASE (APB2PERIPH_BASE + 0x0800)
这里对APB2外设基地址进行偏移量为0x0800的地址偏移,偏移到GPIOA对应区域。
#define GPIOA ((GPIO_TypeDef \*) GPIOA_BASE)
这里将GPIOA宏定义为GPIOA基地址经过强制类型转换为GPIO_TypeDef的指针,这样的作用是使GPIOA结构体内对应的成员按顺序填充内存区域,如图3所示。因此GPIOA的CRL寄存器就是作为GPIOA基地址后的第一个内存块,GPIOA->CRL的本质就是这个内存块的地址,或者说是用GPIOA->CRL给这个地址取了个形象的别名,即寄存器映射。
🔥 更多精彩专栏:
收集整理了一份《2024年最新物联网嵌入式全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升的朋友。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人
都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!