Configuring ARM interrupts
The ARM Cortex A9 core has two external interrupt request ports; one for ‘Fast interrupt requests’ (FIQ
) and for normal interrupts (IRQ
). When an interrupt is requested on either of these ports, based on the internal configuration of the core, the core may jump to an interrupt handler. This document details the configuration of the core so interrupts can be enabled or disabled.
Current Program Status Register
The Current Program Status Register (CPSR) is a special register in the ARM that configures the processor’s mode as well as enabling or disabling interrupts. It’s bitfields are shown below:
For the Purpose of this Document we will only examine the lowest byte. All other fields in the CPSR should remain unmodified.
The diagram shows that bits 7 and 6 are the I
and F
bits respectively. The I
bit is for disabled/enabling IRQ
(interrupt request) interrupts and the F
bit is for disabling/enabling FIQ
(fast interrupt request) interrupts. A 1
written to one of these bits disables the corresponding interrupt. Conversely, a 0
enables the specified interrupt.
Additionally, the least significant 5 bits in the CPSR determine which mode the processor is in. Writing 5b11111
to the mode will set the core to System Mode
allowing protected resources to be modified.
The T
bit should also be set to 0
to ensure the processor stays in ARM mode and not thumb mode.
Disabling ARM Interrupts
To modify the CPSR through c code, you need to make use of inline assembly. You’ll need 2 assembly instructions (in addition to operations done with c code). The MRS instruction moves the contents of a special register to a general purpose register. Likewise, the MSR moves a GPR’s value to a special register. The below code modifies the CPSR to put it into system mode with both the FIQ and IRQ disabled.
void disable_arm_interrupts(void)
{
uint32_t cpsr_val =0;
asm("mrs %0, cpsr\n" : "=r" (cpsr_val) ); //get current cpsr
cpsr_val &= ~(0xFF); //clear lower 8 bits
cpsr_val |= 0xDF; //set all bits but the 'T' bit
asm("msr cpsr, %0\n" : : "r" (cpsr_val)); //writeback modified value
return;
}
Enabling Interrupts
Conversly, To renable interrupts, just clear the ‘I’ bit in the CPSR.
void enable_arm_interrupts(void)
{
uint32_t cpsr_val =0;
asm("mrs %0, cpsr\n" : "=r" (cpsr_val) ); //get current cpsr value
cpsr_val &= ~(0xFF); //clear lower 8 bits
cpsr_val |= 0x5F; //set all bits but 'T' and 'I' bit
asm("msr cpsr, %0\n" : : "r" (cpsr_val)); //writeback modified value
return;
}
After enabling interrupts via the CPSR, the processor will jump to the IRQ vector once it receives a request on the IRQ port. In the Zynq system, interrupt requests are arbitrated through the Generic Interrupt Controller (GIC). First it must be configured before it will generate interrupt requests. Additionally, code for servicing requests needs to be written and registered into the vector table.
Information on configuring the GIC can be found in this document: Configuring the GIC
Information for writing and registering Interrupt handlers can be found here : Interrupt Handlers