Is 'volatile' keyword required in this ISR?

I had a ISR routine that did not work until I make a variable volatile and I wonder why. Here is a simplified version of what I did.

ISR (TIMER0_OVF_vect) {
  static volatile byte count = 0;
  count++;
  if (count > 100) {
    digitalWrite(MY_LED, HIGH);
  } else {
    digitalWrite(MY_LED, LOW);
  }
}

Without the volatile keyword, it seems that the counter was not incremented across ISR invocations. How come? Isn't the ISR supposed to flush the count value to memory at some point before it leaves?

Are you using the count variable outside the ISR function?

What are "volatile" variables?

Variables shared between ISR functions and normal functions should be declared "volatile". This tells the compiler that such variables might change at any time, and thus the compiler must reload the variable whenever you reference it, rather than relying upon a copy it might have in a processor register.

I had a ISR routine that did not work until I make a variable volatile and I wonder why

Maybe you are wrong and what makes your code working is the static keyword Static means keep the variable in the stack and don't wash it when the function ends If you are just using the counter variable inside the ISR function then you don't need to declare it has volatile Read this to learn more about interrupts http://www.gammon.com.au/forum/?id=11488

I am familiar with the ‘static’ keyword and its semantic. Just confirmed it again that volatile makes a difference. Below is the actual code I just used. The led turns on with ‘volatile’ and does not turn on without it. I am using Arduino 1.0.5 with this board https://www.sparkfun.com/products/11113

Is this a gcc issue? Anybody can replicate it?

ISR(TIMER2_COMPA_vect)
{
  static volatile byte foo = 0;
  foo++;
  if (foo > 10) {
    // Turn led on.
    PORTB |= (1 << PINB5);
  }
}

Edit: I kept playing with it, looks at objdump and it looks OK (just an extra and redundant lds r24) and now I cannot reproduce it. Am not sure what’s going on. I removed the ‘volatile’ from my code and will report back if will encounter the problem again.

I can't see any good reason "foo" should be declared volatile, but then, Incand't see your code either.

AWOL:
I can’t see any good reason “foo” should be declared volatile, but then, Incand’t see your code either.

I encountered it again and then disappeared. I have the impression that using the ‘save’ button and then recompiling makes the code to work. Now I know better what to look for and how to capture it if it will happen again. Objdump will then solve the mystery, I hope. :wink:

zapta:
I am familiar with the ‘static’ keyword and its semantic. Just confirmed it again that volatile makes a difference. Below is the actual code I just used. The led turns on with ‘volatile’ and does not turn on without it. I am using Arduino 1.0.5 with this board https://www.sparkfun.com/products/11113

Is this a gcc issue? Anybody can replicate it?

ISR(TIMER2_COMPA_vect)

{
 static volatile byte foo = 0;
 foo++;
 if (foo > 10) {
   // Turn led on.
   PORTB |= (1 << PINB5);
 }
}




Edit: I kept playing with it, looks at objdump and it looks OK (just an extra and redundant lds r24) and now I cannot reproduce it. Am not sure what's going on. I removed the 'volatile' from my code and will report back if will encounter the problem again.

I don’t think your code is a good test for what you are asking. Each time there is an interrupt you set foo = 0, then you increment foo by one and then test it’s value. The next time there is an interrupt you again set foo back to 0? How will foo ever get higher then 1?

retrolefty: I don't think your code is a good test for what you are asking. Each time there is an interrupt you set foo = 0, then you increment foo by one and then test it's value. The next time there is an interrupt you again set foo back to 0? How will foo ever get higher then 1?

It's a static variable, not local. Just like variables defined outside of functions but with restricted visibility.

zapta:

retrolefty: I don't think your code is a good test for what you are asking. Each time there is an interrupt you set foo = 0, then you increment foo by one and then test it's value. The next time there is an interrupt you again set foo back to 0? How will foo ever get higher then 1?

It's a static variable, not local. Just like variables defined outside of functions but with restricted visibility.

Yes, but he still sets foo back to zero every time the interrupt is triggered, that can't be correct.

Nope, with the static keyword, the default value is assigned when the variable is initialized, then repeated calls to the function retain their previous value. That's exactly how it should be written.

SirNickity: Nope, with the static keyword, the default value is assigned when the variable is initialized, then repeated calls to the function retain their previous value. That's exactly how it should be written.

How very strange and non-intuitive. Oh well that's why a consider myself a hardware guy. Also maybe why I tend to use as many global variables as I do, they just seem to come with fewer 'rules'. ;)

In the reference section for static they show a usage example:

static int  place;

Maybe the posters explicit making the variable = 0 is what made me think it would be reset every call to the function, where as the reference example just says it's automatically initialized but only on the first call to the function. I guess my next question is how does the run time environment know that it is or is not the first time the function has been called?

Lefty

The runtime environment doesn't need to know. Declaring a variable as static within a function makes it act as if it was declared global (i.e. initialized at bootup) but it is only accessible from within the function.

Pete

retrolefty: I guess my next question is how does the run time environment know that it is or is not the first time the function has been called?

I am not exactly an expert on compilers, but I think static and global variables are given addresses and initial values at compile time. So, there's no reinitialization on function entry. Kinda like a global but with local scope.

Kinda like a global but with local scope

Wrong it's not kinda it's exactly :D.

Mark