dsPIC33A Exception Mechanism
On dsPIC33A, peripheral and external interrupts, traps, system calls, and anything else that can disrupt the normal flow of execution are called "exceptions" and are handled by a single mechanism.
Overview
The interrupt controller is responsible for pre-processing all exception events (traps/interrupts) prior to them being presented to the processor core. The highest level unmasked interrupt request is presented to the processor core, along with a vector number, which represents an offset into the vector table, and the associated priority level.
The interrupt controller has the following key features:
- Six trap vectors and up to 502 interrupt vectors
- Seven user-selectable priority levels
- A unique vector for each interrupt or exception in full Interrupt Vector Table (IVT) mode
- A collapsed vector for all peripheral interrupts in Interrupt Vector Table Collapse (IVTC) mode
- Fixed priority within a specified user priority level
- Configurable base address for IVT
- Supports alternate IVT availability (via IVTBASE)
Simplified Exception Process
When an exception event occurs:
- Hardware (core or peripheral) detects it
- If the programmed priority of the exception event is GREATER THAN the current CPU priority, the current program execution is halted
- The CPU Stacks the SR and PC registers, then switches its current working register context to that of the Interrupt Priority Level (IPL) of the new interrupt
- The CPU executes the Interrupt Service Routine (ISR) using the new register context
When an ISR completes:
- Hardware executes the RETFIE instruction which restores the previously halted program execution (at the preserved CPU register context) at the exact instruction that would have been executed had the exception event not occurred.
CPU Priority
The dsPIC33A CPU can operate at one of 16 priority levels (0-15). An interrupt or trap source must have a set priority level greater than the current CPU priority in order to initiate an exception process.
Priority levels for peripheral and external interrupt sources can be programmed to levels 0-7, while CPU priority levels 8-15 are reserved for trap sources and are fixed.
The CPU priority for the currently executing thread is indicated by the IPL bits in the CPU status register as shown:
Configuring CPU Priority
The IPL bits are automatically controlled by the exception processing logic based on the exception source. You can also manually set the user CPU priority bits (IPL<2:0>) at any time, which is useful for temporarily masking all other interrupts to perform a CPU-intensive task. Additionally, the IPL3 bit is set only by the core and indicates a trap event.
Interrupt Nesting
Interrupts, by default, are nestable. Any ISR that is in progress may be interrupted by another interrupt source having a higher programmed priority level. The following illustration demonstrates a specific scenario involving the main() execution thread along with two ISR threads pre-programmed at varying levels of priority with interrupt nesting enabled:
- t0: CPU priority is 0 and is running the main() execution thread.
- t1: A Level-1 exception is triggered. Since the exception priority (1) is greater than the current CPU priority (0), the Level-1 exception thread is executed.
- t2: A Level-2 exception is triggered. Since the exception priority (2) is greater than the current CPU priority (1), the Level-2 exception thread is executed.
- t3: The Level-2 exception thread completes and issues a RETFIE. The queued Level-1 exception is triggered.
- t4: The Level-1 exception thread completes and issues a RETFIE. The Level-0 (main()) thread's context is popped off the stack (including the saved CPU priority) and the Level-0 thread continues execution.
Types of Exceptions
The exception processing system recognizes two types of exceptions.
Non-Maskable Traps
Traps can be considered as non-maskable, nestable interrupts that adhere to a fixed priority structure. They are intended to detect certain hardware and software problems. The dsPIC33A has six implemented sources of non-maskable traps:
- Bus error trap
- Associated with instruction or data bus access
- Illegal opcode error trap
- Associated with an attempt to execute an illegal opcode
- Address error trap
- Associated with misaligned data word access
- Stack error trap
- Associated with the stack pointer crossing pre-defined limits
- Math error trap
- Associated with a variety of mathematical errors
- Generic trap
- Associated with a variety of events signalled in the INTCON5 register
Peripheral and External Interrupts
These are the regular, maskable interrupt requests that come from a variety of implemented MCU peripherals:
- External Interrupt Pins
- Input Capture/Output Compare
- Communication Interfaces (UART/SPI/I²C)
- Analog I/O (Comparator, ADC/DAC)
Remappable Interrupt Vector Table (RIVT)
Each exception source can trigger the execution of a unique piece of code, called an ISR. Each ISR's start address (also called a vector) is stored in a Remappable Interrupt Vector Table (RIVT) as shown in the accompanying image.
Collapsed Interrupt Vector
The IVT can be collapsed by configuring the IVTC bit within the IVTCREG register. While trap handlers remain unaffected by this setting, all peripheral interrupts are directed to a singular location that follows trap vectors:
Resolving Interrupt Conflicts
Since more than one interrupt request source may be assigned to a specific priority level, a means is provided to resolve priority conflicts within a given user-assigned level.
Each interrupt source has a natural order priority based on its location in the IVT. Lower-numbered vectors have higher natural priority as shown in the accompanying image:
The overall priority level for any pending interrupt source is thus determined:
- First, by the user-assigned priority of that source in the IPCn register,
- Then by the natural order priority within the IVT.
Configuring and Using Interrupts
There are three sets of control bits that need to be considered when working with interrupts:
- Interrupt Flags (IFSx Registers)
- Indicate that an interrupt event has occurred
- Set by the hardware and cleared by the programmer
- Interrupt Enables (IECx Registers)
- Enable or disable individual interrupt sources
- Interrupt Priority bits (IPCx Registers)
- Set the priority of individual interrupt sources
The Flag, Enable, and Priority control bits are used by the interrupt controller to receive/prioritize all exception requests and send a single vector and corresponding IPL to the CPU core as shown in the accompanying image:
Timer Interrupt Example (Timer1)
IECx Register
To enable any interrupt, IEC registers are used. By setting the corresponding bit, the interrupt can be enabled. This diagram depicts the IEC bit location for Timer 1 on the dsPIC33AK128MC106.
IPCx Register
The IPCx registers are used to set the priority of any interrupt. A 3-bit IP field is provided, allowing you to set the priority from 0 to 7. This diagram depicts the IPC6 register locations for Timer1 interrupt on dsPIC33AK128MC106.
IFSx Register
On an occurrence of a specific event, the interrupt’s interrupt flag will be set in the IFSx register. In this example, the Timer1 interrupt flag is in register IFS1 on the dsPIC33AK128MC106.
Persistent Interrupts
Some peripherals generate persistent interrupts.
Persistent interrupts will remain active and the associated interrupt flag (IFSx) set until the issue causing the interrupt is serviced. ISRs for persistent interrupts should clear the interrupt flag after removing the condition that caused the interrupt to ensure that the interrupt flag actually clears.
Refer to the peripheral description in the device data sheet to determine if its associated interrupt is persistent.
Declaring an Interrupt Service Routine
The ANSI-C language specification does not specify how to declare a function as an ISR.
The MPLAB® XC-DSC C compiler defines a special function attribute for declaring an interrupt service routine function, as shown in the accompanying image for the Timer1 interrupt, __attribute__((interrupt)).
Requirements for ISR Functions:
- No parameters
- void return type
- Must use pre-defined ISR function name found in the device data sheet
- Must not be called from main-line code