1. 完成Flash内存映射

This commit is contained in:
coffee 2025-12-06 17:36:52 +08:00
parent 176709e37d
commit 151d1565d6
2 changed files with 389 additions and 0 deletions

80
include/HFlashMem.h Normal file
View File

@ -0,0 +1,80 @@
/**
* : 2025-12-05
* : coffee
* : Flash内存映射, 使Flash
*/
#ifndef __H_FLASH_MEM_H__
#define __H_FLASH_MEM_H__
#include <stdint.h>
// 使用定时器任务ID
#ifndef HFLASH_TIMER_ID
#define HFLASH_TIMER_ID 0
#endif
// Flash内存大小, 需要4k倍数
#ifndef HFLASH_MEM_SIZE
#define HFLASH_MEM_SIZE (4096 * 3)
#endif
///< 以下IO指令必须实现
enum eHFlashMemIO
{
kHFlashMemIOErase, ///< 请求该地址擦除, 异步非阻塞(addr, cmd)
kHFlashMemIOCheckErase, ///< 检查是否已擦除完成(cmd, uint8_t *status) status设置为0:未擦除, 1:已擦除
kHFlashMemIOSyncErase, ///< 请求该地址擦除, 同步阻塞到完成(addr, cmd)
};
///< 内存缓存页, 配置需和 (memSize / 4096) 大小一致
typedef struct HFlashMemCache
{
uint32_t addr; ///< 地址
uint16_t offset; ///< 内存偏移
uint16_t eraseStatus : 2; ///< 擦除状态
uint16_t isDirty : 1; ///< 是否脏页
} HFlashMemCache;
///< 内存操作, 回调返回0表示失败
typedef struct HFlashMemOpts
{
uint8_t (*read)(uint32_t addr, void *buf, uint32_t len); ///< 读取Flash
uint8_t (*write)(uint32_t addr, const void *buf, uint32_t len); ///< 写入Flash
uint8_t (*ioctl)(uint32_t aadr, uint32_t cmd, void *arg); ///< 控制Flash
uint8_t *mem; ///< Flash映射内存, 需要4k倍数
HFlashMemCache *cache; ///< 内存缓存
uint16_t memSize; ///< Flash映射内存大小
uint16_t cacheSize; ///< 内存缓存大小
} HFlashMemOpts;
/**
* @brief Flash内存映射
* @param opts
*/
void HFlashMemInit(HFlashMemOpts *opts);
/**
* @brief Flash
* @param addr
* @param buf
* @param len
*/
uint8_t HFlashMemRead(uint32_t addr, void *buf, uint32_t len);
/**
* @brief Flash
* @param addr
* @param buf
* @param len
*/
uint8_t HFlashMemWrite(uint32_t addr, const void *buf, uint32_t len);
/**
* @brief Flash
*/
void HFlashMemSync();
#endif // __H_FLASH_MEM_H__

309
src/HFlashMem.c Normal file
View File

