3: Interrupts

Interrupts allow a microcontroller to recognize certain events, switch which function is being executed upon recognition, and then safely return to the original function after the event has been completed.

Whether you’re waiting for a button press but don’t want to continuously poll the button’s input pin or triggering an alarm when someone breaks an IR beam, you’ll want to use interrupts and do it right.

The file ‘interrupt_vectors.pdf’ is a list of names that are necessary when writing interrupt service routines. Take it to your computer -> Interrupt_Vectors.pdf.

Slideshow:
Fullscreen:
Download:

/* ==========================================================================
* PIC32 Tutorial 3 – Blinking an LED using a Timer: Timers and Interrupt Service Routines
* ===========================================================================
* Rodrigo S. Bismonte II
* with info from the Northwestern Mechatronics Wiki page on the NU32v2
*
*
* Objectives:
* -Toggle an LED attached to pin RD9 when a timer “times-out”
* -Blink an LED attached to pin RD8 when the PROG (RE7) button is pressed
*
* Tutorial covers:
* -Setup I/O ports for digital input and output
* -Setup for a 16-bit timer with overflow interrupts
* -Setup the Interrupt Service Routine (ISR) for when the timer overflows
*
* ======================= NOTES on Interrupts ===============================
*
* Note that most interrupts with microcontrollers are internal interrupts. Most interrupts are not
* triggered by pressing a button or turning a potentiometer but by an internal timer
* overflow (like below) or a serial data buffer being empty internal to the microcontroller.
*
* Most peripherals will have some sort of interrupt that can be enabled or disabled. Refer to
* the the PIC32 datasheet for specific peripherals. Interrupts have seven priorities
* (1-7, the higher number denotes a higher level of priority) and within each priority
* level are four more sub-priorities (0-3).
*
* Multi-vectored interrupts allows the PIC32 to create several ISR’s that are easily nested.
* That is, if in a lower priority ISR and event trigger’s a higher priority ISR, the PIC32 will
* begin to execute the higher priority interrupt and then return to the lower priority one. Note that
* there are also a set of alternate registers called “shadow registers” that store the processor’s
* context while the ISR is being executed. This allows for a smooth and quick return from the ISR.
* Since there are only one set of “shadow registers” and it’s not recommended to perform the swap twice,
* they are only used for interrupts of the highest priority (ipl7). To enable multi-vectored interrupts,
* include the function “INTEnableSystemMultiVectoredInt()”.
*
* Interrupt peripheral functions can be seen in the Peripheral Library Guide (.pdf).
*
* ===================== NOTES on Choosing the Period for the Timer (example)====================
*
* Suppose you wanted your timer to trigger an interrupt 1000 times a second. This is accomplished
* by picking the [period] based on your processor’s frequency (80MHz), your prescaler (8), and
* the largest and smallest value possible for the period (0×0001 or 0xFFFF).
* First, you would find the maximum and minimum amount of interrupts per second.
* max: 80MHz/8/1 = 10,000,000 interrupts for second
* min: 80MHz/8/65535 = 152.5902 interrupts for second
* (use 2^32 or 4294967295 for 32-bit timers)
*
* Then, to get 1000 interrupts a second, we divide the maximum number of interrupts per
* second by the desired interrupt frequency.
* 10,000,000 / 1000 = 10,000, or 0×2710.
* This is the value of [period] that will trigger an interrupt at about 1000 times a second.
*
* Note that this only works if the value that we end up with is within the range possible
* for the [period] parameter. It must be within 0×0001 to 0xFFFF (1 to 65535) for 16-bit
* timers, and 0×00000001 to 0xFFFFFFFF (1 to 2^32 or 4292967295) for 32-bit timers. If it
* is outside of the range, then you will have to choose a different pre-scaler.
*
* ======================== NOTES on Interrupt Service Routines (ISR) ===========================
*
* Whenever an interrupt is generated (be it a timer overflowing, a pin changing states, etc.)
* the program is stalled, and the corresponding Interrupt Service Routine (ISR) is called. After
* the ISR is serviced, the program returns to the point it left off at.
*
* An ISR is written this way:
* void __ISR(vector, iplx) handlerName(void){
* …code to be excecuted
* function to clear the interrupt flag.
* }
* NOTE: the parameter [vector] is the interrupt vector constant defined in the file,
* InterruptVectors.pdf, x is the interrupt priority level, and handlerName is
* the name you gave to your interrupt hander routine. Make sure that the interrupt
* level in the ISR matches the level of the interrupt. To clear the interrupt flag,
* you can use m(xx)ClearIntFlag() or IntClearFlag(peripheral)–where (xx) is
* replaced by the macro flag from page 83 of the PeripheralLibraryGuide.pdf file,
* and peripheral is the corresponding value from the IRQ table.
*
* For example: An ISR for timer2
*
* void __ISR(_TIMER_2_VECTOR, ipl2) handlerForT2(void){
* LATAINV = 0×0001; // toggles an LED in pin RD1
*
* mT2ClearIntFlag(); // clears the timer2 interrupt flag
* }
*
* =====================================================================
*/
#define SYSCLK 80000000L // Give the system’s clock frequency
 
#include <p32xxxx.h> // Include PIC32 specifics header file
#include <plib.h> // Include the PIC32 Peripheral Library
 
int main(void){
 
        SYSTEMConfigPerformance(SYSCLK);
 
        TRISDCLR = 0x0300; // Sets RD8 and RD9 as digital outputs
 
        OpenTimer2( T2_ON | T2_SOURCE_INT | T2_PS_1_256, 0xFFFF);
        // This statement says: turn on timer2 | have it use an internal clock source | have it
        // use a prescaler of 1:256, and use a period of 0xFFFF or 2^16 cycles
 
        // Timer2 as configured would trigger an interrupt at a frequency of (80MHZ/256/65535), or 4.77
        // times a second.
 
        ConfigIntTimer2( T2_INT_ON | T2_INT_PRIOR_2);
        // This statement configured the timer to produce an interrupt with a priority of 2
 
        INTEnableSystemMultiVectoredInt();
        // Use multi-vectored interrupts
 
        while( 1)
        {
                LATDbits.LATD8 = ~PORTEbits.RE7;
                // Similar to digital I/O tutorial. Pressing the PROG button will light the LED
                // that’s connected to pin RD8
        }
 
        return 1;
}
 
// Timer2 Interrupt Service Routine
void __ISR(_TIMER_2_VECTOR, ipl2) handlesTimer2Ints(void){
        // **make sure iplx matches the timer’s interrupt priority level
 
        LATDINV = 0x0200;
        // This statement looks at pin RD9, and latches RD9 the inverse of the current state.
        // In other words, it toggles the LED that is attached to RD9
 
        mT2ClearIntFlag();
        // Clears the interrupt flag so that the program returns to the main loop
} // END Timer2 ISR

Take me home -> pic32_tut3_interrupts.c

One thought on “3: Interrupts

Leave a Reply

Your email address will not be published. Required fields are marked *