Unable to use LittleFS on External Flash on nrf9160

Hello,

I am currently using the nrf9160dk and would like to use the external flash available on the development kit. I want to use LittleFS on the external flash. 

I found several articles all covering different aspects, but I was unable to arrive to a working solution for using LittleFS on the external flash.

-  I first tested the external flash using the NVS sample and got that working.

-  Then I proceeded to the LittleFS sample located in the 'zephyr/samples/subsys/fs/littlefs' directory. Now the board has two different build targets, the nrf9160_9160 and the nrf9160_9160_ns version. I first tried the non-"ns" version (so secure) as per this post of someone getting it to work. It built successfully, but unlike the post, I received this message in the log indicating that it was using the internal flash rather than the external flash chip. (Using strictly the sample code only). Calculating the size (6 * 0x1000 = ~24kB) which indicates it is the internal flash.

[00:00:00.406,524] <inf> littlefs: FS at NRF_FLASH_DRV_NAME:0xfa000 is 6 0x1000-byte blocks with 512 cycle

Then, I replicated the prj.conf and the overlay to match the first post on the thread. Flashing it to the board, the shell would not appear and the file system would still be mounted on the internal flash. How can I change it to external flash and verify that it is indeed on external flash? That same post the person said that he could get it working on the secure but not the "ns" version. I can't get it working on either secure or non-secure. 

Here is my current configuration:

Hardware: nrf9160dk v1.1.0

Sample: zephyr/samples/subsys/fs/littlefs

Ncs: v1.7.0

prj.conf

# fs_dirent structures are big.
CONFIG_MAIN_STACK_SIZE=2048

# Let __ASSERT do its job
CONFIG_DEBUG=y

CONFIG_LOG=y

CONFIG_FLASH=y
CONFIG_FLASH_MAP=y
CONFIG_FLASH_PAGE_LAYOUT=y

CONFIG_FILE_SYSTEM=y
CONFIG_FILE_SYSTEM_LITTLEFS=y

# CONFIG_PM_PARTITION_REGION_LITTLEFS_EXTERNAL=y


CONFIG_FLASH=y
CONFIG_LOG=y
#CONFIG_FS_LOG_LEVEL_DBG=y
CONFIG_HEAP_MEM_POOL_SIZE=16384
CONFIG_SHELL=y
CONFIG_SHELL_LOG_LEVEL_INF=y
CONFIG_FILE_SYSTEM=y
CONFIG_FILE_SYSTEM_SHELL=y
CONFIG_FILE_SYSTEM_LITTLEFS=y
CONFIG_FLASH_MAP=y
CONFIG_FLASH_PAGE_LAYOUT=y
CONFIG_SPI=y
CONFIG_SPI_NOR=y
CONFIG_SPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096

app.overlay:

/delete-node/ &storage_partition;

&mx25r64  {
  // spi-max-frequency = <1000000>;
  partitions {
    compatible = "fixed-partitions";
    #address-cells = <1>;
    #size-cells = <1>;

    storage_partition: partition@0 {
      label = "storage";
      reg = <0x00000000 0x00800000>;
    };
  };
};

