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?
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?
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:
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: