josuah.net | panoramix-labs.fr
resume | links | blog | quotes | ascii | tgtimes | gopher | mail
The difference between low-end microcontrollers and powerful CPUs might be thin, but we are still focusing on microcontrollers here.
As the name interrupt suggests, they are events that stop the main execution of a program for doing something else, until the execution can come back to the main task.
The execution jumps from whatever address it was at to a predefined code location that contains the code to manage whichever event did just trigger the interrupt.
In that way, they offer a more efficient mechanism to wait for an event or react to an event, instead of letting the main program checking over and again for the presence of an event.
hard interrupts describes events triggered by hardware peripherals, such as when the UART receiver gets some new data, or when the ADC conversion is over, when the voltage of a pin goes up or down, when a timer reaches a threshold value...
soft interrupts are triggered by a software. Ability to trigger an interrupt from software level makes it more convenient to write operating systems.
Simpler or earlier architectures like the 8-bit AVR have a jump table: a code region with only
jmp instructions, each
jmp present at its well-defined address corresponding to the interrupt event.
While an interrupt happen, the execution simply moves to a constant address in the jump table depending on the interrupt type, and because that address will contain a
jmp statement, the execution will move again according to the
jmp instruction. Now at the right address, the interrupt handler function will now execute.
For instance on AVR:
.org 0x00 interrupt_jump_table: jmp reset_handler jmp interrupt_int0_handler jmp interrupt_int1_handler jmp interrupt_pcint0_handler jmp interrupt_pcint1_handler jmp interrupt_pcint2_handler jmp interrupt_wdt_handler [...]
reset_handler is by convention the first interrupt, and happen while the microcontroller first boots, or is reset. It is the entry point of execution.
For AVR, there is a special
reti instruction for returning from the interrupt back to the main execution. It clears the interrupt flag, letting the microcontroller know that the code may be interrupted again.
Jumping straight out of the main execution thread to the interrupt handler has side effects on registers, overriden by the interrupt handler function. Their content must be saved by the developer (such as
push instructions) and restored back (such as
Because pushing and restoring the context can be teidious, and because special instructions must be issued, vectorised interrupts were developed.
When an interrupt event happen, instead of jumping to a fixed address, the microcontroller loads an address from an address table called vector table, and jumps to that address instead to jumping to the middle of the interrupt table itself.
For instance on ARM:
.org 0x00 vectors: .word initial_stack_address .word reset_handler .word interrupt_nmi_handler .word interrupt_hardfault_handler .word interrupt_memorymanagement_handler .word interrupt_busfault_handler .word interrupt_usagefault_handler [...]
The first bytes
initial_stack_address are loaded by the microcontroller onto the stack pointer register at startup.
The microcontroller will also:
popinstructions which need not to be added by the developer;
Because of the above, it now permits to write complete interrupts hander function in C instead of completely or partly in assembly.
In the case of RISC-V, there are both cases present: cases present:
/* execution jumps here on reset or startup */ .org 0x0000 /* initialize the stack pointer register */ la sp, __stack_top /* jump to the reset handler */ j __reset_handler /* just enough room for the beginning of the vector table */ /* a regular interrupt vector table follows */ .org 0x000C .word interrupt_clic_int_sft_handler .org 0x001C .word interrupt_clic_int_tmr_handler .org 0x0044 .word interrupt_clic_int_bwei_handler .word interrupt_clic_int_pmovi_handler .word interrupt_wwdgt_handler .word interrupt_lvd_handler
This is a compromise between the simplicity of building a jump table, and the speed of a vector table: the reset handler does not need to save any register, as there were nothing executing before it (startup) or we do not care about it (reset, much like a reboot).