Going NAKED

Hi,

I want to look at the minimum overhead of using an ISR to adjust PWM duty cycle to control some external hardware. The basic task is just to output a byte value calculated elsewhere in the program.

I'm hoping to get this fast enough so that it won't disrupt SPI comm to SD using SDlib

volatile byte pwm=0;

ISR (TIMER2_OVF_vect,ISR_NAKED) {
  OCR2B=pwm;
  reti();
}

compiles to

00000248 <__vector_9>:
     248:       80 91 7c 07     lds     r24, 0x077C
     24c:       80 93 b4 00     sts     0x00B4, r24
     250:       18 95           reti

So I need to save/restore r24 and SREG

The normal ISR compiles to this:

00000248 <__vector_9>:
     248:       1f 92           push    r1
     24a:       0f 92           push    r0
     24c:       0f b6           in      r0, 0x3f        ; 63
     24e:       0f 92           push    r0
     250:       11 24           eor     r1, r1
     252:       8f 93           push    r24
     254:       80 91 7c 07     lds     r24, 0x077C
     258:       80 93 b4 00     sts     0x00B4, r24
     25c:       8f 91           pop     r24
     25e:       0f 90           pop     r0
     260:       0f be           out     0x3f, r0        ; 63
     262:       0f 90           pop     r0
     264:       1f 90           pop     r1
     266:       18 95           reti

already quite efficient However, I don't think r0 is relevant to lds and sts so saving and restoring is wasteful. Equally, I don't need to push and pop the SREG value, it will still be in r0.

With the help of Nick's article here:

I calculate that means I could save two push/pop pairs and the eor = 9 cycles out of 23 (not counting entry/exit overhead of 7. A worthwhile saving.

I think that leaves me with a hit of 21 cycles (1.3 us) to change PWM duty.

Anything I've missed ?

thanks.

LDS/STS don't change the status register, so you don't even need to save that.

many thanks, I had wondered about whether it may set a flag if the written value was zero but I had not had time to check it out.

That would mean the following would be sufficient:

      8f 93           push    r24
      80 91 7c 07     lds     r24, 0x077C
      80 93 b4 00     sts     0x00B4, r24
      8f 91           pop     r24   
      18 95           reti

a hand-coded ISR would be a considerable improvement in this case.

Yes, this works fine:

ISR (TIMER2_OVF_vect  ,ISR_NAKED ) {
asm( "push r24         \n\t"
     "lds r24,  new_pwm\n\t"
     "sts 0xB4, r24    \n\t"
     "pop r24          \n\t"
     "reti             \n\t"
);

In fact if I could reserve a register for that variable, I could go the whole way and just do sts and reti.
But that's going OTT unless I have a real hard timing problem.

This is now about 1.2 us, so even firing at about 50kHz , it's an acceptable load.