Struggled with a Bug on My Energy Meter Project
Hello everyone, Good day.
I have been battling a bug for almost 24 hours on my Energy meter project and discovered the bug had to do with the "volatile" keyword. So basically there were some variables I declared to be used as counters, I observed that there were times when the system could transmit data over UART and then blink my LED once the counter reached a particular value. Something like
if(timer2_count > 50)
{
}
The condition becomes true and the block of code gets executed. Other times the block of code does not execute. After doing some research and consulting chat GPT, I discovered that the volatile keyword was not used, which was the issue. Funny enough, while I was using STM32 cube ide I never experienced such an issue, but it became an issue while using vs code. I just declared the variable using the volatile keyword, which has been consistent. Has anyone had such an issue before? I"'d like to hear about our experiences with keywords like volatile
4 Replies
Compilers do have the liberty to rearrange code how they see fit in order to produce optimal executables. Some of these changes related to volatile would be the compiler changing, for example, the order of access of a variable or caching the value of a variable such that for successive reads the value is only fetched for the first read and the cache is used for any subsequent read. Now this sounds neat but there are cases where it becomes undesirable. Imagine a register in your UART changes but the variable you used to track it is cached.
To avoid such nastiness, volatile is used to direct the compiler not to cache the values of the variable. It will generate code to take the value of the given volatile variable from the memory every time it encounters it. This mechanism is used because at any time the value can be modified by the OS or any interrupt. So using volatile will ensure accessing the value afresh every time.
Since you started can you break down volatile pointers and volatile values inside pointers, such as cases where one uses volatile twice.
Certainly.
1. So volatile values are used when the those values can change unexpectedly so we do not want the compiler to make any assumptions about the value of the variable.
2. Non-volatile pointer to volatile values. We can use this to read memory-mapped peripheral registers. We know that the pointer will not change but the values stored at that location change and compilers should not be allowed to make any assumptions and optimize things away.
uint32_t volatile *UART_BASE = (uint32_t *) 0x7200005E;
3. Volatile pointer to non-volatile values. A pointer can change but the value in the memory remains unchanged.
uint32_t *volatile ptr = data
. This can be useful when the pointer address might change in a ISR but the data itself is safe to assume as not changing.
4. Volatile pointer to volatile values. Both the pointer and the value are assumed to change unexpectedly. This can be useful when working in embedded environments where for example dynamic memory may change during runtime.
Intreasting, thank you