打印
[STM32F0]

[学习笔记]读《EEPROM emulation in STM32F0xx microcontrolles》BUG修正[

[复制链接]
1515|2
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 sky.sun.zz 于 2018-12-19 22:06 编辑

       读《EEPROM emulation in STM32F0xx microcontrolles》一个BUG的修正
    项目开发时需要在STM32F051断电前保存少量变量数据,于是在STM32中文官网找到《EEPROM emulation in STM32F0xx microcontrolles》这篇应用笔记。学习这篇应用笔记让我收益匪浅。它把STM32F0xx的内部Flash的2个页拿来仿真EEPROM,解决了低成本产品无需外挂eeprom断电保存数据的难题。
    这个仿真EEPROM的构思实在巧妙,它为每一个要保存的数据预先设置一个16位虚拟地址,紧跟一个16位变量数据。当写入一个新数据时,只需重新写一次该数据的虚拟地址,接着写入新的数据即可。旧的数据作废,直到本页写满。读数据时搜索最后一次写入的地址,就能读出最新的数据。无需整页Flash都删除再写入,大大提高了Flash的读写寿命。本项目开发使用这个EEPROM仿真是优选的方案。


    到 https://www.stmcu.com.cn/Designresource/design_resource_detail?file_name=STSW_STM32117_STM32F0xx%E5%BE%AE%E6%8E%A7%E5%88%B6%E5%99%A8%E4%B8%AD%E7%9A%84EEPROM%E4%BB%BF%E7%9C%9F&lang=EN&ver=1.0.0
下载了“STSW_STM32117_STM32F0xx微控制器中的EEPROM仿真”固件包。这个固件包演示了在仿真EEPROM的页里对VarData[0]、VarData[1]、VarData[2]写入数据,然后读出。

for (VarValue = 1; VarValue <= 0x64; VarValue++)
  {    EE_WriteVariable(VirtAddVarTab[0], VarValue);
  }
再读出。
  EE_ReadVariable(VirtAddVarTab[0], &VarDataTab[0]);
  for (VarValue = 1; VarValue <= 0xC8; VarValue++)
  {    EE_WriteVariable(VirtAddVarTab[1], VarValue);
  }
  EE_ReadVariable(VirtAddVarTab[0], &VarDataTab[0]);
  EE_ReadVariable(VirtAddVarTab[1], &VarDataTab[1]);
  for (VarValue = 1; VarValue <= 0x1C2; VarValue++)
  {    EE_WriteVariable(VirtAddVarTab[2], VarValue);
  }
  EE_ReadVariable(VirtAddVarTab[0], &VarDataTab[0]);
  EE_ReadVariable(VirtAddVarTab[1], &VarDataTab[1]);
  EE_ReadVariable(VirtAddVarTab[2], &VarDataTab[2]);
     在NUCLEO开发板上运行演示代码进行评估验证,仿真EEPROM的数据写入读出都正确,放心移植到目标板了。

     不料,目标板调试过程中发现,只要断电,再上电后读出的数据就不是断电前写入的数据了。排除硬件故障的可能性后,接下来是判断是写出错还是读出错。这片STM32F051C6T6的Flash长度为32KB,我照抄演示文件中的代码,将第8和第9扇区设置用来仿真EEPROM,它的每页长为0x400,地址从0x08002000到0x080027FF。使用STM32 ST-LINK Utility工具读该扇区,Flash已经正确写入。判断故障在读操作。
先查阅STM32F0xx的eeprom.h,其中有:
#define PAGE_SIZE             ((uint32_t)0x0400)  
#define EEPROM_START_ADDRESS ((uint32_t)0x08002000)
这里定义:#defineEEPROM_START_ADDRESS ((uint32_t)0x08002000)

再查阅STM32F0xx的 eeprom.c:
uint16_t EE_ReadVariable(uint16_t VirtAddress, uint16_t* Data)
{  uint16_t ValidPage = PAGE0;
  uint16_t AddressValue = 0x7777, ReadStatus = 1;
  uint32_t Address = 0x08001000, PageStartAddress = 0x08001000;
}
    这里地址的分配是这样安排的:
uint32_t Address= 0x08001000, PageStartAddress = 0x08001000;
这个EEPROM emulation in STM32F0xx是从EEPROM emulation in STM32F10xx移植过来的。于是查阅F1系列相关的文件,

STM32F10xx 的eeprom.h是这样的:
#define EEPROM_START_ADDRESS    ((uint32_t)0x08010000) 
STM32F10xx的 eeprom.c是这样的:
uint16_t EE_ReadVariable(uint16_t VirtAddress, uint16_t* Data)
{  uint16_t ValidPage = PAGE0;
  uint16_t AddressValue = 0x5555, ReadStatus = 1;
  uint32_t Address =0x08010000, PageStartAddress =0x08010000;
}

      ST工程师在移植F1仿真EEPROM到F0仿真EEPROM时,忘记把F0的eeprom.h和eeprom.c文件里关于仿真Flash页的地址修改一致:
在F051写入的首地址是0x08002000,而读出的首地址则在0x08001000。从而导致读数据的地址不是写入数据的地址——读出错。
修改eeprom.c代码:
uint32_t Address= 0x08002000, PageStartAddress = 0x08002000;
故障排除。
    那为何在用nucleo进行评估验证时却读写正常呢?下载有BUG的原代码进行跟踪调试可知:由于读地址与写地址不符,进入读函数后当判断地址不符,就执行return了。根本就没有读数据。而恰好在演示代码中写完Flash后数组变量没有清空,在读出错return后,数组变量里保留着写操作留下的残余,让你误以为读写正常。
这个F0里的BUG,也希望ST工程师能纠正。



沙发
Dick Hou| | 2018-12-20 17:24 | 只看该作者
不错

使用特权

评论回复
板凳
sky.sun.zz|  楼主 | 2018-12-20 21:22 | 只看该作者
本帖最后由 sky.sun.zz 于 2018-12-21 07:23 编辑

谢谢楼上的鼓励

使用特权

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

本版积分规则

41

主题

732

帖子

13

粉丝