分享一下片内flash使用小技巧--轮询写入

[复制链接]
 楼主| 穿西装的强子 发表于 2025-5-9 09:25 | 显示全部楼层 |阅读模式
本帖最后由 穿西装的强子 于 2025-6-6 11:52 编辑

#申请原创# @21小跑堂
      以GD32F4为例,假设我们需要将一个扇区反复写入一个用户参数,例如参数有20个bytes,而反复擦写flash会导致损坏,按GD32F4的数据手册上介绍,擦除次数只有10万次,因此反复擦写太快有超过的风险。
61137681d55fd2a1df.png
      为了解决这个问题,我们想到了将扇区所有空间都利用起来,使用索引的方式进行写入,这样就不会反复的擦除,只有在最开始的时候才会擦除,大大的减少了擦除的次数。

写入流程
1. 识别FLASH扇区索引,未存储区域,例如 0x08050020 无数据,记录索引为 0x08050020。
2.写数据,按索引 0x08050020  开始写,不擦除flash,写一次,索引自加(数据长度)。
3.写到扇区最后,如 0x08070000 ,索引变为 0x08050000,开始写,这个时候才擦除一次扇区,然后继续写入数据。

一、Flash 写入次数计算
128K存储,假设每次存24个Bytes,整个存储可以存5461次,再擦除一次扇区,扇区可以擦写10万次,存储次数10万*5461,每10秒存一次,可以写193年。
二、硬件平台与开发环境

  • MCU:GD32F4xx
  • 开发工具:Keil MDK 或 IAR Embedded Workbench
  • SDK:GD32F4xx Standard Peripheral Library
三、Flash 轮询写入实现步骤

  • 初始化读索引
    在初始化的时候使用flash_find_index()函数进行索引的获取,索引使用一个全局变量或结构体变量进行保存,在每次写入的时候进行累加

  • 定义存储区域
    根据应用需求划分 Flash 存储区域,例如使用最后一页作为用户数据区。
    1. #define USER_DATA_ADDR    (0x080E0000)  // 用户数据起始地址(根据芯片型号调整) ADDR_FMC_SECTOR_11
  • 轮询写数据
  1. void flash_write_data(FlashData_t flashData;)
  2. {
  3.         if( flash_addr == FLASH_USER_START_ADDR || flash_addr == ADDR_FMC_SECTOR_12)
  4.         {
  5.                 fmc_erase_sector(fmc_sector_get(FLASH_USER_START_ADDR));
  6.                 flash_addr = FLASH_USER_START_ADDR;
  7.         }
  8.         
  9.         flashData.reserved = 0;
  10.         fmc_write_32bit_data(flash_addr, sizeof(flashData) / 4, (INT32*)&flashData);
  11.         flash_addr        +=        sizeof(flashData);        // 每次写入都增加存储的大小
  12. }

4.读数据
  1. int flash_read_data(UINT32 addr,FlashData_t *data)
  1. {
  2. FlashData_t flashData;
  3.     fmc_read_32bit_data(addr, sizeof(flashData) / 4, (INT32*)&flashData);
  4. *data =flashData;
  5.     return TRUE;
  6. }

5.读索引
  1. UINT32 flash_find_index(void)
  2. {
  3.         UINT32 addr;
  4.         FlashData_t flashData;
  5.         UINT16 i;
  6.         // 搜索未被使用的地址
  7.         for(i = 0; i < MEMORY_SIZE;)
  8.         {
  9.                 addr = FLASH_USER_START_ADDR + i;
  10.                 fmc_read_32bit_data(addr, sizeof(flashData) / 4, (INT32*)&flashData);
  11.                 i += sizeof(flashData);
  12.                 if( flashData.reserved == 0xffff)        // 该值正常时为0,因此判定该值为0xff时待办该地址为被使用
  13.                 {
  14.                         break;
  15.                 }
  16.         }
  17.         if( i == MEMORY_SIZE)        // 找到最后,将地址为赋值为最新
  18.                 addr = FLASH_USER_START_ADDR;
  19.         return addr;
  20. }





四、使用流程


