Unable to mount fat FS using external partition manager using pm_static.yml file

Hi,

I am trying to mount Fat FS using pm_static.yml instead of devicetree overlay fixed partition. I can generate a memory report, but when I try to mount file system I get the following mount errors. 

Errors:

winbondw25q02@0 SPI flash testing
==========================

Perform test on single sector
Test 1: Flash erase
*** Booting nRF Connect SDK v2.7.0-5cb85570ca43 ***
*** Using Zephyr OS v3.6.99-100befc70c74 ***
[00:00:00.257,232] <err> usb_msc: Storage init ERROR !!!! - Aborting USB init
Flash erase succeeded!

Test 2: Flash write
Attempting to write zu bytes
Data read matches data written. Good!!
[00:00:00.380,065] <err> fs: fs mount error (-5)
Error mounting FATFS: -5. Formatting now...
[00:00:00.380,126] <err> fs: fs not mounted (mp == 0x200000d0)
Error unmounting FATFS: -22
Error formatting FATFS: 3
[00:00:00.380,218] <err> fs: fs mount error (-5)
Error mounting FATFS after formatting: -5
[00:00:00.380,249] <err> fs: mount point not found!!
[00:00:00.380,279] <err> flash_test: Failed to open file /NAND:/test.txt (err: -2)
[00:00:00.380,279] <err> fs: mount point not found!!
[00:00:00.380,310] <err> flash_test: Failed to open file /NAND:/test.txt (err: -2)
[00:00:00.380,401] <dbg> flash_test: enable_usb_device: USB mass storage enabled
[00:00:00.380,432] <inf> flash_test: USB mass storage enabled.

Prj.Conf

# Copyright (c) 2018 Nordic Semiconductor
#
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
#

# Enable the UART driver
CONFIG_UART_ASYNC_API=y
CONFIG_NRFX_UARTE0=y

# print
CONFIG_NEWLIB_LIBC=y
CONFIG_NEWLIB_LIBC_FLOAT_PRINTF=y

# I2C
CONFIG_I2C=y
CONFIG_I2C_NRFX=y
CONFIG_NRFX_TWIM1=y
CONFIG_NFCT_PINS_AS_GPIOS=y

#SPI
CONFIG_SPI=y
CONFIG_SPI_ASYNC=y
CONFIG_SPI_SLAVE=y

CONFIG_HEAP_MEM_POOL_SIZE=2048
# Enable DK LED and Buttons library
CONFIG_DK_LIBRARY=y
CONFIG_STDOUT_CONSOLE=y

#USB related configs
CONFIG_USB_DEVICE_STACK=y
CONFIG_USB_DEVICE_PRODUCT="Zephyr MSC sample"
CONFIG_USB_DEVICE_PID=0x0008
CONFIG_LOG=y
CONFIG_USB_DRIVER_LOG_LEVEL_ERR=y
CONFIG_USB_MASS_STORAGE=y
CONFIG_USB_DEVICE_LOG_LEVEL_ERR=y
CONFIG_USB_MASS_STORAGE_LOG_LEVEL_ERR=y
CONFIG_USB_DEVICE_INITIALIZE_AT_BOOT=n
CONFIG_APP_MSC_STORAGE_FLASH_FATFS=y
CONFIG_MAIN_STACK_SIZE=10240
CONFIG_FILE_SYSTEM=y
CONFIG_FILE_SYSTEM_LITTLEFS=n

CONFIG_SPI_NOR=y
CONFIG_FLASH_JESD216_API=y
CONFIG_SPI_NRFX=y
CONFIG_SPI_NOR_IDLE_IN_DPD=y

#FLASH Config ##############################################
CONFIG_DISK_ACCESS=y
CONFIG_FAT_FILESYSTEM_ELM=y
CONFIG_FS_FATFS_LFN=y

CONFIG_FLASH=y
CONFIG_FLASH_MAP=y
CONFIG_FLASH_LOG_LEVEL_ERR=y
CONFIG_MPU_ALLOW_FLASH_WRITE=y
CONFIG_DISK_DRIVER_FLASH=y
CONFIG_PM_OVERRIDE_EXTERNAL_DRIVER_CHECK=y

overlay file:

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

/* Disable conflicting buttons and UART */
&button2 {
	status = "disabled";
};

