ARM特殊寄存器定义详解——#define A (* (volatile unsigned long *) 0x48000000

发布者:心满愿望最新更新时间:2024-07-18 来源: cnblogs关键字:ARM 手机看文章 扫描二维码
随时随地手机看文章

今天在看S3C2440开发板的初始化代码时,对#define A (* (volatile unsigned long *) 0x48000000这种形式的定义方式有困惑,于是求助GOOGLE大神,在网上搜到了一些文章,觉得以下三篇文章对理解这个有些作用:


文章一:


有关volatile unsigned long一些说明

 

 

对于不同的计算机体系结构,设备可能是端口映射,也可能是内存映射的。如果系统结构支持独立的IO地址空间,并且是端口映射,就必须使用汇编语言完成实际对设备的控制,因为C语言并没有提供真正的“端口”的概念。如果是内存映射,那就方便的多了。

         以 #define IOPIN           (*((volatile unsigned long *) 0xE0028000))     为例:作为一个宏定义语句,define是定义一个变量或常量的伪指令。首先( volatile unsigned long * )的意思是将后面的那个地址强制转换成 volatile unsigned long * ,unsigned long * 是无符号长整形,volatile 是一个类型限定符,如const一样,当使用volatile限定时,表示这个变量是依赖系统实现的,以为着这个变量会被其他程序或者计算机硬件修改,由于地址依赖于硬件,volatile就表示他的值会依赖于硬件。


volatile 类型是这样的,其数据确实可能在未知的情况下发生变化。比如,硬件设备的终端更改了它,现在硬件设备往往也有自己的私有内存地址,比如显存,他们一般是通过映象的方式,反映到一段特定的内存地址当中,这样,在某些条件下,程序就可以直接访问这些私有内存了。另外,比如共享的内存地址,多个程序都对它操作的时候。你的程序并不知道,这个内存何时被改变了。如果不加这个voliatile修饰,程序是利用catch当中的数据,那个可能是过时的了,加了 voliatile,就在需要用的时候,程序重新去那个地址去提取,保证是最新的。归纳起来如下:


1. volatile变量可变 允许除了程序之外的比如硬件来修改他的内容   

2. 访问该数据任何时候都会直接访问该地址处内容,即通过cache提高访问速度的优化被取消  


对于((volatile unsigned long *) 0xE0028000)为随硬件需要定义的一种地址,前面加上“*”指针,为直接指向该地址,整个定义约定符号IOPIN代替,调用的时候直接对指向的地址寄存器写内容既可。这实际上就是内存映射机制的方便性了。其中volatile关键字是嵌入式系统开发的一个重要特点。上述表达式拆开来分析,首先(volatile unsigned long *) 0xE0028000的意思是把0xE0028000强制转换成volatile unsigned long类型的指针,暂记为p,那么就是#define A *p,即A为P指针指向位置的内容了。这里就是通过内存寻址访问到寄存器A,可以读/写操作。


对于(volatile unsigned char *)0x20我们再分析一下,它是由两部分组成: 

1)(unsigned char *)0x20,0x20只是个值,前面加(unsigned char *)表示0x20是个地址,而且这个地址类型是unsigned char ,意思是说读写这个地址时,要写进unsigned char 的值,读出也是unsigned char 。 

2)volatile,关键字volatile 确保本条指令不会因C 编译器的优化而被省略,且要求每次直接读值。例如用 while((unsigned char *)0x20)时,有时系统可能不真正去读0x20的值,而是用第一次读出的值,如果这样,那这个循环可能是个死循环。用了volatile 则要求每次都去读0x20的实际值。 


那么(volatile unsigned char *)0x20是一个固定的指针,是不可变的,不是变量。而char  *u则是个指针变量。 

再在前面加'*':*(volatile unsigned char *)0x20则变成了变量(普通的unsigned char变量,不是指针变量),如果#define i (*(volatile unsigned char *)0x20),那么与unsigned char i是一样了,只不过前面的i的地址是固定的。 


那么你的问题就可解答了,(*(volatile unsigned char *)0x20)可看作是一个普通变量,这个变量有固定的地址,指向0x20。而0x20只是个常量,不是指针更不是变量。



文章二:


对于不同的计算机体系结构,设备可能是端口映射,也可能是内存映射的。如果系统结构支持独立的IO地址空间,并且是端口映射,就必须使用汇编语言完成实际对设备的控制,因为C语言并没有提供真正的“端口”的概念。如果是内存映射,那就方便的多了。


举个例子,比如像寄存器A(地址假定为0x48000000)写入数据0x01,那么就可以这样设置了。


#define A (*(volatile unsigned long *) 0x48000000 )

...

     A = 0x01;

...


这实际上就是内存映射机制的方便性了。其中volatile关键字是嵌入式系统开发的一个重要特点。volatile


