Howto: Remanent data after microcontroller software reset

I recently needed to write a special bootloader for the STM32 controller. One requirement was the ability to explicitly start the bootloader from the application. In this case the bootloader stays active until the next power cycle or when a firmware upgrade has been successfully applied.

The basic idea is to set a special “flag” in the application and then trigger a reset of the controller, telling the bootloader to remain in this mode. If the flag is not set (which is the default), the bootloader will just load the application. Setting a flag sounds easy, but the problem is that a reset invalidates most of the data.

Just writing the flag into a CPU register will not work because all registers are reset to zero. Misusing special peripheral registers won’t work either because of the same reason. But you can use the SRAM present on the controller – if you are cautious – because the SRAM retains its contents even after resets. But you cannot just write a flag blindly to some memory address because you might overwrite some important data of the currently running application. Much worse: This special flag might immediately be overwritten by the bootloader after the reset event because it also needs RAM (heap, stack and static data).

In order to solve this problem, I basically told both bootloader and application to leave some space (in my case 8 bytes) at the end of the RAM, just behind the initial stack pointer. For a device with 192 KB RAM this means that the firmware uses memory addresses from 0x00000 to 0x2FFF8 (relative to the RAM start address). The memory content 0x2FFF8-0x2FFFF will be reserved for the special flag (or other kind of data you might find useful). Of course the initial stack pointer must then point to 0x2FFF8 instead of the default 0x30000. When the bootloader reads the flag, it will automatically reset (or invalidate) the flag.

UPDATE: An earlier of this post assumed 4 bytes instead of 8 bytes for special data. While 4 bytes are usually enough, setting the end of the stack pointer to an address which is not aligned to 8 bytes may lead to serious problems in the application. I spent two days debugging a firmware which used this kind of technique with 4 bytes of data. The problem (wrong representation of IEEE 754 floating point numbers) occured while implicitly using some double-word instructions of an STM32F4 processor in combination with floating-point unit code.

Now let’s see some code. 😉
I only show the relevant changes compared to the reference implementation made by STMicroelectronics. I use the GCC ARM Embedded toolchain, but this concept will most likely also work with other controllers and compilers – some code changes required.

Modify the assembler startup file in bootloader and application:

Modify the linker file in both bootloader and application:

This is the application code that sets the flag and resets the device, so that the bootloader will run:

This is the bootloader code that detects the reason of invocation:

Enjoy. 😉

Leave a Reply

Your email address will not be published. Required fields are marked *