Skip to content

Reference23 min read

Cortex-M Quick Reference

Core facts apply to every ARMv7-M part (Cortex-M3, M4, M7) unless marked. Device facts are for the STM32F407 used throughout the course. Always confirm device details against the reference manual (RM0090) for your exact part.

RegisterNameRoleSaved by
r0-r3a1-a4Arguments, return value (r0, r0:r1 for 64-bit), scratchCaller; hardware on exception entry
r4-r11v1-v8Local variables preserved across callsCallee; RTOS context switch in software
r12ipIntra-procedure scratch (linker veneers)Caller; hardware on exception entry
r13spStack pointer, banked as MSP or PSP; must be 8-byte aligned at public interfaces
r14lrReturn address after bl; EXC_RETURN value inside a handlerHardware on exception entry
r15pcProgram counter; bit 0 of branch targets selects Thumb (must be 1)Hardware on exception entry
s0-s31 / d0-d15FPUSingle-precision registers (M4F); s0-s15 caller-saved, s16-s31 callee-savedHardware stacks s0-s15, FPSCR (lazily)
FPSCRFPU status and control: flags, rounding mode

Accessed with MRS and MSR only (CMSIS: __get_X / __set_X).

RegisterBitsMeaning
APSR31 N, 30 Z, 29 C, 28 V, 27 Q, 19:16 GE (M4/M7)Condition flags from the last flag-setting instruction
IPSR8:0Exception number of the running handler, 0 in Thread mode
EPSR24 T, 26:25 and 15:10 ICI/ITThumb state (always 1), interrupted multi-cycle or IT-block state
xPSRAPSR, IPSR, EPSR combined; bit 9 in the stacked copy flags 4-byte stack padding
PRIMASK01 = mask all configurable-priority exceptions (everything except NMI and HardFault)
FAULTMASK01 = also mask HardFault (only NMI runs); cleared automatically on exception return
BASEPRI7:0 (top 4 bits used on STM32)Mask exceptions with priority value greater than or equal to this; 0 disables masking
BASEPRI_MAXWrite alias that only raises the mask, never lowers it
CONTROL0 nPRIV, 1 SPSEL, 2 FPCAUnprivileged Thread mode; use PSP in Thread mode; FP context active
MSPMain stack pointer: used by handlers and, by default, Thread mode
PSPProcess stack pointer: used by RTOS tasks
MSPLIM, PSPLIMStack limit registers, ARMv8-M (M23/M33) only
ModeEntered byStackPrivilege
ThreadReset, exception return to ThreadMSP or PSP (CONTROL.SPSEL)Privileged or unprivileged (CONTROL.nPRIV)
HandlerAny exceptionAlways MSPAlways privileged
Exc #ExceptionVector offsetPriorityNotes
(0)Initial MSP value0x000Loaded into sp at reset
1Reset0x004-3 (fixed)Loaded into pc at reset
2NMI0x008-2 (fixed)Clock security system on STM32
3HardFault0x00C-1 (fixed)All faults escalate here if their handler is disabled or cannot run
4MemManage0x010configurableMPU violation, execute from XN region
5BusFault0x014configurableBus error on fetch or data access
6UsageFault0x018configurableUndefined instruction, invalid state, divide by zero (if trapped)
7-10reserved (SecureFault is 7 on ARMv8-M)0x01C-0x028
11SVCall0x02Cconfigurablesvc instruction
12DebugMonitor0x030configurableSoftware debug monitor
13reserved0x034
14PendSV0x038configurableSoftware-pended, used for RTOS context switches
15SysTick0x03CconfigurableCore timer
16 + nIRQn0x040 + 4nconfigurableDevice interrupts; STM32F407 has 82 (IRQ0 to IRQ81)
IRQnNameVector offset
0WWDG0x040
4FLASH0x050
5RCC0x054
6EXTI00x058
7-10EXTI1 to EXTI40x05C-0x068
11-17DMA1_Stream0 to DMA1_Stream60x06C-0x084
18ADC (ADC1, ADC2, ADC3)0x088
23EXTI9_50x09C
28TIM20x0B0
29TIM30x0B4
30TIM40x0B8
31I2C1_EV0x0BC
32I2C1_ER0x0C0
35SPI10x0CC
37USART10x0D4
38USART20x0D8
40EXTI15_100x0E0
41RTC_Alarm0x0E4
47DMA1_Stream70x0FC
54TIM6_DAC0x118
55TIM70x11C
56-60DMA2_Stream0 to DMA2_Stream40x120-0x130
67OTG_FS0x14C
68-70DMA2_Stream5 to DMA2_Stream70x150-0x158
71USART60x15C
81FPU0x184

