Few days back I came across this question, searched web to find complete answer explaining every details. However, the answers were scattered at many places So I thought of accumulating the answers to have complete picture of this question. So lets dive in!
Volatile in C actually came into existence for the purpose of not caching the values of variable automatically. It will tell the machine not to cache the value of this variable. So it will take the value of the given volatile variable from the main memory every time it encounters it. This mechanism is used because at any time the value can be modified by the OS or any interrupt. So using volatile will help us accessing the value afresh every time.
Syntax:
To declare a variable volatile, include keyword volatile before or after the data type:
// Declaration of variable
int volatile foo;
volatile int foo;
Use:
A variable should be declared volatile whenever its value can change unexpectedly. In practice, there are three cases:
- Memory mapped peripheral register
- Global variable modified by ISR
- Global variable in multi-threaded application
Embedded system contains real hardware, usually with sophisticated peripherals. These peripherals contain registers, whose value may change asynchronously with program flow. As a very simple example consider an 8-bit register at address 0x1234. It is required that you poll that register until its status becomes non-zero.
The naive and incorrect implementation is as:
UINT1 *ptr = (UINT1 *)0x1234;
// Wait for register to become non-zero.
while(*ptr == 0);
// Do something
This statement will almost certainly fail, if you turn on the optimizer, Since the compiler will generate assembly that will look something like this:
mov ptr, 0x1234
mov a, @ptr
loop bz loop
The rationale of optimizer is quite simple: having already read the value into the accumulator(second line), there is no need to re-read it. Thus, in third line we end up in infinite loop.
To force the compiler what we want, we modify the declaration to:
UINT1 volatile *ptr = (UINT1 volatile *)0x1234;
// Wait for register to become non-zero.
while(*ptr == 0);
// Do something
The corresponding assembly language now looks like:
mov ptr, 0x1234
loop mov a, @ptr
bz loop
Thus desired behavior is achieved.
Comments
Post a Comment