109 lines
4.1 KiB
C
109 lines
4.1 KiB
C
/**
|
||
* @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__
|