/** * @file wl_flash.h * @author xushenghao * @date 2024-07-22 13:57:02 * @brief * @copyright Copyright (c) 2024 by xxx, All Rights Reserved. */ /** * @brief 磨损平衡算法 * * 1. 初始化block_page大小和当前写入地址 * 2. 写入数据前,检查剩余空间是否足够 * a. 如果足够,直接写入数据 * b. 如果不足够,执行以下步骤: * i. 检查是否有已擦除但未使用的block_page,如果有,移动到该block_page继续写入 * ii. 如果没有已擦除的block_page,检查当前block_page是否已满 * - 如果已满,移动到下一个block_page * - 在移动前,检查该block_page是否有有效数据需要迁移,如果有,则先迁移数据 * 3. 在决定擦除新的block_page前,采用Wear Leveling算法选择最佳的block_page进行擦除 * 4. 数据写入后,更新剩余空间大小和当前写入地址 */ /** * 使用方法 * #define LL_FLASH_PAGE_SIZE (2 * 1024) #define PVD_RESET_STORAGE_START_ADDRESS (256 * LL_FLASH_PAGE_SIZE) static void test_wl_flash(void) { uint32_t address = 0; wl_flash_t wf = { .wl_flag = TRUE, .addr = PVD_RESET_STORAGE_START_ADDRESS, .len = 2 * LL_FLASH_PAGE_SIZE, .page_size = LL_FLASH_PAGE_SIZE, .data_size = sizeof(device_reset_t), .write_gran = 8, .ops.srand = board_srand, .ops.read = flash_read, .ops.write = flash_write, .ops.erase_page = flash_erase_page, }; wl_flash_init(&wf); wl_flash_erase(&wf); address = wl_flash_get_current_address(&wf); device_reset_t power_on; power_on.flag = PVD_RESET_FLAG; // 一页2048/16 = 128个数据,2页 = 256个数据,i=255时数据从头开始 for (uint16_t i = 0; i < 1000; i++) { wl_flash_write(&wf, (uint8_t *)&power_on, sizeof(device_reset_t)); wl_flash_set_next_address(&wf); address = wl_flash_get_current_address(&wf); if (address == wf.addr) { __NOP(); } } } */ #ifndef __WL_FLASH_H__ #define __WL_FLASH_H__ #include "lib.h" typedef struct { BOOL wl_flag; // 开启平衡擦写标志 uint32_t addr; // Flash 起始地址 uint32_t len; // Flash 长度 uint16_t page_size; // Flash 页大小 2^N uint16_t data_size; // 数据大小 /* write minimum granularity, unit: byte. 1(stm32f2/f4)/ 4(stm32f1)/ 8(stm32l4) 0 will not take effect. */ uint8_t write_gran; struct { void (*srand)(void); // 随机数种子 BOOL(*read) (uint32_t addr, uint8_t *buf, uint16_t size); BOOL(*write) (uint32_t addr, const uint8_t *buf, uint16_t size); BOOL(*erase_page) (uint32_t page); } ops; struct { uint32_t current_address; // 当前准备写入的地址 uint16_t residue_size; // 剩余可写大小 uint16_t start_page; // 起始页 uint16_t page_total; // 总页数 uint16_t block_page; // 擦除块大小 } private; } wl_flash_t; extern void wl_flash_init(wl_flash_t *cfg); ///< 初始化 Flash 磨损平衡算法 extern uint32_t wl_flash_get_current_address(wl_flash_t *cfg); ///< 获取当前写入地址 extern void wl_flash_set_next_address(wl_flash_t *cfg); ///< 设置下一个写入地址,下一个写入区域会被擦除 extern void wl_flash_set_current_address(wl_flash_t *cfg, uint32_t address); ///< 设置当前写入地址 extern void wl_flash_erase(wl_flash_t *cfg); ///< 擦除 Flash, 如果开启了平衡擦写标志, 则会随机分配写入地址 extern BOOL wl_flash_write(wl_flash_t *cfg, const uint8_t *buf, uint16_t size); ///< 写入 Flash extern BOOL wl_flash_read(wl_flash_t *cfg, uint8_t *buf, uint16_t size); ///< 读取 Flash #endif // __WL_FLASH_H__