硬汉嵌入式论坛

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

[技术讨论] stm32g4 flash读写错误

[复制链接]

23

主题

49

回帖

118

积分

初级会员

积分
118
发表于 2024-6-3 16:05:38 | 显示全部楼层 |阅读模式
本帖最后由 zhouyalong 于 2024-6-3 16:06 编辑

看着正点原子的stm32f103的片上flash代码移植到自己的工程中出错,因为stm32g473的hal库中没有半字写入,所以我把他改成了以双字(64位)的形式写入数据。每次写入一个双字,然后地址增加4,
stm32f103中的宏定义为:

#define FLASH_TYPEPROGRAM_HALFWORD             0x01U  /*!<Program a half-word (16-bit) at a specified address.*/
#define FLASH_TYPEPROGRAM_WORD                 0x02U  /*!<Program a word (32-bit) at a specified address.*/
#define FLASH_TYPEPROGRAM_DOUBLEWORD           0x03U  /*!<Program a double word (64-bit) at a specified address*/
stm32g473中为:
#define FLASH_TYPEPROGRAM_DOUBLEWORD    0x00U              /*!< Program a double-word (64-bit) at a specified address.*/
#define FLASH_TYPEPROGRAM_FAST          0x01U              /*!< Fast program a 32 row double-word (64-bit) at a specified address.
                                                                And another 32 row double-word (64-bit) will be programmed */
#define FLASH_TYPEPROGRAM_FAST_AND_LAST 0x02U              /*!< Fast program a 32 row double-word (64-bit) at a specified address.
                                                                And this is the last 32 row double-word (64-bit) programmed */




