打印
[STM32L4]

写片内Flash有时会失败

[复制链接]
931|7
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
zhenxizhou|  楼主 | 2019-11-29 15:10 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
因为片内FLASH有使用寿命,我们写了个函数:
1、如果目标地址已经写过,先擦除再写
2、如果目标地址没有写过,直接写到目标地址
RetType_t Flash_AdvantageWrite(uint32_t address, uint16_t * buf, uint32_t bytenum)
{  
        uint8_t needErase = 0;
        HAL_StatusTypeDef status = HAL_OK;
        uint16_t *addp = NULL;
        uint32_t tadd = (address-address%FLASHPAGESIZE);
        int i;
        uint32_t FirstPage = 0, NbOfPages = 0, BankNumber = 0;
        uint32_t PAGEError = 0;
        FLASH_EraseInitTypeDef EraseInitStruct;
        uint64_t data_64_A = 0,data_64_B = 0,data_64_C = 0,data_64_D = 0;
        uint32_t startCheckAddr, endCheckAddr;
        uint16_t byteNum;

        Voice_WaitEnd();
        FeedDog();

        _say_("FlashWrite:address=0x%x,bytenum=%d\r\n", address, bytenum);

        if ((address%FLASHPAGESIZE+bytenum) > FLASHPAGESIZE)
        {
                _say_("Exceed limit:address=0x%x,bytenum=0x%x\r\n", address, bytenum);
                return RET_EXCEED_LIMIT;
        }

        memset(g_flagpagebuf, 0xff, FLASHPAGESIZE);
       
        //判断需要写的区域是否已经写过,并更新标志位
        startCheckAddr = address - address % 8;
        endCheckAddr = address + bytenum;
        if (endCheckAddr % 8 != 0)
        {
                endCheckAddr += 8 - (endCheckAddr % 8);
        }
        for (i = startCheckAddr; i < endCheckAddr; i += 2)
        {
                addp = (uint16_t *)i;
                if (*addp != FLASH_DEFAULT_HALFWORD)
                {
                        needErase = 1;
                        _say_("Writed,need to erase!\r\n");
                        break;
                }
        }

        // 如果需要写的区域已经被写过,需要把数据全部读出,更新后重新写入
        if (needErase == 1)
        {
                addp = (uint16_t *)(address-address%FLASHPAGESIZE);// 当前页首地址

                _memcpy(g_flagpagebuf,addp,FLASHPAGESIZE);//读出数据到g_flagpagebuf

                HAL_FLASH_Unlock();
                __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPTVERR);

                /* Get the 1st page to erase */
                FirstPage = GetPage(address);
                /* Get the number of pages to erase from 1st page */
                NbOfPages = 1;
                /* Get the bank */
                BankNumber = GetBank(address);
                /* Fill EraseInit structure*/
                EraseInitStruct.TypeErase   = FLASH_TYPEERASE_PAGES;
                EraseInitStruct.Banks       = BankNumber;
                EraseInitStruct.Page        = FirstPage;
                EraseInitStruct.NbPages     = NbOfPages;

                status = HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError);
                if (status != HAL_OK)
                {
                        HAL_FLASH_Lock();
                        _say_("Fail to Erase!\r\n");
                        return RET_ERASE_FLASH_ERROR;
                }

                memcpy(g_flagpagebuf+(address%FLASHPAGESIZE)/2,buf,bytenum);// 更新buf数据

                // 将数据写回
                for (i = 0; i < FLASHPAGESIZE/8; tadd += 8, i++)
                {
                        data_64_A = g_flagpagebuf[i*4+0];
                        data_64_B = g_flagpagebuf[i*4+1];
                        data_64_C = g_flagpagebuf[i*4+2];
                        data_64_D = g_flagpagebuf[i*4+3];
                        status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, tadd, data_64_A+(data_64_B<<16)+(data_64_C<<32)+(data_64_D<<48));
                        if (status != HAL_OK)
                        {
                                _say_("FLASH program fail(page),status=%d,i=%d\r\n", status, i);
                                break;
                        }                               
                }               
        }
        else // 如果需要写的区域没有被写过,直接将数据写入
        {
                /*必须保证address是2字节的倍数*/
                HAL_FLASH_Unlock();
                __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPTVERR);
                //SET_BIT(FLASH->CR, 1 << 27);
                memcpy(g_flagpagebuf+(address%8)/2,buf,bytenum);
                tadd = address - address % 8;
                byteNum = bytenum + address % 8;
                if (byteNum % 8 != 0)
                {
                        byteNum += 8 - (byteNum % 8);
                }
                _say_("tadd=0x%x, byteNum=%d\r\n", tadd, byteNum);
                for (i = 0; i < byteNum/8; tadd += 8, i++)
                {
                        data_64_A = g_flagpagebuf[i*4+0];
                        data_64_B = g_flagpagebuf[i*4+1];
                        data_64_C = g_flagpagebuf[i*4+2];
                        data_64_D = g_flagpagebuf[i*4+3];
                        status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, tadd, data_64_A+(data_64_B<<16)+(data_64_C<<32)+(data_64_D<<48));                        
                        if (status != HAL_OK)
                        {
                                uint32_t data1, data2;
                                _say_("Program %d Dword fail,status=%d\r\n", i, status);
                                data1 = *(uint32_t*)tadd;
                                data2 = *(uint32_t*)(tadd+4);
                                _say_("data1=0x%X,data2=0x%X\r\n", data1, data2);
                                break;
                        }
                }
        }

        HAL_FLASH_Lock();
        FeedDog();

        return (status != HAL_OK) ? RET_WRITE_FLASH_ERROR : RET_OK;
}
先对整个页进行擦除,然后进行读写操作,测试中发现:
1、对于已经写过数据的先擦除再写没问题
2、对没有写过的写数据时有时会出错。
出错的地方在FLASH_WaitForLastOperation中,
error = (FLASH->SR & FLASH_FLAG_SR_ERRORS);
状态寄存器被置上了FLASH_SR_PEMPTY
请问各位大大什么情况下状态寄存器会被置上这个值?
有没有解决方案或规避方案?
谢谢

使用特权

评论回复
沙发
xinpian101| | 2019-11-29 21:24 | 只看该作者
不清楚,不知道这给是什么原因,测试了两块都这样吗

使用特权

评论回复
板凳
xinpian101| | 2019-11-29 21:24 | 只看该作者
先排除不是硬件的单一问题。然后确认是软件没有搞对的问题。

使用特权

评论回复
地板
观海| | 2019-12-11 14:12 | 只看该作者
每次都会失败吗

使用特权

评论回复
5
八层楼| | 2019-12-11 14:13 | 只看该作者
供电电压稳定吗

使用特权

评论回复
6
晓伍| | 2019-12-11 14:16 | 只看该作者
是不是时许有问题

使用特权

评论回复
7
磨砂| | 2019-12-11 14:18 | 只看该作者
出错时候的flash地址是定值吗

使用特权

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

本版积分规则

37

主题

76

帖子

2

粉丝