Daniel Mangum had just joined Nordic and was learning the nRF54L security architecture the way he usually does — no firmware, just GDB and manual register pokes at the Key Management Unit. Provisioning a 128-bit key into a slot and pushing it to a destination address worked exactly once per erase. Every subsequent push to the same address read back as the original value.

The push was fine. The read was a lie.

  • The KMU stores key values in SICR slots; a PUSH task writes the slot value to a destination address fixed at provisioning time
  • After pushing a second key to 0x20000000, a four-word x command still returned the old abc123... pattern, no matter how many times it was repeated
  • Reading the same address through the access port — monitor ReadMemAP 0x0 0x20000000 4 0 — returned the new de56f4de value immediately
  • With set debug remote 1, the two paths show different RSP traffic: GDB’s examine command goes out as one packet format, the access-port read is a qRcmd that hex-encodes ReadMemAP straight to JLinkGDBServer
  • The culprit is JLinkArm.dll’s memory cache, SetEnableMemCache, which is on by default and keeps serving values for addresses already read while the CPU is not advancing

The datasheet-adjacent detail that makes this a class of bug rather than a curiosity: JLinkArm.dll’s cache assumes the core is the only thing that can change memory. The nRF54LM20’s KMU writes by DMA, and DMA doesn’t care that the CPU is halted.

The practical outs, in order of preference:

  • Read the access port directly, which bypasses the cache without changing global debugger behavior
  • Advance the core with stepi, which clears the cache for the next read
  • monitor exec SetEnableMemCache = 0, which works but earns an explicit warning in Segger’s docs — it is meant only for specific test cases, not IDEs

The transferable lesson is about where to point doubt. When a write appears not to land, “the hardware is broken” and “the debugger is lying” are both live hypotheses, and the second one is cheap to test by reading one layer down the bus.