打印
[STM32L4]

HAL_FLASH_Program写数据失败问题

[复制链接]
3500|7
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
zhenxizhou|  楼主 | 2020-10-12 17:18 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
STM32L431每次对Flash的操作是八字节对齐,如果我每次以八字节对齐写数据,没问题,对一个扇区只需擦除一次。
但如果是每次4字节写,则写第3个4字节的时候会失败。
我的操作如下,先擦除这个扇区,然后从0x801c000开始,第一个4字节写0x11223344, 第二个4字节写0x44332211, 如此往复

第一个4字节写入成功
Flash_Test,i=0
<     28448>FlashWrite:address=0x801c000,bytenum=4
<     28452>startCheckAddr=0x801c000,endCheckAddr=0x801c008
<     28457>tadd=0x801c000, byteNum=8
11223344 ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff

第2个4字节,因为写操作是八个字节对齐,所以先要擦除这个扇区,写入成功
Flash_Test,i=4
<     28862>FlashWrite:address=0x801c004,bytenum=4
<     28867>Writed,need to erase!
<     28870>startCheckAddr=0x801c000,endCheckAddr=0x801c008
11223344 44332211 ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff

第3个4个字节,因为全是1,所以直接写,但是失败
Flash_Test,i=8
<     29300>FlashWrite:address=0x801c008,bytenum=4
<     29305>startCheckAddr=0x801c008,endCheckAddr=0x801c010
<     29310>tadd=0x801c008, byteNum=8
ERROR=0xa8, error=0xa8
<     29316>Program 0 Dword fail,status=1
<     29319>data1=0xFFFFFFFF,data2=0xFFFFFFFF
11223344 44332211 ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff

0xa8对应的错误是FLASH_FLAG_PROGERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGSERR,为什么此时0x801c008开始的FLASH地址都是1,但是写数据却失败,可能是什么原因

使用特权

评论回复
沙发
香水城| | 2020-10-12 17:47 | 只看该作者
你都知道了,每次FLASH编程要按双字来操作,要始终遵循双字对齐。

STM32L4系列内部FLASH双字编程示例

使用特权

评论回复
板凳
zhenxizhou|  楼主 | 2020-10-13 11:19 | 只看该作者
香水城 发表于 2020-10-12 17:47
你都知道了,每次FLASH编程要按双字来操作,要始终遵循双字对齐。

STM32L4系列内部FLASH双字编程示例 ...

写失败的时候也是凑足八个字节,八字节对齐写的。
我又做了个试验:
void Flash_Test(void)
{
        uint32_t startAddr = 0x0801C000;
        HAL_StatusTypeDef status;
        FLASH_EraseInitTypeDef EraseInitStruct;
        uint32_t pageErr;

        printf("erase one page\r\n");
        /*erase one page*/
        HAL_FLASH_Unlock();
        __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPTVERR);
        EraseInitStruct.TypeErase   = FLASH_TYPEERASE_PAGES;
        EraseInitStruct.Banks       = GetBank(startAddr);
        EraseInitStruct.Page        = GetPage(startAddr);
        EraseInitStruct.NbPages     = 1;
        status = HAL_FLASHEx_Erase(&EraseInitStruct, &pageErr);
        HAL_FLASH_Lock();
        if (status != HAL_OK)
                return;

        printf("before write 0xff to one page\r\n");
        for (int i = 0; i < 2048; i += 4)
        {
                printf("%x ", *(volatile uint32_t*)(startAddr + i));
        }
        printf("\r\n");

        /*write 0xff to one page*/
        HAL_FLASH_Unlock();
        __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPTVERR);
        for (int i = 0; i < 2048; i += 8)
        {
                status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, startAddr + i, 0xffffffffffffffff);
                if (status != HAL_OK)
                {
                        printf("Fail to write all pages!\r\n");
                        break;
                }
        }
        HAL_FLASH_Lock();

        printf("after write 0xff to one page\r\n");
        for (int i = 0; i < 2048; i += 4)
        {
                printf("%x ", *(volatile uint32_t*)(startAddr + i));
        }
        printf("\r\n");

        /*write 8 bytes*/
        HAL_FLASH_Unlock();
        __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPTVERR);
        status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, startAddr, 0xffffffffffffffff);
        if (status != HAL_OK)
        {
                printf("Fail to write 8 bytes!\r\n");
        }
        HAL_FLASH_Lock();
}
1、先擦除0x0801C000首址的一页
2、读出来,这页数据都是0xff
3、写0xff数据到这页
4、读出来,这页数据都是0xff
5、再往这页首址写8字节数据,FLASH_WaitForLastOperation就会出错,pFlash.ErrorCode的错误码是0xa8
从这个实验可以看出,擦除之后只能写一次数据,之后即使FLASH中的内容全为1,调用HAL_FLASH_Program也会失败

使用特权

评论回复
评论
小小怪一s 2022-11-29 13:26 回复TA
感谢楼主,受教了 
地板
zchong| | 2020-10-13 13:30 | 只看该作者
地址要对齐

使用特权

评论回复
5
香水城| | 2020-10-13 14:41 | 只看该作者
本帖最后由 香水城 于 2020-10-15 17:00 编辑

是的,对于该系列的flash编程写过了就不能再写,即使双字写的是全1. 唯一种可能性可再写就是将数据改写成全0.

使用特权

评论回复
6
zhenxizhou|  楼主 | 2020-10-14 09:58 | 只看该作者
本帖最后由 zhenxizhou 于 2020-10-14 09:59 编辑

这改变了我对FLASH的认知。
我原来以为FLASH只是不能从0到1,从1到0没问题。
以致于在最近的产品中做了这样的设计:为了减少擦除的次数,延长FLASH的寿命,只要检测到8字节对齐的64位全为1,就可以去写数据。。这部分得重新设计了。

使用特权

评论回复
7
香水城| | 2020-10-15 16:56 | 只看该作者
zhenxizhou 发表于 2020-10-14 09:58
这改变了我对FLASH的认知。
我原来以为FLASH只是不能从0到1,从1到0没问题。
以致于在最近的产品中做了这样 ...

整体上, 你的认知没有问题。

STM32芯片内FLASH,出于信息安全等方面的考虑,往往加入了些特定的保护机制。

关于这点,不同的STM32系列在flash编程上可能会略有差异

比如早期的STM32F1/F3系列,就没有上面的问题。即只要相应地址空间内容
为FF,且不违反对齐及其它规定,就可以再次写入。
比方以F3芯片为例,下面的操作是可以的:

    HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, Address, 0x33333333);

    Address = Address + 4;
         HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, Address, 0xffffffff);
         
   Address = Address + 4;
         HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, Address, 0x55555555);

    Address = Address - 4;
HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, Address, 0x88888888);

这里的最后一行指令就可以修改前面的0xffffffff的内容。

使用特权

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

本版积分规则

37

主题

76

帖子

2

粉丝