I have some code where interrupt jitter is deal killer. There are just one interrupt source and that need to be as precise as possible. For ATMEGA the max interrupt response is the length of current instruction + call to interrupt routine.
But my code behave erratic. The interrupt delay seems much larger. Finally I find where trouble lies. The GCC disables the interrupt by itself!!! So here is simple example of that. No interrupt usage at all in source code.
#include <avr/io.h>
void DoJob(void){
uint8_t buf[256];
for (uint8_t i = 0; i < 255; i++){
PORTB=buf[i];
buf[i]=PORTB;
}
}
int main(void){
for(;;){
DoJob();
}
}
Now in assembler listing there is surprise. There are CLI instruction to disable the interrupts.
000000cc <DoJob>:
cc: cf 93 push r28
ce: df 93 push r29
d0: cd b7 in r28, 0x3d ; 61
d2: de b7 in r29, 0x3e ; 62
d4: da 95 dec r29
d6: 0f b6 in r0, 0x3f ; 63
d8: f8 94 cli
da: de bf out 0x3e, r29 ; 62
dc: 0f be out 0x3f, r0 ; 63
de: cd bf out 0x3d, r28 ; 61
e0: fe 01 movw r30, r28
e2: 31 96 adiw r30, 0x01 ; 1
e4: ce 01 movw r24, r28
e6: 93 95 inc r25
e8: 21 91 ld r18, Z+
ea: 25 b9 out 0x05, r18 ; 5
ec: 25 b1 in r18, 0x05 ; 5
ee: df 01 movw r26, r30
f0: 11 97 sbiw r26, 0x01 ; 1
f2: 2c 93 st X, r18
f4: e8 17 cp r30, r24
f6: f9 07 cpc r31, r25
f8: b9 f7 brne .-18 ; 0xe8 <DoJob+0x1c>
fa: d3 95 inc r29
fc: 0f b6 in r0, 0x3f ; 63
fe: f8 94 cli
100: de bf out 0x3e, r29 ; 62
102: 0f be out 0x3f, r0 ; 63
104: cd bf out 0x3d, r28 ; 61
106: df 91 pop r29
108: cf 91 pop r28
10a: 08 95 ret
0000010c <main>:
10c: 0e 94 66 00 call 0xcc ; 0xcc <DoJob>
110: fd cf rjmp .-6 ; 0x10c <main>
In this example the solution is simple as just declaring buffer to be global solve the problem. But in real code can't declare all buffers and variables global as there is no space. So how to avoid that and is it there some other situations where compiler WITHOUT KNOWING DISABLE INTERRUPTS? At least warning that compiler do that should be welcome. My system misbehave maybe once per day and it take really long time to find problem.