armhub.dev
Cortex-M · 24 pages
Cortex-M

Cortex-M33

ARMv8-M Mainline — the modern mid-tier Cortex. TrustZone-M, optional FPU and DSP, MPU, 3-stage pipeline. The default pick for new secure IoT and industrial designs.

6 min read · 1,289 wordsupdated · May 13, 2026

The Cortex-M33 is the workhorse of the ARMv8-M generation. It picks up where the M3 and M4 left off — same general performance envelope, same code-density, same toolchain — and adds TrustZone-M, an updated MPU, and a cleaner ISA. For a vendor designing a new mid-tier MCU in 2024 or later, the M33 is the default core. STMicroelectronics, NXP, Nordic, Renesas, Microchip, and Infineon (Cypress PSoC 6) all ship M33-based product lines.

The M33's design centers on modular optional features. The base core is small and resembles a beefed-up M3. Vendors then license, in any combination: FPU (single or double precision), DSP saturating extensions, TrustZone-M, and the MPU. STM32U5 ships with all four; PSoC 6 has FPU + DSP + MPU but no TrustZone-M on some variants; Nordic nRF5340 ships dual M33s (one for the application processor, one for the radio) with TrustZone-M on the application core.

Cortex-M33 at a glance
Architecture
ARMv8-M Mainline
Pipeline
3-stage in-order, with branch speculation on direct branches
TrustZone-M
Optional — same security model as M23, plus per-region MPU and SAU
FPU
Optional — FPv5-SP (single precision only). No double-precision option on M33.
DSP
Optional — saturating arithmetic (QADD/QSUB), SIMD on packed 16-bit/8-bit data
MPU
Optional, ARMv8-M MPU, up to 16 regions per security state
Co-processor interface
Up to 8 user-defined co-processors via CP0–CP7 (CDP/MRC/MCR instructions)
NVIC
Up to 480 IRQs, 8 priority bits (16 levels typical in silicon)
DMIPS/MHz
1.50 (Dhrystone 2.1)
CoreMark/MHz
~4.02
Typical clock
64–160 MHz silicon, headroom to ~250 MHz on modern processes
Typical parts
STM32U5, STM32L5, STM32H5, Nordic nRF5340 / nRF9160, Infineon PSoC 6, Renesas RA6M5

Pipeline and microarchitecture

Three stages: fetch, decode, execute. Direct branches are speculatively predicted as taken or not-taken based on a small static predictor (forward = not-taken, backward = taken — the standard cheap heuristic). The branch penalty is 0 cycles on correctly-predicted direct branches and 2 cycles on mispredict or indirect branch. Loads are 2 cycles to use unless the result lands in a different pipeline slot; load-use stalls show up but rarely.

The M33's IPC is about 1.0 for typical control code, drifting up to 1.2 on hot loops where the static predictor wins. Compared to the M3 (which the M33 is positionally replacing), the IPC is essentially identical — the win is on the ISA side (more compact code, faster division) and on the system side (TrustZone, better MPU).

Bus interfaces

The M33 has multiple bus master ports:

  • I-bus — instruction fetches
  • D-bus — data accesses
  • S-bus — system accesses (to peripheral region, PPB)

This Harvard-style split means an instruction fetch and a data access can happen in the same cycle. Vendors typically route I-bus and D-bus to flash (with an instruction cache buffer) and to SRAM. The PPB is always on a dedicated channel — accesses to NVIC, SCB, MPU, and SysTick go through the S-bus and don't contend with code or data.

Some vendors add TCMs (tightly-coupled memory) — the M33 doesn't have native TCM support (that's an M7/M55/M85 feature) but vendors can put low-latency SRAM at conventional addresses to mimic the effect. STM32U5 has 192 KB of "SRAM4" at single-cycle latency for performance-critical code.

TrustZone-M on the M33

The TrustZone implementation is identical to the M23, but with the M33's wider feature set everything compounds: the FPU has banked state per security domain (FPCCR.S/FPCCR.NS), the MPU has separate region tables per state, the NVIC banks priorities per state. This makes the M33 a credible target for security-certified products — the partition is enforceable from boot through every interrupt.

The flow looks like this. Boot starts in secure state. The Secure boot code:

  1. Programs the SAU and IDAU (vendor-specific) to define which regions are S, NS, and NSC.
  2. Sets up the MPU for secure state.
  3. Configures FPU and any DSP-relevant state.
  4. Sets SCB->NSACR (Non-Secure Access Control Register) to grant or deny non-secure access to the FPU and any co-processors.
  5. Configures interrupt targeting (NVIC->ITNS — bit per IRQ, 0=secure, 1=non-secure).
  6. Sets up the non-secure MSP and vector table.
  7. Branches to non-secure code via BLXNS or BXNS.

From this point, non-secure code runs the application, and secure code is only reachable through SG gateways. See TrustZone-M architecture.

