josuah.net | panoramix-labs.fr

cv | links | blog | quotes | ascii | tgtimes | gopher | mail | rss

MCU Interrupts

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.

Interrupts Jump Table

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
[...]

The 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 pop instructions).

Vectorised Interrupts

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:

Because of the above, it now permits to write complete interrupts hander function in C instead of completely or partly in assembly.

Mixed Situations

In the case of RISC-V, there are both cases present: cases present:

For instance:

/* 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).

--- #draft