# Interrupt (Overview)

## Introduction

Interrupts provide a mechanism for temporarily interrupting one executing program so a more urgent program can execute, and then resume execution of the first program.

If some special process needs to be conducted because of the state of the system or hardware, the only way to implement that process—if interrupts are not employed—is to check the status periodically (polling) to look for an opportunity. But if interrupts are used, a program that has been prepared for a set of conditions can be executed immediately when those conditions arise. The interrupt mechanism provides more immediacy than polling, and it lets the main program devote itself to its own processes.

This page explains the functions that handle interrupts.

### Interrupt Causes

A variety of events can cause interrupts, and the causes differ for the ARM9 and the ARM7. Below is a list of of interrupt names and their causes on the ARM9.

`OS_IE_V_BLANK` | V blank interrupt
`OS_IE_H_BLANK` | H blank interrupt
`OS_IE_V_COUNT` | V counter interrupt
`OS_IE_TIMER0` | Timer0 interrupt
`OS_IE_TIMER1` | Timer1 interrupt
`OS_IE_TIMER2` | Timer2 interrupt
`OS_IE_TIMER3` | Timer3 interrupt
`OS_IE_DMA0` | DMA0 interrupt
`OS_IE_DMA1` | DMA1 interrupt
`OS_IE_DMA2` | DMA2 interrupt
`OS_IE_DMA3` | DMA3 interrupt
`OS_IE_KEY` | Key interrupt
`OS_IE_CARTRIDGE` | Game Pak IREQ/DREQ interrupt
`OS_IE_SUBP` | ARM7 interrupt
`OS_IE_SPFIFO_SEND` | ARM9-ARM7 send FIFO empty interrupt
`OS_IE_SPFIFO_RECV` | ARM9-ARM7 receive FIFO not-empty interrupt
`OS_IE_CARD_DATA` | Card data transfer end interrupt
`OS_IE_CARD_IREQ` | Card IREQ interrupt
`OS_IE_GXFIFO` | Geometry command FIFO interrupt

### Registers and Work Regions Associated With Interrupts

The `reg_IME (0x04000208)` register functions as the master enable/disable flag—setting all interrupts. When the bit is `1`, all interrupts are enabled. When the bit is `0`, all interrupts are disabled.

The I/O register, `reg_IE (0x04000210)`, specifies which causes are allowed to generate interrupts. When the bit for a cause is set to `1`, it is permitted to generate an interrupt.

Each bit in the Interrupt Request register `reg_IF (0x03000214)` takes the value `1` when the corresponding interrupt gets generated. The relation between interrupts and bits is the same as that for the `reg_IE` register.

The ARM9 processor's Current Program Status Register (CPSR) has a bit that defines whether IRQs are enabled. (See System (overview)for details.) IRQs are disabled when the `I` flag of this register is `1` and are enabled when the bit is `0`.

Check-flag regions are set up so the interrupt handlers can check things out when interrupts are generated. These regions are located in DTCM. The relation between interrupt causes and bits is the same as that for the `reg_IE` register.

Interrupts are a kind of processor exception. When an interrupt occurs, the system jumps to the address stored in the interrupt vector `HW_INTR_VECTOR_BUF`. The address for the OS IRQ handler is usually stored here, but you can overwrite the value if you want to use your own interrupt routine. This region is also located in DTCM.

### Process Flow For an Interrupt

The interrupt signal from a device or elsewhere reaches the processor through the flow depicted below:

If the specified device has been configured so the IF flag is set when an IRQ is generated, then the corresponding IF bit will take the value `1` when an IRQ is generated and fully satisfies the device's IRQ conditions. (This is not related to the register settings for interrupts that were mentioned above.)

An interrupt will not be generated if the interrupt cause associated with that standing IF flag bit has not been set in the IE register. An interrupt will also not be generated if the IME master enable flag has been set to disable all interrupts. If none of these conditions exist the interrupt signal will reach the ARM9 processor, but an IRQ interrupt still will not be generated if the CPSR's IRQ flag is set to `1` (disable). However, if the CPSR's IRQ flag is set to `0`, an IRQ interrupt will be generated.

IRQ interrupts are a kind of ARM processor exception (called an IRQ exception). For details, see Exceptions (overview).

