You are on page 1of 28

Chapter 5

Interrupts

Checklist
The following tools will be used in this lesson:

MPLAB X, Integrated Development Environment


(v1.8 or later, free)
MPLAB XC16, C compiler (v1.11 or later, free)

The following pieces of documentation will be used during this


lesson:

PIC24FJ128GA010 Datasheet DS39747 (latest rev.)

PIC24F Reference Manual Chapter 29. - RTCC


Make sure they are available and/or installed and ready to use on
your computer.
You can download them from Microchip web site at:
http://www.microchip.com/mplabx
And
http://www.microchip.com/xc16
Di Jasio Programming 16-bit Microcontrollers in C (Second Edition)

Interrupt Service Routines

The PIC24 keeps all interrupt vectors in Interrupt Vector


Table (IVT)
MPLAB XC16 compiler automatically associates interrupt
vectors with special user defined C functions as long as
:

They do not 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.

The following example illustrates the syntax that could be


used to associate a function to the Timer1 interrupt
vector:
void __attribute__ (( interrupt)) _T1Interrupt ( void)
{
// interrupt service routine code here...
} // InterruptVector

Di Jasio Programming 16-bit Microcontrollers in C (Second Edition)

The _ISR Macro

In practice, to avoid the verbose syntax


__attribute__ (( interrupt)) it is more convenient
to use the predefined macro _ISR as in the
following example:
void _ISR _T1Interrupt (void)
{
// interrupt service routine code here...
} // _InterruptVector

Di Jasio Programming 16-bit Microcontrollers in C (Second Edition)

PIC24 Interrupt Sources

The PIC24 GA010 family allows for the following list of interrupt
sources:

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 I 2C)
Parallel Master Port
And among the internal sources we count:
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 CRC generator

NOTE: The PIC24F GA1, GB1, DA2 and GB2 families add several more
peripherals sources each capable of generating additional interrupt events,
including: several additional Timers, a USB interface (GBx), and a CTMU or
touch sensing interface.

Di Jasio Programming 16-bit Microcontrollers in C (Second Edition)

PIC24 Interrupt Vector Table

Di Jasio Programming 16-bit Microcontrollers in C (Second Edition)

PIC24 Interrupt Vector Table (cont)

Di Jasio Programming 16-bit Microcontrollers in C (Second Edition)

Interrupt Control

Each interrupt source has 5 associated control bits, allocated in


various special-function registers:

The Interrupt Enable bit (suffix-IE).


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 (suffix IF).
A single bit of data, is set each time the specific trigger event is activated. Once set, it
must be cleared (manually) by the user.
The Priority Level (suffix IP).
Interrupts can have up to 7 levels of priority.
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.
Within an assigned priority level there is also a natural (or default) priority amongst the
various sources in the fixed order of appearance in the IVT table.

The PIC24 current execution priority level is kept in the SR register in


three bits referred to as IPL0..IPL2.
Interrupts with a priority level lower than the current value of IPL will
be ignored.
At power on, all interrupt sources are assigned a default level of 4 and
the processor priority is initially set at level zero.

Di Jasio Programming 16-bit Microcontrollers in C (Second Edition)

Interrupt Nesting

Interrupts can be nested so that a lower priority


interrupt service routine can be, in his turn,
interrupted by a higher priority routine.
This behavior can be changed by the NSTDIS bit in
the INTCON1 register of the PIC24.
When the NSTDIS bit is set, as soon as an interrupt is
received, the priority level of the processor ( IPL) is
set to the highest level (7) independently of the
specific interrupt level assigned to the event.
This prevents new interrupts being serviced until the
present one is completed. In other words when
NSTDIS bit is set, the priority level of each interrupt is
used only to resolve conflicts, in the event that
multiple interrupts should occur simultaneously. In
this case all interrupts will be serviced sequentially.

Di Jasio Programming 16-bit Microcontrollers in C (Second Edition)

Traps

Di Jasio Programming 16-bit Microcontrollers in C (Second Edition)

Template for Using Timer1


main()
{
// 2. initializations
_T1IP = 4;
// this is the default value anyway
TMR1 = 0;
// clear the timer
PR1 = PERIOD-1; // set the period register
// 3. configure Timer1 module
T1CON = 0x8020; // enabled, prescaler 1:64, internal clock
// 4. init the Timer 1 Interrupt control bits
_T1IF = 0;
// clear the interrupt flag, before
_T1IE = 1;
// enable the T1 interrupt source

// 5. main loop
while( 1)
{
// your main code here
} // main loop
} // main

