硬汉嵌入式论坛

 找回密码
 立即注册
查看: 2470|回复: 11
收起左侧

[有问必答] 关于V4例程片内flash读写的一个小BUG

[复制链接]

1

主题

10

回帖

13

积分

新手上路

积分
13
QQ
发表于 2020-7-16 17:51:16 | 显示全部楼层 |阅读模式
本帖最后由 夜歌 于 2020-7-16 17:53 编辑

一个项目中需要保存几个参数在内部,板子是客户的,坑爹的客户板子没有eeprom,好在不是很频繁所以就存在了片内flash里面,使用的安富莱的V4的片内flash例程,其中在写入内容的时候会调用一个函数bsp_CmpCpuFlash对比写入内容和片内存的内容,如果不相等时候判断片内是不是ff如果是表示可以直接写不用擦除,代码如下
  1. ucIsEqu = 1;                        /* 先假设所有字节和待写入的数据相等,如果遇到任何一个不相等,则设置为 0 */
  2.         for (i = 0; i < _ulSize; i++)
  3.         {
  4.                 ucByte = *(uint8_t *)_ulFlashAddr;

  5.                 if (ucByte != *_ucpBuf)
  6.                 {
  7.                         if (ucByte != 0xFF)
  8.                         {
  9.                                 return FLASH_REQ_ERASE;                /* 需要擦除后再写 */
  10.                         }
  11.                         else
  12.                         {
  13.                                 ucIsEqu = 0;        
  14.                         }
  15.                 }

  16.                 _ulFlashAddr++;
  17.                 _ucpBuf++;
  18.         }
复制代码

复制代码
问题就在黑体部分,对应ucIsEqu = 0;        的分支,假如我写入的数据是 aa bb fd 00 内部存的是aa bb ff 00,这时候就会判断写入的内容可以直接写入到芯片内容,实际这个是错误的,因为写入时候同时会把aa bb 在此写入,最后跟踪问题找到了对应的描述,所以在判断数据的时候不能通过一个字节是否为ff来判断是否需要擦除,不然会有问题

flash寄存器描述

flash寄存器描述
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106882
QQ
发表于 2020-7-16 18:06:07 | 显示全部楼层
谢谢楼主分享,如果方便的话,把你修改后的贴上,方便后面也有人咨询了,直接看这个帖子。

主要是F1系列不再维护了,让他们直接看这个帖子方便些。
回复

使用道具 举报

1

主题

10

回帖

13

积分

新手上路

积分
13
QQ
 楼主| 发表于 2020-7-16 18:21:20 | 显示全部楼层
eric2013 发表于 2020-7-16 18:06
谢谢楼主分享,如果方便的话,把你修改后的贴上,方便后面也有人咨询了,直接看这个帖子。

主要是F1系列 ...

我是将8-15行代码只保留第10行,就是只要数据不相等就进行一次擦除,如果要判断是否是ff还需要在扫描是不是全部是ff,我觉得除了第一次写入一片没有写过数据的内存时可能全部是FF,感觉判断有点没太大意义
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106882
QQ
发表于 2020-7-16 18:28:25 | 显示全部楼层
夜歌 发表于 2020-7-16 18:21
我是将8-15行代码只保留第10行,就是只要数据不相等就进行一次擦除,如果要判断是否是ff还需要在扫描是不 ...

好的,强制擦除。
回复

使用道具 举报

1

主题

44

回帖

47

积分

新手上路

积分
47
发表于 2020-7-17 07:17:23 | 显示全部楼层
我觉得原来的代码是有意义的,只是要改成 如果和原来相同,就不再重复写,这样才最好。
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106882
QQ
发表于 2020-7-17 08:26:26 | 显示全部楼层
1847123212 发表于 2020-7-17 07:17
我觉得原来的代码是有意义的,只是要改成 如果和原来相同,就不再重复写,这样才最好。


是这样的,前面讨论的就是这个意思。