When an IRQ interrupt is generated, the ARM9 processor interrupts the program and jumps to `0xFFFF0018`. Take a look at the flow shown below.

After the process jumps to `0xFFFF0018`, control is transferred to the address stored in `HW_INTR_VECTOR_BUF` in some region of DTCM. The address for the OS IRQ handler is usually stored here, so overwrite `HW_INTR_VECTOR_BUF` if you want to create your own IRQ handler. The user's preregistered interrupt handler is called from inside the IRQ handler. After that, the program starts again from the address where the interrupt occurred. (Actually, the thread can also switch. See Threads (overview).)

Following is a more detailed description of the processes inside the OS IRQ handler.

Once inside the handler, the process first checks whether the IME register enables interrupts and returns without doing anything if the answer is "No." Otherwise, the next step is to perform a logical AND on the IE and IF bits. If the result is `0`, the process returns without doing anything. Otherwise, the process continues by calling the interrupt handler corresponding to the bit that is `1`. The IME, IE, and IF bits are checked because it is possible for an interrupt signal to make it to the processor while some process is accessing the I/O register and making changes to prohibited interrupts and the causes of interrupts. These checks thus ensure that the settings in the I/O register are correctly followed.

The interrupt handler called is one that has already been registered in the IRQ table by the user. This table is referenced from the IRQ handler to determine the address of the user's interrupt handler.

After the process comes back from the user's interrupt handler it returns to the user program. However, if a thread-switch event occurs inside the interrupt handler, thread rescheduling occurs (see Threads (overview)).

Set a check flag for the interrupt inside the user's interrupt handler. This check flag is used by other OS functions. If these functions will not be using the check flag, it does not need to be set. However, we recommend that you set it anyway so it is there just in case later changes require its presence. (See `OS_SetIrqCheckFlag()`.)

### Enabling/Disabling Interrupts

These functions can be used to control the master enable flag for all interrupts:

`OS_EnableIrq()`, `OS_DisableIrq()`, `OS_RestoreIrq()`

### Enabling/Disabling System State Interrupts

For details, see System (overview). These functions are "system" category functions, not "interrupt" category functions. They can be used to change the CPSR status.

`OS_EnableInterrupts()`, `OS_DisableInterrupts()`, `OS_RestoreInterrupts()`

### Configuring Interrupt Causes

The following functions can be used to set the causes of interrupts:

`OS_SetIrqMask()`, `OS_GetIrqMask()`, `OS_EnableIrqMask()`, `OS_DisableIrqMask()`

### Controlling Interrupt Request Flags

The following functions can be used to control interrupt request flags:

`OS_ResetRequestIrqMask()`, `OS_GetRequestIrqMask()`

### Configuring Interrupt Handlers

The following functions can be used to set interrupt handlers:

`OS_InitIrqTable()`, `OS_SetIrqFunction()`, `OS_GetIrqFunction()`

### Controlling the Interrupt Check Flag

The following functions can be used to control the interrupt check flag:

`OS_SetIrqCheckFlag()`, `OS_ClearIrqCheckFlag()`, `OS_GetIrqCheckFlag()`

### Waiting for Interrupts

The following functions are designed to wait until an interrupt occurs:

`OS_WaitIrq()`, `OS_WaitAnyIrq()`, `OS_WaitInterrupt()`

The arguments in `OS_WaitIrq()` and `OS_WaitInterrupt()` specify which interrupt to wait for. In contrast, `OS_WaitAnyIrq()` is designed to wait for any interrupt to occur.

`OS_WaitIrq()` and `OS_WaitInterrupt()` differ in the way they operate while waiting for an interrupt. `OS_WaitIrq()` switches the context and transfers the process to another thread, while `OS_WaitInterrupt()` stops when `OS_Halt()` is called, so no thread switching occurs. If you are not using the thread system, both functions behave the same way.

The `SVC_WaitVBlankIntr()` function is available to wait for a V blank in a system call.

### The V-Blank Counter

The following function is available to get the V-blank counter value used for V-blank interrupts:

`OS_GetVBlankCount()`

V-blank interrupts are always enabled in the ARM7, so this function internally writes the number of interrupts in the shared region of main memory. The ARM9 command reflects the value written in the shared region.

## See Also

List of OS Functions (Interrupts)

## Revision History

11/17/2004 Initial version