Skip to content

littlefs

sipke edited this page Jul 8, 2019 · 23 revisions

https://github.com/ARMmbed/littlefs

Uses for loops with initialisation, so C99 is required. -std=c99 will need to be added to compiler options.

lfs_util.h contains a few debug/error macros, which utilise printf, so depending on whether your system has printf you may get warnings to deal with.

Suggested option in lfs_utils.h is to write your own config file and use -DLFS_CONFIG=lfs_config.h to have it included instead of lfs_utils.h, which means you need to copy and adjust anything needed.

If your compiler and associated system files does not have inttypes.h (see for example https://github.com/openbsd/src/blob/master/include/inttypes.h) you will need to add one or just define the following few which are needed by the debug macros.

#define PRIu16 "u" /* uint16_t */

#define PRIu32 "u" /* uint32_t */

If your system does not have printf, you can take the easy option at least initially and disable them using compiler defines (see lfs_util.h). LFS_NO_DEBUG, LFS_NO_WARN, LFS_NO_ERROR, LFS_NO_ASSERT Alternatively you need to provide a printf, or if you have created an lfs_config.h file replace printf with an appropriate debug print function on your system.

Additionally if you have a very restricted microcontroller, its likely you will want to set both or one of define LFS_NO_MALLOC, LFS_NO_ASSERT The first ensuring that memory allocation is not used, and the second if you do not want assert functionality.

If you want assert, then you will also need uintptr_t which is an optional C99 type, so may not exist in your system. Again you will need to typedef this yourself to the appropriate 'pointer size' for your system.

If you do provide your own lfs_config.h file, LFS_CONFIG will not be defined, so the lfs_crc function will not be built either. This means you need to create your own, or copy the implementation to a file which is going to build this into your image.

lfs.c has a number of inline functions which can use builtin gcc functions, or if your compiler does not have these, you need to define LFS_NO_INTRINSICS to ensure a local version of the same function is used. If you get

littlefs/lfs.c:2921: undefined reference to ___clzhi2'`

or

littlefs/lfs.c:2923: undefined reference to ___popcounthi2'`

Then in your lfs_config.h

#define LFS_NO_INTRINSICS

With all compilation/build in place, next the HW write to flash needs to be implemented for your device. In lfs.h you will see the following members of the lfs_config structure. (in Github: https://github.com/ARMmbed/littlefs/blob/5ee20e8d774adf0bb538269870b3552fdfc0e046/lfs.h#L95-L114)

// Read a region in a block. Negative error codes are propogated
// to the user.
int (*read)(const struct lfs_config *c, lfs_block_t block,
        lfs_off_t off, void *buffer, lfs_size_t size);

// Program a region in a block. The block must have previously
// been erased. Negative error codes are propogated to the user.
// The prog function must return LFS_ERR_CORRUPT if the block should
// be considered bad.
int (*prog)(const struct lfs_config *c, lfs_block_t block,
        lfs_off_t off, const void *buffer, lfs_size_t size);

// Erase a block. A block must be erased before being programmed.
// The state of an erased block is undefined. Negative error codes
// are propogated to the user.
int (*erase)(const struct lfs_config *c, lfs_block_t block);

// Sync the state of the underlying block device. Negative error codes
// are propogated to the user.
int (*sync)(const struct lfs_config *c);

Which corresponds to the lfs_config in the example: https://github.com/ARMmbed/littlefs#example

When configuring the lsf_config for your flash part, things to note are If not using malloc, then you must provide a static buffer for read_buffer, prog_buffer, lookahead_buffer. Also as commented in the lsf_config structure definition read_buffer and prog_buffer must be of cache size, and this must be a multiple of read and program sizes.

#define BASE_SIZE 16 static uint8_t readbuf[BASE_SIZE]; static uint8_t progbuf[BASE_SIZE]; static uint8_t lookbuf[BASE_SIZE];

// configuration of the filesystem is provided by this struct const struct lfs_config cfg = { // block device operations .read = my_read, .prog = my_program, .erase = my_erase, .sync = my_sync,

// block device configuration
.read_size = sizeof(readbuf),
.prog_size = sizeof(progbuf),
.block_size = 4096,
.block_count = 128,
.cache_size = CACHE_SIZE,
.lookahead_size = sizeof(lookaheadbuf),
.read_buffer = readbuf,
.prog_buffer = progbuf,
.lookahead_buffer = lookaheadbuffer,

};

Note that the lookahead buffer needs to be byte aligned, and it is asserted for (if you have assert enabled) in the lfs_init function. https://stackoverflow.com/questions/1468513/attribute-aligned-not-working-with-static-variables

what is lsf_config.sync: https://github.com/ARMmbed/littlefs/issues/35

file reported as directory: https://github.com/ARMmbed/littlefs/issues/178

static memory systems (no malloc) must used lsf_file_opencfg(...) function and pass in file.cfg with a pointer to a file specific cache buffer. Not entirely clear if the buffer needs to be 64bit aligned, as per look ahead buffer, but would not hurt to do.

struct lfs_file_config myfileconfig myfileconfig.buffer = myFileBuffer; int err = lfs_file_opencfg(&lfs, &file, "boot_count", LFS_O_RDWR | LFS_O_CREAT, &myfileconfig);

Gotchas

Once you have decided on a maximum for maximums for attributes like name_max, you will not be able to change them and expect the 'mount' to work, as you will get an error lfs:error:3401: Unsupported name_max (255 > 64)

Clone this wiki locally