&button3 {
	status = "disabled";
};

&gpio_fwd {
	status = "disabled";
};

&pinctrl {
		spi_master_default: spi_master_default {
				group1 {
						psels = <NRF_PSEL(SPIM_SCK, 0, 2)>,
										<NRF_PSEL(SPIM_MOSI, 0, 9)>,
										<NRF_PSEL(SPIM_MISO, 0, 3)>;
				};
		};

		spi_master_sleep: spi_master_sleep {
				group1 {
						psels = <NRF_PSEL(SPIM_SCK, 0, 2)>,
										<NRF_PSEL(SPIM_MOSI, 0, 9)>,
										<NRF_PSEL(SPIM_MISO, 0, 3)>;
						low-power-enable;
				};
		};
};

&spi4 {
		compatible = "nordic,nrf-spim";
		pinctrl-0 = <&spi_master_default>;
		pinctrl-1 = <&spi_master_sleep>;
		pinctrl-names = "default", "sleep";
		cs-gpios = <&gpio0 11 GPIO_ACTIVE_LOW>;	
		status = "okay";
		winbond:winbondw25q02@0 {
			compatible = "jedec,spi-nor";
			reg = <0>;
			spi-max-frequency = <32000000>;
			jedec-id = [ ef 70 22 ];
			size = <268435456>;
			has-dpd;
		};
};

pm_static.yml and memory report

app:
  address: 0x00010200
  end_address: 0x00E4000
  region: flash_primary
  size: 0x00D3E00

external_flash:
  address: 0x00000000
  device: DT_CHOSEN(nordic_pm_ext_flash)
  end_address: 0x10000000  # 256MB
  region: external_flash
  size: 0x10000000

mcuboot:
  address: 0x00000000
  end_address: 0x00010000
  region: flash_primary
  size: 0x00010000

mcuboot_pad:
  address: 0x00010000
  end_address: 0x00010200
  region: flash_primary
  size: 0x00000200

mcuboot_primary:
  address: 0x00010000
  end_address: 0x00E4000
  orig_span: &id001
    - mcuboot_pad
    - app
  region: flash_primary
  size: 0x00D4000
  span: *id001

mcuboot_secondary:
  address: 0x00000000
  device: DT_CHOSEN(nordic_pm_ext_flash)
  end_address: 0x00D4000
  region: external_flash
  size: 0x00D4000

mcuboot_secondary_1:
  address: 0x00D4000
  device: DT_CHOSEN(nordic_pm_ext_flash)
  end_address: 0x0114000
  region: external_flash
  size: 0x0040000

EMPTY_1:
  address: 0x0114000
  device: DT_CHOSEN(nordic_pm_ext_flash)
  end_address: 0x0120000
  region: external_flash
  size: 0x000C000

mcuboot_primary_2:
  address: 0x0120000
  device: DT_CHOSEN(nordic_pm_ext_flash)
  end_address: 0x0160000
  region: external_flash
  size: 0x0040000

mcuboot_secondary_2:
  address: 0x0160000
  device: DT_CHOSEN(nordic_pm_ext_flash)
  end_address: 0x01A0000
  region: external_flash
  size: 0x0040000

storage_partition:
  address: 0x01A0000  # Start of FATFS storage partition after mcuboot_secondary_2
  device: DT_CHOSEN(nordic_pm_ext_flash)
  end_address: 0x10000000  # End of storage partition (remaining memory)
  region: external_flash
  size: 0x0FE50000  # Remaining memory for storage (260416KB or approx 254MB)
  type: storage

msc_disk0:
  address: 0x01A0000  # Place MSC Disk inside storage_partition
  device: DT_CHOSEN(nordic_pm_ext_flash)
  end_address: 0x01B0000  # 0x01A0000 + 0x10000 (64KB for disk with cache)
  region: storage_partition  
  type: cache
  cache_size: 0x10000  # 64KB cache size
  disk_name: "NAND"
 external_flash (0x10000000 - 262144kB):
