Define callbacks for interrupts

The ARMs implement an interrupt table to store the address for each interrupt handler (or callback, basically the same thing). Basically, all of the addresses of the interrupt handlers are stored in program memory at a predefined location. When an interrupt occurs, the processor knows where in the table that interrupt's entry is, grabs it and branches to the address stored there.

How do you populate this table? Usually all this information is contained in a startup file. Typically you just define a constant array of pointers, fill it with the addresses of the callbacks you want to use. Here is a website detailing how to create a startup file for a specific ARM microcontroller. The tricky thing about this is that almost all of the particulars of making the file depend heavily on the linker, compiler and chip you're using, so you'll either have to find an example out there or muddle through making your own.


the cortex-m3 is very interrupt friendly. You dont need a trampoline in asm or need to add any non-standard compiler syntax to make the compiler do it for you. The hardware conforms to an abi by preserving a certain number of registers for you as well as changing modes. The link register is encoded so that upon return from the function the hardware knows it is actually a return from interrupt. So all the things you had to do on an arm and many other processors you do not have to do.

Likewise, to a level of pain, the cortex-m (and other newer arms) have a zillion vectors in the vector table, dozens to hundreds of interrupts, etc. as mentioned in a comment above see http://github.com/dwelch67/stm32f4d the blinker05 example uses interrupts with a timer, you can see in vectors.s that all you do is place the name of the function:

.word hang
.word tim5_handler
.word hang

And then write the C code:

//-------------------------------------------------------------------
volatile unsigned int intcounter;
//-------------------------------------------------------------------
// CAREFUL, THIS IS AN INTERRUPT HANDLER
void tim5_handler ( void )
{
    intcounter++;
    PUT32(TIM5BASE+0x10,0x00000000);
}
// CAREFUL, THIS IS AN INTERRUPT HANDLER
//------------------------------------------------------------------

Now as with any interrupt from some peripheral/device you probably have to, in the handler, tell the device to clear the interrupt otherwise you might get stuck constantly re-entering the handler.

My examples dont use an IDE, they use open source tools (gnu gcc and binutils and llvm's clang compiler). Remove the clang binaries from the all: line in the makefile if you dont have/want to use llvm. The gnu tools are easy to come by, both building from sources (I have instructions somewhere at github, probably a number of places) or just get the lite version from codesourcery (now mentor graphics). My examples are developed and tested on linux, but that shouldnt discourage windows users, change a few things like rm -f *.o to del *.o, things like that or just build a batch file from the assembler/compiler/linker commands in the makefile.

I very highly recommend disassembling your binary, esp if you are trying to place a handler in the vector table, with so many it is easy to miscount and not have it at the right address. You need to know the address from the arm docs then check the disassembly. the blinker05 example when disassembled:

 8000100:       0800014f        stmdaeq r0, {r0, r1, r2, r3, r6, r8}
 8000104:       0800014f        stmdaeq r0, {r0, r1, r2, r3, r6, r8}
 8000108:       08000179        stmdaeq r0, {r0, r3, r4, r5, r6, r8}
 800010c:       0800014f        stmdaeq r0, {r0, r1, r2, r3, r6, r8}
 8000110:       0800014f        stmdaeq r0, {r0, r1, r2, r3, r6, r8}

offset 0x108 being the targeted entry. Note that the addresses in the table should be odd 0x178 is the actual address, arm wants the lsbit set to indicate it is a thumb instruction set address (the cortex-m3 only knows thumb and the thumb2 extensions it cannot execute arm instructions).