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 <pab@pabigot.com>
This commit is contained in:
parent
fb73fcd4ba
commit
cfa64bde1c
9 changed files with 314 additions and 0 deletions
12
samples/subsys/fs/littlefs/CMakeLists.txt
Normal file
12
samples/subsys/fs/littlefs/CMakeLists.txt
Normal file
|
@ -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})
|
11
samples/subsys/fs/littlefs/Kconfig
Normal file
11
samples/subsys/fs/littlefs/Kconfig
Normal file
|
@ -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"
|
69
samples/subsys/fs/littlefs/README.rst
Normal file
69
samples/subsys/fs/littlefs/README.rst
Normal file
|
@ -0,0 +1,69 @@
|
|||
.. _littlefs-sample:
|
||||
|
||||
littlefs File System Sample Application
|
||||
#######################################
|
||||
|
||||
Overview
|
||||
********
|
||||
|
||||
This sample app demonstrates use of Zephyr's :ref:`file system API
|
||||
<file_system>` 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] <inf> littlefs: LittleFS version 2.0, disk version 2.0
|
||||
[00:00:00.010,559] <err> littlefs: Corrupted dir pair at 0 1
|
||||
[00:00:00.010,559] <wrn> 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] <inf> littlefs: filesystem mounted!
|
||||
[00:00:00.867,034] <err> 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:
|
13
samples/subsys/fs/littlefs/boards/nrf52840_pca10056.conf
Normal file
13
samples/subsys/fs/littlefs/boards/nrf52840_pca10056.conf
Normal file
|
@ -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
|
8
samples/subsys/fs/littlefs/boards/particle_xenon.conf
Normal file
8
samples/subsys/fs/littlefs/boards/particle_xenon.conf
Normal file
|
@ -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
|
33
samples/subsys/fs/littlefs/particle_xenon.overlay
Normal file
33
samples/subsys/fs/littlefs/particle_xenon.overlay
Normal file
|
@ -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>;
|
||||
};
|
||||
};
|
||||
};
|
21
samples/subsys/fs/littlefs/prj.conf
Normal file
21
samples/subsys/fs/littlefs/prj.conf
Normal file
|
@ -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
|
7
samples/subsys/fs/littlefs/sample.yaml
Normal file
7
samples/subsys/fs/littlefs/sample.yaml
Normal file
|
@ -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
|
140
samples/subsys/fs/littlefs/src/main.c
Normal file
140
samples/subsys/fs/littlefs/src/main.c
Normal file
|
@ -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 <stdio.h>
|
||||
|
||||
#include <zephyr.h>
|
||||
#include <device.h>
|
||||
#include <fs/fs.h>
|
||||
#include <fs/littlefs.h>
|
||||
#include <storage/flash_map.h>
|
||||
|
||||
/* 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);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue