Implimenting Interrupts using MPLAB® Code Configurator

This page discusses how to efficiently code interrupts in applications configured with MPLAB® Code Configurator (MCC).

PIC® MCUs service interrupt requests through interrupt vectors addresses. When an interrupt occurs, the MCU saves the current program's context data, and then 'jumps' to a predetermined address. This predetermined address is referred to as the interrupt vector. (The amount of context data saved and the interrupt vector address(es) used are device and peripheral specific. Please refer to your device's datasheet for details.)


The application developer is responsible for writing an Interrupt Service Routine (ISR) to respond to the interrupt condition. In non-MCC applications, the developer inserts a compiler directive into the source, ensuring the compiler places a jump instruction at the interrupt vector address, whose destination is the application's ISR. At run-time, an interrupt causes non-MCC applications to jump indirectly to the ISR.


When using MCC, an extra jump occurs when servicing interrupts. The code generated by MCC for each interrupt source creates a callback function and places a jump to callback at the interrupt vector. MCC inserts a directive in the code making the interrupt jump to the callback function. The callback function will then jump to the application's developer-written ISR. MCC based projects utilize two jumps before the application's ISR executes.


Why does MCC Interrupt Want to Encourage this Extra Jump?

The MCC's callback mechanism provides a level of abstraction between the code written by the developer and the code generated by MCC.

When a developer uses MCC to configure an interrupt, MCC places the source code defining the callback into the one of the MCC generated project files. With the exception of user-supplied files and main.c, all the MCC files are overwritten each time the programmer makes any change to an MCC configuration and pushes the Generate button. If the user were to input their code into the MCC supplied file, the code would be lost each time the MCC configuration changes. To avoid the consequences of having to re-enter application code and to provide the ability to change an ISR at runtime, MCC utilizes a callback mechanism for the ISR.


How to use the Callback function

To use the callback function, the user-supplied ISR must be registered with the callback function. For each interrupt defined, MCC supplies a function to register the user-generated ISR.

To utilize the callback ISR in MCC the following steps must be taken:

  1. Specify the peripheral interrupt using MCC.
  2. Click the Generate button to generate the MCC code.
  3. Write a function in a file NOT located in the MCC generated section of the project.
  4. Insert the code into the application startup process to register the ISR with the callback function.

Example of Registering a Timer1 interrupt on an 8-bit PIC MCU

When MCC is used to generate an interrupt for Timer1, MCC creates tmr1.c containing all the function calls needed to setup and control interrupts for Timer1. Among the functions created there are two we will talk about:

  • TMR_ISR(void) - the callback function
  • TMR1_SetInterruptHandler(void* InterruptHandler) - the function to register the application ISR with the callback


void TMR1_ISR(void)

    // Clear the TMR1 interrupt flag
    PIR1bits.TMR1IF = 0;

    TMR1H = (timer1ReloadVal >> 8);  //Reset the 8-bit  Timer1 overflow value
    TMR1L = timer1ReloadVal;


void TMR1_SetInterruptHandler(void* InterruptHandler){
    TMR1_InterruptHandler = InterruptHandler;

The user supplies their own application-specific ISR. This ISR function must be located in a non-MCC supplied file such as main.c. An example of an application ISR could be a simple toggling an I/O pin:

void myTimerISR(void);

void myTimerISR(void)

The application's ISR is registered with the callback at run-time. TMR1_SetInterruptHandler must be called with the address of MyTimerISR as the input parameter.

TMR1_SetInterruptHandler (myTimerISR);     //Register the ISR

Completed main.c

The final main.c code is shown below with all the Timer1 Interrupt additions to toggle an IO pin when a Timer1 interrupt occurs.

#include "mcc_generated_files/mcc.h"

void myTimerISR(void);

                         Main application
void main(void)
    // initialize the device

   TMR1_SetInterruptHandler (myTimerISR);     //Register the interrupt Handler

    // When using interrupts,set the Interrupt Enable bits
    // Use the following macros to:

    // Enable the Global Interrupts

    // Enable the Peripheral Interrupts

    while (1)
        // Add your application code

void myTimerISR(void){
 End of File
© 2024 Microchip Technology, Inc.
Notice: ARM and Cortex are the registered trademarks of ARM Limited in the EU and other countries.
Information contained on this site regarding device applications and the like is provided only for your convenience and may be superseded by updates. It is your responsibility to ensure that your application meets with your specifications. MICROCHIP MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND WHETHER EXPRESS OR IMPLIED, WRITTEN OR ORAL, STATUTORY OR OTHERWISE, RELATED TO THE INFORMATION, INCLUDING BUT NOT LIMITED TO ITS CONDITION, QUALITY, PERFORMANCE, MERCHANTABILITY OR FITNESS FOR PURPOSE. Microchip disclaims all liability arising from this information and its use. Use of Microchip devices in life support and/or safety applications is entirely at the buyer's risk, and the buyer agrees to defend, indemnify and hold harmless Microchip from any and all damages, claims, suits, or expenses resulting from such use. No licenses are conveyed, implicitly or otherwise, under any Microchip intellectual property rights.