Am I missing something, are ISRs fundamentally different in the way that registers are preserved ?
Yes.
Let's not just guess, shall we?
Here's a test sketch:
volatile byte a, b, c;
void foo ()
{
a++;
b++;
c++;
}
void setup ()
{
Serial.begin (115200);
}
void loop ()
{
a = 5;
foo ();
b = 6;
foo ();
c = 7;
foo ();
}
This was designed to show the overhead of calling foo three times. However, interestingly, the compiler inlined the lot:
void loop ()
{
a = 5;
foo ();
b = 6;
e2: 86 e0 ldi r24, 0x06 ; 6
e4: 80 93 13 01 sts 0x0113, r24
void loop ();
volatile byte a, b, c;
void foo ()
{
a++;
e8: 80 91 12 01 lds r24, 0x0112
ec: 8f 5f subi r24, 0xFF ; 255
ee: 80 93 12 01 sts 0x0112, r24
b++;
f2: 80 91 13 01 lds r24, 0x0113
f6: 8f 5f subi r24, 0xFF ; 255
f8: 80 93 13 01 sts 0x0113, r24
c++;
fc: 80 91 14 01 lds r24, 0x0114
100: 8f 5f subi r24, 0xFF ; 255
102: 80 93 14 01 sts 0x0114, r24
{
a = 5;
foo ();
b = 6;
foo ();
c = 7;
106: 87 e0 ldi r24, 0x07 ; 7
108: 80 93 14 01 sts 0x0114, r24
void loop ();
volatile byte a, b, c;
void foo ()
{
a++;
10c: 80 91 12 01 lds r24, 0x0112
110: 8f 5f subi r24, 0xFF ; 255
112: 80 93 12 01 sts 0x0112, r24
b++;
116: 80 91 13 01 lds r24, 0x0113
11a: 8f 5f subi r24, 0xFF ; 255
11c: 80 93 13 01 sts 0x0113, r24
c++;
120: 80 91 14 01 lds r24, 0x0114
124: 8f 5f subi r24, 0xFF ; 255
126: 80 93 14 01 sts 0x0114, r24
foo ();
b = 6;
foo ();
c = 7;
foo ();
}
12a: 08 95 ret
0000012c <setup>:
c++;
}
Notice how the code for "foo" is actually inlined into loop in two places? (It worked out that the first call was completely redundant). So you can save yourself the trouble, the compiler is smart enough to do it for you.
And if I add a call to millis(), the code generated for millis() is this:
000001d2 <millis>:
unsigned long millis()
{
unsigned long m;
uint8_t oldSREG = SREG;
1d2: 8f b7 in r24, 0x3f ; 63
// disable interrupts while we read timer0_millis or we might get an
// inconsistent value (e.g. in the middle of a write to timer0_millis)
cli();
1d4: f8 94 cli
m = timer0_millis;
1d6: 20 91 19 01 lds r18, 0x0119
1da: 30 91 1a 01 lds r19, 0x011A
1de: 40 91 1b 01 lds r20, 0x011B
1e2: 50 91 1c 01 lds r21, 0x011C
SREG = oldSREG;
1e6: 8f bf out 0x3f, r24 ; 63
return m;
}
1e8: b9 01 movw r22, r18
1ea: ca 01 movw r24, r20
1ec: 08 95 ret
I can't see a single register there being pushed or popped.
My suggestion still is: don't try to outsmart the compiler. Write simple, readable code.