Why Use volatile in Embedded C: Explanation and Examples
volatile tells the compiler that a variable can change unexpectedly, so it must not optimize or cache its value. This is crucial for hardware registers or variables shared with interrupts, ensuring the program always reads the latest value.How It Works
Imagine you have a mailbox that can be changed by someone else at any time, like a hardware device or an interrupt. If you keep a note of the mailbox content and never check it again, you might miss new letters. The volatile keyword tells the compiler to always check the mailbox directly instead of using a saved note.
Normally, compilers try to be smart and speed up programs by remembering variable values in fast storage (like registers). But for variables linked to hardware or interrupts, their values can change without the program's direct action. volatile stops the compiler from making assumptions and forces it to read the variable fresh every time.
Example
This example shows a variable that might be changed by an interrupt or hardware. Without volatile, the compiler might optimize the loop and never see changes.
#include <stdio.h> #include <stdbool.h> volatile bool flag = false; void interrupt_simulator() { // Simulate an interrupt setting the flag flag = true; } int main() { printf("Waiting for flag...\n"); while (!flag) { // Waiting for flag to become true } printf("Flag detected!\n"); return 0; }
When to Use
Use volatile when a variable can change outside the normal program flow, such as:
- Hardware registers in microcontrollers
- Variables modified by interrupt service routines
- Shared variables in multi-threaded or concurrent environments
Without volatile, the compiler might optimize away necessary reads or writes, causing bugs that are hard to find.
Key Points
- volatile prevents compiler optimizations on variables that can change unexpectedly.
- It ensures the program always reads the current value from memory or hardware.
- Essential for embedded systems interacting with hardware or interrupts.
- Does not make code thread-safe by itself; it only affects compiler behavior.