What is a normal interrupt latency and context saving time on Microchip C18?
-
27-04-2021 - |
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!
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?
La solution
Under some circumstances interrupt overhead can be great as yours!
Take a look at this.
Autres conseils
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.