闪存实现中的循环缓冲区

Circular buffer in flash implementation

我一直在为嵌入式设备开发数据记录器。目标是存储 以周期性方式将一组变量的值存入外部闪存。 我的想法是在 RAM 中创建一个缓冲区。缓冲区的大小将等于 外部闪存中一个扇区的字节数,即 512 B. 到期后 在规定的时间内,我将用变量的值填充缓冲区,然后 我会把这条记录存入外置闪存。外部闪光灯包含几个 为数据日志存储保留的块。这些块形成一个循环缓冲区 即一旦缓冲区已满,最旧的记录将被覆盖。

我首先想到的是如何识别 循环缓冲区我可以用于实际的记录存储。基于问题Circular Buffer in Flash 我知道我需要在每条记录中附加一个 header 。这个header 应包含一个记录号。

据我理解正确回答问题Circular Buffer in Flash我所知道的数字 应插入记录 header 应大于块数 在为数据日志存储保留的外部闪存中。

为了更好地理解 headers 包含记录号的想法,我有 决定写一个模拟软件在我的电脑上而不是目标 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;
}

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,

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,

根据问题 Circular Buffer in Flash 的回答,我认为最大 header 数量大于闪存中的块总数就足够了。根据我所做的实验,最大 header 数量似乎必须至少是闪存中块总数的两倍。请问谁能告诉我我的最大 header 数的想法是否正确?提前感谢您的任何建议。

鉴于代码中的这一行:

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

部分 & (length - 1) 仅适用于 2 的幂的 length。它实际上是 % length 的优化,仅当 length 为2 的幂。

因此,如果您将 & (length - 1) 部分替换为 % length,那么它应该适用于 9 的长度(或任何其他不是 2 的幂的数字)。

(如果您直接使用 BUFFER_SIZE 而不是将其作为参数传递 length,那么只要 BUFFER_SIZE 是 2 的幂。)