123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306 |
- * 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, 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 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
|