Arduino Stack Exchange is a question and answer site for developers of open-source hardware and software that is compatible with Arduino. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

It's clearly documented that when global data is shared with an ISR and the main program, the data needs to be declared volatile in order to guarantee memory visibility (and that only suffices for 1-byte data; anything bigger needs special arrangements to guarantee also atomicity). Here we have good rules:

  • Variables only used outside an ISR should not be volatile.
  • Variables only used inside an ISR should not be volatile.
  • Variables used both inside and outside an ISR should be volatile.

But is volatile needed when the variable is accessed from > 1 ISRs, but not shared outside ISRs? For example, I have a function that maintains internal state using a static variable:

void func() {
    static volatile long counter; // volatile or not?
    // Do stuff with counter etc.

That function is called in two ways: from pin interrupt, and from TimerOne library:

  1. attachInterrupt(0, func, CHANGE);
  2. Timer1.attachInterrupt(func);

There are no atomicity problems, since when an ISR is entered, interrupts are automatically disabled, but this volatile is more of a compiler question: what is cached and what is not.

Better safe than sorry, of course...

share|improve this question
up vote 9 down vote accepted

volatile only informs the compiler's code generator that the variable may be modified by something other than the code being generated, so not to assume any copy of it remains accurate.

ISR code must be written/generated under the assumption that it has no context at entry, and preserve the CPU's context around its (ISR's) own operation. So, as with the indivisbility of non-atomic operations, volatility depends, in this case*, on whether or not interrupts are allowed to nest. If non-nesting is guaranteed, the shared variable can not change by other than this ISR during its own execution. If your ISR might someday be used in an environment where interrupts are allowed to nest, then that constraint will no longer hold.

* in this case:
I'm assuming a software-maintained variable here. If we're talking about a variable that can be updated by a hardware event, a timer register for example, all bets are off: the variable is volatile no matter what.

share|improve this answer
So, as long as I don't change Arduino's default "interrupts don't nest" behavior, then the variable doesn't need to be volatile, since it's not modified by anything other than the code being generated; compiler can "assume" that the ISR executes linearly, and it does, as long as interrupts don't nest. That makes sense. Thanks! – Joonas Pulakka Jun 2 '14 at 12:41

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.