You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

149 lines
4.6 KiB

/*
* LittleFS block device adapter for W25QXX SPI Flash
*
* Maps littlefs read/prog/erase/sync callbacks to the W25QXX driver:
* read -> W25QXX_Read
* prog -> W25QXX_Write_NoCheck (littleFS guarantees erase-before-prog)
* erase -> W25QXX_Erase_Sector (4 KiB sector)
* sync -> W25QXX_Wait_Busy
*/
#include "lfs_flashbd.h"
#include "../../bspMCU/include/w25qxx.h"
#include <string.h>
int lfs_flashbd_create(const struct lfs_config *cfg,
const struct lfs_flashbd_config *bdcfg) {
lfs_flashbd_t *bd = (lfs_flashbd_t *)cfg->context;
/* 参数校验 */
if (bdcfg->base_addr % LFS_FLASHBD_SECTOR_SIZE != 0) {
return LFS_ERR_INVAL;
}
if (bdcfg->block_count == 0) {
return LFS_ERR_INVAL;
}
bd->cfg = bdcfg;
/* 初始化 W25QXX Flash */
W25QXX_Init();
return LFS_ERR_OK;
}
int lfs_flashbd_destroy(const struct lfs_config *cfg) {
(void)cfg;
return LFS_ERR_OK;
}
int lfs_flashbd_read(const struct lfs_config *cfg, lfs_block_t block,
lfs_off_t off, void *buffer, lfs_size_t size) {
lfs_flashbd_t *bd = (lfs_flashbd_t *)cfg->context;
LFS_ASSERT(block < bd->cfg->block_count);
LFS_ASSERT(off + size <= cfg->block_size);
uint32_t addr = bd->cfg->base_addr
+ (uint32_t)block * cfg->block_size
+ (uint32_t)off;
W25QXX_Read((uint8_t *)buffer, addr, (uint16_t)size);
return LFS_ERR_OK;
}
int lfs_flashbd_prog(const struct lfs_config *cfg, lfs_block_t block,
lfs_off_t off, const void *buffer, lfs_size_t size) {
lfs_flashbd_t *bd = (lfs_flashbd_t *)cfg->context;
LFS_ASSERT(block < bd->cfg->block_count);
LFS_ASSERT(off + size <= cfg->block_size);
uint32_t addr = bd->cfg->base_addr
+ (uint32_t)block * cfg->block_size
+ (uint32_t)off;
/*
* W25QXX_Write_NoCheck 的第一个参数是 uint8_t*(非 const),
* 但该函数只读取 buffer 内容,不会修改,故安全地去除 const。
* littleFS 保证写入前块已擦除,因此无需带擦除的 W25QXX_Write。
*/
W25QXX_Write_NoCheck((uint8_t *)(uintptr_t)buffer, addr, (uint16_t)size);
return LFS_ERR_OK;
}
int lfs_flashbd_erase(const struct lfs_config *cfg, lfs_block_t block) {
lfs_flashbd_t *bd = (lfs_flashbd_t *)cfg->context;
LFS_ASSERT(block < bd->cfg->block_count);
uint32_t addr = bd->cfg->base_addr
+ (uint32_t)block * cfg->block_size;
/*
* W25QXX_Erase_Sector 的参数是扇区号(内部会乘以 4096),
* 所以传入字节地址除以扇区大小。
*/
W25QXX_Erase_Sector(addr / LFS_FLASHBD_SECTOR_SIZE);
return LFS_ERR_OK;
}
int lfs_flashbd_sync(const struct lfs_config *cfg) {
(void)cfg;
W25QXX_Wait_Busy();
return LFS_ERR_OK;
}
void lfs_flashbd_default_config(
struct lfs_config *cfg,
lfs_flashbd_t *bd,
struct lfs_flashbd_config *bdcfg,
uint32_t base_addr,
uint32_t block_count,
void *read_buffer,
void *prog_buffer,
void *lookahead_buffer) {
memset(cfg, 0, sizeof(*cfg));
/* flashbd 配置 */
bdcfg->base_addr = base_addr;
bdcfg->block_count = block_count;
bd->cfg = bdcfg;
/* 回调函数 */
cfg->context = bd;
cfg->read = lfs_flashbd_read;
cfg->prog = lfs_flashbd_prog;
cfg->erase = lfs_flashbd_erase;
cfg->sync = lfs_flashbd_sync;
/* 块设备参数 */
cfg->read_size = 256; /* W25QXX 页大小,读取可任意长度 */
cfg->prog_size = 256; /* W25QXX 页编程大小 */
cfg->block_size = LFS_FLASHBD_SECTOR_SIZE; /* 4096 字节扇区 */
cfg->block_count = block_count;
cfg->block_cycles = 500; /* 磨损均衡建议值 */
cfg->cache_size = 256; /* 缓存大小 = prog_size */
/*
* lookahead 缓存是一个位图,每字节跟踪 8 个块。按块数自动计算,
* 保证一次分配扫描即可覆盖全部块(块数向上取整到字节)。
* RAM 消耗 = ceil(block_count / 8) 字节,例如 3072 块 -> 384 字节。
* 注意:若调用者提供静态 lookahead_buffer,其大小必须 >= 该值。
*/
cfg->lookahead_size = (block_count + 7) / 8;
cfg->compact_thresh = 0; /* 使用默认值 */
/* 静态缓冲区,NULL 则由 littleFS 动态分配 */
cfg->read_buffer = read_buffer;
cfg->prog_buffer = prog_buffer;
cfg->lookahead_buffer = lookahead_buffer;
/* 使用默认值 */
cfg->name_max = 0;
cfg->file_max = 0;
cfg->attr_max = 0;
}