Di Jasio Programming 16-bit Microcontrollers in C (Second Edition)

Template for Using TMR1 (cont)


// 1. Timer1 interrupt service routine
void _ISR _T1Interrupt( void)
{
// insert your code here
// ...
// remember to clear the interrupt flag before exit
_T1IF = 0;
} //T1Interrupt

Di Jasio Programming 16-bit Microcontrollers in C (Second Edition)

Example using Timer1


#include <config.h>
int dSec = 0;
int Sec = 0;
int Min = 0;
// 1. Timer1 interrupt service routine
void _ISR _T1Interrupt( void)
{
// 1.1 your code here
dSec++;
// increment the tens of a second counter
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
_T1IF = 0;
} //T1Interrupt

Di Jasio Programming 16-bit Microcontrollers in C (Second Edition)

main()
{
// 2. initializations
_T1IP = 4;
// this is the default value anyway
TMR1 = 0;
// clear the timer
PR1 = 25000-1; // set the period register
TRISA = 0xff00; // set PORTA LSB as output
// 3. configure Timer1 module
T1CON = 0x8020; // enabled, prescaler 1:64, internal
clock
// 4. init the Timer 1 Interrupt control bits
_T1IF = 0;
// clear the interrupt flag, before
_T1IE = 1;
// enable the T1 interrupt source
// 5. main loop
while( 1)
{
// your main code here
PORTA = Sec;
} // main loop
} // main

Testing Timer1 Interrupt


Build for Debugging using Debug>Debug
Project
Set a breakpoint

Run the application


Until breakpoint reached

Di Jasio Programming 16-bit Microcontrollers in C (Second Edition)

Inspect the SR register

Di Jasio Programming 16-bit Microcontrollers in C (Second Edition)

Enabling the Secondary Oscillator


OSCCON register:

The contents of the OSCSCON register are protected.


They require use of a special unlock sequence.
MPLAB XC16 offers a convenient builtin funciton:
__builtin_write_OSCCONL( 2);

Di Jasio Programming 16-bit Microcontrollers in C (Second Edition)

Using the RTCC

Di Jasio Programming 16-bit Microcontrollers in C (Second Edition)

Initializing the RTCC

The RTCC is protected by lock sequence, use a specific XC16 builtin


function to unlock it:
__builtin_write_RTCWEN();

After this step, initializing the RTCC, set the date and time as follows:
_RTCEN = 0;

// disable the module

// example set 12/01/2006 WED 12:01:30


_RTCPTR = 3;
// start the loading sequence
RTCVAL = 0x2006; // YEAR
RTCVAL = 0x1100; // MONTH-1/DAY-1
RTCVAL = 0x0312; // WEEKDAY/HOURS
RTCVAL = 0x0130; // MINUTES/SECONDS

// optional calibration
//_CAL = 0x00;

// enable and lock


_RTCEN = 1;
// enable the module
_RTCWREN = 0;
// lock settings

Di Jasio Programming 16-bit Microcontrollers in C (Second Edition)

Practical Rules
1.

2.

3.

4.

Keep it short and simple.


Make sure the interrupt routines are the shortest/fastest possible,
and under no circumstances should you attempt to perform any
processing of the incoming data.
Limit the activity to buffering, transferring and flagging.
Use the priority levels to determine which event deserves to
be serviced first, in the case two events might be triggered
simultaneously.
Consider very carefully whether you want to face the
additional complexity and headaches that result from enabling
the use of nested interrupt calls.
If the interrupt service routines are short and efficient, the extra
latency introduced by waiting for the current interrupt to be
completed before a new one is serviced is going to be extremely
small.
If you determine that you dont really need nesting, make sure
the NSTDIS control bit is set to prevent it:
_NSTDIS = 1; // disable interrupt nesting (default)

Di Jasio Programming 16-bit Microcontrollers in C (Second Edition)

Di Jasio Programming 16-bit Microcontrollers in C (Second Edition)

Notes for C Experts

The interrupt vector table (IVT) is an essential part of the crt0


code segment for the PIC24. Two copies of it are required to be
present in the first 256 locations of the program memory.

