在嵌入式系统中,常见的 Flash 存储模块根据接口类型和用途可分为NOR、NAND、EMMC、SD卡等。本文基于NAND-Flash介绍Zephyr下的驱动模型,SPI与HAL层寄存器操作暂不做解析,仅基于API实现最基本接口。
最基本的Flash模块驱动模型包括以下几个要点:
static const struct flash_parameters shenju_flash_parameters = {
#if DT_NODE_HAS_PROP(SOC_FLASH_NODE, write_block_size)
.write_block_size = DT_PROP(SOC_FLASH_NODE, write_block_size),
#else
.write_block_size = DEFAULT_WRITE_BLOCK_SIZE,
#endif
.erase_value = 0xff,
};
说明:
static int flash_erase(const struct device *dev, off_t offset, size_t len)
{
if (FLASH_TYPE == NAND)
int block_size = spinand_get_block_size();
int block_number = offset / block_size;
int block_count = len / block_size;
if(len % block_size) block_count++;
spinand_erase_length(block_number, block_count, 1);
return 0;
}
说明:
static int flash_read(const struct device *dev, off_t offset, void *data, size_t len)
{
sys_cache_data_flush_and_invd_range(data, len);
if (FLASH_TYPE == NAND)
// spinand_read((uint32_t)data, offset, len);
spinand_read_quad((uint32_t)data, offset, len);
return 0;
}
说明:
static int flash_write(const struct device *dev, off_t offset, const void *data, size_t len)
{
uint32_t write_flash_addr = offset;
uint16_t write_len = len;
uint8_t *write_data = (uint8_t *)data;
if ((ret = spinand_write_enable()) != 0) {
return ret;
}
sys_cache_data_flush_range(write_data, write_len);
if (FLASH_TYPE == NAND)
// spinand_write((uint32_t)write_data, write_flash_addr, write_len);
spinand_write_quad((uint32_t)write_data, write_flash_addr, write_len);
return 0;
}
说明:
void flash_page_layout(const struct device *dev,
const struct flash_pages_layout **layout,
size_t *layout_size)
{
static struct flash_pages_layout flash_layout = {
.pages_count = 0,
.pages_size = 0,
};
ARG_UNUSED(dev);
if (flash_layout.pages_count == 0) {
flash_layout.pages_size = DT_PROP(DT_CHOSEN(zephyr_flash), block_size);
flash_layout.pages_count = DT_REG_SIZE(DT_CHOSEN(zephyr_flash))/flash_layout.pages_size;
}
*layout = &flash_layout;
*layout_size = 1;
}
说明:
void spinand_detect_bad_block_4kpage(void)
{
uint8_t buf[4];
for (uint32_t i = 0; i < 64; i++) {
spinand_read_to_cache(64 * i, 1);
spinand_read_from_cache((uint32_t)buf, 1024 * 2, 4);
if (buf[0] != 0xff) {
LOG_WRN("block:%u bad, value:%x\n", i, buf[0]);
}
}
}
说明:
遍历所有块(假设共64个块)
读取每个块的第一页 的OOB(Out-of-Band)区域前4字节
检查OOB数据:若首字节非 0xFF,则标记为坏块
这段代码展示了SPI NAND Flash(如W25N04KV)驱动的核心逻辑:通过坏块检测和Quad SPI加速实现高效存储管理。包括:揪出故障区块、四线Quad SPI拉满传输速度、sys_cache系列操作确保CPU与闪存数据一致性