user73424: Let's say I want to modify a global variable from inside an interrupt service routine. I must ensure that any variables I modify are volatile. Does it work to use a volatile pointer to data I want to modify if the data itself is not volatile?
In my case the data is a struct, but does the answer change if the data is a class, array, or just a variable?
#include <Arduino.h>

#define PIN_INTERRUPT  2

typedef struct MyStruct
{
    int a_field;
} MyStruct;


MyStruct struct_data;
int array_data[32];

volatile bool _flag_ISR = false;
volatile MyStruct *_struct_ISR = &struct_data;
void myISR()
{
    // just some example stuff
    int read = digitalRead(PIN_INTERRUPT);
    _struct_ISR->a_field = read;
    _arr_data_ISR[4] = read;
    
    _flag_ISR = true;
}

void setup()
{
    attachInterrupt(digitalPinToInterrupt(PIN_INTERRUPT), myISR, CHANGE);
}

void loop()
{
    if (_flag_ISR)
    {
        // do processing here...
        _flag_ISR = false;
    }
}


user7508: First, beware that what you have written is not a volatile pointer, it's
a pointer to volatile data. If you always access the object through this
pointer, you should be fine. If you use the pointer in the ISR, but
access the data directly in the main code (bypassing the volatile
qualifier), then the program could fail.
Consider the following:
void loop()
{
    if (_flag_ISR) {
        _flag_ISR = false;
        Serial.println(struct_data.a_field);
    }
}

Once the compiler inlines the call to loop() from main(), the
main program looks like
int main()
{
    init();  // Arduino core initialization
    setup();
    for (;;) {  // inlined loop()
        if (_flag_ISR) {
            _flag_ISR = false;
            Serial.println(struct_data.a_field);
        }
    }
}

And now, since struct_data is not volatile, the compiler can
legitimately optimize the code by avoiding repeatedly accessing the same
RAM location:
int main()
{
    init();  // Arduino core initialization
    setup();
    register int data_copy = struct_data.a_field;
    for (;;) {  // inlined loop()
        if (_flag_ISR) {
            _flag_ISR = false;
            Serial.println(data_copy);
        }
    }
}

And now the program prints only zeros.

73424: <p>Let's say I want to modify a global variable from inside an <a href="https://www.arduino.cc/reference/en/language/functions/external-interrupts/attachinterrupt/" rel="nofollow noreferrer">interrupt</a> service routine. I must ensure that any variables I modify are volatile. Does it work to use a volatile pointer to data I want to modify if the data itself is not volatile?</p>
<p>In my case the data is a struct, but does the answer change if the data is a class, array, or just a variable?</p>
<pre class="lang-cpp prettyprint-override"><code>#include &lt;Arduino.h&gt;

#define PIN_INTERRUPT  2

typedef struct MyStruct
{
    int a_field;
} MyStruct;


MyStruct struct_data;
int array_data[32];

volatile bool _flag_ISR = false;
volatile MyStruct *_struct_ISR = &amp;struct_data;
void myISR()
{
    // just some example stuff
    int read = digitalRead(PIN_INTERRUPT);
    _struct_ISR-&gt;a_field = read;
    _arr_data_ISR[4] = read;
    
    _flag_ISR = true;
}

void setup()
{
    attachInterrupt(digitalPinToInterrupt(PIN_INTERRUPT), myISR, CHANGE);
}

void loop()
{
    if (_flag_ISR)
    {
        // do processing here...
        _flag_ISR = false;
    }
}
</code></pre>
 7508: <p>First, beware that what you have written is not a volatile pointer, it's
a pointer to volatile data. If you always access the object through this
pointer, you should be fine. If you use the pointer in the ISR, but
access the data directly in the main code (bypassing the <code>volatile</code>
qualifier), then the program could fail.</p>
<p>Consider the following:</p>
<pre class="lang-cpp prettyprint-override"><code>void loop()
{
    if (_flag_ISR) {
        _flag_ISR = false;
        Serial.println(struct_data.a_field);
    }
}
</code></pre>
<p>Once the compiler inlines the call to <code>loop()</code> from <code>main()</code>, the
main program looks like</p>
<pre class="lang-cpp prettyprint-override"><code>int main()
{
    init();  // Arduino core initialization
    setup();
    for (;;) {  // inlined loop()
        if (_flag_ISR) {
            _flag_ISR = false;
            Serial.println(struct_data.a_field);
        }
    }
}
</code></pre>
<p>And now, since <code>struct_data</code> is not volatile, the compiler can
legitimately optimize the code by avoiding repeatedly accessing the same
RAM location:</p>
<pre class="lang-cpp prettyprint-override"><code>int main()
{
    init();  // Arduino core initialization
    setup();
    register int data_copy = struct_data.a_field;
    for (;;) {  // inlined loop()
        if (_flag_ISR) {
            _flag_ISR = false;
            Serial.println(data_copy);
        }
    }
}
</code></pre>
<p>And now the program prints only zeros.</p>
