Cortex-M3 Exception
Handling and Interrupts —
Complete Notes
Reference: Joseph Yiu, The Definitive Guide to the ARM Cortex-M3/M4, Second Edition,
Elsevier, 2010 (Ch.2, Ch.8–9)
1. Exception Types
The Cortex-M3 implements a new exception model in ARMv7‑M, with a number of system
exceptions and up to 240 external interrupts (IRQs).
1.1 Exception Numbering and Classes
Exceptions are numbered from 1 to 15 for system exceptions and from 16 upwards for
external interrupts.[1]
Exception Name Class Default Description
# Priority
1 Reset System -3 (highest, Power‑on and reset
fixed) handling.
2 NMI System -2 (fixed) Non‑Maskable Interrupt
— cannot be disabled by
software.
3 HardFault System -1 (fixed) Escalation point for
unrecoverable or
unhandled faults.]
4 MemManage Fault Programmable Memory protection and
MPU violation faults.
5 BusFault Fault Programmable Bus errors during
instruction fetch or data
access.
6 UsageFault Fault Programmable Undefined instruction,
illegal state,
divide‑by‑zero (if
enabled), etc
7–10 Reserved — — Reserved
11 SVCall System Programmable Supervisor Call triggered
service by SVC instruction.
12 Debug Debug Programmable Breakpoints, watchpoints,
Monitor or external debug request.
13 Reserved — — Reserved.
14 PendSV System Programmable Pendable service call,
service typically used for RTOS
context switching.
15 SysTick System Programmable System tick timer
timer interrupt/exception.
16–255 IRQ0– External Programmable External interrupt inputs
IRQ239 interrupt from peripherals.
Classes:
• System exceptions: Reset, NMI, HardFault, fault exceptions, SVCall, Debug
Monitor, PendSV, SysTick.
• Fault exceptions: MemManage, BusFault, UsageFault, and HardFault.
• External interrupts: IRQ0–IRQn, tied to device‑specific peripherals (timers,
GPIO, communication interfaces).
2. Exception Priority
Each exception has an associated priority level, used by the NVIC to decide which exception
to service and whether it can preempt another.
2.1 Priority Numbering
• Smaller numeric value = higher logical priority (0 is highest configurable
priority).
• Reset, NMI, and HardFault have fixed negative priorities and cannot be changed.
• All other system exceptions and external interrupts have programmable priorities
via NVIC and System Handler Priority (SHP) registers.
2.2 Priority Rules
1. A pending exception with higher priority than the current running exception is
granted service (preemption).
2. If two pending exceptions have the same priority, the one with the lower
exception number is serviced first.
3. The priority of fault exceptions (MemManage, BusFault, UsageFault) is configurable
through SHP registers; HardFault priority is fixed at -1
3. Vector Tables
The vector table is an array of 32‑bit words located at a fixed address (default
0x0000_0000) that maps each exception number to its handler address.
3.1 Vector Table Layout
• Entry 0 (word at 0x0000_0000) holds the initial Main Stack Pointer (MSP)
value.
• Entry 1 (0x0000_0004) holds the Reset handler address.
• Subsequent entries hold the addresses of NMI, HardFault, faults, system handlers,
and external IRQ handlers, in order.
Vector Table (default base 0x0000_0000)
Address Content Description
----------- ------------------------------ ------------------------------
0x0000_0000 Initial MSP value Stack pointer after reset
0x0000_0004 Reset_Handler address Exception #1
0x0000_0008 NMI_Handler address Exception #2
0x0000_000C HardFault_Handler address Exception #3
0x0000_0010 MemManage_Handler address Exception #4
0x0000_0014 BusFault_Handler address Exception #5
0x0000_0018 UsageFault_Handler address Exception #6
0x0000_001C Reserved Exception #7
...
0x0000_002C SVC_Handler address Exception #11
0x0000_0030 DebugMon_Handler address Exception #12
0x0000_0034 Reserved Exception #13
0x0000_0038 PendSV_Handler address Exception #14
0x0000_003C SysTick_Handler address Exception #15
0x0000_0040 IRQ0_Handler address Exception #16 (external)
...
The vector table base address can be relocated using the VTOR (Vector Table Offset
Register) in the System Control Block (SCB), typically to move it into SRAM for dynamic
modification.
3.2 Diagram: Vector Table and Reset
Flash Memory at 0x0000_0000
+---------------------------+
| Initial MSP | <-- loaded into MSP on reset
+---------------------------+
| [1] Reset_Handler | <-- loaded into PC on reset
+---------------------------+
| [2] NMI_Handler |
+---------------------------+
| [3] HardFault_Handler |
+---------------------------+
| [4] MemManage_Handler |
+---------------------------+
| [5] BusFault_Handler |
+---------------------------+
| [6] UsageFault_Handler |
+---------------------------+
| ... |
+---------------------------+
| [15] SysTick_Handler |
+---------------------------+
| [16] IRQ0_Handler |
+---------------------------+
| [17] IRQ1_Handler |
+---------------------------+
| ... up to IRQ239 |
+---------------------------+
4. Interrupt Inputs and Pending
Behaviour
4.1 Interrupt Inputs vs System Exceptions
• Interrupt inputs: External lines mapped to IRQ0–IRQn (exceptions #16 and
above). Enabled/disabled and prioritized via NVIC registers.
• System exceptions: Generated internally by the core (faults, SVCall, PendSV,
SysTick) or by NMI input; some are controlled through SCB instead of NVIC.
As Joseph Yiu notes, NVIC functions such as NVIC_EnableIRQ() apply only to external
interrupts (exception numbers ≥ 16), not to system exceptions like SysTick, SVCall, PendSV.
4.2 Pending and Active States
Each exception is tracked by the NVIC/SCB with at least two conceptual bits:
• Pending: An event has occurred and is waiting to be serviced.
• Active: The exception is currently being serviced (handler is running).
State Transitions for One Exception
Idle ──(event)──► Pending ──(accepted by NVIC)──► Active ──(return)──► Idle
▲ ▲ │
│ └─ (clear pending) ───┘
└─ (new event re-pends while active)
• A pending interrupt of lower or equal priority than the current running exception
will wait until the current handler completes.
• A higher‑priority pending interrupt can cause preemption (nested interrupt).
5. Fault Exceptions
Fault exceptions provide sophisticated error detection and reporting, making debugging
much easier than on classic ARM cores.
5.1 Fault Types
Fault Exception Typical Causes
#
MemManage 4 MPU region violation, execute from non‑executable
Fault memory, access to forbidden regions.
BusFault 5 Bus errors for instruction fetch or data access (e.g.,
illegal address, external bus error).
UsageFault 6 Undefined instruction, invalid state, unaligned access
(if trapped), divide‑by‑zero (if enabled).
HardFault 3 Escalation when faults are disabled or have lower
priority; also some critical errors (e.g., vector fetch
failure).
After reset, MemManage, BusFault, and UsageFault are often disabled; faults then escalate
to HardFault unless explicitly enabled via SCB->SHCSR bits.
5.2 Fault Status Registers
The Configurable Fault Status Register (CFSR) in the SCB encodes the reason for
MemManage, BusFault, and UsageFault
• Bits are grouped into subfields: MMFSR, BFSR, UFSR (for MemManage, Bus, and
UsageFault causes).
• Additional fault address registers (MMFAR, BFAR) hold the faulting address when
valid.
This detailed status allows the fault handler to log, diagnose, and possibly recover from
certain errors.
6. Supervisor Call (SVCall) and
Pendable Service Call (PendSV)
6.1 Supervisor Call (SVCall)
SVCall is a software‑triggered system exception used to request privileged services from
the OS or kernel.
• Triggered by executing the SVC instruction with an 8‑bit immediate.
• The SVC handler inspects the stacked PC to read the SVC number from the
instruction stream.
• Used for system calls, switching to privileged operations on behalf of unprivileged
threads, and RTOS APIs.
User Thread (Unprivileged) Kernel (Privileged)
┌────────────────┐ ┌──────────────────────┐
│ User code │ SVC #imm │ SVCall_Handler │
│ in Thread │──────────────►│ - Decode SVC number │
│ Mode │ │ - Perform service │
└────────────────┘ │ - Optionally change │
│ CONTROL, PSP, etc. │
└─────────┬────────────┘
│
Exception return
│
▼
Back to Thread mode
6.2 Pendable Service Call (PendSV)
PendSV is a pendable system exception intended primarily for context switching in an
RTOS.
• It can be pended by software without immediate servicing.
• Typically assigned lowest priority so it runs only when no other higher‑priority
interrupts are active.
• RTOS uses PendSV to perform task switching, saving and restoring task contexts.[5]
RTOS Typical Use of PendSV
1. A tick interrupt (SysTick or timer IRQ) decides a context switch is needed.
2. ISR sets the PendSV pending bit in SCB->ICSR.
3. When all higher‑priority ISRs complete, NVIC enters PendSV handler.
4. PendSV handler saves current task state, selects next task, restores its state.
5. Exception return resumes execution in the newly selected task.
7. NVIC: Nested Vectored Interrupt
Controller
The NVIC is tightly coupled to the Cortex‑M3 core and implements the exception model,
including priority, masking, and vectoring.
7.1 NVIC Overview
Key capabilities:
• Up to 240 external interrupts plus system exceptions.
• Nested interrupts: higher‑priority exceptions preempt lower‑priority ones.
• Vectored interrupt support: direct fetch of ISR start address from vector table.
• Dynamic priority changes: priorities can be changed at runtime.
• Optimized latency: automatic stacking/unstacking of registers, tail‑chaining, late
arrival handling.
Simplified NVIC Block Diagram
+--------------------------+
| Exception Signals |
| (System + External) |
+------------+-------------+
|
v
+--------------------------+
| NVIC |
| - Pending bits |
| - Active bits |
| - Priority registers |
| - Masking logic |
+------------+-------------+
|
Highest priority
pending exception
|
v
+--------------------------+
| Cortex-M3 Core |
| - Stack/Unstack logic |
| - Vector fetch (PC) |
| - Mode / xPSR control |
+--------------------------+
8. Basic Interrupts and SysTick Timer
8.1 Basic Interrupt Flow
1. An external peripheral asserts an interrupt input (e.g., IRQ0).
2. NVIC sets the corresponding pending bit.
3. If the interrupt is enabled and has higher priority than current execution, NVIC
initiates exception entry.
4. Core automatically stacks 8 registers (R0–R3, R12, LR, PC, xPSR) on the current
stack (MSP or PSP).
5. Core loads the ISR start address from vector table into PC and starts executing
handler.
6. On completion, handler executes an exception return (e.g., BX LR with
EXC_RETURN) and hardware automatically unstacks the saved registers.
8.2 SysTick Timer
The SysTick is a simple 24‑bit countdown timer integrated in Cortex‑M, commonly used as a
system tick for RTOS or periodic tasks.
• Located in the system control space with registers CTRL, LOAD, VAL, CALIB.
• When enabled, it counts down from LOAD to 0 using either the processor clock or
an external reference clock.
• When it reaches 0:
o It reloads LOAD automatically.
o It sets the COUNTFLAG bit.
o If the TICKINT bit in CTRL is set, it triggers the SysTick exception
(exception #15)
SysTick Usage (Typical)
SysTick_Config(SystemCoreClock / 1000);
- Sets LOAD for 1 ms period
- Clears VAL
- Enables SysTick with TICKINT and CLKSOURCE bits set
Result: SysTick_Handler runs every 1 ms.
Note: SysTick is a system exception, so it is not enabled via NVIC_EnableIRQ() (which only
handles external interrupts); it is enabled through SysTick->CTRL.
9. Interrupt / Exception Sequences
9.1 Exception Entry Sequence
When an exception is accepted, the Cortex‑M3 core performs the following steps atomically
Exception Entry (simplified)
1. Finish current instruction (unless it triggers the exception itself).
2. Determine active stack pointer (MSP or PSP) from CONTROL.
3. Push 8 registers onto the stack in this order:
- xPSR
- PC (return address)
- LR
- R12
- R3, R2, R1, R0
4. Update LR with an EXC_RETURN value encoding return mode & stack.
5. Fetch handler address from vector table and load into PC.
6. Switch to Handler mode (privileged), update IPSR with exception number.
The automatic stacking means handlers can be written in C without explicit
prologue/epilogue save/restore for those core registers.
9.2 Exception Return Sequence
On completion of an ISR or exception handler, a special EXC_RETURN value in LR
triggers exception return when executed via BX LR:
Exception Return (simplified)
1. Decode EXC_RETURN in LR to determine:
- Return to Thread or Handler mode
- Use MSP or PSP as stack pointer
2. Pop 8 registers from stack (R0–R3, R12, LR, PC, xPSR).
3. Restore processor mode, execution state, and flags from xPSR.
4. Resume execution at restored PC.
Typical EXC_RETURN values:
• 0xFFFF_FFF1 — Return to Handler mode, use MSP.
• 0xFFFF_FFF9 — Return to Thread mode, use MSP.
• 0xFFFF_FFFD — Return to Thread mode, use PSP.
10. Nested Interrupts
Nested interrupts occur when a higher‑priority exception preempts a lower‑priority
one.[5][1]
Timeline Example: Nested Interrupts
Time →
Foreground Code
|──── ISR (IRQ A, priority 3) ────|
▲
| IRQ B (priority 1) arrives
IRQ A Handler (prio 3)
|──── running ──(preempted)───────|──── resumes ──|
▲ ▲
| |
IRQ B Handler (prio 1)
|────── running ──────|
• When IRQ B (higher priority) becomes pending, the NVIC preempts IRQ A and
performs a second exception entry.
• When IRQ B completes and returns, the core automatically resumes IRQ A handler
from where it left off (nested handling).
11. Tail-Chaining
Tail‑chaining is an optimization that avoids redundant stack pop/push operations when
one exception immediately follows another.
11.1 Concept
If, at the end of an ISR, another pending exception of higher or equal priority is ready to
run, the core can skip the full unstacking and restacking sequence
Instead of:
1. Pop 8 registers (return from ISR1).
2. Immediately push the same 8 registers again (entry to ISR2).
The core performs:
• No pop of the registers.
• Simply updates internal state and vector fetch to jump directly to ISR2.
This greatly reduces the interrupt latency between consecutive ISRs.
Tail-Chaining Diagram (Conceptual)
Normal case (no tail-chaining):
ISR1: POP stack (8 regs)
... core returns to thread ...
PUSH stack (8 regs) for ISR2
Tail-chaining case:
ISR1: (no POP)
► internal tail-chaining phase (~6 cycles)
► fetch ISR2 vector, jump directly to ISR2
Result: No redundant stack traffic, faster response to ISR2.
On Cortex‑M3, tail‑chaining transition can take as few as six cycles versus dozens of cycles
on classic ARM7 cores.
12. Late Arrivals
A late‑arriving interrupt is a higher‑priority exception that becomes pending while
exception entry for a lower‑priority exception is in progress.
12.1 Behavior
• Core starts exception entry for lower‑priority IRQ A, stacking registers and preparing
to branch.
• Before entry completes, a higher‑priority IRQ B becomes pending.
• The core detects this “late arrival” and redirects to perform entry for IRQ B
without repeating the partially completed stacking.
Late Arrival Timing (Simplified)
Time →
Foreground Code
|---- start entry to IRQ A ----|
▲
| IRQ B (higher priority) arrives
Stacking Phase
R0,R1,R2,R3,R12,LR,PC,xPSR are already being pushed for IRQ A.
Optimization:
- Use the same stack frame for IRQ B.
- Vector directly to IRQ B handler.
After IRQ B completes:
- Core can tail-chain into IRQ A (if still pending),
or return to foreground code.
This optimization reduces latency for high‑priority interrupts without extra stack overhead,
since the stacked context is identical to what both IRQ A and IRQ B need (the pre‑interrupt
thread state).
13. Interrupt Latency
Interrupt latency is the time from the assertion of an interrupt until the first
instruction of the corresponding ISR executes.
13.1 Components of Latency
On Cortex‑M3, latency includes:
• Time to
o Complete current instruction (or abort/handle if fault).
o Perform automatic stacking of 8 registers.
o Update internal state and fetch ISR vector.
o Fill the 3‑stage pipeline with the first ISR instructions.
In optimized cases:
• Tail‑chaining can remove the stack pop/push between consecutive ISRs, reducing
effective latency to as few as ~6 cycles between back‑to‑back interrupts.
• Late arrival can ensure higher‑priority ISR starts as quickly as possible when arriving
during entry of a lower‑priority ISR.
Latency Illustration (Conceptual)
Event (IRQ asserted)
│
▼
[ Finish current instruction ]
│ N cycles
▼
[ Exception entry & stacking ]
│ ~12 cycles (typical)
▼
[ Vector fetch + pipeline fill ]
│ 3–5 cycles
▼
First ISR instruction executes
Optimization Scenarios:
- Tail-chaining: Skip pop/push between ISRs → small fixed overhead (~6 cycles).
- Late arrival: Reuse partial stacking for higher-priority ISR → shorter entry.
Careful configuration of priorities, minimizing long critical sections, and leveraging
tail‑chaining and PendSV can help meet real‑time deadlines more easily.