PostHeaderIcon STM32F745: The Program in ROM That Decides How the Job Starts

Before any bench equipment is connected, a device of this family is already running a program that its owner did not write and cannot remove. It sits in a read-only region of the address space, it is entered by holding configuration pins at reset, and it implements a command set over a serial interface. It exists so that a blank device can be programmed at the factory, and it remains in every shipped product.

That program is the first thing worth talking to. Its responses classify the device in a way that no amount of documentation can, and its limits are precise enough to plan around.

What it is and how it is entered

The bootloader is selected at reset by sampling two configuration pins. One combination boots the application from flash, another enters the loader, and a third is reserved. Designs wire these pins to fixed levels or to a connector, and the choice is visible on the schematic in about thirty seconds.

pin state what the device does at reset
both low boots the application from flash
one high enters the factory bootloader, which then waits on a serial interface
the other high reserved, behaviour not defined for application use
both high enters the factory bootloader

The loader negotiates a serial protocol: a synchronisation byte, an acknowledgement, then commands. It runs from an internal oscillator, so it works on a board with a dead crystal, a shorted peripheral or a program that never reaches its first instruction. That is the reason it is worth trying first on a device described as dead.

The command set

The set is small, and each command answers a different question.

command what it returns what it establishes
initialise the loader version and the list of supported commands that the interface works and what else is available
identify the device identification word and the flash size in kilobytes which die is fitted and how large the array is
read the contents of a memory range the image, when permitted
write acknowledgement, or an error whether the target region is writable
erase acknowledgement after a mass erase that the array is now blank, irreversibly
read protection status whether protection is set the classification that decides the whole job
jump none, the device restarts into the application a clean exit without a power cycle

The second row is useful even when nothing else works. A dead board that still answers identify has told you the die, the array size and, by implication, which memory map applies — the same information a debugger would give, obtained without a working clock.

The sixth row is the one to issue second, immediately after identify. It is a single transaction and it splits every incoming job into two categories.

How protection is enforced

Protection is not a single switch. It is applied per command, and the pattern is consistent.

command protection unset protection level one protection level two
identify works works works, but the debug path is gone
read works refused refused
write to unprotected region works works works
mass erase works works, and clears the array works, and clears the array
read protection status reports unset reports set reports set
jump to application works works works

The asymmetry in the second and fourth rows is the whole story of this class of job. The loader will happily destroy the array on a protected device and will refuse to show it, which means the one command a protected device still accepts is the one that makes recovery impossible.

what the loader says what it means what follows
read succeeds protection is unset read the array and finish
read refused, erase accepted level one the flash contents are not obtainable through this path
read refused, identify works level one or two distinguish by attempting a debug attach
no response at all the loader is not being entered check the pins, the interface and the supply before concluding the device is dead

The one-word test

The most efficient habit in this work is to attempt a read of a single word immediately after identify, before anything else is discussed. It costs one transaction and it converts an open question into a decided one.

A successful single-word read establishes that the entire array is readable through the same path, because the protection check is per request rather than per region. A refusal establishes that no read command will work at any address, which removes an entire category of plan from consideration and points the work at the debug port and, if that is also closed, at physical access.

What it does not establish is whether the refusal was caused by protection or by a malformed request. The two produce the same negative acknowledgement on the wire, which is why the protection status command exists and why issuing it second is worth the extra transaction.

What the ROM path cannot do

Four things, each of which is proposed regularly as a workaround.

It cannot read a protected array, at any address, by any arrangement of commands. It cannot bypass the protection by starting a write and reading back the result, because a write to a protected region is refused before it reaches the array. It cannot be replaced with a modified loader, because the region is read-only by construction. And it cannot be made to run user code with the protection temporarily lifted, because there is no such state.

The one thing it can do that is sometimes overlooked is execute a jump to an address outside flash. A device whose application has been damaged can be given control of a small routine placed in RAM, and that routine can do what the loader will not — provided the protection permits reading the array at all. This is a narrow path and it depends entirely on the first classification; where protection is unset, the loader’s own read command is simpler and faster.

Where this fits in a job

The order is fixed. Enter the loader if the pins allow it, identify the device, read the protection status, attempt a one-word read, and only then plan the work. A job that starts at the debug port skips the cheapest diagnostic available, and a job that starts with physical work may be skipping two cheaper routes.

The member of the family with two USB controllers, where this loader is reachable over USB and where the descriptor tables provide the product’s own documentation, is in STM32F723 binary recovery. The protection levels described from the crypto side, including the case where a key is derived from the device identifier, are in STM32F756 code recovery, and the stripped member where the loader is often the only interface the product exposes is in STM32F722 code recovery.

FAQ

Does entering the loader erase anything? No. It runs from read-only memory and waits for commands; only the erase command changes the array.

Can the loader read a device protected at level one? No, and there is no sequence of commands that changes that. Level one also blocks the debug port.

Why does the loader still accept an erase on a protected device? Because erasing is how a protected device is returned to service, and the array is destroyed in the process. That is the intended behaviour and the opposite of a recovery.

Conclusion

The factory loader is the cheapest diagnostic instrument on the board: it runs without the application, it reports the die and the array size, and it classifies protection in two short transactions. Its refusal to read is not an obstacle to be worked around but a fact that redirects the job, and knowing that before quoting is worth more than any single piece of equipment.

Comments are closed.