下面是我的代码
[C] 纯文本查看 复制代码
u16 STMFLASH_ReadHalfWord(u32 faddr)
{
    return *(vu16 *)faddr;
}
#if STM32_FLASH_WREN // 如果使能了写
// 不检查的写入
// WriteAddr:起始地址
// pBuffer:数据指针
// NumToWrite:半字(16位)数
// 以**半字(16位)**的形式写入数据。每次写入一个半字,然后地址增加2。这是因为一个半字包含1个16位的数据,所以地址需要增加2。
// void STMFLASH_Write_NoCheck(u32 WriteAddr, u16 *pBuffer, u16 NumToWrite)
// {
//     u16 i;
//     for (i = 0; i < NumToWrite; i++)
//     {
//         HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, WriteAddr, pBuffer);
//         WriteAddr += 2; // 地址增加2.
//     }
// }
// 以**双字(64位)**的形式写入数据。每次写入一个双字,然后地址增加4。这是因为一个双字包含4个16位的数据,所以地址需要增加4。
void STMFLASH_Write_NoCheck(u32 WriteAddr, u16 *pBuffer, u16 NumToWrite)
{
    u16 i;
    u32 buffer;
    for (i = 0; i < NumToWrite; i += 2)
    {
        buffer = ((u32)pBuffer) | ((u32)pBuffer[i + 1] << 16);
        HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, WriteAddr, buffer);
        WriteAddr += 4; // 地址增加4.
    }
}
// 从指定地址开始写入指定长度的数据
// WriteAddr:起始地址(此地址必须为2的倍数!!)
// pBuffer:数据指针
// NumToWrite:半字(16位)数(就是要写入的16位数据的个数.)
#if STM32_FLASH_SIZE < 256
#define STM_SECTOR_SIZE 1024 // 字节
#else
#define STM_SECTOR_SIZE 2048
#endif
u16 STMFLASH_BUF[STM_SECTOR_SIZE / 2]; // 最多是2K字节
void STMFLASH_Write(u32 WriteAddr, u16 *pBuffer, u16 NumToWrite)
{
    u32 secpos;    // 扇区地址
    u16 secoff;    // 扇区内偏移地址(16位字计算)
    u16 secremain; // 扇区内剩余地址(16位字计算)
    u16 i;
    u32 offaddr; // 去掉0X08000000后的地址
    if (WriteAddr < STM32_FLASH_BASE || (WriteAddr >= (STM32_FLASH_BASE + 1024 * STM32_FLASH_SIZE)))
        return; // 非法地址
    HAL_FLASH_Unlock();                       // 解锁
    offaddr = WriteAddr - STM32_FLASH_BASE;   // 实际偏移地址.
    secpos = offaddr / STM_SECTOR_SIZE;       // 扇区地址  0~127 for STM32F103RBT6
    secoff = (offaddr % STM_SECTOR_SIZE) / 2; // 在扇区内的偏移(2个字节为基本单位.)
    secremain = STM_SECTOR_SIZE / 2 - secoff; // 扇区剩余空间大小
    if (NumToWrite <= secremain)
        secremain = NumToWrite; // 不大于该扇区范围
    while (1)
    {
        STMFLASH_Read(secpos * STM_SECTOR_SIZE + STM32_FLASH_BASE, STMFLASH_BUF, STM_SECTOR_SIZE / 2); // 读出整个扇区的内容
        for (i = 0; i < secremain; i++)                                                                // 校验数据
        {
            if (STMFLASH_BUF[secoff + i] != 0XFFFF)
                break; // 需要擦除
        }
        if (i < secremain) // 需要擦除
        {
            FLASH_PageErase(secpos * STM_SECTOR_SIZE + STM32_FLASH_BASE, FLASH_BANK_1); // 擦除这个扇区
            FLASH_WaitForLastOperation(FLASH_WAITETIME);                                // 等待上次操作完成
            CLEAR_BIT(FLASH->CR, FLASH_CR_PER);                                         // 清除CR寄存器的PER位,此操作应该在FLASH_PageErase()中完成!
                                                                                        // 但是HAL库里面并没有做,应该是HAL库bug!
            for (i = 0; i < secremain; i++)                                             // 复制
            {
                STMFLASH_BUF[i + secoff] = pBuffer;
            }
            STMFLASH_Write_NoCheck(secpos * STM_SECTOR_SIZE + STM32_FLASH_BASE, STMFLASH_BUF, STM_SECTOR_SIZE / 2); // 写入整个扇区
        }
        else
        {
            FLASH_WaitForLastOperation(FLASH_WAITETIME);           // 等待上次操作完成
            STMFLASH_Write_NoCheck(WriteAddr, pBuffer, secremain); // 写已经擦除了的,直接写入扇区剩余区间.
        }
        if (NumToWrite == secremain)
            break; // 写入结束了
        else       // 写入未结束
        {
            secpos++;                   // 扇区地址增1
            secoff = 0;                 // 偏移位置为0
            pBuffer += secremain;       // 指针偏移
            WriteAddr += secremain * 2; // 写地址偏移(16位数据地址,需要*2)
            NumToWrite -= secremain;    // 字节(16位)数递减
            if (NumToWrite > (STM_SECTOR_SIZE / 2))
                secremain = STM_SECTOR_SIZE / 2; // 下一个扇区还是写不完
            else
                secremain = NumToWrite; // 下一个扇区可以写完了
        }
    };
    HAL_FLASH_Lock(); // 上锁
}
#endif
// 从指定地址开始读出指定长度的数据
// ReadAddr:起始地址
// pBuffer:数据指针
// NumToWrite:半字(16位)数
void STMFLASH_Read(u32 ReadAddr, u16 *pBuffer, u16 NumToRead)
{
    u16 i;
    for (i = 0; i < NumToRead; i++)
    {
        pBuffer = STMFLASH_ReadHalfWord(ReadAddr); // 读取2个字节.
        ReadAddr += 2;                                // 偏移2个字节.
    }
}

其中函数STMFLASH_Write_NoCheck被注释的是正点原子的代码,下面是我修改的,现在的问题就是,我测试的时候在地址0X08070000上写入"STM32F103 FLASH TEST",但是读出来的只有STM3,后面的内容都没有了,这是什么问题?求大佬解答



回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
116197
QQ
发表于 2024-6-4 10:08:56 | 显示全部楼层
重新测试下,不要整合任何API,直接调用HAL库的擦除函数,擦除扇区,然后调用HAL库的编程函数,支持那种位宽,支持那个就调用那个,看看是否正常。
回复

使用道具 举报

23

主题

49

回帖

118

积分

初级会员

积分
118
 楼主| 发表于 2024-6-5 08:27:05 | 显示全部楼层
eric2013 发表于 2024-6-4 10:08
重新测试下,不要整合任何API,直接调用HAL库的擦除函数,擦除扇区,然后调用HAL库的编程函数,支持那种位 ...

