Saturday, October 23, 2010

AT90USB162 Atmel AVR Interrupts

In order to do most anything useful your micro controller is going to have to interact with the external world. For example instead of just blinking an led you might want to turn on the led when the user takes an action like manipulating the joystick or inserting a memory card. There are two ways you could go about doing this. You can either use a method called polling, meaning you constantly loop and check if some action had happened, but this is in efficient. The better way to achieve this result is through the use of interrupts. An interrupt is like an alarm you set it and then forget about it and it alerts you when some event you were interested in happens. In this example we will use an Olimex AVR-STK-USB board and use an interrupt to turn the on board led on and off when a memory card is inserted into the MMC slot.

To start we need to look at the board schematic and determine how the MMC slot is wired to the micro controller. The schematic shows the MMC slot in the upper right corner. Notice that pins 13 and 15 on the MMC slot are labeled "cp1" and "cp2". "cp", in this case stands for "card presence". Examining the schematic further we see that pin 15 is wired to ground with a resistor and pin 13 is wired to power and is also labeled "cp" indicating it is connected to the micro controller. Looking at the micro controller block in the schematic pin PD1 is also labeled "cp" so we can conclude that this is pin connected to the card presence circuit on the MMC slot.

Judging from the schematic we can conclude that PD1 will be a logic high when there is no card and logic low when a card is inserted. You can test this theory for yourself using a multi meter. Set up your meter to measure DC voltage. Attached the black prob to the ground pin and the red prob to the PD1 pin. Power the board and the meter on. The meter will read 3.3 volts. Now insert a card and watch what happens. With a card inserted your meter should read near zero volts.

Next we need to figure out how the interrupt mechanism of the micro controller works. The relevant documentation is in chapter 12 page 84 of the AT90USB data sheet. The interrupt documentation for the avr-libc library is also helpful reading. Note: PD1 also happens to be the same as INT1 or External Interrupt #1

From these two documents we learn that the interrupt can be programed to trigger in four different ways outlined in table 12-1. We want it to trigger whenever there is any change in the value of PD1 so we will need to set ISC11 to zero and ISC10 to one in the EICRA register. Also the the INT1 bit in the EIMSK register will need to be set to enable external interrupt #1. Putting it altogether this is what the code looks like.

#include <avr/io.h>
#include <avr/wdt.h>
#include <avr/sleep.h>
#include <avr/interrupt.h>

#define MMC_IS_PRESENT() (!(PIND & _BV(PIND1)))
#define LED_ON() (PORTD |= _BV(PD4))
#define LED_OFF() (PORTD &= ~_BV(PD4))

int main(int argc, char **argv) {

/* disable the watch dog timer */

/* setup card presence input */
DDRD &= ~_BV(DDD1);
PORTD &= ~_BV(PD1);

/* setup interrupt */
EICRA |= _BV(ISC10);
EICRA &= ~_BV(ISC11);

/* setup LED in correct state */
DDRD |= _BV(DDD4);
if (MMC_IS_PRESENT()) { LED_ON(); }
else { LED_OFF(); }

sei(); /* enable interrupts */
while(1) { sleep_mode(); }

return 0;

/* Interrupt routine */
ISR(INT1_vect) {
if (MMC_IS_PRESENT()) { LED_ON(); }
else { LED_OFF(); }

Full code with makefile is available on Github A good exercise is to try modifying the above code to also turn the led on whenever the joystick is clicked.