User guide

5.5 Interrupt handlers
The ARM processor has two levels of external interrupt, FIQ and IRQ, both of which are level-sensitive active LOW
signals into the core. For an interrupt to be taken, the appropriate disable bit in the CPSR must be clear.
FIQs have higher priority than IRQs in two ways:
FIQs are serviced first when multiple interrupts occur.
Servicing a FIQ causes IRQs to be disabled, preventing them from being serviced until after the FIQ handler
has re-enabled them. This is usually done by restoring the CPSR from the SPSR at the end of the handler.
The FIQ vector is the last entry in the vector table (at address 0x1C) so that the FIQ handler can be placed directly at
the vector location and run sequentially from that address. This removes the need for a branch and its associated
delays, and also means that if the system has a cache, the vector table and FIQ handler may all be locked down in
one block within it. This is important because FIQs are designed to service interrupts as quickly as possible. The five
extra FIQ mode banked registers enable status to be held between calls to the handler, again increasing execution
speed.
Note
An interrupt handler must contain code to clear the source of the interrupt.
5.5.1 Simple interrupt handlers in C
You can write simple C interrupt handlers by using the __irq function declaration keyword. You can use the __irq
keyword both for simple one-level interrupt handlers, and interrupt handlers that call subroutines. However, you
cannot use the __irq keyword for reentrant interrupt handlers, because it does not cause the SPSR to be saved or
restored. In this context, reentrant means that the handler re-enables interrupts, and may itself be interrupted. See
Reentrant interrupt handlers for more information.
The __irq keyword:
preserves all ATPCS corruptible registers
preserves all other registers (excluding the floating-point registers) used by the function
exits the function by setting the program counter to (lr 4) and restoring the CPSR to its original value.
If the function calls a subroutine, __irq preserves the link register for the interrupt mode in addition to preserving the
other corruptible registers. See Calling subroutines from interrupt handlers for more information.
Note
C interrupt handlers cannot be produced in this way using tcc. The __irq keyword is faulted by tcc because tcc can
only produce Thumb code, and the processor is always switched to ARM state when an interrupt, or any other
exception, occurs.
However, the subroutine called by an __irq function can be compiled for Thumb, with interworking enabled. See
Chapter 3 Interworking ARM and Thumb for more information on interworking.
Calling subroutines from interrupt handlers
If you call subroutines from your top-level interrupt handler, the __irq keyword also restores the value of lr_IRQ
from the stack so that it can be used by a SUBS instruction to return to the correct address after the interrupt has
been handled.
Example 5-13 shows how this works. The top level interrupt handler reads the value of a memory-mapped interrupt
controller base address at 0x80000000. If the value of the address is 1, the top-level handler branches to a handler
written in C.
Example 5-13
__irq void IRQHandler (void)
{
volatile unsigned int *base = (unsigned int *) 0x80000000;
if (*base == 1) // which interrupt was it?
{
C_int_handler(); // process the interrupt
}
*(base+1) = 0; // clear the interrupt
}
Compiled with armcc, Example 5-13 produces the following code:
IRQHandler PROC
STMFD sp!,{r0-r4,r12,lr}
Handling Processor Exceptions
Copyright ?1999 2001 ARM Limited 5-14