重新写了一份flash  已经好了
回复

使用道具 举报

1

主题

11

回帖

14

积分

新手上路

积分
14
发表于 2024-9-30 08:51:16 | 显示全部楼层
楼主,硬汉哥,您们好。我也遇到了在这个系列下Flash写入的问题,首先我有经验基于标准库与HAL库对F1与F4系列的Flash操作,但是在使用G系列时发现,Flash擦除操作只有第一次(全片擦除)烧录代码后能正确,不报错,复位后在跑程序就会写入错误,错误码也没什么有用的指示。还请批评指正,谢谢啦。
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
116197
QQ
发表于 2024-9-30 10:33:05 | 显示全部楼层
SGK0514 发表于 2024-9-30 08:51
楼主,硬汉哥,您们好。我也遇到了在这个系列下Flash写入的问题,首先我有经验基于标准库与HAL库对F1与F4系 ...

1、这个在CubeG4软件包里面应该有例子的,你测试是否正常。
2、然后就是看看此贴,问题是否类似

STM32G0B1CB使用片内flash,擦除失败
https://www.armbbs.cn/forum.php? ... 0335&fromuid=58
(出处: 硬汉嵌入式论坛)
回复

使用道具 举报

1

主题

11

回帖

14

积分

新手上路

积分
14
发表于 2024-10-8 14:40:36 | 显示全部楼层
eric2013 发表于 2024-9-30 10:33
1、这个在CubeG4软件包里面应该有例子的,你测试是否正常。
2、然后就是看看此贴,问题是否类似

谢谢硬汉哥的回复,我后面随机分别买了STM32G030C8T6与STM32G473RC两块最小系统板,想着都是G系列。用了CubeG4软件包里的代码,基础代码是cubeMX直接按照芯片型号与外部时钟生成的,拷贝了Flash操作业务逻辑,增加了打印提示。步骤:全片擦除,烧录,能擦除,能写入,能读出,这个时候,按下复位,想着代码在跑一次,此刻就擦除失败了。我读了用户手册和数据手册,但我经验太浅,没找到有效的信息,还请大家批评指正。
回复

使用道具 举报

3

主题

295

回帖

304

积分

高级会员

积分
304
发表于 2024-10-8 15:59:01 | 显示全部楼层
SGK0514 发表于 2024-10-8 14:40
谢谢硬汉哥的回复,我后面随机分别买了STM32G030C8T6与STM32G473RC两块最小系统板,想着都是G系列。用了C ...

G0和G4还是有区别的,比如F1和F4都是F系列但区别就很大,代码不一定通用。
擦除和写入之前都要清除一下错误标志:FLASH->SR = FLASH_SR_CLEAR;
回复

使用道具 举报

1

主题

11

回帖

14

积分

新手上路

积分
14
发表于 2024-10-8 17:10:59 | 显示全部楼层
skyshine 发表于 2024-10-8 15:59
G0和G4还是有区别的,比如F1和F4都是F系列但区别就很大,代码不一定通用。
擦除和写入之前都要清除一下 ...

我查了错误码0xA8对应的错误标志位,然后都清零了一遍,最终现象还是没变。
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPTVERR | FLASH_FLAG_EOP | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PROGERR);
回复

使用道具 举报

12

主题

53

回帖

89

积分

初级会员

面霸

积分
89
发表于 2024-12-31 19:31:23 | 显示全部楼层
SGK0514 发表于 2024-10-8 17:10
我查了错误码0xA8对应的错误标志位,然后都清零了一遍,最终现象还是没变。
__HAL_FLASH_CLEAR_FLAG(FLAS ...

楼主有结论了吗,我现在做G4也有这个问题,只有第一次能写入成功,也看到了错误码A8
回复

使用道具 举报

1

主题

11

回帖

14

积分

新手上路

积分
14
发表于 2025-1-2 11:37:13 | 显示全部楼层
1350280419 发表于 2024-12-31 19:31
楼主有结论了吗,我现在做G4也有这个问题,只有第一次能写入成功,也看到了错误码A8

解决了,其实是我们没搞清楚扇区地址对应的bank。
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2025-6-10 04:43 , Processed in 0.309326 second(s), 24 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

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