#define rTCFG0 (*(volatileunsigned *)0x51000000)
#define rTCFG1 (*(volatileunsigned *)0x51000004)
#define rTCNTB0 (*(volatileunsigned *)0x5100000C)
#define rTCMPB0 (*(volatileunsigned *)0x51000010)
#define rTCON (*(volatileunsigned *)0x51000008)
#define rGPBCON (*(volatileunsigned *)0x56000010)
#define rGPBUP (*(volatileunsigned *)0x56000018)
#define rGPBDAT (*(volatileunsigned *)0x56000014)
下面是網上前輩看到的英文資料:
Using C, I was trying to assign a variable nameto a register address so thatmy
code would be readable. An example of how to dothis is as follows:
#define DDRA (*(volatile unsigned char*)(0x22))
This means that if a register or memorylocation exists at address 0×22, I canuse
DDRA to read or write to it likeso..
DDRA =0x05
In my C code.The #define looks really crypticat first. The way to understandthis
is by breaking it down intopieces.
First ofall,
unsignedchar
means we are using a byte-sized memorylocation. Byte being 8-bitswide.
unsigned char * means we are declaring apointer that points to a byte-sizedlocation.
(unsigned char *)(0x22)
means the byte-sized pointer points to address0×22. The C compiler will referto
address 0×22 when the variable DDRA is used.The assembly code will end upusing
0×22 in Load(LD) and Store (STR)insturctions.
(*(unsigned char*)(0x22))
The first asterisk from the left signifies thatwe want to manipulate the valuein
address 0×22. * means “the value pointed to bythe pointer”.
volatile
volatile forces the compiler to issue a Load orStore anytime DDRA is accessedas
the value may change without the compilerknowing it.
中文的解釋:
#define DDRA (*(volatile unsigned char*)(0x22))
然後就可以用 C 語言對這個內存地址進行讀寫操作了
讀:tmp = DDRA;
寫:DDRA = 0x55;
定義 volatile是因爲它的值可能會改變,大家都知道爲什麼改變了;
如果在一個循環操作中需要不停地判斷一個內存數據,例如要等待 RAM_ADDR 的I標誌位置
位, 因爲 RAM_ADDR 也是映射在 SRAM 空間,爲了加快速度,編譯器可能會編譯出這樣的代碼:
把 RAM_ADDR 讀取到 Register 中,然後不停地判斷 Register相應位。而不會再讀取
RAM_ADDR,這樣當然是不行了,因爲程序或其它事件(中斷等)會改變RAM_ADDR,結果很
可能是一個死循環出不來了。如果定義成 volatile型變量,編譯的代碼是這樣的:每次要
操作一個變量的時候都從內存中讀取一次。
#define rGPACON(*(volatile unsigned long*)0x56000000)
對於不同的計算機體系結構,設備可能是端口映射,也可能是內存映射的。如果系統結構支
持獨立的IO地址空間,並且是端口映射,就必須使用彙編語言完成實際對設備的控制,因
爲 C語言並沒有提供真正的“端口”的概念。如果是內存映射,那就方便的多了。
舉個例子,比如像寄存器 A(地址假定爲 0x48000000)寫入數據0x01,那麼就可以這樣設
置了。
#define A (*(volatile unsigned long*)0x48000000)
...
A = 0x01;
...
這實際上就是內存映射機制的方便性了。其中 volatile關鍵字是嵌入式系統開發的一個重要特點。上述表達式拆開來分析,首先(volatile unsigned long*)0x48000000的意思是把0x48000000
強制轉換成 volatile unsigned long 類型的指針,暫記爲p,那麼就是#defineA *p,即A 爲P 指針指向位置的內容了。 這裏就是通過內存尋址訪問到寄存器 A,
可以讀/寫操作。
用 GCC 編譯時。volatile所指示的寄存器不進行優化!!!
理解#definerRTCCON (*(volatile unsigned char *)0x57000043) //RTCcontrol
嵌入式系統編程,要求程序員能夠利用 C語言訪問固定的內存地址。既然是個地址,那麼按
照 C語言的語法規則,這個表示地址的量應該是指針類型。所以,知道要訪問的內存地址後,
比如0x57000043,
第一步是要把它強制轉換爲指針類型
(unsigned char *)0x57000043, s3c2410的rRTCCON是單字節訪問的(怎麼看出來的???
我無法理解),所以 0x57000043 強制轉換爲指向 unsigned char類型。
volatile(可變的)這個關鍵字說明這變量可能會被意想不到地改變,這樣編譯器就不
會去假設這個變量的值了。這種“意想不到地改變”,不是由程序去改變,而是由硬件去改
變——意想不到。
第二步,對指針變量解引用,就能操作指針所指向的地址的內容了
*(volatileunsigned char *)0x57000043
第三步,小心地把#define宏中的參數用括號括起來,這是一個很好的習慣。
在嵌入式系統中經常使用到 Volatile,對於volatile的用法
編譯器對代碼的優化是指:
CPU 在執行的過程中,因爲訪問內存的速度遠沒有 cpu的執行速度快,爲了提高效率,引入了
高速緩存 cache. C編譯器在編譯時如果不知道變量會被其它外部因素(操作系統、硬件或者
其它線程)修改,那麼就會對該變量進行標識,即優化.那麼這個變量在CPU的執行過程中,就
會被放到高速緩存 cache 去,進而達到對變量的快速訪問.在瞭解了優化的概念後,試想如
果我們事先就知道該變量會被外部因素改變,那麼我們就在這個變量定義前加上Volatile,
這樣編譯器就不會對該變量進行優化.這樣該變量在 cpu處理的過程當中,就不會被放到高
速緩存 cache中。
爲什麼要讓變量在執行的過程中不被放到 cache中去呢?
如果變量是被外部因素改變,那麼 cpu就無法判斷出這個變量已經被改變,那麼程序在執行
的過程中如果使用到該變量,還會繼續使用 cache中的變量,但是這個變量其實已經被改變
了.需要到內存地址中更新其內容了.
還有一個原因,在一些寄存器變量或數據端口的使用中,因爲寄存器變量本身也是靠cache
來處理,爲了避免引起錯誤,也可以使用volatile修飾符.
簡單的說使用volatile的目的就是:
讓對 volatile變量的存取不能緩存到寄存器,每次使用時需要重新存取。
參考閱讀:
http://hi.baidu.com/hustor/item/e4e90d17a68b883ab93180d9