Mount LittleFS to both internal & external flash

Greetings,

I have previously added the LittleFS to the internal flash of the nRF52840 with success using the available documentation. Our .dts & and code is shown below.

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

/* Flash configuration copied from nRF52840DK */
&flash0 {

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

		boot_partition: partition@0 {
			label = "mcuboot";
			reg = <0x00000000 0x0000C000>;
		};
		slot0_partition: partition@c000 {
			label = "image-0";
			reg = <0x0000C000 0x00067000>;
		};
		slot1_partition: partition@73000 {
			label = "image-1";
			reg = <0x00073000 0x00067000>;
		};
		scratch_partition: partition@da000 {
			label = "image-scratch";
			reg = <0x000da000 0x0001e000>;
		};

		/*
		 * The flash starting at 0x000f8000 and ending at
		 * 0x000fffff is reserved for use by the application.
		 */

		/*
		 * Storage partition will be used by FCB/LittleFS/NVS
		 * if enabled.
		 */
		storage_partition: partition@f8000 {
			label = "storage";
			reg = <0x000f8000 0x00008000>;
		};
	};
};

#define PARTITION_NODE DT_NODELABEL(lfs1)

FS_FSTAB_DECLARE_ENTRY(PARTITION_NODE);

static struct fs_mount_t *mp =	&FS_FSTAB_ENTRY(PARTITION_NODE);

prj.conf

# Flash File System configuration
CONFIG_FLASH=y
CONFIG_FLASH_MAP=y
CONFIG_FLASH_PAGE_LAYOUT=y
CONFIG_FILE_SYSTEM=y
CONFIG_FILE_SYSTEM_LITTLEFS=y

After this configuration, we were able to use the internal flash to store/retrieve data with ease.

Now we want to mount a second instance of LittleFS to an external flash memory (SPI NOR W25Q512NW). We have tried two different ways but both result in the same.

1st implementation:

.DTS file

/ {
	chosen {
		zephyr,sram = &sram0;
		zephyr,flash = &flash0;
		zephyr,code-partition = &slot0_partition;
		zephyr,pm-ext-flash = &w25q512nw;
	};

&spi1{
	compatible = "nordic,nrf-spi";
	status = "okay";
	pinctrl-0 = <&spi1_default>;
	pinctrl-1 = <&spi1_sleep>;
	pinctrl-names = "default", "sleep";
	cs-gpios = < &gpio0 26 GPIO_ACTIVE_LOW >;

	w25q512nw: w25q512nw@0 {
		compatible = "jedec,spi-nor";
		status = "okay";
		label = "W25Q512NW";
		wp-gpios = <&gpio0 30 GPIO_ACTIVE_LOW>;
		hold-gpios = <&gpio0 14 GPIO_ACTIVE_LOW>;
		reg = < 0 >;
		spi-max-frequency = < 8000000 >;
		jedec-id = [ ef 60 20 ]; // Manufacturer ID = EFh, Memory Type (ID15-ID8) = 60h and Capacity (ID7-ID0) = 20h 
		size = < 536870912 >;    // Flash capacity in bits = 512M-bit = 1024 * 1024 * 512 * 1bit = 536870912 bit
		has-dpd;
		t-enter-dpd = < 3000 >;  // in nanoseconds - The power-down state will entered within the time duration of tDP: 3us 
		t-exit-dpd = < 30000 >;  // in nanoseconds - The Release from power-down will take the time duration of tRES1: 30us
	};
};

Code:

FS_LITTLEFS_DECLARE_DEFAULT_CONFIG(_LfsConfig);
static struct fs_mount_t lfs_storage_mnt = {
  .type = FS_LITTLEFS,
  .fs_data = &_LfsConfig,
  // .storage_dev = (void *)DT_FLASH_AREA_STORAGE_ID,
  .storage_dev = (void *)FLASH_AREA_ID(littlefs_storage),
  .mnt_point = "/lfs2"
};

prj.conf

# SPI NOR configuration
CONFIG_SPI=y
CONFIG_SPI_NOR=y
CONFIG_SPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096

# Partition Manager Setttings
CONFIG_PM_EXTERNAL_FLASH_MCUBOOT_SECONDARY=n

 2nd implementation:

.dts file:

/ {

	chosen {

		zephyr,sram = &sram0;
		zephyr,flash = &flash0;
		zephyr,code-partition = &slot0_partition;
		zephyr,pm-ext-flash = &w25q512nw;
	};
};

&spi1{
	compatible = "nordic,nrf-spi";
	status = "okay";
	pinctrl-0 = <&spi1_default>;
	pinctrl-1 = <&spi1_sleep>;
	pinctrl-names = "default", "sleep";
	cs-gpios = < &gpio0 26 GPIO_ACTIVE_LOW >;

	w25q512nw: w25q512nw@0 {
		compatible = "jedec,spi-nor";
		status = "okay";
		label = "W25Q512NW";
		wp-gpios = <&gpio0 30 GPIO_ACTIVE_LOW>;
		hold-gpios = <&gpio0 14 GPIO_ACTIVE_LOW>;
		reg = < 0 >;
		spi-max-frequency = < 8000000 >;
		jedec-id = [ ef 60 20 ]; // Manufacturer ID = EFh, Memory Type (ID15-ID8) = 60h and Capacity (ID7-ID0) = 20h 
		size = < 536870912 >;    // Flash capacity in bits = 512M-bit = 1024 * 1024 * 512 * 1bit = 536870912 bit
		has-dpd;
		t-enter-dpd = < 3000 >;  // in nanoseconds - The power-down state will entered within the time duration of tDP: 3us 
		t-exit-dpd = < 30000 >;  // in nanoseconds - The Release from power-down will take the time duration of tRES1: 30us
		partitions {
			compatible = "fixed-partitions";
			#address-cells = <1>;
			#size-cells = <1>;
			/* 64 MB partition to use for LFS filesystem */
			ext_storage_partition: partition@0000000 {
				label = "littlefs_storage";
				reg = <0x0000000 0x2000000>;
			};
		};
	};
};

Code:

#define FLASH_EXT_PARTITION_NODE DT_NODELABEL(lfs2)
FS_FSTAB_DECLARE_ENTRY(FLASH_EXT_PARTITION_NODE);

static struct fs_mount_t *lfs_storage_mnt =	&FS_FSTAB_ENTRY(FLASH_EXT_PARTITION_NODE);

prj.conf

# SPI NOR configuration
CONFIG_SPI=y
CONFIG_SPI_NOR=y
CONFIG_SPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096

# Partition Manager Setttings
CONFIG_PM_EXTERNAL_FLASH_MCUBOOT_SECONDARY=n

For both these implementation, we get the same result, it seems that the two LittleFS file systems are mounted to the same place which is the internal SoC flash memory because the logs we get is shown below:

[00:00:00.002,502] <inf> littlefs: littlefs partition at /lfs1
[00:00:00.002,532] <inf> littlefs: LittleFS version 2.4, disk version 2.0
[00:00:00.002,777] <inf> littlefs: FS at flash-controller@4001e000:0xf8000 is 6 0x1000-byte blocks with 512 cycle
[00:00:00.002,777] <inf> littlefs: sizes: rd 16 ; pr 16 ; ca 64 ; la 32
[00:00:00.002,868] <err> littlefs: WEST_TOPDIR/modules/fs/littlefs/lfs.c:1077: Corrupted dir pair at {0x0, 0x1}
[00:00:00.002,899] <wrn> littlefs: can't mount (LFS -84); formatting
[00:00:00.175,292] <inf> littlefs: /lfs1 mounted
[00:00:00.175,292] <inf> littlefs: Automount /lfs1 succeeded
[00:00:00.175,323] <inf> littlefs: littlefs partition at /lfs2
[00:00:00.175,323] <inf> littlefs: LittleFS version 2.4, disk version 2.0
[00:00:00.175,567] <inf> littlefs: FS at flash-controller@4001e000:0xf8000 is 6 0x1000-byte blocks with 512 cycle
[00:00:00.175,598] <inf> littlefs: sizes: rd 16 ; pr 16 ; ca 64 ; la 32
[00:00:00.175,842] <inf> littlefs: /lfs2 mounted
[00:00:00.175,872] <inf> littlefs: Automount /lfs2 succeeded

As seen in Line 3 & Line 11 the File Systems seem to be mounted at the same partition in the internal SoC flash.

How could we make the second instance of LittleFS to be mounted correctly in the external flash (while still keeping the first instance mounted on the internal SoC flash)? 

Thank you and I look forward to hearing from you!

Best Regards,

Stavros

Parents Reply Children
  • Hello Sigurd,

    I did try all combinations of defining the mount point with the CONFIG_PM_PARTITION_REGION_LITTLEFS_EXTERNAL=y enabled but I still get a mounting error for the external flash storage ( the internal flash is mounted successfully).

    Could you please provide some feedback on the following questions:

    1. Is it possible to mount one instance of the LittleFS system in the internal flash and in the same application (simultaneously) mount a second instance of the LittleFS system in the external SPI NOR flash?
    2. Could you please send some code or some more specific information on which way the mounting needs to be set-up, using the FSTAB entries or manually?
    3. Also what about the .dts file do I need to just define the flash memory subnode in the spi node as shown below or do I need to add the partition property to it as shown in the second segment below:

    Just the flash memory node:

    &spi1{
    	compatible = "nordic,nrf-spi";
    	status = "okay";
    	pinctrl-0 = <&spi1_default>;
    	pinctrl-1 = <&spi1_sleep>;
    	pinctrl-names = "default", "sleep";
    	cs-gpios = < &gpio0 26 GPIO_ACTIVE_LOW >;
    
    	w25q512nw: w25q512nw@0 {
    		compatible = "jedec,spi-nor";
    		status = "okay";
    		label = "W25Q512NW";
    		wp-gpios = <&gpio0 30 GPIO_ACTIVE_LOW>;
    		hold-gpios = <&gpio0 14 GPIO_ACTIVE_LOW>;
    		reg = < 0 >;
    		spi-max-frequency = < 8000000 >;
    		jedec-id = [ ef 60 20 ]; // Manufacturer ID = EFh, Memory Type (ID15-ID8) = 60h and Capacity (ID7-ID0) = 20h 
    		size = < 536870912 >;    // Flash capacity in bits = 512M-bit = 1024 * 1024 * 512 * 1bit = 536870912 bit
    		has-dpd;
    		t-enter-dpd = < 3000 >;  // in nanoseconds - The power-down state will entered within the time duration of tDP: 3us 
    		t-exit-dpd = < 30000 >;  // in nanoseconds - The Release from power-down will take the time duration of tRES1: 30us
    	};
    };

    The flash memory node with the partition property as shown in the post you linked

    &spi1{
    	compatible = "nordic,nrf-spi";
    	status = "okay";
    	pinctrl-0 = <&spi1_default>;
    	pinctrl-1 = <&spi1_sleep>;
    	pinctrl-names = "default", "sleep";
    	cs-gpios = < &gpio0 26 GPIO_ACTIVE_LOW >;
    
    	w25q512nw: w25q512nw@0 {
    		compatible = "jedec,spi-nor";
    		status = "okay";
    		label = "W25Q512NW";
    		wp-gpios = <&gpio0 30 GPIO_ACTIVE_LOW>;
    		hold-gpios = <&gpio0 14 GPIO_ACTIVE_LOW>;
    		reg = < 0 >;
    		spi-max-frequency = < 8000000 >;
    		jedec-id = [ ef 60 20 ]; // Manufacturer ID = EFh, Memory Type (ID15-ID8) = 60h and Capacity (ID7-ID0) = 20h 
    		size = < 536870912 >;    // Flash capacity in bits = 512M-bit = 1024 * 1024 * 512 * 1bit = 536870912 bit
    		has-dpd;
    		t-enter-dpd = < 3000 >;  // in nanoseconds - The power-down state will entered within the time duration of tDP: 3us 
    		t-exit-dpd = < 30000 >;  // in nanoseconds - The Release from power-down will take the time duration of tRES1: 30us
    	    partitions {
    			compatible = "fixed-partitions";
    			#address-cells = <1>;
    			#size-cells = <1>;
    			/* 64 MB partition to use for LFS filesystem */
    			ext_storage_partition: partition@0000000 {
    				label = "external_flash";
    				reg = <0x0000000 0x2000000>;
    			};
    		};
    	};
    };

    I also assumed this piece for the .dts is necessary, please confirm.

    chosen {
    		nordic,pm-ext-flash = &w25q512nw;
    	};

    1. For the mount point definition(for the external flash) in the code so I need to define using the FSTAB entry or the manual entry? For the manual entry, what do I need to put in the .storage_dev field?

    FS_LITTLEFS_DECLARE_DEFAULT_CONFIG(_LfsConfig);
    static struct fs_mount_t lfs_storage_mnt = {
    	.type = FS_LITTLEFS,
    	.fs_data = &_LfsConfig,
    	// .storage_dev = (void *)FLASH_AREA_LABEL_STR(external_flash),
    	.storage_dev = (void *)FLASH_AREA_ID(external_flash),
    	.mnt_point = "/lfs2",
    };
    
    static struct fs_mount_t *mp = &lfs_storage_mnt;

    1. The internal flash is set up successfully using the following definition of the mount point. Could this definition create conflicts with the external flash definition of the mount point?

    FS_LITTLEFS_DECLARE_DEFAULT_CONFIG(_Lfs1Config);
    static struct fs_mount_t lfs_storage_mnt = {
    	.type = FS_LITTLEFS,
    	.fs_data = &_Lfs1Config,
    	.storage_dev = (void *)FLASH_AREA_ID(storage),
    	.mnt_point = "/lfs1",
    };
    
    static	struct fs_mount_t *mp =	&lfs_storage_mnt;

    1. For the prj file I have the following, please confirm if any config options are missing or need to be changed?

    # Flash File System configuration
    CONFIG_FLASH=y
    CONFIG_FLASH_MAP=y
    CONFIG_FLASH_PAGE_LAYOUT=y
    CONFIG_FILE_SYSTEM=y
    CONFIG_FILE_SYSTEM_LITTLEFS=y
    
    # SPI NOR configuration
    CONFIG_SPI=y
    CONFIG_SPI_NOR=y
    CONFIG_SPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096
    
    # Partition Manager Setttings
    CONFIG_PM_EXTERNAL_FLASH_MCUBOOT_SECONDARY=n
    CONFIG_PM_PARTITION_REGION_LITTLEFS_EXTERNAL=y
    CONFIG_PM_PARTITION_SIZE_LITTLEFS=0x2000000

    If you could please provide specific answers in these 6 questions numbered above it would be extremely helpful.

    Thank you very much and I look forward to hearing from you!

    Best regards,

    Stavros

  • Hi, sorry to get into this conversation; I have the same problem, the same flash and the same micro, and I am very interested in a possible solution.

  •  I am very interested in a possible solution.

Related