Saravana Pandian Annamalai
27. October 2016 · Write a comment · Categories: ARM, Embedded Software, Technology · Tags:

With an understanding of ARM registers and Exception model, now we are ready to explore the ARM interrupt controllers. These are the modules that sit in between the interrupt sources (peripherals) and ARM cores deciding how to route the interrupts to.

The ARM core accepts only two input signals handling unscheduled interrupts from the external systems – nIRQ and nFIQ. If IRQ is asserted, the system enters IRQ mode as discussed earlier or if FIQ is asserted, FIQ mode is entered.

It is up to the ARM licences i.e SoC manufacturer to decide the mechanism to route the interpret signals to the core. There are many ways to implement the interrupt controllers each of which are discussed in detail in this blog.

Vendor Specific Model

In the early ARM implementations where there used to be only one core in general, the logic for this routing of interrupts to the core is done by the SoC manufacturer mostly based on their design philosophy. More likely there will be a set of following registers

  • RAW Interrupt Status register
  • Interrupt Enable Register
  • Interrupt Status Register
  • IRQ Priority Encoding
  • FIQ/IRQ Selection

Up on assertion of any interrupt line, the interrupt source is checked if it is configured as FIQ. If so, the signal is routed to the core immediately. If it is an IRQ interrupt, ARM interrupt status is updated. If multiple interrupts occur simultaneously, the priority is resolved between other pending interrupts and finally the core is given the interrupt signal.

The below diagram gives a model implementation for the Interrupt Controller by Freescale called the Interrupt Collector (ICOLL) used in Freescale/NXP iMx233/iMx28 series of MCUs.

Freescale Interrupt Collector

Vendor specific Interrupt Controller

Vectored Interrupt Controller – VIC

ARM itself came up with a model called Vectored Interrupt Controller (VIC). Sitting directly on the AMBA High Speed bus, the latency is significantly reduced. Being an early generation controller it supports 32 interrupt sources each of which can be routed to either FIQ or IRQ signals. A unique feature of VIC is that, as it name suggests, it supports 16 vectored interrupts. In this there are 16 registers where the address of the corresponding interrupt service routines (ISR) can be saved. Based on the priority, the VIC identifies the high priority interrupt and loads its ISR address to a register called VICVectAddr. The firmware can simply use a LDR PC instruction to jump to this ISR. This saves a lot of software effort in branching to the ISR there by reducing latency.

Interrupt Controller from ARM

Vectored Interrupt Controller (VIC)

But VIC supports only level sensitive interrupts that must remain active HIGH till the ISR services it. Thus for these reasons, many SoC designers preferred their own implementation rather than the VIC.

Generic Interrupt Controller – GIC

As processors evolved, soon the number of interrupts became quiet large and also it was not uncommon to have more than 1 core (either symmetric or asymmetric), there was a need for a more standardized way of handling interrupts.

ARM defines Generic Interrupt Controller that suits this need. Though vendors are still free to choose their own mechanism, GIC has become very popular and is almost present in all modern SoCs. It consists of primarily two components – Distributor and CPU interfaces. The primary functionalities of the same include

Distributor:

This is the peripheral facing component that is available as only one implementation (instance). It is responsible for managing interrupts in the whole system and decides priorities between them and routing mechanism of the same.

CPU Interfaces:

For each CPU core available, there is a corresponding CPU Interface present bridging the Distributor interface with the core. It implements the priority masking for the processor.

The below diagram explains the same.

ARM's Interrupt Controller for Multi-core SoCs

ARM Generic Interrupt Controller (GIC)

The interrupts are identified by unique ID and could be in any one of the following 4 states (as explained by the GIC Architecture Specification):

  • Inactive: An interrupt that is not active or pending.
  • Pending: An interrupt from a source to the GIC that is recognized as asserted in hardware or generated by software and is waiting to be serviced by a target processor.
  • Active: An interrupt from a source to the GIC that has been acknowledged by a processor, and is being serviced but has not completed.
  • Active and pending: A processor is servicing the interrupt and the GIC has a pending interrupt from the same source.

Based on the source, there are three major types of interrupts defined.

Shared Peripheral Interrupts – SPI: These interrupts sources are typically from different peripherals in the system. They can be routed to (i.e shared with) any one or more of the cores as per the requirement and will be handled suitably. For example, UART0 and UART1 interrupts could be SPI and configured in the Distributor to be routed to two available cores. Up on UART0 interrupt, the signal is routed to first available processor. If at that instance, UART1 interrupt is received, the distributor routes it to the other core for handling.

These are assigned Interrupt ID from 32 to 1019.

Private Peripheral Interrupts – PPI: There could be interrupts that are only specific to one processor. In such cases, they are routed to PPI of only that processor. For example in an asymmetric system with a Cortex A5 and Cortex M4, a Watchdog interrupt corresponding to A5 will be routed only to the A5 core. There might be no need to share it with the M4. Hence it will be routed as a PPI.

The interrupt ID is defined from 16 to 31.

Software Generated Interrupts – SGI: ARM defines interrupt IDs 0 through 15 specifically for Inter processor communication. It is possible a SGI can be routed to one or more processors through the Distributor.

The Interrupts 0 to 31 are banked by the distributor for each CPU Interface i.e. each processor sees them different and are identified by the CPUID. For example, PPI 16 could be pending in CPU0 but not in CPU1. Whereas, in case of the SPI, it will be same across the CPU’s as they are not banked.

Irrespective of all these, each core is provided signal through either nIRQ or nFIQ lines for interrupting program execution.

Nested Vectored Interrupt Controller – NVIC

While the above implementations are suitable for powerful processors, there is a need for specialized handling in microcontroller profiles that typically run in sub-100MHz speed and with few tens of kilobytes of RAM and flash. It is important to reduce the interrupt latency and to leverage the fact that the number of peripherals is less and hence fewer interrupt sources. For that, ARM defines a NVIC model for the Cortex-M implementations.

In Cortex-M implementation, the interrupt service routine addresses are to be provided in a set of consecutive addresses at offsets corresponding to the vector number. As soon as the interrupt signals are received, the NVIC finds the ISR corresponding to the highest priority interrupt and jumps to it.

The Cortex-M core accepts only nIRQ interrupt and there is no option for a FIQ.

With our understanding of hardware implementation, in the upcoming blogs, we will discuss software mechanism in handling interrupts in ARM architectures.

Saravana Pandian Annamalai
15. July 2015 · Write a comment · Categories: Embedded Software, Technology · Tags:

Interrupts are in-dispensable when writing any practical embedded firmware. With the CPU generally concentrating itself on a computationally intensive job, peripherals are used for IO intensive (reading from serial port) or memory intensive (DMA transfers) operations. Interrupts are the mechanism to gain attention of the CPU asynchronously either on completion of the operation or need for beginning of next cycle of operations. In any modern Operating System, timer interrupts are needed for scheduling and Software Interrupts (SWI) is the way to enter kernel mode when executing system calls.

In a series of blogs beginning with this, we will explore various Interrupt Architectures and Interrupt handling in embedded software across different CPU architectures. Some of the topics that we will cover includes

  • Introduction to ARM Architecture – ISA, Registers and Exception Model
  • ARM Interrupt architecture
  • ARM Interrupt handling – Firmware perspective
  • ARM Linux Interrupt handling
  • ARM WinCE Interrupt handling
  • Nested Vectored Interrupt Controller – NVIC
  • 8051 Interrupt architecture and handling
  • PIC Interrupt architecture and handling
  • AVR Interrupt architecture and handling
  • x86 Interrupt architecture and handling

As you can see, more emphasis is given to ARM architecture due to its huge popularity and deployment across embedded systems.

Interrupt Mechanism and ISR

As a quick introduction, we will see how the interrupt mechanism works and Interrupt handling done in any embedded software. Assume the CPU is performing some activity by running a sequence of instructions. Now when a peripheral controller wants to break the sequence, it generates the Interrupt signal, which is typically a single line of connection from the peripheral/interrupt controller.

The sequence operations related to interrupt handling is captured in the below diagram.

ISR

Interrupt Handling and ISR

Up on reception of the same, the general sequence of handling is as follows

  • Current instruction being executed is completed.
  • CPU copies the internal register called PSW – Program Status Word (the register that has the flags like Carry, Zero etc) on to stack or an internal backup register
  • Address of the next instruction to be executed is saved on the stack or another internal backup register so that it can be resumed after interrupt processing.
  • The Program counter is set to the vector address specific to that interrupt.

