What each one blocks
| Mechanism | Blocks | Does not block | Set via | Families |
|---|---|---|---|---|
| RDP (read-out protection) | Read-out of the whole flash through debug (JTAG/SWD) or the bootloader | On-device code reading its own flash; program/erase from your own code | Option byte (RDP) |
All classic families (F0-F7, L0/L1/L4, G0/G4, H7, WB, WL) |
| WRP (write protection) | Program and erase of a flash area (overwrite) | Any read; read-out over debug | Option bytes (WRPx / WRP_AREA / WPSN) |
Every STM32 family |
| PCROP (execute-only) | On-device data reads, DMA and debug reads of a code region (the CPU can still run it) | Program/erase (that is WRP); read-out (that is RDP) | Option bytes (PCROP area) | F4, F7, L4, L4+, G4, WB, WL, H7. Gone on Cortex-M33 parts |
| HDP (hide protection) | All access (read, write, execute) to a region, after boot, until the next reset | Access during the boot window, before the hide bit is set | FLASH_SECHDPCR / HDP option bytes |
L5, U5, U3, WBA, WL, H5, H7B3/H7Ax, H7RS |
| Secure watermark / TrustZone | Non-secure code touching secure flash, SRAM or peripherals at runtime | An attacker already running in the secure world | SECWM option bytes + GTZC |
Cortex-M33: L5, U5, U3, H5, WBA |
| Firewall (legacy) | Any entry into a protected code or data segment except through its single call gate | (superseded, see below) | Firewall peripheral (runtime) | L0, L4, L4+ only |
Read the table as five separate jobs, not five versions of the same one:
- RDP stops an outside attacker reading your flash.
- WRP stops anyone, including your own buggy code, erasing or overwriting it.
- PCROP lets you ship code that runs but cannot be read, even by other code on the same chip.
- HDP lets your boot code use secrets, then blocks access to itself for the rest of the run.
- TrustZone / secure watermark splits the chip into two software worlds that cannot read each other.
Mix two of these up and you get a false sense of security. The sections below take them one at a time.
RDP: read-out protection
RDP is the best known. It has three levels, set by one option byte:
- Level 0 (
0xAA): open. Debug and the bootloader can read and write everything. - Level 1 (any value other than
0xAAor0xCC): flash, backup SRAM and backup registers are blocked from any read over the debug port or the bootloader. Your own code still runs and can read its own memory. You can attach a debugger, but you cannot read protected memory through it. - Level 2 (
0xCC): full lockdown. JTAG/SWD is disabled, the bootloader is disabled, and the option bytes are frozen.
The regression behaviour catches people out. Raising the level (0 to 1, or 1 to 2) does not erase anything. Going back down from Level 1 to Level 0 forces a full mass erase of user flash (and backup SRAM where present); only the option bytes survive. The idea is that you cannot lower protection and keep the data.
On the older families, Level 2 is one-way. There is no going back. If you set 0xCC by mistake during development, that part stays locked: no debug, no re-flash. It is an easy way to lose a batch of boards.
# Read the current protection level with STM32CubeProgrammer CLI
STM32_Programmer_CLI -c port=SWD -ob displ
# Raise to Level 1 (reversible, but 1->0 will mass-erase)
STM32_Programmer_CLI -c port=SWD -ob RDP=0xBB
# Do NOT script RDP=0xCC unless you mean "never debug this board again".
RDP blocks read-out of your firmware over SWD or the bootloader. It does not stop your own firmware (or malware running as your firmware) from reading flash, and it does not stop a glitch attack or an overwrite.
WRP: write protection
WRP marks flash sectors, pages or areas as not programmable and not erasable. That is all it does, and the important part is what it does not do: WRP does not block reads. It protects integrity. It stops a stray pointer, a buggy field update, or malware from erasing your bootloader or corrupting a known-good image.
The option-byte encoding differs by family (WRPx/nWRP, WRP_AREA with start and end pages, a WPSN word on H7), but the behaviour is the same everywhere. WRP is on every STM32.
A common pairing is WRP over the bootloader or root of trust: RDP stops it being read out, WRP stops it being replaced.
WRP blocks program and erase of the protected area. It does not block reads, including read-out over debug.
PCROP: execute-only code
PCROP makes a flash region execute-only. The CPU can fetch and run the code, but every data path is blocked: data reads, DMA and debug reads all fail in hardware. The bus allows instruction fetches only.
The use case is protecting code you ship. You can give a customer or a contract manufacturer a crypto library or a proprietary routine as an execute-only block they can call but cannot read back or clone. Even code on the same chip cannot read it.
Two things to watch:
- Granularity varies by family. On STM32L4 a PCROP area is set to 8-byte (double-word) granularity, not per page. STM32WL uses 1 KB, with up to two areas. F4 and F7 are sector-based. Check the reference manual before you lay out the linker script.
- You cannot just turn it off. Clearing PCROP needs an RDP regression (a mass erase). A
PCROP_RDPbit sets whether the PCROP area is erased during that regression; set it to keep the area, and it is effectively permanent.
PCROP blocks on-chip data, DMA and debug reads of a code region, so the binary cannot be cloned. It does not stop program/erase (that is WRP) or read-out of the rest of flash (that is RDP).
HDP: hide protection
RDP, WRP and PCROP are static: set in option bytes, active from reset. HDP adds timing, and it is the basis of a clean secure boot.
The sequence:
- Reset. The HDP region is executable. Your immutable boot code runs from it and uses its secrets: public keys, the signature check, sensitive constants.
- As its last step, the boot code sets the hide bit (
FLASH_SECHDPCR.HDPx_ACCDISon L5/U5/U3/WBA). - From then on, all access to the region (fetch, read, program, erase) is blocked until the next reset.
- The application starts. It cannot read or call back into the boot code or reach its secrets.
That "run once, then block access" behaviour is what you want for a chain of trust: the trusted code does its job and puts itself out of reach before any less-trusted code runs.
The name varies across the range ("secure user memory", "securable memory area" and "sticky-bit area" all mean the same thing), and the mechanism has changed over time. On L5/U5/U3/WBA it is a single enable/disable tied to the secure watermark. On STM32H5 it became three levels (HDPL1/2/3) across the secure-boot stages, with a different register set, so an H5 design does not port register-for-register from a U5 one.
HDP blocks any access to the hidden region once boot hands off. It does not block access during the boot window, before the bit is set, so your boot code has to be correct in that window.
What changed on Cortex-M33
If you move from an F4 or L4 design to an STM32L5, U5 or H5, two things you may rely on are gone, on purpose.
PCROP and the L0/L4 Firewall were dropped on the Cortex-M33 families. The old Firewall put a sensitive code or data area behind a single call gate and reset the chip on any illegal entry. It only ever existed on L0/L4/L4+. Once TrustZone arrived (secure and non-secure worlds, enforced by the SAU/IDAU and ST's GTZC) plus HDP for hiding, both PCROP's execute-only area and the Firewall's single-entry area became redundant. On L5/U5/H5/WBA you rebuild those patterns with a TrustZone secure region plus HDP, not with PCROP or a Firewall. Non-TrustZone parts like STM32WL keep PCROP and securable memory, so the older toolkit still applies there.
STM32H5 replaced RDP levels with a product-state life cycle. Instead of an option byte holding 0xAA or 0xCC, an H5 device moves through named states:
OPEN, PROVISIONING, (TZ-)CLOSED, CLOSED, LOCKED
Roughly: OPEN is like RDP0, CLOSED is like RDP2 with a way back, and LOCKED is like RDP2 with no way back. The change that matters: you leave a closed state through Debug Authentication, a password or certificate challenge, which erases flash and reopens the device. Because the exit is authenticated instead of a one-way byte value, the old "RDP2 means bricked" problem is gone on H5. STM32U5 and WBA reach the same result another way, with OEM-key regression that can even exit RDP Level 2.
Combining them
None of these is the single answer. They cover different attacks, so a real product turns on several. ST splits them (in AN5156) into static protections checked at boot (RDP or product state, WRP, PCROP, HDP, secure watermark) and dynamic protections you set at runtime (Firewall on L0/L4, MPU, TrustZone/GTZC, tamper detection, IWDG).
A reasonable baseline for a connected product with a secure boot:
- RDP Level 1 or product-state
CLOSED: nobody reads your flash over SWD, and you can still get back in for repair. - WRP over the bootloader or root of trust: no accidental or malicious overwrite.
- HDP over the root of trust: it runs at reset, then blocks access before the application starts.
- PCROP (classic parts) or a TrustZone secure region (M33 parts) over any proprietary or crypto code you want to keep unreadable.
- Keep RDP Level 2 or
LOCKEDfor the final production image only, and keep it out of your CI scripts.
Each layer closes a gap the others leave open: RDP the external read, WRP the overwrite, PCROP the on-chip clone, HDP the post-boot secret, TrustZone the cross-domain leak. Knowing which one covers which is the point.
Want the hands-on version? Ac6's 2-day course SEC5: Embedded Security for STM32-based Devices covers this on real STM32 boards with STM32CubeIDE and STM32CubeProgrammer, including a full secure boot chain: