Here's a quick review of how I do it:
SIG_UART_RECV: ; uart receiver ISR push r31 in r31, __SFR_IO_ADDR(SREG) ; SREG ori r31, 0x80 ; pre-reenable interrupt in the SAVED version push r31 push r30 ... push r24 ; this concludes saving all the useful registers, note that ; the registers are saved in the same order as the entry ; point of rtkSemaphoreV
The previous code saves the registers so we can use them in the ISR. The important trick to note is how I set the I-bit in the saved copy of SREG. This allows me to do tricks later on.
Next, we write code to check if there is room in the UART receive FIFO. If there is enough room, we put the received byte into the FIFO, then perform the following:
rjmp rtkSemphoreVCont
The ISR is not ended with a rti! rtkSemaphoreVCont is
an alternative entry point to V a semaphore. This label is defined
immediately after the registers are saved in the subroutine
rtkSemaphoreV. In other words, we make the ISR just an
alternative front for rtkSemaphoreV. Two things can happen:
rtkSemaphoreV does a normal return. The return code
restores all the registers from the stack and does a normal
ret. However, because we ``doctored'' the saved SREG
earlier, interrupt is re-enabled when we return.
Is this approach ugly? Oh, yes, absolutely! It makes it impossible to write ISRs in C. On the other hand, this approach promotes efficiency in the ISR. If you have complicated stuff to do when a device interrupts, do it in the handling thread and code it in C.
Copyright © 2008-10-25 by Tak Auyeung