微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > 寄存器物理地址映射到结构体封装的寄存器的过程

寄存器物理地址映射到结构体封装的寄存器的过程

时间:11-26 来源:互联网 点击:
一、 STM32头文件中 结构体封装寄存器的方式

typedef struct
{
vu32 CR;
vu32 CFGR;
vu32 CIR;
vu32 APB2RSTR;
vu32 APB1RSTR;
vu32 AHBENR;
vu32 APB2ENR;
vu32 APB1ENR;
vu32 BDCR;
vu32 CSR;
} RCC_TypeDef;

#define PERIPH_BASE((u32)0x40000000)

#define AHBPERIPH_BASE(PERIPH_BASE + 0x20000)

#define RCC_BASE(AHBPERIPH_BASE + 0x1000)

#define RCC((RCC_TypeDef *) RCC_BASE)

在头文件中这样定义后,就可以在程序中以

RCC->CR|=0x00010000;来直接操作某一寄存器了。

二、对这一方式的分析与总结也就是关于单片机寄存器封装问题:

最近在学习嵌入式linux过程中,看到 DM368寄存器地址映射到结构体封装的寄存器的系统文件。因为嵌入式linux开发没有像单片机一样的编译软件,系统文件不是编译软件本身自带的。嵌入式编程需要自己找到需要用的模块的头文件,来操作相应的寄存器,编写相应的驱动。于是乎,在看别人的程序时,迷迷糊糊的就从主程序看到了驱动程序,又看到了底层操作寄存器的程。为了彻底搞懂嵌入式程序,终于注意到了以前单片机编程时没怎么注意过的结构体封装寄存器,映射物理地址。看了好半天也没有看明白 宏定义是如何映射地址的,关键是这样语法的一句话:

#define RCC((RCC_TypeDef *) RCC_BASE)

RCC_BASE的定义是 #define RCC_BASE(AHBPERIPH_BASE + 0x1000)  是物理地址经过代换(AHBPERIPH_BASE + 0x1000)=0x40021000

经过思索和讨教,对这种封装寄存器的来龙去脉终于恍然大悟。

首先,碰到#define一定要牢记C语言老师的教诲--‘仅仅是替换’。因此在使用结构体封装的寄存器来操作寄存器时,如RCC->CR =0x00实际上等价于 ((RCC_TypeDef *) RCC_BASE)->CR=0x00。 进一步,将RCC_BASE替换为 (AHBPERIPH_BASE + 0x1000) ,这里AHBPERIPH_BASE是地址,也是常量。于是整句话就被还原为 ((RCC_TypeDef *)0x40021000)->CR=0x00 。

也就是 先对地址常量 (AHBPERIPH_BASE + 0x1000) 进行强制类型转换为 (RCC_TypeDef )类型的结构体指针。由结构体指针的相关知识可知,将一个地址指向结构体,那么该地址后面的地址会自动按结构体中定义的结构体成员来划分。所以 ,作为该结构体的第一个成员CR,((RCC_TypeDef *)0x40021000)->CR也就是代表 (AHBPERIPH_BASE + 0x1000) 。 以此类推 ,,((RCC_TypeDef *)0x40021000)->CFGR 则代表

RCC_BASE(0x40021000)的下一段地址 即0x40021004 (手册中 RCC_CFGR寄存器的地址)

可以看到这种结构体封装寄存器方式访问寄存器的实质仍然是直接对寄存器所在的物理地址操作!!

至于为什么用这种方式来封装结构体。可以参考51单片机寄存器的定义方式。keil中51单片机每一个寄存器是直接给出对应的存储器地址,而没有用这种结构体方式封装。因为操作寄存器的实质永远都是对寄存器所在的地址操作。 STM32 中寄存器很多,如果像51一样 对每一个寄存器地址给定一个寄存器名称,太繁杂而且没有直观性。结构体封装,可以直观的看出每个模块中有哪些寄存器,方便编程。

图:keil中51寄存器的定义方式

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top