NOR Flash for Industrial Firmware Updates: Dual-Bank XIP Design
NOR Flash for Industrial Firmware Updates: Dual-Bank XIP Design
You power up an industrial controller. The CPU resets. The reset vector points at NOR Flash. The bootloader starts executing directly from that Flash — no copy to RAM, no load phase. That's execute-in-place (XIP), and it's why NOR Flash is the default choice for industrial firmware.
But here's the thing nobody warns you about: the same property that makes XIP so clean — the CPU reading code straight from Flash — is what makes firmware updates dangerous. When you erase a sector and a brownout hits mid-erase, you've just bricked the bootloader.
Dual-bank XIP is the answer. It's not a clever trick. It's a partitioning strategy that makes a failed update a non-event. This article covers how it works, what it costs you, and the hardware you need around it.
Why XIP Is the Default for Industrial Boot
XIP means the CPU fetches instructions directly from NOR Flash through the address bus. The Flash is mapped into the CPU's memory space, so a fetch at an address inside the Flash window goes to the chip, not to SRAM.
This matters most at the very start of boot. The CPU has not yet initialized SDRAM, configured any memory controller, or loaded an OS. It has the reset vector and the Flash it's already wired to. If that Flash is NOR and the bootloader is compiled for that physical address, the first instruction after reset runs from Flash.
For industrial controllers, XIP is the right answer because boot time is a hard constraint and the bootloader is small. A bootloader under 256 KB fits entirely in a single NOR Flash chip. You don't need SRAM to hold it. The CPU just runs.
NAND Flash can't do this. NAND requires a controller and a copy step — you read pages into RAM before you can execute them. That's fine for a 256 GB data drive. It's the wrong tool for a 128 KB bootloader that has to start in under a second.
The trade-off of NOR XIP is speed. A typical NOR Flash has a random-access read latency in the 50 to 120 nanosecond range. A 100 MHz Cortex-M CPU wants a fetch every ~10 nanoseconds. So the CPU stalls on every cache-miss fetch. A bootloader compiled for XIP boots 20 to 40 percent slower than the same bootloader loaded into SRAM. For most industrial applications, that delta is acceptable. For a real-time control loop with a strict startup deadline, it may not be.
The mitigations are well understood: an instruction cache (I-Cache) of 4 to 32 KB absorbs repeated code paths, a 2 to 8 byte prefetch buffer hides the initial fetch latency, and the memory controller can insert wait states to keep the Flash within its rated access time. None of these remove the XIP penalty. They just make it manageable.
The Write Problem That Makes Updates Dangerous
NOR Flash has a one-way write. You can program a bit from 1 to 0. You cannot write a 1 over a 0. To change a single byte, you must erase the entire sector first, which resets every bit in that region to 1, and then program the new pattern.
This asymmetry is the root of every firmware-update problem. A 64 KB sector erase takes 100 ms to 2 seconds on typical NOR parts. A full-chip erase can take 30 to 40 seconds. Programming a page runs in the hundreds of microseconds.
Now layer in the industrial environment. Brownouts. Power glitches. A cold crash during a field update. If you're erasing the sector that holds the bootloader and VCC drops mid-erase, the sector is left in an indeterminate state. Some bits are 1, some are 0. The bootloader is gone. The CPU is still pointing its reset vector at that sector. The device is dead.
This is not a hypothetical. It's the reason every serious bootloader design for NOR Flash includes a recovery path. The question is where you put that path.
Dual-Bank XIP: The Partitioning Strategy
The dual-bank (A/B) pattern is simple to state and hard to get wrong. You partition the NOR Flash into two equal regions. Bank A holds the active firmware — the bootloader and any firmware the CPU is currently running via XIP. Bank B is the update target.
A firmware update works in three steps:
-
Write. The new firmware image is programmed into Bank B. This is a sequence of sector-erase-and-page-program operations. It's slow but isolated — Bank A is untouched and the CPU keeps running from it the whole time.
-
Verify. After the write completes, the bootloader computes a CRC32 (or hash) over the new image in Bank B and compares it against the expected value in the update packet. If the CRC fails, the update is aborted. Bank B is left as-is — or erased — and the boot pointer still points at Bank A. The system keeps running on the known-good firmware.
-
Swap. Only after verification passes does the bootloader update a small configuration structure — the boot pointer — that tells the reset vector where to jump. On the next reset, the CPU starts from Bank B. Bank A becomes the new backup.
The critical insight: the boot pointer is the only thing that changes on a successful update. The active firmware region does not get erased or rewritten during the swap. The swap is a few-byte write to a config sector, not a megabyte-scale flash operation.
If the new firmware in Bank B fails to start — say it hangs in an initialization loop, or a sensor driver crashes on the first SPI transfer — the boot pointer still points at Bank A. On the next watchdog-triggered reset, the system recovers automatically. The user sees a brief restart, not a bricked device.
Protecting the Boot Pointer
The config sector that holds the boot pointer is a single point of failure. Erase it or corrupt it, and you lose the ability to choose which bank to boot. The whole A/B mechanism collapses.
Here's the thing: this sector must be written infrequently and protected aggressively. A naive design that rewrites the boot pointer on every boot — even when nothing has changed — will burn through the sector's endurance in months.
NOR Flash endurance is typically 100,000 to 1,000,000 erase/program cycles per sector, depending on the part. A design that erases 10 sectors on every firmware update, with weekly updates over a 5-year deployment, sees about 2,600 erases per sector. That's fine. But if the config sector gets erased on every boot, and the controller reboots 10 times a day, you hit 100,000 erases in about 3 years. The sector is wearing out under normal operation, long before any firmware update.
The standard mitigations:
- Write only on change. Compare the current boot pointer against the requested one. If they're identical, skip the write — no erase, no endurance cost.
- Redundant config sectors. Store the boot pointer in two (or more) small, separate config sectors. A corruption in one doesn't kill the boot path. If the two disagree, fall back to a default (usually Bank A).
- Separate small Flash chip. For high-criticality applications, the boot pointer and minimal recovery code live in a tiny, dedicated NOR Flash (1 MB or 2 MB) on a separate bus. The main firmware Flash can be fully erased or replaced without touching the recovery mechanism.
Power-Fail Protection: The Hardware You Can't Skip
Software protections only work if the hardware gives them a chance. A firmware update mid-erase when VCC collapses will corrupt the sector regardless of what the bootloader's state machine intended.
The fix is a power-fail detection circuit. A voltage comparator monitors VCC. A hold-up capacitor (1 to 5 µF) on the VCC rail provides enough stored energy to carry the Flash through an in-progress erase or program after the supply sags. The bootloader detects the comparator output and either completes the operation or aborts it cleanly, updating the boot pointer only after it is confirmed done.
Two more practices round out the protection:
- Read-after-write verification. After every program operation, read back the bytes just written and compare them against the expected value. If the comparison fails, the operation was not atomic. The bootloader aborts the update and keeps the old boot pointer.
- Power-fail-safe state machine. Every intermediate state in the update state machine must be a safe state. If power fails at any point, the system on next power-up is either in the old configuration (Boot Pointer → Bank A) or the new (Boot Pointer → Bank B). There is no state where the pointer is half-written.
When Single-Bank Still Makes Sense
Dual-bank XIP is the default. Single-bank is the exception, and it requires a recovery mechanism of its own — a separate recovery partition, a boot ROM fallback, or an external JTAG path.
Single-bank is defensible when:
- The Flash is too small to split into two equal banks
- The bootloader is small enough that a single-sector erase-and-reprogram is fast and the risk window is short
- The application has an independent recovery path — a watchdog that reboots into a boot ROM that can reflash the single bank
If you're designing an industrial controller from scratch and the Flash has room, the answer is almost always: split it into two banks, protect the boot pointer, add the power-fail capacitor, and let the A/B pattern do its job.
Loongtion makes NOR Flash modules in 1MB to 512MB densities for industrial firmware. Contact us for a design review.
By Loongtion Technical Team
Related resources
Continue with related selection guides and notes for the same industrial storage topic.