When I tried it on the non-secure build target, it would fail to compile (can't find mx25r64). So, I modified one of the spi interfaces to get it to work as per this post. It then would "work", but still failed to use the external flash (which is interesting as the same overlay would use the external flash on the NVS sample).

I read something about a partition manager, this post on something very similar, and also configured the board controller.

So, in summary: How do you configure LittleFS to utilize the external flash (preferably for the ns version)? And, how can you verify LittleFS is utilizing the external flash?

Thank you in advance for the help,

Ben

  • Hello Ben,

    I tried to do the same with the littlefs sample using the following device tree overlay:

    /*
     * Copyright (c) 2019 Peter Bigot Consulting, LLC
     *
     * SPDX-License-Identifier: Apache-2.0
     */
    
    /delete-node/ &storage_partition;
    
    /* Configure partition manager to use mx25r64 as the external flash device */
    / {
        chosen {
            nordic,pm-ext-flash = &mx25r64;
        };
    };
    
    &spi3 {
    	cs-gpios = <&arduino_header 16 GPIO_ACTIVE_LOW>, /* D10 */
    		   <&gpio0 25 GPIO_ACTIVE_LOW>;
    	mx25r64: mx25r6435f@1 {
    		compatible = "jedec,spi-nor";
    		status = "disabled";
    		reg = <1>;
    		spi-max-frequency = <8000000>;
    		label = "MX25R64";
    		jedec-id = [c2 28 17];
    		sfdp-bfp = [
    			e5 20 f1 ff  ff ff ff 03  44 eb 08 6b  08 3b 04 bb
    			ee ff ff ff  ff ff 00 ff  ff ff 00 ff  0c 20 0f 52
    			10 d8 00 ff  23 72 f5 00  82 ed 04 cc  44 83 68 44
    			30 b0 30 b0  f7 c4 d5 5c  00 be 29 ff  f0 d0 ff ff
    		];
    		size = <67108864>;
    		has-dpd;
    		t-enter-dpd = <10000>;
    		t-exit-dpd = <35000>;
    	};
    };
    
    
    / {
    	fstab {
    		compatible = "zephyr,fstab";
    		lfs1: lfs1 {
    			compatible = "zephyr,fstab,littlefs";
    			mount-point = "/lfs1";
    			partition = <&lfs1_part>;
    			automount;
    			read-size = <16>;
    			prog-size = <16>;
    			cache-size = <64>;
    			lookahead-size = <32>;
    			block-cycles = <512>;
    		};
    	};
    };
    
    &mx25r64 {
    	partitions {
    		compatible = "fixed-partitions";
    		#address-cells = <1>;
    		#size-cells = <1>;
    
    		lfs1_part: partition@0 {
    			label = "storage";
    			reg = <0x00000000 0x00010000>;
    		};
    	};
    };
    

    But I realized the CONFIG_PM_PARTITION_REGION_LITTLEFS_EXTERNAL symbol didn't get introduced until SDK v2.1.0: https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrf/releases/release-notes-2.1.0.html#scripts.

    Would it be an option to upgrade to a more recent version? If not, I think the solution will be to create a static partition file with your partition in external flash (https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrf/scripts/partition_manager/partition_manager.html#configuring-static-partitions) or cherry-pick the changes from SDK 2.1.0.

    Another post with a similar question:  Using LittleFS with mx25r64 and nRF Connect VS Code  

    Also, for reference, here are instructions on how to add external flash from the latest SDK documentation:

    https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrf/working_with_nrf/nrf91/nrf9160.html#adding-the-configuration-and-devicetree-option 

    Best regards,

    Vidar

    EDIT: I see now that the overlay for the spi3 node should be redundant if you build for revision 0.14.0 of the board (default):  https://github.com/nrfconnect/sdk-zephyr/blob/main/boards/arm/nrf9160dk_nrf9160/nrf9160dk_nrf9160_common_0_14_0.dtsi#L40. Prior versions did not include the flash IC so it was not defined in the device tree either.

  • Hello Vidar, 

    Thank you for the response. I tried your device overlay. At first it didn't work as expected. However, I noticed that it did not define the pins and it marked the mx25r64 as disabled. I made slight modifications and I got it to work.

    Here is the overlay:

    /*
     * Copyright (c) 2019 Peter Bigot Consulting, LLC
     *
     * SPDX-License-Identifier: Apache-2.0
     */
    
     /delete-node/ &storage_partition;
    
     /* Configure partition manager to use mx25r64 as the external flash device */
     / {
    	 chosen {
    		 nordic,pm-ext-flash = &mx25r64;
    	 };
     };
    
     &spi3 {
    	status = "okay";
    	sck-pin = <13>;
    	mosi-pin = <11>;
    	miso-pin = <12>;
    	 cs-gpios = <&arduino_header 16 GPIO_ACTIVE_LOW>, /* D10 */
    			<&gpio0 25 GPIO_ACTIVE_LOW>;
    	 mx25r64: mx25r6435f@1 {
    		 compatible = "jedec,spi-nor";
    		 status = "okay";
    		 reg = <1>;
    		 spi-max-frequency = <8000000>;
    		 label = "MX25R64";
    		 jedec-id = [c2 28 17];
    		 sfdp-bfp = [
    			 e5 20 f1 ff  ff ff ff 03  44 eb 08 6b  08 3b 04 bb
    			 ee ff ff ff  ff ff 00 ff  ff ff 00 ff  0c 20 0f 52
    			 10 d8 00 ff  23 72 f5 00  82 ed 04 cc  44 83 68 44
    			 30 b0 30 b0  f7 c4 d5 5c  00 be 29 ff  f0 d0 ff ff
    		 ];
    		 size = <67108864>;
    		 has-dpd;
    		 t-enter-dpd = <10000>;
    		 t-exit-dpd = <35000>;
    	 };
     };
     
     
     / {
    	 fstab {
    		 compatible = "zephyr,fstab";
    		 lfs1: lfs1 {
    			 compatible = "zephyr,fstab,littlefs";
    			 mount-point = "/lfs1";
    			 partition = <&lfs1_part>;
    			 automount;
    			 read-size = <16>;
    			 prog-size = <16>;
    			 cache-size = <64>;
    			 lookahead-size = <32>;
    			 block-cycles = <512>;
    		 };
    	 };
     };
     
     &mx25r64 {
    	 partitions {
    		 compatible = "fixed-partitions";
    		 #address-cells = <1>;
    		 #size-cells = <1>;
     
    		 lfs1_part: partition@0 {
    			 label = "storage";
    			 reg = <0x00000000 0x00010000>;
    		 };
    	 };
     };

    prj.conf  (changed slightly... added PM_EXTERNAL_FLASH)

    # Optionally force the file system to be recreated
    #CONFIG_APP_WIPE_STORAGE=y
    
    # fs_dirent structures are big.
    CONFIG_MAIN_STACK_SIZE=2048
    
    # Let __ASSERT do its job
    CONFIG_DEBUG=y
    
    CONFIG_LOG=y
    
    CONFIG_FLASH=y
    CONFIG_FLASH_MAP=y
    CONFIG_FLASH_PAGE_LAYOUT=y
    
    CONFIG_FILE_SYSTEM=y
    CONFIG_FILE_SYSTEM_LITTLEFS=y
    
    # CONFIG_PM_PARTITION_REGION_LITTLEFS_EXTERNAL=y
    
    
    CONFIG_FLASH=y
    CONFIG_LOG=y
    #CONFIG_FS_LOG_LEVEL_DBG=y
    CONFIG_HEAP_MEM_POOL_SIZE=16384
    CONFIG_SHELL=y
    CONFIG_SHELL_LOG_LEVEL_INF=y
    CONFIG_FILE_SYSTEM=y
    CONFIG_FILE_SYSTEM_SHELL=y
    CONFIG_FILE_SYSTEM_LITTLEFS=y
    CONFIG_FLASH_MAP=y
    CONFIG_FLASH_PAGE_LAYOUT=y
    CONFIG_SPI=y
    CONFIG_SPI_NOR=y
    CONFIG_SPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096
    
    CONFIG_PM_EXTERNAL_FLASH=y
    CONFIG_PM_EXTERNAL_FLASH_DEV_NAME="MX25R64"

    And this worked for the "_ns" build target which is perfect.

    For the logs, does this verify it is using the external flash? (I do notice the MX25R64 indicated, and the size is about 8MB, so it seems correct.) Is there a way to increase the size (as the chip has 64MB)?

    *** Booting Zephyr OS build v2.6.99-ncs1  ***
    Area 0 at 0x0 on MX25R64 for 8388608 bytes
    /lfs1 automounted
    /lfs1: bsize = 16 ; frsize = 4096 ; blocks = 2048 ; bfree = 2046
    /lfs1/boot_count stat: 0
            fn 'boot_count' siz 4
    /lfs1/boot_count read count 4: 4
    /lfs1/boot_count seek start: 0
    /lfs1/boot_count write new boot count 5: 4
    /lfs1/boot_count close: 0
    /lfs1 opendir: 0
      F 4 boot_count
    End of files
    /lfs1 unmount: 0
    [00:00:00.203,002] <inf> littlefs: littlefs partition at /lfs1
    [00:00:00.203,063] <inf> littlefs: LittleFS version 2.2, disk version 2.0
    [00:00:00.204,986] <inf> littlefs: FS at MX25R64:0x0 is 2048 0x1000-byte blocks with 512 cycle
    [00:00:00.204,986] <inf> littlefs: sizes: rd 16 ; pr 16 ; ca 64 ; la 32
    [00:00:00.208,312] <inf> littlefs: /lfs1 mounted
    [00:00:00.208,312] <inf> littlefs: Automount /lfs1 succeeded
    [00:00:00.256,896] <inf> littlefs: /lfs1 unmounted

    Thanks,

    Ben

  • One interesting observation is that automount or mounting in main does use the external flash. However, mounting via shell via the "fs mount" command uses the internal flash.

  • Hello Ben,

    The external flash region gets added when you have set the 'pm-ext-flash' property, as explained in the External Flash of the partition manager documentation. However, it does not automatically place the littlefs partition within it. We added the CONFIG_PM_PARTITION_REGION_LITTLEFS_EXTERNAL symbol in v2.1.0 to allow the partition to be added automatically.

    For v1.7.1, you need to define the partition yourself. You can do this by creating a file named 'pm_static.yml' that contains the following:

    littlefs_storage:
      region: external_flash
      address: 0x0
      size: 0x10000
    external_flash:
      address: 0x10000
      size: 0x7F0000
      device: MX25R64
      region: external_flash
    

    Then place the file in your project directory so it gets picked up by the build system (Static Configuration).

    Tip: you can use the "Memory report" button in VS code if you want to view the memory layout, or "$ west build -t partition_manager_report" if you are building from the command line.

    Best regards,

    Vidar

  • Hello Vidar, 

    Awesome. That makes sense. Tried the static partition file, and it worked nicely. I also realized I read the datasheet wrong and that the external flash chip has 64Mbit (8MB) verses 64MByte.

    Thank you for your help,

    Ben

Related