Circular buffer in flash implementation
Asked Answered
M

1

0

I have been working on data logger for an embedded device. The goal is to store values of a set of variables in periodic manner into the external flash memory. My idea is to create a buffer in RAM. Size of the buffer will be equal to the number of bytes in one sector in the external flash i.e. 512 B. After expiration of prescribed time I will fill the buffer with values of the variables and then I will store this record into the external flash. External flash contains several blocks reserved for the data logs storage. These blocks form a circular buffer i.e. as soon as the buffer is full the oldest records will be overwritten.

First thing I have been thinking about is how to recognize what block in the circular buffer I can use for actual record storage. Based on the question Circular Buffer in Flash I have understood that I need to append a header into each record. This header shall contain a record number.

As far as I understand correctly answer to the question Circular Buffer in Flash the number which I shall insert into the record header should be greater than the number of blocks in the external flash which are reserved for the data logs storage.

For better understanding the idea with headers containing record numbers I have decided to write a simulation software for testing on my pc instead of the target MCU.

#define BUFFER_SIZE     8
#define NONE_INDEX      BUFFER_SIZE
#define ERASED_BYTE     0x00


unsigned char buffer[BUFFER_SIZE];

void PrintBuffer(unsigned char *buffer){
    for(unsigned char index = 0; index < BUFFER_SIZE; index++){
        std::cout << std::setw(3);      // 3 digits
        std::cout << showbase << dec;   // in decimal
        std::cout << (unsigned short)*(buffer + index) << ", ";
    }
    std::cout << "\n";
}

void ClearBuffer(unsigned char *buffer, unsigned char length){
    for(unsigned char index = 0; index < length; index++){
        *(buffer + index) = ERASED_BYTE;
    }
}

void Insert2Buffer(unsigned char *buffer, unsigned char elem, unsigned char pos){
    *(buffer + pos) = elem;
}

unsigned char FindPosInBuffer(unsigned char *buffer, unsigned char length){

    unsigned char curr_hdr;
    unsigned char next_hdr;
    unsigned char retval = NONE_INDEX; // non-existent index

    unsigned char index;
    unsigned char next_index;

    // searching for erased byte
    for(index = 0; index < length; index++){
        curr_hdr = *(buffer + index);
        if(curr_hdr == ERASED_BYTE){
            retval = index;
            break;
        }
    } 

    // erased byte does not exist - buffer is full i.e. free position is the
    // position where a discontinuity in record headers numbers occurs
    if(retval == NONE_INDEX){
        for(index = 0; index < length; index++){
           curr_hdr   = *(buffer + index);

           next_index = ((index + 1) & (length - 1)); // indices 0 ... 7
           next_hdr   = *(buffer + next_index);

           if((curr_hdr + 1) != next_hdr){
               retval = next_index;
               break;
           }
        }
    }

    return retval;
}

/*
 * 
 */
int main(int argc, char** argv) {

    unsigned char free_pos;
    unsigned char elem = 1;

    ClearBuffer(buffer, BUFFER_SIZE);
    PrintBuffer(buffer);

    // inserting into buffer
    for(unsigned short insert = 0; insert < 64; insert++){
        free_pos = FindPosInBuffer(buffer, BUFFER_SIZE);
        Insert2Buffer(buffer, elem, free_pos);
        elem++;
        // headers 1 ... 16
        if(elem == 17){
            elem = 1;
        }
        // headers 1 ... 9 - does not work
        //if(elem == 10){
        //    elem = 1;
        //}

        PrintBuffer(buffer);
    }

    return 0;
}

