I do have firmware for an embedded device, which has several UUIDs in flash. The UUIDs have to change for every controller flashed in production. There is no EEProm available - only flash.

I'm wondering how to do this properly (for e.g. mid-scale production environments). I came up with three solutions (Research, Thinkering):

  1. Flash the firmware with dummy-values in flash. Then receive the actual UUIDs from the programming probe (e.g. write to RAM) and write them to flash via a dedicated function in the firmware. This way, the firmware does not change between devices -> Cumbersom, as page-buffering etc. is required. Also CRC recomputation for entire flash must be done after update.

  2. Place the declarations (static const structs with initializers) in seperate .c file. Replace the init values with some-kind of mark (e.g %REPLACE_ME_X%). Then, before flashing, replace the placeholders with the actual values (e.g. via C# app), build the code headless and flash the software -> Allows to compute CRC post-build -> Gives nice automation options, as everything can be done from app (Replace, build, flash, test, log).

  3. Replace the dummy values in the .hex file with some-kind of mark(e.g %REPLACE_ME_X%). Then flash the .hex file -> Requires to recompute the CRC for every .hex file too.

  4. (See answers)

  5. Found an option to export .hex file post-build as c-array. Link UUID array with dummy-values to absolut address in generic firmware. Use c-array in C# (e.g.) app, replace with desired values and recompute CRC. Transform back to .hex and flash -> Avoids the dedicated flash page (flash footprint is of concern), avoids build process for every controller, avoids dedicated interfaces with debugger/programming probes - requires custom app.

  6. Even simpler! Use Opt. Nr. 5 but work with binary files. This also allows to ship encrypted images for field updates (Caution! See Comments!)

  7. Extending Opt. 6: Generate generic FW image as .bin. Write post-build script/app to replace the UUID-Dummys with actual values (e.g. from Database). Flash the modified .bin to the device in production. Link the UUID-Array in a dedicated flash page (Also including CRC-Tables, Hash-Tables, SIN-Tables, basic functions, bare-minimum level-1 bootloader and other stuff that is not going to change over the product/FW life-cycle). Lock this Flash-Page for delete in flash-controller. Use a dedicated CRC for this flash page computed in script -> No Flash-Page wasted, no extra programming step and only a simple script to write. Bonus: Script can have a -flag to remove the specific (constants) page from output .bin and encrypt the remaining contents -> Allows shipping of encrypted image to download with level-1 bootloader to all remaining flash pages (JTAG/SWD locked).

  8. See answer about virgin 0xff state of UUIDs. Can flash generic FW in first step and download/flash only the dedicated UUID-Linker-Section in second step either by FW itself or programming probe. Nontheless: UUIDs should reside in dedicated flash page with other constants (across the entire product/FW life-cycle) as in Opt. 7 -> No flash page wasted, secured against changes due to FW field-update and simple.

I am absolutly happy to learn more about this kind of problems! Thank you.

  • 1
    \$\begingroup\$ Re your #6 - surely you'd want all the UUIDs in the device to stay the same through an update? If you ship the entire image, both FW & UUIDs, in a single encrypted package, then you'd have to create that individualized package for every single device out in the field... If you're only planning on shipping 10 of them then sure - but if you even hope in your wildest dreams to ship more than a few hundred you're just setting yourself up for pain & suffering. \$\endgroup\$
    – brhans
    Commented Nov 6, 2022 at 18:27
  • \$\begingroup\$ A valid point! did not think this one through.... :) Thank you! \$\endgroup\$ Commented Nov 6, 2022 at 18:39

1 Answer 1

  1. Place all of the UUIDs in a separate flash page (your compiler & linker will have instructions to achieve this).
    Use separate CRCs for the main flash image and for the UUID page.
    In production, flash the application binary image (which is identical for every device), then flash the UUID page after using whatever your favorite tool is (python, whatever) to generate an individual UUID page image for each device 'on-the-fly'.

Your recent edit indicated that flash space is a concern and that you might not want to dedicate a full flash page to the UUIDs - that's fine with this method too.
Keeps all the UUIDs in a separate section in your firmware project (using your particular development tools' version of something like gcc's __attribute__((section ".UUIDs")), and ensure that they're uninitialized.
So by default they'll have 0xFF in them, which you can then program afterwards, either using the same flash tool you used to program the firmware, or using the firmware itself.
You do not need to erase & re-flash the entire flash page where this section is located.

  • 1
    \$\begingroup\$ This also makes sense in combination with method 1: reserve separate flash page for UUID, but zero it out in "default" image. Flash default image. Upon booting, the software checks for zero-UUID, and if it encounters that, enters a mode where it waits for the UUID to be transmitted via some e.g. serial link. \$\endgroup\$ Commented Nov 6, 2022 at 16:14
  • \$\begingroup\$ Regarding your edit: Did not even think about the virign 0xFF state. Added as Opt. 8. Thank you! \$\endgroup\$ Commented Nov 6, 2022 at 19:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.