mirror of
https://github.com/pellepl/spiffs.git
synced 2026-08-28 04:40:08 +00:00
added readme, added some comments
This commit is contained in:
@@ -0,0 +1,282 @@
|
||||
SPIFFS (SPI Flash File System)
|
||||
V1.0
|
||||
|
||||
Copyright (c) 2013 Peter Andersson
|
||||
|
||||
For legal stuff, see LICENCE in this directory.
|
||||
|
||||
|
||||
* INTRODUCTION
|
||||
|
||||
Spiffs is a file system intended for SPI flash devices on embedded targets.
|
||||
|
||||
Spiffs is designed with following characteristics in mind:
|
||||
- Small (embedded) target, sparse RAM
|
||||
- Only big areas of data (blocks) can be erased
|
||||
- An erase will reset all bits in block to ones
|
||||
- Writing pulls one to zeroes
|
||||
- Zeroes can only be pulled to ones by erase
|
||||
- Wear leveling
|
||||
|
||||
Spiffs is inspired by YAFFS structurally, but is a clean write from scratch.
|
||||
|
||||
|
||||
* INTEGRATING SPIFFS
|
||||
|
||||
In order to integrate spiffs to your embedded target, you will basically need:
|
||||
- A SPI flash device which your processor can communicate with
|
||||
- An implementation for reading, writing and erasing the flash
|
||||
- Memory (flash or ram) for the code
|
||||
- Memory (ram) for the stack
|
||||
|
||||
Threaded systems might need mutexes and so on.
|
||||
|
||||
** Logical structure
|
||||
|
||||
One must decide how to divide up the SPI flash for spiffs. Having the datasheet
|
||||
for the actual SPI flash in hand will help. Spiffs can be defined to use all or
|
||||
only parts of the SPI flash.
|
||||
|
||||
If this seems arcane, read the "DESIGN" chapter first.
|
||||
|
||||
- Decide the logical size of blocks. This must be a multiple of the physical
|
||||
SPI flash block size. To go safe, use the physical block size - which in
|
||||
almost all cases are 65536 bytes.
|
||||
- Decide the logical size of pages. This must be a 2nd logarithm part of the
|
||||
logical block size. To go safe, use 256 bytes to start with.
|
||||
- Decide how much of the SPI flash memory to be used for spiffs. This must be
|
||||
on logical block boundary. If unsafe, use 1 megabyte to start with.
|
||||
- Decide where on the SPI flash memory the spiffs area should start. This must
|
||||
be on physical block/sector boundary. If unsafe, use address 0.
|
||||
|
||||
** SPI flash API
|
||||
|
||||
The target must provide three functions to spiffs:
|
||||
|
||||
- s32_t (*spiffs_read)(u32_t addr, u32_t size, u8_t *dst)
|
||||
- s32_t (*spiffs_write)(u32_t addr, u32_t size, u8_t *src)
|
||||
- s32_t (*spiffs_erase)(u32_t addr, u32_t size)
|
||||
|
||||
These functions define the only communication between the SPI flash and the
|
||||
spiffs stack.
|
||||
|
||||
On success these must return 0 (or SPIFFS_OK). Anything else will be considered
|
||||
an error.
|
||||
|
||||
The size for read and write requests will never exceed the logical page size,
|
||||
but it may be less.
|
||||
|
||||
The address and size on erase requests will always be on physical block size
|
||||
boundaries.
|
||||
|
||||
** Mount specification
|
||||
|
||||
In spiffs.h, there is a SPIFFS_mount function defined, used to mount spiffs on
|
||||
the SPI flash.
|
||||
|
||||
s32_t SPIFFS_mount(
|
||||
spiffs *fs,
|
||||
spiffs_config *config,
|
||||
u8_t *work,
|
||||
u8_t *fd_space,
|
||||
u32_t fd_space_size,
|
||||
void *cache,
|
||||
u32_t cache_size,
|
||||
spiffs_check_callback check_cb_f)
|
||||
|
||||
- fs Points to a spiffs struct. This may be totally uninitialized.
|
||||
- config Points to a spiffs_config struct. This struct must be
|
||||
initialized when mounting. See below.
|
||||
- work A RAM memory buffer being double the size of the logical page
|
||||
size. This buffer is used excessively by the spiffs stack. If
|
||||
logical page size is 256, this buffer must be 512 bytes.
|
||||
- fd_space A RAM memory buffer used for file descriptors.
|
||||
- fd_space_size The size of the file descriptor buffer. A file descriptor
|
||||
normally is around 32 bytes depending on the build config -
|
||||
the bigger the buffer, the more file descriptors are
|
||||
available.
|
||||
- cache A RAM memory buffer used for cache. Ignored if cache is
|
||||
disabled in build config.
|
||||
- cache_size The size of the cache buffer. Ignored if cache is disabled in
|
||||
build config. One cache page will be slightly larger than the
|
||||
logical page size. The more ram, the more cache pages, the
|
||||
quicker the system.
|
||||
- check_cb_f Callback function for monitoring spiffs consistency checks and
|
||||
mending operations. May be null.
|
||||
|
||||
The config struct must be initialized prior to mounting. One must always
|
||||
define the SPI flash access functions:
|
||||
|
||||
spiffs_config.hal_read_f - pointing to the function reading the SPI flash
|
||||
spiffs_config.hal_write_f - pointing to the function writing the SPI flash
|
||||
spiffs_config.hal_erase_f - pointing to the function erasing the SPI flash
|
||||
|
||||
|
||||
|
||||
spiffs_config.phys_size - the physical number of bytes accounted for
|
||||
spiffs on the SPI flash
|
||||
spiffs_config.phys_addr - the physical starting address on the SPI flash
|
||||
|
||||
TODO
|
||||
|
||||
** Build config
|
||||
|
||||
makefile: The files needed to be compiled to your target resides in files.mk to
|
||||
be included in your makefile, either by cut and paste or by inclusion.
|
||||
|
||||
Types: spiffs uses the types u8_t, s8_t, u16_t, s16_t, u32_t, s32_t; these must
|
||||
be typedeffed.
|
||||
|
||||
spiffs_config.h: you also need to define a spiffs_config.h header. Example of
|
||||
this is found in the default/ directory.
|
||||
|
||||
|
||||
* QUICK AND DIRTY INTEGRATION EXAMPLE
|
||||
|
||||
So, assume you're running a Cortex-M3 board with a 2 MB SPI flash on it. The
|
||||
SPI flash has 64kB blocks. Your project is built using gnumake, and now you
|
||||
want to try things out.
|
||||
|
||||
First, you simply copy the files named in files.mk to your own source folder. Then
|
||||
you point out these files in your make script for compilation.
|
||||
|
||||
Also copy the spiffs_config.h over from the default/ folder.
|
||||
|
||||
Build fails, nagging about inclusions and u32_t and whatnot. Open the
|
||||
spiffs_config.h and delete the bad inclusions. Also, add following typedefs:
|
||||
|
||||
typedef signed int s32_t;
|
||||
typedef unsigned int u32_t;
|
||||
typedef signed short s16_t;
|
||||
typedef unsigned short u16_t;
|
||||
typedef signed char s8_t;
|
||||
typedef unsigned char u8_t;
|
||||
|
||||
Now it should builds. Over to the mounting business. Assume you already
|
||||
implemented the read, write and erase functions to your SPI flash:
|
||||
|
||||
void my_spi_read(int addr, int size, char *buf)
|
||||
void my_spi_write(int addr, int size, char *buf)
|
||||
void my_spi_erase(int addr, int size)
|
||||
|
||||
In your main.c or similar, include the spiffs.h and do that spiffs struct:
|
||||
|
||||
#include <spiffs.h>
|
||||
|
||||
static spiffs fs;
|
||||
|
||||
Also, toss up some of the needed buffers:
|
||||
|
||||
#define LOG_PAGE_SIZE 256
|
||||
|
||||
static u8_t spiffs_work_buf[LOG_PAGE_SIZE*2];
|
||||
static u8_t spiffs_fds[32*4];
|
||||
static u8_t spiffs_cache[(LOG_PAGE_SIZE+32)*4];
|
||||
|
||||
Now, write the my_spiffs_mount function:
|
||||
|
||||
void my_spiffs_mount() {
|
||||
spiffs_config cfg;
|
||||
cfg.phys_size = 2*1024*1024; // use all spi flash
|
||||
cfg.phys_addr = 0; // start spiffs at start of spi flash
|
||||
cfg.phys_erase_block = 65536; // well, this is what the datasheet says
|
||||
cfg.log_block_size = 65536; // seems sensible
|
||||
cfg.log_block_size = LOG_PAGE_SIZE; // seems sensible
|
||||
|
||||
cfg.hal_read_f = my_spi_read;
|
||||
cfg.hal_write_f = my_spi_write;
|
||||
cfg.hal_erase_f = my_spi_erase;
|
||||
|
||||
int res = SPIFFS_mount(&fs,
|
||||
&cfg,
|
||||
spiffs_work_buf,
|
||||
spiffs_fds,
|
||||
sizeof(spiffs_fds),
|
||||
spiffs_cache,
|
||||
sizeof(spiffs_cache),
|
||||
0);
|
||||
printf("mount res: %i\n", res);
|
||||
}
|
||||
|
||||
Now, build warns about the my_spi_read, write and erase functions. Wrong
|
||||
signatures, so go wrap them:
|
||||
|
||||
static s32_t my_spiffs_read(u32_t addr, u32_t size, u8_t *dst) {
|
||||
my_spi_read(addr, size, dst);
|
||||
return SPIFFS_OK;
|
||||
}
|
||||
|
||||
static s32_t my_spiffs_write(u32_t addr, u32_t size, u8_t *src) {
|
||||
my_spi_write(addr, size, dst);
|
||||
return SPIFFS_OK;
|
||||
}
|
||||
|
||||
static s32_t my_spiffs_erase(u32_t addr, u32_t size) {
|
||||
my_spi_erase(addr, size);
|
||||
return SPIFFS_OK;
|
||||
}
|
||||
|
||||
Redirect the config in my_spiffs_mount to the wrappers instead:
|
||||
|
||||
cfg.hal_read_f = my_spiffs_read;
|
||||
cfg.hal_write_f = my_spiffs_write;
|
||||
cfg.hal_erase_f = my_spiffs_erase;
|
||||
|
||||
Ok, now you should be able to build and run. However, you get this output:
|
||||
|
||||
mount res: -1
|
||||
|
||||
but you wanted
|
||||
|
||||
mount res: 0
|
||||
|
||||
This is probably due to you having being experimenting with your SPI flash, so
|
||||
it contains garbage from spiffs's point of view. Do a mass erase and run again.
|
||||
|
||||
If all is ok now, you're good to go. Try creating a file and read it back:
|
||||
|
||||
static void test_spiffs() {
|
||||
char buf[12];
|
||||
|
||||
spiffs_file fd = SPIFFS_open(&fs, "my_file", 0, SPIFFS_CREAT | SPIFFS_TRUNC | SPIFFS_RDWR);
|
||||
if (SPIFFS_write(&fs, fd, "Hello world", 12) < 0) printf("errno %i\n", SPIFFS_errno(&fs));
|
||||
SPIFFS_close(&fs, fd);
|
||||
|
||||
fd = SPIFFS_open(&fs, "my_file", 0, SPIFFS_RDWR);
|
||||
if (SPIFFS_read(&fs, fd, buf, 12) < 0) printf("errno %i\n", SPIFFS_errno(&fs));
|
||||
SPIFFS_close(&fs, fd);
|
||||
|
||||
printf("--> %s <--\n", buf);
|
||||
}
|
||||
|
||||
And, crossing fingers hard, you'll get the output:
|
||||
|
||||
--> Hello world <--
|
||||
|
||||
|
||||
* USING SPIFFS
|
||||
|
||||
TODO
|
||||
|
||||
* DESIGN
|
||||
|
||||
** SPI flash devices
|
||||
|
||||
Below is a small description of how SPI flashes work internally.
|
||||
|
||||
SPI flash devices are physically divided in blocks. On some SPI flash devices,
|
||||
blocks are further divided into sectors. Common memory capacaties for SPI
|
||||
flashes are 1,2,4 or 8 megabyte of data, with blocks of 64K. Sectors normally
|
||||
are 4K, if supported. The entire memory is linear and can be written in random
|
||||
access, but erasing can only be done block- or sectorwise; or by mass erase.
|
||||
|
||||
SPI flashes can normally be erased from 100.000 up to 1.000.000 cycles before
|
||||
they fail erasing.
|
||||
|
||||
A clean SPI flash from factory have all bits in entire memory set to one. A
|
||||
mass erase will reset the device to this state. Block or sector erasing will
|
||||
put the area given by the sector or block to ones. Writing to a SPI flash
|
||||
pulls ones to zeroes. Writing 0xFF to an address is simply a no-op. This way
|
||||
of "nand-writing" is used considerably in spiffs.
|
||||
|
||||
** TODO
|
||||
@@ -8,7 +8,8 @@
|
||||
#ifndef SPIFFS_CONFIG_H_
|
||||
#define SPIFFS_CONFIG_H_
|
||||
|
||||
|
||||
// following includes are for the linux test build of spiffs
|
||||
// this may/should/must be removed/altered/replaced in your target
|
||||
#include "stypes.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -17,9 +18,13 @@
|
||||
|
||||
// compile time switches
|
||||
|
||||
// set generic spiffs debug output
|
||||
#define SPIFFS_DBG(...)
|
||||
// set spiffs debug output for garbage collecting
|
||||
#define SPIFFS_GC_DBG(...)
|
||||
// set spiffs debug output for caching
|
||||
#define SPIFFS_CACHE_DBG(...)
|
||||
// set spiffs debug output for system consistency checks
|
||||
#define SPIFFS_CHECK_DBG(...)
|
||||
|
||||
// define maximum number of gc runs to perform to reach desired free pages
|
||||
|
||||
@@ -224,6 +224,7 @@ typedef struct {
|
||||
* @param fd_space_size memory size of file descriptors
|
||||
* @param cache memory for cache, may be null
|
||||
* @param cache_size memory size of cache
|
||||
* @param check_cb_f callback function for reporting during consistency checks
|
||||
*/
|
||||
s32_t SPIFFS_mount(spiffs *fs, spiffs_config *config, u8_t *work,
|
||||
u8_t *fd_space, u32_t fd_space_size,
|
||||
|
||||
Reference in New Issue
Block a user