A piece of code called the Interrupt Service Routine (ISR) is placed in the vector location of an interrupt, to handle it. Typical flow of operation includes

  • If needed, store the previous PSW and return address in memory
  • Store the context – any more internal registers, status registers etc that might be modified during the course of execution of this ISR
  • Perform necessary operations to process that interrupt like copying data to/from the peripheral, prepare for next cycle etc.
  • Up on completion, restore the context back to the original values from the stored values
  • Restore the PSW and jump to the address of the instruction next to the interrupted one.

While the overall interrupt mechanism remains same, the exact handling, ways to return from interrupt etc are different for CPU architectures like 8051, ARM, AVR etc.

Interrupt Concepts and Terms

Some of the other concepts that we need to familiarize ourselves with are listed below.

Interrupt Controller Functionality

Interrupt Sources, Level, Masking and Priority

Interrupt Controller

In a typical SoC, there could be hundreds of peripherals – interrupt sources that may vie for processor attention. It is impossible to route all these signals to the CPU. So there is another special purpose peripheral called Interrupt Controller to which all the peripheral interrupts signals are connected. The controller is in turn connected to the CPU with one or few lines of signals, with which it can interrupt the CPU. Controller is provided with various registers to mask/unmask the interrupts, read pending/raw status, set priority etc. The controller monitors the signals from peripherals and if there are any active interrupts, based on the preconfigured priority decides the source to be processed first. Then it signals the CPU with interrupt. The CPU, in the ISR, can then read the pending interrupt register and process the same.

Interrupt Sources

Interrupts could be from hardware, software or other sources. Hardware interrupts are the most discussed types originating from on-chip/on-board peripherals. Apart of them, most architectures provides instructions (such as SWI – Software Interrupt) that can be used to generate an interrupt – typically to enter kernel mode. Also exceptions like page fault, instruction fetch errors etc are handled as interrupts.

Interrupt Types and Levels

The interrupt signal could either level triggered or edge triggered. Level triggered interrupts remains active till the condition of interrupt remains, where as with edge triggered interrupts there is a change in signal level and then it again changes back to original state. The type of interrupt can be decided based on various conditions like transition in state (level triggered) or occurrence of events (edge) and is mostly specific to the hardware implementation.

Again the level triggered interrupt could be

  • Low level triggered
  • High level triggered

And the edge triggered interrupt could be

  • Rising edge triggered
  • Falling edge triggered
  • Both edge triggered

Interrupt Maskability

While most of the interrupts could be enabled or disabled by the will of the user, in some implementations, there might be some interrupts that cannot be disabled or masked. These Non-Maskable Interrupts or NMI, as they are called, are used to inform CPU of critical conditions like power going down, occurrence of watchdog interrupt etc. Most likely, there is no need for special handling of the same in software perspective.

Interrupt Priority

As we have seen the Interrupt controller can accept hundreds of interrupt sources, there is a need for a mechanism to determine the priority when two or more interrupts are active simultaneously. So the controller provides configurations to set the priority. Also the CPU itself may accept multiple lines of interrupts each with different priorities and handles them suitably.

Interrupt Nesting and Preemption

The concept of priority automatically leads us to the concept of nesting and preemption. It might be required to process a higher priority interrupt even when the CPU is servicing a lower priority interrupts. So we need to support nesting, whereby interrupts are enabled as soon as possible after entering the ISR and current priority level of interrupt processing is set. When a higher priority interrupt occurs, it enters the ISR of that interrupt, interrupts enabled soon and the cycle goes on.

Interrupt Latency

There is always a delay from the time of assertion of interrupt and the action handling of that interrupt. This might be due to various reasons like the CPU executing a critical section with interrupts disabled, or executing a higher priority interrupt etc. Handling of this delay or latency determines the difference between a General Purpose (no guaranteed latency) and a Real Time Operating System (guaranteed latency).

With this quick introduction about Interrupt mechanism, concepts and associated terms, we will now explore various methods of interrupt handling in embedded systems starting with an introduction to the ARM architecture.