You are on page 1of 18

AVR programming:

Interrupts and timers


Sven Gestegård Robertz

Department of Computer Science


Lund University
Sweden
Outline
● Interrupts
– What is it?
– How are they programmed?
– Pitfalls?
● Specific peripherals
– External interrupts
– Timers
The interrupt mechanism
● A low-level mechanism for multitasking
● Interrupt what you're doing to handle an
external signal (similar to a phone call)
● Vaguely similar to Java Threads
– or rather, threads can be implemented
using interrupts
– no support for scheduling, etc.
– interrupts may have priorities (not on AVR)
– interrupts do not provide separate stacks
etc.
Types of interrupts
● Hardware interrupts
– externally generated
– frees up CPU from polling
● Software interrupts
– generated by CPU instruction
● on AVR: writing to a pin change interrupt
pin configured as output triggers interrupt
– used to implement system calls
Execution of an interupt
● An (external) signal interrupts the CPU's
normal execution
● CPU jumps to an interrupt handler (ISR)
– pointed to from the interrupt vector
● The ISR handles the interrupt
● ISR returns to the interrupted routine
– reti();
Maskable interrupts
● An interrupt mask selects which
interrupts are active
● Example: Timer/Counter interrupt mask
(TIMSKn). Similar for other peripherals

● Some interrupts are non-maskable (reset)


The global interrupt flag
● Sometimes you do not want to be
interrupted, for performance or data
consistency reasons.
● CLear Interrupts: turn off all interrupts
– CLI / cli();
● SEt Interrupts: turn on all interrupts
– SEI / sei();
● Enabling an interrupt requires both
enabling it in the interrupt mask and
setting the global interrupt flag.
Restoring the interrupt flag
● A more reusable and robust way
● The interrupt flag is in the status register
#include <avr/interrupt.h>
void do_something_atomic()
{
unsigned char sreg = SREG; // remember interrupt flag
cli(); // clear interrupt flag
do_stuff(): // do something without being interrupted
SREG = sreg; // restore interrupt flag
}

● See also ATOMIC_BLOCK in util/atomic.h


Handling interrupts in AVR-libc
● Interrupt names defined in header files
(e.g., avr/iomx8.h) but refer to the
documentation (avr-libc documentation
link in the help menu of AVRstudio.)
● Example ISR for overflow in Timer 0
#include <avr/io.h>
#include <avr/interrupt.h>

ISR(TIMER0_OVF_vect, ISR_NAKED) {
// do something each time timer 0 overflows
reti();
}
Handling interrupts (cont'd)
● The ISR macro takes attributes to specify
its behaviour
– ISR_BLOCK: run with interrupts disabled
– ISR_NONBLOCK: don't disable interrupts
● (nested interrupts needs more careful
analysis)
ISR(some_vect, ISR_BLOCK) {
// do something
// NB! No reti(). That is done in the epilogue
// inserted by the macro.
}
External interrupts
● PCINT
– generates an interrupt when a pin changes
– available on all pins
– three sets of pins (controlled by PCICR)
● many pins can trigger the same interrupt
● may be handy for the two encoder signals
– pins masked by PCMSKn (n = [0,2])
● INT0, INT1
– pin change, edge or level trigged
– controlled by EICRA
– masked by EIMSK
Example, PCINT for pin 24
● Consult data sheet
● pin 24 → PCINT9
● PCICR: PCINT14..8 → PCIE1
● Find the bit in PCMSK1
volatile int counter;
ISR(PCINT1_vect) {
// count positive edges
if(PINC & (1<<PINC1)) counter++;
}
void setup_interrupt(){
PCICR = (1<<PCIE1);
PCMSK1 = (1<<PCINT9);
sei();
}
Timers
● A counter, clocked from the system clock
or externally
● Prescaler (clk/8, clk/64, … clk/1024)
● Gives two (three) types of interrupts
– overflow
● when the conter wraps
– output compare
● when the counter reaches a set value
● more programmable, two compare values
● also used for waveform generation
– (input capture)
Timer usage
● Required configuration
– set prescaler for desired frequency range
– set mode of operation
– enable any interrupts
● PWM mode(s)
– usually better to use the built-in PWM
modes if possible. (typically fast PWM)
● CTC mode
– Clear Timer on Compare match
– allows more fine-grained control over
interrupt frequency
Fast PWM mode
● Single slope counting
● OCRnx controls duty cycle
● OCRnx is double buffered
Fast PWM: Setting period time
● TOP can be fixed, or set using OCRnA
(or ICR1)
Tips...
● Avoid using many interrupts concurrently
– prototype by polling, then switch to ISR.
● Usually a good idea to turn off interrupts
in ISRs (e.g., ISR_BLOCK)
– to avoid data races
– running out of stack space
● Try to keep ISRs very short
– if possible, do just store data or set a flag
and do actual processing elsewhere
● Shared data must be volatile and global
Tips... (cont'd)
● Check if interrupt flags are reset by the
hardware of if you need to do it in code
● If not, nonblocking ISRs will get called
over and over.
– UART interrupts
– level triggered external interrupts

You might also like