+----------------------------------------------------+
| 0x0: external_flash (0x10000000 - 262144kB)        |
| 0x0: mcuboot_secondary (0xd4000 - 848kB)           |
| 0xd4000: mcuboot_secondary_1 (0x40000 - 256kB)     |
| 0x114000: EMPTY_1 (0xc000 - 48kB)                  |
| 0x120000: mcuboot_primary_2 (0x40000 - 256kB)      |
| 0x160000: mcuboot_secondary_2 (0x40000 - 256kB)    |
| 0x1a0000: storage_partition (0xfe50000 - 260416kB) |
+----------------------------------------------------+

  flash_primary (0x100000 - 1024kB):
+----------------------------------------------+
| 0x0: mcuboot (0x10000 - 64kB)                |
+---0x10000: mcuboot_primary (0xd4000 - 848kB)-+
| 0x10000: mcuboot_pad (0x200 - 512B)          |
| 0x10200: app (0xefe00 - 959kB)               |
+----------------------------------------------+

  otp (0x2fc - 764B):
+------------------------------+
| 0xff8100: otp (0x2fc - 764B) |
+------------------------------+

  sram_primary (0x80000 - 512kB):
+--------------------------------------------+
| 0x20000000: sram_primary (0x80000 - 512kB) |
+--------------------------------------------+

main.c

#include <sample_usbd.h>
#include <zephyr/kernel.h>
#include <zephyr/drivers/flash.h>
#include <zephyr/device.h>
#include <zephyr/devicetree.h>
#include <stdio.h>
#include <string.h>
#include <zephyr/fs/fs.h>
#include <zephyr/storage/disk_access.h>
#include <zephyr/logging/log.h>
#include <ff.h>  // FATFS definition
#include <zephyr/usb/usb_device.h>
#include <zephyr/usb/usbd.h>
#include <zephyr/usb/class/usbd_msc.h>

#define STORAGE_PARTITION		storage_partition
#define STORAGE_PARTITION_ID		DEVICE_DT_GET(DT_CHOSEN_nordic_pm_ext_flash)

LOG_MODULE_REGISTER(flash_test, LOG_LEVEL_DBG);

#if defined(CONFIG_BOARD_ADAFRUIT_FEATHER_STM32F405)
#define SPI_FLASH_TEST_REGION_OFFSET 0xf000
#else
#define SPI_FLASH_TEST_REGION_OFFSET 0xff000
#endif

#define SPI_FLASH_SECTOR_SIZE 4096
#define FATFS_MOUNT_POINT "/NAND:"
static FATFS fat_fs;

static struct fs_mount_t fatfs_mount = {
    .type = FS_FATFS,
    .fs_data = &fat_fs,
    .mnt_point = FATFS_MOUNT_POINT,
};

// Define a LUN for USB MSC (similar to your original code)
USBD_DEFINE_MSC_LUN(NAND, "Zephyr", "FlashDisk", "0.00");

// Declare the "erased" array
const uint8_t erased[] = { 0xff, 0xff, 0xff, 0xff };

// Function to enable USB device for mass storage
static int enable_usb_device(void)
{
    int err = usb_enable(NULL);  // Use standard Zephyr USB enable function
    if (err != 0) {
        LOG_ERR("Failed to enable USB device support: %d", err);
        return err;
    }
    LOG_DBG("USB mass storage enabled");
    return 0;
}

void format_fatfs(void)
{
    struct fs_mount_t *mp = &fatfs_mount;
    int res = fs_unmount(mp);  // Unmount before formatting
    if (res != 0) {
        printk("Error unmounting FATFS: %d\n", res);
    }

    MKFS_PARM fs_options = {
        .fmt = FM_FAT,  // FAT format
        .n_fat = 1,     // Number of FATs (1 or 2)
        .align = 0,     // Alignment (0 for default)
        .n_root = 0,    // Number of root directory entries (0 for default)
        .au_size = 0    // Allocation unit size (0 for default)
    };

    res = f_mkfs("", &fs_options, NULL, 0);  // Format the filesystem
    if (res == FR_OK) {
        printk("FATFS format successful.\n");
    } else {
        printk("Error formatting FATFS: %d\n", res);
    }
}

void mount_fatfs(void)
{
    int res = fs_mount(&fatfs_mount);
    if (res == 0) {
        printk("FATFS mounted successfully.\n");
    } else {
        printk("Error mounting FATFS: %d. Formatting now...\n", res);
        format_fatfs();  // Format the flash if mounting fails
        res = fs_mount(&fatfs_mount);  // Try to mount again after formatting
        if (res == 0) {
            printk("FATFS mounted successfully after formatting.\n");
        } else {
            printk("Error mounting FATFS after formatting: %d\n", res);
        }
    }
}