我贴下正确的代码,取消掉了一个特例情况,即要填写的Flash地址有部分oxFF的,可以直接改写的情况。


  1. /*
  2. *********************************************************************************************************
  3. *        函 数 名: bsp_CmpCpuFlash
  4. *        功能说明: 比较Flash指定地址的数据.
  5. *        形    参: _ulFlashAddr : Flash地址
  6. *                         _ucpBuf : 数据缓冲区
  7. *                         _ulSize : 数据大小(单位是字节)
  8. *        返 回 值:
  9. *                        FLASH_IS_EQU                0   Flash内容和待写入的数据相等,不需要擦除和写操作
  10. *                        FLASH_REQ_WRITE                1        Flash不需要擦除,直接写
  11. *                        FLASH_REQ_ERASE                2        Flash需要先擦除,再写
  12. *                        FLASH_PARAM_ERR                3        函数参数错误
  13. *********************************************************************************************************
  14. */
  15. uint8_t bsp_CmpCpuFlash(uint32_t _ulFlashAddr, uint8_t *_ucpBuf, uint32_t _ulSize)
  16. {
  17.         uint32_t i;
  18.         uint8_t ucIsEqu;        /* 相等标志 */
  19.         uint8_t ucByte;

  20.         /* 如果偏移地址超过芯片容量,则不改写输出缓冲区 */
  21.         if (_ulFlashAddr + _ulSize > FLASH_BASE_ADDR + FLASH_SIZE)
  22.         {
  23.                 return FLASH_PARAM_ERR;                /* 函数参数错误 */
  24.         }

  25.         /* 长度为0时返回正确 */
  26.         if (_ulSize == 0)
  27.         {
  28.                 return FLASH_IS_EQU;                /* Flash内容和待写入的数据相等 */
  29.         }

  30.         ucIsEqu = 1;                        /* 先假设所有字节和待写入的数据相等,如果遇到任何一个不相等,则设置为 0 */
  31.         for (i = 0; i < _ulSize; i++)
  32.         {
  33.                 ucByte = *(uint8_t *)_ulFlashAddr;

  34.                 if (ucByte != *_ucpBuf)
  35.                 {
  36.                         return FLASH_REQ_ERASE;                /* 需要擦除后再写 */
  37.                 }

  38.                 _ulFlashAddr++;
  39.                 _ucpBuf++;
  40.         }

  41.         if (ucIsEqu == 1)
  42.         {
  43.                 return FLASH_IS_EQU;        /* Flash内容和待写入的数据相等,不需要擦除和写操作 */
  44.         }
  45.         else
  46.         {
  47.                 return FLASH_REQ_WRITE;        /* Flash不需要擦除,直接写 */
  48.         }
  49. }
复制代码


回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106882
QQ
发表于 2020-7-17 08:35:58 | 显示全部楼层
确诊了下,这个是F1的特色啊,F4系列就没有这个要求,也没有这个错误标志
F1:

QQ截图20200717083636.jpg

2.jpg

F407:
3.jpg

F429:
4.jpg



回复

使用道具 举报

2

主题

16

回帖

22

积分

新手上路

积分
22
发表于 2020-7-27 11:02:13 | 显示全部楼层
增加0xffff的判断...
        if (_ulFlashAddr + _ulSize > FLASH_BASE_ADDR + FLASH_SIZE)
        {
                return FLASH_PARAM_ERR;                /* 函数参数错误 */
        }

        /* 长度为0时返回正确 */
        if (_ulSize == 0)
        {
                return FLASH_IS_EQU;                /* Flash内容和待写入的数据相等 */
        }

        ucIsEqu = 1;                        /* 先假设所有字节和待写入的数据相等,如果遇到任何一个不相等,则设置为 0 */
        ucReqErase = 0;              //suppose not require to erase
        for (i = 0; i < _ulSize; i++)
        {
                ucByte = *(uint8_t *)_ulFlashAddr;
             if (ucByte != *_ucpBuf)
                {
                        ucIsEqu = 0;        // 不相等,需要写 //
                }
                if (ucByte != 0xFF)  
                {   
                        ucReqErase = 1;
                }
               
                _ulFlashAddr++;
                _ucpBuf++;
        }

        if (1 == ucIsEqu )
        {
                return FLASH_IS_EQU;        /* Flash内容和待写入的数据相等,不需要擦除和写操作 */
        }
        else if (1 == ucReqErase) //"ucIsEqu == 0" and "ucReqErase == 1"
        {
                return FLASH_REQ_ERASE;
        }
        else   //"ucIsEqu == 0" and "ucReqErase == 0"
        {
                return FLASH_REQ_WRITE;        /* Flash不需要擦除,直接写 */
        }
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106882
QQ
发表于 2020-7-27 11:19:43 | 显示全部楼层
sunwindsz 发表于 2020-7-27 11:02
增加0xffff的判断...
        if (_ulFlashAddr + _ulSize > FLASH_BASE_ADDR + FLASH_SIZE)
        {

这么改貌似有问题。

如果是待写入的和Flash里面已经有的内容相同,你程序里面ucByte != 0xFF会造成需要擦除的情况。
回复

使用道具 举报

2

主题

16

回帖

22

积分

新手上路

积分
22
发表于 2020-7-29 09:17:27 | 显示全部楼层
        if (1 == ucIsEqu )
        {
                return FLASH_IS_EQU;        /* Flash内容和待写入的数据相等,不需要擦除和写操作 */
        }

后面先判断相等就return了, 当然把一开始判断0xff写在判断内容相不相等内部更好理解和严谨
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106882
QQ
发表于 2020-7-29 09:21:59 | 显示全部楼层
sunwindsz 发表于 2020-7-29 09:17
if (1 == ucIsEqu )
        {
                return FLASH_IS_EQU;        /* Flash内容和待 ...

这个判断不太好,6楼的修改更靠谱些。

if (ucByte != 0xFF)  
{   
        ucReqErase = 1;
}
回复

使用道具 举报

2

主题

16

回帖

22

积分

新手上路

积分
22
发表于 2020-7-29 10:06:17 | 显示全部楼层


flash操作,如1楼,第一次写入一片没有写过数据的内存时可能全部是FF, 其他时候基本上是要擦除后再写的。所以判断0xff意义不是很大。  1楼和6楼的方式是实用的。
  
纯属探讨,
6楼的,这段不会执行到。
        else
        {
                return FLASH_REQ_WRITE;        /* Flash不需要擦除,直接写 */
        }



回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-5-9 05:19 , Processed in 0.298509 second(s), 28 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表