`
yzd
  • 浏览: 1820508 次
  • 性别: Icon_minigender_2
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

(*(volatile unsigned int *))详解

 
阅读更多
<p><span style="background-color: #ccffff;"><span style="color: #000000;"><span style="font-size: medium;">在看vivi代码时,Nand_read.c文件中有下面一段<br>
#define __REGb(x) (*(volatile unsigned char *)(x)) #define __REGi(x) (*(volatile unsigned int *)(x))<br>
#define
NF_BASE 0x4e000000 #define NFCONF __REGi(NF_BASE + 0x0) #define NFCMD
__REGb(NF_BASE + 0x4) #define NFADDR __REGb(NF_BASE + 0x8) #define
NFDATA __REGb(NF_BASE + 0xc) #define NFSTAT __REGb(NF_BASE + 0x10)<br>
把宏定义放入句中就是(*(volatile unsigned int *))(0x4e000000),不知其何意??好像是定义一指针,该指针指向的内容就是0x4e000000该寄存器的内容。</span>
</span>
</span>
</p>
<p><span style="background-color: #ccffff;"><span style="color: #000000;"><span style="font-size: medium;"><br></span>
</span>
</span>
</p>
<p><span style="background-color: #ccffff;"><span style="color: #000000;">
</span>
</span>
</p>
<p><span style="background-color: #ccffff;"><span style="color: #000000;"><span style="font-size: medium;">使用一个32位处理器,要对一个32位的内存地址进行访问,可以这样定义<br>
#define RAM_ADDR (*(volatile
unsigned long *)0x0000555F) 然后就可以用C语言对这个内存地址进行读写操作了 读:tmp = RAM_ADDR;
写:RAM_ADDR = 0x55; 定义volatile是因为它的值可能会改变,大家都知道为什么改变了;
如果在一个循环操作中需要不停地判断一个内存数据,例如要等待RAM_ADDR的I标志位置位,因为RAM_ADDR也是映射在SRAM空间,为了加快速
度,编译器可能会编译出这样的代码:把RAM_ADDR
读取到Register中,然后不停地判断Register相应位。而不会再读取RAM_ADDR,这样当然是不行了,因为程序或其它事件(中断等)会改
变RAM_ADDR,结果很可能是一个死循环出不来了。如果定义成volatile型变量,编译的代码是这样的:每次要操作一个变量的时候都从内存中读取
一次。 #define rGPACON(*(volatile unsigned long *)0x56000000)
对于不同的计算机体系结构,设备可能是端口映射,也可能是内存映射的。如果系统结构支持独立的IO地址空间,并且是端口映射,就必须使用汇编语言完成实际
对设备的控制,因为C语言并没有提供真正的“端口”的概念。如果是内存映射,那就方便的多了。
举个例子,比如像寄存器A(地址假定为0x48000000)写入数据0x01,那么就可以这样设置了。 #define A (*(volatile
unsigned long *)0x48000000) ... A = 0x01; ...
这实际上就是内存映射机制的方便性了。其中volatile关键字是嵌入式系统开发的一<br>
个重要特点。上述表达式拆开来分析,首先
(volatile unsigned long *)0x48000000的意思是把0x48000000强制转换成volatile
unsigned long类型的指针,暂记为p,那么就是#define A
*p,即A为P指针指向位置的内容了。这里就是通过内存寻址访问到寄存器A,可以读/写操作。
用GCC编译时。volatile所指示的寄存器不进行优化!!!<br>
理解#define rRTCCON (*(volatile
unsigned char *)0x57000043) //RTC control
嵌入式系统编程,要求程序员能够利用C语言访问固定的内存地址。既然是个地址,那么按照C语言的语法规则,这个表示地址的量应该是指针类型。所以,知道要
访问的内存地址后,比如0x57000043, 第一步是要把它强制转换为指针类型 (unsigned char
*)0x57000043,s3c2410的rRTCCON是单字节访问的(怎么看出来的???我无法理解),所以0x57000043强制转换为指向
unsigned char类型。
volatile(可变的)这个关键字说明这变量可能会被意想不到地改变,这样编译器就不会去假设这个变量的值了。这种“意想不到地改变”,不是由程序去
改变,而是由硬件去改变——意想不到。 第二步,对指针变量解引用,就能操作指针所指向的地址的内容了 *(volatile unsigned
char *)0x57000043 第三步,小心地把#define宏中的参数用括号括起来,这是一个很好的习惯。
在嵌入式系统中经常使用到Volatile,对于volatile的用法 编译器对代码的优化是指:
CPU在执行的过程中,因为访问内存的速度远没有cpu的执行速度快,为了提高效率,引入了高速缓存cache.
C编译器在编译时如果不知道变量会被其它外部因素(操作系统、硬件或者其它线程)修改,那么就会对该变量进行标识,即优化.那么这个变量在CPU的执行过
程中,就会被放到高速缓存cache去,进而达到对变量的快速访问.
在了解了优化的概念后,试想如果我们事先就知道该变量会被外部因素改变,那么我们就在这个变量定义前加上Volatile,这样编译器就不会对该变量进行
优化.这样该变量在cpu处理的过程当中,就不会被放到高速缓存cache中。 为什么要让变量在执行的过程中不被放到cache中去呢?
如果变量是被外部因素改变,那么cpu就无法判断出这个变量已经被改变,那么程序在执行的过程中如果使用到该变量,还会继续使用cache中的变量,但是
这个变量其实已经被改变了.需要到内存地址中更新其内容了.
还有一个原因,在一些寄存器变量或数据端口的使用中,因为寄存器变量本身也是靠cache来处理,为了避免引起错误,也可以使用volatile修饰符.
简单的说使用volatile的目的就是: 让对volatile 变量的存取不能缓存到寄存器,每次使用时需要重新存取。</span>
</span>
</span>
</p>
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics