6.7.2. 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 can itself be interrupted. See Reentrant interrupt handlers for more information.

The __irq keyword:

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 when compiling Thumb C code. When compiling for Thumb (--thumb option or #pragma thumb), any functions specified as __irq are compiled for ARM.

However, the subroutine called by an __irq function can be compiled for Thumb, with interworking enabled. See Chapter 4 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 6.14 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 6.14. 

__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 6.14 produces the following code:


IRQHandler PROC
        STMFD    sp!,{r0-r4,r12,lr}
        MOV      r4,#0x80000000
        LDR      r0,[r4,#0]
        SUB      sp,sp,#4
        CMP      r0,#1
        BLEQ     C_int_handler
        MOV      r0,#0
        STR      r0,[r4,#4]
        ADD      sp,sp,#4
        LDMFD    sp!,{r0-r4,r12,lr}
        SUBS     pc,lr,#4
        ENDP

Compare this with the result when the __irq keyword is not used:


IRQHandler PROC
        STMFD    sp!,{r4,lr}
        MOV      r4,#0x80000000
        LDR      r0,[r4,#0]
        CMP      r0,#1
        BLEQ     C_int_handler
        MOV      r0,#0
        STR      r0,[r4,#4]
        LDMFD    sp!,{r4,pc}
        ENDP

Copyright © 2002-2006 ARM Limited. All rights reserved.ARM DUI 0203G
Non-Confidential