Output for headers 1 ... 16:

  0,   0,   0,   0,   0,   0,   0,   0, 
  1,   0,   0,   0,   0,   0,   0,   0, 
  1,   2,   0,   0,   0,   0,   0,   0, 
  1,   2,   3,   0,   0,   0,   0,   0, 
  1,   2,   3,   4,   0,   0,   0,   0, 
  1,   2,   3,   4,   5,   0,   0,   0, 
  1,   2,   3,   4,   5,   6,   0,   0, 
  1,   2,   3,   4,   5,   6,   7,   0, 
  1,   2,   3,   4,   5,   6,   7,   8, 
  9,   2,   3,   4,   5,   6,   7,   8, 
  9,  10,   3,   4,   5,   6,   7,   8, 
  9,  10,  11,   4,   5,   6,   7,   8, 
  9,  10,  11,  12,   5,   6,   7,   8, 
  9,  10,  11,  12,  13,   6,   7,   8, 
  9,  10,  11,  12,  13,  14,   7,   8, 
  9,  10,  11,  12,  13,  14,  15,   8, 
  9,  10,  11,  12,  13,  14,  15,  16, 
  1,  10,  11,  12,  13,  14,  15,  16, 
  1,   2,  11,  12,  13,  14,  15,  16, 
  1,   2,   3,  12,  13,  14,  15,  16, 
  1,   2,   3,   4,  13,  14,  15,  16, 
  1,   2,   3,   4,   5,  14,  15,  16, 
  1,   2,   3,   4,   5,   6,  15,  16, 
  1,   2,   3,   4,   5,   6,   7,  16, 
  1,   2,   3,   4,   5,   6,   7,   8, 
  9,   2,   3,   4,   5,   6,   7,   8, 
  9,  10,   3,   4,   5,   6,   7,   8, 
  9,  10,  11,   4,   5,   6,   7,   8, 
  9,  10,  11,  12,   5,   6,   7,   8, 
  9,  10,  11,  12,  13,   6,   7,   8, 
  9,  10,  11,  12,  13,  14,   7,   8, 
  9,  10,  11,  12,  13,  14,  15,   8, 
  9,  10,  11,  12,  13,  14,  15,  16, 
  1,  10,  11,  12,  13,  14,  15,  16, 
  1,   2,  11,  12,  13,  14,  15,  16, 
  1,   2,   3,  12,  13,  14,  15,  16, 
  1,   2,   3,   4,  13,  14,  15,  16, 
  1,   2,   3,   4,   5,  14,  15,  16, 
  1,   2,   3,   4,   5,   6,  15,  16, 
  1,   2,   3,   4,   5,   6,   7,  16, 
  1,   2,   3,   4,   5,   6,   7,   8, 
  9,   2,   3,   4,   5,   6,   7,   8, 
  9,  10,   3,   4,   5,   6,   7,   8, 
  9,  10,  11,   4,   5,   6,   7,   8, 
  9,  10,  11,  12,   5,   6,   7,   8, 
  9,  10,  11,  12,  13,   6,   7,   8, 
  9,  10,  11,  12,  13,  14,   7,   8, 
  9,  10,  11,  12,  13,  14,  15,   8, 
  9,  10,  11,  12,  13,  14,  15,  16, 
  1,  10,  11,  12,  13,  14,  15,  16, 
  1,   2,  11,  12,  13,  14,  15,  16, 
  1,   2,   3,  12,  13,  14,  15,  16, 
  1,   2,   3,   4,  13,  14,  15,  16, 
  1,   2,   3,   4,   5,  14,  15,  16, 
  1,   2,   3,   4,   5,   6,  15,  16, 
  1,   2,   3,   4,   5,   6,   7,  16, 
  1,   2,   3,   4,   5,   6,   7,   8, 
  9,   2,   3,   4,   5,   6,   7,   8, 
  9,  10,   3,   4,   5,   6,   7,   8, 
  9,  10,  11,   4,   5,   6,   7,   8, 
  9,  10,  11,  12,   5,   6,   7,   8, 
  9,  10,  11,  12,  13,   6,   7,   8, 
  9,  10,  11,  12,  13,  14,   7,   8, 
  9,  10,  11,  12,  13,  14,  15,   8, 
  9,  10,  11,  12,  13,  14,  15,  16,

