Example of using external flash that is on nRF5340dk ?

Im having trouble setting up and using flash on nRF5340dk. 

Is there any example on how to use LittleFS on external flash that is on the dev kit?

Parents
  • my code for testing the flash storage is:

    /* Matches LFS_NAME_MAX */
    #define MAX_PATH_LEN 255

    #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 *)FLASH_AREA_ID(storage),
        .mnt_point = "/lfs",
    };
    #endif /* PARTITION_NODE */

    void testLittleFS(void)
    {
      struct fs_mount_t *mp =
    #if DT_NODE_EXISTS(PARTITION_NODE)
          &FS_FSTAB_ENTRY(PARTITION_NODE)
    #else
          &lfs_storage_mnt
    #endif
          ;
      unsigned int id = (uintptr_t)mp->storage_dev;
      char fname[MAX_PATH_LEN];
      const struct flash_area *pfa;
      int rc;

      snprintf(fname, sizeof(fname), "%s/boot_count", mp->mnt_point);

      rc = open_flash_area(id, &pfa);
      if (rc < 0)
      {
        return;
      }

      if (IS_ENABLED(CONFIG_APP_WIPE_STORAGE))
      {
        rc = erase_flash_area(pfa);
      }

      flash_area_close(pfa);

    #if !DT_NODE_EXISTS(PARTITION_NODE) || (FSTAB_ENTRY_DT_MOUNT_FLAGS(PARTITION_NODE) & !FS_MOUNT_FLAG_AUTOMOUNT)
      rc = mount_fs(mp);
      if (rc < 0)
      {
        return;
      }
    #endif

      reformat_and_mount_lfs(mp);

      struct fs_statvfs sbuf;
      rc = get_fs_stats(mp->mnt_point, &sbuf);

      rc = read_update_write_boot_count(mp, fname);

      rc = list_directory_contents(mp);

      rc = unmount_fs(mp);
    }

    int open_flash_area(unsigned int id, const struct flash_area **pfa)
    {
      int rc = flash_area_open(id, pfa);
      if (rc < 0)
      {
        printk("FAIL: unable to find flash area %u: %d\n", id, rc);
      }
      else
      {
        printk("Area %u at 0x%x on %u for %u bytes\n", id, (unsigned int)(*pfa)->fa_off, (*pfa)->fa_id, (unsigned int)(*pfa)->fa_size);
      }
      return rc;
    }

    int erase_flash_area(const struct flash_area *pfa)
    {
      printk("Erasing flash area ... ");
      int rc = flash_area_erase(pfa, 0, pfa->fa_size);
      printk("%d\n", rc);
      return rc;
    }

    int mount_fs(struct fs_mount_t *mp)
    {
      int rc = fs_mount(mp);
      if (rc < 0)
      {
        printk("FAIL: mount id %" PRIuPTR " at %s: %d\n", (uintptr_t)mp->storage_dev, mp->mnt_point, rc);
      }
      else
      {
        printk("%s mount: %d\n", mp->mnt_point, rc);
      }
      return rc;
    }

    int get_fs_stats(const char *mnt_point, struct fs_statvfs *sbuf)
    {
      int rc = fs_statvfs(mnt_point, sbuf);
      if (rc < 0)
      {
        printk("FAIL: statvfs: %d\n", rc);
      }
      else
      {
        printk("LittleFS statistics:\n");
        printk(" - Total space: %lu bytes\n", (unsigned long)sbuf->f_blocks * sbuf->f_frsize);
        printk(" - Free space: %lu bytes\n", (unsigned long)sbuf->f_bfree * sbuf->f_frsize);
        printk(" - Block size: %lu bytes\n", (unsigned long)sbuf->f_frsize);
      }
      return rc;
    }

    int read_update_write_boot_count(struct fs_mount_t *mp, const char *fname)
    {
      struct fs_dirent dirent;
      int rc = fs_stat(fname, &dirent);
      printk("%s stat: %d\n", fname, rc);
      if (rc >= 0)
      {
        printk("\tfn '%s' size %zu\n", dirent.name, dirent.size);
      }

      struct fs_file_t file;
      fs_file_t_init(&file);

      rc = fs_open(&file, fname, FS_O_CREATE | FS_O_RDWR);
      if (rc < 0)
      {
        printk("FAIL: open %s: %d\n", fname, rc);
        return rc;
      }

      uint32_t boot_count = 0;
      rc = fs_read(&file, &boot_count, sizeof(boot_count));
      printk("%s read count %u: %d\n", fname, boot_count, rc);
      rc = fs_seek(&file, 0, FS_SEEK_SET);
      printk("%s seek start: %d\n", fname, rc);

      boot_count += 1;
      rc = fs_write(&file, &boot_count, sizeof(boot_count));
      printk("%s write new boot count %u: %d\n", fname, boot_count, rc);

      rc = fs_close(&file);
      printk("%s close: %d\n", fname, rc);

      return rc;
    }

    int list_directory_contents(struct fs_mount_t *mp)
    {
      struct fs_dir_t dir;
      fs_dir_t_init(&dir);

      int rc = fs_opendir(&dir, mp->mnt_point);
      printk("%s opendir: %d\n", mp->mnt_point, rc);

      while (rc >= 0)
      {
        struct fs_dirent ent = {0};

        rc = fs_readdir(&dir, &ent);
        if (rc < 0)
        {
          break;
        }
        if (ent.name[0] == 0)
        {
          printk("End of files\n");
          break;
        }
        printk("  %c %zu %s\n",
               (ent.type == FS_DIR_ENTRY_FILE) ? 'F' : 'D',
               ent.size,
               ent.name);
      }

      (void)fs_closedir(&dir);

      return rc;
    }

    int unmount_fs(struct fs_mount_t *mp)
    {
      int rc = fs_unmount(mp);
      printk("%s unmount: %d\n", mp->mnt_point, rc);
      return rc;
    }

    static int write_test_file(const char *filename)
    {
      struct fs_file_t file;
      int res = fs_open(&file, filename, FS_O_CREATE | FS_O_WRITE);
      if (res < 0)
      {
        printk("Failed to open file for writing: %d\n", res);
        return res;
      }
    #define FILE_SIZE 512
      uint8_t buffer[512];
      size_t remaining = FILE_SIZE;
      while (remaining > 0)
      {
        size_t to_write = MIN(remaining, sizeof(buffer));
        ssize_t written = fs_write(&file, buffer, to_write);
        if (written < 0)
        {
          printk("Failed to write to file: %d\n", (int)written);
          fs_close(&file);
          return (int)written;
        }
        remaining -= written;
      }

      fs_close(&file);
      return 0;
    }

    void erase_partition(const struct flash_area *fa)
    {
      flash_area_erase(fa, fa->fa_off, fa->fa_size);
    }

    int reformat_littlefs(struct fs_mount_t *mp)
    {
      printk("REFORMATING");
      struct fs_littlefs *fs = mp->fs_data;
      const struct lfs_config *lfs_cfg = &fs->cfg; // Access the 'cfg' member directly
      int rc = lfs_format(&fs->lfs, lfs_cfg);
      return rc;
    }

    void reformat_and_mount_lfs(struct fs_mount_t *mp)
    {
      // Unmount the filesystem
      fs_unmount(mp);

      // Erase the partition
      const struct flash_area *fa;
      flash_area_open(FLASH_AREA_ID(storage), &fa);
      erase_partition(fa);
      flash_area_close(fa);

      // Reformat the filesystem using the updated configuration
      reformat_littlefs(mp);

      // Remount the filesystem
      fs_mount(mp);
    }
    with overlay:
    /delete-node/ &storage_partition;

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

    &mx25r64 {
        partitions {
            compatible = "fixed-partitions";
            #address-cells = <1>;
            #size-cells = <1>;

            lfs1_part: partition@0 {
                label = "storage";
                reg = <0x00000000 0x00800000>;
            };
        };
    };
    Area 7 at 0xf8000 on 7 for 24576 bytes
    [00:00:00.451,812] [0m<inf> littlefs: /lfs1 unmounted[0m
    REFORMATING[00:00:00.630,737] [0m<inf> littlefs: LittleFS version 2.5, disk version 2.0[0m
    [00:00:00.630,767] [0m<inf> littlefs: FS at flash-controller@39000:0xf8000 is 6 0x1000-byte blocks with 512 cycle[0m
    [00:00:00.630,767] [0m<inf> littlefs: sizes: rd 256 ; pr 256 ; ca 256 ; la 16[0m
    [00:00:00.631,134] [0m<inf> littlefs: /lfs1 mounted[0m
    LittleFS statistics:
    - Total space: 24576 bytes
    - Free space: 16384 bytes
    - Block size: 4096 bytes
    but it should be 8mb ??
Reply
  • my code for testing the flash storage is:

    /* Matches LFS_NAME_MAX */
    #define MAX_PATH_LEN 255

    #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 *)FLASH_AREA_ID(storage),
        .mnt_point = "/lfs",
    };
    #endif /* PARTITION_NODE */

    void testLittleFS(void)
    {
      struct fs_mount_t *mp =
    #if DT_NODE_EXISTS(PARTITION_NODE)
          &FS_FSTAB_ENTRY(PARTITION_NODE)
    #else
          &lfs_storage_mnt
    #endif
          ;
      unsigned int id = (uintptr_t)mp->storage_dev;
      char fname[MAX_PATH_LEN];
      const struct flash_area *pfa;
      int rc;

      snprintf(fname, sizeof(fname), "%s/boot_count", mp->mnt_point);

      rc = open_flash_area(id, &pfa);
      if (rc < 0)
      {
        return;
      }

      if (IS_ENABLED(CONFIG_APP_WIPE_STORAGE))
      {
        rc = erase_flash_area(pfa);
      }

      flash_area_close(pfa);

    #if !DT_NODE_EXISTS(PARTITION_NODE) || (FSTAB_ENTRY_DT_MOUNT_FLAGS(PARTITION_NODE) & !FS_MOUNT_FLAG_AUTOMOUNT)
      rc = mount_fs(mp);
      if (rc < 0)
      {
        return;
      }
    #endif

      reformat_and_mount_lfs(mp);

      struct fs_statvfs sbuf;
      rc = get_fs_stats(mp->mnt_point, &sbuf);

      rc = read_update_write_boot_count(mp, fname);

      rc = list_directory_contents(mp);

      rc = unmount_fs(mp);
    }

    int open_flash_area(unsigned int id, const struct flash_area **pfa)
    {
      int rc = flash_area_open(id, pfa);
      if (rc < 0)
      {
        printk("FAIL: unable to find flash area %u: %d\n", id, rc);
      }
      else
      {
        printk("Area %u at 0x%x on %u for %u bytes\n", id, (unsigned int)(*pfa)->fa_off, (*pfa)->fa_id, (unsigned int)(*pfa)->fa_size);
      }
      return rc;
    }

    int erase_flash_area(const struct flash_area *pfa)
    {
      printk("Erasing flash area ... ");
      int rc = flash_area_erase(pfa, 0, pfa->fa_size);
      printk("%d\n", rc);
      return rc;
    }

    int mount_fs(struct fs_mount_t *mp)
    {
      int rc = fs_mount(mp);
      if (rc < 0)
      {
        printk("FAIL: mount id %" PRIuPTR " at %s: %d\n", (uintptr_t)mp->storage_dev, mp->mnt_point, rc);
      }
      else
      {
        printk("%s mount: %d\n", mp->mnt_point, rc);
      }
      return rc;
    }

    int get_fs_stats(const char *mnt_point, struct fs_statvfs *sbuf)
    {
      int rc = fs_statvfs(mnt_point, sbuf);
      if (rc < 0)
      {
        printk("FAIL: statvfs: %d\n", rc);
      }
      else
      {
        printk("LittleFS statistics:\n");
        printk(" - Total space: %lu bytes\n", (unsigned long)sbuf->f_blocks * sbuf->f_frsize);
        printk(" - Free space: %lu bytes\n", (unsigned long)sbuf->f_bfree * sbuf->f_frsize);
        printk(" - Block size: %lu bytes\n", (unsigned long)sbuf->f_frsize);
      }
      return rc;
    }

    int read_update_write_boot_count(struct fs_mount_t *mp, const char *fname)
    {
      struct fs_dirent dirent;
      int rc = fs_stat(fname, &dirent);
      printk("%s stat: %d\n", fname, rc);
      if (rc >= 0)
      {
        printk("\tfn '%s' size %zu\n", dirent.name, dirent.size);
      }

      struct fs_file_t file;
      fs_file_t_init(&file);

      rc = fs_open(&file, fname, FS_O_CREATE | FS_O_RDWR);
      if (rc < 0)
      {
        printk("FAIL: open %s: %d\n", fname, rc);
        return rc;
      }

      uint32_t boot_count = 0;
      rc = fs_read(&file, &boot_count, sizeof(boot_count));
      printk("%s read count %u: %d\n", fname, boot_count, rc);
      rc = fs_seek(&file, 0, FS_SEEK_SET);
      printk("%s seek start: %d\n", fname, rc);

      boot_count += 1;
      rc = fs_write(&file, &boot_count, sizeof(boot_count));
      printk("%s write new boot count %u: %d\n", fname, boot_count, rc);

      rc = fs_close(&file);
      printk("%s close: %d\n", fname, rc);

      return rc;
    }

    int list_directory_contents(struct fs_mount_t *mp)
    {
      struct fs_dir_t dir;
      fs_dir_t_init(&dir);

      int rc = fs_opendir(&dir, mp->mnt_point);
      printk("%s opendir: %d\n", mp->mnt_point, rc);

      while (rc >= 0)
      {
        struct fs_dirent ent = {0};

        rc = fs_readdir(&dir, &ent);
        if (rc < 0)
        {
          break;
        }
        if (ent.name[0] == 0)
        {
          printk("End of files\n");
          break;
        }
        printk("  %c %zu %s\n",
               (ent.type == FS_DIR_ENTRY_FILE) ? 'F' : 'D',
               ent.size,
               ent.name);
      }

      (void)fs_closedir(&dir);

      return rc;
    }

    int unmount_fs(struct fs_mount_t *mp)
    {
      int rc = fs_unmount(mp);
      printk("%s unmount: %d\n", mp->mnt_point, rc);
      return rc;
    }

    static int write_test_file(const char *filename)
    {
      struct fs_file_t file;
      int res = fs_open(&file, filename, FS_O_CREATE | FS_O_WRITE);
      if (res < 0)
      {
        printk("Failed to open file for writing: %d\n", res);
        return res;
      }
    #define FILE_SIZE 512
      uint8_t buffer[512];
      size_t remaining = FILE_SIZE;
      while (remaining > 0)
      {
        size_t to_write = MIN(remaining, sizeof(buffer));
        ssize_t written = fs_write(&file, buffer, to_write);
        if (written < 0)
        {
          printk("Failed to write to file: %d\n", (int)written);
          fs_close(&file);
          return (int)written;
        }
        remaining -= written;
      }

      fs_close(&file);
      return 0;
    }

    void erase_partition(const struct flash_area *fa)
    {
      flash_area_erase(fa, fa->fa_off, fa->fa_size);
    }

    int reformat_littlefs(struct fs_mount_t *mp)
    {
      printk("REFORMATING");
      struct fs_littlefs *fs = mp->fs_data;
      const struct lfs_config *lfs_cfg = &fs->cfg; // Access the 'cfg' member directly
      int rc = lfs_format(&fs->lfs, lfs_cfg);
      return rc;
    }

    void reformat_and_mount_lfs(struct fs_mount_t *mp)
    {
      // Unmount the filesystem
      fs_unmount(mp);

      // Erase the partition
      const struct flash_area *fa;
      flash_area_open(FLASH_AREA_ID(storage), &fa);
      erase_partition(fa);
      flash_area_close(fa);

      // Reformat the filesystem using the updated configuration
      reformat_littlefs(mp);

      // Remount the filesystem
      fs_mount(mp);
    }
    with overlay:
    /delete-node/ &storage_partition;

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

    &mx25r64 {
        partitions {
            compatible = "fixed-partitions";
            #address-cells = <1>;
            #size-cells = <1>;

            lfs1_part: partition@0 {
                label = "storage";
                reg = <0x00000000 0x00800000>;
            };
        };
    };
    Area 7 at 0xf8000 on 7 for 24576 bytes
    [00:00:00.451,812] [0m<inf> littlefs: /lfs1 unmounted[0m
    REFORMATING[00:00:00.630,737] [0m<inf> littlefs: LittleFS version 2.5, disk version 2.0[0m
    [00:00:00.630,767] [0m<inf> littlefs: FS at flash-controller@39000:0xf8000 is 6 0x1000-byte blocks with 512 cycle[0m
    [00:00:00.630,767] [0m<inf> littlefs: sizes: rd 256 ; pr 256 ; ca 256 ; la 16[0m
    [00:00:00.631,134] [0m<inf> littlefs: /lfs1 mounted[0m
    LittleFS statistics:
    - Total space: 24576 bytes
    - Free space: 16384 bytes
    - Block size: 4096 bytes
    but it should be 8mb ??
Children
No Data
Related