0

Consider the following example:

int i { 0 };

void incInt() {
    ++i;
}

int readInt() {
    return i;
}

setup() {
    Serial.begin(9600);
    attachInterrupt(digitalPinToInterrupt(D1), incInt, CHANGE);
}

loop() {
    noInterrupts();
    int currI = readInt();
    interrupts();

    Serial.println(currI);
}

By wrapping the call to readInt() with noInterrupts() and interrupts() it is ensured that i cannot be changed externally during the execution of readInt(). i also cannot be changed externally during the execution of incInt(), as long as it is only called as ISR (interrupt service routine). Do I still need to declare i as volatile?

Does the situation change if i is accessed directly in the main loop:

loop() {
    noInterrupts();
    int currI = i;
    interrupts();

    Serial.println(currI);
}

In other words: What is the context in which the compiler expects a variable to not be changed externally if it is not declared volatile?

1

Declaring a variable as volatile tells the compiler, that it always has to read the real variable and that it cannot use a cached value. Also the compiler cannot optimize this variable, since it is unknown, when the variable will change. For this it is irrelevant, how you actually read the variable in the main sketch, it only matters, that it get's read. Also this has nothing directly to do with doing the read atomically (with noInterrupts()) (though you only garantee correct values, when doing it)

So yes, you need to declare it volatile, or the compiler might think, that the value doesn't change and optimize it out in some way.

What is the context in which the compiler expects a variable to not be changed externally if it is not declared volatile?

Externally here means outside of the main routine. This covers variables, that get changed in ISRs and also registers, that are changed by hardware (so the register definition in the used core are also volatile). The compiler cannot know, when these changes happen, because they are triggered by the hardware, not by the code. It will try to optimize your sketch (which is a rather complex procedure), and might see, that your variable is never changing in the code (the ISR does not get called from the main sketch, thus the compiler does not see it getting called) and will try to optimize it. To ensure, that your sketch works properly, it is your task to tell the compiler, that this variable can change at any time (so that it does not think the other way). You are doing this by declaring it as volatile

1

Let's forget about atomicity for a moment, which is a separate issue, and assume i is an atomic type (maybe byte or something equivalent). Consider the following code:

void loop()
{
    Serial.println(i);
}

Not so long ago I would have expected this to work just fine on Arduino, as there aren't many ways to compile this function… on its own! However, since version 1.6.10, the IDE enables link-time optimization. This means that the compiler (or rather, the optimizer working within the linker), can see the whole program and notice that setup() and loop() are called from only one function which belongs to the Arduino core:

int main()  // slightly simplified
{
    init();      // Arduino core initialization
    setup();     // User's initialization
    for (;;)
        loop();  // User's loop
}

This makes them perfect candidates for inlining:

int main()
{
    init();      // will likely be inlined too

    // Inlined setup():
    Serial.begin(9600);
    attachInterrupt(digitalPinToInterrupt(D1), incInt, CHANGE);    

    for (;;) {
        // Inlined loop():
        Serial.println(i);
    }
}

Now it should become clearer that repeatedly reading i from memory looks like a waste of time, which can be optimized-out. The for loop then becomes:

register uint8_t cached_i = i;  // save `i' in an internal CPU register
for (;;) {
    // Inlined loop():
    Serial.println(cached_i);
}

And now the program only prints zeros. That's why you need volatile to prevent that optimization.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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