Flash partitioning

The MCUboot, Slot0, and Slot1 flash partitions are defined in the board file. E.g., nrf52840dk_nrf52840.dts has boot_partition at 0 with length 0xC000, slot0_partition at 0xC000 with length 0x76000, slot1_partition at 0x82000 with length 0x76000, and storage_partition picking up at 0xF8000, right after Slot1.

In a Sigurd Hellesvik git repo, I learned about partition_manager_report; "west build -t partition_manager_report", which seems to say that Slot 0, for the primary image, is at 0xC000 with a length of 0x7A000 (starting with a 0x200 "pad") and Slot 1, for the secondary image, is at 0x86000 with a length of 0x7A000. It would seem the partition manager is free to allocate flash0 in nrf52840_qiaa.dtsi however it likes. Is the stuff in the DTS just a suggestion? This would seem to conflict with CONFIG_USE_DT_CODE_PARTITION=y in the prj.conf.

If I put stuff like USB in MCUboot and have to grow the partition to fit it by setting CONFIG_PM_PARTITION_SIZE_MCUBOOT, it reworks Slot0 and Slot1 lengths to fit in the 1Mbyte flash.

If I set CONFIG_NVS=y, partition_manager_report now has a nvs_storage block, not starting at 0xF8000 per the DTS file, but actually CONFIG_PM_PARTITION_SIZE_NVS_STORAGE from the end. So we really can't use the DTS macros to determine where a user-defined constant in flash might be.

The application I'm working on currently reserves some memory at the very end, to be loaded with a device serial number via nrfjprog. I'm "reserving" it in a DTS overlay and giving it a symbol that can be recovered with a DT macro. But if partition manager isn't really paying attention to the partition allocations in DT, how would I tell partition manager to reserve the space and not potentially overwrite it with a DFU or some NVS operation?

  • Short answer: UICR looks like what you need. Specifically CUSTOMEr.

    This cannot be changed, and you have limited space.

    NVS is more for changeable persistent data, or data that you will add regularly (aka large amounts in the end)

    I will return later and write answers to your context questions.


    Maybe Persistent storage of keys and data using the nRF Connect SDK would be of interest in the meantime

  • Thanks. That blog article is very helpful. I will have more questions about using flash when my project gets to that point.

    I've been playing with UICR and it will do exactly what I want for semi-permanently storing the unit serial number, and access it from within the code as *(uint32_t *)(0x10001080). Super!

    Now: I hope you can explain this partition management business to me.

    Among other things, this project:
    1. Uses BLE and saves bonding info, so I've got Settings and BT Settings enabled
    2. Uses NVS for saving program data in flash, to survive power cycles
    3. Will accept DFU via "serial recovery" in the bootloader.

    The relevant config selections:
    CONFIG_FLASH=y
    CONFIG_FLASH_MAP=y
    CONFIG_FLASH_PAGE_LAYOUT=y
    CONFIG_NVS=y
    CONFIG_SETTINGS=y
    CONFIG_BT_SETTINGS=y
    CONFIG_BOOTLOADER_MCUBOOT=y

    For NVS, I'm following the NVS sample. I'm allocating three 4K sectors

    fs.sector_count = 3U;

    The DTS for the nRF52840DK has storage_partition starting at 0xf8000. The code has

    #define NVS_PARTITION storage_partition
    #define NVS_PARTITION_DEVICE FIXED_PARTITION_DEVICE(NVS_PARTITION)
    #define NVS_PARTITION_OFFSET FIXED_PARTITION_OFFSET(NVS_PARTITION)

    If I print

    fs.offset = NVS_PARTITION_OFFSET;

    I get 0xfe000.

    As previously explained, Partition Manager is overriding the Device Tree allocations. However, so happens this is 0x2000 before the end of memory. How is it allocating three sectors (without throwing any errors) when there's only two available?

    And where would it be putting the settings?

    If I look through build/zephyr/.config, I find

    CONFIG_PM_PARTITION_SIZE_SETTINGS_STORAGE=0x2000

    and if I get a partition_manager_report, I get

    flash_primary (0x100000 - 1024kB):
    +-------------------------------------------------+
    | 0x0: mcuboot (0xc000 - 48kB) |
    +---0xc000: mcuboot_primary (0x79000 - 484kB)-----+
    | 0xc000: mcuboot_pad (0x200 - 512B) |
    +---0xc200: mcuboot_primary_app (0x78e00 - 483kB)-+
    | 0xc200: app (0x78e00 - 483kB) |
    +-------------------------------------------------+
    | 0x85000: mcuboot_secondary (0x79000 - 484kB) |
    | 0xfe000: settings_storage (0x2000 - 8kB) |
    +-------------------------------------------------+

    What I believe I'm seeing is that there is no NVS partition reported, just a block for the settings, and there's two 4K sectors. And the space for the secondary image for DFU runs right up to the start of the settings block.

    Apparently, I can't allocate space for an NVS partition separately from the NVS settings space. The symbol

    CONFIG_PM_PARTITION_SIZE_NVS_STORAGE

    depends on

    CONFIG_NVS && !CONFIG_SETTINGS_NVS

    and CONFIG_SETTINGS_NVS is True if CONFIG_SETTINGS and CONFIG_NVS are True.

  • Or perhaps I'm laboring under the misconception that Settings with the NVS backend is using a different flash area than NVS for program data storage.  Perhaps the bond info, and anything else stored as Settings, are mixed in with the entries that the program makes for other purposes.  But then it would seem that Settings would have an allocation of ID numbers separate from the set available for NVS filesystem.

    Even if this is true, seems odd that nvs_mount() would allow setting up the filesystem in three sectors when there are two available.

  • Interestingly, if CONFIG_PM_PARTITION_SIZE_SETTINGS_STORAGE is left at the default 2 sectors, and NVS is set up at runtime with 3 sectors, nvs_mount() won't complain, but (at least) nvs_read() will fail with -EINVAL.  So the PARTITION_SIZE has to be set at least as large as what is requested for the NVS filesystem.  I do that, and nvs_read() doesn't complain anymore.

    I have not yet got to the point of seeing how well NVS for data storage cooperates with NVS for BLE settings.

  • My application has a serial command interface (sort of "shell") in which a command writes a 20-byte object to NVS.  I've rigged this command to print what it is about to write.  I've rigged another command to dump a portion at the top of the Settings partition.  Which is sized at 0x3000 in prj.conf (per above).

    Start: clear out all flash with nrfjprog --eraseall and then west flash the bootloader and application.

    Note that the NVS filesystem is initialized before bt_enable() and settings_load() are called.

    When I dump the partition portion before doing anything else, I get

    000FD000 : FFFF8001 AC2807FA E8DA3D07 968B0056
    000FD000 : A6C9D78D 682F7462 FF687361 FFFFFFFF
    000FD000 : FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF
    000FD000 : FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF

    I'm guessing this is something the BLE subsystem writes into the settings.

    Then I command writing the following object to ID 1 in NVS:

    73646401 0000007B FFFFFF00 12FFFFFF 00000034

    and then dump the partition portion again.

    000FD000 : 73640001 0000007A E8DA3D00 128B0056
    000FD000 : 00000004 682F7462 FF687361 FFFFFFFF
    000FD000 : FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF
    000FD000 : FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF

    nvs_write() is overwriting the previous info.  Therefore I conclude that NVS filesystem for program data storage and NVS for Settings are not compatible.  I'm going to have to set up separate partitions.

Related