Output for headers 1 ... 9:

  0,   0,   0,   0,   0,   0,   0,   0, 
  1,   0,   0,   0,   0,   0,   0,   0, 
  1,   2,   0,   0,   0,   0,   0,   0, 
  1,   2,   3,   0,   0,   0,   0,   0, 
  1,   2,   3,   4,   0,   0,   0,   0, 
  1,   2,   3,   4,   5,   0,   0,   0, 
  1,   2,   3,   4,   5,   6,   0,   0, 
  1,   2,   3,   4,   5,   6,   7,   0, 
  1,   2,   3,   4,   5,   6,   7,   8, 
  9,   2,   3,   4,   5,   6,   7,   8, 
  9,   1,   3,   4,   5,   6,   7,   8, 
  9,   2,   3,   4,   5,   6,   7,   8, 
  9,   3,   3,   4,   5,   6,   7,   8, 
  9,   4,   3,   4,   5,   6,   7,   8, 
  9,   5,   3,   4,   5,   6,   7,   8, 
  9,   6,   3,   4,   5,   6,   7,   8, 
  9,   7,   3,   4,   5,   6,   7,   8, 
  9,   8,   3,   4,   5,   6,   7,   8, 
  9,   9,   3,   4,   5,   6,   7,   8, 
  9,   1,   3,   4,   5,   6,   7,   8, 
  9,   2,   3,   4,   5,   6,   7,   8, 
  9,   3,   3,   4,   5,   6,   7,   8, 
  9,   4,   3,   4,   5,   6,   7,   8, 
  9,   5,   3,   4,   5,   6,   7,   8, 
  9,   6,   3,   4,   5,   6,   7,   8, 
  9,   7,   3,   4,   5,   6,   7,   8, 
  9,   8,   3,   4,   5,   6,   7,   8, 
  9,   9,   3,   4,   5,   6,   7,   8, 
  9,   1,   3,   4,   5,   6,   7,   8, 
  9,   2,   3,   4,   5,   6,   7,   8, 
  9,   3,   3,   4,   5,   6,   7,   8, 
  9,   4,   3,   4,   5,   6,   7,   8, 
  9,   5,   3,   4,   5,   6,   7,   8, 
  9,   6,   3,   4,   5,   6,   7,   8, 
  9,   7,   3,   4,   5,   6,   7,   8, 
  9,   8,   3,   4,   5,   6,   7,   8, 
  9,   9,   3,   4,   5,   6,   7,   8, 
  9,   1,   3,   4,   5,   6,   7,   8, 
  9,   2,   3,   4,   5,   6,   7,   8, 
  9,   3,   3,   4,   5,   6,   7,   8, 
  9,   4,   3,   4,   5,   6,   7,   8, 
  9,   5,   3,   4,   5,   6,   7,   8, 
  9,   6,   3,   4,   5,   6,   7,   8, 
  9,   7,   3,   4,   5,   6,   7,   8, 
  9,   8,   3,   4,   5,   6,   7,   8, 
  9,   9,   3,   4,   5,   6,   7,   8, 
  9,   1,   3,   4,   5,   6,   7,   8, 
  9,   2,   3,   4,   5,   6,   7,   8, 
  9,   3,   3,   4,   5,   6,   7,   8, 
  9,   4,   3,   4,   5,   6,   7,   8, 
  9,   5,   3,   4,   5,   6,   7,   8, 
  9,   6,   3,   4,   5,   6,   7,   8, 
  9,   7,   3,   4,   5,   6,   7,   8, 
  9,   8,   3,   4,   5,   6,   7,   8, 
  9,   9,   3,   4,   5,   6,   7,   8, 
  9,   1,   3,   4,   5,   6,   7,   8, 
  9,   2,   3,   4,   5,   6,   7,   8, 
  9,   3,   3,   4,   5,   6,   7,   8, 
  9,   4,   3,   4,   5,   6,   7,   8, 
  9,   5,   3,   4,   5,   6,   7,   8, 
  9,   6,   3,   4,   5,   6,   7,   8, 
  9,   7,   3,   4,   5,   6,   7,   8, 
  9,   8,   3,   4,   5,   6,   7,   8, 
  9,   9,   3,   4,   5,   6,   7,   8, 
  9,   1,   3,   4,   5,   6,   7,   8,

Based on the answer to the question Circular Buffer in Flash I thought that it is suficient to have the maximal header number greater than total number of blocks in flash. Based on the experiments I have done it seems that the maximal header number has to be at least double of total number of blocks in flash. Please can anybody tell me whether my idea with maximal header number is correct? Thanks in advance for any suggestions.

Masonite answered 2/1, 2019 at 9:34 Comment(0)
F
1

Given this line in the code:

next_index = ((index + 1) & (length - 1)); // indices 0 ... 7

The part & (length - 1) only works for a length that is a power of 2. It is effectively an optimisation of % length that is valid only if length is a power of 2.

So if you replace the & (length - 1) part with % length, then it should work for a length of 9 (or any other number that isn't a power of 2).

(If you use BUFFER_SIZE directly rather than passing it as parameter length, then the compiler will most likely optimise % length to the equivalent & (length - 1) whenever BUFFER_SIZE is a power of 2.)

Fillin answered 3/1, 2019 at 11:45 Comment(1)
Thank you for your reaction. I think that I have just found the cause of my problems. The problem is in this conditional statement if((curr_hdr + 1) != next_hdr). The curr_hdr has to be incremented modulo 9.Masonite

© 2022 - 2024 — McMap. All rights reserved.