Configuring external flash and internal flash for MCU Boot, Little FS, and for settings with a custom board

I am trying to set up a w25q128 using SPI with a nrf5340 on a custom board and had a few questions. I have used DevAcademy as a reference as I do eventually want to set up MCUBoot but right now I want to get the fiile system and settings up and running. 

  • Is there any change to the need for pm_static.yml when using toolchains 2.9.x or 3.x?
  • Is there a reason why one would use the boot, slot0, and slot1 partitions for mcuboot on external flash vs internal flash? Could I use the 1MB of internal flash for this?
  • Do I need to create a seperate partition when using the Zephyr settings infrastructure?
  • Are the instructions to use pm manager until things are set applicable when using littlefs? Doesn't that also cause me to "freeze" the partitions (see reference below)?
  • Does SRAM needs to be configured as well?
  • I have seen multiple entries for secure and non-secure, do I need to create paritions for each? When does one get used vs another?

I've watched this Nordic video on DFU/FOTA which was great and I hope you do more of these. The use of pm manager and memory report to show the memory:

In it he recommends using dynamic partitioning for development and then freeze the partitioning. I've also listened to Zephyr 101 - Device Settings Using nRF9160 Feather External Flash which is also very helpful but would like to drill deeper into some of the specific topics I'm interested in and would like more coverage of the basics as well. For example:

When I have this code:

//start filesystem config
#define PARTITION_NODE DT_NODELABEL(lfs)
FS_FSTAB_DECLARE_ENTRY(PARTITION_NODE);
struct fs_mount_t *mp = &FS_FSTAB_ENTRY(PARTITION_NODE);

It references a fstab entry which in another example I have looks like this:

	fstab {
		compatible = "zephyr,fstab";
		lfs: lfs {
			compatible = "zephyr,fstab,littlefs";
			mount-point = "/lfs";
			partition = <&littlefs_storage>;
			automount;
            read-size = <16>;
			prog-size = <16>;
			cache-size = <64>;
			lookahead-size = <32>;
			block-cycles = <512>;
		};
	};

I believe that also has to be references in the device tree as well. In the case of the dk I am trying to adapt to my custom board that would look like:

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

		littlefs_storage: partition@0 {
			label = "littlefs_storage";
			reg = <0x00000000 0x00200000>;
		};
		lvgl_raw_partition: partition@200000 {
			label = "lvgl_raw_partition";
			reg = <0x00200000 0x00200000>;
		};
        settings_partition: partition@400000 {
            label = "settings_partition";
            reg = <0x400000 0x100000 >;
        };
	};
};


I don't really need all those partitions, but the example I was using had them. I don't know if I need to keep settings in a different partition from the littlefs_storage or not. I guess this is the part I need to mirror in the pm_static.yml, is that correct? Do I only need to have a subset of the entries from the pm_static.yml in here? Do the values (such as reg) need to match those in the pm_static.yml?

I've had even very seasoned Zephry/Nordic people mention "It's not super easy to get it up and running, took me some fiddling around until I got it to work...", so it may be worth while to cover. I've seen

I have seen the comments in here which brings up the quetion of trust zone and sram.

I see the documentation for partition manager and 

Regarding posts I've read:

I've looked in git and seen:

  • sdk-nrf which seems to also include sram entries
