, ,

Master ARM Cortex-M Exception Handling (2025)

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

CategoryExamplesTriggered By
System ExceptionsReset, NMI, HardFault, SysTick, PendSV, etc.System events or faults
Fault ExceptionsMemManage, BusFault, UsageFaultErrors 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:

TypeDescription
Interrupts (IRQs)Triggered by external devices like timers, buttons, UART, etc.
System ExceptionsTriggered internally by the processor (like faults, system calls, etc.)

List of System Exceptions (with vector numbers)

Here are some common system exceptions:

Exception NameVector NumberDescription
Reset1Happens when the processor starts or is reset.
NMI (Non-Maskable Interrupt)2A high-priority interrupt that cannot be disabled.
HardFault3Happens when something goes seriously wrong (e.g., invalid memory access).
MemManage Fault4Memory protection violation.
BusFault5Bus error during instruction/data access.
UsageFault6Illegal instructions (like divide by zero, etc).
SVCall11Supervisor Call (used in RTOS or OS).
PendSV14Used in context switching in RTOS.
SysTick15Timer interrupt, often used for OS ticks.

What Happens When an Exception Occurs?

  1. Processor saves context (automatically):
    • Saves registers: R0-R3, R12, LR, PC, xPSR onto the stack.
  2. Jumps to the exception handler:
    • The address is taken from the vector table.
  3. Executes handler function.
  4. Returns to where it was using BX LR or exception 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 (called SVC).
  • 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 TypeSimple MeaningWho Triggers ItCan It Be Turned Off?
ResetSystem restartPower or reset buttonNo
NMIEmergency interruptHardwareNo
HardFaultSerious errorProcessorNo
MemManageBad memory accessProcessorYes
BusFaultMemory bus errorProcessorYes
UsageFaultWrong instructionProcessorYes
SVCallSystem service requestSoftwareYes
PendSVTask switch requestSoftware/OSYes
SysTickTimer interruptTimerYes
IRQNormal interruptPeripheralsYes

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

StateWhat it means
InactiveNothing is happening. Not triggered or running.
PendingWaiting in line. Triggered but not yet handled.
ActiveCPU is handling it right now.
Active & PendingCPU 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?

  1. 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.
  2. 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.
  3. 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 using
  • ICSR: Controls system exceptions
  • AIRCR: Lets you request a system reset
  • SCR: Controls system sleep modes
  • CCR: Enables/disables certain features like fault trapping
  • SHCSR: 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

ColumnMeaning
AddressThe memory-mapped address of the register in the SCB address space.
NameName of the register.
TypeRead/Write access: RW (Read/Write), RO (Read-Only), etc.
Required PrivilegeOnly privileged code (like kernel or supervisor mode) can access it.
Reset ValueThe value stored in the register after reset.
DescriptionFunction of the register.

Important Registers Explained

RegisterAddressPurpose
ACTLR0xE000E008Auxiliary Control Register – Enables/Disables implementation-specific features.
CPUID0xE000ED00CPUID Base Register – Read-only; identifies the processor type and revision.
ICSR0xE000ED04Interrupt Control and State Register – Controls pending interrupts and tracks the current interrupt number.
VTOR0xE000ED08Vector Table Offset Register – Points to the interrupt vector table in memory.
AIRCR0xE000ED0CApplication Interrupt and Reset Control Register – Software reset, endianness config, interrupt priority grouping.
SCR0xE000ED10System Control Register – Configures deep sleep, sleep-on-exit, etc.
CCR0xE000ED14Configuration and Control Register – Enables stack alignment, fault traps, etc.
SHPRx0xE000ED18 to 0xE000ED20System Handler Priority Registers – Set priorities for system exceptions like SVCall, PendSV, SysTick.
SHCSR0xE000ED24System Handler Control and State Register – Enables system exceptions and indicates their active/pending states.
CFSR0xE000ED28Configurable 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.
HFSR0xE000ED2CHardFault Status Register – Indicates causes of HardFault exceptions.
MMAR0xE000ED34MemManage Fault Address Register – Address that caused memory fault.
BFAR0xE000ED38BusFault Address Register – Address that caused bus fault.
AFSR0xE000ED3CAuxiliary 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

ExceptionEnable BitRegisterHandler
PendSV(default enabled)SHPR3 (priority)PendSV_Handler()
MemManageBit 16SHCSRMemManage_Handler()
BusFaultBit 17SHCSRBusFault_Handler()
UsageFaultBit 18SHCSRUsageFault_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

Your email address will not be published. Required fields are marked *