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...

1 Answer 1


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.

  • 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! Jun 2, 2014 at 12:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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