LittleFS External Configuration



Hello Support Team,

I hope this message finds you well.

I've been experimenting with the LittleFS sample available at the following link: LittleFS Sample Code. The sample works flawlessly with internal memory. However, after integrating it into my project, I made a few modifications to better suit my needs:

  • Utilized the MCU
  • Implemented external flash
  • Enabled BLE functionality

Despite my efforts, I am encountering issues with incorrect partition information for the LittleFS storage. Here are the details of my current configuration:

I found various article but no solution and also i see wrong partition information 

littlefs_storage:
  address: 0x00700000
  end_address: 0x00800000
  placement:
    before:
      - end
  region: external_flash
  size: 0x00100000

// To get started, press Ctrl+Space (or Option+Esc) to bring up the completion menu and view the available nodes.

// You can also use the buttons in the sidebar to perform actions on nodes.
// Actions currently available include:

// * Enabling / disabling the node
// * Adding the bus to a bus
// * Removing the node
// * Connecting ADC channels

// For more help, browse the DeviceTree documentation at https://docs.zephyrproject.org/latest/guides/dts/index.html
// You can also visit the nRF DeviceTree extension documentation at https://nrfconnect.github.io/vscode-nrf-connect/devicetree/nrfdevicetree.html


/ {
	zephyr,user {
		io-channels = <&adc 0>;
	};
};


&comp {
	compatible = "nordic,nrf-lpcomp";
	status = "okay";
};
&adc {
	#address-cells = <1>;
	#size-cells = <0>;
    status ="okay";

	channel@0 {
		reg = <0>;
		zephyr,gain = "ADC_GAIN_1_6";
		zephyr,reference = "ADC_REF_INTERNAL";
		zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
		zephyr,input-positive = <NRF_SAADC_AIN2>; 
	};
	channel@1 {
		reg = <1>;
		zephyr,gain = "ADC_GAIN_1_6";
		zephyr,reference = "ADC_REF_INTERNAL";
		zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
		zephyr,input-positive = <NRF_SAADC_AIN3>;
	};
     // Channel 2 - Used for manual battery power reading
     channel@2 {
	 	reg = <2>;
	 	zephyr,gain = "ADC_GAIN_1_6";
	 	zephyr,reference = "ADC_REF_INTERNAL";
	 	zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
	 	zephyr,input-positive = <NRF_SAADC_AIN7>;
	 };
    
};

/ {
    aliases {
        sw0 = &button1;
        led0 = &green_led;
        spi-flash0 = &is25lp064a;
        adc0 = &adc;
    };
    
    chosen {
        zephyr,extflash = &is25lp064a;
		nordic,pm-ext-flash = &is25lp064a;
		zephyr,settings-partition = &settings_partition;
    };

    buttons {
        compatible = "gpio-keys";
        button1: button_1 {
            gpios = <&gpio1 1 GPIO_PULL_UP>;
            label = "Push button switch 1";
        };
    };
};


&qspi {
	pinctrl-0 = <&qspi_default>;
	pinctrl-1 = <&qspi_sleep>;
	pinctrl-names = "default", "sleep";
	is25lp064a: is25lp064a@0 {
		compatible = "nordic,qspi-nor";
		reg = <0>;
		//writeoc = "pp4io";
		//readoc = "read4io";
		sck-frequency = <133000000>;
		jedec-id = [9d 60 17];
		size = <8388608>; //8 MB or DT_SIZE_M(8)
        partitions {
            compatible = "fixed-partitions";
            #address-cells = <1>;
            #size-cells = <1>;
		ext_partition: partition@0 {
			label = "image-ext";
			reg = <0x00000000 0x00700000>; //7 MB
		};
		lfs1_partition: partition@700000 {
			label = "lfs1";
			reg = <0x00700000 0x00100000>; // 1 MB
		};
    };

	};
};

&pinctrl {
    qspi_default: qspi_default {
        group1 {
            psels = <NRF_PSEL(QSPI_SCK,1, 4)>,    // SCK
                    <NRF_PSEL(QSPI_CSN,0, 26)>,    // CSN
                    <NRF_PSEL(QSPI_IO0,0, 30)>,    // IO0
                    <NRF_PSEL(QSPI_IO1,0, 29)>,    // IO1
                    <NRF_PSEL(QSPI_IO2,0, 28)>,    // IO2
                    <NRF_PSEL(QSPI_IO3,1, 2)>;    // IO3
        };
    };
    qspi_sleep: qspi_sleep {
        group1 {
            psels = <NRF_PSEL(QSPI_SCK,1, 4)>,    // SCK
                    <NRF_PSEL(QSPI_CSN,0, 26)>,    // CSN
                    <NRF_PSEL(QSPI_IO0,0, 30)>,    // IO0
                    <NRF_PSEL(QSPI_IO1,0, 29)>,    // IO1
                    <NRF_PSEL(QSPI_IO2,0, 28)>,    // IO2
                    <NRF_PSEL(QSPI_IO3,1, 2)>;    // IO3
        };
    };
};

&is25lp064a {
    address-size-32;
};


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


/delete-node/ &storage_partition;

&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.
		 */
		settings_partition: partition@f8000 {
			label = "settings";
			reg = <0x000f8000 0x00008000>; 
		};
	};
};

my code 

#define ARCHIVE_FILE_PATH "/lfs1/archive.dat"
#define PARTITION_NODE DT_NODELABEL(lfs1)

#if DT_NODE_EXISTS(PARTITION_NODE)
FS_FSTAB_DECLARE_ENTRY(PARTITION_NODE);
#else /* PARTITION_NODE */
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",
};
#endif /* PARTITION_NODE */

	struct fs_mount_t *mp =
