Interrupts

The PIC32MX generates interrupt requests in response to interrupt events from peripheral modules. The Interrupt module exists external to the CPU logic and prioritizes the interrupt events before presenting them to the CPU.
The PIC32MX Interrupts module includes the following features :

ISRs are organized in IVT. ISR is defined as a standard function but with the iv directive afterwards which connects the function with specific interrupt vector. For more information on IVT refer to the PIC32 Family Reference Manual.

Configuring Interrupts

The PIC32MX interrupt controller can be configured to operate in one of two modes :

Interrupt Priorities

In the Multi Vector Mode, the user is able to assign a group priority and group subpriority level to each of the interrupt vectors. The user-selectable priority levels range from 1 (the lowest priority) to 7 (the highest).
If an interrupt priority is set to zero, the interrupt vector is disabled for both interrupt and wake-up purposes. Interrupt vectors with a higher priority level preempt lower priority interrupts.

The subpriority will cause that when two interrupts with the same priority are pending, the interrupt with the highest subpriority will be handled first. The user-selectable subpriority levels range from 0 (the lowest subpriority) to 3 (the highest).

Interrupts and Register Sets

The PIC32MX family of devices employs two register sets, a primary register set for normal program execution and a shadow register set for highest priority interrupt processing.

Interrupt Coding Requirements

In order to correctly utilize interrupts and correctly write the ISR code, the user will need to take care of these things :

  1. Write the Interrupt Service Routine. You may use Interrupt Assistant to easily write this routine.
  2. Initialize the module which will generate an interrupt.
  3. Set the correct priority and subpriority for the used module according to the priorities set in the Interrupt Service Routine.
  4. Enable Interrupts.

Interrupt Service Routine

Interrupt service routine is defined in this way :

void interrupt() iv IVT_ADC ilevel 7 ics ICS_SOFT {
  // Interrupt service routine code
}

where :


User can explicitly declare starting interrupt routine address using org directive :

void interrupt() org 0x9D000000 iv IVT_ADC ilevel 7 ics ICS_SOFT {
  // Interrupt service routine code
}

Function Calls from Interrupt

Calling functions from within the interrupt routine is possible. The compiler takes care about the registers being used, both in "interrupt" and in "main" thread, and performs "smart" context-switching between two of them, saving only the registers that have been used in both threads. It is not recommended to use a function call from interrupt. In case of doing that take care of stack depth.

Disable Context Saving

Use the #pragma disablecontextsaving to instruct the compiler not to automatically perform context-switching.
This means that no register will be saved/restored by the compiler on entrance/exit from interrupt service routine, except STATUS, WREG and BSR registers in high priority interrupt ('Fast Register Stack').

This exception can be overrided by placing an asm RETFIE, 0 instruction at the end of the high priority interrupt routine (with redirecting all routine exits to this instruction).
Thus, #pragma disablecontextsaving pragma enables the user to manually write code for saving registers upon entrance and to restore them before exit from interrupt.

Interrupt Example

Here is a simple example of handling the interrupts from Timer1 (if no other interrupts are allowed):

void Timer1_interrupt() iv IVT_TIMER_1 ilevel 7 ics ICS_SRS {
  T1IF_bit = 0;             // Clear T1IF
  LATB = ~ PORTB;           // Invert PORTB
}

void main() {
  AD1PCFG = 0xFFFF;         // Initialize AN pins as digital
  TRISB  = 0;               // initialize PORTB as output
  LATB   = 0xAAAA;          // Initialize PORTB value
  
  TMR1 = 0;                 // reset timer value to zero
  PR1 = 65535;              // Load period register

  T1IP0_bit = 1;            // set interrupt
  T1IP1_bit = 1;            // priority
  T1IP2_bit = 1;            // to 7

  TCKPS0_bit = 1;           // Set Timer Input Clock
  TCKPS1_bit = 1;           // Prescale value to 1:256

  EnableInterrupts();       // Enable all interrupts

  T1IE_bit = 1;             // Enable Timer1 Interrupt
  ON__T1CON_bit = 1;        // Enable Timer1
}

Copyright (c) 2002-2012 mikroElektronika. All rights reserved.
What do you think about this topic ? Send us feedback!
Want more examples and libraries? 
Find them on LibStock - A place for the code