当前位置:首页 > 嵌入式 > 技术让梦想更伟大
[导读]关注、星标公众号,直达精彩内容来源:技术让梦想更伟大作者:李肖遥最近在使用Nordic的最新蓝牙芯片nRF52832开发过程中,因为做一些测试涉及到对内存地址的操作,有(*(volatileunsignedint*)0xE000EDFC)的用法然后进行宏定义,本文将解析一下这种用...

关注、星标公众号,直达精彩内容

来源:技术让梦想更伟大

作者:李肖遥


最近在使用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是Cotex-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变量的存取不能缓存到寄存器,每次使用时需要重新存取。在嵌入式开发中这种用法很常见也很关键,需要掌握。

参考:https://blog.csdn.net/u010404580/article/details/11638619

‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧  END  ‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: 驱动电源

在工业自动化蓬勃发展的当下,工业电机作为核心动力设备,其驱动电源的性能直接关系到整个系统的稳定性和可靠性。其中,反电动势抑制与过流保护是驱动电源设计中至关重要的两个环节,集成化方案的设计成为提升电机驱动性能的关键。

关键字: 工业电机 驱动电源

LED 驱动电源作为 LED 照明系统的 “心脏”,其稳定性直接决定了整个照明设备的使用寿命。然而,在实际应用中,LED 驱动电源易损坏的问题却十分常见,不仅增加了维护成本,还影响了用户体验。要解决这一问题,需从设计、生...

关键字: 驱动电源 照明系统 散热

根据LED驱动电源的公式,电感内电流波动大小和电感值成反比,输出纹波和输出电容值成反比。所以加大电感值和输出电容值可以减小纹波。

关键字: LED 设计 驱动电源

电动汽车(EV)作为新能源汽车的重要代表,正逐渐成为全球汽车产业的重要发展方向。电动汽车的核心技术之一是电机驱动控制系统,而绝缘栅双极型晶体管(IGBT)作为电机驱动系统中的关键元件,其性能直接影响到电动汽车的动力性能和...

关键字: 电动汽车 新能源 驱动电源

在现代城市建设中,街道及停车场照明作为基础设施的重要组成部分,其质量和效率直接关系到城市的公共安全、居民生活质量和能源利用效率。随着科技的进步,高亮度白光发光二极管(LED)因其独特的优势逐渐取代传统光源,成为大功率区域...

关键字: 发光二极管 驱动电源 LED

LED通用照明设计工程师会遇到许多挑战,如功率密度、功率因数校正(PFC)、空间受限和可靠性等。

关键字: LED 驱动电源 功率因数校正

在LED照明技术日益普及的今天,LED驱动电源的电磁干扰(EMI)问题成为了一个不可忽视的挑战。电磁干扰不仅会影响LED灯具的正常工作,还可能对周围电子设备造成不利影响,甚至引发系统故障。因此,采取有效的硬件措施来解决L...

关键字: LED照明技术 电磁干扰 驱动电源

开关电源具有效率高的特性,而且开关电源的变压器体积比串联稳压型电源的要小得多,电源电路比较整洁,整机重量也有所下降,所以,现在的LED驱动电源

关键字: LED 驱动电源 开关电源

LED驱动电源是把电源供应转换为特定的电压电流以驱动LED发光的电压转换器,通常情况下:LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: LED 隧道灯 驱动电源
关闭