Safe to read volatile variables?

Is it safe to reference volatile variables that are being continually updated by interrupt service routines? Or should I stop interrupts, take a copy of the variable then start interrupts again?

Thanks

The purpose of volatile is to prevent the compiler from making optimizations and ruining your code.

For example

boolean quit = false;
void loop(){
  while(quit == false);
}

Now obviously the compiler will look at this and think, well quit = false and quit isnt changed anywhere else, therefore the while loop will be optimized to while(true). But, and this is where volatile comes into play, you know that an interrupt can and will change quit to true. Volatile tells the compiler NOT to optimize code that it is involved in, therefore leaving the while loop alone and not breaking your code.

So back to your question, yes volatile is completely safe to reference anywhere Read Reply #3, including an interrupt. As a matter of fact, whenever using a variable inside an interrupt, it is highly advised that you make it a volatile variable. Read Reply #8

EDIT: Read Below!

Thanks

That makes sense, and I have indeed made all variables referenced within interrupts volatile.

So conversely, if I wish to take a copy of a volatile variable, it's safe to do so without stopping interrupts first?

Edit: What I'm thinking is that if I don't stop interrupts before copying, is it conceivably possible an interrupt could occur during the copy process, resulting in a corrupted variable? e.g. if there are multiple instructions required to copy a 16 or 32 wide.

On an 8-bit processor like the Atmega328 you are safe reading the value if it is a single byte variable. But if it is larger, say an int or long or float, then you should suspend interrupts temporarily while you read the value. Otherwise an interrupt can occur in between reading successive bytes and the variable could change. Doing a read modify write operation (e.g. x += 100), you should still suspend interrupts since one could otherwise occur in between reading and writing the variable, even if it is an 8-bit variable.

You know, I have never thought about that before. An interrupt can occur between reading all of the bytes of a variable and cause problems. Thank you for that insight jboyton. So yes, Zaite12, suspend when using 16,32,64 bit variables.

Reply #1 doesn't really address your issue.

The arduinos are single-byte machines. Doing even elementary operations on basic int variables ( 16 bits ) requires a bunch of single-byte operations loading bytes into and out of memory and the cpu registers.

Interrupts can occur at any time. If you are halfway through loading a 16-bit int, and an interrupt occurs, and the interrupt routine changes the value of the int stored in memory, and the interrupt routine completes, and whatever function was running before the interrupt resumes, and loads the second half of the int, which has now changed, then yes, you might get some data corruption.

So your question is a valid and interesting one, and "code optimization" isn't the only issue.

I'm not sure of the correct answer. It is possible to suppress interrupts while dealing with volatile variables, although you rarely see code examples where people actually do this.

One suggestion is to use only single-byte variables in volatile situations, and then the issue of the variable changing when you are halfway through loading it, won't arise, because loading or storing or comparing a single-byte variable is a single cpu operation.

Thanks for the replies, much appreciated

I'm dealing with remote control PWM rising and falling edges and the timing is wider than 8 bits.

It makes sense to stop interrupts when dealing with 16/32/64 bit variables, although presumably there is a risk a rising/falling edge interrupt may be missed while the copy instructions are executed? It's not a huge problem if one gets missed but not ideal. And of course the stars and planets may align and 1,2,3 successive interrupts could get missed too.

Is there a way to queue up interrupts instead of stopping them entirely?

Zaite12:
Is there a way to queue up interrupts instead of stopping them entirely?

The processor queues them for you. It won't forget.

For that matter, you could end up with interrupts temporarily disabled by another interrupt occurring. For example, once every 1024 microseconds timer 0 overflows and generates an interrupt which is handled by the system code.

If you want more precise timing, route the signal in question into the input capture pin for a 16-bit timer. That will latch the time of arrival of the edge as well as generate an interrupt. When you finally get to the interrupt routine you just read the value that was latched. With this approach you can time an edge to within one clock cycle, or 62.5ns on a 16MHz processor.

michinyon:
One suggestion is to use only single-byte variables in volatile situations, and then the issue of the variable changing when you are halfway through loading it, won't arise, because loading or storing or comparing a single-byte variable is a single cpu operation.

Contrary to some earlier advice, you should protect access to volatile variables, outside an ISR, with a noInterrupts() ... interrupts() sequence.

See: Gammon Forum : Electronics : Microprocessors : Interrupts - in particular reply #7 on that page.

Even single-byte variables could be a problem if you update them outside an ISR (eg. adding one) because that is not a single machine instruction.

Is there a way to queue up interrupts instead of stopping them entirely?

Interrupts will be remembered if you stop them. Most interrupting devices set a processor flag which is tested for when interrupts are enabled again. You should not miss interrupts, unless you have them turned off long enough that two or more happen. This is why ISRs should be short, and you turn interrupts off only briefly.

As a matter of fact, whenever using a variable inside an interrupt, it is highly advised that you make it a volatile variable.

Variables purely inside an interrupt don't need to be volatile. Only ones used both inside and outside an interrupt. Once the ISR starts the compiler won't get confused if variables (only used by the ISR) are not volatile. In fact, making them volatile stops the compiler putting variables into registers, which would slow the ISR down.

Its a good idea to arrange your volatiles into two categories - those that are never altered by the
ISR and those that are never altered by the main code body. If you can do that you just have
to protect read or write multi-byte values with a critical section.

In particular a common (bad) idiom you see is this:

volatile byte counter = 0 ;

ISR (???)
{
    counter ++ ;  // ISR does read, modify, write atomically because its an interrupt routine.
}

byte read_counts ()
{
   // should have noInterrupts () here
   byte copy = counter ;    // these two instructions are not atomic
   counter = 0 ;            // these two instructions are not atomic
   // and interrupts() here
   return copy ;
}

This is more safely done this way:

byte last_reading = counter ;

byte read_counts ()
{
  byte copy = counter ; // sample counter, safe as single byte
  byte diff = copy - last_reading ;  // we don't write the volatile, only the ISR does that.
  last_reading = copy ;
  return diff ;
}

The other advantage is that we can use this counter for other purposes - this is exactly
how millis() and micros() are used if you think about it.