8.1.4 Tak's solution

My solution is somewhat ugly: resort to assembly programming. But wait, I have justifications:

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:

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