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

位带操作

[复制链接]
mr.hs 提问时间:2015-1-10 14:22 /
位带操作  :即向别名区写0/1即向对应位写0/1

那么位带区地址对应的是那些寄存器呢?

收藏 评论4 发布时间:2015-1-10 14:22

举报

4个回答
回答时间:2015-1-10 15:28:41
用联合体定义,这个网上自己搜素用法吧.
莫问今生 回答时间:2015-1-10 15:28:44
??????????????
Angel_YY 回答时间:2018-3-12 14:49:19
在CM3中,有两个区中实现了位带。其中一个是 SRAM 区的最低 1MB 范围,第二个则是片内外设区的最低 1MB 范围。这两个区中的地址除了可以像普通的 RAM 一样使用外,它们还都有自己的“位带别名区”,位带别名区把每个比特膨胀成一个 32 位的字。当你通过位带别名区访问这些字时,就可以达到访问原始比特的目的。
在位带区中,每个比特都映射到别名地址区的一个字(这是只有 LSB 有效的字)。当一个别名地址被访问时,会先把该地址变换成位带地址。对于读操作,读取位带地址中的一个字,再把需要的位右移到 LSB,并把 LSB 返回。对于写操作,把需要写的位左移至对应的位序号处,然后执行一个原子的“读-改-写”过程。
支持位带操作的两个内存区的范围是:
0x2000_0000‐0x200F_FFFF(SRAM 区中的最低1MB)
0x4000_0000‐0x400F_FFFF(片上外设区中的最低 1MB)
位带(Bit-band)操作是Cortex-M3提供的特殊操作:位带区的每个位都有位带别名区的一个字与之对应。Bit-band区域的存储器以32位方式进行访问,其中有效的仅仅是BIT0位,只有BIT0的值才对应到相应的普通区域的比特位上,其他位无效。STM32F系列芯片为所有外设寄存器和SRAM提供相对应的Bit-band区域,以简化对外设寄存器和SRAM的操作位带操作最重要的一环就是寻址,即为需要操作的“目标位”找到位带别名区相对应的地址:
位带别名区首地址+(操作字节的偏移量*32) +(操作位的偏移量*4)
内置SRAM区的位带别名区首地址 = 0x2200,0000
外设寄存器区的位带别名区首地址 = 0x4200,0000
例如:GPIOA的端口输出数据寄存器地址0x4001080c(stm32f1xx系列),对于PA.0来说控制其输出电平的比特位的位带操作地址为:
0x42000000+(0x1080c*32)+(0*4) = 0x42021018

以stm32f207为例,介绍stm32的位带操作。
在《ARM Cortex M3权威指南》92页介绍了如何在C语言中使用位带操作。个人在使用位带操作过程中将其大致总结为三种:
①  查找需要定义的位所在的地址,将地址强制转换为指针,通过取指针内容的方式使用。
例如:
  1. #define PD12   ((volatile unsigned long *)(0x424182b0))  
  2. //0x424182b0为GPIOD_Pin12引脚对应的映射地址
  3. *PD12=0x01;                    //PD12引脚置高
复制代码
②  直接使用地址进行操作
  1.   (*((u32*)0x424182b0))=0x01;    //PD12引脚置高
复制代码
当然也可以通过如下定义使用
例如:
  1. #define PD12   *((volatile unsigned long *)(0x424182b0))
  2. //0x424182b0为GPIOD_Pin12引脚对应的映射地址
  3. PD12=0x01;                      //PD12引脚置高
复制代码
③在多个引脚需要定义时,显然上面两种方法都比较繁琐。为简化位带操作,也可以定义一些宏。比如,我们可以建立一个把“位带地址+位序号”换成别名地址的宏,再建立一个把别名地址转换成指针类型的宏。
例如
  1. #define GPIOD_ODR_Addr    ((uint32_t)(GPIOD_BASE+0x14))        // GPIOD_BASE已经定义过
  2. #define BITBAND(addr,bitnum)  ((addr&0xF0000000)+0x2000000+((addr&0xFFFFF)<<5)+(bitnum<<2))
  3. #define MEM_ADDR(addr)  (*((volatile unsigned long *)(addr)) )   
  4. #define BIT_ADDR(addr, bitnum)   MEM_ADDR( BITBAND(addr, bitnum) )
  5. #define PD12  BIT_ADDR(GPIOD_ODR_Addr, 12)  //12为GPIOD对应的引脚号
  6. #define PD12  BIT_ADDR(GPIOD_ODR_Addr, 13)  //13为GPIOD对应的引脚号
  7. PD12=0x01;                            //PD12引脚置高
  8. PD13=0x01;                            //PD13引脚置高
复制代码
说明:GPIOD_BASE已经在库文件stm32f2xx.h中定义过,直接使用即可,对应地址是GPIOD的基地址,0x14是ODR的偏移地址。第二条语句是把“位带地址+序号”转换为对应的位带别名区地址。第三条语句MEM_ADDR(addr)代表的是(addr)地址中的内容。volatile必须使用,原因如下。
volatile 是易变的、不稳定的意思。用它修饰的变量表示可以被某些编译器未知的因素更改,比如操作系统、硬件或者其它线程等。遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。
先看看下面的例子:
int i=10;
int j = i;//(1)语句
int k = i;//(2)语句
这时候编译器对代码进行优化,因为在(1)、(2)两条语句中,i 没有被用作左值。这时候编译器认为 i 的值没有发生改变,所以在(1)语句时从内存中取出 i 的值赋给 j 之后,这个值并没有被丢掉,而是在(2)语句时继续用这个值给 k 赋值。编译器不会生成出汇编代码重新从内存里取 i 的值,这样提高了效率。但要注意:(1)、(2)语句之间 i 没有被用作左值才行。
再看另一个例子:
volatile   int i=10;
int j = i;//(3)语句
int k = i;//(4)语句
volatile 关键字告诉编译器  i 是随时可能发生变化的,每次使用它的时候必须从内存中取出 i的值,因而编译器生成的汇编代码会重新从 i 的地址处读取数据放在 k 中。这样看来,如果 i 是一个寄存器变量或者表示一个端口数据或者是多个线程的共享数据,就容易出错,所以说 volatile 可以保证对特殊地址的稳定访问。

评分

参与人数 1蝴蝶豆 +4 收起 理由
zero99 + 4

查看全部评分

nyszx 回答时间:2018-3-12 16:21:52
请楼主查阅《Cortex™-Mx技术参考手册》或权威指南之类的书籍资料,就可以明白位带操作原理。
The mapping formula is:
bit_word_addr = bit_band_base + (byte_offset x 32) + (bit_number × 4)
where:
bit_word_addr is the address of the word in the alias memory region that maps to the
targeted bit.
bit_band_base is the starting address of the alias region
byte_offset is the number of the byte in the bit-band region that contains the targeted
bit
bit_number is the bit position (0-7) of the targeted bit.
具体操作的寄存器是什么功能,那就得查看相应器件的参考手册中的存储器和总线构架章节中的存储器映射。

所属标签

相似问题

关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版