(可变的)这个关键字说明这变量可能会被意想不到地改变,这样编译器就不会去假设这个变量的值了。这


种“意想不到地改变”,不是由程序去改变,而是由硬件去改变。


volatile 限定编译器不对这个指针的指向的存储单元进行优化, 即不用通用寄存器暂时代替这个指针的指向


的存储单元,而是每次取值都直接到指针的指向的存储单元取值.volatile 主要用于变量会异步改变的情况下,


主要有三个方面:1.cpu外设寄存器 2.中断和主循环都会用到的全局变量   3.操作系统中的线程间都会用到


的公共变量.上述表达式拆开来分析,


首先(volatile unsigned long *) 0x48000000的意思是把0x48000000强制转换成volatile unsigned long类型


的指针,即对指针的操作的范围是从0x48000000开始的4个字节(long型).暂记为p,那么就是


#define A   *p,即A为P指针指向位置的内容了。这里就是通过内存寻址访问到寄存器A,可以读/写操作!


文章三:


理解嵌入式中#define rRTCCON (*(volatile unsigned char *))0x57000043


#define rRTCCON    (*(volatile unsigned char *)0x57000043) //RTC control


理解#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的用法,我根据自己的理解做如下阐述,希望大家可以发表评论:


在c语言中,volatile关键字是一种类型修饰符, 用它声明的类型变量表示该变量可以被某些编译器未知的外部因素(比如:操作系统、硬件或者其它线程)更改. 遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址(定义的变量在内存中的地址)的稳定访问。


编译器对代码的优化是指:CPU在执行的过程中,因为访问内存的速度远没有cpu的执行速度快,为了提高效率,引入了高速缓存cache. C编译器在编译时如果不知道变量会被其它外部因素(操作系统、硬件或者其它线程)修改,那么就会对该变量进行标识,即优化.那么这个变量在CPU的执行过程中,就会被放到高速缓存cache去,进而达到对变量的快速访问. 在了解了优化的概念后,试想如果我们事先就知道该变量会被外部因素改变,那么我们就在这个变量定义前加上Volatile,这样编译器就不会对该变量进行优化.这样该变量在cpu处理的过程当中,就不会被放到高速缓存cache中.