@ -0,0 +1,309 @@
#include "HFlashMem.h"
#include "HDLog.h"
#include "HTimer.h"
#ifdef USE_STD_MEM
#define FATAL_ERROR(format, ...) LogE(format, ##__VA_ARGS__);
#else
#define FATAL_ERROR(format, ...) while (1) { LogE(format, ##__VA_ARGS__); };
#endif
// flash块大小
#define HFLASH_BLOCK_SIZE (4096)
// 是否对齐页
#define IS_4K(size) ((size & (HFLASH_BLOCK_SIZE - 1)) == 0)
enum eErase
{
kEraseWait, ///< 等待擦除
kEraseStart, ///< 擦除开始
kWaitWrite, ///< 擦除结束, 等待写入数据
};
struct Info
{
uint16_t useNum; ///< 缓存已使用数量
uint16_t needWaitErase : 1; ///< 用于判断是否在擦除
};
// 内存操作
static HFlashMemOpts *sOpts;
// 信息
static struct Info sInfo;
// 检查定时器
static HTimer_t sCheckTimer = HTIMER_INVALID;
// 对齐页地址, 向下取整
static inline uint32_t Align4K(uint32_t addr) {
return addr & ~(HFLASH_BLOCK_SIZE - 1);
}
// 查找映射表
static inline uint8_t *GetMMap(uint16_t offset) {
return (uint8_t *)sOpts->mem + offset * HFLASH_BLOCK_SIZE;
}
static void SyncCache()
{
// 如果存在异步等待擦除的, 先等擦除完成
if (sInfo.needWaitErase) {
uint8_t status = 0;
for (;;) {
sOpts->ioctl(0, kHFlashMemIOCheckErase, &status);
if (status) {
break;
}
}
sInfo.needWaitErase = 0;
}
for (uint16_t i = 0; i < sInfo.useNum; ++i) {
if (sOpts->cache[i].isDirty == 0) {
continue;
}
LogD("Sync[%d], addr[0x%08x], offset[%d]", i, sOpts->cache[i].addr, sOpts->cache[i].offset);
sOpts->ioctl(sOpts->cache[i].addr, kHFlashMemIOSyncErase, NULL);
sOpts->write(sOpts->cache[i].addr, GetMMap(i), HFLASH_BLOCK_SIZE);
sOpts->cache[i].isDirty = 0;
sOpts->cache[i].eraseStatus = kEraseWait;
}
}
static void CheckSyncCache()
{
// 检查擦除是否完成
uint8_t status = 0;
if (sInfo.needWaitErase) {
sOpts->ioctl(0, kHFlashMemIOCheckErase, &status);
if (status == 0) {
return ;
}
sInfo.needWaitErase = 0;
}
uint16_t needErase = sInfo.useNum;
for (int32_t i = sInfo.useNum - 1; i >= 0; --i) {
// 检查哪个页的异步擦除, 现在擦除完成
if (sOpts->cache[i].eraseStatus == kEraseStart) {
sOpts->cache[i].eraseStatus = kWaitWrite;
}
if (needErase == sInfo.useNum) {
// 寻找需要擦除的页
if (sOpts->cache[i].isDirty && sOpts->cache[i].eraseStatus == kEraseWait) {
needErase = i;
}
}
// 如果不是脏页就跳过
if (sOpts->cache[i].isDirty == 0) {
continue;
}
// 检查Flash是否已经擦除完成
if (sOpts->cache[i].eraseStatus != kWaitWrite) {
continue;
}
sOpts->write(sOpts->cache[i].addr, GetMMap(i), HFLASH_BLOCK_SIZE);
sOpts->cache[i].isDirty = 0;
sOpts->cache[i].eraseStatus = kEraseWait;
}
if (needErase != sInfo.useNum) {
sInfo.needWaitErase = 1;
sOpts->cache[needErase].eraseStatus = kEraseStart;
sOpts->ioctl(sOpts->cache[needErase].addr, kHFlashMemIOErase, NULL);
}
if (sInfo.needWaitErase == 0) {
if (sCheckTimer != HTIMER_INVALID) {
HTimerRemove(sCheckTimer);
sCheckTimer = HTIMER_INVALID;
}
}
}
static void StartSyncCache()
{
if (sCheckTimer != HTIMER_INVALID) {
HTimerRemove(sCheckTimer);
sCheckTimer = HTIMER_INVALID;
}
sCheckTimer = HTimerAdd(HFLASH_TIMER_ID, 1, CheckSyncCache, kHTimerLoop);
}
static HFlashMemCache *FindCache(uint32_t addr, uint8_t create)
{
addr = Align4K(addr);
for (uint16_t i = 0; i < sInfo.useNum; ++i) {
if (addr != sOpts->cache[i].addr) {
continue;
}
return sOpts->cache + i;
}
if (create == 0) {
return NULL;
}
// 如果缓存没有满, 直接增加
if (sInfo.useNum < sOpts->cacheSize) {
const uint16_t index = sInfo.useNum;
++sInfo.useNum;
if (sOpts->read(addr, GetMMap(index), HFLASH_BLOCK_SIZE) == 0) {
LogE("addr[0x%08x], read faild", addr);
return NULL;
}
memset(sOpts->cache + index, 0, sizeof(HFlashMemCache));
sOpts->cache[index].addr = addr;
sOpts->cache[index].offset = index;
return sOpts->cache + index;
}
// 从尾巴开始找旧的并且已经不是脏页的
for (int32_t i = sInfo.useNum - 1; i > 0; --i) {
if (sOpts->cache[i].eraseStatus || sOpts->cache[i].isDirty) {
continue;
}
if (sOpts->read(addr, GetMMap(i), HFLASH_BLOCK_SIZE) == 0) {
LogE("addr[0x%08x], read faild", addr);
return NULL;
}
memset(sOpts->cache + i, 0, sizeof(HFlashMemCache));
sOpts->cache[i].addr = addr;
sOpts->cache[i].offset = i;
return sOpts->cache + i;
}
// 如果在创建模式下, 没有一个空闲的缓存, 就需要先同步脏页, 再获取一个
HFlashMemSync();
return FindCache(addr, create);
}
static uint8_t WriteData(uint32_t addr, const void *buf, uint32_t len)
{
uint32_t adjustAddr = Align4K(addr);
HFlashMemCache *cache = FindCache(adjustAddr, 1);
if (cache == NULL) {
LogE("addr[0x%08x], write len[%d] faild", addr, len);
return 0;
}
// 开启逐步同步
StartSyncCache();
// 找到映射表, 先处理首页
const uint8_t *bufPtr = (const uint8_t *)buf;
const uint32_t offset = addr - cache->addr;
const uint32_t remain = offset + len > HFLASH_BLOCK_SIZE ? HFLASH_BLOCK_SIZE - offset : len;
// 先处理首页
cache->isDirty = 1;
memcpy(GetMMap(cache->offset) + offset, bufPtr, remain);
len -= remain;
bufPtr += remain;
adjustAddr += HFLASH_BLOCK_SIZE;
for (; len >= HFLASH_BLOCK_SIZE; adjustAddr += HFLASH_BLOCK_SIZE, len -= HFLASH_BLOCK_SIZE, bufPtr += HFLASH_BLOCK_SIZE) {
cache = FindCache(adjustAddr, 1);
if (cache == NULL) {
LogE("addr[0x%08x], write len[%d] faild", adjustAddr, len);
return 0;
}
cache->isDirty = 1;
memcpy(GetMMap(cache->offset), bufPtr, HFLASH_BLOCK_SIZE);
}
if (len) {
cache = FindCache(adjustAddr, 1);
if (cache == NULL) {
LogE("addr[0x%08x], write len[%d] faild", adjustAddr, len);
return 0;
}
cache->isDirty = 1;
memcpy(GetMMap(cache->offset), bufPtr, len);
}
return 1;
}
void HFlashMemInit(HFlashMemOpts *opts)
{
sOpts = opts;
if (sOpts == NULL || sOpts->read == NULL || sOpts->write == NULL || sOpts->ioctl == NULL) {
FATAL_ERROR("opts is null");
return ;
}
if (sOpts->mem == NULL || IS_4K(sOpts->memSize) == 0) {
FATAL_ERROR("not 4k align");
return ;
}
if (sOpts->cache == NULL || sOpts->cacheSize != sOpts->memSize / HFLASH_BLOCK_SIZE) {
FATAL_ERROR("cache is null");
return ;
}
}
uint8_t HFlashMemRead(uint32_t addr, void *buf, uint32_t len)
{
if (sOpts == NULL) {
return 0;
}
uint8_t *p = (uint8_t *)buf;
while (len > 0) {
const uint32_t pageAddr = Align4K(addr);
const uint32_t offset = addr - pageAddr;
const uint32_t remain = HFLASH_BLOCK_SIZE - offset;
const uint32_t copyLen = len > remain ? remain : len;
HFlashMemCache *cache = FindCache(pageAddr, 0);
if (cache) {
memcpy(p, GetMMap(cache->offset) + offset, copyLen);
} else {
if (sOpts->read(addr, p, copyLen) == 0) {
LogE("addr[0x%08x], read faild", addr);
return 0;
}
}
addr += copyLen;
p += copyLen;
len -= copyLen;
}
return 1;
}
uint8_t HFlashMemWrite(uint32_t addr, const void *buf, uint32_t len)
{
if (sOpts == NULL) {
return 0;
}
return WriteData(addr, buf, len);
}
void HFlashMemSync()
{
SyncCache();
}