|
From: | Dave Hansen |
Subject: | RE: [avr-gcc-list] "Volatile" |
Date: | Fri, 15 Apr 2005 17:47:58 -0400 |
From: Keith Gudger <address@hidden> [...]
Those of us on this list all know the "volatile" drill - it's FAQ #1. This is sort of the same issue, and I'm wondering if the code that "got me" is as obvious as the other volatile stuff. I have a volatile variable, "Flags", that is set and cleared in many routines, including an interrupt. Here is the disassembly for the Flags_Clear function: 00000f3e <Flags_Clear>: f3e: 98 2f mov r25, r24 f40: 90 95 com r25 f42: 80 91 a4 00 lds r24, 0x00A4 f46: 89 23 and r24, r25 ; <- interrupt here f48: 80 93 a4 00 sts 0x00A4, r24 f4c: 08 95 ret The interrupt occured right before f46, and set the flag. The interrupt pushed and popped r24 & r25's values, so when the interrupt returned to f46, the flags were restored to their *previous* state (the flag unset! Ack! I'm screwed!)
You're conflating two separate issues: Atomic access, and the disabling of certain optimizations.
The "volatile" keyword does not guarantee atomic access. Any time a shared variable undergoes a read-modify-write operation that might be interrupted, access to the variable should be protected to ensure the operation isn't interrupted. The simplest thing to do in this case is disable interrupts, e.g.
Disable(); Flags &= ~mask; Enable();A less drastic (but more complex) solution is to disable only those interrupts whose service routines might modify the shared variable.
The "volatile" keyword tells the compiler "I know things about this variable that you don't, so do exactly what I say to do with it, when I say it, no more, no less." For example, given
x = 0; x = 1;The compiler is free to optimize out the first statement unless x is volatile, because it knows the value of 0 isn't used by anyone, and no one could tell. Declaring x volatile tells the compiler, "I can tell." Perhaps x is a hardware register.
Another common situation is something like a flag that gets set in an interrupt service routine, and main-line code that waits for the flag looks like
flag = 0; while (!flag) do_something_else();If flag isn't volatile, the compiler will likely load flag into a register, then test the register in the loop. Declaring flag volatile forces the compiler to read the memory each time through the loop.
HTH, -=Dave
[Prev in Thread] | Current Thread | [Next in Thread] |