为什么要让变量在执行的过程中不被放到cache中去呢?如果变量是被外部因素改变,那么cpu就无法判断出这个变量已经被改变,那么程序在执行的过程中如果使用到该变量,还会继续使用cache中的变量,但是这个变量其实已经被改变了.需要到内存地址中更新其内容了.还有一个原因,在一些寄存器变量或数据端口的使用中,因为寄存器变量本身也是靠cache来处理,为了避免引起错误,也可以使用volatile修饰符.(简单的说使用volatile的目的就是:让对volatile 变量的存取不能缓存到寄存器,每次使用时需要重新存取。


关键字:ARM 引用地址:ARM特殊寄存器定义详解——#define A (* (volatile unsigned long *) 0x48000000

上一篇:对s3c2440、s3c2410的存储控制及启动代码的理解
下一篇:uboot在s3c2440上的移植(2)

推荐阅读最新更新时间:2024-11-08 09:28

基于ARM的双频RFID读写系统设计解析方案
引言 鉴于目前国内市场上应用最为广泛的射频卡和读写器实现方法,本文采用ARM 嵌入式系统作为微控制器,设计了能对低频125KHz 和高频13.56MHz 的二种频率RFID 卡操作的读写模块,实现了的双频RFID 读写系统。 2 系统设计 由于ARM 微处理器具有运行速度快,接口功能丰富,其应用越来越广泛。本文采用三星公司的S3C44B0X,它是ARM7 系列的低功耗的32 位RISC 处理器,具有ARM7TDMI内核,有丰富的内置部件,包括8K 字节Cache 和内部SRAM,带自动握手联络的2 通道UART,定时器,通用 I/O 口,ADC 和I2C-BUS 控制器等。尤其是它的内置液晶显示器接口,可直接连接L
[单片机]
基于<font color='red'>ARM</font>的双频RFID读写系统设计解析方案
基于ARM的车辆检测系统控制单元设计
摘 要:本文介绍了利用ARM7内核微处理器LPC2114设计的高速公路车辆检测系统控制单元,着重分析了大容量Flash存储单元的设计和ARM开发相关注意事项,给出了系统原理框图、单元电路设计和软件设计思想。 关键词:ARM微处理器;LPC2114;Flash存储;车辆检测系统 引言 由于交通需求的不断增加,有越来越多的环形感应线圈检测器用于交通检测。这些埋设在道路表面下的线圈可以检测到车辆通过时的电磁变化进而精确地算出交通流量。交通流量是交通统计和交通规划的基本数据,通过这些检测结果可以用来计算占用率(表征交通密度),在使用双线圈模式时还可以提供速度、车辆行驶方向、车型分类等数据,这些数据对于交通管理和统计是极为重要的。通
[应用]
ARM I2C 总线的数据传送方式
AR M VC 总线接口共有主控器发送、主控器接收、被控器发送和被控器接收4种操作模式。在流量积算仪表的设计中IZC总线接口扩展了数据采集 电路 ,数据采集是由定时器控制完成的,每间隔100 ms进行一次数据采样。在操作模式中主要用到主控器发送模式和主控器接受模式,下面结合这两种模式介绍总线中数据的传送方式。 在AR M IZC总线的数据传送中,进行传输的每个字节数据必须是8位的,而对每一次传送而言,可被传送的字节数没有限制。在主控器发送模式下,主控器先发出起始信号,然后发送一个字节的数据,其中包括7位从地址以决定哪个接收器件被主控器选中和I位的写操作标志位。一个字节的发送操作完成以后,被寻址的接收器件要发送I个ACK位作为应
[单片机]
<font color='red'>ARM</font> I2C 总线的数据传送方式
ARM7与FPGA相结合的应用
  工业控制中往往需要完成多通道故障检测及多通道命令控制(这种多任务设置非常普遍),单独的CPU芯片由于其外部控制接口数量有限而难以直接完成多路检控任务,故利用ARM芯片与FPGA相结合来扩展检控通道是一个非常好的选择。这里介绍用Atmel公司ARM7处理器(AT91FR40162)和ALTERA公司的低成本FPGA芯片(cyclone2)结合使用完成多通道检控任务的一种实现方法。   各部分功能简介   图1为此系统的结构连接框图。如图所示,ARM芯片与FPGA芯片之间通过数据总线、地址总线及读写控制线相连,而与终端PC则通过串口通信;FPGA与目标设备通过命令控制总线和故障检测总线相连。         图1 系统结构框
[单片机]
<font color='red'>ARM</font>7与FPGA相结合的应用
利用一个ARM7处理器对无刷电机实施磁场定向控制
电机驱动能效不论提高多少,都会节省大量的电能,这就是市场对先进的电机控制算法的兴趣日浓的部分原因。三相无刷电机主要指是交流感应异步电机和永磁同步电机。这些电机以能效高、可靠性高、维护成本低、产品成本低和静音工作而著称。感应电机已在水泵或风扇等工业应用中得到广泛应用,并正在与永磁同步电机一起充斥家电、空调、汽车或伺服驱动器等市场。推动三相无刷电机发展的主要原因有:电子元器件的价格降低,实现复杂的控制策略以克服本身较差的动态性能成为可能。 以异步电机为例。简单的设计需要给定子施加三个120°相移的正弦波电压,这些绕组的排列方式能够产生一种旋转磁通量。利用变压器效应,这个磁通量在转子笼内感应出一股电流,然后产生转子磁通量。就是这两种磁通
[工业控制]
ARM-CortexM0/M0+单片机的指针变量替换方法
引言 CortexM0/M0+是RISC类型的低端ARM内核,其指令集与高端ARM兼容,在性能、功耗和价格方面远优于传统的以8051、68S08/12等为代表的8/16位CISC(复杂指令流)CPU。目前,各半导体厂商纷纷以之替代原有的8/16位MCU内核,32位ARM MCU全面替代8/16位MCU已是大势所趋。 CortexM0+将CortexM0的3级流水线简化为2级,并进一步降低功耗、提高性能,这些优点使得CortexM0+成为目前8/16位处理器较好的替代者。不过 替代8/16位MCU的低端ARM往往内存资源非常有限,目前典型的CortexM0/M0+ MCU往往仅有2 KB、4 KB或8 KB,最多16 KB片
[单片机]
<font color='red'>ARM</font>-CortexM0/M0+单片机的指针变量替换方法
ARM】Linux驱动移植
#1驱动模块移植过程 ##1.1模块的第一种编译方法——改kconfig 第一步:改kconfig 文件在:Drivers/char/kconfig; tristate三态表示可以编译在模块 M ; bool表示只能被选择编 或不编 。 第二步:配置内核 make menuconfig后会自动生成供编译的.config文件。 wuchengbing@ubuntu:~/linux/kernel-2.6.13$ make menuconfig Device Drivers --- Character devices --- S3C2410 RTC Driver │ │
[单片机]
【<font color='red'>ARM</font>】Linux驱动移植
ARM7入门12,SPI通信
数码管显示1-F。 主程序: /******************************************************************************* *File: Main.c *功能: LED数码管显示0-F字符,同时控制4个LED显示对应的十六进制 *******************************************************************************/ #include config.h #define HC595_CS 0x00000100 /*P0.8口为74HC595的片选*/ uint8 rcv_d
[单片机]
<font color='red'>ARM</font>7入门12,SPI通信
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

更多每日新闻

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved