Reserving internal flash for user data

nRF52832 & nRF Connect SDK 2.6.1

We would like to reserve some internal flash for user configuration data that would be written in production like

nrfjprog -f NRF52 --erasepage 0x7F000
nrfjprog -f NRF52 --memwr 0x07F000 --val <data0> --verify
nrfjprog -f NRF52 --memwr 0x07F004 --val <data1> --verify
...

and read by FW but never modified by FW.

So we shrank the "storage" partition and added a custom partition in our *.dts:

&flash0 {
    partitions {
        compatible = "fixed-partitions";
        #address-cells = <1>;
        #size-cells = <1>;

        boot_partition: partition@0 {
            label = "mcuboot";
            reg = <0x0 0xc000>;
        };
        slot0_partition: partition@c000 {
            label = "image-0";
            reg = <0xc000 0x32000>;
        };
        slot1_partition: partition@3e000 {
            label = "image-1";
            reg = <0x3e000 0x32000>;
        };
        scratch_partition: partition@70000 {
            label = "image-scratch";
            reg = <0x70000 0xa000>;
        };
        storage_partition: partition@7a000 {
            label = "storage";
            reg = <0x7a000 0x5000>;
        };
        config_partition: partition@7f000 {
            label = "config";
            reg = <0x7f000 0x1000>;
        };
    };
};

Is this enough to guarantee that this last flash page will neither be used by anything else (NVM, code, ...) nor erased or written to during FW flashing?

Parents
  • Hi,

    If you don't use the partition manager, then it looks good. However, the default for multi image builds is to use the partition manager, and then you need to make changes in pm_static.yml.  See Configuring static partitions for details.

  • Thank you for your prompt response. I have two sub-questions:

    1. To be sure that we are not using the partition manager, is it enough to check that no partitions.yml file gets generated in the build folder?

    2. We would also like to have a few bytes of FW version data at a fixed address somewhere in flash (but outside the config_partition, not to get erased) to be readable by

    nrfjprog -f NRF52 --memrd <address>

    Unlike the config data mentioned above, this data should be part of the FW image that gets flashed when the FW is written. As far as I understand, this should be done by placing a variable in a dedicated section:

    static const uint32_t FW_VERSION __attribute__((section(<section_name>))) = 0x12345678;
    

    If this is the right way to achieve this, how to create this new section and specify its address? And how to prevent the compiler eliminating it as an unused variable?

    Or perhaps there is a better way to guarantee that the FW binary will contain some known bytes at a known address?

  • Hi,

    1. That should be good, but you can also see the generated config files. If using sysbuild, you can add SB_CONFIG_PARTITION_MANAGER=n to sysbuild.conf to make sure it is disabled.

    2. Yes, if you use that approach to specify an address within the firmware that makes sense. This can be done with __attribute__ as you would any other C project built with GCC.

  • Hi,

    so how to create a new section to put its name into __attribute__?

    And where to specify the absolute address at which the variable should be put?

    FYI: If I use

    __attribute__((at(0x7f000))) static const uint32_t FW_VERSION = 0x12345768;

    I get this at build:

    warning: 'at' attribute directive ignored [-Wattributes]

  • Hi,

    You can refer to the implementation of fw_info to see how it is done there (you have the cod ein fw_info.c and the linker script in fw_info.ld. Also, there the Kconfig defines the address as an offset by FW_INFO_OFFSET.

    (This module does much of what you describe that you want from before, so you could also consider using it directly).

  • Thank you. In the meantime, I found a 2nd solution:

    - Put a custom.ld file in project folder with the following lines:

    .version_section 0x3DFC0 :
    {
    PROVIDE(__version_section_start = .);
    KEEP(*(.version_section))
    PROVIDE(__version_section_end = .);
    } > FLASH
    

    - Add the following line to CMakeLists.txt:

    zephyr_linker_sources(SECTIONS custom.ld)

    - Define your variable that will be put to the address specified in custom.ld:

    static const uint32_t FW_VERSION __attribute__((section(".version_section"))) __attribute__((used)) = 0x12345678;

Reply
  • Thank you. In the meantime, I found a 2nd solution:

    - Put a custom.ld file in project folder with the following lines:

    .version_section 0x3DFC0 :
    {
    PROVIDE(__version_section_start = .);
    KEEP(*(.version_section))
    PROVIDE(__version_section_end = .);
    } > FLASH
    

    - Add the following line to CMakeLists.txt:

    zephyr_linker_sources(SECTIONS custom.ld)

    - Define your variable that will be put to the address specified in custom.ld:

    static const uint32_t FW_VERSION __attribute__((section(".version_section"))) __attribute__((used)) = 0x12345678;

Children
No Data
Related