Path: Home => AVR overview => Interrupt programming => Interrupt execution    (Diese Seite in Deutsch: Flag DE) Logo

Interrupt programming in AVR Assembler

Here it is decribed how interrupt-driven programs basically work. To demonstrate the principles, an example with multiple interrupts can work together.

Warning! Here you will learn a completely new concept!

For all those who have previously programmed in higher-level languages or have written loop-controlled assembler programs so far: here is a helpful warning! Forget what you learned about program execution so far, the following will require you to learn a very different approach. If you stick with your previous views, you'll not be able to understand the different concept. So better forget that for a while.

Interrupt-driven programs are like this: If you have difficulties to understand or feel inconvenient with that concept: do not try to fall back to linear programming. I guarantee that if you overcome this early difficulties, you'll be happy to have absolved that, because those interrupt-driven programs are more efficient, are simpler and elegant, avoid unnecessary loops and offer simple debugging opportunities.

Execution of interrupt-driven programs

The standard execution of an interrupt-driven program in general form shows the following picture.

Execution of an interrupt-driven program This is how an interrupt-driven program executes:
  1. If the device resets, it starts executing the Reset vector at address 0000. There, a jump instruction routes program execution to the Main: routine. This routine initializes the stack, which is needed in interrupts. It then sets up the hardware (the pin for INT0 and TC0) and enables their interrupts.
  2. The init routine then runs into a loop: the controller is send to sleep, and only wakes up if one of the interrupt is executed. When woken up, the interrupt executes and program execution continues by checking the two flags. If one or both of those are set, the respective reaction is executed, following clearing of the flag. All those routines loop back to the SLEEP instruction.
  3. If the user pushes the INT0 button (no matter when this happens), the controller That routine sets flag A and then returns from interrupt: That ensures that, following the execution of the interrupt service routine, the controller always returns back to the original execution address.
  4. If the timer reaches its interrupt condition, whenever this occurs, the same happens, but now with the TC0 vector address. If, within the interrupt service routine of TC0, e. g. a counter is downcounted and reaches zero, the flag B is set. If, after being woken up, the TC0-ISR returns from interrupt, flag B is checked and the respective reaction occurs.
It is crucial to understand that while an interrupt executes any other interrupts are disabled by the clearing of the I bit in SREG. So, execution of another interrupt is blocked until the running interrupt ends with RETI. Therefore: keep those interrupt service routines as short as possible and perform lengthy operations outside the ISR. And: never forget the RETI.

If, by chance, the user pushes the button exactly in the short moment when TC0 reaches its interrupt condition, the INT0-ISR is executed first because it is located at the lower address. But the TC0 interrupt is not missed: its ISR is executed immediately after the INT0-ISR terminates.

If your program has to execute very quick, e. g. for the generation of an infrared signal with 40 kHz, hence you have only 12.5µs until the next interrupt occurs, you'll have to ensure that the interrupt service routine does not block further interrupts and misses interrupts. This can require counting clock cycles, and checking execution times very exactly.

A general rule: interrupt service routines have to communicate via flags with the normal program execution.

Did I promise too much at the beginning? The two interrupts control the whole program execution. All other routines react on those interrupts, and only execute if the interrupts have requested them via the flags. No wait loops, no unnecessary extra rounds but only necessary instructions. And: a clear, simple and consequent program structure. And easy to debug: just make sure that the interrupts are executed when necessary, and make sure that the reactions are as expected.

To the top of that page

©2009-2019 by