Arduino Circular Buffer to Serial Flash

Writing an Arduino Circular Buffer to Serial Flash.

Data is arranged in BLOCKS of 4K, each block contains PAGES of length 256 bytes. Pages are written sequentially to flash.

When we get to the end of the flash we then start at the beginning. Serial Flash must be erased a BLOCK at a time. We erase only one BLOCK ahead of where we are currently writing.

On startup we determine what is the next free page in the flash so that we can continue writing. We keep an address pointer in memory after this.

The first byte of each page is used to flag teh following:

11111111 – not written

01111111 – writing

00111111 – written

The following 255 bytes contain the page payload. We CANNOT write more than 255 bytes to a page.

#define BLOCK_SIZE 4096  //4K
#define PAGE_SIZE 256    //

#define PAGE_WRITING 0x7F //01111111
#define PAGE_WRITTEN 0x3F //00111111

SPIFlash flash;
uint32_t addr;
uint32_t capacity;

void setup() {
   capacity = flash.getCapacity(); 
   addr = getNextAddress();

  Writes a variable length packet of no more than 255
  bytes to the rolling log

  @param data_buffer[] the bytes to write
  @param bufferSize the size of data_buffer
  @return the next available address
uint32_t writePacket(byte data_buffer[], int bufferSize) {
  if (addr%BLOCK_SIZE==0) {
    flash.eraseSector( (addr + BLOCK_SIZE)%capacity);
  flash.writeByte(addr, 0x7F); //flag as started
  flash.writeByteArray(addr+1, data_buffer, bufferSize);
  flash.writeByte(addr, 0x3F); //flag as written
  return (addr + PAGE_SIZE) % capacity;  

  Examines the SerialFlash finds the next empty page. Should
  be called on startup. A reference can then be kept to
  log position.

  @return the next available address
uint32_t getNextAddress() {
    uint32_t ad = search(0,capacity, BLOCK_SIZE, 0x3F);
    return (search(ad, BLOCK_SIZE, PAGE_SIZE, 0x3F)+ PAGE_SIZE)%capacity;

  Examines the first byte in a chunk of flash to determine if 
  page has been written.

  @param from the from address
  @param to the to address
  @param ss the step size, normally BLOCK or PAGE
  @param headermask mask to apply to first byte of PAGE
  @return the next available address
uint32_t search(uint32_t from,uint32_t to, uint32_t  ss, byte headermask) {
  byte lb = 255;//isnt written
  uint32_t pt;
  for ( pt = from; pt<=to;pt=pt+ss) {
    byte b = flash.readByte(pt);   
    if ((b==255) && (~lb & ~headermask)) {
      return pt-ss;
    lb = b;
  //got to the end
  return pt;