Handling hardware Interrupts

1. Overview

Interrupts are events that when each one occurs, the program will immediately switch from normal routine to handler routine for that interrupt and then return to normal routine when the handler is done. The switching can happen anytime, whenever an interrupt occurs and it is controlled by hardware, the main routine does not have to prepare for it. Although the main program flow is switched to interrupt routine for a while, the program is usually uninformed about that.

Interrupt handlers are special routine, in form of a function. There is one function for handling each interrupt and hardware will call the corresponding function for each interrupt when it occurs. Interrupts functions are the same with other functions in a program except they have one of the names that are reserved.

The sources of interrupts are from CPU's peripherals. Each peripheral can be programmed to trigger interrupts when needed. An interrupt function for each source must be created by programmer when it is enabled. If there is no handler for an interrupt, it will just be ignored. Some interrupts will be repeatedly triggered if not properly handled or ignored, which will halt the execution of main routine.

The CPU has a feature that lets the program to allow or disallow interrupts to be served. A pending interrupt will not be served (handler will not be called) if the program disallow all interrupts. This feature can be used when the program needs to temporally disallow any interrupt that may happen when it's in the middle of some task that requires accurate timing.

2. Interrupts and Handler functions

The CPU of Ansteron Board has 26 interrupt sources, one of which (RESET) is reserved for system use; the other 25 are available for user programs. These interrupts are triggered by peripherals when they are enabled. Interrupts are also called requests and numbered from 1 to 26.

Request numberDescription
1RESET, reserved for system use
2External interrupt on pin D2
3External interrupt on pin D3
4Pin change interrupt group 1
5Pin change interrupt group 2
6Pin change interrupt group 3
7Watchdog timer time-out
8Timer/Counter2 Compare match (channel A)
9Timer/Counter2 Compare match (channel B)
10Timer/Counter2 counter overflow
11Timer/Counter1 capture event
12Timer/Counter1 Compare match (channel A)
13Timer/Counter1 Compare match (channel B)
14Timer/Counter1 counter overflow
15Timer/Counter0 Compare match (channel A)
16Timer/Counter0 Compare match (channel B)
17Timer/Counter0 counter overflow
18SPI transfer complete
19Serial (UART) receive complete
20Serial (UART) data register empty
21Serial (UART) transmit complete
22ADC conversation complete
23EEPROM ready
24Analog comparator interrupt
25TWI interrupt
26SPM ready

The request numbers in the table above match the numbers in CPU datasheet (ATMEGA328P). These numbers are then used for specifying handler function for each interrupt. The name of each interrupt function starts with "system_interrupt_request_" and then the request number. Interrupt handler functions cannot take input nor return value. The example below is handler function for interrupt request number 19, which will be called when a byte is received by Serial interface.

When the Linker of Ansteron IDE detects a function with one of those names, it will perform necessary steps to direct interrupt vector to the function, allowing it to be called when the event occurs. A report as seen in message section above is made for each interrupt request detected.

Interrupt functions should use global variables to store data and status. They can be defined in preprocessor tab. Local variables can be used in interrupt functions as well but their value will not be saved. Directly access to CPU's registers is recommended to make it more efficient. All registers will be visible to the program when Low level access option in Compiler settings is selected.

Programmer should make interrupt functions compact, efficient and returns as quickly as possible. The goal is to avoid any effect to the main program if handlers take too much time. Calling other functions inside interrupt functions should be avoided if possible since there is more data of the main program that will need to back up to make it possible for calling subsequence functions.

Interrupts from a peripheral will only trigger if the setting of that peripheral is enabled. Besides, the CPU must be allowed to serve interrupt requests. To set up an interrupts, the program should call appropriate functions or directly write setting values to peripheral's registers. All registers inside the CPU can be accessed by their names when Low level access option is enabled in Compiler settings. Two system functions, "system_enable_interrupts();" and "system_disable_interrupts();" are used to allow or disallow the CPU to server interrupt requests. Note that all interrupts are disabled by default.

3. Note

For more information about interrupts for each peripheral, please refer datasheet of ATMEGA328P. Some libraries are made for easy handling certain interrupts, such as external interrupts, can be used instead. The following conventions should be followed to make interrupts handling compatible with other libraries for Ansteron Board.

  • Compact, efficient and consume minimal CPU time.
  • When accessing peripheral´┐Żs register, only change the bits that needed, keep other ones as is.
  • Timer 0,1 and 2 should be kept so that their PWM function will not be affected. The timers should be left on and running when interrupts are no longer needed.
  • Avoid calling other functions by handlers if possible.
  • Avoid excessive number of calculations that use multiplication, division, and modulus.