Robust remote firmware update - unattended and without mass memory

Status
Not open for further replies.

stevech

Well-known member
This might be useful for some that want a similar capability.

On an STM32F4, I've finished production code that permits remote reprogramming with a fail-safe to restart itself after a power failure, loss of data link (including serial) connectivity during re-flashing, etc. The same technique could be used on the Kenitis, I think.

It won't work if your app is more than half the size of the flash in the MCU. This technique differs from re-flashing using a function running in RAM, in that with the RAM code method, a disrupted download will likely require a site visit to reflash using some other means (SWD, auxillary boot chip, etc). The scheme described here tries to be foolproof for at-scale projects where Murphy does visit.

Here's the gist of it:
There's a Linker file with interrupt vectors at the usual address 0 (power up default). That points to place X in flash were the "base" app is loaded - which can be anywhere else in flash. (I scatter-load to save some small sized sectors for many KB of application non-volatile data.)
The base app has code that can receive a binary image of "new version" code that is a newer version of the base, and compiled to have its own vectors table and its own code, and live in different flash sector(s) than does the base code.

If there is no valid "new" program in the other sectors, the base code just runs itself. That can be the full app, or less.

The base code is told to download a new app version and uses a predefined medium (wireless, USB, serial, SPI, CAN). It erases the sector(s) where "new" will go, and writes the new version as it comes in, without a big RAM buffer or SD disk. When it finishes writing flash, it generates an MD5 by doing a flash-read. The source of "new" on the other end of the data link sends the expected MD5 as a check. If this is OK, the base app writes a check number in the last few bytes of the sector. (This presumes the MCU can execute code from flash that writes to other-sector flash; the one I use does. No RAM function call needed.)

At next power up, the base app runs as usual. It checks to see if a valid "new" exists in the other sector(s) for a new. If not, then base just runs, it being an older version but working.
If there is a valid "new", then base shuts off interrupts, changes the SCB->VTOR to the table in "new", reinitializes the stack pointer, and jumps through the initial PC vector in "new's" vector table. Base will do this on every power up, unless "new" zeros the is-valid flag bytes to all 0s. This will cause base to run at the next power up or reset, and download/install another newer "new".

This deals with a corrupt or incomplete download. Also, "new" has a watchdog timer going but base does not, as base is presumed bug free at least for download, if not the full app. Base is by intent not a bootloader, but rather, a fully functional older version of the main app. Base could be shrunk to fit in a small sector if need be. But 512KB and 1MB flash in MCUs is cheap these days.

So this scheme avoids adding mass storage like uSD, or an SPI flash chip without file system, and does well at avoiding "bricking" an unattended remote device.

Sorry, I can't provide source code for this. Again, maybe the technique can recycle.
 
Last edited:
Status
Not open for further replies.
Back
Top