You are on page 1of 19

The University of Texas at Arlington Lecture 9 Interrupts

CSE 3442/5442
1

Interrupts
An asynchronous (could happen any time) signal indicating the need for immediate attention to the processor. A way to tell the processor that a peripheral needs attention, without the processor constantly polling that peripheral. The processor can elect to ignore (mask) various interrupts or can elect to suspend its current execution and jump to a ROM location to execute an interrupt handler routine.
2

Interrupts vs. Polling


We have seen before that we can wait for peripherals to finish their tasks by constantly polling their SFR. When polling the microcontroller has to spend a considerable amount of time evaluating the content of a register which will possibly keep it from doing work it needs to. Furthermore, with polling the time when the peripherals need is realized may be too late (e.g., waiting for serial data to come in). When using polling and serving one peripheral, another (maybe more important) peripheral may be starved of attention it needs promptly. We cannot assign priorities. If we are using more than one peripheral the above problems really show themselves and interrupts will look better and better to serve our purposes. If the microcontroller would have a sleep state, interrupts would be great to wake it (and indeed).
3

Interrupt Service Routines


If indeed we can have peripherals interrupting the current processing, then we need programs that can handle these interrupts. Interrupt service routines (ISR) serve that purpose. The processor will need to know where to jump to (in the program ROM) when a non-masked interrupt hits. These locations are known as the interrupt vector table.
On some CPU-s there are more such addresses (PIC18,586) and on others there is but a single one (PIC16). On some CPU-s this address is reconfigurable and on some it is not (PIC18).

Interrupt Vectors of PIC18


The PIC18 has two (three) special locations (interrupt vectors) for interrupts (i.e., three entries for an interrupt vector table):
1. High Priority Interrupt at address: 0008 2. Low Priority Interrupt at address: 0018 3. Power-on reset at address: 0000

As there is limited space at these addresses it is a good idea to place a GOTO instruction at the interrupt vector jumping to a remote location for the ISR implementation.
5

What Happens When an Interrupt Hits? The current instructions execution is finished and the next instructions address is pushed to the stack. Interrupts are disabled (GIE or GIEH or GIEL cleared). The PC is loaded with the interrupt vector (jump to the ISR) The instructions in the ISR are executed until a RETFIE instruction RETFIE will cause the microcontroller to pop the PC from the stack and resume normal operations (unless more interrupts pending). Interrupts are enabled (GIE or GIEH or GIEL set).

PIC18 Sources of Interrupts


Many peripherals can ask for the attention of the CPU:
Each timer can ask for an interrupt (well cover them later) Hardware interrupts: pins designated as INT0, INT1, and INT2 (likely RB0,RB1,RB2) can function as digital inputs and if their level is changing can cause an interrupt. PORTB hardware interrupts: some other pins of PORTB can signal interrupts but not individually (the user will need to check what changed) The serial communication peripheral if it received or transmitted a byte can interrupt. The ADC can signal that it has finished converting The compare/capture/PWM module can signal for attention

Masking Interrupts
By default though, all interrupts are masked (disabled). It is up to the user to enable them if they are needed. Enabling/disabling interrupts is done through designated registers in the SFR:
INTCON, INTCON2, INTCON3 RCON PIR1, PIR2, PIR3 PIE1, PIE2, PIE3 IPR1, IPR2, IPR3

All interrupts can be masked by clearing the GIE (general Interrupt enable) bit in INTCON (default).

Simplified View of Interrupts


We can easily think of interrupts as digital signals. In general, each interrupt has two signals:
A flag that is set if interrupt should be invoked A masking bit that can disable the actual interrupt from happening

To make things confusing, some peripherals can be masked in a group by a PEIE mask.

A very simplified view with omitting some flags and some masks

Enabling Interrupts GIE in INTCON has to be set (BSF INTCON, GIE) We need to find the interrupt mask for the peripheral we want to use and set it high. As some interrupts are designated as peripheral interrupts (IMHO a bad nomenclature) for some interrupts the PEIE bit needs to be set (BSF INTCON, PEIE)
10

Two Levels of Priorities


The PIC18 has two levels of interrupts By default (when reset) all interrupts are high priority (compatibility) (address 00008H) In RCON we can enable the two-level priority option by setting IPEN (SETF RCON, IPEN) Then we can assign low or high priority to interrupts by setting/clearing an interrupt priority bit in the IPRx SFRs. This means that there really are three bits controlling each interrupt. The INT0 (RB0) hardware interrupt can only be of high priority. If two-level priority is enabled, GIE will become GIEH (for high priority) and PEIE will become GIEL (for low priority) Low priority interrupts will go to a different handler (address 00018H) Most importantly: When handling a low priority interrupt, high priority interrupts can steal the processor away (thus the word priority).

11

What Happens to Other Important Registers?


As we have seen, only the PC has a real(!) stack So, what happens to other important registers (WREG, Status, BSR) that may be impacted by an interrupt (especially as they should be found the same way as they were left when returning!) The solution lies in the ISR having to save these register at the beginning and restoring at the end (order!).

