你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

MDK中寄存器地址名称映射分析

[复制链接]
雪泥鸿爪 发布时间:2017-12-26 23:11
本帖最后由 雪泥鸿爪 于 2017-12-26 23:31 编辑

转自:http://bbs.elecfans.com/jishu_467552_1_33.html
之所以要讲解这部分知识,是因为经常会遇到客户提到不明白MDK中那些结构体是怎么与寄存器地址对应起来的。这里我们就做一个简要的分析吧。
首先我们看看51中是怎么做的。51单片机开发中经常会引用一个reg51.h的头文件,下面我们看看他是怎么把名字和寄存器联系起来的:
  1. sfr P0 =0x80;
复制代码

sfr也是一种扩充数据类型,点用一个内存单元,值域为0~255。利用它可以访问51单片机内部的所有特殊功能寄存器。如用sfr P1 = 0x90这一句定义P1为P1端口在片内的寄存器。然后我们往地址为0x80的寄存器设值的方法是:
  1. P0=value;
复制代码

那么在STM32中,是否也可以这样做呢??
答案是肯定的。肯定也可以通过同样的方式来做,但是STM32因为寄存器太多太多,如果一一以这样的方式列出来,那要好大的篇幅,既不方便开发,也显得太杂乱无序的感觉。所以MDK采用的方式是通过结构体来将寄存器组织在一起。下面我们就讲解MDK是怎么把结构体和地址对应起来的,为什么我们修改结构体成员变量的值就可以达到操作对应寄存器的值。这些事情都是在stm32f10x.h文件中完成的。


我们通过GPIOA的几个寄存器的地址来讲解吧。 首先我们可以查看《STM32中文参考手册V10》中的寄存器地址映射表(P159)


从这个表我们可以看出,GPIOA的7个寄存器都是32位的,所以每个寄存器占有4个地址,一共占用28个地址,地址偏移范围为(000h~01Bh)。这个地址偏移是相对GPIOA的基地址而言的。GPIOA的基地址是怎么算出来的呢?因为GPIO都是挂载在APB2总线之上,所以它的基地址是由APB2总线的基地址+GPIOA在APB2总线上的偏移地址决定的。同理依次类推,我们便可以算出GPIOA基地址了。这里设计到总线的一些知识,我们在后面会讲到。下面我们打开stm32f10x.h定位到GPIO_TypeDef定义处:
  1. typedef struct
  2. {
  3.   __IO uint32_t CRL;
  4.   __IO uint32_t CRH;
  5.   __IO uint32_t IDR;
  6.   __IO uint32_t ODR;
  7.   __IO uint32_t BSRR;
  8.   __IO uint32_t BRR;
  9.   __IO uint32_t LCKR;
  10. } GPIO_TypeDef;
复制代码

然后定位到:
  1. #define     GPIOA                            ((GPIO_TypeDef *) GPIOA_BASE)
复制代码

可以看出,GPIOA是将GPIOA_BASE强制转换为GPIO_TypeDef指针,这句话的意思是,
GPIOA指向地址GPIOA_BASE,GPIOA_BASE存放的数据类型为GPIO_TypeDef。然后双
击“GPIOA_BASE”选中之后右键选中“Go to definition of ”,便可一查看GPIOA_BASE
的宏定义:
  1. #define GPIOA_BASE                       (APB2PERIPH_BASE + 0x0800)
复制代码

依次类推,可以找到最顶层:
  1. #define APB2PERIPH_BASE              (PERIPH_BASE + 0x10000)
  2. #define PERIPH_BASE                      ((uint32_t)0x40000000)  
复制代码

所以我们便可以算出GPIOA的基地址位:
  1. GPIOA_BASE= 0x40000000+0x10000+0x0800=0x40010800  
复制代码

   
下面我们再跟《STM32中文参考手册V10》比较一下看看GPIOA的基地址是不是
0x40010800。截图P28存储器映射表我们可以看到,GPIOA的起始地址也就是基地址确实
是0x40010800
同样的道理,我们可以推算出其他外设的基地址。
  上面我们已经知道GPIOA的基地址,那么那些GPIOA的7个寄存器的地址又是怎么算出来的呢??在上面我们讲过GPIOA的各个寄存器对于GPIOA基地址的偏移地址,所
以我们自然可以算出来每个寄存器的地址。
   
GPIOA的寄存器的地址=GPIOA基地址+寄存器相对GPIOA基地址的偏移值
这个偏移值在上面的寄存器地址映像表中可以查到。
  那么在结构体里面这些寄存器又是怎么与地址一一对应的呢?这里涉及到结构体成员
变量地址对齐方式方面的知识,这方面的知识大家可以在网上查看相关资料复习一下,这
里我们不做详细讲解。在我们定义好地址对齐方式之后,每个成员变量对应的地址就可以
根据其基地址来计算。对于结构体类型GPIO_TypeDef,他的所有成员变量都是32位,成
员变量地址具有连续性。所以自然而然我们就可以算出GPIOA指向的结构体成员变量对应
地址了。
寄存器  偏移地址  实际地址=基地址+偏移地址
  1. GPIOA->CRL  0x00  0x40010800+0x00
  2.   GPIOA->CRH;  0x04  0x40010800+0x04
  3. GPIOA->IDR;  0x08  0x40010800+0x08
  4. GPIOA->ODR  0x0c  0x40010800+0x0c
  5.   GPIOA->BSRR  0x10  0x40010800+0x10
  6. GPIOA->BRR  0x14  0x40010800+0x14
  7.   GPIOA->LCKR  0x18  0x40010800+0x18
复制代码

表4.6.3 GPIOA各寄存器实际地址表


我们可以把GPIO_TypeDef的定义中的成员变量的顺序和GPIOx寄存器地址映像对比可以发现,他们的顺序是一致的,如果不一致,就会导致地址混乱了。
这就是为什么固件库里面:GPIOA->BRR=value;就是设置地址为

0x40010800 +0x014(BRR偏移量)=0x40010814的寄存器BRR的值了。
它和51里面P0=value是设置地址为0x80的P0寄存器的值是一样的道理。

收藏 评论0 发布时间:2017-12-26 23:11

举报

0个回答

所属标签

STM32团队

意法半导体微控制器和微处理器拥有广泛的产品线,包含低成本的8位单片机和基于ARM® Cortex®-M0、M0+、M3、M4、M33、M7及A7内核并具备丰富外设选择的32位微控制器及微处理器


最新内容

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版