void create_write_file(const char *file_path)
{
    struct fs_file_t file;
    int res;

    fs_file_t_init(&file);
    res = fs_open(&file, file_path, FS_O_CREATE | FS_O_RDWR);
    if (res < 0) {
        LOG_ERR("Failed to open file %s (err: %d)", file_path, res);
        return;
    }

    const char *sample_data = "Hello FATFS on SPI Flash!";
    res = fs_write(&file, sample_data, strlen(sample_data));
    if (res < 0) {
        LOG_ERR("Failed to write to file %s (err: %d)", file_path, res);
        fs_close(&file);
        return;
    }

    fs_close(&file);
    printk("File write successful!\n");
}

void read_file(const char *file_path)
{
    struct fs_file_t file;
    int res;
    char buffer[64];

    fs_file_t_init(&file);
    res = fs_open(&file, file_path, FS_O_READ);
    if (res < 0) {
        LOG_ERR("Failed to open file %s (err: %d)", file_path, res);
        return;
    }

    printk("Reading file content:\n");
    while ((res = fs_read(&file, buffer, sizeof(buffer) - 1)) > 0) {
        buffer[res] = '\0';  // Null-terminate the read data
        printk("%s", buffer);  // Print to console
    }

    fs_close(&file);
}

void single_sector_test(const struct device *flash_dev)
{
    const uint8_t expected[] = {0x55, 0xaa, 0x66, 0x99};
    const size_t len = sizeof(expected);
    uint8_t buf[sizeof(expected)];
    int rc;

    printf("\nPerform test on single sector\n");
    printf("Test 1: Flash erase\n");

    rc = flash_erase(flash_dev, SPI_FLASH_TEST_REGION_OFFSET, SPI_FLASH_SECTOR_SIZE);
    if (rc != 0) {
        printf("Flash erase failed! %d\n", rc);
    } else {
        memset(buf, 0, len);
        rc = flash_read(flash_dev, SPI_FLASH_TEST_REGION_OFFSET, buf, len);
        if (rc != 0) {
            printf("Flash read failed! %d\n", rc);
            return;
        }
        if (memcmp(erased, buf, len) != 0) {
            printf("Flash erase failed at offset 0x%x got 0x%x\n",
                SPI_FLASH_TEST_REGION_OFFSET, *(uint32_t *)buf);
            return;
        }
        printf("Flash erase succeeded!\n");
    }

    printf("\nTest 2: Flash write\n");

    printf("Attempting to write %zu bytes\n", len);
    rc = flash_write(flash_dev, SPI_FLASH_TEST_REGION_OFFSET, expected, len);
    if (rc != 0) {
        printf("Flash write failed! %d\n", rc);
        return;
    }

    memset(buf, 0, len);
    rc = flash_read(flash_dev, SPI_FLASH_TEST_REGION_OFFSET, buf, len);
    if (rc != 0) {
        printf("Flash read failed! %d\n", rc);
        return;
    }

    if (memcmp(expected, buf, len) == 0) {
        printf("Data read matches data written. Good!!\n");
    } else {
        printf("Data read does not match data written!!\n");
    }
}

void winbond_begin(void)
{
    const struct device *flash_dev = DEVICE_DT_GET(DT_CHOSEN(nordic_pm_ext_flash));

    if (!device_is_ready(flash_dev)) {
        printk("%s: device not ready.\n", flash_dev->name);
        return;
    }

    printf("\n%s SPI flash testing\n", flash_dev->name);
    printf("==========================\n");

    // Perform a sector test to ensure flash is working
    single_sector_test(flash_dev);

    // Mount the FATFS file system or format if necessary
    mount_fatfs();

    // Perform file operations (create and read a file)
    const char *file_path = FATFS_MOUNT_POINT "/test.txt";
    create_write_file(file_path);
    read_file(file_path);

    // Enable USB for mass storage
    int usb_err = enable_usb_device();
    if (usb_err == 0) {
        LOG_INF("USB mass storage enabled.");
    } else {
        LOG_ERR("Failed to enable USB mass storage.");
    }
}

regards,

Barsha

Related