[MCU] 分享:沁恒 CH32V103 内置 Flash 延长使用时间及均衡磨损写入

火辣西米秀   2021-10-7 20:04 楼主

       单片机在断电后,RAM 数据区的数据就会全部丢失
  用 MP3 播放器打个比方,如果每次重新开机,都从第一首开始播放,过不了几天,再听到这首歌就会像听到早上的闹钟一样 

  如果想保存当前播放的曲目,下次开机时继续播放,则需要将参数保存在 EEPROM 或者 FLASH 里
  但是,EEPROM 或者 FLASH 可靠吗?

  EEPROM 例如 AT24Cxx 系列,寿命大致为10万次擦写,如果每播放一首,擦写一次 EEPROM,每天20首歌,可以用13年,可以用到过时

  外置 Flash 例如 W25Qxx 系列,基本也能达到10万次擦写寿命
  内置 Flash 则相对比较娇贵了,寿命大致在1万次擦写,使用寿命打折到1年,这。。。

  有什么办法能延长使用时间呢?

  一、减少擦写次数
    每次擦写前先读取,如果数据一致,则没必要再进行擦写
    缓存需要擦写的数据,仅擦写最后的数据,变多次为一次

    使用电池或大电容蓄电,在断电时统一保存数据,这样断电一次,只擦写一次

  二、以空间换时间
    如果频繁擦写不可避免,可以分散对单个存储单元擦写的压力,均衡磨损多个存储单元

 

  举个栗子:


    一双鞋每天穿,可以穿1年,买10双轮流穿,就可以穿10年了吧

  Flash 擦写也是一样,多个区块轮流擦写,这样寿命就可以UpUpUp了 

  以沁恒 CH32V103 为例,芯片兼容 STM32F103 的 1024 字节 Flash 区块擦写,还支持 128 字节的快速擦写模式

  正常存储参数时,先擦除 1 个区块 1024 字节空间,再写入 1 个 unsigned short 或者 unsigned long 参数,即 2~4 字节

  为了延长 Flash 使用时间,我们同样使用 1 个区块 1024 字节空间,在写入 1 个 unsigned long 参数时,判断 Flash 空间是否为空(为 0xFFFFFFFF),如果非空,往后 4 字节判断是否为空,直到找到空的 Flash 空间,如果超出 1024 字节空间还没找到空区间,则擦除整个区块,把参数写在第一个字节空间

  读取参数类似,从第一个空间开始往后读取,找到最后一个非空单元,该单元存储的参数即为最后存的参数

  这样就实现了对该区间的均衡磨损,如果区块大小为 1024 字节,折寿命直接延长为 1024 / 4 字节 = 256倍,够用到退休了

  并且这个 1024 字节区间还可以扩展为 2048 甚至更多,寿命呈倍数增长

  均衡写入代码如下,Addr 参数为内部 Flash 地址,Size 为区块大小,单个参数在这个区块内均衡磨损读写,Data 即为需要写入的数据:

u8 Flash_Balance_WriteU32(u32 Addr, u32 Size, u32 Data)

{

  u8 ret;

  u32 i;

  for(i=0; i<Size; i+=4)

  {

    if(Flash_ReadU32(Addr+i) == 0xffffffff) break;

  }

  if(i >= Size)

  {

    ret = 0;

    for(i=0; i<Size; i+=FLASH_SECTOR_SIZE)

    {

      ret |= Flash_EraseSector(Addr+i);

    }

    ret |= Flash_WriteU32(Addr, Data);

  }

  else

  {

    ret = Flash_WriteU32(Addr+i, Data);

  }

  return ret;

}

均衡读取代码如下:
 

u8 Flash_Balance_ReadU32(u32 Addr, u32 Size, u32 *Data)

{

  u32 i;

  for(i=0; i<Size; i+=4)

  {

    if(Flash_ReadU32(Addr+i) == 0xffffffff) break;

  }

  if(i == 0)

  {

    *Data = 0xffffffff;

    return SR_ERR;

  }

  else

  {

    *Data = Flash_ReadU32(Addr+i-4);

    return SR_OK;

  }

}

 问题一:效率高吗?由于均衡磨损基于查找算法,从头到尾查找,区间大小变大时,需要查找整个区间,查找时间会变多,效率会变低,所以 Size 不能取太大

  解决办法也有很多,前辈们设计了很多查找算法,例如二分法,就能更好的处理大区间查找

  问题二:可靠性高吗?如果在区间满的时候,写入数据,这时候会擦除整个区间,在擦除完成时如果异常断电,则会丢失这个数据

  采用通用擦写操作时,这个问题也会出现,由于 Flash 需要擦除,再写入,所以擦除完还没写入时断电,都会导致数据丢失,这个问题解决办法也有很多,可以使用 EEPROM,不需要擦除就没有这个问题,也可以先备份数据设置标志位,再擦除,再写入,这里就不再扩展

  问题三:可以存多少个数据?理论上 1 个区块存 1 个数据,也可以多个区块存 1 个数据

  如果想 1 个区块存多个数据,甚至存多个可变长度数据例如字符串,可以采用帧头+数据长度+删除标志位+数据的方式进行读写,方法有很多种,这个我也曾经做过,可以一起讨论

  优点一:在未进行擦除前,历史参数可还原

  由于区块未满前,设置的数据依次往后填充区块,所以很容易找的每次设置的参数,知道每次设置都设置了哪些参数

  当然还有上面提到的增加使用时间等优点,由于不用擦除,在一些时候也会减少写入时间。

回复评论 (2)

可以试试 LittleFS

点赞  2021-10-7 20:55
引用: dcexpert 发表于 2021-10-7 20:55 可以试试 LittleFS

值得期待

点赞  2021-10-8 11:54
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复