Chapter 5: Interrupts - Programming 16-bit

advertisement
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 I2C™)
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;
_RTCWREN = 0;
// enable the module
// 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 don’t 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)
Download