Is volatile
needed for a variable that is read&write in main loop, but read-only in ISR?
EDIT: At the moment of writing in main, the ISR is disabled. So, the variable is effectively used atomically.
EDIT: (Very much related):
Is volatile
needed for a variable that is read&write in main loop, but read-only in ISR?
EDIT: At the moment of writing in main, the ISR is disabled. So, the variable is effectively used atomically.
EDIT: (Very much related):
volatile
is a bad way to synchronize access. It is an optimization barrier but not more.
it is not atomic; e.g. when your some_type
is uint64_t
on a platform without native 64 bit datatypes, there might be read only a part. E.g.
main() irq()
/* initialization */
var[0..31] = 4
var[32..63] = 8
/* modificatoin */
var[32..63] = 23
/* read */
a_hi = var[32..64] = 32
a_lo = var[0..31] = 4
var[0..31] = 42
depending on architecture, there might be needed memory barrier operations. E.g. when main
and irq
runs on different cores which have dedicated caches, the irq
will never see the updated value
The first problem requires locking but locking operations usually imply an optimization barrier, so that volatile
is superfluously.
Ditto for the second problem where memory barriers act as an optimization barrier too.
volatile
is useful for implementing access to processor memory (which might change between two reads or have side effects when writing). But usually, it is unneeded and too expensive.
Is volatile needed for a variable that is read&write in main loop, but read-only in ISR?
volatile
is not the issue here, as much as insuring main
loop's writes are not broken apart.
Any changes in main()
without protection from an ISR call, can lead to problems, volatile
or not. Declaring it volatile
does not save code from that issue.
volatile some_type obj;
void ISR() {
foo(obj);
}
int main() {
for (;;) {
// volatile useful here to prevent the assignment from being optimized away.
some_type tmp = bar();
// protect from potential interruption need here.
// Without protection, ISR(),
// doesn't know it is working with a completely written `obj`
obj = tmp;
// release from potential interruption
}
volatile
is useful in both directions, for main()
to know ISR()
may have changed obj
and for main()
to not optimize away assignments.
Yet since ISR()
does not change obj
, so volatile
is not needed.
Declaring obj
atomic
may help - but that is another question.
volatile
, right? –
Filberte int x; x = 1; x = 0;
could omit the x = 1;
unlike volatile int y; y = 1; y = 0;
. Still the write needs to be done atomically, potentially needing a block on a potential ISR()
interrupt. volatile int z; block(); z = 1; unblock(); foo(); block(); z = 0; unblock();
. See also atomic
. –
Spurn © 2022 - 2024 — McMap. All rights reserved.
0
to the corresponding register (TXIE
), write to the variable (the one of the question)(a buffer for UART data), and then enable the interrupt again & start the transmission. After transmitting each character from the buffer, the hardware will fire the ISR (ISR code is written by me) which loads the next character from the buffer to the TX register, until the buffer is completely used. At that point, the code in the ISR will disable the interrupt again by writing to the register. – Filberte