1. 初始化检测索引,使用flash_find_index()函数
2. 如果检测到addr为FLASH_USER_START_ADDR起始地址,则擦除并写入第一组数据
3. 写入时自动累计flash_addr值
4. 读取时使用flash_addr进行读取


五、应用场景
该方案适用于传感器数据记录、设备配置保存等场景,特别适合没有外部存储介质的低成本设计方案。
通过上述方法,开发者可以高效可靠地实现基于 GD32 的 Flash 数据存储功能。在实际工程中,建议结合 CRC 校验等机制进一步提升数据可靠性。



评论

6666666  发表于 2025-8-19 10:41
内容详细,赞,逻辑清晰  发表于 2025-8-19 10:40
有过这个需求,谢谢  发表于 2025-8-19 10:39
Hi 大佬 感谢谢分享,本贴内容不满800字未达原创审核门槛,可填充内容后再次申请原创~  发表于 2025-5-14 11:29
zhengshuai888 发表于 2025-5-14 21:57 来自手机 | 显示全部楼层
MCU片内FLASH最好不要频繁擦除

评论

没有反复写啊,你看下逻辑吧  发表于 2025-5-15 10:37
lidi911 发表于 2025-5-15 08:46 来自手机 | 显示全部楼层
如一楼所述MCU内部flash要避免频繁擦除,适合用于存储不需要经常变动的数据。

评论

不是,你们都没仔细看吗,一个扇区用完了再擦除啊,不会频繁擦除  发表于 2025-5-15 10:16
kepe 发表于 2025-5-31 01:50 | 显示全部楼层
通过扇区内的多块空间轮流写入,减少擦写次数。擦除只在整扇区写满时执行一次。
claretttt 发表于 2025-6-5 11:35 | 显示全部楼层
根据应用需求划分Flash存储区域
backlugin 发表于 2025-6-5 12:25 | 显示全部楼层
合并多次小数据写入              
hudi008 发表于 2025-6-5 13:22 | 显示全部楼层
擦除扇区 → 写入数据 → 轮询状态寄存器(如BUSY位)→ 验证数据。
mickit 发表于 2025-6-5 14:13 | 显示全部楼层
在关键应用中,可以考虑在多个块中备份重要数据,以防止数据丢失。
lzmm 发表于 2025-6-5 15:04 | 显示全部楼层
关键是实现磨损均衡、数据校验和错误恢复机制
maudlu 发表于 2025-6-5 15:55 | 显示全部楼层
通过合理设计扇区结构和循环机制,可以显著提高 Flash 使用寿命和数据可靠性。
jkl21 发表于 2025-6-5 16:53 | 显示全部楼层
写入时自动累加flash_addr值
rosemoore 发表于 2025-6-5 17:45 | 显示全部楼层
Flash在写入数据之前必须先擦除。擦除操作通常比写入操作耗时更长。
mollylawrence 发表于 2025-6-5 18:35 | 显示全部楼层
批量写入时,尽量减少Flash操作次数。
10299823 发表于 2025-6-5 19:18 | 显示全部楼层
在低功耗应用中,考虑在写入时关闭非关键外设以节省电量。
youtome 发表于 2025-6-5 21:01 | 显示全部楼层
可以使用一个简单的算法来选择下一个写入的块,例如循环使用每个块。
chenci2013 发表于 2025-6-5 21:49 | 显示全部楼层
Flash通常以页或扇区为单位进行擦除,因此需要合理规划写入地址,避免跨页写入导致不必要的擦除操作。
abotomson 发表于 2025-6-5 22:40 | 显示全部楼层
需要快速响应的实时系统              
lihuami 发表于 2025-6-6 09:48 | 显示全部楼层
轮询通过读取状态寄存器判断写入是否完成,避免依赖固定延时。
jimmhu 发表于 2025-6-6 10:34 | 显示全部楼层
在写入过程中,需确保电源稳定,避免电压波动导致写入失败。
maqianqu 发表于 2025-6-6 11:16 | 显示全部楼层
适用于存储不需要经常变动的数据              
您需要登录后才可以回帖 登录 | 注册

本版积分规则

62

主题

259

帖子

3

粉丝
快速回复 在线客服 返回列表 返回顶部

62

主题

259

帖子

3

粉丝
快速回复 在线客服 返回列表 返回顶部