Thursday, November 1, 2007

volatile, __no_init

DECLARING OBJECTS VOLATILE
There are three main reasons for declaring an object volatile:
● Shared access; the object is shared between several tasks in a multitasking
environment
● Trigger access; as for a memory-mapped SFR where the fact that an access occurs
has an effect
● Modified access; where the contents of the object can change in ways not known to
the compiler.


Variables that are accessed from multiple threads, for example from main or an
interrupt, must be properly marked and have adequate protection, the only exception to
this is a variable that is always read-only.

To mark a variable properly, use the volatile keyword. This informs the compiler,
among other things, that the variable can be changed from other threads. The compiler
will then avoid optimizing on the variable (for example, keeping track of the variable in
registers), will not delay writes to it, and be careful accessing the variable only the
number of times given in the source code.

The object attribute must be placed in front of the type. For example, to place myarray
in memory that is not initialized at startup:
__no_init int myarray[10];

__no_init
Syntax Follows the generic syntax rules for object attributes, see Object attributes, page 169.
Description Use the __no_init keyword to place a data object in non-volatile memory. This means
that the initialization of the variable, for example at system startup, is suppressed.
Example __no_init int myarray[10];


In the following examples, there are two const declared objects, where the first is
initialized to zero, and the second is initialized to a specific value. Both objects are
placed in ROM. This is useful for configuration parameters, which are accessible from
an external interface. Note that in the second case, the compiler is not obliged to actually
read from the variable, because the value is known. To force the compiler to read the
value, declare it volatile:
#pragma location=0x1004
volatile const int beta; /* OK */
volatile const int gamma @ 0x1008 = 3; /* OK */

In the following example, the value is not initialized by the compiler; the value must be
set by other means. The typical use is for configurations where the values are loaded to
ROM separately, or for special function registers that are read-only. To force the
compiler to read the value, declare it volatile:
volatile __no_init const char c @ 0x1004;

The following examples show incorrect usage:
int delta @ 0x100C; /* Error, neither */
/* "__no_init" nor "const".*/
const int epsilon @ 0x1011; /* Error, misaligned.