Interrupt Subsystem
- We have two strategies for getting input from an external device:
- Polling — continually watch for completion of an event.
- Interrupts — hardware generated subroutine call.
- Polling with the ADC involved a tight loop that watched for a change in the ADSC flag:
poll:
sbic ADCSRA, ADSC ; skip if bit clear (ADC complete)
rjmp poll
in r16, ADCH
- Using interrupts allows the microcontroller to continue executing useful instructions.
- When an interrupt occurs:
- Completes current instruction.
- Saves program counter (PC) on the stack.
- Executes interrupt jump vector instruction (typically loads PC with the location of the Interrupt Service Routinue starting location).
- Executes Interrupt Service Routine (ISR).
- Returns to program when ISR encounters RETI instruction.
Interrupt Sources
The Interrupt Subsystem on the ATmega32 can receive interrupts from internal and external sources.
Internal Interrupt Sources
- Power Subsystem:
- Power on
- Reset
- Voltage low
- Timer/Counter Subsystem:
- Timer expired
- Counter match
- Analog to Digital Converter Subsystem:
- ADC complete
- Serial Communication Subsystem:
- Character received
- Character sent
- Covered in more detail in CS-3841: Design of Operating Systems.
External Interrupt Sources
- Anything that can generate an "on/off" signal.
- ATmega32 has 3 pins (PD2, PD3, PB2) that the controller "listens" for an external trigger.
Interrupt Vector Table
.cseg
.org 0x00
rjmp start
; Interrupt Vector Table
.org 0x2a
start:
; ....
- The ATmega32 has approximately 20 interrupts.
- Each interrupt has a program memory location that stores a RJMP instruction that jumps to the ISR for the particular interrupt.
- The m32def.inc file has labels associated with each interrupt type
- Setting up the location of the ISR for the ADC, looks like this:
.org 0x00
rjmp start
.org ADCCaddr
rjmp adcISR
.org 0x2a
start:
; ...
; ISR for ADC subsystem
adcISR:
; ...
The ATmega32 interrupt subsystem supports twenty one different kinds of interrupts:
| Vector No. | Program Address | Label | Source | Interrupt |
|---|---|---|---|---|
| 1 | 0x00 | — | RESET | Power-on Reset, etc... |
| 2 | 0x02 | INT0addr | INT0 | External Interrupt Request 0 |
| 3 | 0x04 | INT1addr | INT1 | External Interrupt Request 1 |
| 4 | 0x06 | INT2addr | INT2 | External Interrupt Request 2 |
| 5 | 0x08 | OC2addr | TIMER2 COMP | Timer/Counter2 Compare Match |
| 6 | 0x0A | OVF2addr | TIMER2 OVF | Timer/Counter2 Overflow |
| 7 | 0x0C | ICP1addr | TIMER1 CAPT | Timer/Counter1 Capture Event |
| 8 | 0x0E | OC1Aaddr | TIMER1 COMP A | Timer/Counter1 Compare Match A |
| 9 | 0x10 | OC1Baddr | TIMER1 COMP B | Timer/Counter1 Compare Match B |
| 10 | 0x12 | OVF1addr | TIMER1 OVF | Timer/Counter1 Overflow |
| 11 | 0x14 | OC0addr | TIMER0 COMP | Timer/Counter0 Compare Match |
| 12 | 0x16 | OVF0addr | TIMER0 OVF | Timer/Counter0 Overflow |
| 13 | 0x18 | SPIaddr | SPI STC | Serial Transfer Complete |
| 14 | 0x1A | URXCaddr | USART RXC | USART, Rx Complete |
| 15 | 0x1C | UDREaddr | USART UDRE | USART, Data Register Empty |
| 16 | 0x1E | UTXCaddr | USART TXC | USART, Tx Complete |
| 17 | 0x20 | ADCCaddr | ADC | ADC Conversion Complete |
| 18 | 0x22 | ERDYaddr | EE_RDY | EEPROM Ready |
| 19 | 0x24 | ACIaddr | ANA_COMP | Analog Comparator |
| 20 | 0x26 | TWIaddr | TWI | Two-wire Serial Interface |
| 21 | 0x28 | SPMRaddr | SPM_RDY | Store Program Memory Ready |
Enabling Interrupts
- Must enable the global interrupt flag.
- Ways to set I flag (enable interrupts):
- SEI — Set Enable Interrupt.
- RETI — RETurn from Interrupt service routine (automatically sets the I flag.
- Ways to clear I flag (disable interrupts):
- CLI — clears the interrupt flag.
- Whenever the ATmega32 is reset, the I flag is cleared.
- Whenever an interrupt occurs, the I flag is cleared.
Interrupt Processing Steps
Setup:
- Must initialize the stack.
- Must set up the interrupt jump table.
- Must enable the global interrupt flag.
- Must enable particular local interrupt we are interested in.
When the interrupt occurs:
- Finish current instruction.
- Push current PC onto the stack.
- Clear I flag.
- Execute RJMP instruction in the Interrupt Vector Table.
- Execute the interrupt service routine.
- Execute RETI at end of ISR.
- Set I flag.
- Pop saved PC into the PC.
Interrupt Service Routine Guidelines
- Make it as short as possible.
- Push/Pop any registers that must be preserved onto the stack.
- Push/Pop SREG onto the stack.
push r0
in r0, SREG
push r0
; ...
pop r0
out SREG, r0
pop r0
Sample Code
Here is a simple program that makes use of the interrupt subsystem to display the results of the ADC conversion on the LEDs.
; Author: t a y l o r@msoe.edu
; Date: 4-23-2007
; Filename: adcIntDemo.asm
;
; This program uses the ADC subsystem and the interrupt subsystem
; to take the analog signal on ADC channel 0 and display its digital
; representation on the LEDs.
; Hardware configuration:
; - PORTB connected to LEDs.
; - PORTA pin 0 connected to analog source.
.nolist
.include "m32def.inc"
.list
.def temp = r16 ; Use r16 as a temp register
.cseg
.org 0x00
rjmp stackInit
.org ADCCaddr ; Jump vector for ADC interrupts
rjmp adcISR
.org 0x2a
stackInit:
ldi temp, HIGH(RAMEND-0x20)
out SPH, temp
ldi temp, LOW(RAMEND-0x20)
out SPL, temp
start:
ldi temp, 0xff ; Configure PORTB as output
out DDRB, temp
cbi DDRA, 0 ; Configure PORTA as input
rcall adcIntInit0
sbi ADCSRA, ADSC ; Start AD conversion
; Program just loops forever doing nothing (until interrupted)
forever:
rjmp forever
; Initialize ADC for single ended conversion on ADC channel 0
; with interrupt subsystem enabled.
adcIntInit0:
.def temp = r16
push temp
; Set ADC reference voltage, put in 8-bit mode and select channel 0
ldi temp, 0b01100000
out ADMUX, temp
; Enable ADC and ADC interrupts, prescale factor = 128
ldi temp, 0b10001111
out ADCSRA, temp
sei ; Enable global interrupt flag
pop temp
ret
; Interrupt Service Routine for ADC subsystem
; Takes result of ADCH and sends compliment of the result
; (since LED are active low) to the LEDs on PORTB and then
; starts the ADC all over again.
; Assumptions:
; - ADC and Interrupt subsystems have been initialized.
; - Using ADC channel 0.
; - Using only 8 MSB of ADC result.
; - PORTB is configured as output.
; Hardware configuration:
; - Analog input source is connected to PORTA pin 0.
; - PORTB connected to active low LEDs.
adcISR:
push temp
in temp, SREG ; Capture status register
push temp
in temp, ADCH
out PORTB, temp
sbi ADCSRA, ADSC ; Start ADC again
pop temp
out SREG, temp ; Restore status register
pop temp
reti
