Keil Logo

CARM: NESTING INTERRUPTS


Information in this article applies to:

  • CARM Version 0.20 or higher

QUESTION

The classic ARM architecture only provides two interrupts (IRQ and FIQ). The Vectored Interrupt Controller or Advanced Interrupt Controller provides interrupt priorities and interrupt nesting for the standard interrupt, but it requires that you set the I bit in the CPSR.

In this context I have the following questions:

  • Is it required to switch the CPU into the User/System Mode?
  • What is the code sequence to set the I bit?
  • What is the best method to allow interrupt nesting?

ANSWER

It should be noted that good programming technique implies that you keep interrupt functions very short. When you are using short interrupt functions, interrupt nesting becomes unimportant. When you are using an Real-Time Operating System (such as Advanced RTX), the stack usage of user tasks becomes unpredictable when you allow interrupt nesting.

However, if you still need interrupt nesting in your application, you may implement it as described below:

  • Is it required to switch the CPU into the User/System Mode?
    Yes, it is required to switch the CPU into the User/System Mode. Otherwise it would be impossible to call other functions within the interrupt service routine.
  • What is the code sequence to set the I bit?
    With in-line assembly it is very simple to access the I bit in the CPSR. You may use the macros IENABLE and IDISABLE that are shown below in your application code.
  • What is the best method to allow interrupt nesting?
    An example for interrupt nesting is shown below.

You may nest interrupts by using the macros IENABLE and IDISABLE at beginning and end of an interrupt service routine.

#define IENABLE                      /* Nested Interrupts Entry */   \ 
  __asm { MRS     LR, SPSR      }    /* Copy SPSR_irq to LR     */   \ 
  __asm { STMFD   SP!, {LR}     }    /* Save SPSR_irq           */   \ 
  __asm { MSR     CPSR_c, #0x1F }    /* Enable IRQ (Sys Mode)   */   \ 
  __asm { STMFD   SP!, {LR}     }    /* Save LR                 */   \ 
#define IDISABLE                      /* Nested Interrupts Exit */   \ 
  __asm { LDMFD   SP!, {LR}     }     /* Restore LR              */   \ 
  __asm { MSR     CPSR_c, #0x92 }     /* Disable IRQ (IRQ Mode)  */   \ 
  __asm { LDMFD   SP!, {LR}     }     /* Restore SPSR_irq to LR  */   \ 
  __asm { MSR     SPSR_cxsf, LR }     /* Copy LR to SPSR_irq     */   \ 

The usage is as shown below:

void interrupt_srv (void) __irq {
  IENABLE;                            // allow nested interrupts
  ... // interrupt code
  IDISABLE;                           // disable interrupt nesting
}

Depending on interrupt controller, it might be required to clear the interrupt source and acknowledge the interrupt. So in reality an implementation might look like the following example:

/* External Interrupt 1 Service */
void eint1_srv (void) __irq {
  EXTINT      = 2;                    // Clear EINT1 interrupt flag
  IENABLE;                            // allow nested interrupts
  delay ();
  ++intrp_count;                      // increment interrupt count
  IDISABLE;                           // disable interrupt nesting
  VICVectAddr = 0;                    // Acknowledge Interrupt
}

MORE INFORMATION

  • Getting Started User's Guide

SEE ALSO

FORUM THREADS

The following Discussion Forum threads may provide information related to this topic.

Last Reviewed: Thursday, March 31, 2005


Did this article provide the answer you needed?
 
Yes
No
Not Sure
 
  Arm logo
Important information

This site uses cookies to store information on your computer. By continuing to use our site, you consent to our cookies.

Change Settings

Privacy Policy Update

Arm’s Privacy Policy has been updated. By continuing to use our site, you consent to Arm’s Privacy Policy. Please review our Privacy Policy to learn more about our collection, use and transfers
of your data.