Volatile keyword with ADC, USB interrupt readings
You need the volatile keyword because a good optimizing compiler will try to reduce memory accesses.  If the variable in question can change outside of what the code is doing to it, or if the pertinent memory location is used as an output, then that's not behavior you want.

The volatile keyword tells the compiler "keep the physical memory up to date, and don't assume that the physical memory stays the same".  There's some detail about exactly where it reads and writes, which you can find in a longer article about this, but that's the essence.

So, this tells you:


If it gets updated by hardware, or if it affects hardware, it needs to be volatile.
If it gets updated or used by an interrupt and used or updated elsewhere, it needs to be volatile.  You can think of an interrupt as "looking like" hardware to the compiler, because it's not within the thread of control that the compiler knows about.
If it's getting used to communicate between threads (as in an RTOS), then it needs to be volatile (and yes, there are RTOS mechanisms for this -- and sometimes  they're the right mechanisms.  When they aren't, and you need to just write to or read from a global -- use volatile).
If it's set and read in the same thread of control, it does not need to be volatile, even if it's global.