Skip to main content

Command Palette

Search for a command to run...

Volatile Pointers and Volatile Data Types

Updated
•4 min read•View as Markdown

Volatile is a type qualifier in ‘c’ used with variables to instruct the compiler not to invoke any optimization on the variable operation

It tells the compiler that the value of the variable may change at any time with or without the programmer’s consent. So, the compiler turns off optmizing the read-write operations on variables which are declared using volatile kyboard.

Volatile is very much helpful in embedded systems codes.

case 1: Volatile data

Commonly used.

uint8_t volatile my_data;
volatile uint8_t my data;

my_data is a volatile variable of type unsigned int8_t.

case 2: non volatile pointer to volatile data

Commonly used

uint8_t volatile *pStatusReg;

pStatusReg is a non-volatile pointer pointing to volatile data of type unsigned int8_t.

This means that the pointer itself does not change (it's a stable address), but the data at that address can change at any time. This is commonly used for accessing hardware registers, where the value at the memory location can be altered by the hardware without the program's knowledge.

This is a perfect case of accessing memory mapped peripheral registers. Use this syntax generously whenever you are accessing memory mapped registers in your microcontroller code.

case 3: volatile pointer to non volatile data

uint8_t *volatile pStatusReg;

pStatusReg is a volatile pointer pointing to non-volatile data of type unsigned int8_t.

This means the pointer itself can change (it may point to a different address), but the data at the pointed address does not change unexpectedly.

Use Case: This is less common, but you might use it when you need to dynamically change which non-volatile data a pointer refers to while ensuring the data itself is stable.

case 4: volatile pointer to volatile data

uint8_t volatile *volatile pStatusreg;

pStatusReg is a volatile pointer pointing to volatile data of type unsigned int8_t.

This is typically used in situations where both the address of the data and the data itself can be modified by hardware or other external factors. It's less common but can be useful in complex scenarios involving multiple hardware components.

When to use Volatile qualifier?

  1. Memory mapped peripheral registers of the microcontrollerrs

  2. When a global variable is used to share data between the main code and an ISR code

  3. Multiple tasks accessing global variables in an RTOS multi threaded application.

Tricky Questions

  1. Can a parameter be both const and volatile?

    Yes, a parameter can be both const and volatile. The const qualifier indicates that the value pointed to by the parameter cannot be modified, while volatile indicates that the value may change unexpectedly (e.g., due to hardware or interrupts). This is useful in scenarios where you want to ensure that the function does not change the value, but the value itself may be updated by external factors.

  2. Can a pointer be volatile?

    Yes, a pointer can be declared as volatile. When a pointer is marked as volatile, it indicates that the pointer itself may be changed unexpectedly, meaning that the address it points to can be modified by external factors (like hardware). This is important in embedded systems where the address of the resource might be altered outside of the program's control.

  3. What is wrong with the following function?

int square(volatile int *ptr) {
    return *ptr * *ptr;
}

The issue with this function is that dereferencing a volatile pointer multiple times can lead to unintended behavior. Since volatile indicates that the value may change at any moment (e.g., by hardware), the value of *ptr could change between the two dereferences. This could result in inconsistent or incorrect calculations. A better approach would be to store the dereferenced value in a temporary variable.

long square(volatile int *ptr){
    int a;
    a = *ptr;
    return a * a;
}

The issue with this function is that since *ptr is declared as volatile, its value may change unexpectedly between the two dereferences. This means a and b could hold different values, leading to an incorrect result that is not a true square.

A correct approach would be to read the value once and store it in a temporary variable. This ensures that the same value is used for the calculation, preventing potential inconsistencies.

Take Away

  • Volatile Data: Data can change.

  • Non-volatile Pointer to Volatile Data: Pointer stable, data can change.

  • Volatile Pointer to Non-volatile Data: Pointer can change, data stable.

  • Volatile Pointer to Volatile Data: Both pointer and data can change.

Using volatile appropriately ensures that your embedded system code behaves as expected, especially when dealing with hardware registers and interrupts. Always remember to use volatile when accessing memory-mapped registers or data that can be modified by external factors.

In depth explanation of volatile keyword