Reputation: 5462
The C Standard mandates that a signal handler may access only objects of type sig_atomic_t
(besides lock-free atomics). Accesses to objects of other types produce UB. An interrupt service routine resembles a signal handler, so this restriction must be obeyed when writing ISRs.
avr-libc's signal.h
is broken in that it does not declare type sig_atomic_t
, though it does declare a variable of that name, of type volatile signed char
. Presumably, that was meant to be a typedef
.
But if you want an ISR to access, say, a systick
counter of type uint32_t
then that would produce UB.
Are there any special precautions / exceptions from the standard that avr-gcc imposes, so that it would be possible to write a strictly conforming ISR?
Upvotes: 1
Views: 270
Reputation: 3918
How to write strictly conforming interrupt service routines (on AVR)
As you tagged the question avr-gcc
, I'll assume GCC1 in the remainder. It's not possible to do it in a performing way due to 2 reasons:
There is no way to write an ISR in a conforming way. avr-gcc uses attributes to implement this.
avr-gcc implements neither atomic types nor atomic builtins (where the latter are compiler specific of course, so you can ignore them for conforming discussion). Even if avr-gcc implemented atomic types, using libatomic would be considered inappropriate due to its resource consumption by most AVR folks. And even the simple atomic accesses that could be performed by the compiler without resorting to lib code are not implemented. Take for example:
int var;
_Atomic int aaa;
int get_var_atomic (void)
{
int v;
__atomic_load (&var, &v, __ATOMIC_SEQ_CST);
return v;
}
int get_var_atomic_n (void)
{
return __atomic_load_n (&var, __ATOMIC_SEQ_CST);
}
int get_aaa (void)
{
return aaa;
}
All three functions will forward to __atomic_load_2
, which does not exists (as of avr-gcc v13), and respective insns don't exist, either. Or more precisely: there are generic versions in libatomic, but bachend avr has libatomic disabled.
So the closest you can do is to use these primitives to implement atomic magic, and also to provide these functions. By its very nature, these functions cannot be inlined. So the only reasonable approach is to implement this in the compiler backend itself, which is somewhere in ./gcc/config/avr/avr.md
2,3.
1 Hence avr-gcc
or avr-g++
and AVR-LibC. Dunno how the situation is for other compiler brands like IAR.
2 You can use the vanilla non-atomic loads and stores code emitters, but you'll have to get an 8-bit tmp reg Rx
so you can
in Rx, SREG
cli
<vanilla-code>
out SREG, Rx
for the simple cases. __tmp_reg__
can't be used here for obvious reasons.
3 I just got ranted for globally switching off IRQs. So if you want to avoid that, you'll have to go the libatomic way and allocate semaphores. No need so say that this is extremely expensive compared to the usual approaches.
Upvotes: 2