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.
179 lines
5.2 KiB
179 lines
5.2 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>
|
|
#include "rd_thread.h"
|
|
|
|
static rd_mutex_t g_lfs_mutex;
|
|
|
|
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;
|
|
|
|
if (W25QXX_Read((uint8_t *)buffer, addr, (uint16_t)size) != 0)
|
|
{
|
|
return LFS_ERR_IO;
|
|
}
|
|
|
|
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。
|
|
*/
|
|
if (W25QXX_Write_NoCheck((uint8_t *)(uintptr_t)buffer, addr, (uint16_t)size) != 0)
|
|
{
|
|
return LFS_ERR_IO;
|
|
}
|
|
|
|
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),
|
|
* 所以传入字节地址除以扇区大小。
|
|
*/
|
|
if (W25QXX_Erase_Sector(addr / LFS_FLASHBD_SECTOR_SIZE) != 0)
|
|
{
|
|
return LFS_ERR_IO;
|
|
}
|
|
|
|
return LFS_ERR_OK;
|
|
}
|
|
|
|
int lfs_flashbd_sync(const struct lfs_config *cfg) {
|
|
(void)cfg;
|
|
W25QXX_Wait_Busy();
|
|
return LFS_ERR_OK;
|
|
}
|
|
|
|
int lfs_flashbd_lock(const struct lfs_config *cfg)
|
|
{
|
|
(void)cfg;
|
|
Rd_MutexLock(&g_lfs_mutex, __func__, NULL);
|
|
return LFS_ERR_OK;
|
|
}
|
|
|
|
int lfs_flashbd_unlock(const struct lfs_config *cfg)
|
|
{
|
|
(void)cfg;
|
|
Rd_MutexUnlock(&g_lfs_mutex, __func__, NULL);
|
|
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;
|
|
|
|
(void)Rd_MutexInit(&g_lfs_mutex);
|
|
|
|
/* 回调函数 */
|
|
cfg->context = bd;
|
|
cfg->read = lfs_flashbd_read;
|
|
cfg->prog = lfs_flashbd_prog;
|
|
cfg->erase = lfs_flashbd_erase;
|
|
cfg->sync = lfs_flashbd_sync;
|
|
cfg->lock = lfs_flashbd_lock;
|
|
cfg->unlock = lfs_flashbd_unlock;
|
|
|
|
/* 块设备参数 */
|
|
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;
|
|
}
|
|
|