Pushed automatically by hardware on exception entry, onto the stack in use (MSP or PSP). The frame is 8-byte aligned; if padding was needed, bit 9 of the stacked xPSR is set.

Basic frame (8 words, 32 bytes) Extended frame with FPU (26 words, 104 bytes)
sp+0x00 r0 sp+0x00 .. sp+0x1C same 8 words as basic
sp+0x04 r1 sp+0x20 s0
sp+0x08 r2 ...
sp+0x0C r3 sp+0x5C s15
sp+0x10 r12 sp+0x60 FPSCR
sp+0x14 lr (of interrupted code) sp+0x64 reserved (alignment)
sp+0x18 pc (return address)
sp+0x1C xPSR

With lazy stacking (FPCCR.LSPEN = 1, the default), space for s0-s15 and FPSCR is reserved but the values are only written if the handler executes an FPU instruction.

Inside a handler, lr holds one of these. Branching to it (bx lr, pop {pc}) performs the exception return.

ValueReturn toStackFrame
0xFFFFFFF1Handler modeMSPbasic
0xFFFFFFF9Thread modeMSPbasic
0xFFFFFFFDThread modePSPbasic
0xFFFFFFE1Handler modeMSPextended (FPU)
0xFFFFFFE9Thread modeMSPextended (FPU)
0xFFFFFFEDThread modePSPextended (FPU)

Bit 2 = 1 means the frame is on PSP; bit 3 = 1 means return to Thread mode; bit 4 = 0 means an extended FPU frame was stacked. A fault handler tests bit 2 to find the stacked frame.

Base 0xE000E100. Each 32-bit register covers 32 IRQs: IRQ n is bit n % 32 of register n / 32.

RegisterAddressAccessPurpose
ISER0-ISER70xE000E100-0xE000E11Cwrite 1 to setEnable interrupt
ICER0-ICER70xE000E180-0xE000E19Cwrite 1 to clearDisable interrupt
ISPR0-ISPR70xE000E200-0xE000E21Cwrite 1 to setSet pending
ICPR0-ICPR70xE000E280-0xE000E29Cwrite 1 to clearClear pending
IABR0-IABR70xE000E300-0xE000E31Cread-onlyActive
IPR0-IPR590xE000E400-0xE000E4EFbyte accessibleOne priority byte per IRQ at 0xE000E400 + n
STIR0xE000EF00write-onlyWrite IRQ number to trigger it from software

On the STM32F407 only the top 4 bits of each priority byte are implemented: priority 5 is written as 0x50. Lower value means higher priority. USART2 (IRQ 38) is enabled by writing 1u << 6 to ISER1.

Base 0xE000ED00.

