From cfa64bde1c45431ff7dbce0e96002586e371320e Mon Sep 17 00:00:00 2001 From: "Peter A. Bigot" Date: Sun, 21 Jul 2019 15:21:43 -0500 Subject: [PATCH] samples/subsys/fs/littlefs: add a basic sample Uses a littlefs file system to maintain a boot counter. Also tests some other functions. Signed-off-by: Peter A. Bigot --- samples/subsys/fs/littlefs/CMakeLists.txt | 12 ++ samples/subsys/fs/littlefs/Kconfig | 11 ++ samples/subsys/fs/littlefs/README.rst | 69 +++++++++ .../fs/littlefs/boards/nrf52840_pca10056.conf | 13 ++ .../fs/littlefs/boards/particle_xenon.conf | 8 + .../subsys/fs/littlefs/particle_xenon.overlay | 33 +++++ samples/subsys/fs/littlefs/prj.conf | 21 +++ samples/subsys/fs/littlefs/sample.yaml | 7 + samples/subsys/fs/littlefs/src/main.c | 140 ++++++++++++++++++ 9 files changed, 314 insertions(+) create mode 100644 samples/subsys/fs/littlefs/CMakeLists.txt create mode 100644 samples/subsys/fs/littlefs/Kconfig create mode 100644 samples/subsys/fs/littlefs/README.rst create mode 100644 samples/subsys/fs/littlefs/boards/nrf52840_pca10056.conf create mode 100644 samples/subsys/fs/littlefs/boards/particle_xenon.conf create mode 100644 samples/subsys/fs/littlefs/particle_xenon.overlay create mode 100644 samples/subsys/fs/littlefs/prj.conf create mode 100644 samples/subsys/fs/littlefs/sample.yaml create mode 100644 samples/subsys/fs/littlefs/src/main.c diff --git a/samples/subsys/fs/littlefs/CMakeLists.txt b/samples/subsys/fs/littlefs/CMakeLists.txt new file mode 100644 index 00000000000..bf55d6efad3 --- /dev/null +++ b/samples/subsys/fs/littlefs/CMakeLists.txt @@ -0,0 +1,12 @@ +# +# Copyright (c) 2019 Peter Bigot Consulting, LLC +# +# SPDX-License-Identifier: Apache-2.0 +# + +cmake_minimum_required(VERSION 3.13.1) +include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE) +project(littlefs) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/samples/subsys/fs/littlefs/Kconfig b/samples/subsys/fs/littlefs/Kconfig new file mode 100644 index 00000000000..3a784b05869 --- /dev/null +++ b/samples/subsys/fs/littlefs/Kconfig @@ -0,0 +1,11 @@ +# Copyright (c) 2019 Peter Bigot Consulting, LLC +# +# SPDX-License-Identifier: Apache-2.0 +# + +config APP_WIPE_STORAGE + bool "Option to clear the flash area before mounting" + help + Use this to force an existing file system to be created. + +source "$ZEPHYR_BASE/Kconfig" diff --git a/samples/subsys/fs/littlefs/README.rst b/samples/subsys/fs/littlefs/README.rst new file mode 100644 index 00000000000..d11c4373409 --- /dev/null +++ b/samples/subsys/fs/littlefs/README.rst @@ -0,0 +1,69 @@ +.. _littlefs-sample: + +littlefs File System Sample Application +####################################### + +Overview +******** + +This sample app demonstrates use of Zephyr's :ref:`file system API +` over `littlefs`_, using a file system with a file that +counts the number of times the system has booted. Other information +about the file system is also displayed. + +.. _littlefs: + https://github.com/ARMmbed/littlefs + +Requirements +************ + +The partition labeled "storage" will be used for the file system; see +:ref:`flash_partitions`. If that area does not already have a +compatible littlefs file system its contents will be replaced by an +empty file system. You will see diagnostics like this:: + + [00:00:00.010,192] littlefs: LittleFS version 2.0, disk version 2.0 + [00:00:00.010,559] littlefs: Corrupted dir pair at 0 1 + [00:00:00.010,559] littlefs: can't mount (LFS -84); formatting + +The error and warning are normal for a new file system. + +After the file system is mounted you'll also see:: + + [00:00:00.182,434] littlefs: filesystem mounted! + [00:00:00.867,034] fs: failed get file or dir stat (-2) + +This error is also normal for Zephyr not finding a file (the boot count, +in this case). + +Building and Running +******************** + +This example should work on any board that provides a "storage" +partition. Two tested board targets are described below. + +You can set ``CONFIG_APP_WIPE_STORAGE`` to force the file system to be +recreated. + +NRF52840 Development Kit +======================== + +On this device the file system will be placed in the SOC flash. + +.. zephyr-app-commands:: + :zephyr-app: samples/subsys/fs/littlefs + :board: nrf52840_pca10056 + :goals: build + :compact: + +Particle Xenon +============== + +On this device the file system will be placed on the external SPI NOR +flash memory. + +.. zephyr-app-commands:: + :zephyr-app: samples/subsys/fs/littlefs + :board: particle_xenon + :goals: build + :compact: diff --git a/samples/subsys/fs/littlefs/boards/nrf52840_pca10056.conf b/samples/subsys/fs/littlefs/boards/nrf52840_pca10056.conf new file mode 100644 index 00000000000..339d2b51a78 --- /dev/null +++ b/samples/subsys/fs/littlefs/boards/nrf52840_pca10056.conf @@ -0,0 +1,13 @@ +# +# Copyright (c) 2019 Peter Bigot Consulting, LLC +# +# SPDX-License-Identifier: Apache-2.0 +# + +# Need this when storage is on flash +CONFIG_MPU_ALLOW_FLASH_WRITE=y + +# Need this when storage is on MX25R64 +CONFIG_SPI=y +CONFIG_SPI_NOR=y +CONFIG_SPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096 diff --git a/samples/subsys/fs/littlefs/boards/particle_xenon.conf b/samples/subsys/fs/littlefs/boards/particle_xenon.conf new file mode 100644 index 00000000000..317cd8f29db --- /dev/null +++ b/samples/subsys/fs/littlefs/boards/particle_xenon.conf @@ -0,0 +1,8 @@ +# +# Copyright (c) 2019 Peter Bigot Consulting, LLC +# +# SPDX-License-Identifier: Apache-2.0 +# +CONFIG_SPI=y +CONFIG_SPI_NOR=y +CONFIG_SPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096 diff --git a/samples/subsys/fs/littlefs/particle_xenon.overlay b/samples/subsys/fs/littlefs/particle_xenon.overlay new file mode 100644 index 00000000000..5998b2e59c4 --- /dev/null +++ b/samples/subsys/fs/littlefs/particle_xenon.overlay @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2019 Peter Bigot Consulting, LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/delete-node/ &storage_partition; + +&mx25l32 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* This is the littlefs v1 file system pre-installed + * by Particle. + */ + littlefs_partition: partition@0 { + label = "littlefs"; + reg = <0x00000000 0x00200000>; + }; + /* A 16 KiBy partition to use for the test. */ + storage_partition: partition@200000 { + label = "storage"; + reg = <0x00200000 0x00004000>; + }; + /* A bigger partition for something else. */ + partition@220000 { + label = "scratch"; + reg = <0x00204000 0x001fc000>; + }; + }; +}; diff --git a/samples/subsys/fs/littlefs/prj.conf b/samples/subsys/fs/littlefs/prj.conf new file mode 100644 index 00000000000..5aedc837f16 --- /dev/null +++ b/samples/subsys/fs/littlefs/prj.conf @@ -0,0 +1,21 @@ +# +# Copyright (c) 2019 Peter Bigot Consulting, LLC +# +# SPDX-License-Identifier: Apache-2.0 +# + +# Optionally force the file system to be recreated +#CONFIG_APP_WIPE_STORAGE=y + +# fs_dirent structures are big. +CONFIG_MAIN_STACK_SIZE=2048 + +CONFIG_LOG=y +#CONFIG_FS_LOG_LEVEL_DBG=y + +CONFIG_FLASH=y +CONFIG_FLASH_MAP=y +CONFIG_FLASH_PAGE_LAYOUT=y + +CONFIG_FILE_SYSTEM=y +CONFIG_FILE_SYSTEM_LITTLEFS=y diff --git a/samples/subsys/fs/littlefs/sample.yaml b/samples/subsys/fs/littlefs/sample.yaml new file mode 100644 index 00000000000..9a3d3968713 --- /dev/null +++ b/samples/subsys/fs/littlefs/sample.yaml @@ -0,0 +1,7 @@ +sample: + name: littlefs filesystem sample +tests: + sample.subsys.fs.littlefs: + build_only: true + platform_whitelist: nrf52840_pca10056 particle_xenon + tags: filesystem diff --git a/samples/subsys/fs/littlefs/src/main.c b/samples/subsys/fs/littlefs/src/main.c new file mode 100644 index 00000000000..1b056a81f45 --- /dev/null +++ b/samples/subsys/fs/littlefs/src/main.c @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2019 Peter Bigot Consulting, LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* Sample which uses the filesystem API with littlefs */ + +#include + +#include +#include +#include +#include +#include + +/* Matches LFS_NAME_MAX */ +#define MAX_PATH_LEN 255 + +static struct fs_littlefs lfs_storage; +static struct fs_mount_t lfs_storage_mnt = { + .type = FS_LITTLEFS, + .fs_data = &lfs_storage, + .storage_dev = (void *)DT_FLASH_AREA_STORAGE_ID, + .mnt_point = "/lfs", +}; + +void main(void) +{ + struct fs_mount_t *mp = &lfs_storage_mnt; + unsigned int id = (uintptr_t)mp->storage_dev; + char fname[MAX_PATH_LEN]; + struct fs_statvfs sbuf; + const struct flash_area *pfa; + int rc; + + snprintf(fname, sizeof(fname), "%s/boot_count", mp->mnt_point); + + rc = flash_area_open(id, &pfa); + if (rc < 0) { + printk("FAIL: unable to find flash area %u: %d\n", + id, rc); + return; + } + + 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); + + /* Optional wipe flash contents */ + if (IS_ENABLED(CONFIG_APP_WIPE_STORAGE)) { + printk("Erasing flash area ... "); + rc = flash_area_erase(pfa, 0, pfa->fa_size); + printk("%d\n", rc); + flash_area_close(pfa); + } + + rc = fs_mount(mp); + if (rc < 0) { + printk("FAIL: mount id %u at %s: %d\n", + (unsigned int)mp->storage_dev, mp->mnt_point, + rc); + return; + } + printk("%s mount: %d\n", mp->mnt_point, rc); + + rc = fs_statvfs(mp->mnt_point, &sbuf); + if (rc < 0) { + printk("FAIL: statvfs: %d\n", rc); + goto out; + } + + printk("%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); + + struct fs_dirent dirent; + + rc = fs_stat(fname, &dirent); + printk("%s stat: %d\n", fname, rc); + if (rc >= 0) { + printk("\tfn '%s' siz %u\n", dirent.name, dirent.size); + } + + struct fs_file_t file; + + rc = fs_open(&file, fname); + if (rc < 0) { + printk("FAIL: open %s: %d\n", fname, rc); + goto out; + } + + u32_t boot_count = 0; + + if (rc >= 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); + + struct fs_dir_t dir = { 0 }; + + 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 %u %s\n", + (ent.type == FS_DIR_ENTRY_FILE) ? 'F' : 'D', + ent.size, + ent.name); + } + + (void)fs_closedir(&dir); + +out: + rc = fs_unmount(mp); + printk("%s unmount: %d\n", mp->mnt_point, rc); +}