查看: 1848|回复: 0

volatile by 下家山

[复制链接]
  • TA的每日心情
    郁闷
    2024-10-28 10:11
  • 签到天数: 1703 天

    连续签到: 1 天

    [LV.Master]伴坛终老

    发表于 2013-8-16 17:12:20 | 显示全部楼层 |阅读模式
    分享到:
    【楼主按曰】这个帖子的深度显然和下家山的自我介绍“02年接触ARM和ucos,05年开始从事Linux及Rtems WiFi,camera,Ethernet等驱动开发工作”不相称,是入门级的,但是可以帮助初学者的

    一:为什么要讲volatile
           因为,很多”面试官”自己找不到能够测试应聘者的好的方式,所以就google了一下,发现了”嵌入式经典的0x10个面试题”,于是乎就拿来直接问了。我想第一个想到用这个来提问应聘者的人绝对是值得我们仰慕的。
    二:Volatile官方说明
    Indicates that a variable can be changed by a background routine.
    Keyword volatile is an extreme opposite of const. It indicates that a variable may be changed in a way which is absolutely unpredictable by analysing the normal program flow (for example, a variable which may be changed by an interrupt handler). This keyword uses the following syntax:
    volatile data-definition;
    Every reference to the variable will reload the contents from memory rather than take advantage of situations where a copy can be in a register.
    翻译:
         表示一个变量也许会被后台程序改变.
            关键字volatile是与const绝然对立的。它指示一个变量也许会被某种方式修改,这种方式按照正常程序流程分析是无法预知的(例如,一个变量也许会被一个中断服务程序所修改)。这个关键字使用下列语法定义:
          volatile data-definition;
          变量如果加了volatile修饰,则会从内存重新装载内容,而不是直接从寄存器拷贝内容。
    三:实例分析
             Volatile应用比较多的场合,在中断服务程序和cpu相关寄存器的定义。
    比如,下面就是lpc2136 相关寄存器定义
    /**************************
    【By 下家山 Q群 75303301        上海松江文汇路928号258室    松江大学城
    上海索漫科技  http://www.xiajiashan.com  专注嵌入式(ARM7,Cortex-M0,Cortex-M3,ARM9,linux)培训】**************************************/

    /* Vectored Interrupt Controller (VIC) */
    #define VICIRQStatus    (*((volatile unsigned long *) 0xFFFFF000))
    #define VICFIQStatus    (*((volatile unsigned long *) 0xFFFFF004))
    #define VICRawIntr      (*((volatile unsigned long *) 0xFFFFF008))
    #define VICIntSelect      (*((volatile unsigned long *) 0xFFFFF00C))
    #define VICIntEnable     (*((volatile unsigned long *) 0xFFFFF010))
    #define VICIntEnClr      (*((volatile unsigned long *) 0xFFFFF014))
    #define VICSoftInt       (*((volatile unsigned long *) 0xFFFFF018))
    #define VICSoftIntClear   (*((volatile unsigned long *) 0xFFFFF01C))
    #define VICProtection    (*((volatile unsigned long *) 0xFFFFF020))
    #define VICVectAddr     (*((volatile unsigned long *) 0xFFFFF030))
    #define VICDefVectAddr  (*((volatile unsigned long *) 0xFFFFF034))
    #define VICVectAddr0    (*((volatile unsigned long *) 0xFFFFF100))
    #define VICVectAddr1    (*((volatile unsigned long *) 0xFFFFF104))
    #define VICVectAddr2    (*((volatile unsigned long *) 0xFFFFF108))
    #define VICVectAddr3    (*((volatile unsigned long *) 0xFFFFF10C))
    #define VICVectAddr4    (*((volatile unsigned long *) 0xFFFFF110))
    #define VICVectAddr5    (*((volatile unsigned long *) 0xFFFFF114))
    #define VICVectAddr6    (*((volatile unsigned long *) 0xFFFFF118))
    #define VICVectAddr7    (*((volatile unsigned long *) 0xFFFFF11C))
    #define VICVectAddr8    (*((volatile unsigned long *) 0xFFFFF120))
    #define VICVectAddr9    (*((volatile unsigned long *) 0xFFFFF124))
    #define VICVectAddr10   (*((volatile unsigned long *) 0xFFFFF128))
    #define VICVectAddr11   (*((volatile unsigned long *) 0xFFFFF12C))
    也许有人看到这里有带出了跟本文无关的疑问,#define VICIntEnable     (*((volatile unsigned long *) 0xFFFFF010))
    是什么语法。
    这里也一并介绍了:
    先总结一句话,#define VICIntEnable     (*((volatile unsigned long *) 0xFFFFF010))
    其实就是定义一个指针变量。
    那什么是指针变量呢,万变不离其宗!
    我们看C里面对指针变量的定义:(大家可以去看谭浩强老师C语言第四版指针部分)
    Int a;这里a是一个变量,是一个32位整形变量;
    Int *p;同理,p也是一个变量,但他是一个指针变量,他可以存放一个地址,
    如:p=&a,(p可以这样赋值),p存放的地址是变量a的地址。&是取地址符合。
    那么*p是什么呢?
    *p就是p所指向的内容。比如:
    {
    Int a;
    Int *p;
    a=100;
    p=&a
    }
    那么*p就等于100;
    但是,这里还有个问题,p本身的地址。如果想到了这里,我们就好介绍
    ,#define VICIntEnable     (*((volatile unsigned long *) 0xFFFFF010))
    我们来做一个例比:
    (*((volatile unsigned long *) 0xFFFFF010))=========*p
    那么这里 ((volatile unsigned long *) 0xFFFFF010)========p
    这里0xFFFFF010就对应到p本身的地址。

    首先,大家应该知道这是一个C语言里面的宏定义;然后,0xFFFFF010这个32位数,这个数的来源在lpc2136 datasheet,52page/270

    1.jpg

    所以,这个32位数是一个寄存器地址,要把一个32位数表示成地址怎么表示呢?
    (unsigned long *) 0xFFFFF010,就是这样(也可以表示成(unsigned char *) 0xFFFFF010,前者表示这个地方可以存放32位数据,后者表示这个地址只能存放8位数据)。既然是地址,就像我们在超市里面的寄存包裹箱一样,是可以存放东西,而且可以取出东西的地方。我们叫可读写,当然有些地址是不能写的,只读的,比如这里面的VICIRQStatus..
        寄存器地址为什么要加volatile修饰呢,是因为,这些寄存器里面的值是随时变化的。比如,我们这里的中断状态寄存器VICIRQStatus ,当某个中断发生的时候,我们无法知道,那么这个状态寄存器的内容也是无法预知的。我们读取的时候,CPU就直接到内存里面取值,而不是到cache里面取值。
    写于上海松江
    作者:下家山(请尊重原创, 转载请注明)  http://www.xiajiashan.com,有什么问题可与我联系:ximenpiaoxue4016@sina.com

    回复

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /4 下一条

    手机版|小黑屋|与非网

    GMT+8, 2024-11-25 12:30 , Processed in 0.132736 second(s), 15 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.