RegisterAddressKey bits
ACTLR0xE000E0080 DISMCYCINT, 1 DISDEFWBUF (makes bus faults precise), 2 DISFOLD
CPUID0xE000ED00Implementer 0x41 (Arm), PartNo 0xC24 for Cortex-M4
ICSR0xE000ED0431 NMIPENDSET, 28 PENDSVSET, 27 PENDSVCLR, 26 PENDSTSET, 25 PENDSTCLR, 20:12 VECTPENDING, 8:0 VECTACTIVE
VTOR0xE000ED08Vector table address (aligned to the table size rounded up to a power of two, at least 128 bytes; 512 bytes for STM32F407)
AIRCR0xE000ED0C31:16 VECTKEY (write 0x05FA), 15 ENDIANNESS, 10:8 PRIGROUP, 2 SYSRESETREQ, 1 VECTCLRACTIVE
SCR0xE000ED101 SLEEPONEXIT, 2 SLEEPDEEP, 4 SEVONPEND
CCR0xE000ED143 UNALIGN_TRP, 4 DIV_0_TRP, 8 BFHFNMIGN, 9 STKALIGN
SHPR10xE000ED18Priority bytes: 7:0 MemManage, 15:8 BusFault, 23:16 UsageFault
SHPR20xE000ED1C31:24 SVCall
SHPR30xE000ED2023:16 PendSV, 31:24 SysTick
SHCSR0xE000ED2416 MEMFAULTENA, 17 BUSFAULTENA, 18 USGFAULTENA, plus active and pending bits
CFSR0xE000ED28MMFSR 7:0, BFSR 15:8, UFSR 31:16 (see fault bits below)
HFSR0xE000ED2C1 VECTTBL, 30 FORCED (escalated from another fault), 31 DEBUGEVT
DFSR0xE000ED30Debug fault status
MMFAR0xE000ED34Faulting address for MemManage (valid if MMARVALID)
BFAR0xE000ED38Faulting address for BusFault (valid if BFARVALID)
AFSR0xE000ED3CAuxiliary, implementation-defined
CPACR0xE000ED8823:20 CP10 and CP11 access; write 0xF << 20 for full FPU access

AIRCR.PRIGROUP splits the priority byte into preempt priority and subpriority. With 4 implemented bits: PRIGROUP 3 (or less) gives 16 preempt levels and no subpriority; PRIGROUP 4 gives 8 and 2; 5 gives 4 and 4; 6 gives 2 and 8; 7 gives 1 and 16.

Software reset: write (0x05FAu << 16) | (1u << 2) to AIRCR, preserving PRIGROUP, then DSB.

RegisterAddressKey bits
SYST_CSR (CTRL)0xE000E0100 ENABLE, 1 TICKINT, 2 CLKSOURCE (1 = processor clock, 0 = external reference, HCLK/8 on STM32), 16 COUNTFLAG (clears on read)
SYST_RVR (LOAD)0xE000E01423:0 reload value; period = LOAD + 1 cycles
SYST_CVR (VAL)0xE000E01823:0 current value; any write clears it to 0
SYST_CALIB0xE000E01CCalibration value (vendor-defined)

1 ms tick at 16 MHz: LOAD = 16000 - 1. At 168 MHz: LOAD = 168000 - 1. Maximum LOAD is 0x00FFFFFF (about 99.9 ms at 168 MHz).

RegisterAddressKey bits
DHCSR0xE000EDF00 C_DEBUGEN (debugger attached), 1 C_HALT; write key 0xA05F in 31:16
DEMCR0xE000EDFC24 TRCENA (enable DWT and ITM), 0 VC_CORERESET
DWT_CTRL0xE00010000 CYCCNTENA; 31:28 NUMCOMP (number of comparators, 4 on M4)
DWT_CYCCNT0xE000100432-bit cycle counter
DWT_COMPn0xE0001020 + 0x10 * nWatchpoint comparator address
DWT_MASKn0xE0001024 + 0x10 * nAddress mask (ignore low bits)
DWT_FUNCTIONn0xE0001028 + 0x10 * nComparator function (read, write, access watchpoint)
DWT_LAR0xE0001FB0Lock access; write 0xC5ACCE55 to unlock (needed on Cortex-M7)
ITM_STIMn0xE0000000 + 4 * nStimulus ports for SWO output
FPCCR0xE000EF3431 ASPEN (automatic FP state preservation), 30 LSPEN (lazy stacking)
FPCAR0xE000EF38Address of reserved FP frame space
DBGMCU_CR0xE0042004STM32: keep debug alive in Sleep/Stop/Standby (bits 0 to 2)
DBGMCU_APB1_FZ0xE0042008STM32: freeze timers, watchdogs, I2C timeouts while the core is halted

Cycle counter enable:

