This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

A nice place to keep a small amount of state data

Hello Nordic users and employees,

I'm having a small dilemma. The device I'm building runs on the nRF51822 and needs to store a small number of bytes off to the side and some will occasionally be modified. However, flash is very precious in my application, I have a file system that needs as much space as possible.

The bytes must be off to the side and not a part of the file system because they must be read and written by both my main application and a small bootloader and the latter does not have or need the ability to use the file system. This is in the interest of saving space.

I'm considering using the user-reserved parts of the UICR region of memory to save my data, which consists of state and factory production parameters (date of manufacture, etc.). The factory parameters will not change in normal use.

The state data will occasionally change to signal that the bootloader should perform a device firmware update (DFU) on the next restart. Once the DFU is complete, the bootloader must clear the flag and launch the application normally.

I'm a little concerned using the UICR region for this because if it were somehow corrupted the BOOTLOADERADDR field would be unset and my device would become bricked.

Given that background, my question essentially is: Is there a safe way to use UICR for storing a small amount of modifiable data, without putting the BOOTLOADERADDR and other configuration registers at risk, or is there another place to tuck some nonvolitile data out of the way of main flash?

Regards, Cody

  • Hi

    I do not think it is possible to use the UICR to store application data that occasionally needs to be updated. You can write once to the "user reserved data" region of the UICR (addresses 0x10001080 - 0x100010FC), but in order to write again, you need to erase the whole UICR. As described in the nRF51 Reference Manual, chapter for NVMC, when erasing UICR, you also delete the whole code area, i.e. application and bootloader.

    The only retained register is the GPREGRET, which can store one byte. In fact this register is used by the latest bootloader in nRF51 SDK v6.1.0. The latest heart rate example in SDK 6.1.0 includes a bootloader service that you can write to in order to enable bootloader mode from a central device, which is convenient for devices that do not have a button to enable the bootloader mode. The application will write 0xB1 (if I remember correctly) to the GPREGRET register and then restart the device. The bootloader check for value 0xB1 when it starts up and goes into bootloader mode if the value is there.

    Update 22.10.2014 So I guess the conclusion is that the only place to store nonvolatile storage is the 256kB of flash. Have you already utilized all the flash, so there is no space left for these few bytes? Have you compressed the bootloader and your application, in order to consume less flash space?

  • My first answer was to use the GPREGRET register as Stefan mentioned but, of course, it is just one byte and the Nordic bootloader uses it. It is RAM backed.

    A sneaky but similar technique is to use GPIO configuration registers for unassigned pins. They are preserved on sleep as long as power is not removed.

    Dan

  • Thanks for the replies, somehow I disabled email notifications so I didn't realize I had any follow-ups! Here's some resolution:

    I really have two different types of data here.

    The first type is what we call "production values", like the serial number and hardware revision. These are burned-in at the factory during manufacturing and don't ever change during normal use. If we accidentally erase these values during development with a prototype, that is unfortunate but not critical. We ended up placing a small memory segment containing these values at a high address above our bootloader in flash, making use of the "slop" between the end of the bootloader and the beginning of the next page of flash.

    The second type of data, which is kind of a "boot mode" flag and some associated data is more volatile, though it has to persist through resets. While it would have made some things easier to keep it in flash, the use of an entire page to store several dozen bytes was too wasteful.

    To keep this data, we carved up a small piece of RAM, just above the S110's section, and located a struct there holding our values. We also used a "magic number" signature and a checksum, updated at every write to this section, to guarantee the data was valid.

    Then we designed to bootloader to verify a checksum over the application space before executing the application. That way, if we completely lose power and RAM while the application is being updated we know not to execute the corrupt application and instead ask for an OTA update. What this means is we have a fail-safe if the boot mode flags are lost and the system is in a bad state.

    I hope this helps anybody else in a similar situation :).

    Oh, and we would have used the UICR for the static production values, but we determined flash was simpler and we had some available anyway...

  • This is exactly what we did with our old project as well. Figured it would be similar with the NRF :)

Related