打印
[STM32L4]

HAL_FLASH_Program写数据失败问题

[复制链接]
4392|17
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
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的内容。

使用特权

评论回复
8
童雨竹| | 2024-11-8 08:10 | 只看该作者

引线长度就决定了其响应信号的波长

使用特权

评论回复
9
Wordsworth| | 2024-11-8 09:13 | 只看该作者

数字电压表(DVM)或仪器来测量效率

使用特权

评论回复
10
Clyde011| | 2024-11-8 10:16 | 只看该作者

靠近功率开关管或整流器的电容分到的纹波电流远多于相距较远的电容分到的纹波电流

使用特权

评论回复
11
公羊子丹| | 2024-11-8 11:09 | 只看该作者

任何一条PCB引线都可能成为天线

使用特权

评论回复
12
Uriah| | 2024-11-8 13:15 | 只看该作者

离线式变换器

使用特权

评论回复
13
帛灿灿| | 2024-11-8 15:11 | 只看该作者

交流能量就会从输入或输出滤波电容上流进流出

使用特权

评论回复
14
Bblythe| | 2024-11-8 16:14 | 只看该作者

经变压器映射成这么多节点

使用特权

评论回复
15
周半梅| | 2024-11-8 18:10 | 只看该作者

专门的滤波器来阻止交流噪声进入周围的电路

使用特权

评论回复
16
Pulitzer| | 2024-11-8 19:13 | 只看该作者

电流型变换器电流检测电阻的公共接点和输出端电阻分压器的下端

使用特权

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

本版积分规则

37

主题

76

帖子

2

粉丝