#include <stdint.h>
#define DEMCR (*(volatile uint32_t *)0xE000EDFCu)
#define DWT_CTRL (*(volatile uint32_t *)0xE0001000u)
#define DWT_CYCCNT (*(volatile uint32_t *)0xE0001004u)
static inline void cyccnt_init(void)
{
DEMCR |= (1u << 24); /* TRCENA */
DWT_CYCCNT = 0u;
DWT_CTRL |= 1u; /* CYCCNTENA */
}
RegisterAddressPurpose
MPU_TYPE0xE000ED9015:8 DREGION: number of regions (8 on STM32F407)
MPU_CTRL0xE000ED940 ENABLE, 1 HFNMIENA, 2 PRIVDEFENA
MPU_RNR0xE000ED98Region number selector
MPU_RBAR0xE000ED9CRegion base address, 4 VALID, 3:0 REGION
MPU_RASR0xE000EDA028 XN, 26:24 AP, 21:16 TEX/S/C/B, 15:8 SRD (subregion disable), 5:1 SIZE (region = 2^(SIZE+1) bytes), 0 ENABLE
BitNameRegisterTypical cause
0IACCVIOLMMFSRExecuting from an XN region or MPU-forbidden address, often a bad function pointer
1DACCVIOLMMFSRData access forbidden by the MPU; address in MMFAR
3MUNSTKERRMMFSRMPU fault while unstacking on exception return (corrupted stack pointer)
4MSTKERRMMFSRMPU fault while stacking on exception entry (stack overflow into guard region)
5MLSPERRMMFSRMPU fault during lazy FP state preservation
7MMARVALIDMMFSRMMFAR holds the faulting address
8IBUSERRBFSRBus error on instruction fetch: jumped to unmapped memory
9PRECISERRBFSRPrecise data bus error; address in BFAR: bad pointer, unclocked peripheral on some parts
10IMPRECISERRBFSRBuffered write failed later; pc is not the culprit. Set ACTLR.DISDEFWBUF to make it precise
11UNSTKERRBFSRBus error unstacking on exception return
12STKERRBFSRBus error stacking on entry: sp points outside RAM, stack overflow
13LSPERRBFSRBus error during lazy FP stacking
15BFARVALIDBFSRBFAR holds the faulting address
16UNDEFINSTRUFSRUndefined instruction: executing data, corrupted code, wrong -mcpu
17INVSTATEUFSRBranch to an address with bit 0 clear (Thumb bit missing), bad function pointer
18INVPCUFSRBad EXC_RETURN value in lr on exception return
19NOCPUFSRFPU instruction with FPU disabled: CPACR not set before using float
24UNALIGNEDUFSRUnaligned access with CCR.UNALIGN_TRP set, or unaligned ldm/stm/ldrd
25DIVBYZEROUFSRInteger divide by zero with CCR.DIV_0_TRP set

The fault bits are write-1-to-clear. HFSR.FORCED means a configurable fault escalated; look in CFSR for the original cause.

InstructionCMSISGuaranteesUse it
dmb__DMB()Memory accesses before it are observed before accesses after itSharing buffers with DMA or another core; implementing locks
dsb__DSB()All memory accesses complete before the next instruction executesBefore wfi; after clearing an interrupt flag at the end of an ISR; after AIRCR reset request; after writing VTOR or MPU regions
isb__ISB()Flushes the pipeline so later instructions are fetched freshAfter writing CONTROL, CPACR (enable FPU), VTOR, MPU enable; after self-modifying code
compiler barrier__asm volatile("" ::: "memory")Compiler does not move memory accesses across it; emits nothingOrdering around critical sections; not a hardware barrier

Canonical sequences: VTOR write then DSB then ISB; CPACR write then DSB then ISB; DSB then WFI.

