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