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)

推荐阅读最新更新时间:2026-03-25 12:23

ARM特殊寄存器定义详解——#define A (* (volatile unsigned long *) 0x48000000
今天在看S3C2440开发板的初始化代码时,对#define A (* (volatile unsigned long *) 0x48000000这种形式的定义方式有困惑,于是求助GOOGLE大神,在网上搜到了一些文章,觉得以下三篇文章对理解这个有些作用: 文章一: 有关volatile unsigned long一些说明 对于不同的计算机体系结构,设备可能是端口映射,也可能是内存映射的。如果系统结构支持独立的IO地址空间,并且是端口映射,就必须使用汇编语言完成实际对设备的控制,因为C语言并没有提供真正的“端口”的概念。如果是内存映射,那就方便的多了。 以 #define IOPIN (*((vo
[单片机]
ARM定义特殊寄存器*(volatile unsigned long *))的理解
以前老是对ARM程序中(*(volatile unsigned long *))不理解,通过查阅资料,和看别人写的文章,今天对这个类型转换进行解析一下。这个用法不止在定义内部特殊寄存器有用,在用到外部总线时,定义外部器件的地址也会用。 对于嵌入式系统编程,要求程序员能够利用C语言访问固定的内存地址。既然是个地址,那么按照C语言的语法规则,这个表示地址的量应该是指针类型。所以,知道要访问的内存地址后,比如0x5F。 第一步是要把它强制转换为指针类型 (unsigned CHAR *)0x5F AVR的SREG是八位寄存器,所以0x5F强制转换为指向unsigned CHAR类型。 v
[单片机]
C51对特殊功能寄存器位变量定义写法不严谨
C51对特殊功能寄存器位变量定义写法是否有不严谨之处,因为sbit P1_3=P1^3;中^是一个双目运算符 (按位加),P1口的8位状态和3正好构成双目,前面又是一个赋值号,又把一个字节赋给一个位,逻辑上讲不通。为什么非要用一个^号来定义,如果用两个(^^)来定义就不会有歧意,也不会被人误解了,在C51中有很多这样的符号,如== && !! =等。须要用上面的写法来定义吗?在这点上我可能是有点晕,但尚未影响编程,如果方便请看了书的和会搞程序的同人给予指点!
[单片机]
Arm 扩展与清华大学合作,共筑产学研融合与人才培养新范式
Arm 控股有限公司(以下简称 Arm)昨日(12 日)与清华大学经济管理学院在北京正式签署合作协议 ,该协议是基于双方长期合作的基础,进一步扩大教学科研的实践和 AI 人才的培养。在此次合作协议中,双方不仅将在授课项目、教材开发、人才交流等方面展开合作,同时 Arm 捐赠专项资金,用于采购搭载 Arm 架构的国产服务器等科研资源,从基础设施底层支撑学院开展教学科研、大模型部署及数据推理分析工作。这一举措不仅将 Arm 与清华大学的合作拓展至技术应用层面,更标志着 Arm 在中国产学研生态建设的又一重要落地,为中国科技和产业人才成长注入新动能。 Arm 战略与中国副总裁 Philip Stanbury-Jones(左) 和
[嵌入式]
<font color='red'>Arm</font> 扩展与清华大学合作,共筑产学研融合与人才培养新范式
安谋科技Arm China发布“山海”S30FP/S30P SPU IP,兼顾信息安全和功能安全
12月24日,安谋科技(中国)有限公司(以下简称 “安谋科技”)推出新一代SPU IP——“山海”S30FP/S30P,为高性能计算芯片提供全栈安全解决方案。 该产品是完善的HSM子系统,全面增强抗物理攻击能力与系统可靠性,功能安全可达到最高等级ASIL D,助力客户芯片实现CC EAL4+及国密二级等高等级安全认证,并默认支持Arm ® TrustZone ® 和硬件虚拟化,从硬件IP层、软件中间件到云端服务,构建起覆盖芯片底层至应用层的一栈式安全防护体系。 “山海” S30FP/S30P主要面向智能汽车、基础设施、移动终端等应用领域的高性能计算场景,通过软硬件协同设计与灵活可配置能力,满足客户多元化的功能
[嵌入式]
安谋科技<font color='red'>Arm</font> China发布“山海”S30FP/S30P SPU IP,兼顾信息安全和功能安全
Arm 发布 20 项技术预测:洞见 2026 年及未来发展趋势
随着全球迈入智能计算新时代,Arm 发布 2026 年技术预测 全球计算技术的格局正在发生深刻变革——计算模式正从集中式云架构,向覆盖各类设备、终端及系统的分布式智能架构演进。2026 年将迈入智能计算新纪元,届时,计算将具备更高的模块化特性和能效表现,实现云端、物理终端及边缘人工智能 (AI) 环境的无缝互联。 基于这一趋势,Arm 发布了 20 项技术预测,这些技术将引领 2026 年的下一波创新浪潮。 芯片创新 1. 模块化芯粒技术将重新定义芯片设计 随着行业持续突破芯片技术的极限,从单片式芯片向模块化芯粒架构的转型将全面加速。通过将计算单元、内存与 I/O 拆分为可复用的构建模块,芯片设计人员可
[嵌入式]
<font color='red'>Arm</font> 发布 20 项技术预测:洞见 2026 年及未来发展趋势
深入解析Arm Neoverse计算平台的技术架构与性能优势
十年前,云基础设施主要承担Web应用和企业级工作负载,其性能与功耗相对稳定且可预测;如今,云基础设施必须应对多样化工作负载的规模化扩展,保障多租户环境的安全,并将计算能力从数据中心延伸至数据产生的源头。 如今的云平台在全球各地运行,AI 工作负载对内存带宽和性能提出了更高的要求;与此同时,分布式系统使算力更加接近于用户和设备,而运营商则面临提升能效比、加强架构安全性、缩短部署时间的多重压力。 基础设施正朝着分布式、软件定义和 AI 赋能的方向演进,必须在固定功耗与成本限制内,实现高性能,并高效扩展。这正是 Neoverse 平台诞生的使命。 详解 Arm Neoverse 平台 Arm Neoverse 平台是一系
[单片机]
深入解析<font color='red'>Arm</font> Neoverse计算平台的技术架构与性能优势
Arm 执行副总裁:尚未向合作伙伴提供适用于 Windows 操作系统的 GPU
3 月 10 日消息,Arm 边缘 AI 事业部执行副总裁 Christopher Bergey 在 MWC26 巴塞罗那上接受西班牙科技媒体 GEEKNETIC 采访时表示,尚未向合作伙伴提供适用于 Windows 操作系统的 GPU。 尽管 WoA 生态在最近数年获得了不小的进展,但 Arm 的第一方 GPU IP 仍未登陆 Windows:高通在其 PC SoC 中采用的是自有 Adreno GPU;预计很快面世的 PC 版英伟达 N1 平台自然也基于“绿厂”的自有 GPU。 Christopher Bergey 表示,目前仅有四家 GPU 供应商获得了 Windows 认证,即英伟达、AMD、英特尔、高通。他还提到,智能体
[嵌入式]
小广播
最新单片机文章
何立民专栏 单片机及嵌入式宝典

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

厂商技术中心

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

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