12

What Happens to Other Important Registers? Fast Context Switching


Alternatively, the microcontroller could do this (save registers) for us. There is a one-deep shadow register set for WREG, Status and BSR. The user has no access to this fast return register stack. ISRs making use of this should return with RETFIE 0x01 If both high and low priority interrupts are enabled and indeed low priority interrupts are preemptable (they do not disable GIEH right away) then this option cannot be used (as there will be an interrupt within an interrupt). This feature can be used for regular subroutines as well understanding that it is but one deep (CALL LABEL, FAST and RETURN FAST)
13

Some Remarks
As interrupts are asynchronous (especially if they are external), there is a latency for handling them (CPU has to finish current task). This latency can be from two instruction cycles to four instruction cycles (especially for external interrupts). In many cases the interrupt flag has to be cleared when handling the interrupt to avoid the flag to recursively re-interrupt the device. Some flags are automatically cleared when reading a port. Interrupt flags are set even if the interrupts are not enabled (they are the way peripherals signal to polling or interrupts). And vice versa, many of the flags can be set from code, thus causing invocation of an interrupt. If more interrupts are pending at RETFIE then a new interrupt will be started. It is customary to check at the ISR first which flag caused the interrupt (obvious). Dont use MOVFF insider an ISR to modify an interrupt register (why would you?)
14

Logical View of High Priority Interrupts

15

Logical View of All Interrupts

16

External INT Interrupts


INT0, INT1, and INT2 are all interrupts assigned to digital I/O pins. Thus, to use them the corresponding TRIS(B) bits have to be set. INT interrupts are edge (not level) triggered, thus a change must happen on the pins to trigger an interrupt. Whether rising (default) or falling edge triggers the interrupt is software (INTCON2.INTEDGx bits) selectable. When triggered (like many other flags) the ISR should explicitly clear the INTxIF flag. They can all be used to wake the processor from a sleep mode (more later). INT0 is always of high priority, the other two can be set.
17

External PORTB Interrupts


Changes on PB4:PB7 can also cause interrupts but are on the group of the bits not individual. (This leaves PB3 as the only PORTB pin without interrupt capability) Interrupt priority can be set. When handling interrupt, PORTB should be read and INTCON.RBIF should be cleared. Great e.g. for keyboard interfacing.

18

INTCON

19

INTCON2

20

INTCON3

21

PIR1

22

PIR2

23

PIR3

24

PIE1

25

PIE2

26

PIE3

27

IPR1

28

IPR2

29

IPR3

30

RCON

31

Interrupt Programming from Assembly


It really is just a quasi tedious job of setting the right bits in the right registers and org-ing the code at the right place. E.g.,
ORG 0000H GOTO MAIN ORG 0008H GOTO HP_ISR ORG 00018H GOTO LP_ISR HP_ISR ORG 200H BTFSS INTCON, INT0IF RETFIE 0x01 BTG BCF PORTB, 7 INTCON, INT0IF

RETFIE 0x01
32

Interrupt Programming from C


We need to define functions that are for high priority and low priority ISRs. We need to make sure that our ISRs are in the right place. We do not need to worry about context switching, the C compiler is going to make sure our registers are properly handled and variables that need saving are saved. Interrupt handlers should start off with an if or a switch-case complex to identify the source of the interrupt
33

Defining ISRs in C
Defining functions that are for high priority and low priority ISRs: At the beginning of the program, have a prototype of all functions (including ISRs) Use #pragma interrupt function_name and #pragma interruptlow function_name to tell compiler that a function is an interrupt function (so it can use proper RETFIE returns and fast context switching)
34

Placing ISRs in C
Make sure that our ISRs are in the right place. At the beginning of the code insert goto instructions to the interrupt vectors
#pragma code My_Hi_Priority_Int = 0x0008 void My_Hi_Priority_Int(void) { _asm GOTO chk_isr _endasm }
35

Interrupt Handling All in All (in C)


#include <P18F458.h> void My_ISR_High(void); void My_ISR_Low(void); #pragma code My_Hi_Priority_Int = 0x0008 void My_Hi_Priority_Int(void) { _asm GOTO My_ISR_High _endasm } #pragma code My_Lo_Priority_Int = 0x00018 void My_Hi_Priority_Int(void) { _asm GOTO My_ISR_Low _endasm } #pragma interrupt My_ISR_High void My_ISR_High(void) { interrupt handling } #pragma interruptlow My_ISR_Low void My_ISR_Low(void) { interrupt handling for low }

36

Summary
Interrupts are a great way to handle peripheral attention or external happenings. Some of the most used interrupts are timers (later), external hardware, serial communications, and ADC ready. All interrupts in the PIC18 can be masked in a group or individually. We can have two levels of priorities, with an almost fully configurable what interrupt belong to what level relationship. Programming ISRs from C requires knowledge of how the compiler is told about ISRs. (The sample provided here is for the C18 compiler.)
37