打印
[RISC-V MCU 创新应用比赛]

沁恒 CH32V103 内置 Flash 延长使用时间,均衡磨损写入

[复制链接]
27344|8
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
gtbestom|  楼主 | 2021-9-27 10:34 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
#申请原创# @21小跑堂

  单片机在断电后,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 个区块存多个数据,甚至存多个可变长度数据例如字符串,可以采用帧头+数据长度+删除标志位+数据的方式进行读写,方法有很多种,这个我也曾经做过,可以一起讨论

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

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

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

使用特权

评论回复

相关帖子

沙发
xxxxyc| | 2021-9-28 15:08 | 只看该作者
原来是这样啊

使用特权

评论回复
板凳
linzl000| | 2021-9-28 15:19 | 只看该作者
学习了

使用特权

评论回复
地板
数码小叶| | 2021-9-29 13:50 | 只看该作者
之前看过ST的均衡擦写算法,原理基本上都差不多,但是感觉pcb有面积的情况下,还是外置 Flash比较靠谱,成本差距不大

使用特权

评论回复
5
6552918| | 2021-9-30 10:10 | 只看该作者
学习了!

使用特权

评论回复
6
hui223| | 2021-10-4 21:14 | 只看该作者
可以在滿數據之前,擦除一個足夠存儲的空間,先存儲後擦除,保證存儲及時性

使用特权

评论回复
7
NJZR| | 2021-10-5 22:24 | 只看该作者
写得不错!不过要更正一个小问题,二十年前主流EEPROM厂家保证的擦写寿命就已经是百万次了,实际测试结果整片基本都在两百万次以上才开始出现坏位,不是楼主说的与主流FLASH同样的十万次。

使用特权

评论回复
8
飞思啦| | 2021-10-9 10:15 | 只看该作者
以前还没注意到过擦写问题

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

19

主题

106

帖子

0

粉丝