C Library to transform a physical SPI Flash into a arbitrary number of logical circular buffers. The interface between SFCB and SPI core is realized as shared memory.
- Arbitrary SPI Flash support, selectable via
-D
at compile time - Arbitrary number of circular buffer queues (cbID) in a single SPI flash
- Interaction between circular buffer and SPI interface is realized as shared memory
- File system (LittleFS, SPIFFS) free
Version | Date | Source | Change log |
---|---|---|---|
latest | latest.zip |
git clone --recursive https://github.com/andkae/SPI-Flash-Circular-Buffer.git
The Makefile builds the repository with unit test:
$ make
gcc -c -O -Wall -Wextra -Wconversion -I . -I ../ -DW25Q16JV ./test/sfcb_test.c -o ./test/sfcb_test.o
gcc -c -O -Wall -Wextra -Wconversion -I . -I ../ -DW25Q16JV -DSFCB_PRINTF_EN ./spi_flash_cb.c -o ./test/sfcb.o
gcc -c -O -Wall -Wextra -Wconversion -I . -I ../ -DW25Q16JV ./test/spi_flash_model/spi_flash_model.c -o ./test/spi_flash_model.o
gcc ./test/sfcb_test.o ./test/sfcb.o ./test/spi_flash_model.o -Wall -Wextra -I. -lm -o ./test/sfcb_test
The library part itself can be built with:
gcc -c -O -Wall -Wextra -Wconversion -I . -DW25Q16JV -Werror ./spi_flash_cb.c -o ./test/sfcb.o
The flash memory W25Q16JV was selected via compile switch -D
.
To run the unit test call:
$ ./test/sfcb_test
Initializes SFCB common handle and assigns memory.
int sfcb_init (t_sfcb *self, void *cb, uint8_t cbLen, void *spi, uint16_t spiLen);
Arg | Description |
---|---|
self | SFCB storage element |
cb | Circular buffer queue memory |
cbLen | max. number of cb queues |
spi | SFCB / SPI core exchange buffer |
spiLen | spi buffer size in bytes |
Creates a new logical independent circular buffer queue in the SPI Flash.
int sfcb_new_cb (t_sfcb *self, uint32_t magicNum, uint16_t elemSizeByte, uint16_t numElems, uint8_t *cbID);
Arg | Description |
---|---|
self | SFCB storage element |
magicNum | Magic number, needs to be unique for every queue on the same SPI Flash |
elemSizeByte | Payload size in byte, header/footer causes |
numElems | minimal number of required elements in queue, rounded up to next full SECTOR |
cbID | assigned ID to this queue, needed for all further requests |
Checks if SFCB is processing another request.
int sfcb_busy (t_sfcb *self);
Arg | Description |
---|---|
self | SFCB storage element |
In last request ended with error.
int sfcb_isero (t_sfcb *self);
Arg | Description |
---|---|
self | SFCB storage element |
Acquires all queue information from SPI flash. Needed after calling sfcb_add to update all management information.
int sfcb_mkcb (t_sfcb *self);
Arg | Description |
---|---|
self | SFCB storage element |
Append bytes to the current selected circular buffer queue element.
int sfcb_add (t_sfcb *self, uint8_t cbID, void *data, uint16_t len);
Arg | Description |
---|---|
self | SFCB storage element |
cbID | circular buffer queue to interact |
*data | pointer to write data |
len | number of bytes in *data |
Force writing the Footer if not all available bytes in the circular buffer queue
element are occupied by Add. The Footer is used to detect an complete writing of an element.
The general recommendation is to call sfcb_add_done
every time when you completed the queue element writing.
int sfcb_add_done (t_sfcb *self, uint8_t cbID);
Arg | Description |
---|---|
self | SFCB storage element |
cbID | circular buffer queue to interact |
Acquire the current number of written bytes to queues element. Enables multistage data object writing to circular buffer element.
uint16_t sfcb_get_pl_wrcnt (t_sfcb *self, uint8_t cbID);
Arg | Description |
---|---|
self | SFCB storage element |
cbID | circular buffer queue to interact |
Write byte count of queue element.
Read last written queue element back.
int sfcb_get_last (t_sfcb *self, uint8_t cbID, void *data, uint16_t len, uint32_t *elemID);
Arg | Description |
---|---|
self | SFCB storage element |
cbID | circular buffer queue to interact |
*data | pointer to read data |
len | number of bytes in *data |
*elemID | queue element number |
Raw data read from flash.
int sfcb_flash_read (t_sfcb *self, uint32_t adr, void *data, uint16_t len);
Arg | Description |
---|---|
self | SFCB storage element |
adr | SPI Flash memory address |
*data | pointer to read data |
len | number of bytes in *data |
Services circular buffer layer request as well SPI packet processing. This function should called in a time based matter. The SPI data packet transfer should use an ISR based dataflow.
void sfcb_worker (t_sfcb *self);
Arg | Description |
---|---|
self | SFCB storage element |
None.
By sfcb_worker created SPI packet size in bytes.
uint16_t sfcb_spi_len (t_sfcb *self);
Arg | Description |
---|---|
self | SFCB storage element |
Byte Count of SPI packet.
Get SFCB compiled flash type total size.
uint32_t sfcb_flash_size (void);
Size in bytes.
Get highest element number of circular buffer queue cbID.
uint32_t sfcb_idmax (t_sfcb *self, uint8_t cbID);
Arg | Description |
---|---|
self | SFCB storage element |
cbID | circular buffer queue to interact |
Highest element number.
Value | Description |
---|---|
SFCB_OK | Accepted |
SFCB_E_NO_FLASH | no flash type selected, use -D |
SFCB_E_MEM | not enough memory assigned in sfcb_init |
SFCB_E_FLASH_FULL | Flash capacity exceeded |
SFCB_E_WKR_BSY | sfcb_worker is busy, wait |
SFCB_E_NO_CB_Q | circular buffer queue cbID not existent |
SFCB_E_WKR_REQ | circular buffer management data not prepared for request, run sfcb_mkcb |
SFCB_E_CB_Q_MTY | no valid entries in queue |
The SFCB supports an arbitrary number of circular buffer queues. Each circular buffer starts at the lowest free SPI Flash address. The Flash architecture requires an dedicated data clear - so called Sector Erase. Through this limitation needs to be at least two sectors allocated. Otherwise would the overwrite of the first written element result in an complete circular buffer queue overwrite without keeping any previous entries. Every new entry is marked with the incremented highest 32bit IdNum and MagicNum. The MagicNum ensures the detection of an occupied circular buffer queue element.
An exemplary memory organization for 240 bytes payload and 32 elements (= two sectors) shows the figure below: