中微8S6990 EEPROM内容丢失解决记录
问题描述:
问题程序如下:
void temp_remember(uint16_t temperature,uint16_t address_H,uint16_t address_L)
{
uint8_t temp,temp1 = 0;
temp = temperature>>8;
temp1 = temperature;
FLASH_UnLock();
FLASH_Erase_DataArea(address_H);
delay_ms(1);
FLASH_Erase_DataArea(address_L);
delay_ms(1);
FLASH_Write_DataArea(address_H,temp);
FLASH_Write_DataArea(address_L,temp1);
FLASH_Lock();
}
void EEProm_Write(void)
{
FLASH_UnLock();
delay_ms(1);
FLASH_Erase_DataArea(var4_addr);
delay_ms(1);
FLASH_Write_DataArea(var4_addr,0x7F); /* var4_addr -- 0x00 */
FLASH_Lock();
/* temp_air_H -- 0x01 temp_air_L -- 0x02 */
temp_remember(temperature_air,temp_air_H,temp_air_L);
}
理论效果: 按照理论来说,EEPROM的0x00地址会被写入0x7F , 0x01地址会被写入温度高位 , 0x02地址会被写入温度低位.
芯片特性: 数据保存的位置是6990N的数据存储区,中微规格书中标称数据存储区擦写次数可达10万次,大小为1KB,分两页,每页512KB,而Flash空间智能擦写2万次,所以数据存储区更适合作为EEPRom来使用。
现象描述:上面程序选择写入的就是6990N的数据存储区(0x00-0x3FF),将0x7F写入0x00这个地址,实测发现0x00的数据内容始终是0xFF,即没写入内容的状态。找问题找了2个多小时才发现问题之处。
排查过程:
-
发现0x00始终内容为0xFF,但是0x01和0x02地址的数据内容又符合我写入的数据,这是最奇怪的,所以我尝试把这段程序换为这样写:
FLASH_UnLock(); delay_ms(1); FLASH_Erase_DataArea(var4_addr); delay_ms(1); FLASH_Write_DataArea(var4_addr,0x7F); /* var4_addr -- 0x00 */ FLASH_Lock(); //改为以下写法 temp_remember(0x8F7F,0x03,0x04);
观察0x03和0x04的内容是不是8F和7F,但实测发现这两个地址的内容都是0xFF,说明没有写入成功。
-
第一步不成功,智能先把第二段写入EEPROM的程序先注释掉,试试只写入0x00这个地址会有什么效果
FLASH_UnLock(); delay_ms(1); FLASH_Erase_DataArea(var4_addr); delay_ms(1); FLASH_Write_DataArea(var4_addr,0x7F); /* var4_addr -- 0x00 */ FLASH_Lock(); /* temp_air_H -- 0x01 temp_air_L -- 0x02 */ // temp_remember(temperature_air,temp_air_H,temp_air_L);
执行程序之后,读取0x00这个地址惊喜的发现读出来的数据变为 0x7F 了,说明写入成功!
经历了一些更换调用位置、更换写法等不同的试错手段之后,得出基本结论:
FLASH_UnLock();
delay_ms(1);
FLASH_Erase_DataArea(var4_addr);
delay_ms(1);
FLASH_Write_DataArea(var4_addr,0x7F); /* var4_addr -- 0x00 */
FLASH_Lock();
执行了FLASH_Erase_DataArea(var4_addr);
擦除操作之后,FLASH_Write_DataArea(var4_addr,0x7F);
写入了内容,然后FLASH_Lock();
锁上了操作FLASH的一些寄存器的修改标志。
后面紧接着又立刻执行了 FLASH_UnLock();
解锁了操作FLASH的寄存器,并执行了新一轮的擦除FLASH_Erase_DataArea(address_H);
就是后面的这个擦除导致前面调用的FLASH_Write_DataArea(var4_addr,0x7F);
没有执行成功,具体原因不得而知。
中微提供的参考手册写道:
中微提供的参考代码中写道:
FLASH_UnLock();
addr= 0;
Dtemp =0;
FLASH_Erase_DataArea(addr);
for(i = 0 ;i< 256 ;i++) //连续256 bytes的写等待Flash执行完成
{
FLASH_Write_DataArea(0x3ff, 0xFF); //写地址使用最后的地址(任意地址都可以,建议用使用较少的地址)
}
for(addr=0;addr<0x10; addr++)
{
FLASH_Write_DataArea(addr, Dtemp++);
temp = FLASH_Read_DataArea(addr);
}
FLASH_Lock();
并没有提及写入数据后需要做怎样的等待,所以有理由推测上文是写入后与下一次的擦除操作时间太过于接近导致数据还没写入到对应地址的时候,擦除工作已经开始,两个任务的寄存器产生了冲突导致写入失败。(只是推测)
再具体的原因就不继续深究了,在此记录以免下次再次踩坑。中微这款6990N算是个好芯片,价格实惠功能完备,略有一点瑕疵,瑕不掩瑜。
结论:
两次EEPROM的写入程序,中间时间间隔要注意,如果发现前面的内容丢失,而后面的内容正常,那么第一时间检查延时够不够。或者换用另外一种写法,把需要连续调用的擦除写入操作,汇总到一起,统一擦除,擦除后再统一写入。避免擦写、擦写或者是解锁、上锁之间时间太短导致内容丢失。
工作较忙,更新随缘,前面开的一些坑,比如ESP32的学习暂时搁置(学ESP32先要学FreeRTOS,目前处于FreeRTOS学习中)
0827晚更新:
最新结论:
已定位问题点:并非上文提到的延时问题,而是FLASH存储器在写入时是以页为单位,所以任何对FLASH的操作都会导致所有保存的数据全部丢失,如果需要只写某一位,那么用户需要做的是:将不想被修改的数据全部保存起来,修改完想要修改位置的数据之后,再把所有受影响的数据全部写入回FLASH中。
中微参考手册写道:
最后一行: Flash存储器擦除操作仅支持扇区擦除,不支持字节擦除。再修改某个地址的数据之前,建议先将其他数据保存后,再擦除当前扇区,最后进行数据写入操作。
原先是我个人的误解,原先我理解为了擦除CODE区的最小操作单位是扇区,而DATA区的最小单位是字节。所以也是一个乌龙事件。