M33 TrustZone-M state transitions
BLXNS / BXNSBL to NSC regionSG instructionillegal crosshandlerSecureNon-secureNSC entry (SG)SecureFault
On Cortex-M33, every Non-secure to Secure crossing must land on an SG instruction inside an NSC region — any other crossing raises a SecureFault. Banked SP, MPU, NVIC priorities, and FPU state make the partition enforceable from boot through every interrupt.
// Boot: configure SAU
SAU->RNR = 0;
SAU->RBAR = 0x0C000000;            // NSC region base
SAU->RLAR = 0x0C00FFFF | SAU_RLAR_NSC_Msk | SAU_RLAR_ENABLE_Msk;
 
SAU->RNR = 1;
SAU->RBAR = 0x08040000;            // Non-secure flash
SAU->RLAR = 0x080FFFFF | SAU_RLAR_ENABLE_Msk;
 
SAU->CTRL = SAU_CTRL_ENABLE_Msk;
__DSB(); __ISB();

FPU — FPv5-SP

If licensed, the M33's FPU is FPv5-SP: single-precision IEEE 754 only. 32 single-precision registers (s0..s31), or equivalently 16 doubles when paired (d0..d15) — but actual double-precision ops are not implemented on M33; doubles must go through software helpers. Operations include add, subtract, multiply, multiply-accumulate, divide, square-root, and conversions. Latencies are mostly 1–3 cycles; divide and sqrt are 14 cycles non-pipelined.

Lazy stacking on exception entry: the FPU registers are not pushed unless the handler actually uses the FPU. This saves up to 17 stack words on every interrupt for code that doesn't touch floats. See FPU page for the FPCCR.LSPEN bit and the lazy stacking dance.

DSP extensions

Optional. The DSP extensions add the same SIMD-on-packed-data instructions the M4 had: SADD16, SSUB16, SADD8, SSUB8 (parallel add/sub on packed halves), QADD, QSUB (saturating), SMLAD, SMLSD (dual MAC), USAT/SSAT (saturate to N bits), and pack/extract operations. The CMSIS-DSP library is heavily optimized around these and gives 4–8× speedup for FIR filters, FFTs, and complex-arithmetic kernels versus pure scalar C.

DSP-extension-equipped M33s show "Cortex-M33F" or "Cortex-M33D" in some vendor datasheets — though the official ARM nomenclature is just "Cortex-M33 with DSP extension."

NVIC and exceptions

Up to 480 external IRQs (most parts ship 100–200), priority bits up to 8 (most ship 3 or 4). With TrustZone-M, every IRQ is targetable: NVIC_ITNS bit chooses whether the IRQ runs in secure or non-secure state. SysTick is banked — there are two SysTicks, one per state, with independent reload values and counters.

Exception entry preserves security state. A secure exception entered from non-secure context pushes an extended stack frame that includes a security signature (a hash of the stack contents), and on return the hardware verifies the signature to detect tampering. The hardware also pushes additional registers when crossing security boundaries to prevent secure state from leaking into non-secure registers.

Memory protection

The MPU is the ARMv8-M MPU — up to 16 regions per security state, non-power-of-two sizes, MAIR-indexed attributes. With TrustZone, the secure MPU and non-secure MPU are independent. The secure side typically locks down the entire chip, hands out a few permissions through NSC gateways, and lets the non-secure side configure its own MPU as it pleases.

Stack overflow detection works the same way as on M7/M4 — guard region with no-access. The M33 adds a hardware Stack Limit register (MSPLIM, PSPLIM, plus secure variants) that triggers a UsageFault if SP drops below the limit, without needing an MPU region. This is much cheaper for stack overflow detection — one comparison per push instead of a full MPU check — and is on by default in CMSIS startup files when configured.

__set_MSPLIM((uint32_t)&_estack_limit);
__set_PSPLIM((uint32_t)&_task_stack_limit);

Representative parts

PartVendorHighlights
STM32U5STMicroBest mainstream M33 — 160 MHz, full TZ, OCTOSPI, large flash, 1.5 µA in Stop2
STM32L5STMicroPredecessor to U5 — 110 MHz, TZ, USB, broader peripheral set
STM32H5STMicroHigh-perf M33 — 250 MHz, similar peripheral set to H7
nRF5340NordicDual M33 — 128 MHz application core + 64 MHz network core, BLE 5.x, Thread, Matter
nRF9160NordicLTE-M / NB-IoT, M33 with TZ, GPS
PSoC 6InfineonDual-core M33+M0+ (or M4+M0+ on older variants), programmable analog/digital fabric
RA6M5Renesas200 MHz, 2 MB flash, TZ, Ethernet, CAN-FD

When to choose Cortex-M33

The M33 is the default for new designs in the 64–250 MHz range that need any of:

  • Hardware security (TrustZone-M)
  • FPU for sensor fusion or DSP
  • Mid-tier performance with low active-mode power
  • A modern ISA with v8-M memory ordering

Step down to M23 only when BoM cost is brutal. Step up to M55 when you need ML inference (Helium MVE), or M7/M85 when you need 400+ MHz pure throughput. Avoid the old M4 for new designs — same performance, no TrustZone, older ISA, vendor support is shrinking.

Cross-references