本帖最后由 穿西装的强子 于 2025-5-9 16:51 编辑
#申请原创# @21小跑堂 以GD32F4为例,假设我们需要将一个扇区反复写入一个用户参数,例如参数有20个bytes,而反复擦写flash会导致损坏,按GD32F4的数据手册上介绍,擦除次数只有10万次,因此反复擦写太快有超过的风险。 为了解决这个问题,我们想到了将扇区所有空间都利用起来,使用索引的方式进行写入,这样就不会反复的擦除,只有在最开始的时候才会擦除,大大的减少了擦除的次数。
一、Flash 写入次数计算128K存储,假设每次存24个Bytes,整个存储可以存5461次,再擦除一次扇区,扇区可以擦写10万次,存储次数10万*5461,每10秒存一次,可以写193年。 二、硬件平台与开发环境- MCU:GD32F4xx
- 开发工具:Keil MDK 或 IAR Embedded Workbench
- SDK:GD32F4xx Standard Peripheral Library
三、Flash 轮询写入实现步骤void flash_write_data(FlashData_t flashData;)
{
if( flash_addr == FLASH_USER_START_ADDR || flash_addr == ADDR_FMC_SECTOR_12)
{
fmc_erase_sector(fmc_sector_get(FLASH_USER_START_ADDR));
flash_addr = FLASH_USER_START_ADDR;
}
flashData.reserved = 0;
fmc_write_32bit_data(flash_addr, sizeof(flashData) / 4, (INT32*)&flashData);
flash_addr += sizeof(flashData); // 每次写入都增加存储的大小
}
4.读数据
int flash_read_data(UINT32 addr,FlashData_t *data)
{
FlashData_t flashData;
fmc_read_32bit_data(addr, sizeof(flashData) / 4, (INT32*)&flashData);
*data =flashData;
return TRUE;
}
5.读索引
UINT32 flash_find_index(void)
{
UINT32 addr;
FlashData_t flashData;
UINT16 i;
// 搜索未被使用的地址
for(i = 0; i < MEMORY_SIZE;)
{
addr = FLASH_USER_START_ADDR + i;
fmc_read_32bit_data(addr, sizeof(flashData) / 4, (INT32*)&flashData);
i += sizeof(flashData);
if( flashData.reserved == 0xffff) // 该值正常时为0,因此判定该值为0xff时待办该地址为被使用
{
break;
}
}
if( i == MEMORY_SIZE) // 找到最后,将地址为赋值为最新
addr = FLASH_USER_START_ADDR;
return addr;
}
四、使用流程
1. 初始化检测索引,使用flash_find_index()函数
2. 如果检测到addr为FLASH_USER_START_ADDR起始地址,则擦除并写入第一组数据
3. 写入时自动累计flash_addr值
4. 读取时使用flash_addr进行读取
五、应用场景该方案适用于传感器数据记录、设备配置保存等场景,特别适合没有外部存储介质的低成本设计方案。 通过上述方法,开发者可以高效可靠地实现基于 GD32 的 Flash 数据存储功能。在实际工程中,建议结合 CRC 校验等机制进一步提升数据可靠性。
|