Interrupt Setup Procedure

  1. 1.When using interrupt priority levels, set IPEN and then select the user-assigned priority level for the interrupt source by writing the control bits in the appropriate IPRx control register.
    Important: At a device Reset, the IPRx registers are initialized such that all user interrupt sources are assigned to high priority.
  2. 2.Clear the Interrupt Flag Status bit associated with the peripheral in the associated PIRx STATUS register.
  3. 3.Enable the interrupt source by setting the interrupt enable control bit associated with the source in the appropriate PIEx register.
  4. 4.If the vector table is used (MVECEN = 1), then set up the start address for the Interrupt Vector Table using IVTBASE. See the Interrupt Vector Table Contents section for more details.
  5. 5.Once IVTBASE is written to, set the interrupt enable bits in INTCON0.
  6. 6.An example of setting up interrupts and ISRs using assembly and C can be found in Setting Up Vectored Interrupts Using MPASM and Setting Up Vectored Interrupts Using XC8.

Setting Up Vectored Interrupts Using MPASM

; Each ISR routine must have a predetermined origin otherwise there will be
; an assembly error because the address is not determined until link time
; which is too late to do the divide by 4 math on the address.
; Predetermined addresses must be evenly divisible by 4.

ISRSW CODE 0x3E00
; SW interrupt service code here.        
    BANKSEL    PIR0
    BCF        PIR0, SWIF
    RETFIE     FAST

ISRHLVD    CODE 0x3E40
; HLVD interrupt service code here.
    BANKSEL    PIR0
    BCF        PIR0, HLVDIF    
    RETFIE     FAST

ISROSF    CODE 0x3E60
; OSF interrupt service code here.    
    BANKSEL    PIR0    
    BCF        PIR0, OSFIF
    RETFIE     FAST

IntInit:
    ; Disable all interrupts
    BCF        INTCON0, GIE, ACCESS

    ; Set IVTBASE (optional - default is 0x000008)    
    CLRF        IVTBASEU, ACCESS
    MOVLW       0x3F
    MOVWF       IVTBASEH, ACCESS
    CLRF        IVTBASEL, ACCESS

    ; Clear any interrupt flags before enabling interrupts
    BANKSEL     PIR0
    BCF         PIR0, SWIF
    BCF         PIR0, HLVDIF
    BCF         PIR0, OSFIF

    ; Enable interrupts
    BANKSEL     PIE0
    BSF         PIE0, SWIE
    BSF         PIE0, HLVDIE
    BSF         PIE0, OSFIE

    ; Set interrupt priorities if necessary
    BANKSEL     IPR0    
    BSF         INTCON0, IPEN_INTCON0, ACCESS    ; Enable interrupt priority
    BCF         IPR0, HLVDIP        ; Make HLVD interrupt low priority

    ; Enable interrupts
    BSF         INTCON0, GIEH, ACCESS
    BSF         INTCON0, GIEL, ACCESS

    RETURN 1

; Save SWISR in vector table (IVTBASE+0*2)
ISR1    CODE 0x3F00
        DW    (0x3E40>>2)        ; (SWISR/4)

; Save HLVDISR in vector table (IVTBASE+1*2)
ISR2    CODE 0x3F02    
        DW    (0x3E60>>2)        ; (HLVDISR/4)

; Save CLC2ISR in vector table (IVTBASE+2*2)
ISR3    CODE 0x3F04
        DW    (0x3E00>>2)        ; (OSFISR/4)

Setting Up Vectored Interrupts Using XC8

// NOTE 1: If IVTBASE is changed from its default value of 0x000008, then the
// "base(...)" argument must be provided in the ISR. Otherwise the vector
// table will be placed at 0x0008 by default regardless of the IVTBASE value.

// NOTE 2: When MVECEN=0 and IPEN=1, a separate argument as "high_priority"
// or "low_priority" can be used to distinguish between the two ISRs.
// If the argument is not provided, the ISR is considered high priority
// by default.

// NOTE 3: Multiple interrupts can be handled by the same ISR if they are
// specified in the "irq(...)" argument. Ex: irq(IRQ_SW, IRQ_HLVD)

void __interrupt(irq(IRQ_SW), base(0x3008)) SW_ISR(void)
{
    PIR0bits.SWIF = 0;    // Clear the interrupt flag
    LATCbits.LATC0 ^= 1;    // ISR code goes here
}
void __interrupt(irq(default), base(0x3008)) DEFAULT_ISR(void)
{
    // Unhandled interrupts go here
}
void INTERRUPT_Initialize (void)
{
    INTCON0bits.GIEH = 1;    // Enable high priority interrupts
    INTCON0bits.GIEL = 1;    // Enable low priority interrupts    
    INTCON0bits.IPEN = 1;    // Enable interrupt priority
    PIE0bits.SWIE = 1;     // Enable SW interrupt
    PIE0bits.HLVDIE = 1;     // Enable HLVD interrupt
    IPR0bits.SWIP = 0;     // Make SW interrupt low priority

    // Change IVTBASE if required
    IVTBASEU = 0x00;          // Optional
    IVTBASEH = 0x30;          // Default is 0x000008
    IVTBASEL = 0x08;
}