PostHeaderIcon STM32F767: Two Megabytes, Two Banks, and a Boundary at Half Way

Two megabytes of flash on a microcontroller sounds like a simple quantity, and the tools treat it as one: a length, an offset, a single block of output. The silicon does not work that way. The array is two banks of one megabyte each, with a boundary in the middle that is not visible in a hex dump and that governs erase granularity, write protection and the possibility of updating half the device while the other half runs.

None of this stops a read from succeeding. It stops the conclusions drawn from the read from being right.

Where the boundary is

The first bank occupies the lower megabyte of the flash address range and the second bank occupies the upper megabyte. The boundary falls at the address one megabyte above the flash base, which in a flat image is offset one million and forty-eight thousand five hundred and seventy-six.

range contents what it governs
lower bank, first megabyte normally the program, its vector table and its constants the reset vector and the entry point
upper bank, second megabyte a second image, application data, or nothing the update path and the fallback

The row that matters is the third column. A device that uses the upper bank for a stored update has a program in the lower bank and a payload in the upper one, and a flat dump of two megabytes contains both with nothing marking the join. A reader who assumes the second megabyte is unused space will treat a valid second image as garbage, and a reader who assumes it is a continuation of the first will disassemble the join as a single program and find nonsense at the seam.

observation in a flat dump the wrong conclusion the better reading
code ends before the boundary, upper bank erased the device has one small program consistent with a device whose second bank was never populated
upper bank contains a plausible vector table the array holds two programs an update is staged, or the device runs from the upper bank
a valid program in each bank with different sizes the image is corrupted two firmware versions are both present
upper bank starts with a header and a length field the data is unreadable a packaged update, not code

Erase granularity depends on the mode

This is the detail that catches people who work from memory of another family. The sector size on this part is not a constant; it follows the bank configuration.

configuration sector size sectors effect on the image
single-bank mode 256 KB eight across the whole array erase units are large, so small updates rewrite a lot
dual-bank mode 128 KB eight per bank finer granularity, and the two banks can be treated separately

The consequence for a recovery is about interpreting what is blank. In single-bank mode, an erased region is at least 256 KB, and a program that occupies less than that leaves a large uniform expanse of erased values. In dual-bank mode, the same program leaves 128 KB boundaries. Looking at the size of the erased runs is therefore a way to infer the mode the device was configured in, which in turn tells you whether the design intended to update one bank while running from the other.

That inference is worth making because it is cheap and it is independent of anything the customer says. A device whose firmware uses a bank-swap style update will show a clean 128 KB alignment; a device that never updates in place will show whatever alignment the linker chose.

Read while write

The reason the part has two banks is that one can be erased and programmed while code executes from the other. This is the hardware basis of every robust field-update design, and it is also the mechanism that produces the most confusing partial states.

An update proceeds in stages: the new image is received and programmed into the idle bank, verified, and then a marker is written that makes the next reset start from the new bank. Interruption at each stage leaves a different artefact.

interruption point what the device holds what the next boot does
during programming of the idle bank a partial image in the idle bank, the old image intact runs the old image, because the marker was never written
after programming, before the marker a complete new image that is not in use runs the old image; the new one is orphaned
after the marker, before the old bank is erased two complete images, one designated runs the new image
during erase of the old bank one complete image and one partially erased runs the new image, with no fallback

The second row is the one that generates support tickets. The device behaves exactly as it did before the update, the customer reports a failed update, and the actual state is that the update succeeded and was never activated. A recovery from such a device returns two programs, and the question is not which one is valid but which one the marker points at.

Write protection is set per bank

Protection of the array against writing is configured in option bytes, with a granularity that follows the regions rather than the whole device. That matters because a design can protect the lower bank — the one that must not be damaged in the field — and leave the upper bank writable for updates.

When such a device is recovered, the protection state is part of the answer. A customer who intends to restore the device needs to know which regions will refuse programming, and a customer who intends to modify the firmware needs to know that the modification will be rejected by hardware rather than by software. Reading the option bytes and decoding them into a list of write-protected ranges takes a minute and prevents an afternoon of confusion.

The read-out protection is a separate mechanism with its own two levels, and its interaction with the boot path is described in STM32F745 heximal extraction. The contrast with a family that goes further and lets the two banks exchange their base addresses at runtime is in STM32H743 flash recovery — there the mapping itself is configurable, which produces two correct but different answers to the same question.

Reading the array correctly

Three steps, in order. First, read the option bytes and decode the bank mode and the write protection. Second, read the array as a whole; the read itself is indifferent to banks. Third, analyse the result bank by bank, because the analysis is not indifferent.

The third step is where the join has to be handled explicitly. A vector table at the flash base tells you where the program starts. A second vector table at the boundary tells you that a second program exists. Neither tells you which one runs, and the answer to that question lives in the option bytes or in a marker written by the update logic, which is why the first step comes first.

What the report should say

The report should name the bank mode, the sector size that follows from it, the write protection ranges found, and the contents of each bank as a separate statement. Where two images are present it should say which is designated active and on what evidence, and where a staged update was interrupted it should say so plainly rather than presenting a partial image as a corruption.

The RAM map that sits below all of this, and misleads anyone who assumes it follows the usual pattern, is in STM32F765 heximal recovery. The external memory path that often holds the rest of a large application is in STM32F769 program recovery, and the case where the internal array is far too small to hold the product at all is in STM32F750 flash recovery.

FAQ

Does the part support swapping the two banks’ base addresses? Not in the sense that later families do. The banks have fixed addresses; what an update changes is which bank the boot process uses, recorded in configuration rather than by remapping the array.

Is a two-megabyte dump always two megabytes of program? No. It is two megabytes of array, which may contain one program, two programs, one program and a staged update, or a program and a great deal of erased space.

Can the array be read while the device runs? Yes, and the bank that is not executing can be erased at the same time, which is the whole point of the arrangement.

Conclusion

The quantity is two megabytes; the structure is two banks with a boundary, a mode-dependent sector size and separate protection. Reading the bytes is the easy part, and it is also the part that creates the false confidence. Naming the banks, the mode and the designated image is what turns a dump into a description of a device.

Comments are closed.