5.4. Interrupt Vectors and Handlers

CS3 provides standard handlers for interrupts, exceptions and traps, but also allows you to define your own handlers as needed. In this section, we use the term interrupt as a generic term for this entire class of events.

Different processors handle interrupts in various ways, but there are three general approaches:

M-profile processors like the Cortex-M3 use the address vector model. Classic ARM processors (including ARM7/ARM9 as well as Cortex-A/R series processors) are technically code vector processors. However, each vector slot only holds a single instruction. CS3 emulates the address vector model on these processors by placing an indirect branch instruction in each slot of the real exception vector. The remainder of this section assumes that you have some understanding of the specific requirements for your target; refer to the architecture manuals if necessary.

5.4.1. ARM EABI Interrupt Vector Implementation

On address vector processors, the CS3 library provides an array of pointers to interrupt handlers named __cs3_interrupt_vector_form, where form identifies the particular processor variant the vector is appropriate for. Each entry in the vector holds a reference to a symbol named __cs3_isr_name, where name is the customary name of that interrupt on the processor, or a number if there is no consistently used name. You can find the interrupt vector details in Section 5.6, “Interrupt Vector Tables”. The particular vector used by a given CS3-supported board is documented in the tables in Section 5.5, “Supported Boards for ARM EABI”.

CS3 provides a reasonable default definition for each __cs3_isr_name handler. Many of these symbols are aliased to a common handler routine. If your program stops at a default interrupt handler, its name as shown in backtraces may therefore not correctly reflect which interrupt occurred.

To override an individual handler, provide your own definition for the appropriate __cs3_isr_name symbol. The definition need not be placed in any particular object file section.

To override the entire interrupt vector, you can define __cs3_interrupt_vector_form. You must place this definition in a section named .cs3.interrupt_vector. The linker script reports an error if the .cs3.interrupt_vector section is empty, to ensure that the definition of __cs3_interrupt_vector_form occupies the proper section.

You may define the vector in C with an array of pointers using the section attribute to place it in the appropriate section. For example, to override the interrupt vector on Altera Cyclone III Cortex-M1 boards, make the following definition:

typedef void handler(void);
handler *__attribute__((section (".cs3.interrupt_vector")))
  __cs3_interrupt_vector_micro[] =
{ ... };

5.4.2. Writing Interrupt Handlers

Interrupt handlers typically require special call/return and register usage conventions that are target-specific and beyond the scope of this document. In many cases, normal C functions cannot be used as interrupt handlers. For example, the EABI requires that the stack be 8-byte aligned, but on some ARMv7-M processors, only 4-byte stack alignment is guaranteed when calling an interrupt vector. This can cause subtle runtime failures, usually when 8-byte types are used.

As an alternative to writing interrupt handlers in assembly language, on ARM targets they may be written in C using the interrupt attribute. This tells the compiler to generate appropriate function entry and exit sequences for an interrupt handler. For example, to override the __cs3_isr_nmi handler, use the following definition:

void __attribute__ ((interrupt)) __cs3_isr_nmi (void)
{
  ... custom handler code ...
}
On ARM targets, the interrupt attribute also takes an optional parameter to specify the type of interrupt. Refer to the GCC manual for more details about attribute syntax and usage.