7.1 Interrupt Code (Mid-range)
The example shown in this chapter shows how to write an interrupt service routine (ISR).
- Have its entry point linked to the address of the relevant interrupt vector,
- Ensure that the content of any registers it uses and which are also used by main-line code are preserved,
- Ensure that only the relevant code is executed for each interrupt source, and
- Execute a special return-from-interrupt instruction to end the routine and interrupt processing.
PSECT isrVec,class=CODE,delta=2
isr:
;no context save required in software for this device
PAGESEL $ ;select this page for the following goto
BANKSEL PIE0 ;for TMR0IE and TMR0IF
;for timer interrupts, set the required LED state
btfsc TMR0IE
btfss TMR0IF
goto notTimerInt ;not a timer interrupt
bcf TMR0IF
;toggle the desired bit state
movlw 1 shl (LEDState&7)
BANKSEL LEDState/8
xorwf BANKMASK(LEDState/8),f
notTimerInt:
;code to handle other interrupts could be added here
exitISR:
;no context restore required in software
retfie
The entry point to an ISR, like that of the code executed after Reset, must be linked to
the appropriate interrupt vector address for the target device. To do this, the ISR, or
at least the code containing the entry point to the ISR, should be placed in a unique
psect that can be linked to the required address. In this example the
isrVec
psect holds the entire interrupt routine. Some PIC18 devices
can employ an interrupt vector table and have different linking requirements for ISRs,
as described in section Interrupts and Bits Example For PIC18
Devices.
Any registers that are modified by an ISR (and any routines they call) and that are also used in main-line code must be saved on entry to the ISR and then restored on exit. For devices that support more than one interrupt vector (e.g. PIC18 devices), an ISR will need to save any registers that are modified but not saved by other ISRs. The code that saves and restores registers is often called context switch code.
Like many modern PIC devices, the 16F18446 automatically saves the state of core registers into shadow registers when an interrupt occurs, so context switching does not usually need to be performed in software for these devices, unless there are other registers or objects that the ISR should not leave modified. The example code above includes no context switch code at all, instead it immediately process the interrupt. If you need to write context switch code, see section Manual Context Switch.
The ISR shown here toggles the desired state of the LED when a timer 0 interrupt occurs.
It performs no action for any other interrupt source, but you could add code to this ISR
to process as many interrupt sources as required. The btfss TMR0IF
instruction checks the relevant timer interrupt flag to ensure that the timer 0 has
triggered, but it does this in conjunction with the btfsc TMR0IE
instruction, which checks the timer 0 interrupt enable bit. Only when both of these bits
are set can you be sure that timer 0 is the source of the interrupt.
To terminate execution of the interrupt code and return to main-line code, use a
retfie
instruction, as shown. A regular return
instruction will not return the state of the device to that when the interrupt occurred
and will lead to code failure.
Since this ISR contains a goto
instruction, a PAGESEL
directive was added to ensure that the page that contains the ISR is selected and that
the goto
will reach the intended destination.