We want to do most of our ISR in C, since it’s a much easier language to write for than assembly.
Let’s assume that we are writing an ISR called my_isr
. We would put this into the vector table in the setup code for whichever interrupt we want. This ISR needs to be written in assembly, but there is nothing stopping an ISR from calling other functions. We need to be careful about how we do it (see below), but we are free to call whatever functions we want.
Let’s presume that we’ve written a C function called my_isr_c
that is a helper function for the assembly. In the simplest case, this function would take no arguments. The assembly code might look something like this:
Step-by-step:
- Line 1-4: Setup. We defining an
AREA
that is forCODE
, then declaring to the assembler that a function,my_isr_c
, is written external to this file. We makemy_isr
global, and preserve the stack alignment. - Line 8-9: Create the function. We then push LR onto the stack because we are calling a function – when we call a function, we want to return back here, so we need the return address. Pushing R4 through R11 is optional, but is usually a good idea since these registers may not be preserved in the function.
- Line 12: Next, we BL to the C function. The “B” part is just a function call, and the “L” is “link”, or “return to the return address stored in LR”. The function, which is just a basic C function written however we want, gets called and returns.
- Line 15-16: We restore the context.
- Line 19: We BX from LR.
Pitfall: Doing too much inside of ISRs
Nesting interrupts or tail-chaining them sucks. Weird things can happen to the registers, we need to do more in assembly than most people are comfortable with (which is zero), and the key point – if we are inside of an ISR we are, by definition, not doing what the main program is supposed to do anyway!
ISRs are not where your code should be written. Instead, they should be short, clear, and fast.
- This lets us get out of the ISR quickly and minimize the chances of nesting/tail-chaining anyway.
- Bugs in interrupt code cause bigger problems, since we are in a privileged mode of operation. The big takeaway here is – do as much in your ISR as you need, but no more. If you can do it in the main code, do it there.