#if DT_NODE_EXISTS(PARTITION_NODE)
		&FS_FSTAB_ENTRY(PARTITION_NODE)
#else
		&lfs_storage_mnt
#endif
		;

int data_archive_init(void) {
    

    	/* Do not mount if auto-mount has been enabled */
#if !DT_NODE_EXISTS(PARTITION_NODE) ||						\
	!(FSTAB_ENTRY_DT_MOUNT_FLAGS(PARTITION_NODE) & FS_MOUNT_FLAG_AUTOMOUNT)
	int rc = fs_mount(mp);
	if (rc < 0) {
		LOG_ERR("FAIL: mount id %" PRIuPTR " at %s: %d\n",
		       (uintptr_t)mp->storage_dev, mp->mnt_point, rc);
		return rc;
	}
	LOG_INF("%s mount: %d\n", mp->mnt_point, rc);
#else
	LOG_INF("%s automounted\n", mp->mnt_point);
#endif


    LOG_INF("Filesystem mounted successfully");
    return 0;
}

output

Issues Encountered:

  1. Enabling Bluetooth in the LittleFS sample app causes the LittleFS to NOT use external flash.*
  2. Problems with binding external flash (external flash + SPI + OTA). **

I have scoured through various articles, the Zephyr documentation, and forums, including Discord, but have yet to find a viable solution.

Could you please provide guidance or suggestions on resolving these issues?

Enabling Bluetooth to the Littlefs sample app will make the littlefs **NOT** use external flash. 

** External Flash get binding is Issue. (external flash + spi + OTA)  

  • Hey QBSho,

    I recommend checking out this video for configuring littlefs for use on an external flash. Configuring littlefs is the toughest part, and the video goes over it very well. 

  • Thank you luckyyorange, 

    I already know this guy and the video. 


    #Partion manager
    CONFIG_PM_EXTERNAL_FLASH_MCUBOOT_SECONDARY=n
    seems not working, because of 

    external_flash:
    address: 0x0
    end_address: 0x00800000
    region: external_flash
    size: 0x8388608
    littlefs_storage:
    address: 0x0
    device: is25lp064a
    region: external_flash
    size: 0x00100000
    Anything to force this?
    the build log looks good. 
    Also my app doesn't start correctly - non output on RTT.  Also without automount!
    BR S
  • I got a little further, 

    a restart of the system and before flash manually trigger the build brings now the right paritions. 
    It uses now 1MB as configured but the mounting point is not showing up 

    Where i could debug the mounting point?

    FS_LITTLEFS_DECLARE_DEFAULT_CONFIG(storage);
    static struct fs_mount_t lfs_storage_mnt = {
    	.type = FS_LITTLEFS,
    	.fs_data = &storage,
    	.storage_dev = (void *)FLASH_AREA_ID(littlefs_storage),
    	.mnt_point = "/lfs1",
    };
    
    struct fs_mount_t *mp = &lfs_storage_mnt;
    
    
    int data_archive_init(void) {
    
    	unsigned int id = (uintptr_t)mp->storage_dev;
    	struct fs_statvfs sbuf;
    	const struct flash_area *pfa;
    	int rc;
    
        rc = flash_area_open(id, &pfa);
    	if (rc < 0)
    	{
    		LOG_ERR("FAIL: unable to find flash area %u: %d\n",
    			   id, rc);
    		return;
    	}
    
    	LOG_INF("Area %u at 0x%x for %u bytes\n",
    		   id, (unsigned int)pfa->fa_off, (unsigned int)pfa->fa_size);
    
    	/* Optional wipe flash contents */
    	if (IS_ENABLED(CONFIG_APP_WIPE_STORAGE))
    	{
    		LOG_INF("Erasing flash area ... ");
    		rc = flash_area_erase(pfa, 0, pfa->fa_size);
    		LOG_INF("%d\n", rc);
    	}
    
    	flash_area_close(pfa);
    
    	rc = fs_mount(mp);
    	if (rc < 0)
    	{
    		LOG_ERR("FAIL: mount id %u at %s: %d\n",
    			   (unsigned int)mp->storage_dev, mp->mnt_point,
    			   rc);
    		return;
    	}
    	LOG_INF("%s mount: %d\n", mp->mnt_point, rc);
    
    	rc = fs_statvfs(mp->mnt_point, &sbuf);
    	if (rc < 0)
    	{
    		LOG_ERR("FAIL: statvfs: %d\n", rc);
    
    	}
    
    	LOG_INF("%s: bsize = %lu ; frsize = %lu ;"
    		   " blocks = %lu ; bfree = %lu\n",
    		   mp->mnt_point,
    		   sbuf.f_bsize, sbuf.f_frsize,
    		   sbuf.f_blocks, sbuf.f_bfree);
        
    
        return 0;
    }

    00:00:00.559,448] <inf> littlefs: LittleFS version 2.5, disk version 2.0
    [00:00:00.559,478] <dbg> littlefs: littlefs_flash_init: FS area 9 at 0x700000 for 1048576 bytes
    [00:00:00.559,600] <err> fs: fs mount error (-22)
    [00:00:00.559,631] <err> data_archive: FAIL: mount id 9 at /lfs1: -22
    
    [00:00:00.559,661] <err> fs: mount point not found!!
    [00:00:00.559,692] <err> data_archive: FAIL: open /lfs/archive.dat: -2

    How to fix the invalid -22 mountpoint!

  • Hi,

    I have tried to see if anyone else have reported the same error I have also tried to dig a bit into the code, but I can't really find what may be failing here. It could be some configuration problem so maybe going back to the simple littlf sample.

    Kenneth

  • The simple littlefs works, but as i going to external and do not use the standard the problem pops up.

Related