Skip to main content Which Parts of an Interrupt Path Come From CPU Architecture, Interrupt Controllers, and the OS? | IoT Worker

Which Parts of an Interrupt Path Come From CPU Architecture, Interrupt Controllers, and the OS?

When debugging interrupts, it is easy to call everything “the interrupt.”

A peripheral status bit was not cleared: interrupt problem. The interrupt controller was not enabled: interrupt problem. The CPU never entered exception entry: interrupt problem. The ISR ran but the task did not wake: also interrupt problem. Everyone is debugging “interrupts,” but not the same layer.

The safer first model is this: an interrupt is a cross-layer path. A peripheral creates an event, the SoC routes that event to an interrupt controller, the controller selects, masks, prioritizes, and delivers it, the CPU receives it through exception entry, and the OS maps it to an ISR, bottom half, thread, or task wakeup.

peripheral event
-> SoC interrupt line / routing
-> interrupt controller
-> CPU exception entry
-> OS interrupt framework
-> ISR / deferred work / task wakeup

Before asking why an interrupt did not arrive, ask which layer did not see it.

The Peripheral Decides Whether an Event Exists

The beginning of an interrupt path is usually not the CPU. It is the peripheral.

A UART receives a byte, a timer expires, a GPIO level changes, a DMA transfer completes, or a network queue receives a packet. These events first appear inside the peripheral. The peripheral usually has status bits, enable bits, mask bits, clear bits, and trigger conditions.

Common problems at this layer include:

  • peripheral clock is off, so the module is not running
  • pinmux is wrong, so the external signal never reaches the peripheral
  • the peripheral’s own interrupt enable is off
  • trigger mode is wrong, such as edge versus level
  • a status bit is set but not connected to interrupt output
  • the interrupt source is not cleared, so it retriggers repeatedly
  • FIFO or DMA ring overflowed, so data is already lost

CPU architecture cannot fix these directly. The CPU can only respond to events that are delivered to it. If the peripheral never generates an interrupt request, the controller and OS will never see it.

The SoC Decides How Events Reach the Controller

A peripheral event does not necessarily go directly to the CPU. It usually passes through SoC interrupt routing, gating, muxing, and power-domain boundaries.

This layer may include:

  • interrupt line or message from peripheral to controller
  • interrupt-number mapping
  • interrupt mux or router
  • wakeup controller
  • power domain and clock domain
  • security or virtualization routing
  • target CPU selection in multicore systems

That is why two ARM SoCs or two RISC-V SoCs can have completely different interrupt configuration. Interrupt numbers, trigger types, routing registers, wakeup capability, and behavior across low-power states are concrete SoC design choices.

A wrong interrupt number, trigger type, parent interrupt controller, or wakeup property in Device Tree, ACPI, or BSP code can make the OS appear as if interrupts do not work. That is not an ISA-layer problem. It is a SoC description and hardware-connection problem.

The Interrupt Controller Selects, Masks, and Delivers

The interrupt controller manages many interrupt sources and one or more CPUs.

It commonly handles:

  • enable/disable
  • pending state
  • active state
  • priority
  • trigger type
  • target CPU
  • interrupt acknowledge
  • end-of-interrupt
  • nesting and preemption rules

ARM systems commonly use NVIC or GIC. RISC-V systems may use PLIC, CLINT, AIA, or vendor controllers. Names and models differ, but the common idea is this: the controller is neither the peripheral status bit nor the CPU handler. It is the arbitration layer between interrupt sources and CPU exception entry.

If the controller has a pending bit but enable is off, the CPU will not enter. If a higher-priority event blocks it, entry may be delayed. If an interrupt is active but no EOI is sent, later interrupts from the same source may not arrive. With a level-triggered interrupt, if the peripheral condition is not cleared, the interrupt may become pending again immediately after EOI.

So debugging should inspect both peripheral state and controller state. Looking only for ISR logs is often too late.

CPU Architecture Defines Exception Entry and Minimal State

When the interrupt controller decides to deliver an event to the CPU, the CPU enters handling through architecture-defined exception entry.

CPU architecture usually defines:

  • which kind of exception or trap represents an interrupt
  • how the entry base or vector table is located
  • how current PC and status are saved
  • how current privilege level or mode changes
  • how interrupt masks, priorities, or nesting affect entry
  • which mechanism restores state on return

Cortex-M interrupt entry, AArch64 exception vectors, and RISC-V trap vectors are organized differently. The common point is that the CPU does not know the business meaning of a peripheral. It only sees a delivered exception event and enters through the contracted entry.

Common problems at this layer include:

  • vector table or trap vector is wrong
  • entry alignment is invalid
  • current privilege cannot access required control registers
  • interrupts are globally masked or masked by current priority
  • exception-return state is corrupted
  • interrupt stack or exception stack is misconfigured

These are CPU-architecture and low-level runtime boundaries. The peripheral may have raised the event and the controller may have delivered it, but the CPU still may not enter the handler correctly.

The OS Maps Interrupt Numbers to ISRs

After the CPU enters exception entry, the operating system or runtime must dispatch to a concrete handler.

Bare-metal systems may jump directly from a vector table to an ISR. An RTOS may enter a common interrupt entry, save context, call the registered ISR, and trigger scheduling if needed. Linux goes through architecture entry, interrupt-controller drivers, the generic IRQ layer, and then the device driver’s registered handler.

The OS layer usually handles:

  • IRQ domains or interrupt-number mapping
  • ISR registration and shared interrupts
  • interrupt threads or bottom halves
  • interrupt-context restrictions
  • interaction with the scheduler
  • statistics and tracing
  • wakeup sources and power-management integration

This explains a common case: the CPU entered interrupt handling, but your driver handler was not called. Wrong interrupt mapping, missing handler registration, shared-interrupt filtering failure, disabled IRQ, or unscheduled threaded IRQ can all stop the path at the OS layer.

The ISR Acknowledges the Event, Not the Whole Business

An ISR is not the whole interrupt path. It is the handler entry after OS dispatch.

The ISR’s main jobs are usually:

  • identify which hardware event occurred
  • read minimal required state
  • clear or acknowledge the peripheral interrupt source
  • notify the interrupt controller that handling is complete if required
  • wake the deferred handling path

Complex work usually belongs in schedulable context: Linux threaded IRQs, workqueues, softirqs, or RTOS tasks, queues, semaphores, and event flags.

If the ISR does too much, interrupt handling time grows. If it does not clear the interrupt source, it may immediately re-enter. If it clears the hardware event but fails to hand data to a later task, the application still sees “no data.”

So “the ISR ran” only proves the path reached one layer. It does not prove the interrupt handling chain is complete.

Interrupt Priority Exists in Several Layers

Interrupt priority is not a single number.

Real systems may have:

  • priority among multiple events inside a peripheral
  • priority in the interrupt controller
  • current CPU exception priority or mask level
  • RTOS restrictions on which ISR priorities may call kernel APIs
  • task priority in the OS scheduler
  • Linux threaded-IRQ scheduling priority

These layers are easy to mix up. A high interrupt priority may mean the CPU receives it earlier. It does not mean the task awakened by that ISR runs immediately. An ISR may wake a high-priority task, but interrupt return, locks, interrupt-disabled sections, or higher-priority interrupts can still delay it.

Real-time analysis should separate:

  • event-to-request latency
  • controller delivery latency
  • CPU response and exception-entry latency
  • ISR handling time
  • deferred task scheduling latency
  • business handling time

Simply raising interrupt priority rarely guarantees end-to-end response.

Low Power Adds Another Layer

After a device sleeps, the interrupt path may no longer be just peripheral to CPU.

In low-power states, some clock domains may be off. Some peripherals may not generate normal interrupts. Some events only act as wakeup events. Some events first reach a wakeup controller, then restore power and clocks, and only later allow the CPU to enter normal exception handling.

Common problems include:

  • the peripheral interrupts while running but cannot wake from sleep
  • wakeup source is not configured
  • interrupt-controller state is not fully restored
  • pin or GPIO wakeup configuration differs from normal IRQ configuration
  • first peripheral access after wake fails because clock or reset is not restored

These problems cannot be explained by ISR code alone. Power domains, clock domains, wakeup controllers, SoC routing, and OS power management must be considered together.

Debug by Confirming Each Layer

Interrupt debugging can follow this path:

  1. Did the peripheral event actually happen?
  2. Are peripheral interrupt enable, status, and clear logic correct?
  3. Are SoC routing, interrupt number, trigger type, pinmux, clock/reset correct?
  4. Are controller pending, enable, priority, target, and active states reasonable?
  5. Can the CPU receive interrupts, and is the vector table or trap vector correct?
  6. Did the OS map this hardware interrupt to the right IRQ and handler?
  7. Did the ISR acknowledge and clear the hardware event?
  8. Was the deferred thread, task, or bottom half awakened and able to consume data?
  9. In low power, does the wakeup path match the normal IRQ path?

This is more useful than saying “the interrupt was lost.” Often the interrupt was not lost. The event did not exist, routing was wrong, the controller did not deliver it, the CPU was masked, the handler was not registered, or the later task did not consume data.

What to Remember

An interrupt is not a single mechanism. It is a cross-layer path.

CPU architecture mainly defines exception entry, saved state, privilege state, and return mechanism. The interrupt controller selects, masks, prioritizes, and delivers. The SoC decides how peripheral events connect to the controller. The OS decides interrupt numbers, handlers, threaded handling, and scheduler interaction. The driver or ISR acknowledges the hardware event and hands work to the later path.

Once these layers are separated, “why did the handler not run?” becomes a more specific question: did the event happen, did the controller have it pending, did the CPU accept it, did the OS dispatch it, did the ISR clear it, and did the task consume it?