220 likes | 335 Vues
Chapter 5 - Interrupts. Interrupts and Exceptions. 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.
E N D
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.
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
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: • 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. • 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 GroupPriority 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. • 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.
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
Interrupt Service Macro • A more compact alternative using the pre-defined macro: __ISR( v, ipl) • Example: void __ISR( 0, ipl1) InterruptHandler (void) { // interrupt service routine code here... } // interrupt handler
“int.h” Support Functions & Macros • INTEnableSystemSingleVectoredInt(); • 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. • INTEnableSystemMultiVectoredInt(); • Same as the above, but enables the vectored interrupt management mode of the PIC32. • mXXSetIntPriority( x); • 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.
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
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
Nesting.c Example (cont.) main() { // 4. init timers PR3 = 20; PR2 = 15; T3CON = 0x8030; T2CON = 0x8030; // 5. init interrupts mT2SetIntPriority( 1); mT3SetIntPriority( 3); INTEnableSystemSingleVectoredInt(); mT2IntEnable( 1); mT3IntEnable( 1); // main loop while( 1); } // main
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
Multiple.c Example (cont.) main() { // 5. init timers PR3 = 20; PR2 = 15; T3CON = 0x8030; T2CON = 0x8030; // 6. init interrupts mT2SetIntPriority( 1); mT3SetIntPriority( 7); INTEnableSystemMultiVectoredInt(); mT2IntEnable( 1); mT3IntEnable( 1); // 7. main loop while( 1); } // main
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
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
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 cyclesPR1 = 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.
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
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