Saravana Pandian Annamalai
26 May 2024 Categories: Technology,

This blog is in continuation with our earlier set of articles on interrupt architecture, ARM interrupt handling and ARM Cortex M interrupt handling. Renesas is a leading supplier in automotive domain and one of their offerings is the hugely popular RH850 series of MCU. Based on the V850 core, a 32-bit RISC ISA, the series had many MCUs suitable for different applications including body control, telematics, instrument clusters and so on. There are multi-core variants too available specially designed for Zonal E/E architecture. Some popular variants include RH850/F1KM-S1, RH850/F1KM-S2, RH850/F1KM-S4, RH850/F1KH-D8, RH850/U2A, RH850/C1M-Ax, RH850/D1M1A, RH850/D1L, RH850/E2H. Offered over different CPU core structures such as single, multiple, lock-step, and combination, RH850 MCUs enable high-performance and/or high-reliability requirements helping achieve ASIL-D level.

Following our discussions on interrupt architecture, ARM interrupt handling, ARM Cortex M interrupt handling and Renesas RH850, let us explore interrupt handling in one of the most used microcontroller architectures - PIC. As we have seen earlier, interrupts are a fundamental concept in embedded systems, and understanding how to effectively manage them is crucial for developing robust and efficient applications.

In this article, we'll dive deep into the world of PIC MCUs, exploring the various families, and the intricacies of interrupt handling. Whether you're a seasoned embedded engineer or just starting your journey in the world of PIC MCUs, this guide will provide you with the knowledge and insights you need to master interrupt handling.

Overview of the Microchip PIC Architecture

The PIC16 family represents the baseline PIC MCUs, offering a simple and cost-effective solution for basic control applications. These MCUs are characterized by their limited peripheral set, straightforward interrupt handling, and relatively low performance.

The PIC18 family, also known as the enhanced mid-range PIC MCUs, provides more advanced features and capabilities compared to the PIC16 family. These MCUs offer improved performance, expanded peripheral sets, and more sophisticated interrupt handling mechanisms.

Moving up the performance ladder, the PIC24 family introduces 16-bit PIC MCUs. These MCUs offer increased computational power, expanded memory, and a richer peripheral set, making them well-suited for applications that require more advanced processing capabilities.

The dsPIC33 family, also known as the digital signal controllers (DSCs), are designed for applications that require digital signal processing (DSP) capabilities. These MCUs combine the core features of the PIC24 family with dedicated DSP instructions and hardware, making them a powerful choice for applications such as motor control, power conversion, and audio processing.

At the high-end of the PIC MCU spectrum, we have the PIC32 family, which features 32-bit MCUs. These MCUs deliver exceptional performance, large memory capacities, and advanced peripheral sets, catering to the needs of more demanding applications.

Interrupt Handling in Baseline PIC MCUs

Interrupt handling in baseline PIC MCUs, such as the PIC16 family, is relatively straightforward. These MCUs typically have a limited number of interrupt sources, and the interrupt handling mechanism is based on a simple priority-based system. When an interrupt occurs, the processor suspends the current execution and jumps to a single specific interrupt service routine (ISR) where the software needs to identify the triggered interrupt source and perform processing.

In the PIC16 family, the interrupt handling process involves the following steps:

  1. The interrupt flag is set, indicating the occurrence of an interrupt.
  2. The processor checks the interrupt enable bits to determine if the interrupt is enabled.
  3. If the interrupt is enabled, the processor saves the current program counter and status information, and jumps to the corresponding ISR.
  4. The ISR validates all the interrupt sources and services them one by one.
  5. Before returning to the main program, the ISR restores the saved program counter and status information.

This straightforward interrupt handling mechanism in baseline PIC MCUs can be easily implemented using __interrupt() specifier as given below.

void __interrupt global_isr()
{
    if(…) //interrupt 1 source enabled
    {
        //Reset the interrupt flag and perform operations
        …
        
    }
    else if(...) //Check next interrupt source
    {
    }	
        
}

Based on the variants, some of the registers are automatically stored and restored when entering and exiting ISR. Rest of the registers used by the software code must be explicitly stored by the compiler.

