
What is Exception Handling in ARM Cortex-M?
ARM Cortex-M Exception Handling: In ARM Cortex-M, exceptions are interrupts and system events that cause the processor to temporarily stop the main program and execute a special function (handler) to deal with it.
✅ Cortex-M CPUs have a built-in Nested Vectored Interrupt Controller (NVIC) that supports exceptions, prioritization, nesting, and vector table.
Types of Exceptions
Category | Examples | Triggered By |
---|---|---|
System Exceptions | Reset, NMI, HardFault, SysTick, PendSV, etc. | System events or faults |
Fault Exceptions | MemManage, BusFault, UsageFault | Errors in code or hardware |
External Interrupts (IRQs) | Timer, GPIO, UART, etc. | Peripheral hardware requests |
What is an Exception?
An exception is a special event that interrupts the normal program execution and transfers control to a special function called an exception handler.
You can think of it like this:
“Hey CPU, stop what you’re doing. Something important just happened. Handle it now!”
Types of Exceptions in Cortex-M4
The ARM Cortex-M4 processor has two main types of exceptions:
Type | Description |
---|---|
Interrupts (IRQs) | Triggered by external devices like timers, buttons, UART, etc. |
System Exceptions | Triggered internally by the processor (like faults, system calls, etc.) |
List of System Exceptions (with vector numbers)
Here are some common system exceptions:
Exception Name | Vector Number | Description |
---|---|---|
Reset | 1 | Happens when the processor starts or is reset. |
NMI (Non-Maskable Interrupt) | 2 | A high-priority interrupt that cannot be disabled. |
HardFault | 3 | Happens when something goes seriously wrong (e.g., invalid memory access). |
MemManage Fault | 4 | Memory protection violation. |
BusFault | 5 | Bus error during instruction/data access. |
UsageFault | 6 | Illegal instructions (like divide by zero, etc). |
SVCall | 11 | Supervisor Call (used in RTOS or OS). |
PendSV | 14 | Used in context switching in RTOS. |
SysTick | 15 | Timer interrupt, often used for OS ticks. |
What Happens When an Exception Occurs?
- Processor saves context (automatically):
- Saves registers:
R0-R3
,R12
,LR
,PC
,xPSR
onto the stack.
- Saves registers:
- Jumps to the exception handler:
- The address is taken from the vector table.
- Executes handler function.
- Returns to where it was using
BX LR
orexception return sequence
.
Vector Table
The vector table is a list of addresses stored at the beginning of memory (0x00000000
). Each entry is a pointer to the handler for each exception.
Example:
void (* const vector_table[])() __attribute__((section(".isr_vector"))) = {
(void*) 0x20002000, // Initial Stack Pointer
Reset_Handler, // Reset
NMI_Handler, // NMI
HardFault_Handler, // HardFault
...
};
Common Fault Exceptions
1. HardFault
- Most serious.
- Happens when no other fault handler catches the error.
- Example: Dereferencing a
NULL
pointer.
2. MemManage Fault
- Related to memory protection (MPU).
- Example: Accessing restricted memory.
3. BusFault
- Caused by bus errors during instruction fetch or data access.
- Example: Accessing non-existent memory address.
4. UsageFault
- Caused by incorrect use of instructions.
- Example: Division by zero, unaligned access.
How to Write a Simple Exception Handler
Example for HardFault:
void HardFault_Handler(void) {
while (1) {
// Stay here forever - you can add logging or LED blink
}
}
SysTick and PendSV (RTOS Related)
SysTick
: Regular timer interrupt (e.g., every 1ms) used to keep track of time.PendSV
: Used for context switching in operating systems.
These are critical for implementing real-time operating systems.
Registers Involved
- xPSR (Program Status Register): Gives status of current program state.
- LR (Link Register): Helps in return from exception.
- PC (Program Counter): Address of the instruction being executed.
Debugging Tips
- Check the value of the
LR
(Link Register) to know where the exception came from. - You can decode the value of LR to understand the exception return type (called EXC_RETURN).
Exception Types in Cortex-M4 (Made Simple)
1. Reset
- What is it?
It happens when you first turn on the microcontroller (power-up) or when it’s manually reset (like pressing a reset button). - What does it do?
The processor starts from the beginning — it looks at a specific address (in the vector table) and starts running your main code. - Think of it like:
Turning off and on your computer — it restarts from scratch.
2. NMI (Non-Maskable Interrupt)
- What is it?
It’s a very important interrupt that cannot be ignored or turned off. - When does it happen?
Triggered by special hardware problems or important peripherals. - Why is it special?
- It can’t be blocked by other interrupts.
- Only the Reset has a higher priority than NMI.
- Think of it like:
A fire alarm — it will ring no matter what else is going on.
3. HardFault
- What is it?
A major error that happens when something really bad occurs — like accessing invalid memory or when another exception fails. - When does it happen?
- Program tries to use a bad address.
- An exception cannot be handled properly.
- What makes it special?
- Has very high priority (second only to Reset and NMI).
- Can’t be ignored if it happens.
- Think of it like:
A system crash or blue screen. The processor doesn’t know what to do and enters a special error state.
4. MemManage Fault
- What is it?
A memory access error — trying to read or write to protected or forbidden areas in memory. - Example:
Trying to execute code in a non-executable area. - Think of it like:
You tried opening a locked door. You’re not allowed in.
5. BusFault
- What is it?
Happens when something goes wrong while moving data to or from memory (like over a bus). - Example:
You try to read from a memory location that doesn’t respond or doesn’t exist. - Think of it like:
A delivery truck goes to an address, but no one is there to accept the package.
6. UsageFault
- What is it?
Happens when you use instructions incorrectly. - Examples:
- Using an undefined instruction
- Dividing by zero
- Using misaligned memory access
- Think of it like:
Typing a wrong command in a computer program — something the processor doesn’t understand.
7. SVCall (Supervisor Call)
- What is it?
It’s triggered by a special instruction in the program (calledSVC
). - Why is it used?
To ask the operating system for help — like calling a system function or driver. - Think of it like:
A customer service call — your code is asking the OS for assistance.
8. PendSV (Pending Supervisor Call)
- What is it?
A special interrupt used for context switching in an operating system. - When is it used?
When the OS wants to switch from one task to another. - Think of it like:
Switching between open apps on your phone — only when the current one is done.
9. SysTick
- What is it?
A system timer interrupt that goes off at regular time intervals (like every 1 millisecond). - Why is it useful?
- Used by RTOS (real-time operating systems) to keep track of time.
- Helps schedule tasks.
- Think of it like:
A ticking clock that reminds the CPU to check tasks.
10. Interrupt (IRQ)
- What is it?
Regular interrupts triggered by external devices like:- Timers
- Buttons
- Sensors
- Why are they important?
Peripherals use IRQs to alert the processor when they need attention. - Think of it like:
Your phone buzzing — something needs your attention.
Summary Table
Exception Type | Simple Meaning | Who Triggers It | Can It Be Turned Off? |
---|---|---|---|
Reset | System restart | Power or reset button | No |
NMI | Emergency interrupt | Hardware | No |
HardFault | Serious error | Processor | No |
MemManage | Bad memory access | Processor | Yes |
BusFault | Memory bus error | Processor | Yes |
UsageFault | Wrong instruction | Processor | Yes |
SVCall | System service request | Software | Yes |
PendSV | Task switch request | Software/OS | Yes |
SysTick | Timer interrupt | Timer | Yes |
IRQ | Normal interrupt | Peripherals | Yes |
Final Notes
- Exceptions help the processor react to important or error conditions.
- Some are triggered by hardware (like Reset, NMI), some by your own code (like SVCall).
- Faults like HardFault, UsageFault help catch bugs and protect your system.


