Question

I am using the Microchip C18 compiler and on occurrence of an interrupt I am experiencing a quite long delay before the ISR code starts running.

As an experiment, this is in my main function:

while(1)
{
    LATAbits.LATA4 = 1;
    LATAbits.LATA4 = 0;
}

As interrupt handler I am using this code I copied from some example (I don't know why it's done this way):

#pragma interrupt high_isr
void high_isr(void)
{
    LATAbits.LATA4 = 1;
    LATAbits.LATA4 = 1;
    LATAbits.LATA4 = 0;
    LATAbits.LATA4 = 1;
    LATAbits.LATA4 = 1;
    LATAbits.LATA4 = 0;
}

#pragma code high_vector=0x08
void interrupt_at_high_vector(void)
{
_asm GOTO high_isr _endasm
}

I am receiving bytes via SPI and shortly after a byte is received, the main loop stops. Then a delay of 16.5 µs follows before the ISR code starts running. That is 165 instruction cycles!

interrupt timing enlarge image

I know there is some context saving associated with interrupts and that it's even worse with low priority interrupts. I have disabled IPEN and I am using only the high priority vector. Is 165 instructions a normal duration for context saving?

Was it helpful?

Solution

Under some circumstances interrupt overhead can be great as yours!
Take a look at this.

OTHER TIPS

The key to getting good performance from interrupts on the PIC is to minimize the extent of required context save/restore code required. In many cases, this means writing the time-critical parts of the interrupt handler in machine code. On parts which have at least some unbanked registers that can be devoted to interrupt use (I really dislike Microchip's decision to gobble up most or all of the common bank for FSR2 addressing, instead of allocating e.g. 15 bytes for FSR2 addressing, 7 bytes each for FSR0 and FSR1 addressing, and one "magic manipulation" register for each FSR [I'd love to chat about ideas for such things]) it's sometimes possible to get by without any context save/restore in the common case. For example, in one of my 14-bit PIC projects, I needed an interrupt every 1000 clock cycles. So with RTCC prescalar disabled, my interrupt was something like:

INTERRUPT_ENTRY:
  bcf    INTCON,TMR0IF
  decfsz int_counter,f
   retfie
  movwf  saveW
  movf   STATUS,w
  clrf   STATUS  ; Bank 0
  movwf  saveStat
  movlw  4
  movwf  int_counter
  movlw  1024+3-1000  ' TMR0 unadjusted time, plus 3 'slip', minus desired time
  addwf  TMR0,f
  bsf    INTCON,GIE ; Interrupts can safely nest after this point!
  ... other interrupt stuff
  movf   saveStat,w
  movwf  STATUS
  swapf  saveW
  retfie ; Could just as well use RETURN, since interrupts are enabled  

Note that 3/4 of the time, an interrupt will return after executing a whopping total of three instructions, taking a total of about 6 cycles from whatever code was executing underneath.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top