C - 在闪存中存储全局变量?

C - Store global variables in flash?

正如标题所暗示的,我目前在我的程序中缺少 SRAM,我找不到减少全局变量的方法。是否可以将全局变量带到闪存中?由于这些变量是频繁读取和写入的,因此nand flash是否会因为它们的read/write循环次数有限而对nand flash不利?

如果闪光灯无法解决这个问题,EEPROM 会是一个不错的选择吗?

编辑: 对不起,模棱两可的家伙。我正在使用 Atmel AVR ATmega32HVB,它具有: 2K字节的SRAM, 1K字节的EEPROM 32K字节的FLASH

编译器:AVR C/C++

平台:IAR 嵌入式 AVR

我要去掉的全局变量是:

uint32_t capacityInCCAccumulated[TOTAL_CELL];

int32_t AccumulatedCCADCvalue[TOTAL_CELL]; 

代码片段:

  int32_t AccumulatedCCADCvalue[TOTAL_CELL];
    void CCGASG_AccumulateCCADCMeasurements(int32_t ccadcMeasurement, uint16_t slowRCperiod)
{ 
    uint8_t cellIndex;
    // Sampling period dependant on configuration of CCADC sampling..
    int32_t temp = ccadcMeasurement * (int32_t)slowRCperiod;

    bool polChange = false;
    if(temp < 0) {
        temp = -temp;
        polChange = true;
    }

    // Add 0.5*divisor to get proper rounding
    temp += (1<<(CCGASG_ACC_SCALING-1));
    temp >>= CCGASG_ACC_SCALING;

    if(polChange) {
        temp = -temp;
    }
    for (cellIndex = 0; cellIndex < TOTAL_CELL; cellIndex++)
    {
        AccumulatedCCADCvalue[cellIndex] += temp;
    }

    // If it was a charge, update the charge cycle counter
    if(ccadcMeasurement <= 0) {
        // If it was a discharge, AccumulatedCADCvalue can be negative, and that
        // is "impossible", so set it to zero
        for (cellIndex = 0; cellIndex < TOTAL_CELL; cellIndex++)
        {
            if(AccumulatedCCADCvalue[cellIndex] < 0) 
            {
                AccumulatedCCADCvalue[cellIndex] = 0;
            }
        }
    }   
}

还有这个

uint32_t capacityInCCAccumulated[TOTAL_CELL];
void BATTPARAM_InitSramParameters() {
        uint8_t cellIndex;
        // Active current threshold in ticks
    battParams_sram.activeCurrentThresholdInTicks = (uint16_t) BATTCUR_mA2Ticks(battParams.activeCurrentThreshold);

        for (cellIndex = 0; cellIndex < TOTAL_CELL; cellIndex++) 
        {
    // Full charge capacity in CC accumulated
            battParams_sram.capacityInCCAccumulated[cellIndex] = (uint32_t) CCGASG_mAh2Acc(battParams.fullChargeCapacity);
    }
    // Terminate discharge limit in CC accumulated
    battParams_sram.terminateDischargeLimit = CCGASG_mAh2Acc(battParams.terminateDischargeLimit);

    // Values for remaining capacity calibration
    GASG_CalculateRemainingCapacityValues();
}

would it be bad for the nand flash because they have limited number of read/write cycle?

是的,频繁修改数据时使用闪存不是一个好主意。 只读闪存不会减少闪存的使用寿命。擦写会减少flash的寿命。

与传统内存相比,从闪存读取和写入速度要慢得多。

要写入一个字节,必须擦除整个块并重新写入闪存。

任何类型的 Flash 都不是用于频繁更改值的好主意:

  • erase/write 循环次数有限,请参阅数据表。
  • 非常慢 erase/write(擦除大约需要 1 秒),请参阅数据表。
  • 您需要一个特殊的顺序来先擦后写(无语言支持)。
  • 虽然最多阻止对闪存的擦除或写入访问,但有些要求根本不访问闪存(未定义的行为)。
  • 闪存单元不能自由写入per-byte/word。大多数必须按页写入(例如 64 字节)并以更大的单位擦除大部分时间 (segments/blocks/sectors)。

对于NAND Flash来说,与NOR Flash相比,耐久性更差,而且单元的可靠性也更差(位可能偶尔会翻转或有缺陷),所以你必须添加错误检测和纠正。这很可能是你不应该去的方向。

真正的 EEPROM 共享大多数问题,但它们可能被写入 byte/word-wise(内部擦除)。

请注意,现代 MCU 集成 "EEPROM" 大多数时候也是闪存。一些实现只是使用稍微更可靠的单元(比程序闪存多 erase/write 周期大约十年)和允许任意 byte/word 写入(自动擦除)的额外硬件。但这对于频繁更改仍然不够。

但是,您首先应该验证您的应用程序是否可以容忍如此长的 write/erase 次。你能接受一个阻塞那么长时间的进程,或者相应地重写你的程序吗?如果答案是"no",你甚至应该停止对该方向的进一步调查。否则,您应该计算预期生命周期内的更新次数,并与数据表中的信息进行比较。也有减少擦除次数的方法,但是太过分了。

如果可以选择外部设备 (I2C/SPI),则可以使用串行 SRAM。尽管更好(并且可能更便宜)的方法是更大的 MCU 或考虑更有效(即更少的 RAM,更多的代码)的方法来将数据存储在 SRAM 中。