As a general concept Global variable ("value") used in ISR function should be declared as volatile to avoid compiler optimization. but my doubt is a global variable is used in sub-function "ISR-SUB" which is invoked in ISR, whether the global variable used sub-function which is invoked in ISR also needs to be declared as volatile ?
unsigned int STATUS; // -----> needs to be declared as volatile ?
void ISR-SUB()
{
STATUS = 1; -->accessed in sub function invoked in ISR which will be optimized or not
}
void ISR ()
{
ISR-SUB();
}
void main()
{
/* interrupt occurred and ISR called */
if (1 == STATUS)
{
code part
}
}
Yes it does.
The function of
volatile
is to tell the compiler that the value of the variable may be read or written at any time without its knowledge. With a normal variable the compiler assumes that it has full information about how and when it is changed.Consider this function to go with your ISR:
If
STATUS
is not markedvolatile
then the compiler is allowed to keep the value ofSTATUS
in a register between the two statements that reference it or even to assume that the if statement will never trigger.A more common pattern would be
You are expecting that the ISR will set
STATUS
to 1 and stop thewhile
loop. However the compiler is allowed to read it once, keep that value in a register and never read it again. It may even only test it once.The complementary problem is
Here the compiler is allowed to not actually write the value of STATUS until the end of the function. So long as it keeps track of what its value should be it can put off writing to the memory location. If your ISR was waiting for
STATUS
to be 3 that would be a problem.Volatile :
this key word is used generally when we are working in embedded hardware system, because the declared variable may be not modified only by our C code but could be modified by our embedded hardware system
For example , if we choose to map the address of our variable to be a part of the address of our external embedded hardware system then we choose as option for our compiler(GCC for example) to make an optimization on the code. What is going to happen if we poll to the value of this variable not declared as volatile to check if it become 1 or not, in fact our compiler will see that we are checking the value of a variable that have always the same address, so it will copy the initial value of our non volatile variable into a temporary internal register to make easy the check and not to take each time the time to go reading the contain of our hardware address.
But what if our embedded hardware system modify the contain of this hardware variable address in this case we will never figure out because the compiler is reading from the temporary register and not the hardware address of our variable and here we figure out how much is important the key word volatile.
Of course you do.
volatile
isn't a prerogative of an ISR, it has a specific definition in the C11 standard:So whenever you control flows in a manner that cannot be deduced from the sources (like when an interrupt occurs), the compiler cannot know that a variable may have changed meanwhile.
You have to use
volatile
to tell it that such variable is subject to change at any moment.If that's too abstract, consider this toy code for the AVR microcontroller:
This gets compiled into this assembly code
As you can see, the variable
STATUS
is read once and updated in the registerr24
, so the loop will never end!Now look at what happens when we use
volatile
This time
STATUS
is read and updated at every iteration, as requested.Note on synchronisation
Many thanks to @Olaf for pointing out the necessity of this section.
I made no claims above that
volatile
is a sufficient condition for whatever the OP is trying to implement (there is simply not enough context to made any claim).The way this answer is to be interpreted is that
volatile
is a necessary condition (as the simple counter-example above shows).The code shown, as said, is a toy example meant to show a simple issue that can arise without
volatile
.It is not meant to be working code because actually I will not work.
When dealing with concurrent flows of execution synchronisation is mandatory and for C this can be achieved using the
stdatomic.h
header and functions.Being this a uC question,
stdatomic.h
may not be present or no synchronisation may be required (this is rare).Just to avoid any misunderstanding: if you have
stdatomic.h
then use it (it will eventually compile to nothing but it made the code portable).The example above contains a RMW operation (the
|=
) that is not atomic can thus cancel the update made by the ISR.So yes, you do need (at least)
volatile
.