Volatile variables in ISR context in Embedded C - Time & Space Complexity
When using volatile variables in interrupt service routines (ISRs), it's important to understand how often the code accesses these variables.
We want to see how the number of operations changes as the program runs and interrupts occur.
Analyze the time complexity of the following code snippet.
volatile int flag = 0;
void ISR() {
flag = 1; // Set flag when interrupt occurs
}
int main() {
while (1) {
if (flag) {
flag = 0; // Clear flag
// Handle event
}
}
}
This code sets a volatile flag in an ISR and checks it repeatedly in the main loop.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: The infinite while loop in main repeatedly checks the volatile flag.
- How many times: The loop runs continuously, checking the flag many times per second.
As the program runs longer, the number of flag checks grows proportionally with time.
| Input Size (time units) | Approx. Operations (flag checks) |
|---|---|
| 10 | 10 checks |
| 100 | 100 checks |
| 1000 | 1000 checks |
Pattern observation: The number of operations grows linearly with time spent running the loop.
Time Complexity: O(n)
This means the number of operations grows directly with the length of time the program runs.
[X] Wrong: "The volatile keyword makes the flag check faster or reduces how often it runs."
[OK] Correct: Volatile only tells the compiler not to optimize away the variable; it does not change how often the code runs or how many times the flag is checked.
Understanding how volatile variables behave in loops and ISRs helps you write reliable embedded code and shows you can reason about how code runs over time.
"What if we replaced the volatile flag with a non-volatile variable? How would the time complexity and behavior change?"
Practice
volatile?Solution
Step 1: Understand the role of
Thevolatilevolatilekeyword tells the compiler that the variable's value can change at any time, outside the normal program flow.Step 2: Apply to ISR context
Since ISRs can change variables asynchronously, the compiler must always read the variable fresh, not use cached values.Final Answer:
To tell the compiler the variable can change unexpectedly and prevent optimization errors. -> Option BQuick Check:
Volatile prevents optimization errors in ISR variables = C [OK]
- Thinking volatile makes variable constant
- Assuming volatile allocates more memory
- Believing volatile speeds up code
flag that is modified inside an ISR?Solution
Step 1: Identify the need for volatile
Sinceflagis changed inside an ISR, it must be declaredvolatileto prevent compiler optimizations.Step 2: Check declaration syntax
The correct syntax isvolatile int flag;which tells the compiler to always read the variable fresh.Final Answer:
volatile int flag; -> Option CQuick Check:
ISR-modified variable needs volatile keyword = A [OK]
- Forgetting volatile keyword
- Using const which prevents changes
- Using static without volatile
volatile int flag = 0;
void ISR() {
flag = 1;
}
int main() {
while(flag == 0) {
// wait for flag to change
}
return 0;
}
What will happen if flag was NOT declared volatile?Solution
Step 1: Understand compiler optimization without volatile
Withoutvolatile, the compiler may assumeflagdoes not change in the loop and cache its value.Step 2: Effect on the loop
The loop conditionflag == 0may never be rechecked from memory, causing an infinite loop.Final Answer:
The program may loop forever because the compiler caches flag value. -> Option DQuick Check:
Missing volatile causes infinite loop due to caching = B [OK]
- Thinking program crashes without volatile
- Assuming compile error occurs
- Believing loop exits immediately
int flag = 0;
void ISR() {
flag = 1;
}
int main() {
while(flag == 0) {
// wait
}
return 0;
}Solution
Step 1: Identify variable shared with ISR
The variableflagis modified inside the ISR and read in main.Step 2: Check declaration for optimization safety
Sinceflagis shared, it must be declaredvolatileto prevent the compiler from caching its value.Final Answer:
flag should be declared volatile to avoid optimization issues. -> Option AQuick Check:
Shared ISR variable needs volatile keyword = D [OK]
- Thinking ISR must return a value
- Declaring shared variable const
- Removing the loop instead of fixing volatile
counter incremented inside an ISR and read in the main loop. Which of these is the best way to safely read counter in main without race conditions?Solution
Step 1: Understand volatile role
Declaringcountervolatile ensures main reads fresh value, but does not prevent partial updates during read.Step 2: Prevent race conditions
Disabling interrupts briefly while readingcounterprevents ISR from changing it mid-read, avoiding inconsistent values.Final Answer:
Declare volatile int counter and disable interrupts briefly while reading it in main. -> Option AQuick Check:
Volatile + interrupt disable ensures safe multi-byte read = A [OK]
- Assuming volatile alone prevents race conditions
- Not disabling interrupts during read
- Using const which prevents changes
Ready to prove it?
Pass the test and this pattern moves unknown
