I have a simple function, where all it needs to do is return a volatile multi-byte (uint32_t) global variable. Of course, being prudent, I should use the appropriate mechanisms to access this variable atomically, using ATOMIC_BLOCK. But, it seems inefficient to me to copy the global variable into a local variable inside the atomic block, then return the local one.
So, the question is, can I do the following?
uint32_t get_foo() {
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
return foo; // A global volatile uint32_t
}
}
I understand that ATOMIC_BLOCK uses some macro and compiler magic to ensure that SREG is saved and restored no matter what exit path from the block is taken, but does this apply to a return?
I took a look at the resultant assembly, and I
think it's doing what it should, but I would be happy if someone more knowledgeable of AVR assembler were to look at it and confirm.
00000712 <get_foo>:
712: 2f b7 in r18, 0x3f ; 63
714: f8 94 cli
716: 60 91 03 02 lds r22, 0x0203 ; 0x800203 <foo>
71a: 70 91 04 02 lds r23, 0x0204 ; 0x800204 <foo+0x1>
71e: 80 91 05 02 lds r24, 0x0205 ; 0x800205 <foo+0x2>
722: 90 91 06 02 lds r25, 0x0206 ; 0x800206 <foo+0x3>
726: 2f bf out 0x3f, r18 ; 63
728: 08 95 ret
If I'm understanding this correctly, it's saving SREG in r18, disabling interrupts, copying foo into function return registers, restoring SREG, and finally returning.
If this is all correct and hunky-dory, and follows my intention to atomically access the foo variable, then great.
All I need to do is take care of the compiler warning saying "control reaches end of non-void function". I guess I could whack in a second return statement (that will never be reached) outside the block.