You are on page 1of 17

Lecture 8

Interrupt Subsystem
Interrupt Theory
 Unscheduled, higher
priority events are
handled by Interrupt
system.
 Upon Interrupt MC will
complete the current
instruction and then jump
to Interrupt Service
Routine (ISR).
 Each interrupt has its own
ISR.
 After completing ISR MC
will resume from it left off
before the interrupt.
Interrupt Sources

Interrupt Sources in descending order of priority


Interrupt Sources
The process
 When Interrupt occurs, MC completes current instruction
being executed.
 Stores the address of next instruction on Stack.
 Executes ISR related to the interrupt source.
 Turns off Interrupt system to prevent further interrupts
while one is in progress. The AVR CPU will
automatically disable the Global Interrupt Enable
bit, to prevent the ISR from being itself
interrupted.
 ISR is executed by loading the beginning address of ISR
into the program counter.
 ISR is executed till “reti” is encountered.
Programming an Interrupt
 Ensure the ISR for a specific interrupt is tied to
the correct interrupt vector address, which points
to the starting address of the ISR.
 Ensure the interrupt system has been globally
enabled. This is accomplished with the assembly
language instruction SEI.
 Ensure the specific interrupt subsystem has
been locally enabled.
 Ensure the registers associated with the specific
interrupt have been configured correctly.
Conditions for ISR
 For an ISR to be called, we need three conditions to be true:
 Firstly, the AVR's global Interrupts Enable bit (I) must be set in the
MCU control register SREG. This allows the AVR's core to process
interrupts via ISRs when set, and prevents them from running when
cleared. It defaults to being cleared on power up, so we need to set
it.
 Secondly, the individual interrupt source's enable bit must be set.
Each interrupt source has a separate interrupt enable bit in the
related peripheral's control registers, which turns on the ISR for that
interrupt. This must also be set, so that when the interrupt event
occurs the processor runs the associated ISR.
 Thirdly, The condition for the interrupt must be met
Linking ISR to Interrupt source
 Place a JMP or RJMP instruction to this function at the address specified in
the table we just looked at.
 At the start of the AVR's FLASH memory space lies the Interrupt Vector
Table, which is simply a set of hardwired addresses which the AVR's
processor will jump to when each of the interrupts fire.
 By placing a jump instruction at each interrupt's address in the table, we can
make the AVR processor jump to our ISR which lies elsewhere.
 Code:
.org 0x{Vector Address}
jmp MyISRHandler

MyISRHandler:
; ISR code to execute here
reti
 “reti” has the dual function of exiting the ISR, and automatically re-enabling
the Global Interrupt Enable bit. This happens inside the C version too when
the function returns, we just don't see it normally.
‘C’ definition
 Code:
 #include <avr/interrupt.h>

ISR({Vector Source}_vect)
{
   // ISR code to execute here
}
 E.g. vector source could be INT0, INT1 or
INT2 for external Interrupts.
I-bit
 I-bit: sei, which SEts the I flag
cli, which CLears the I flag
 Code:
sei ; Enable Global Interrupts

 While in C, we have to use special macros from our libc


library's header. In the case of AVR-GCC and its avr-libc
library, we just use the sei() and cli() macro equivalents
defined in <avr/interrupt.h>:
 Code:
sei(); // Enable Global Interrupts
Configuring external Interrupts
 The external interrupts INT0 (pin 16), INT1
(pin 17), and INT2 (pin 3) trigger an
interrupt within the ATmega16 when an
external event occurs.
 Interrupts INT0 and INT1 may be triggered
with a level or an edge signal, whereas
interrupt INT2 is edge-triggered only.
Interrupt Registers
Interrupt Pins
Assembly Example
Assembly Example
.include "m16def.inc"
; Interrupt service vectors
ldi TEMP,(1<<INT0)+(1<<INT1) ; int masks 0 and 1 set
.org $0000
out GICR,TEMP
rjmp Reset ; Reset vector
.org INT0addr ldi TEMP,$0f ; interrupt t0 and t1 on rising edge only
rjmp IntV0 ; INT0 vector (ext. interrupt from pin D2) out MCUCR,TEMP
.org INT1addr ldi TIME,$00 ; Start from 0
rjmp IntV1 ; INT1 vector (ext. interrupt from pin D3) sei ; enable interrupts and off we go!
;--------------------------------------------------------------------------- loop:
; rjmp loop ; Infinite loop - never terminates
; Register defines for main loop ;---------------------------------------------------------------------------
.def TIME=r16 ;
.def TEMP=r17
; Int0 vector - decrease count
;---------------------------------------------------------------------------
;
IntV0:
; Reset vector - just sets up interrupts and service routines and dec TIME
; then loops forever. rjmp Int01 ; jump to common code to display new count
Reset: ;---------------------------------------------------------------------------
ldi TEMP,low(RAMEND) ; Set stackptr to ram end ;
out SPL,TEMP ; Int1 vector - increase count
ldi TEMP, high(RAMEND) IntV1:
out SPH, TEMP inc TIME ; drop to common code to display new count
ser TEMP ; Set TEMP to $FF to... Int01:
out DDRB,TEMP ; ...set data direction to "out"
mov r0,TIME ; display on LEDs
out PORTB,TEMP ; ...all lights off!
out PORTD,TEMP ; ...all high for pullup on inputs
com r0
out PORTB,r0
reti
INT0 Initialization in ‘C’
 void initialize_interrupt0(void) //initialize interrupt 0
{
DDRD = 0xFB; //set PD2 (int0) as input
PORTD &= ~0x04; //disable pullup resistor
//PD2
GICR = 0x40; //enable int 0
MCUCR = 0x03; //set for positive edge
//trigger
sei(); // Enable Global Interrupts
}
‘C’ Example
#include <avr/io.h>
//Do not forget to add this header file
#include <avr/interrupt.h>
 
int main(void)
{
// Set PORTC is as output
DDRC=0XFF;
// Enable INT0 External Interrupt in GICR Register
GICR |= 1<<INT0;
// Falling-Edge Triggered INT0
MCUCR |= 1<<ISC01;
// Enable Interrupts
sei(); 
// Set Bit 0 of PORTC
PORTC = 0x01;
   while (1)
   {
   }
}
// External Interrupt 0 ISR
ISR(INT0_vect)
{
// Invert the Bit 0 of PORT C every time interrupt occurs
   PORTC^=0x01;
}

You might also like