Volatile and IRSs

I’ve read the reference on the volatile variable qualifier but am unclear about the implications.

A variable should be declared volatile whenever its value can be changed by something beyond the control of the code section in which it appears, such as a concurrently executing thread. In the Arduino, the only place that this is likely to occur is in sections of code associated with interrupts, called an interrupt service routine.

Does this mean that any variable that can change both within and outwith an ISR should be volatile?
And if so, does that apply to all variable types?

Does this mean that any variable that can change both within and outwith an ISR should be volatile?
And if so, does that apply to all variable types?

Yes and yes

From this tutorial:

https://gammon.com.au/interrupts

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.

Thanks.

idrisdraig:
Does this mean that any variable that can change both within and outwith an ISR should be volatile?

If an IRQ reads or writes a variable, make it volatile.

Optimized code won’t copy registers back to variables until finished, 8-bit AVR moves 1 byte at a time… it knows when it is done but the IRQ doesn’t know about the registers, reads the RAM before optimized code updates the value.

GoForSmoke:
If an IRQ reads or writes a non-local variable, make it volatile.

How would an IRQ address a local variable out of scope?

PS - you made me think

My understanding was that if the ISR only reads the variable, and doesn't change it, it doesn't need to be volatile (though, if it's larger than a byte (hence writes are not atomic), you need to briefly disable interrupts while writing it, so the interrupt couldn't fine in the middle of a write, thus getting a crazy value)

The rules for non-local variables and ISRs:
If an ISR writes a variable, and anything else uses it, it must be volatile.
If an ISR reads a variable, and it's more than 1 byte in size, writes need to be made atomic by briefly disabling interrupts.

If the ISR reads RAM at the variable address while a GP register has the working value that won’t be updated till later, what will the ISR get even with bytes?

If an ISR reads a variable, and it's more than 1 byte in size, writes need to be made atomic by briefly disabling interrupts.

Interrupts are automatically disabled when in an ISR so there is no need to disable them. Manipulation of multi byte variables outside of an ISR is, however, another matter

FYI, Arduino - Volatile is an outdated "zombie" version of the Arduino Language Reference. It's unfortunate that doesn't redirect. The current version is here:
https://www.arduino.cc/reference/en/language/variables/variable-scope--qualifiers/volatile/

Someone proposed to add this description for the example sketch on that page:

Use a volatile byte to store the pin state in a single byte:

I disagreed:

the purpose of this code is not to "store the pin state in a single byte". That would happen with or without the use of the volatile keyword. The purpose is to ensure that the compiler doesn't optimize out what it will consider to be the unused state variable.

They responded:

Why would the compiler think the state variable is unused? Isn’t the reason of using volatile here that changes to the variable could be missed? In fact, using volatile in this code example should not make any (functional) difference because loop() only writes the pin after reading the variable, and every change to the variable will cause a pin change in the next loop.

Was I wrong?

Without the volatile keyword the compiler will assume a variable's value can be cached in a machine register
without write-through to memory. The ordinary code and the ISR code could both do this, leading to the
variable having three copies in existence at once, not synced up. Volatile forces all writes to go through
to memory, and all reads to be from memory, so there is only one copy, in memory.

When the compiler does its data-flow analysis in order to assign variables to registers (aka register
colouring), it knows nothing about interrupts, it just looks at the function in hand and assumes its
in sole charge of the processor. Colouring a variable to a machine register is a very common optimization
for variables used in inner-loops.