High/Low Priority Interrupt Handling in PIC18

The PIC18 family, as the enhanced mid-range PIC MCUs, introduces a more sophisticated interrupt handling mechanism compared to the baseline PIC16 family. One of the key advancements in the PIC18 family is the support for high and low-priority interrupt handling.

In the PIC18 MCUs, interrupt sources are divided into two priority levels: high priority and low priority. This prioritization allows the processor to respond more quickly to critical interrupt events, while still maintaining responsiveness to lower-priority interrupts.
The high/low priority interrupt handling in PIC18 MCUs works as follows:

  1. When an interrupt occurs, the processor checks the interrupt priority level.
  2. If the interrupt is a high-priority event, the processor suspends the current execution and jumps to the high-priority ISR.
  3. If the interrupt is a low-priority event and a high-priority ISR is not currently executing, the processor jumps to the low-priority ISR.
  4. If a high-priority ISR is already executing, the low-priority interrupt is temporarily held until the high-priority ISR completes.
  5. Before returning to the main program, the ISR restores the saved program counter and status information.

Similar to example shown in the last section, here we can define 2 ISRs.

void __interrupt(high_priority) ISR_High_Prio(void)
{
	if(…) //interrupt 1 source enabled
    {
        //Reset the interrupt flag and perform operations
        …
        
    }
    else if(...) //Check next interrupt source
    {
    }	
        

}

void __interrupt(low_priority) ISR_Low_Prio(void)
{
if(…) //interrupt 1 source enabled
    {
        //Reset the interrupt flag and perform operations
        …
        
    }
    else if(...) //Check next interrupt source
    {
    }	
        
}

The directives low_priority /__ low_priority and high_priority/__ high_priority places the ISRs at vector locations 0x18 and 0x08 respectively.

VIC-based Interrupt Handling in Advanced PIC18

The PIC18 family, as the enhanced mid-range PIC MCUs, also features an advanced interrupt handling mechanism known as the Vector Interrupt Controller (VIC)-based interrupt handling. This system, found in select PIC18 MCUs, provides a more sophisticated and efficient way to manage multiple interrupt sources. Each interrupt source is assigned a unique vector address and interrupt service routines configured for each of them.

The high-level vector interrupt state machine is captured below.

PIC18F42 Vector Interrupt State Machine

PIC18F42 Vector Interrupt State Machine


As with lower models, it supports configurable high priority and low priority levels with the vector base address configurable with a dedicated IVTBASE Address Register. Further access to it can be disabled via the IVTLOCK register.

Vectored Interrupts in PIC MCUs

Vectored interrupts provide a more structured and efficient approach to interrupt handling compared to the simple priority-based system found in the baseline PIC16 and PIC18 MCUs. In a vectored interrupt system, each interrupt source is assigned a unique vector address, which corresponds to the starting address of the associated ISR.
In this model, the ISR looks like this.

void __interrupt(irq(...), base(...), priority) ISR_NAME(void)
{
    // Clear appropriate interrupt flag(s)
    // Interrupt handler code follows
}

where the irq specifies the vector number, base the base address of IVT and priority being high_priority or low_priority.

When an interrupt occurs, the processor automatically jumps to the appropriate ISR based on the interrupt vector, eliminating the need for the processor to manually determine the interrupt source and jump to the corresponding ISR. This streamlined process reduces the overhead associated with interrupt handling, resulting in faster response times and improved overall system performance. It is possible to start servicing within 3 clock cycles of receiving the interrupt.

The introduction of vectored interrupts in the PIC24, dsPIC33, and PIC32 families represents a significant advancement in interrupt handling capabilities, catering to the needs of more sophisticated embedded applications.

Conclusion

In this comprehensive guide, we have explored the world of interrupt handling in Microchip PIC MCUs, from the baseline PIC16 family to the advanced PIC32 and VIC-based PIC18 MCUs. We've discussed the unique features and capabilities of each PIC MCU family, highlighting the evolution of interrupt handling mechanisms as we move up the performance ladder. We will continue to discuss further on embedded firmware interrupt handling in the upcoming articles.

Subscribe to our Blog