The real-time interrupt provides a simple way to have an interrupt occur on a regular basis, independent of your programs activity. It's based on a "free-running counter", which means a hardware counter that keeps running regardless of your programs activity.
About the only control you have over the RTI is how fast it runs, and whether it actually triggers an interrupt. You can't stop it, you can't set a specific value in it, and you can't read it.
The speed of the RTI interrupt is determined by two bits in the Pulse
Accumulator Control Register (PACTL) located at address
$1026.
DDRA7 |
PAEN |
PAMOD |
PEDGE |
0 |
0 |
RTR1 |
RTR0 |
Bits 4-7 aren't used by the RTI system; they are initialized to 0 on reset and can be left alone. Bits 1 and 0 (RTR1 and RTR0) set the rate at which the RTI requests interrupts, as follows:
| RTR1 | RTR0 | Rate |
|---|---|---|
| 0 | 0 | 4.10 ms |
| 0 | 1 | 8.19 ms |
| 1 | 0 | 16.38 ms |
| 1 | 1 | 32.77 ms |
(these numbers are for our particular clock speed. There's a table in the Reference Guide that shows the results for other clock speeds)
RTI interrupts are masked by the global interrupt mask, so you need
to execute a CLI to enable any interrupts at all.
In addition, the RTI interrupt itself has its own interrupt enable
bit, which is in Timer Interrupt Mask Register 2 (TMSK2), located at
$1024:
TOI |
RTII |
PAVI |
PAII |
0 |
0 |
PR1 |
PR0 |
As usual, there are quite a few bits in here that we don't need to
worry about; the important one is RTII. This is an
interrupt enable bit, so we need to write a 1 into this bit to
enable RTI interrupts.
There are two things you need to keep track of in writing your interrupt service routine: first you need to set the interrupt vector to point to it, and second you need to make sure you properly set up the interrupt service routine itself so that you get back to your main program and reset the interrupt request.
The RTI interrupt vector is located at address $fff0.
This means you need to put the address of your RTI interrupt service
routine at that address. Let's take a quick example.
Suppose your interrupt service routine starts at a label
rtiint, like this:
* RTI Interrupt.
rtiint
Then, after your program code and before your end
statement, you need to put
org $fff0
fdb rtiint
In addition to whatever work your ISR needs to accomplish to do its job, there are two tasks it needs to perform: it needs to clear the interrupt request, and it needs to return to the main program.
To clear the interrupt request, it writes a 1 to the RTI flag in
Timer Interrupt Flag 2 Register (TFLG2), located$1025.
TOF |
RTIF |
PAOFV |
PAIF |
0 |
0 |
0 |
0 |
The bits in this register are all screwy: you clear them by trying to write a 1 to them. Yes, it's backwards and doesn't make sense; no, I don't know why. The easiest way to do this is (paradoxically enough) to try to clear all the other bits in the register, so
bclr TFLG2,x #%10111111
Note: Freescale says the most common problem with using the RTI interrupt is to forget this!
This step is actually the same for every interrupt service routine:
you need to use an RTI instruction to return from the
service routine. This restores all the registers to their
state before the interrupt occurred.