IntrinsicEffect
__enable_irq() / __disable_irq()cpsie i / cpsid i (clear or set PRIMASK)
__get_PRIMASK() / __set_PRIMASK(x)Read or write PRIMASK (save/restore critical sections)
__get_BASEPRI() / __set_BASEPRI(x)Read or write BASEPRI (value already shifted, 0x50 for priority 5)
__enable_fault_irq() / __disable_fault_irq()Clear or set FAULTMASK
__get_MSP() / __set_MSP(x)Main stack pointer
__get_PSP() / __set_PSP(x)Process stack pointer
__get_CONTROL() / __set_CONTROL(x)CONTROL register (follow with __ISB())
__get_IPSR(), __get_xPSR()Current exception number, full status
__DSB(), __DMB(), __ISB()Barriers
__WFI(), __WFE(), __SEV()Wait for interrupt, wait for event, send event
__NOP()One nop
__BKPT(n)Breakpoint instruction (halts if a debugger is attached, otherwise HardFault)
__REV(x), __REV16(x), __REVSH(x)Byte reverse 32-bit, each halfword, signed halfword
__RBIT(x)Reverse bit order
__CLZ(x)Count leading zeros
__LDREXW(p), __STREXW(v, p), __CLREX()Exclusive load/store for lock-free atomics (__STREXW returns 0 on success)
__SSAT(x, n), __USAT(x, n)Signed and unsigned saturate to n bits
NVIC_EnableIRQ(n) / NVIC_DisableIRQ(n)Write ISER / ICER
NVIC_SetPriority(n, p)Set priority; p is unshifted (0 to 15 on STM32); also works for negative system exception numbers
NVIC_SetPendingIRQ(n) / NVIC_ClearPendingIRQ(n)Write ISPR / ICPR
NVIC_GetPendingIRQ(n), NVIC_GetActive(n)Read pending, active
NVIC_SetPriorityGrouping(g)Write AIRCR.PRIGROUP with the key
NVIC_SystemReset()Request a system reset via AIRCR.SYSRESETREQ
SysTick_Config(ticks)Load SysTick, set its priority to the lowest, enable with interrupt; returns 1 if ticks too large
CoreArchitectureFPUMPUCacheDSP/SIMDBit-bandingTrustZonePriority bits (typical)
M0ARMv6-Mnononononono2
M0+ARMv6-Mnooptionalnononono2
M3ARMv7-Mnooptionalnonooptionalno3 to 8
M4ARMv7E-Moptional SPoptionalnoyesoptionalno3 to 8 (4 on STM32)
M7ARMv7E-Moptional SP or DPoptionaloptional I and Dyesnono3 to 8
M23ARMv8-M Baselinenooptionalnononooptional2
M33ARMv8-M Mainlineoptional SPoptionalnooptionalnooptional3 to 8
RegionAddressSize
Flash (main memory)0x08000000-0x080FFFFF1 MB, sectors 0-3 16 KB, 4 64 KB, 5-11 128 KB
Boot alias0x00000000Flash, system memory, or SRAM depending on BOOT pins
CCM RAM0x10000000-0x1000FFFF64 KB, CPU data bus only, no DMA, no code execution
System memory (ROM bootloader)0x1FFF000030 KB
OTP area0x1FFF7800528 bytes
Unique device ID0x1FFF7A1096 bits
Flash size register0x1FFF7A2216 bits, size in KB
Option bytes0x1FFFC000
SRAM10x20000000-0x2001BFFF112 KB
SRAM20x2001C000-0x2001FFFF16 KB
Backup SRAM0x400240004 KB (battery-backed domain)
Bit-band alias (SRAM)0x22000000alias = 0x22000000 + (offset * 32) + (bit * 4)
Bit-band alias (peripherals)0x42000000alias = 0x42000000 + (offset * 32) + (bit * 4)
Private peripheral bus0xE0000000-0xE00FFFFFNVIC, SCB, SysTick, DWT, ITM, MPU
BusPeripheralBase
APB1TIM20x40000000
APB1TIM30x40000400
APB1TIM40x40000800
APB1TIM50x40000C00
APB1TIM60x40001000
APB1TIM70x40001400
APB1RTC and backup registers0x40002800
APB1WWDG0x40002C00
APB1IWDG0x40003000
APB1SPI2 / I2S20x40003800
APB1SPI3 / I2S30x40003C00
APB1USART20x40004400
APB1USART30x40004800
APB1UART40x40004C00
APB1UART50x40005000
APB1I2C10x40005400
APB1I2C20x40005800
APB1I2C30x40005C00
APB1CAN10x40006400
APB1CAN20x40006800
APB1PWR0x40007000
APB1DAC0x40007400
APB2TIM10x40010000
APB2TIM80x40010400
APB2USART10x40011000
APB2USART60x40011400
APB2ADC1 / ADC2 / ADC30x40012000 / 0x40012100 / 0x40012200, common 0x40012300
APB2SDIO0x40012C00
APB2SPI10x40013000
APB2SYSCFG0x40013800
APB2EXTI0x40013C00
APB2TIM9 / TIM10 / TIM110x40014000 / 0x40014400 / 0x40014800
AHB1GPIOA to GPIOI0x40020000 + 0x400 * n (A 0x40020000, D 0x40020C00, E 0x40021000, I 0x40022000)
AHB1CRC0x40023000
AHB1RCC0x40023800
AHB1Flash interface0x40023C00
AHB1DMA10x40026000
AHB1DMA20x40026400
AHB1Ethernet MAC0x40028000
AHB1USB OTG HS0x40040000
AHB2USB OTG FS0x50000000
AHB2RNG0x50060800

