mirror of
https://github.com/pellepl/spiffs.git
synced 2026-08-09 11:47:47 +00:00
restructured files
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013 Peter Andersson
|
||||
Copyright (c) 2013 Peter Andersson (pelleplutt1976<at>gmail.com)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
SPIFFS (SPI Flash File System)
|
||||
V0.1
|
||||
|
||||
Copyright (c) 2013 Peter Andersson
|
||||
Copyright (c) 2013 Peter Andersson (pelleplutt1976<at>gmail.com)
|
||||
|
||||
For legal stuff, see LICENCE in this directory. Basically, you may do whatever
|
||||
you want with the source. Use, modify, sell, print it out and smoke it - as
|
||||
long as I won't be held responsible.
|
||||
you want with the source. Use, modify, sell, print it out, roll it and smoke it
|
||||
- as long as I won't be held responsible.
|
||||
|
||||
Love to hear feedback though!
|
||||
|
||||
@@ -28,278 +28,19 @@ What spiffs does:
|
||||
- Spiffs presents a posix-like api: open, close, read, write, seek, stat, etc
|
||||
- Multiple spiffs configurations can be run on same target - and even on same
|
||||
SPI flash device
|
||||
- It implements static wear leveling
|
||||
- It has built in file system consistency checks
|
||||
|
||||
What spiffs does not:
|
||||
- Presently, spiffs does not support directories. It produces a flat
|
||||
- Presently, spiffs does not support directories. It produces a flat
|
||||
structure. Creating a file with path "tmp/myfile.txt" will create a file
|
||||
called "tmp/myfile.txt" instead of a myfile.txt under directory "tmp".
|
||||
called "tmp/myfile.txt" instead of a "myfile.txt" under directory "tmp".
|
||||
- It is not a realtime stack. One write operation might take much longer than
|
||||
another.
|
||||
- Poor scalability. Spiffs is intended for small memory devices - the normal
|
||||
sizes for SPI flashes.
|
||||
|
||||
|
||||
* 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 "DESIGN" 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)
|
||||
- Presently, it does not detect or handle bad blocks.
|
||||
|
||||
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. Datasheets sometimes name blocks as
|
||||
sectors and vice versa.
|
||||
|
||||
Common memory capacaties for SPI flashes are 512kB up to 8 MB 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
|
||||
For integration, see the docs/INTEGRATION file.
|
||||
|
||||
For use and design, see the docs/TECH_SPEC file.
|
||||
|
||||
@@ -0,0 +1,232 @@
|
||||
* 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 "DESIGN" 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
|
||||
|
||||
|
||||
|
||||
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 <--
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
* 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. Datasheets sometimes name blocks as
|
||||
sectors and vice versa.
|
||||
|
||||
Common memory capacaties for SPI flashes are 512kB up to 8 MB 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
|
||||
|
||||
@@ -17,7 +17,6 @@ builddir = build
|
||||
#############
|
||||
|
||||
CC = gcc $(COMPILEROPTIONS)
|
||||
AS = gcc $(ASSEMBLEROPTIONS)
|
||||
LD = ld
|
||||
GDB = gdb
|
||||
OBJCOPY = objcopy
|
||||
@@ -38,7 +37,7 @@ FILES = main.c \
|
||||
testsuites.c \
|
||||
testrunner.c
|
||||
include files.mk
|
||||
INCLUDE_DIRECTIVES = -I./${sourcedir} -I./${sourcedir}/default
|
||||
INCLUDE_DIRECTIVES = -I./${sourcedir} -I./${sourcedir}/default -I./${sourcedir}/test
|
||||
COMPILEROPTIONS = $(INCLUDE_DIRECTIVES)
|
||||
|
||||
############
|
||||
@@ -47,7 +46,7 @@ COMPILEROPTIONS = $(INCLUDE_DIRECTIVES)
|
||||
#
|
||||
############
|
||||
|
||||
vpath %.c ${sourcedir} ${sourcedir}/default
|
||||
vpath %.c ${sourcedir} ${sourcedir}/default ${sourcedir}/test
|
||||
|
||||
OBJFILES = $(FILES:%.c=${builddir}/%.o)
|
||||
|
||||
@@ -57,7 +56,7 @@ ALLOBJFILES += $(OBJFILES)
|
||||
|
||||
DEPENDENCIES = $(DEPFILES)
|
||||
|
||||
# link object files, create binary for flashing
|
||||
# link object files, create binary
|
||||
$(BINARY): $(ALLOBJFILES)
|
||||
@echo "... linking"
|
||||
@${CC} $(LINKEROPTIONS) -o ${builddir}/$(BINARY) $(ALLOBJFILES) $(LIBS)
|
||||
@@ -90,8 +89,4 @@ clean:
|
||||
@echo ... removing build files in ${builddir}
|
||||
@rm -f ${builddir}/*.o
|
||||
@rm -f ${builddir}/*.d
|
||||
@rm -f ${builddir}/*.out
|
||||
@rm -f ${builddir}/*.hex
|
||||
@rm -f ${builddir}/*.elf
|
||||
@rm -f ${builddir}/*.map
|
||||
@rm -f ${builddir}/*_disasm.s
|
||||
|
||||
Reference in New Issue
Block a user