Parents
  • Hi,

    Is there any change to the need for pm_static.yml when using toolchains 2.9.x or 3.x?

    No. Same as before: Don't need for development, but required for release.

    Is there a reason why one would use the boot, slot0, and slot1 partitions for mcuboot on external flash vs internal flash? Could I use the 1MB of internal flash for this?

    boot and slot0 must be on internal flash. slot1 is typically on external flash if you got external flash, but it can be on internal flash if you want to.

    Do I need to create a seperate partition when using the Zephyr settings infrastructure?

    A settings partition will be created automatically for you if use dynamic partitioning and enable settings. If you use static partitioning, then yes.

    Does SRAM needs to be configured as well?

    This will be done dynamically, so I recommend to not do that manually.

    I have seen multiple entries for secure and non-secure, do I need to create paritions for each? When does one get used vs another?

    This will be done dynamically if you use TF-M. Will you use TF-M in your project?

    I've watched this Nordic video on DFU/FOTA which was great and I hope you do more of these.

    Im glad you liked it!

    In it he recommends using dynamic partitioning for development and then freeze the partitioning.

    I still stand by this!

    n the case of the dk I am trying to adapt to my custom board that would look like:

    This is a bit complicated, but:
    If you use the Partition Manager, the partitions in DTS will be ignored. So you can keep them there, but use the one from the partition manager instead.

    I don't really need all those partitions, but the example I was using had them. I don't know if I need to keep settings in a different partition from the littlefs_storage or not. I guess this is the part I need to mirror in the pm_static.yml, is that correct? Do I only need to have a subset of the entries from the pm_static.yml in here? Do the values (such as reg) need to match those in the pm_static.yml?

    The easiest would be to use dynamic partitioning, and then make sure that the DTS partitioning matches the partition report from VS Code after the build. Then build again. 
    Or if you use pm_static.yml, then make the DTS and pm_static.yml match. This is kinda not needed, since DTS partitions are ignored, but I think keeping them aligned will help for tidyness.

    I've had even very seasoned Zephry/Nordic people mention "It's not super easy to get it up and running, took me some fiddling around until I got it to work...", so it may be worth while to cover. I've seen

    But hey, we do have a support team that are doing our best to help you learn this!

    Regards,
    Sigurd Hellesvik

  • Wow. I get the firmware social media sensation on my ticket. I'm truly honored. One of the best decisions I made was to learn on Nordic. Support is incredible and though Zepher is difficult, particularly for a newbie, it seems like the right way to do things. Honestly I can't think of a better support experience I've ever had. My introduction was to Don J and it's been consistently high ever since.

    Ok. Excellent response. Thank you. So I'm going to do everything dynamically and then use the partition report to inform the pm_static.yml when moving to production.

    This will be done dynamically if you use TF-M. Will you use TF-M in your project?

    Probably. I'm just trying to get things working now but I will need secure everything.

    But if I am using fstab it references a partition which I need to have in the dts/overlay. Let's use the fstab I saw in the example:

    	fstab {
    		compatible = "zephyr,fstab";
    		lfs: lfs {
    			compatible = "zephyr,fstab,littlefs";
    			mount-point = "/lfs";
    			partition = <&littlefs_storage>;
    			automount;
                read-size = <16>;
    			prog-size = <16>;
    			cache-size = <64>;
    			lookahead-size = <32>;
    			block-cycles = <512>;
    		};
    	};

    It references littlefs_storage which means I need to include that in a partition reference someplace, right? So how do I use fstab and dynamic partitioning to get this code to work in main.c?

    #define PARTITION_NODE DT_NODELABEL(lfs)
    FS_FSTAB_DECLARE_ENTRY(PARTITION_NODE);
    struct fs_mount_t *mp = &FS_FSTAB_ENTRY(PARTITION_NODE);

    I actually got it building without the fstab but littlefs_storage is on the primary flash. Is there anyway to size it and ensure it's on external flash?

    If I'm using dynamic partitioning I at least need to get the partions onto the right regions, correct? Also, I need a lot more space on my littlefs_storage partition than what was dynamically created.

  • lcj said:
    It references littlefs_storage which means I need to include that in a partition reference someplace, right? So how do I use fstab and dynamic partitioning to get this code to work in main.c?

    Im not sure about exactly how this works with fstab, but maybe  you can just keep that DTS node as is, and then we assume that the partition manager will make it work?

    lcj said:
    I actually got it building without the fstab but littlefs_storage is on the primary flash. Is there anyway to size it and ensure it's on external flash?

    CONFIG_PM_PARTITION_SIZE_LITTLEFS
    CONFIG_PM_PARTITION_REGION_LITTLEFS_EXTERNAL

    (partly documented here)

    lcj said:
    If I'm using dynamic partitioning I at least need to get the partions onto the right regions, correct?

    Yes, but you do that using Kconfig, as seen above.

  • Amazing! Thank you.

    One more thing. When going to production, I need to create a pm_static.yml file. Do I grab the values from this report or is there some other way you would approach it?

  • Maybe I spoke too soon. I'm getting and error and traced it to:

    static inline struct flash_area const *get_flash_area_from_id(int idx)
    {
    	for (int i = 0; i < flash_map_entries; i++) {
    		if (flash_map[i].fa_id == idx) {
    			return &flash_map[i];
    		}
    	}
    
    	return NULL;
    }

    when idx=1, i=0 (first iteration of the loop), and flash_map_entries = 1. flashmap[0] looks like this;

    It errors on an evaluation when there appear to be values to compare.

    and the calling function the area does not appear to be null, although I see a "cannot access memory..." error in there.

    It is called from but fails and -2 is returned.

    	area = get_flash_area_from_id(id);
    	if (area == NULL) {
    		return -ENOENT;
    	}

    The calling function was taken from the sample:

    		/* Mount the filesystem */
    		rc = fs_mount(&lfs_storage_mnt);
    		if (rc < 0) {
    			LOG_ERR("Failed to mount filesystem: %d", rc);
    			return rc;
    		}

    at runtime the mountpoint is:

    type =1
    mnt_point =0x45afc "/"
    fs_data =0x200004e8 <littlefs_storage>
    storage_dev =0x1 <settings_init>
    mountp_len =0
    fs =0x0 <settings_init>
    flags =0 '\000'

    Probably something to do with my configuration. These are the relevant parts of my .dts.

    / {
    	chosen {
    		nordic,pm-ext-flash = &w25q128;
    	};
    };
    
    
    
    
    
    &spi3  {
        status = "okay";
        compatible = "nordic,nrf-spim";
        pinctrl-0 = <&spi3_default>;
        pinctrl-1 = <&spi3_sleep>;
        pinctrl-names = "default", "sleep";
        cs-gpios = <&gpio0 13 GPIO_ACTIVE_LOW>;
        w25q128: w25q128@0 {
    		compatible = "jedec,spi-nor";
    		reg = <0>;
    		//status = "okay";
    		spi-max-frequency = <8000000>;
    		//jedec-id = [ef 18 40]; // Could be 18 40 ef also. You will see in error printout if wrong ID is detected (ID missmatch)
    		jedec-id = [ef 40 18]; // Could be 18 40 ef also. You will see in error printout if wrong ID is detected (ID missmatch)
    		size = <DT_SIZE_M(16*8)>;
    		wp-gpios = <&gpio0 14 GPIO_ACTIVE_LOW>;
    		reset-gpios = <&gpio0 15 GPIO_ACTIVE_LOW>;
    		has-dpd;
            // CS High to Power-Down Mode (tDP) - 3 us
            // https://www.mouser.se/datasheet/2/949/w25q128jv_revf_03272018_plus-1489608.pdf
    		// 9.6 AC Electrical Characteristics(6)
    		t-enter-dpd = <3000>;
            // CS High to Standby Mode without Electronic Signature Read (tRES1) 3 us
            // https://www.mouser.se/datasheet/2/949/w25q128jv_revf_03272018_plus-1489608.pdf
    		// 9.6 AC Electrical Characteristics(6)
    		t-exit-dpd = <3000>;
    	};
    };

    This is what it looks like in main.c:

    	FS_LITTLEFS_DECLARE_DEFAULT_CONFIG(storage);
    	static struct fs_mount_t lfs_storage_mnt = {
    		.type = FS_LITTLEFS,
    		.fs_data = &storage,
    		.storage_dev = (void *)FIXED_PARTITION_ID(storage_partition),
    		.mnt_point = "/lfs",
    	};
    
    	struct fs_mount_t *mountpoint = &lfs_storage_mnt;

    I did see this: the first initialization sends an error: -19 which is what I am getting but I'm on 2.9.1.

  • Ah I thought we had it. Oh well.

    If it is not too much hassle, can you try to disable the partition manager with SB_CONFIG_PARTITION_MANAGER=n and then try the same?

    Im thinking that it would give us good info if we see the same issue without the partition manager or not.
    Who knows, this could even be  a workaround for you

Reply Children
  • No problem at all. So I need a sysbuild.conf and put that in it, correct?

    My memory report shows no partitions when I do that:

    When I did it without the SB_CONFIG_PARTITION_MANAGER=n I added this to the overlay to see if that was the problem:

    &w25q128 {
    	status = "okay";
      partitions {
    		compatible = "fixed-partitions";
    		#address-cells = <1>;
    		#size-cells = <1>;
    		// For Nordic Partition manager to work it has to have this name.
    		littlefs_storage: partition@0 {
    			label = "littlefs_storage";
    			reg = <0x00000000 0xc00000>;
    		};
        external_flash: partition@00c00000 {
    			label = "external_flash";
    			reg = <0x00c00000 0x400000>;
    		};
    	};
    };

    Which matched the memory report:

Related