RCC base 0x40023800.

RegisterOffsetKey bits
CR0x000 HSION, 1 HSIRDY, 16 HSEON, 17 HSERDY, 18 HSEBYP, 19 CSSON, 24 PLLON, 25 PLLRDY
PLLCFGR0x045:0 PLLM, 14:6 PLLN, 17:16 PLLP, 22 PLLSRC (1 = HSE), 27:24 PLLQ
CFGR0x081:0 SW, 3:2 SWS (0 HSI, 1 HSE, 2 PLL), 7:4 HPRE, 12:10 PPRE1, 15:13 PPRE2
AHB1RSTR0x10Reset bits, same positions as AHB1ENR
APB1RSTR0x20Reset bits, same positions as APB1ENR
APB2RSTR0x24Reset bits, same positions as APB2ENR
AHB1ENR0x30Clock enables (below)
AHB2ENR0x34Clock enables (below)
APB1ENR0x40Clock enables (below)
APB2ENR0x44Clock enables (below)
BDCR0x70Backup domain: LSE, RTC clock source
CSR0x740 LSION, 1 LSIRDY, 24 RMVF, 25 BORRSTF, 26 PINRSTF, 27 PORRSTF, 28 SFTRSTF, 29 IWDGRSTF, 30 WWDGRSTF, 31 LPWRRSTF
RegisterBitPeripheral
AHB1ENR0 to 8GPIOA to GPIOI (GPIOD is bit 3, GPIOE bit 4)
AHB1ENR12CRC
AHB1ENR18Backup SRAM
AHB1ENR20CCM data RAM
AHB1ENR21DMA1
AHB1ENR22DMA2
AHB2ENR6RNG
AHB2ENR7USB OTG FS
APB1ENR0TIM2
APB1ENR1TIM3
APB1ENR2TIM4
APB1ENR3TIM5
APB1ENR4TIM6
APB1ENR5TIM7
APB1ENR11WWDG
APB1ENR14SPI2
APB1ENR15SPI3
APB1ENR17USART2
APB1ENR18USART3
APB1ENR21I2C1
APB1ENR22I2C2
APB1ENR23I2C3
APB1ENR25CAN1
APB1ENR28PWR
APB1ENR29DAC
APB2ENR0TIM1
APB2ENR4USART1
APB2ENR5USART6
APB2ENR8ADC1
APB2ENR12SPI1
APB2ENR14SYSCFG
APB2ENR16TIM9

The IWDG has no enable bit: it runs from the LSI and starts when you write 0xCCCC to IWDG_KR.

ClockMaximum (STM32F407)
SYSCLK, HCLK (AHB)168 MHz
PCLK2 (APB2)84 MHz
PCLK1 (APB1)42 MHz
Timer clocks2 x PCLK when the APB prescaler is not 1 (84 MHz on APB1 timers at full speed)
ADC clock36 MHz
Flash wait states at 168 MHz, 2.7 to 3.6 V5