avr-gcc-list
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

RE: [avr-gcc-list] "Volatile"


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






reply via email to

[Prev in Thread] Current Thread [Next in Thread]