mirror of
https://github.com/pellepl/spiffs.git
synced 2026-09-29 04:17:35 +00:00
Delete INTEGRATION file, now on wiki
Sigh
This commit is contained in:
@@ -1,306 +0,0 @@
|
|||||||
* 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 in src/ to your own source folder. Exclude
|
|
||||||
all files in test folder. Then you point out these files in your make script
|
|
||||||
for compilation.
|
|
||||||
|
|
||||||
Also copy the spiffs_config.h over from the src/default/ folder.
|
|
||||||
|
|
||||||
Try building. This 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 build. 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_buf[(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; // according to datasheet
|
|
||||||
cfg.log_block_size = 65536; // let us not complicate things
|
|
||||||
cfg.log_page_size = LOG_PAGE_SIZE; // as we said
|
|
||||||
|
|
||||||
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_buf,
|
|
||||||
sizeof(spiffs_cache_buf),
|
|
||||||
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, src);
|
|
||||||
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 experimented with your SPI flash, so it
|
|
||||||
contains rubbish 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];
|
|
||||||
|
|
||||||
// Surely, I've mounted spiffs before entering here
|
|
||||||
|
|
||||||
spiffs_file fd = SPIFFS_open(&fs, "my_file", SPIFFS_CREAT | SPIFFS_TRUNC | SPIFFS_RDWR, 0);
|
|
||||||
if (SPIFFS_write(&fs, fd, (u8_t *)"Hello world", 12) < 0) printf("errno %i\n", SPIFFS_errno(&fs));
|
|
||||||
SPIFFS_close(&fs, fd);
|
|
||||||
|
|
||||||
fd = SPIFFS_open(&fs, "my_file", SPIFFS_RDWR, 0);
|
|
||||||
if (SPIFFS_read(&fs, fd, (u8_t *)buf, 12) < 0) printf("errno %i\n", SPIFFS_errno(&fs));
|
|
||||||
SPIFFS_close(&fs, fd);
|
|
||||||
|
|
||||||
printf("--> %s <--\n", buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
Compile, run, cross fingers hard, and you'll get the output:
|
|
||||||
|
|
||||||
--> Hello world <--
|
|
||||||
|
|
||||||
Got errors? Check spiffs.h for error definitions to get a clue what went voodoo.
|
|
||||||
|
|
||||||
|
|
||||||
* THINGS TO CHECK
|
|
||||||
|
|
||||||
When you alter the spiffs_config values, make sure you also check the typedefs
|
|
||||||
in spiffs_config.h:
|
|
||||||
|
|
||||||
- spiffs_block_ix
|
|
||||||
- spiffs_page_ix
|
|
||||||
- spiffs_obj_id
|
|
||||||
- spiffs_span_ix
|
|
||||||
|
|
||||||
The sizes of these typedefs must not underflow, else spiffs might end up in
|
|
||||||
eternal loops. Each typedef is commented what check for.
|
|
||||||
|
|
||||||
Also, if you alter the code or just want to verify your configuration, you can
|
|
||||||
run
|
|
||||||
|
|
||||||
> make test
|
|
||||||
|
|
||||||
in the spiffs folder. This will run all testcases using the configuration in
|
|
||||||
default/spiffs_config.h and test/params_test.h. The tests are written for linux
|
|
||||||
but should run under cygwin also.
|
|
||||||
|
|
||||||
|
|
||||||
* 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
|
|
||||||
|
|
||||||
Other stuff may be needed, threaded systems might need mutexes and so on.
|
|
||||||
|
|
||||||
** Logical structure
|
|
||||||
|
|
||||||
First and foremost, 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 following seems arcane, read the "HOW TO CONFIG" chapter first.
|
|
||||||
|
|
||||||
- Decide the logical size of blocks. This must be a multiple of the biggest
|
|
||||||
physical SPI flash block size. To go safe, use the physical block size -
|
|
||||||
which in many cases is 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
|
|
||||||
|
|
||||||
Depending on the build config - if SPIFFS_SINGLETON is set to zero - following
|
|
||||||
parameters must be defined:
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
spiffs_config.phys_erase_block - the physical size of the largest block/sector
|
|
||||||
on the SPI flash found within the spiffs
|
|
||||||
usage address space
|
|
||||||
|
|
||||||
spiffs_config.log_block_size - the logical size of a spiffs block
|
|
||||||
|
|
||||||
spiffs_config.log_page_size - the logical size of a spiffs page
|
|
||||||
|
|
||||||
If SPIFFS_SINGLETON is set to one, above parameters must be set ny defines in
|
|
||||||
the config header file, spiffs_config.h.
|
|
||||||
|
|
||||||
|
|
||||||
** 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.
|
|
||||||
|
|
||||||
|
|
||||||
** RAM
|
|
||||||
|
|
||||||
Spiffs needs ram. It needs a working buffer being double the size of the
|
|
||||||
logical page size. It also needs at least one file descriptor. If cache is
|
|
||||||
enabled (highly recommended), it will also need a bunch of cache pages.
|
|
||||||
|
|
||||||
Say you have a logical page size of 256 bytes. You want to be able to have four
|
|
||||||
files open simultaneously, and you can give spiffs four cache pages. This
|
|
||||||
roughly sums up to:
|
|
||||||
|
|
||||||
256*2 (work buffer) +
|
|
||||||
32*4 (file descriptors) +
|
|
||||||
(256+32)*4 (cache pages) + 40 (cache metadata)
|
|
||||||
|
|
||||||
i.e. 1832 bytes.
|
|
||||||
|
|
||||||
This is apart from call stack usage.
|
|
||||||
|
|
||||||
To get the exact amount of bytes needed on your specific target, enable
|
|
||||||
SPIFFS_BUFFER_HELP in spiffs_config.h, rebuild and call:
|
|
||||||
|
|
||||||
SPIFFS_buffer_bytes_for_filedescs
|
|
||||||
SPIFFS_buffer_bytes_for_cache
|
|
||||||
|
|
||||||
Having these figures you can disable SPIFFS_BUFFER_HELP again to save flash.
|
|
||||||
|
|
||||||
|
|
||||||
* HOW TO CONFIG
|
|
||||||
|
|
||||||
TODO
|
|
||||||
Reference in New Issue
Block a user