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
  • They commented;

    ...the user may not be able to use the FS_FSTAB_ENTRY macro to mount the partition as this thing can only mount to the one of predefined  partitions known by the partition manager.

    Instead user will have to define the fs_mount_t point by hand, like for example in samples/subsys/fs/littlefs/src/main.c.

  • As clearly shown in my original post I have tried both methods of declaring an FSTAB entry and defining the mount point by hand but the results are the same.

    So is it possible to have two LittleFS instances in the context of nRF Connect SDK?

    It seems that the LittleFS has specific mount point names/predefined partitions that it relates to and does not permit mounting it to a partition with a different label (in the .dts) how can this be done. How can I mount the second instance of LittleFS to a not predefined partition?? Is there a way to define the second partition of my external flash in any other way.

    Also, I have scoured every piece of documentation and info on this so I have already seen the samples and have already tried all code from the LittleFS samples, other tickets on DevZone, third party implementation on the net and everything nd anything that is relevant with this that is out there. 

    Could you provide explicit code on how to define the mount points by hand, in detail, because at this point I have already tried every way and every sub combinations of the way.

    Thank you

  • clockis said:
    Also, I have scoured every piece of documentation and info on this so I have already seen the samples and have already tried all code from the LittleFS samples

    Can you give some more information why this is not working for you? The little FS sample shows how to manually define the mount point. You can include logs and error codes preferably. Give as detailed information as possible.

  • The little FS sample shows how to manually define the mount point. You can include logs and error codes preferably. Give as detailed information as possible.

    I have already done the manual definition exactly as it is done in the sample (copied the code from the LittleFS sample) as shown in the 1st implementation in my original post, it doesn't work for two instances of the LittleFS because it mounts them on the same mount point of the internal flash memory..

    I want to mount one instance of the LittleFS in the internal memory (as it currently is) and one other instance of the LittleFS simultaneously on the external flash IC W25Q512NW.

    The first instance is mounted correctly and works as intended (by following the LittleFS sample) but when I try to add the second instance of the LittleFS to the external flash memory IC as shown below, and in every other combination as shown in the original post, it always mounts the second instance to the internal memory as well. 

    I have also included the logs and the error codes, but I will do that again if it helps.

    Manual definition of the mount point in the 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"
    };
    
    struct fs_mount_t *mp = &lfs_storage_mnt;

    .DTS file

    / {
    	chosen {
    		zephyr,sram = &sram0;
    		zephyr,flash = &flash0;
    		zephyr,code-partition = &slot0_partition;
    		nordic,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
    	};
    };

    I also tried with this alternative .DTS file

    / {
    
    	chosen {
    
    		zephyr,sram = &sram0;
    		zephyr,flash = &flash0;
    		zephyr,code-partition = &slot0_partition;
    		nordic,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>;
    			};
    		};
    	};
    };

    also in the prj.conf is the following

    # 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

    Finally, the error codes/logs are the same as in the original post.

    [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

    Could you tell me if anything is wrong in my manual definition of the mount point or in the DTS files? or if something else is causing this behavior? how can I do this so the two instances of the LittleFS can be mounted simultaneously (one for the internal flash) and on for the external flash IC)?

    Are the values passed in the members of the struct in the manual definition of the mount point in the code, correct? Do I need to change something there? the LittleFS sample code does not take into account two simultaneous instances so that is why I am asking for verification on this and it seems that there are only two possible permitted values for the .storage_dev member of the struct, and they both point to the internal flash, so I want to know how to populate these members in my case because I either get build errors or the behavior posted above.

    Thank you for your feedback, please contact me if any more information is needed.

  • Hello

    Kind reminder for any updates or info on this, I have provided as much code, files, logs, and details as I could but if anything else is needed please feel free to ask and I will provide it

    BR

    Stavros

  • Hi,

    Kind reminder on any update or any info on this! If any other information is needed please inform me and I will provide it!

    Thank you and I look forward to hearing from you

  • Hello  
    I'm encountering the same issue — did you happen to find a solution?
    Regards,
    Aurélien

Reply Children
No Data
Related