EXCEPTION AND INTERRUPT HANDLING
At the heart of an embedded system lie the exception handlers. They are responsible for handling errors, interrupts, and other events generated by the external system. Efficient handlers can dramatically improve system performance. The process of determining a good handling method can be complicated, challenging, and fun.
In this chapter we will cover the theory and practice of handling exceptions, and specifically the handling of interrupts on the ARM processor. The ARM processor has seven exceptions that can halt the normal sequential execution of instructions: Data Abort, Fast Interrupt Request, Interrupt Request, Prefetch Abort, Software Interrupt, Reset, and Undefined Instruction.
This chapter is divided into three main sections:
Exception handling. Exception handling covers the specific details of how the ARM processor handles exceptions.
Interrupts. ARM defines an interrupt as a special type of exception. This section discusses the use of interrupt requests, as well as introducing some of the common terms, features, and mechanisms surrounding interrupt handling.
Interrupt handling schemes. The final section provides a set of interrupt handling methods. Included with each method is an example implementation.
An exception is any condition that needs to halt the normal sequential execution of instructions. Examples are when the ARM core is reset, when an instruction fetch or memory access fails, when an undefined instruction is encountered, when a software interrupt instruction is executed, or when an external interrupt has been raised. Exception handling is the method of processing these exceptions.
Most exceptions have an associated software exception handler—a software routine that executes when an exception occurs. For instance, a Data Abort exception will have a Data Abort handler. The handler first determines the cause of the exception and then services the exception. Servicing takes place either within the handler or by branching to a specific service routine. The Reset exception is a special case since it is used to initialize an embedded system.
This section covers the following exception handling topics:
Table 9.1 lists the ARM processor exceptions. Each exception causes the core to enter a specific mode. In addition, any of the ARM processor modes can be entered manually by changing the cpsr. User and system mode are the only two modes that are not entered by a corresponding exception, in other words, to enter these modes you must modify the cpsr. When an exception causes a mode change, the core automatically
Table 9.1
ARM processor exceptions and associated modes.
Exception | Mode | Main purpose |
Fast Interrupt Request | FIQ | fast interrupt request handling |
Interrupt Request | IRQ | interrupt request handling |
SWI and Reset | SVC | protected mode for operating systems |
Prefetch Abort and Data Abort | abort | virtual memory and/or memory protection handling |
Undefined Instruction | undefined | software emulation of hardware coprocessors |
saves the cpsr to the spsr of the exception mode
saves the pc to the lr of the exception mode
Figure 9.1 shows a simplified view of exceptions and associated modes. Note that when an exception occurs the ARM processor always switches to ARM state.
Chapter 2 introduced the vector table—a table of addresses that the ARM core branches to when an exception is raised. These addresses commonly contain branch instructions of one of the following forms:
B <address>—This branch instruction provides a branch relative from the pc.
LDR pc, [pc, #offset]—This load register instruction loads the handler address from memory to the pc. The address is an absolute 32-bit value stored close to the vector table. Loading this absolute literal value results in a slight delay in branching to a specific handler due to the extra memory access. However, you can branch to any address in memory.
LDR pc, [pc, #-0xff0]—This load register instruction loads a specific interrupt service routine address from address 0xfffff030 to the pc. This specific instruction is only used when a vector interrupt controller is present (VIC PL190).
MOV pc, #immediate—This move instruction copies an immediate value into the pc. It lets you span the full address space but at limited alignment. The address must be an 8-bit immediate rotated right by an even number of bits.
You can also have other types of instructions in the vector table. For example, the FIQ handler might start at address offset +0x1c. Thus, the FIQ handler can start immediately at the FIQ vector location, since it is at the end of the vector table. The branch instructions cause the pc to jump to a specific location that can handle the specific exception.
Table 9.2 shows the exception, mode, and vector table offset for each exception.
Exceptions can occur simultaneously, so the processor has to adopt a priority mechanism. Table 9.3 shows the various exceptions that occur on the ARM processor and their associated priority level. For instance, the Reset exception is the highest priority and occurs when power is applied to the processor. Thus, when a reset occurs, it takes precedence over all other exceptions. Similarly, when a Data Abort occurs, it takes precedence over all other exceptions apart from a Reset exception. The lowest priority level is shared by two exceptions, the Software Interrupt and Undefined Instruction exceptions. Certain exceptions also disable interrupts by setting the I or F bits in the cpsr, as shown in Table 9.3.
Each exception is dealt with according to the priority level set out in Table 9.3. The following is a summary of the exceptions and how they should be handled, starting with the highest.
The Reset exception is the highest priority exception and is always taken whenever it is signaled. The reset handler initializes the system, including setting up memory and caches. External interrupt sources should be initialized before enabling IRQ or FIQ interrupts to avoid the possibility of spurious interrupts occurring before the appropriate handler has been set up. The reset handler must also set up the stack pointers for all processor modes.
During the first few instructions of the handler, it is assumed that no exceptions or interrupts will occur. The code should be designed to avoid SWIs, undefined instructions, and memory accesses that may abort, that is, the handler is carefully implemented to avoid further triggering of an exception.
Data Abort exceptions occur when the memory controller or MMU indicates that an invalid memory address has been accessed (for example, if there is no physical memory for an address) or when the current code attempts to read or write to memory without the correct access permissions. An FIQ exception can be raised within a Data Abort handler since FIQ exceptions are not disabled. When the FIQ is completely serviced, control is returned back to the Data Abort handler.
A Fast Interrupt Request (FIQ) exception occurs when an external peripheral sets the FIQ pin to nFIQ. An FIQ exception is the highest priority interrupt. The core disables both IRQ and FIQ exceptions on entry into the FIQ handler. Thus, no external source can interrupt the processor unless the IRQ and/or FIQ exceptions are reenabled by software. It is desirable that the FIQ handler (and also the abort, SWI, and IRQ handlers) is carefully designed to service the exception efficiently.
An Interrupt Request (IRQ) exception occurs when an external peripheral sets the IRQ pin to nIRQ. An IRQ exception is the second-highest priority interrupt. The IRQ handler will be entered if neither an FIQ exception nor Data Abort exception occurs. On entry to the IRQ handler, the IRQ exceptions are disabled and should remain disabled until the current interrupt source has been cleared.
A Prefetch Abort exception occurs when an attempt to fetch an instruction results in a memory fault. This exception is raised when the instruction is in the execute stage of the pipeline and if none of the higher exceptions have been raised. On entry to the handler, IRQ exceptions will be disabled, but the FIQ exceptions will remain unchanged. If FIQ is enabled and an FIQ exception occurs, it can be taken while servicing the Prefetch Abort.
A Software Interrupt (SWI) exception occurs when the SWI instruction is executed and none of the other higher-priority exceptions have been flagged. On entry to the handler, the cpsr will be set to supervisor mode.
If the system uses nested SWI calls, the link register r14 and spsr must be stored away before branching to the nested SWI to avoid possible corruption of the link register and the spsr.
An Undefined Instruction exception occurs when an instruction not in the ARM or Thumb instruction set reaches the execute stage of the pipeline and none of the other exceptions have been flagged. The ARM processor “asks” the coprocessors if they can handle this as a coprocessor instruction. Since coprocessors follow the pipeline, instruction identification can take place in the execute stage of the core. If none of the coprocessors claims the instruction, an Undefined Instruction exception is raised.
Both the SWI instruction and Undefined Instruction have the same level of priority, since they cannot occur at the same time (in other words, the instruction being executed cannot both be an SWI instruction and an undefined instruction).
When an exception occurs, the link register is set to a specific address based on the current pc. For instance, when an IRQ exception is raised, the link register lr points to the last executed instruction plus 8. Care has to be taken to make sure the exception handler does not corrupt lr because lr is used to return from an exception handler. The IRQ exception is taken only after the current instruction is executed, so the return address has to point to the next instruction, or lr – 4. Table 9.4 provides a list of useful addresses for the different exceptions.
Table 9.4
Useful link-register-based addresses.
Exception | Address | Use |
Reset | — | lr is not defined on a Reset |
Data Abort | lr – 8 | points to the instruction that caused the Data Abort exception |
FIQ | lr – 4 | return address from the FIQ handler |
IRQ | lr – 4 | return address from the IRQ handler |
Prefetch Abort | lr – 4 | points to the instruction that caused the Prefetch Abort exception |
SWI | lr | points to the next instruction after the SWI instruction |
Undefined Instruction | lr | points to the next instruction after the undefined instruction |
The next three examples show different methods of returning from an IRQ or FIQ exception handler.
There are two types of interrupts available on the ARM processor. The first type of interrupt causes an exception raised by an external peripheral—namely, IRQ and FIQ. The second type is a specific instruction that causes an exception—the SWI instruction. Both types suspend the normal flow of a program.
In this section we will focus mainly on IRQ and FIQ interrupts. We will cover these topics:
A system designer can decide which hardware peripheral can produce which interrupt request. This decision can be implemented in hardware or software (or both) and depends upon the embedded system being used.
An interrupt controller connects multiple external interrupts to one of the two ARM interrupt requests. Sophisticated controllers can be programmed to allow an external interrupt source to cause either an IRQ or FIQ exception.
When it comes to assigning interrupts, system designers have adopted a standard design practice:
Software Interrupts are normally reserved to call privileged operating system routines. For example, an SWI instruction can be used to change a program running in user mode to a privileged mode. For an SWI handler example, take a look at Chapter 11.
Interrupt Requests are normally assigned for general-purpose interrupts. For example, a periodic timer interrupt to force a context switch tends to be an IRQ exception. The IRQ exception has a lower priority and higher interrupt latency (to be discussed in the next section) than the FIQ exception.
Fast Interrupt Requests are normally reserved for a single interrupt source that requires a fast response time—for example, direct memory access specifically used to move blocks of memory. Thus, in an embedded operating system design, the FIQ exception is used for a specific application, leaving the IRQ exception for more general operating system activities.
Interrupt-driven embedded systems have to fight a battle with interrupt latency—the interval of time from an external interrupt request signal being raised to the first fetch of an instruction of a specific interrupt service routine (ISR).
Interrupt latency depends on a combination of hardware and software. System architects must balance the system design to handle multiple simultaneous interrupt sources and minimize interrupt latency. If the interrupts are not handled in a timely manner, then the system will exhibit slow response times.
Software handlers have two main methods to minimize interrupt latency. The first method is to use a nested interrupt handler, which allows further interrupts to occur even when currently servicing an existing interrupt (see Figure 9.3). This is achieved by reenabling the interrupts as soon as the interrupt source has been serviced (so it won’t generate more interrupts) but before the interrupt handling is complete. Once a nested interrupt has been serviced, then control is relinquished to the original interrupt service routine.
The second method involves prioritization. You program the interrupt controller to ignore interrupts of the same or lower priority than the interrupt you are handling, so only a higher-priority task can interrupt your handler. You then reenable interrupts.
The processor spends time in the lower-priority interrupts until a higher-priority interrupt occurs. Therefore higher-priority interrupts have a lower average interrupt latency than the lower-priority interrupts, which reduces latency by speeding up the completion time on the critical time-sensitive interrupts.
IRQ and FIQ exceptions only occur when a specific interrupt mask is cleared in the cpsr. The ARM processor will continue executing the current instruction in the execution stage of the pipeline before handling the interrupt—an important factor in designing a deterministic interrupt handler since some instructions require more cycles to complete the execution stage.
An IRQ or FIQ exception causes the processor hardware to go through a standard procedure (provided the interrupts are not masked):
1. The processor changes to a specific interrupt request mode, which reflects the interrupt being raised.
2. The previous mode’s cpsr is saved into the spsr of the new interrupt request mode.
3. The pc is saved in the lr of the new interrupt request mode.
4. Interrupt/s are disabled—either the IRQ or both IRQ and FIQ exceptions are disabled in the cpsr. This immediately stops another interrupt request of the same type being raised.
5. The processor branches to a specific entry in the vector table.
The procedure varies slightly depending upon the type of interrupt being raised. We will illustrate both interrupts with an example. The first example shows what happens when an IRQ exception is raised, and the second example shows what happens when an FIQ exception is raised.
The ARM processor core has a simple procedure to manually enable and disable interrupts that involves modifying the cpsr when the processor is in a privileged mode.
Table 9.5 shows how IRQ and FIQ interrupts are enabled. The procedure uses three ARM instructions.
The first instruction MRS copies the contents of the cpsr into register r1. The second instruction clears the IRQ or FIQ mask bit. The third instruction then copies the updated contents in register r1 back into the cpsr, enabling the interrupt request. The postfix _c identifies that the bit field being updated is the control field bit [7:0] of the cpsr. (For more details see Chapter 2.) Table 9.6 shows a similar procedure to disable or mask an interrupt request.
It is important to understand that the interrupt request is either enabled or disabled only once the MSR instruction has completed the execution stage of the pipeline. Interrupts can still be raised or masked prior to the MSR completing this stage.
To enable and disable both the IRQ and FIQ exceptions requires a slight modification to the second instruction. The immediate value on the data processing BIC or ORR instruction has to be changed to 0xc0 to enable or disable both interrupts.
Exceptions handlers make extensive use of stacks, with each mode having a dedicated register containing the stack pointer. The design of the exception stacks depends upon these factors:
Operating system requirements—Each operating system has its own requirements for stack design.
Target hardware—The target hardware provides a physical limit to the size and positioning of the stack in memory.
Two design decisions need to be made for the stacks:
The location determines where in the memory map the stack begins. Most ARM-based systems are designed with a stack that descends downwards, with the top of the stack at a high memory address.
Stack size depends upon the type of handler, nested or nonnested. A nested interrupt handler requires more memory space since the stack will grow with the number of nested interrupts.
A good stack design tries to avoid stack overflow—where the stack extends beyond the allocated memory—because it causes instability in embedded systems. There are software techniques that identify overflow and that allow corrective measures to take place to repair the stack before irreparable memory corruption occurs. The two main methods are (1) to use memory protection and (2) to call a stack check function at the start of each routine.
The IRQ mode stack has to be set up before interrupts are enabled—normally in the initialization code for the system. It is important that the maximum size of the stack is known in a simple embedded system, since the stack size is reserved in the initial stages of boot-up by the firmware.
Figure 9.6 shows two typical memory layouts in a linear address space. The first layout, A, shows a traditional stack layout with the interrupt stack stored underneath the code segment. The second layout, B, shows the interrupt stack at the top of the memory above the user stack. The main advantage of layout B over A is that B does not corrupt the vector table when a stack overflow occurs, and so the system has a chance to correct itself when an overflow has been identified.
In this final section we will introduce a number of different interrupt handling schemes, ranging from the simple nonnested interrupt handler to the more complex grouped prioritized interrupt handler. Each scheme is presented as a reference with a general description plus an example implementation.
The schemes covered are the following:
A nonnested interrupt handler handles and services individual interrupts sequentially. It is the simplest interrupt handler.
A nested interrupt handler handles multiple interrupts without a priority assignment.
A reentrant interrupt handler handles multiple interrupts that can be prioritized.
A prioritized simple interrupt handler handles prioritized interrupts.
A prioritized standard interrupt handler handles higher-priority interrupts in a shorter time than lower-priority interrupts.
A prioritized direct interrupt handler handles higher-priority interrupts in a shorter time and goes directly to a specific service routine.
A prioritized grouped interrupt handler is a mechanism for handling interrupts that are grouped into different priority levels.
A VIC PL190 based interrupt service routine shows how the vector interrupt controller (VIC) changes the design of an interrupt service routine.
The simplest interrupt handler is a handler that is nonnested: the interrupts are disabled until control is returned back to the interrupted task or process. Because a nonnested interrupt handler can only service a single interrupt at a time, handlers of this form are not suitable for complex embedded systems that service multiple interrupts with differing priority levels.
Figure 9.8 shows the various stages that occur when an interrupt is raised in a system that has implemented a simple nonnested interrupt handler:
1. Disable interrupt/s—When the IRQ exception is raised, the ARM processor will disable further IRQ exceptions from occurring. The processor mode is set to the appropriate interrupt request mode, and the previous cpsr is copied into the newly available spsr_{interrupt request mode}. The processor will then set the pc to point to the correct entry in the vector table and execute the instruction. This instruction will alter the pc to point to the specific interrupt handler.
2. Save context—On entry the handler code saves a subset of the current processor mode nonbanked registers.
3. Interrupt handler—The handler then identifies the external interrupt source and executes the appropriate interrupt service routine (ISR).
4. Interrupt service routine—The ISR services the external interrupt source and resets the interrupt.
5. Restore context—The ISR returns back to the interrupt handler, which restores the context.
6. Enable interrupts—Finally, to return from the interrupt handler, the spsr_{interrupt request mode} is restored back into the cpsr. The pc is then set to the next instruction after the interrupt was raised.
SUMMARY: Simple Nonnested Interrupt Handler
Handles and services individual interrupts sequentially.
High interrupt latency; cannot handle further interrupts occurring while an interrupt is being serviced.
Advantages: relatively easy to implement and debug.
Disadvantage: cannot be used to handle complex embedded systems with multiple priority interrupts.
A nested interrupt handler allows for another interrupt to occur within the currently called handler. This is achieved by reenabling the interrupts before the handler has fully serviced the current interrupt.
For a real-time system this feature increases the complexity of the system but also improves its performance. The additional complexity introduces the possibility of subtle timing issues that can cause a system failure, and these subtle problems can be extremely difficult to resolve. A nested interrupt method is designed carefully so as to avoid these types of problems. This is achieved by protecting the context restoration from interruption, so that the next interrupt will not fill the stack (cause stack overflow) or corrupt any of the registers.
The first goal of any nested interrupt handler is to respond to interrupts quickly so the handler neither waits for asynchronous exceptions, nor forces them to wait for the handler. The second goal is that execution of regular synchronous code is not delayed while servicing the various interrupts.
The increase in complexity means that the designers have to balance efficiency with safety, by using a defensive coding style that assumes problems will occur. The handler has to check the stack and protect against register corruption where possible.
Figure 9.9 shows a nested interrupt handler. As can been seen from the diagram, the handler is quite a bit more complicated than the simple nonnested interrupt handler described in Section 9.3.1.
The nested interrupt handler entry code is identical to the simple nonnested interrupt handler, except that on exit, the handler tests a flag that is updated by the ISR. The flag indicates whether further processing is required. If further processing is not required, then the interrupt service routine is complete and the handler can exit. If further processing is required, the handler may take several actions: reenabling interrupts and/or performing a context switch.
Reenabling interrupts involves switching out of IRQ mode to either SVC or system mode. Interrupts cannot simply be reenabled when in IRQ mode because this would lead to possible link register r14_irq corruption, especially if an interrupt occurred after the execution of a BL instruction. This problem will be discussed in more detail in Section 9.3.3.
Performing a context switch involves flattening (emptying) the IRQ stack because the handler does not perform a context switch while there is data on the IRQ stack. All registers saved on the IRQ stack must be transferred to the task’s stack, typically on the SVC stack. The remaining registers must then be saved on the task stack. They are transferred to a reserved block of memory on the stack called a stack frame.
SUMMARY: Nested Interrupt Handler
Handles multiple interrupts without a priority assignment.
Medium to high interrupt latency.
Advantage—can enable interrupts before the servicing of an individual interrupt is complete reducing interrupt latency.
Disadvantage—does not handle prioritization of interrupts, so lower priority interrupts can block higher priority interrupts.
A reentrant interrupt handler is a method of handling multiple interrupts where interrupts are filtered by priority, which is important if there is a requirement that interrupts with higher priority have a lower latency. This type of filtering cannot be achieved using the conventional nested interrupt handler.
The basic difference between a reentrant interrupt handler and a nested interrupt handler is that the interrupts are reenabled early on in the reentrant interrupt handler, which can reduce interrupt latency. There are a number of issues relating to reenabling interrupts early, which will be described in more detail later on in this section.
All interrupts in a reentrant interrupt handler must be serviced in SVC, system, undefined instruction, or abort mode on the ARM processor.
If interrupts are reenabled in an interrupt mode and the interrupt routine performs a BL subroutine call instruction, the subroutine return address will be set in the register r14_irq. This address would be subsequently destroyed by an interrupt, which would overwrite the return address into register r14_irq. To avoid this, the interrupt routine should swap into SVC or system mode. The BL instruction can then use register r14_svc to store the subroutine return address. The interrupts must be disabled at the source by setting a bit in the interrupt controller before reenabling interrupts via the cpsr.
If interrupts are reenabled in the cpsr before processing is complete and the interrupt source is not disabled, an interrupt will be immediately regenerated, leading to an infinite interrupt sequence or race condition. Most interrupt controllers have an interrupt mask register that allows you to mask out one or more interrupts, but the remaining interrupts are still enabled.
The interrupt stack is unused since interrupts are serviced in SVC mode (for example, on the task’s stack). Instead the IRQ stack register r13 is used to point to a 12-byte structure that will be used to store some registers temporarily on interrupt entry.
It is paramount to prioritize interrupts in a reentrant interrupt handler. If the interrupts are not prioritized, the system latency degrades to that of a nested interrupt handler because lower-priority interrupts will be able to preempt the servicing of a higher-priority interrupt. This in turn leads to the locking out of higher-priority interrupts for the duration of the servicing of a lower-priority interrupt.
Both the nonnested interrupt handler and the nested interrupt handler service interrupts on a first-come-first-served basis. In comparison, the prioritized interrupt handler will associate a priority level with a particular interrupt source. The priority level is used to dictate the order that the interrupts will be serviced. Thus, a higher-priority interrupt will take precedence over a lower-priority interrupt, which is a particularly desirable characteristic in many embedded systems.
Methods of handling prioritization can either be achieved in hardware or software. For hardware prioritization, the handler is simpler to design since the interrupt controller will provide the current highest-priority interrupt that requires servicing. These systems require more initialization code at startup since the interrupts and associated priority level tables have to be constructed before the system can be switched on; software prioritization, on the other hand, requires the additional assistance of an external interrupt controller. This interrupt controller has to provide a minimal set of functions that include being able to set and un-setmasks, and to read the interrupt status and source.
The rest of this section will cover a software prioritization technique chosen because it is a general method and does not rely on a specialized interrupt controller. To help describe the priority interrupt handler, we will introduce a fictional interrupt controller based upon a standard interrupt controller from ARM. The controller takes multiple interrupt sources and generates an IRQ and/or FIQ signal depending upon whether a particular interrupt source is enabled or disabled.
Figure 9.11 shows a flow diagram of a simple priority interrupt handler, based on a reentrant interrupt handler.
SUMMARY: Prioritized Simple Interrupt Handler
Handles prioritized interrupts.
Advantage: deterministic interrupt latency since the priority level is identified first and then the service is called after the lower-priority interrupts are masked.
Disadvantage: the time taken to get to a low-priority service routine is the same as for a high-priority routine.
Following on from the prioritized simple interrupt handler, the next handler adds an additional level of complexity. The prioritized simple interrupt handler tested all the interrupts to establish the highest priority—an inefficient method of establishing the priority level but it does have the advantage of being deterministic since each interrupt priority will take the same length of time to be identified.
An alternative approach is to jump early when the highest-priority interrupt has been identified (see Figure 9.13), by setting the pc and jumping immediately once the priority level has been established. This means that the identification section of the code for the prioritized standard interrupt handler is more involved than for the prioritized simple interrupt handler. The identification section will determine the priority level and jump immediately to a routine that will handle the masking of the lower-priority interrupts and then jump again via a jump table to the appropriate ISR.
SUMMARY: Prioritized Standard Interrupt Handler
Handles higher-priority interrupts in a shorter time than lower-priority interrupts.
Advantage: higher-priority interrupts treated with greater urgency with no duplication of code to set external interrupt masks.
Disadvantage: there is a time penalty since this handler requires two jumps, resulting in the pipeline being flushed each time a jump occurs.
One difference between the prioritized direct interrupt handler and the prioritized standard interrupt handler is that some of the processing is moved out of the handler into the individual ISRs. The moved code masks out the lower-priority interrupts. Each ISR will have to mask out the lower-priority interrupts for the particular priority level, which can be a fixed number since the priority level has already been previously determined.
The second difference is that the prioritized direct interrupt handler jumps directly to the appropriate ISR. Each ISR is responsible for disabling the lower-priority interrupts before modifying the cpsr to reenable interrupts. This type of handler is relatively simple since the masking is done by the individual ISR, but there is a small amount of code duplication since each interrupt service routine is effectively carrying out the same task.
SUMMARY: Prioritized Direct Interrupt Handler
Handles higher-priority interrupts in a shorter time. Goes directly to the specific ISR.
Advantage: uses a single jump and saves valuable cycles to go to the ISR.
Disadvantage: each ISR has a mechanism to set the external interrupt mask to stop lower-priority interrupts from halting the current ISR, which adds extra code to each ISR.
Lastly, the prioritized grouped interrupt handler differs from the other prioritized interrupt handlers since it is designed to handle a large set of interrupts. This is achieved by grouping interrupts together and forming a subset, which can then be given a priority level.
The designer of an embedded system must identify each subset of interrupt sources and assign a group priority level to that subset. It is important to be careful when selecting the subsets of interrupt sources since the groups can determine the characteristics of the system. Grouping the interrupt sources together tends to reduce the complexity of the handler since it is not necessary to scan through every interrupt to determine the priority level. If a prioritized grouped interrupt handler is well designed, it will dramatically improve overall system response times.
SUMMARY: Prioritized Grouped Interrupt Handler
Mechanism for handling interrupts that are grouped into different priority levels.
Advantage: useful when the embedded system has to handle a large number of interrupts, and also reduces the response time since the determining of the priority level is shorter.
Disadvantage: determining how the interrupts are grouped together.
To take advantage of the vector interrupt controller, the IRQ vector entry has to be modified.
This instruction loads an ISR address from the memory mapped location 0xffffff030 into the pc which bypasses any software interrupt handler since the interrupt source can be obtained directly from the hardware. It also reduces interrupt latency since there is only a single jump to a specific ISR.
Here is an example of VIC service routine:
This routine saves the context and s psr_irq before clearing the interrupt source. Once this is complete, the IRQ exceptions can be reenabled by clearing the i bit, and the processor mode is set to system mode. The service routine can then process the interrupt in system mode. Once complete, the IRQ exceptions are disabled by setting the i bit, and the processor mode is switched back to IRQ mode.
The spsr_irq is restored from the IRQ stack, preparing the routine to return to the interrupted task.
The service routine then writes to the VICVectorAddr register in the controller. Writing to this address indicates to the priority hardware that the interrupt has been serviced.
Note that since the VIC is basically a hardware interrupt handler, the array of ISR addresses must be preprogrammed into the VIC before it is activated.
An exception changes the normal sequential execution of instructions. There are seven exceptions: Data Abort, Fast Interrupt Request, Interrupt Request, Prefetch Abort, Software Interrupt, Reset, and Undefined Instruction. Each exception has an associated ARM processor mode. When an exception is raised, the processor goes into a specific mode and branches to an entry in the vector table. Each exception also has a priority level.
Interrupts are a special type of exception that are caused by an external peripheral. The IRQ exception is used for general operating system activities. The FIQ exception is normally reserved for a single interrupt source. Interrupt latency is the interval of time from an external interrupt request signal being raised to the first fetch of an instruction of a specific interrupt service routine (ISR).
We covered eight interrupt handling schemes, from a very simple nonnested interrupt handler that handles and services individual interrupts, to an advanced prioritized grouped interrupt handler that handles interrupts that are grouped into different priority levels.
3.12.151.154