Chapter 5 - Interrupts Interrupts and Exceptions Exception Source Reset and NMI On Chip Debug Memory Region Program Program Cache Error TLB Refill RAM or Program RAM or Program General Exception Interrupt RAM or Program RAM or Program Di Jasio - Programming 32-bit Microcontrollers in C Description Normal Reset and Non Maskable Interrupt entry point. Used by the ICD and EJTAG interfaces to enable in circuit debugging features. Error condition specific to the cache mechanism. Not used on PIC32 as a fixed address translation scheme (FMT) is used is place of a full MMU. All other types of exceptions. The proper interrupt vector. Interrupt Service Functions Interrupt service functions are not supposed to return any value (use type void). No parameter can be passed to the function (use parameter void). They cannot be called directly by other functions. Ideally, they should not call any other function. Di Jasio - Programming 32-bit Microcontrollers in C Sources of Interrupt Among the external sources available for the PIC32MX3, there are: 5 x External pins with level trigger detection 22 x External pins connected to the Change Notification module 5 x Input Capture modules 5 x Output Compare modules 2 x Serial port interfaces (UARTs) 4 x Synchronous serial interfaces (SPI and I2C) 1 x Parallel Master Port Among the internal sources we count: 1 x 32 internal (core) timer 5 x 16-bit Timers 1 x Analog-to-Digital Converter 1 x Analog Comparators module 1 x Real Time Clock and Calendar 1 x Flash controller 1 x Fail Safe Clock Monitor 2 x Software interrupts 4 x DMA channels Di Jasio - Programming 32-bit Microcontrollers in C Interrupt Flags & Priorities The Interrupt Enable bit (typically represented with the name of the interrupt source peripheral followed by the suffix –IE in the device datasheet), a single bit of data: The Interrupt Flag (typically represented with a suffix -IF), a single bit of data: is set each time the specific trigger event is activated, independently of the status of the enable bit. Notice how, once set, it must be cleared (manually) by the user. In other words it must be cleared before exiting the interrupt service routine, or the same interrupt service routine will be immediately called again. The Group Priority Level (typically represented with a suffix -IP). Interrupts can have up to 7 levels of priority (from ipl1 to ipl7). Should two interrupt events occur at the same time, the highest priority event will be served first. When cleared, the specific trigger event is prevented from generating interrupts. When set, it allows the interrupt to be processed. At power on, all interrupt sources are disabled by default. Three bits encode the priority level of each interrupt source. At any given point in time, the PIC32 execution priority level value is kept in the MIPS core status-register. Interrupts with a priority level lower than the current value will be ignored. At power on, all interrupt sources are assigned a default level of ipl0, once more assuring all interrupts are disabled. The Sub-priority Level. Two more bits are allocated to define four more possible levels of priority within a priority group. If two events of the same priority level occur simultaneously, the one with the highest sub-priority will be selected first. Once an interrupt of a given priority group is selected though, any following interrupts of the same level (even if of higher sub-priority) will be ignored until the current interrupt (flag) has been cleared. Di Jasio - Programming 32-bit Microcontrollers in C Interrupt Vectors Table Natural Order 0 (highest) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 … 56 (lowest) Macro Abbreviation CT CS0 CS1 INT0 T1 IC1 OC1 INT1 T2 IC2 OC2 INT2 T3 IC3 OC3 INT3 T4 IC4 OC4 INT4 T5 IC5 OC5 SPI1E SPI1TX SPI1RX U1E U1RX U1TX I2C1B I2C1S I2C1M CN AD1 PMP CMP1 CMP2 SPI2E SPI2TX SPI2RX U2E U2RX U2TX I2C2B I2C2S I2C2M FSCM RTCC DMA0 DMA1 DMA2 DMA3 Di Jasio - Programming 32-bit Microcontrollers in C FCE IRQ Symbol Description _CORE_TIMER_IRQ _CORE_SOFTWARE_0_IRQ _CORE_SOFTWARE_1_IRQ _EXTERNAL_0_IRQ _TIMER_1_IRQ _INPUT_CAPTURE_1_IRQ _OUTPUT_COMPARE_1_IRQ _EXTERNAL_1_IRQ _TIMER_2_IRQ _INPUT_CAPTURE_2_IRQ _OUTPUT_COMPARE_2_IRQ _EXTERNAL_2_IRQ _TIMER_3_IRQ _INPUT_CAPTURE_3_IRQ _OUTPUT_COMPARE_3_IRQ _EXTERNAL_3_IRQ _TIMER_4_IRQ _INPUT_CAPTURE_4_IRQ _OUTPUT_COMPARE_4_IRQ _EXTERNAL_4_IRQ _TIMER_5_IRQ _INPUT_CAPTURE_5_IRQ _OUTPUT_COMPARE_5_IRQ _SPI1_ERR_IRQ _SPI1_TX_IRQ _SPI1_RX_IRQ _UART1_ERR_IRQ _UART1_RX_IRQ _UART1_TX_IRQ _I2C1_BUS_IRQ _I2C1_SLAVE_IRQ _I2C1_MASTER_IRQ _CHANGE_NOTICE_IRQ _ADC_IRQ _PMP_IRQ _COMPARATOR_1_IRQ _COMPARATOR_2_IRQ _SPI2_ERR_IRQ _SPI2_TX_IRQ _SPI2_RX_IRQ _UART2_ERR_IRQ _UART2_RX_IRQ _UART2_TX_IRQ _I2C2_BUS_IRQ _I2C2_SLAVE_IRQ _I2C2_MASTER_IRQ _FAIL_SAFE_MONITOR_IRQ _RTCC_IRQ _DMA0_IRQ _DMA1_IRQ _DMA2_IRQ _DMA3_IRQ Core Timer Interrupt Core Software Interrupt 0 Core Software Interrupt 1 External Interrupt 0 Timer 1 Interrupt Input Capture 1 Interrupt Output Compare 1 Interrupt External Interrupt 1 Timer 2 Interrupt Input Capture 2 Interrupt Output Compare 2 Interrupt External Interrupt 2 Timer 3 Interrupt Input Capture 3 Interrupt Output Compare 3 Interrupt External Interrupt 3 Timer 4 Interrupt Input Capture 4 Interrupt Output Compare 4 Interrupt External Interrupt 4 Timer 5 Interrupt Input Capture 5 Interrupt Output Compare 5 Interrupt SPI 1 Fault SPI 1 Transfer Done SPI 1 Receiver Done UART 1 Error UART 1 Receiver UART 1 Transmitter I2C 1 Bus Collision Event I2C 1 Slave Event I2C 1 Master Event Input Change Interrupt ADC Convert Done Parallel Master Port Interrupt Comparator 1 Interrupt Comparator 2 Interrupt SPI 2 Fault SPI 2 Transfer Done SPI 2 Receiver Done UART 2 Error UART 2 Receiver UART 2 Transmitter I2C 2 Bus Collision Event I2C 2 Slave Event I2C 2 Master Event Fail-safe Clock Monitor Interrupt Real Time Clock Interrupt DMA Channel 0 Interrupt DMA Channel 1 Interrupt DMA Channel 2 Interrupt DMA Channel 3 Interrupt _FLASH_CONTROL_IRQ Flash Control Event Interrupt Handlers in C You can declare an Interrupt handler function in C using one of two syntax options: Example using attributes syntax: void __attribute__ (( interrupt(ipl1),vector(0))) InterruptHandler( void) { // your interrupt service routine code here... } // interrupt handler Example using pragma syntax: #pragma interrupt InterruptHandler ipl1 vector 0 void InterruptHandler( void) { // interrupt service routine code here... } // interrupt handler Di Jasio - Programming 32-bit Microcontrollers in C Interrupt Service Macro A more compact alternative using the predefined macro: __ISR( v, ipl) Example: void __ISR( 0, ipl1) InterruptHandler (void) { // interrupt service routine code here... } // interrupt handler Di Jasio - Programming 32-bit Microcontrollers in C “int.h” Support Functions & Macros INTEnableSystemSingleVectoredInt(); INTEnableSystemMultiVectoredInt(); Same as the above, but enables the vectored interrupt management mode of the PIC32. mXXSetIntPriority( x); This function follows a precise sequence of initialization of the interrupt control module (as prescribed in the device datasheet) so to enable the basic interrupt management mode of the PIC32. This is actually just a placeholder for a long list of similar macros (replace the XX with the interrupt source abbreviations from Interrupt Vector Table to obtain each macro name). It assigns a given priority level (from 0 to 7) to the chosen interrupt source. mXXClearIntFlag(); This represents an entire class of macros that allow us to clear the interrupt flag (–IF bit) of the chosen interrupt source. Di Jasio - Programming 32-bit Microcontrollers in C Single.c Example /* ** Single vector Interrupt test */ #include <plib.h> int count; void __ISR( 0, ipl1) InterruptHandler( void) { count++; mT2ClearIntFlag(); } // interrupt handler main() { // 1. init timers PR2 = 15; T2CON = 0x8030; // 2. init interrupts mT2SetIntPriority( 1); INTEnableSystemSingleVectoredInt(); mT2IntEnable( 1); // 3. main loop while( 1); } // main Di Jasio - Programming 32-bit Microcontrollers in C Simulating “single.c” Di Jasio - Programming 32-bit Microcontrollers in C Nesting.c Example /* ** Single Vector Interrupt Nesting */ #include <plib.h> int count; void __ISR( 0, ipl1) InterruptHandler( void) { // 1. re-enable interrupts immediately (nesting) asm("ei"); // 2. check and serve the highest priority first if ( mT3GetIntFlag()) { count++; // clear the flag and exit mT3ClearIntFlag(); } // _T3 // 3. check and serve the lower priority else if ( mT2GetIntFlag()) { // spend a LOT of time here! while( 1); // before clearing the flag and exiting mT2ClearIntFlag(); } // _T2 } // Interrupt Handler Di Jasio - Programming 32-bit Microcontrollers in C Nesting.c Example (cont.) main() { // 4. PR3 = PR2 = T3CON T2CON init timers 20; 15; = 0x8030; = 0x8030; // 5. init interrupts mT2SetIntPriority( 1); mT3SetIntPriority( 3); INTEnableSystemSingleVectoredInt(); mT2IntEnable( 1); mT3IntEnable( 1); // main loop while( 1); } // main Di Jasio - Programming 32-bit Microcontrollers in C Interrupt Vector Table Vector Number 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 … 44 Vector Symbol _CORE_TIMER_VECTOR _CORE_SOFTWARE_0_VECTOR _CORE_SOFTWARE_1_VECTOR _EXTERNAL_0_VECTOR _TIMER_1_VECTOR _INPUT_CAPTURE_1_VECTOR _OUTPUT_COMPARE_1_VECTOR _EXTERNAL_1_VECTOR _TIMER_2_VECTOR _INPUT_CAPTURE_2_VECTOR _OUTPUT_COMPARE_2_VECTOR _EXTERNAL_2_VECTOR _TIMER_3_VECTOR _INPUT_CAPTURE_3_VECTOR _OUTPUT_COMPARE_3_VECTOR _EXTERNAL_3_VECTOR _TIMER_4_VECTOR _INPUT_CAPTURE_4_VECTOR _OUTPUT_COMPARE_4_VECTOR _EXTERNAL_4_VECTOR _TIMER_5_VECTOR _INPUT_CAPTURE_5_VECTOR _OUTPUT_COMPARE_5_VECTOR _SPI1_VECTOR _UART1_VECTOR _I2C1_VECTOR _CHANGE_NOTICE_VECTOR _ADC_VECTOR _PMP_VECTOR _COMPARATOR_1_VECTOR _COMPARATOR_2_VECTOR _SPI2_VECTOR _UART2_VECTOR _I2C2_VECTOR _FAIL_SAFE_MONITOR_VECTOR _RTCC_VECTOR _DMA0_VECTOR _DMA1_VECTOR _DMA2_VECTOR _DMA3_VECTOR _FCE_VECTOR Di Jasio - Programming 32-bit Microcontrollers in C Notes Groups all three SPI1 interrupts Groups all three UART1 interrupts Groups all I2C1 interrupts Groups all three SPI2 interrupts Groups all three UART2 interrupts Groups all I2C2 interrupts Multiple.c Example /* ** Multiple Vector Interrupt */ #include <plib.h> int count; void __ISR( _TIMER_3_VECTOR, ipl7) T3InterruptHandler( void) { // 1. T3 handler is responsible for incrementing count count++; // 2. clear the flag and exit mT3ClearIntFlag(); } // T3 Interrupt Handler void __ISR( _TIMER_2_VECTOR, ipl1) T2InterruptHandler( void) { // 3. re-enable interrupts immediately (nesting) asm("ei"); // 4. T2 handler code here while( 1); // 5. clear the flag and exit mT2ClearIntFlag(); } // T2 Interrupt Handler Di Jasio - Programming 32-bit Microcontrollers in C Multiple.c Example (cont.) main() { // 5. PR3 = PR2 = T3CON T2CON init timers 20; 15; = 0x8030; = 0x8030; // 6. init interrupts mT2SetIntPriority( 1); mT3SetIntPriority( 7); INTEnableSystemMultiVectoredInt(); mT2IntEnable( 1); mT3IntEnable( 1); // 7. main loop while( 1); } // main Di Jasio - Programming 32-bit Microcontrollers in C A Real Time Clock /* ** A real time clock ** */ #include <plib.h> int dSec = 0; int Sec = 0; int Min = 0; // 1. Timer1 interrupt service routine void __ISR( 0, ipl1) T1Interrupt( void) { // 1.1 increment the tens of a second counter dSec++; if ( dSec > 9) // 10 tens in a second { dSec = 0; Sec++; // increment the seconds counter if ( Sec > 59) // 60 seconds make a minute { Sec = 0; Min++; // increment the minute counter if ( Min > 59)// 59 minutes in an hour Min = 0; } // minutes } // seconds // 1.2 clear the interrupt flag mT1ClearIntFlag(); } //T1Interrupt Di Jasio - Programming 32-bit Microcontrollers in C main() { // 2.1 init I/Os DDPCONbits.JTAGEN = 0; // disable JTAG port TRISA = 0xff00; // set PORTA LSB as output // 2.2 configure Timer1 module PR1 = 25000-1; // set the period register T1CON = 0x8030; // enabled, prescaler 1:256, internal clock // 2.3 init interrupts mT1SetIntPriority( 1); mT1ClearIntFlag(); INTEnableSystemSingleVectoredInt(); mT1IntEnable( 1); // 2.4. main loop while( 1) { // your main code here PORTA = Sec; } // main loop } // main Di Jasio - Programming 32-bit Microcontrollers in C Clock.c Simulation Di Jasio - Programming 32-bit Microcontrollers in C Using the Secondary Oscillator // 1. Timer1 interrupt service routine void __ISR( 0, ipl1) T1Interrupt( void) { // 1.1 Sec++; // increment the seconds counter if ( Sec > 59) // 60 seconds make a minute { Sec = 0; Min++; // increment the minute counter if ( Min > 59)// 59 minutes in an hour Min = 0; } // minutes // 1.2 clear the interrupt flag mT1ClearIntFlag(); } //T1Interrupt Change the period register to generate one interrupt every 32,768 cycles PR1 = 32768-1; // set the period register Change the Timer1 configuration word (the prescaler is not required anymore) T1CON = 0x8002; // enabled, prescaler 1:1, use secondary oscillator NOTE: Unfortunately you will not be able to immediately test this new configuration with the simulator since the secondary oscillator input is not fully supported by MPLAB SIM. Di Jasio - Programming 32-bit Microcontrollers in C Using the RTCC module main() { // 2.1 init I/Os DDPCONbits.JTAGEN = 0; // disable JTAG port TRISA = 0xff00; // set PORTA LSB as output // 2.2 configure RTCC module RtccInit(); // inits the RTCC // set present time rtccTime tm; tm.sec=0x15; tm.min=0x30; tm.hour=01; // set present date rtccDate dt; dt.wday=0; dt.mday=0x15; dt.mon=0x10; dt.year=0x07; RtccSetTimeDate(tm.l, dt.l); // set desired alarm to Feb 29th dt.wday=0; dt.mday=0x29; dt.mon=0x2; RtccSetAlarmTimeDate(tm.l, dt.l); // 2.2 init interrupts, mRTCCSetIntPriority( 1); mRTCCClearIntFlag(); INTEnableSystemSingleVectoredInt(); mRTCCIntEnable( 1); // 2.3. main loop while( 1) { // your main code here // ... } // main loop } // main Di Jasio - Programming 32-bit Microcontrollers in C Using the RTCC module (Cont.) // 1. RTCC interrupt service routine void __ISR( 0, ipl1) RTCCInterrupt( void) { // 1.1 your code here, will be executed only once a year // or once every 365 x 24 x 60 x 60 x 16,000,000 MCU cycles // that is once every 504,576,000,000,000 MCU cycles // 1.2 clear the interrupt flag mRTCCClearIntFlag(); } // RTCCInterrupt Di Jasio - Programming 32-bit Microcontrollers in C