One is used during normal program execution,


The second (or Alternate IVT) during debugging.

These tables account for most of the size of the crt0


Subtract 256 words (or 768 bytes) from the file size of the
executable code to obtain the net code size.

Di Jasio Programming 16-bit Microcontrollers in C (Second Edition)

Notes for the Assembly Experts

The _ISRFAST macro can be used to declare a function as an


interrupt service routine and take advantage of a set of four
shadow registers.
This allows the processor to automatically save the content of the
first 4 working registers (W0-W3, i.e. the most frequently used
ones) and most of the content of the SR register in special
reserved locations, without requiring the use of the stack
The shadow registers provide the fastest possible interrupt
response time.
There is only one set of such registers. This does not limit us to
use only one interrupt in the entire application, but rather to use
_ISRFAST only in applications that have all interrupts with the
same priority level or, if multiple levels are in use, reserve the
_ISRFAST options only for the interrupt service routines with the
highest level of priority.

Di Jasio Programming 16-bit Microcontrollers in C (Second Edition)

Notes for the PIC MCU Experts

The PIC24 peripheral libraries can help simplify use of


complex peripheral modules. For example the RTCC
initialization:
#include <rtcc.h>
RtccInitClock();
RtccWrOn(); // unlock and enable writing to RTCC
rtccTimeDate TD = { 0x06, 0x20, // year
0x01, 0x11, // day, month
0x12, 0x03, // hour, weekday
0x30, 0x01};// sec, min
RtccWriteTimeDate( &TD, FALSE);

But it can also obfuscate your code and create


dependencies on files you have limited/no control on.
What do you expect the following call to do?
mPORTACloseAll()

Di Jasio Programming 16-bit Microcontrollers in C (Second Edition)

Tips and Tricks

Since version 3.00 of the PIC24 C compiler (now XC16) a new


attribute has been added as required for every interrupt service
routine:

Use __attribute__ (( no_auto_psv))


To relieve the compiler from the need to save the PSV register (see chapter
6). This is the fastest option.
Use __attribute__ ((auto_psv))
To ask the compiler from to save the PSV register. This is the safest option if
you are modifying the contents of the register in your application.

You can redefine the _ISR and _ISRFAST macros to include by


default the no_auto_psv attribute:
#if __C30_VERSION__ >= 300
#undef _ISR
#define _ISR __attribute__((interrupt,no_auto_psv))
#undef _ISRFAST
#define _ISRFAST __attribute__((interrupt,shadow,no_auto_psv))
#endif

Di Jasio Programming 16-bit Microcontrollers in C (Second Edition)

Tips And Tricks

The PIC24 architecture has no single control bit that disables


all interrupts
The assembly instruction disi can disable interrupts for a
limited number of cycles.
If there is a section of code that requires all interrupts to be
temporarily disabled, you can use the following pair of inline
assembly commands to bracket the code section:
__asm__ volatile("disi #0x3FFF"); // disable temporarily all interrupts
// your code here
// ...
DISICNT = 0; // re-enable all interrupts

Di Jasio Programming 16-bit Microcontrollers in C (Second Edition)

Suggested Excercises
1.
2.

Rewrite the RTCC interrupt example to use the


rtcc.h library and blink an LED at 1Hz
Output time and/or date on a 7 segments LED
display using a few I/O ports

Di Jasio Programming 16-bit Microcontrollers in C (Second Edition)

Recommended Readings

Curtis, K. E. (2006), Embedded Multitasking, Newnes,


Burlinghton, MA
Keith knows multitasking and what it takes to create
small and efficient embedded control applications.
Brown, G. (2003), Flying Carpet, The soul of an
airplane, Iowa State Press, Ames, IO
Greg has many fun episodes from the real life of a
general aviation pilot who uses his plane for recreation
as well as a family utility.

Di Jasio Programming 16-bit Microcontrollers in C (Second Edition)

Online Resources

http://www.niell.org/nixie_clock/Nixieclock.html
A PIC based clock with a retro style, using glowing
Nixie tubes
http://www.aopa.org
This is the web site of the Aircraft Owners and Pilot
Association. Feel free to browse through the web
site and access the many magazines and free
services offered by the association. You will find a lot
of useful and interesting information in here.

Di Jasio Programming 16-bit Microcontrollers in C (Second Edition)

You might also like