Skip to content
Permalink
Browse files

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>
  • Loading branch information...
pabigot authored and carlescufi committed Jul 21, 2019
1 parent fb73fcd commit cfa64bde1c45431ff7dbce0e96002586e371320e
@@ -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})
@@ -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"
@@ -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:
@@ -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
@@ -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
@@ -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>;
};
};
};
@@ -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
@@ -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
@@ -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);
}

0 comments on commit cfa64bd

Please sign in to comment.
You can’t perform that action at this time.