What Are Exception States?
When an exception (like an interrupt or a fault) occurs, the processor doesn’t just instantly handle it — instead, that exception goes through different states.
Think of it like a queue at a doctor’s clinic:
- You wait your turn (Pending)
- You go inside to be treated (Active)
- You’re done and leave (Inactive)
- And sometimes, you’re inside while someone else knocks — that’s Active and Pending!
The 4 States of an Exception
1. Inactive
- What it means:
Nothing is happening — the exception is not triggered or being serviced. - Example:
No interrupt from a button press or sensor — the CPU is doing regular work.
2. Pending
- What it means:
The exception is waiting to be handled by the processor. - How it gets here:
- A peripheral device (like a timer or sensor) sends an interrupt.
- Software writes to a register to generate an interrupt.
- Example:
You press a button → that sends an interrupt → the exception becomes pending, waiting for the CPU to respond.
3. Active
- What it means:
The CPU is currently handling the exception — it’s running the exception handler code. - Example:
The CPU stops what it was doing and jumps to the interrupt handler for your button press.
4. Active and Pending
- What it means:
The CPU is already handling this exception, and another one just came in from the same source — so now it’s both active and pending. - Important Note:
- The CPU won’t handle the new request until the current one finishes.
- This can happen if, for example, a timer interrupt happens again while the CPU is still handling the previous one.
Key Notes (Simplified)
🔁 Can one exception interrupt another?
Yes! If a higher priority exception occurs while a lower priority one is being handled, it can interrupt it.
Then both are in Active state, but the higher one is being serviced.
Table Summary
State | What it means |
---|---|
Inactive | Nothing is happening. Not triggered or running. |
Pending | Waiting in line. Triggered but not yet handled. |
Active | CPU is handling it right now. |
Active & Pending | CPU is still handling it, but another trigger from the same source just came. |
Real-World Analogy
Imagine you’re a doctor (CPU) at a clinic:
- Inactive: No patients in the waiting room.
- Pending: A patient arrives and takes a seat in the waiting room.
- Active: You’re currently treating a patient.
- Active & Pending: While treating a patient, the same patient sends a new report (like a new symptom appears) — you’ll check that next.
What is the System Control Block (SCB)?
The System Control Block (SCB) is a special part of the ARM Cortex-M microcontroller that helps the system control and manage important operations, especially related to exceptions and faults (like errors or interrupts).
Think of SCB as the “Control Room” of the system
Just like a control room in a building handles alarms, system messages, and settings, the SCB handles things like:
- Configuration settings
- Control of system behavior
- Reports on errors and exceptions
What exactly does SCB do?
- Stores Information:
- It contains information about how the system is set up.
- For example, it knows what kind of CPU core you’re using and other system details.
- Controls Exceptions:
- Exceptions are special events like:
- An interrupt from a timer
- A fault caused by invalid memory access
- SCB helps control how the system responds to these events.
- Exceptions are special events like:
- Helps in Debugging:
- It can report errors or faults that occur, which helps you debug your code.
Where is it used?
- It’s part of the core of ARM Cortex-M processors.
- Used when handling:
- Fault exceptions like hard faults or memory faults
- System resets
- Vector table settings (which tell the system what to do when something happens)
Registers in SCB (just names for now):
Here are some important registers inside the SCB (you don’t have to memorize them yet):
CPUID
: Tells which processor you’re usingICSR
: Controls system exceptionsAIRCR
: Lets you request a system resetSCR
: Controls system sleep modesCCR
: Enables/disables certain features like fault trappingSHCSR
: Shows which exceptions are enabled or active
In Short:
The SCB is a built-in control unit in ARM Cortex-M processors that manages exceptions, faults, and system control features like resets and sleep modes. It’s like the system’s supervisor.
System Control Block (SCB) registers are part of the Cortex-M System Control Space, which provides system-level configuration and control features like interrupt priority, fault handling, system reset, and debug support.
Here’s a breakdown of each column:
Columns
Column | Meaning |
---|---|
Address | The memory-mapped address of the register in the SCB address space. |
Name | Name of the register. |
Type | Read/Write access: RW (Read/Write), RO (Read-Only), etc. |
Required Privilege | Only privileged code (like kernel or supervisor mode) can access it. |
Reset Value | The value stored in the register after reset. |
Description | Function of the register. |
Important Registers Explained
Register | Address | Purpose |
---|---|---|
ACTLR | 0xE000E008 | Auxiliary Control Register – Enables/Disables implementation-specific features. |
CPUID | 0xE000ED00 | CPUID Base Register – Read-only; identifies the processor type and revision. |
ICSR | 0xE000ED04 | Interrupt Control and State Register – Controls pending interrupts and tracks the current interrupt number. |
VTOR | 0xE000ED08 | Vector Table Offset Register – Points to the interrupt vector table in memory. |
AIRCR | 0xE000ED0C | Application Interrupt and Reset Control Register – Software reset, endianness config, interrupt priority grouping. |
SCR | 0xE000ED10 | System Control Register – Configures deep sleep, sleep-on-exit, etc. |
CCR | 0xE000ED14 | Configuration and Control Register – Enables stack alignment, fault traps, etc. |
SHPRx | 0xE000ED18 to 0xE000ED20 | System Handler Priority Registers – Set priorities for system exceptions like SVCall, PendSV, SysTick. |
SHCSR | 0xE000ED24 | System Handler Control and State Register – Enables system exceptions and indicates their active/pending states. |
CFSR | 0xE000ED28 | Configurable Fault Status Register – Reports details of usage, bus, or memory faults. |
MMSR/BFSR/UFSR | (parts of CFSR) | Subfields of the CFSR to provide more specific fault information. |
HFSR | 0xE000ED2C | HardFault Status Register – Indicates causes of HardFault exceptions. |
MMAR | 0xE000ED34 | MemManage Fault Address Register – Address that caused memory fault. |
BFAR | 0xE000ED38 | BusFault Address Register – Address that caused bus fault. |
AFSR | 0xE000ED3C | Auxiliary Fault Status Register – Optional register for vendor-specific fault status. |
Key Concepts
- Privileged Access: These registers can only be modified in privileged mode, ensuring the kernel has control over critical system behavior.
- Reset Values: These default values indicate the state of the register after a system reset.
- Exception Handling: Many of these registers are used for handling and prioritizing faults/exceptions.
Enable PendSV and fault exceptions (Memory Management, BusFault, UsageFault) on an ARM Cortex-M processor, you’ll work with specific SCB system control registers. These are:
1. Enabling PendSV Exception
PendSV (Pendable Service Call) is enabled by default, but you may need to:
- Set its priority to control preemption.
- Pend it manually using
ICSR
.
✅ Set PendSV Priority (lowest)
#define SCB_SHPR3 (*(volatile uint32_t *)0xE000ED20)
#define PENDSV_PRIO_POS 16 // Bits 23:16 are for PendSV priority
void enable_pendsv_lowest_priority(void) {
// Set PendSV to lowest priority (0xFF)
SCB_SHPR3 |= (0xFF << PENDSV_PRIO_POS);
}
✅ Manually Pend the PendSV exception
#define SCB_ICSR (*(volatile uint32_t *)0xE000ED04)
#define ICSR_PENDSVSET (1 << 28)
void trigger_pendsv(void) {
SCB_ICSR |= ICSR_PENDSVSET; // Set bit 28 to pend PendSV
}
PendSV Handler Setup
You must implement the handler function like this:
void PendSV_Handler(void) {
// Your context switch or deferred processing here
}
2. Enabling Fault Exceptions
By default, fault handlers are disabled (except HardFault). You must enable:
- Memory Management Fault
- BusFault
- UsageFault
✅ Use SCB_SHCSR
to enable faults:
#define SCB_SHCSR (*(volatile uint32_t *)0xE000ED24)
#define MEMFAULTENA (1 << 16)
#define BUSFAULTENA (1 << 17)
#define USGFAULTENA (1 << 18)
void enable_fault_exceptions(void) {
SCB_SHCSR |= (MEMFAULTENA | BUSFAULTENA | USGFAULTENA);
}
Fault Handler Implementations
You must implement handlers for these faults, or the system will go into HardFault if they occur:
void MemManage_Handler(void) {
// Handle memory fault
}
void BusFault_Handler(void) {
// Handle bus fault
}
void UsageFault_Handler(void) {
// Handle undefined instruction, divide by zero, etc.
}
Summary
Exception | Enable Bit | Register | Handler |
---|---|---|---|
PendSV | (default enabled) | SHPR3 (priority) | PendSV_Handler() |
MemManage | Bit 16 | SHCSR | MemManage_Handler() |
BusFault | Bit 17 | SHCSR | BusFault_Handler() |
UsageFault | Bit 18 | SHCSR | UsageFault_Handler() |
Manual triggering and handling of an interrupt (USART3) on an ARM Cortex-M processor, typically used in STM32 microcontrollers :
/**
******************************************************************************
* @file main.c
* @author Nish
* @version V1.0
* @brief Custom implementation: Triggering USART3 interrupt manually.
******************************************************************************
*/
#if !defined(__SOFT_FP__) && defined(__ARM_FP)
#warning "FPU is not initialized, but the project is compiling for an FPU. Please initialize the FPU before use."
#endif
#include <stdint.h>
#include <stdio.h>
#define USART3_IRQNO 39
int main(void)
{
// Step 1: Manually set the pending bit for USART3 interrupt in NVIC ISPR1
uint32_t *pISPR1 = (uint32_t*)0xE000E204;
*pISPR1 |= (1 << (USART3_IRQNO % 32)); // Force USART3 interrupt to pending state
// Step 2: Enable USART3 interrupt in NVIC ISER1
uint32_t *pISER1 = (uint32_t*)0xE000E104;
*pISER1 |= (1 << (USART3_IRQNO % 32)); // Allow USART3 interrupt to be serviced
// Infinite loop: Wait for interrupt to occur
for (;;);
}
// Custom ISR for USART3 interrupt
void USART3_IRQHandler(void)
{
printf("Inside custom USART3 ISR\n");
}
Leave a Reply