Chapter 6. Interrupt API

It's nearly impossible to find compilers that agree on how to handle interrupt code. Since the C language tries to stay away from machine dependent details, each compiler writer is forced to design their method of support.

In the AVR-GCC environment, the vector table is predefined to point to interrupt routines with predetermined names. By using the appropriate name, your routine will be called when the correspondi ng interrupt occurs. The device library provides a set of default interrupt routines, which will get used if you don't define your own.

Patching into the vector table is only one part of the problem. The compiler uses, by convention, a set of registers when it's normally executing compiler-generated code. It's important that these registers, as well as the status register, get saved and restored. The extra code needed to do this is enabled by tagging the interrupt function with __attribute__((interrupt)).

These details seem to make interrupt routines a little messy, but all these details are handled by the Interrupt API. An interrupt routine is defined with one of two macros, INTERRUPT() and SIGNAL(). The interrupt is chosen by supplying one of the symbols in Table 6-1. These macros register and mark the routine as an interrupt handler for the specified peripheral. See the entries for INTERRUPT() and SIGNAL() for examples of their use.

Unused interrupt vectors point to a routine called _unexpected_. The default version of this function simply consists of a reti instruction. You can define your own handler, if you want to handle unexpected interrupts differently.

Table 6-1. Signal names

NameDescription
SIG_INTERRUPT0External Interrupt0
SIG_INTERRUPT1External Interrupt1
SIG_INTERRUPT2External Interrupt2
SIG_INTERRUPT3External Interrupt3
SIG_INTERRUPT4External Interrupt4
SIG_INTERRUPT5External Interrupt5
SIG_INTERRUPT6External Interrupt6
SIG_INTERRUPT7External Interrupt7
SIG_OUTPUT_COMPARE2Output Compare2 Interrupt
SIG_OVERFLOW2Overflow2 Interrupt
SIG_INPUT_CAPTURE1Input Capture1 Interrupt
SIG_OUTPUT_COMPARE1AOutput Compare1(A) Interrupt
SIG_OUTPUT_COMPARE1BOutput Compare1(B) Interrupt
SIG_OVERFLOW1Overflow1 Interrupt
SIG_OUTPUT_COMPARE0Output Compare0 Interrupt
SIG_OVERFLOW0Overflow0 Interrupt
SIG_SPISPI Interrupt
SIG_UART_RECVUART(0) Receive Complete Interrupt
SIG_UART1_RECVUART(1) Receive Complete Interrupt
SIG_UART_DATAUART(0) Data Register Empty Interrupt
SIG_UART1_DATAUART(1) Data Register Empty Interrupt
SIG_UART_TRANSUART(0) Transmit Complete Interrupt
SIG_UART1_TRANSUART(1) Transmit Complete Interrupt
SIG_ADCADC Conversion complete
SIG_EEPROMEeprom ready
SIG_COMPARATORAnalog Comparator Interrupt

6.1. Function Reference

6.1.1. cli

#include <interrupt.h>
	    

void cli(void);

description. Disables all interrupts by clearing the global interrupt mask. This function actually compiles into a single line of assembly, so there is no function call overhead.

6.1.2. enable_external_int

#include <interrupt.h>
	    

void enable_external_int(uint8_t ints);

description. This function gives access to the gimsk register (or eimsk register if using an AVR Mega device). Although this function is essentially the same as using the outp() function, it does adapt slightly to the type of device being used.

6.1.3. INTERRUPT

#include <sig-avr.h>
	    

INTERRUPT(signame);

description. This macro creates the prototype and opening of a function that is to be used as an interrupt. signame should be one of the symbols found in Table 6-1. The routine will be executed with interrupts enabled. If you want interrupts disabled, use the SIGNAL() macro instead. Example 6-1 sets up an empty routine which gets called when the ADC has completed a conversion.

see also. SIGNAL()

Example 6-1. Setting up an interrupt handler

    /* This function will get attached to the SIG_ADC interrupt vector. */
    
    INTERRUPT(SIG_ADC)
    {
    }

6.1.4. sei

#include <interrupt.h>
	    

void sei(void);

description. Enables interrupts by clearing the global interrupt mask. This function actually compiles into a single line of assembly, so there is no function call overhead.

6.1.5. SIGNAL

#include <sig-avr.h>
	    

SIGNAL(signame);

description. This macro creates the prototype and opening of a function that is to be used as an interrupt. The argument signame should be one of the symbols found in Table 6-1. The routine will be executed with interrupts disabled. If you want interrupts enabled, use the INTERRUPT() macro instead.

Example 6-2 sets up an empty routine which gets called when the ADC has completed a conversion.

see also. INTERRUPT()

Example 6-2. Setting up a signal handler

    /* This function will get attached to the SIG_ADC interrupt vector. */
    
    SIGNAL(SIG_ADC)
    {
    }

6.1.6. timer_enable_int

#include <interrupt.h>
	    

void timer_enable_int(uint8_t ints);

description. This function modifies the timsk register.