Where Are The Return Address And Register Data Saved?

As part of the automatic response to an interrupt request, the uC hardware will save the address of the next instruction that was to be executed.  This address is either saved onto the stack (as pointed to by the CPU stack pointer), or it may be saved into a special CPU register, often called the "link register".  The AVR uses the hardware stack pointer, while the STM32 uses a link register.  Saving to a link register is faster because register-to-register moves are always faster than register-to-memory moves, but when another level of interrupts (or subroutines) is required, the link register must then be saved off to memory by user code (code that is generated by the compiler if you're using a HLL).

As for any register data that is saved and restored, that data will also be saved to a stack - that is, out to memory.  That stack may be the stack maintained by the hardware stack pointer, or it may be a stack maintained by software, just as is used for saving off the link register when necessary.

IS AN ISR A FUNCTION?

As stated, an ISR is similar to a function, but there are some critical differences for most microcontroller designs.  Most of these differences revolve around the fact that an ISR must be "invisible" to the background code that was executing when the ISR is run.  What this means is that no CPU registers or flags can be altered that the background code may be using.  The total state of the CPU, as far as the background code is aware, must be identical when the ISR returns as when the interrupt triggered.  So the ISR must save the state of the CPU on entry, and restore that same state on exit.

If using a high level language, the compiler will take care of most or all of this state saving and restoring.  The programmer simply has to tell the compiler that the ISR function is an ISR, and what interrupt it maps to, and the compiler will fill in the code details invisibly.  The compiler will add the following code to the ISR:

·         Before user ISR code, code to save all flags and registers necessary to maintain main code state

·         After user ISR code, code to restore all saved flags and registers in correct order

·         Finally, a return-from-interrupt instruction which performs any final cleanup such as restoring the saved status register, and returns program execution to the instruction after the interrupted instruction

The compiler will also handle mapping the actual ISR code to the associated interrupt.  If writing in ASM the programmer has to write all the state saving and restoring code explicitly, as well as explicitly place the address of the ISR into the appropriate interrupt vector or slot. 

Each possible interrupt will have an entry in a region of memory usually called the interrupt table or interrupt vector table.  Depending on the CPU design, these entries might contain actual code, or they might be data locations where the starting addresses of the associated ISRs are stored.  As it happens, the AVR uses the first form of interrupt table (each interrupt vector location contains a jump to the associated ISR), while the STM32 uses the second form of table (each interrupt vector location contains the address of the associated ISR).

Interrupt vector table entries for interrupts that will never be enabled can either be left empty, or can all be set to point to a dummy ISR that just returns immediately, or can all be set to point to an ISR that somehow logs and reports the unexpected interrupt (was it a hardware glitch?  did the programmer forget to write an ISR for an enabled interrupt?).