良许Linux教程网 干货合集 嵌入式开发中数值常量如何转化为内存地址?

嵌入式开发中数值常量如何转化为内存地址?

最近在使用Nordic最新的蓝牙芯片nRF52832开发过程中,遇到了一些需要对内存地址进行操作的测试。其中使用了(*(volatile unsigned int *)0xE000EDFC)的语法,并通过宏定义进行解析。本文将对这种用法进行分析。

代码解析

首先,让我们看下面这段代码:

#define ARM_CM_DEMCR (*(volatile unsigned int *)0xE000EDFC)
#define ARM_CM_DWT_CTRL (*(volatile unsigned int *)0xE0001000)
#define ARM_CM_DWT_CYCCNT (*(volatile unsigned int *)0xE0001004)

对这段代码进行结构分析。由于nRF52832是Cortex-M4内核,在ARM处理器中,只能将其识别为一个十六进制数值,而无法自动区分其具体是数据还是地址。

使用(unsigned int *)0xE000EDFC进行强制类型转换,表示该数值为一个无符号整型地址指针值。同时,关键字volatile告诉编译器指针指向的内容是易变的,可能会被硬件等意外因素修改。

*(volatile unsigned int *)0xFFE00000表示获取指针所指向地址处的内容。

采用#define宏的方式,在用户程序中对ARM_CM_DEMCR的操作等同于在地址0xE000EDFC上进行读写操作。

应用

如前所述,在32位处理器中,如果要对一个32位的内存地址进行访问和操作,可以使用类似上述的语法。通过强制类型转换和指针操作,可以对指定地址的内存内容进行读写。

tmp = ARM_CM_DEMCR;//读
ARM_CM_DEMCR = 0x55;//写

使用volatile修饰是因为它的值可能会改变,我们假设在一个循环操作中需要不停地判断一个内存数据,例如要等待ARM_CM_DEMCR的flag标志位置位,因为ARM_CM_DEMCR是映射在SRAM空间,为了加快速度,编译器可能会编译出这样的代码:把ARM_CM_DEMCR读取到寄存器中,然后不停地判断寄存器相应位,而不会再读取ARM_CM_DEMCR.

而实际工程中,程序例如中断事件会改变ARM_CM_DEMCR,而寄存器相应位没有更新,会造成死循环了。如果volatile来修饰,那每次要操作一个变量的时候会都从内存中读取一次。

嵌入式系统编程中要求程序员能够利用C语言访问固定的内存地址。既然是个地址,那么按照C语言的语法规则,这个表示地址的量应该是指针类型。

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

volatile关键字的用途

volatile的意思是告诉编译器,在编程源代码时,对这个变量不要使用优化,C语言中可能会优化一些运算过程中的变量值导致最后的结果不对,这里就不多说了。

volatile还可以防止编译器优化去掉某些语句,在arm中假如需要写1清中断,举例子如下:

#define INTPAND *(volatile unsigned int *)0x560012300
INTPAND = INTPAND; // 清中断

INTPAND = INTPAND;这种操作,如果没有volatile修饰,编译器就很有可能会去掉INTPAND = INTPAND;,相当于没这句话了。

在嵌入式编程中,当地址是io端口的时候,读写这个地址是不能对它进行缓存的(有cache才),比如写这个io端口的时候,如果没有volatile修饰,编译器会先把值先写到一个缓冲区,到一定时候再写到io端口,这样就不能使数据及时的写到io端口,有了volatile修饰就会直接写到io端口,从而避免了读写io端口的延时。

编译器对代码的优化

再说说编译器的优化,CPU在执行的过程中,因为访问内存的速度远没有cpu的执行速度快,为了提高效率,引入了高速缓存cache。

C编译器在编译时如果不知道变量会被其它外部因素(操作系统、硬件或者其它线程)修改,那么就会对该变量进行优化(当然也有些IDE可以设置优化等级),这个变量在CPU的执行过程中会被放到高速缓存cache去,进而达到对变量的快速访问。

在一些寄存器变量或数据端口的使用中,因为寄存器变量本身也是靠cache来处理,为了避免引起错误,也可以使用volatile修饰符。

如果变量是被外部因素改变,那么cpu就无法判断出这个变量已经被改变,那么程序在执行的过程中如果使用到该变量,还会继续使用cache中的变量(已经改变),需要到内存地址中更新,所以变量在执行的过程中不能被放到cache中。

总结

使用volatile的目的就是让对volatile变量的存取不能缓存到寄存器,每次使用时需要重新存取。在嵌入式开发中这种用法很常见也很关键,需要掌握。

以上就是良许教程网为各位朋友分享的Linu系统相关内容。想要了解更多Linux相关知识记得关注公众号“良许Linux”,或扫描下方二维码进行关注,更多干货等着你 !

137e00002230ad9f26e78-265x300
本文由 良许Linux教程网 发布,可自由转载、引用,但需署名作者且注明文章出处。如转载至微信公众号,请在文末添加作者公众号二维码。
良许

作者: 良许

良许,世界500强企业Linux开发工程师,公众号【良许Linux】的作者,全网拥有超30W粉丝。个人标签:创业者,CSDN学院讲师,副业达人,流量玩家,摄影爱好者。
上一篇
下一篇

发表评论

联系我们

联系我们

公众号:良许Linux

在线咨询: QQ交谈

邮箱: yychuyu@163.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

关注微博
返回顶部