Issue Erasing Flash Area on QSPI Flash with LittleFS in Zephyr

Hi, I'm working on a project using Zephyr with LittleFS mounted on a QSPI flash device. However, I'm encountering an issue when trying to erase the flash area. Here are the details:

System Configuration:
MCU: nRF52840 (Seeed studio xiao ble)
Zephyr Version: v3.5.99-ncs1-1 (nRF Connect SDK)
Flash Device: p25q16h (16 MiB QSPI flash)
File System: LittleFS
Device Tree Configuration:

/ {
    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>;
        };
    };
};

&qspi {
    p25q16h: p25q16h@0 {
        partitions {
            compatible = "fixed-partitions";
            #address-cells = <1>;
            #size-cells = <1>;

            lfs1_part: partition@0 {
                label = "storage";
                reg = <0x00000000 0x01000000>;  // 16 MiB partition for LittleFS
            };
        };
    };
};

Problem:


When I try to erase the LittleFS partition, I encounter the following error:

[00:00:00.330,688] <err> qspi_nor: erase error: address or size exceeds expected values. Addr: 0x0 size 16777216
[00:00:00.330,718] <err> main: Erasing flash area ... -22

Here’s the relevant code snippet where the error occurs:

LOG_PRINTK("Area %u at 0x%x on %s for %u bytes\n",
           id, (unsigned int)pfa->fa_off, pfa->fa_dev->name,
           (unsigned int)pfa->fa_size);

if (IS_ENABLED(CONFIG_APP_WIPE_STORAGE)) {
    rc = flash_area_erase(pfa, 0, pfa->fa_size);
    LOG_ERR("Erasing flash area ... %d", rc);
}

Questions:

  1. Is there a specific alignment requirement for the flash_area_erase() function on QSPI flash in Zephyr?
  2. Do I need to adjust any of the LittleFS or partition settings in the device tree to match the QSPI flash memory’s erase block size?
  3. Has anyone encountered a similar issue with QSPI flash erasing in Zephyr, and how did you resolve it?

Any help or suggestions on how to properly erase this flash area would be greatly appreciated!

Thanks in advance for your support!

Parents Reply Children
  • Hi  Thank you for your help. I fixed the size issue but I am still getting the same error. 

    [00:00:00.296,386] <inf> littlefs: littlefs partition at /lfs1
    [00:00:00.296,417] <inf> littlefs: LittleFS version 2.5, disk version 2.0
    [00:00:00.296,508] <inf> littlefs: FS at p25q16h@0:0x0 is 512 0x1000-byte blocks with 512 cycle
    [00:00:00.296,508] <inf> littlefs: sizes: rd 16 ; pr 16 ; ca 64 ; la 32
    [00:00:00.296,997] <inf> littlefs: Automount /lfs1 succeeded
    *** Booting nRF Connect SDK v3.5.99-ncs1-1 ***
    [00:00:00.297,058] <inf> main: Sample program to r/w files on littlefs
    
    Area 0 at 0x0 on p25q16h@0 for 2097152 bytes
    [00:00:00.297,119] <err> qspi_nor: erase error: address or size exceeds expected values.Addr: 0x0 size 2097152
    [00:00:00.297,119] <err> main: Erasing flash area ... -22
    

    This is how I mount the partition:

    #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(lfs1_part),
        .storage_dev= (void*)FLASH_AREA_ID(littlefs_storage);
    	.mnt_point = "/lfs1",
    };
    #endif /* PARTITION_NODE */
    
    	struct fs_mount_t *mountpoint =
    #if DT_NODE_EXISTS(PARTITION_NODE)
    		&FS_FSTAB_ENTRY(PARTITION_NODE)
    #else
    		&lfs_storage_mnt
    #endif
    		;
    
    static int littlefs_mount(struct fs_mount_t *mp)
    {
    	int rc;
    
    	rc = littlefs_flash_erase((uintptr_t)mp->storage_dev);
    	if (rc < 0) {
    		return rc;
    	}
    
    	/* 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)
    	rc = fs_mount(mp);
    	if (rc < 0) {
    		LOG_PRINTK("FAIL: mount id %" PRIuPTR " at %s: %d\n",
    		       (uintptr_t)mp->storage_dev, mp->mnt_point, rc);
    		return rc;
    	}
    	LOG_PRINTK("%s mount: %d\n", mp->mnt_point, rc);
    #else
    	LOG_PRINTK("%s automounted\n", mp->mnt_point);
    #endif
    
    	return 0;
    }
    

    I modified the dts overlay as well since the partition label was the same as the board file definition:

    /{
        chosen{
            nordic,pm-ext-flash=&p25q16h;
        };
    };
    / {
        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>;
            };
        };
    };
    
    &qspi {
        p25q16h: p25q16h@0 {
        partitions {
            compatible = "fixed-partitions";
            #address-cells = <1>;
            #size-cells = <1>;
    
            lfs1_part: partition@0 {
                label = "littlefs_storage";
                reg = <0x00000000 0x00200000>;  // 2 MiB partition for LittleFS
            };
        };
    
            size = <0x00200000>;
      };
    };
    

    These are the partitions from the board file:

    &qspi {
    	status = "okay";
    	pinctrl-0 = <&qspi_default>;
    	pinctrl-1 = <&qspi_sleep>;
    	pinctrl-names = "default", "sleep";
    	p25q16h: p25q16h@0 {
    		compatible = "nordic,qspi-nor";
    		reg = <0>;
    		sck-frequency = <104000000>;
    		quad-enable-requirements = "S2B1v1";
    		jedec-id = [85 60 15];
    		sfdp-bfp = [
    			e5 20 f1 ff  ff ff ff 00  44 eb 08 6b  08 3b 80 bb
    			ee ff ff ff  ff ff 00 ff  ff ff 00 ff  0c 20 0f 52
    			10 d8 08 81
    		];
    		size = <16777216>;
    		has-dpd;
    		t-enter-dpd = <3000>;
    		t-exit-dpd = <8000>;
    	};
    };
    &flash0 {
    	partitions {
    		compatible = "fixed-partitions";
    		#address-cells = <1>;
    		#size-cells = <1>;
    
    		sd_partition: partition@0 {
    			label = "softdevice";
    			reg = <0x00000000 0x00027000>;
    		};
    
    		code_partition: partition@27000 {
    			label = "code_partition";
    			reg = <0x00027000 0x000c5000>;
    		};
    
    		/*
    		 * The flash starting at 0x000ec000 and ending at
    		 * 0x000f3fff is reserved for use by the application.
    		 *
    		 * Storage partition will be used by FCB/LittleFS/NVS
    		 * if enabled.
    		 */
    		storage_partition: partition@ec000 {
    			label = "storage";
    			reg = <0x000ec000 0x00008000>;
    		};
    
    		boot_partition: partition@f4000 {
    			label = "adafruit_boot";
    			reg = <0x000f4000 0x0000c000>;
    		};
    	};
    };
    

  • Hi,

    Please also note that flash devices like p25q16h etc have certain specific erase sizes like 4KB, 32KB or so. You need to make sure that pfa->fa_off (the start address) and pfa->fa_size (the size to erase) are aligned to this block size.

    -Priyanka

Related