5.17 FAL Flash抽象层
2026/7/20大约 7 分钟设备驱动驱动FALFlash分区存储
5.17 FAL Flash抽象层
📚 本节导读
学习时长: 约 35 分钟
难度级别: ⭐⭐⭐☆☆
前置知识: C 语言基础、Flash 存储器基础、5.1 设备驱动框架
🎯 学习目标
- 理解 FAL(Flash Abstraction Layer)的架构设计
- 掌握 Flash 设备的注册与查找
- 掌握 FAL 分区表的配置与使用
- 掌握分区的读写擦除操作
- 理解 MTD 设备与 Block 设备的创建机制
一、概述
FAL(Flash Abstraction Layer)是 OneOS 的 Flash 抽象层,为上层应用(如文件系统、KV 数据库、OTA 升级等)提供统一的 Flash 访问接口。FAL 屏蔽了不同 Flash 硬件的差异(SPI Flash、片上 Flash、eMMC 等),通过分区表将物理 Flash 划分为逻辑分区,每个分区可独立管理。
FAL 位于 drivers/fal/ 目录下,由以下模块组成:
| 模块 | 文件 | 说明 |
|---|---|---|
| Flash 设备抽象 | fal.h / fal.c | Flash 设备注册、查找,定义 fal_flash_t 和 fal_flash_ops |
| 分区管理 | fal_part.h / fal_part.c | 分区表解析、分区读写擦除操作 |
| MTD 设备 | fal_mtd.c | 将 FAL 分区封装为 MTD 设备 |
| Block 设备 | fal_block.c | 将 FAL 分区封装为 Block 设备 |
| RAM 模拟 | fal_ram.c | 基于 RAM 的 Flash 模拟实现(用于测试) |
FAL 架构图:
┌──────────┬──────────┬──────────┬──────────┐
│ FileSys │ KV DB │ OTA │ Bootloader│ ← 上层应用
└────┬─────┴────┬─────┴────┬─────┴────┬─────┘
│ │ │ │
┌────▼──────────▼──────────▼──────────▼────┐
│ MTD Device / Block Device │ ← 设备抽象
└────────────────────┬────────────────────┘
│
┌────────────────────▼────────────────────┐
│ FAL Partition Table │ ← 分区表
└────────────────────┬────────────────────┘
│
┌────────────────────▼────────────────────┐
│ FAL Flash Device Layer │ ← Flash 抽象层
└────┬──────────┬──────────┬──────────────┘
│ │ │
┌────▼────┐ ┌──▼───┐ ┌───▼──────┐
│SPI Flash│ │OnChip│ │RAM Flash │ ← 物理 Flash
└─────────┘ └──────┘ └──────────┘二、核心数据结构
2.1 Flash 设备结构体 fal_flash_t
struct fal_flash
{
char name[FAL_DEV_NAME_MAX]; /* Flash 设备名称 */
uint32_t page_size; /* 页大小(字节),最小写入单位 */
uint32_t block_size; /* 块大小(页数),最小擦除单位 = block_size * page_size */
uint32_t capacity; /* 总容量(字节) */
struct fal_flash_ops ops; /* Flash 操作函数表 */
os_list_node_t list; /* 设备链表节点 */
void *priv; /* 私有数据 */
};| 字段 | 说明 |
|---|---|
name | Flash 设备名称,如 "onchip_flash"、"spi_flash" |
page_size | 页大小,最小写入/读取单位 |
block_size | 块大小(以页为单位),最小擦除单位 = block_size * page_size |
capacity | Flash 总容量(字节) |
ops | 操作函数表 |
priv | HAL 层私有数据(如 SPI 设备句柄) |
2.2 Flash 操作函数表 struct fal_flash_ops
struct fal_flash_ops
{
int (*read_page)(fal_flash_t *flash, uint32_t page_addr,
uint8_t *buff, uint32_t page_nr);
int (*write_page)(fal_flash_t *flash, uint32_t page_addr,
const uint8_t *buff, uint32_t page_nr);
int (*erase_block)(fal_flash_t *flash, uint32_t page_addr,
uint32_t page_nr);
};| 函数指针 | 说明 |
|---|---|
read_page | 从 page_addr 起始页读取 page_nr 页数据到 buff |
write_page | 将 buff 中 page_nr 页数据写入 page_addr 起始页 |
erase_block | 从 page_addr 起始页擦除 page_nr 页(以 block 对齐) |
2.3 片上 Flash 信息 struct onchip_flash_info
struct onchip_flash_info
{
uint32_t start_addr; /* Flash 起始地址 */
uint32_t capacity; /* 容量 */
uint32_t block_size; /* 块大小 */
uint32_t page_size; /* 页大小 */
};2.4 分区信息 fal_part_info_t
typedef struct fal_part_info
{
char name[FAL_DEV_NAME_MAX]; /* 分区名称 */
char flash_name[FAL_DEV_NAME_MAX]; /* 所属 Flash 设备名称 */
uint32_t offset; /* 分区在 Flash 中的偏移 */
uint32_t size; /* 分区大小 */
uint32_t flags; /* 标志位(锁定/解锁) */
} fal_part_info_t;分区标志:
| 宏 | 值 | 说明 |
|---|---|---|
FAL_PART_INFO_FLAGS_LOCKED | (1 << 0) | 分区已锁定 |
FAL_PART_INFO_FLAGS_UNLOCKED | (0 << 0) | 分区未锁定 |
2.5 分区运行时结构 fal_part_t
typedef struct fal_part
{
fal_part_info_t *info; /* 指向分区配置信息 */
fal_flash_t *flash; /* 指向所属 Flash 设备 */
uint32_t flags; /* 运行时标志 */
} fal_part_t;辅助宏:
#define fal_part_size(part) (part->info->size)
#define fal_part_block_size(part) (part->flash->block_size)
#define fal_part_page_size(part) (part->flash->page_size)三、关键 API
3.1 Flash 设备管理
/* 注册 Flash 设备 */
int fal_flash_register(fal_flash_t *flash);
/* 查找 Flash 设备(按名称) */
fal_flash_t *fal_flash_find(const char *name);3.2 分区操作
/* 查找分区 */
fal_part_t *fal_part_find(const char *name);
/* 读取分区数据 */
int fal_part_read(fal_part_t *part, uint32_t addr, uint8_t *buf, size_t size);
/* 写入分区数据 */
int fal_part_write(fal_part_t *part, uint32_t addr, const uint8_t *buf, size_t size);
/* 擦除分区区域 */
int fal_part_erase(fal_part_t *part, uint32_t addr, size_t size);
/* 擦除整个分区 */
int fal_part_erase_all(fal_part_t *part);
/* 锁定/解锁分区 */
int fal_part_lock(fal_part_t *part);
int fal_part_unlock(fal_part_t *part);3.3 MTD/Block 设备创建
/* 从分区创建 MTD 设备 */
os_mtd_device_t *fal_mtd_device_create(const char *parition_name);
/* 从分区创建 Block 设备 */
os_blk_device_t *fal_blk_device_create(const char *parition_name);四、分区表配置
FAL 分区表在 fal_cfg.h 中定义,通过 fal_part_info 数组描述:
/* fal_cfg.h 示例 */
#include <fal_part.h>
/* 定义 Flash 设备 */
extern struct fal_flash onchip_flash_dev;
extern struct fal_flash spi_flash_dev;
/* 分区表定义 */
static const fal_part_info_t fal_part_info[] =
{
/* name, flash_name, offset, size, flags */
/* 片上 Flash 分区 */
{ "boot", "onchip_flash", 0x00000000, 64*1024, 0 },
{ "app", "onchip_flash", 0x00010000, 256*1024, 0 },
{ "download", "onchip_flash", 0x00050000, 128*1024, 0 },
{ "kvdb", "onchip_flash", 0x00070000, 64*1024, 0 },
/* SPI Flash 分区 */
{ "filesys", "spi_flash", 0x00000000, 2*1024*1024, 0 },
{ "easyflash","spi_flash", 0x00200000, 512*1024, 0 },
{ "ota", "spi_flash", 0x00280000, 512*1024, 0 },
};五、使用示例
5.1 注册 Flash 设备
#include <fal.h>
/* 片上 Flash 设备 */
static struct fal_flash onchip_flash_dev =
{
.name = "onchip_flash",
.page_size = 256, /* 256 字节/页 */
.block_size = 16, /* 16 页/块 = 4KB */
.capacity = 512 * 1024, /* 512KB */
.ops =
{
.read_page = onchip_flash_read,
.write_page = onchip_flash_write,
.erase_block = onchip_flash_erase,
},
};
void fal_init(void)
{
/* 注册 Flash 设备 */
fal_flash_register(&onchip_flash_dev);
}5.2 分区读写操作
#include <fal.h>
#include <fal_part.h>
void fal_partition_example(void)
{
fal_part_t *part;
uint8_t buf[256];
int ret;
/* 1. 查找分区 */
part = fal_part_find("kvdb");
if (part == OS_NULL)
{
os_kprintf("partition 'kvdb' not found!\r\n");
return;
}
/* 2. 擦除分区 */
os_kprintf("Erasing partition 'kvdb'...\r\n");
ret = fal_part_erase_all(part);
if (ret < 0)
{
os_kprintf("erase failed!\r\n");
return;
}
/* 3. 写入数据 */
memset(buf, 0xAA, sizeof(buf));
ret = fal_part_write(part, 0, buf, sizeof(buf));
if (ret >= 0)
{
os_kprintf("Write %d bytes to 'kvdb' success\r\n", ret);
}
/* 4. 读取验证 */
memset(buf, 0, sizeof(buf));
ret = fal_part_read(part, 0, buf, sizeof(buf));
if (ret >= 0)
{
os_kprintf("Read %d bytes: buf[0]=0x%02X\r\n", ret, buf[0]);
}
}5.3 创建 MTD 设备
#include <fal.h>
#include <mtd/mtd.h>
void create_mtd_from_fal(void)
{
os_mtd_device_t *mtd;
/* 从 FAL 分区创建 MTD 设备 */
mtd = fal_mtd_device_create("filesys");
if (mtd != OS_NULL)
{
os_kprintf("MTD device 'filesys' created\r\n");
os_kprintf(" block_size: %d, page_size: %d\r\n",
mtd->block_size, mtd->page_size);
}
}5.4 创建 Block 设备
#include <fal.h>
#include <block/block_device.h>
void create_blk_from_fal(void)
{
os_blk_device_t *blk;
/* 从 FAL 分区创建 Block 设备 */
blk = fal_blk_device_create("filesys");
if (blk != OS_NULL)
{
os_kprintf("Block device 'filesys' created\r\n");
os_kprintf(" block_size: %d, block_count: %d\r\n",
blk->geometry.block_size,
blk->geometry.block_count);
}
}六、内部实现机制
6.1 分区表初始化流程
fal_part_init()
│
├── 遍历 fal_part_info[] 表
│ ├── fal_flash_find(flash_name) 查找 Flash 设备
│ ├── 校验 offset + size 不超过 Flash 容量
│ ├── 填充 fal_part_t 结构
│ └── 打印分区表
│
└── 完成初始化6.2 分区读写内部实现
分区的读写操作基于 Flash 设备操作,内部处理跨页访问:
int fal_part_read(fal_part_t *part, uint32_t addr, uint8_t *buf, size_t size)
{
// 1. 将分区内偏移转换为 Flash 绝对地址
uint32_t abs_addr = part->info->offset + addr;
// 2. 边界检查
if (addr + size > part->info->size)
return -1;
// 3. 调用 Flash 的 read_page 操作
// 内部处理跨页读取
return flash_page_op(part->flash, abs_addr, buf, size, READ);
}6.3 MTD 设备封装
fal_mtd_device_create() 将 FAL 分区封装为标准的 MTD 设备:
os_mtd_device_t *fal_mtd_device_create(const char *parition_name)
{
// 1. 查找分区
// 2. 分配 os_mtd_device_t
// 3. 设置 mtd->ops: read/write/erase 回调到 fal_part_read/write/erase
// 4. 设置 mtd->block_size, mtd->page_size, mtd->capacity
// 5. 注册 MTD 设备
// 6. 返回 MTD 设备句柄
}七、注意事项
- 对齐要求: Flash 写入通常有页对齐要求,擦除有块对齐要求,需确保操作的地址和大小符合硬件约束
- 写前擦除: NAND/NOR Flash 写入前需要先擦除,FAL 框架不自动擦除,需显式调用
fal_part_erase() - 分区表定义:
fal_part_info表在fal_cfg.h中定义,需在编译前配置好 - RAM 模拟:
fal_ram.c提供基于 RAM 的 Flash 模拟实现,可用于单元测试和功能验证 - MTD vs Block: MTD 设备面向原始 Flash 操作(支持页级读写),Block 设备面向块存储(如文件系统)
八、驱动文件位置
| 文件 | 路径 | 说明 |
|---|---|---|
fal.h / fal.c | drivers/fal/ | Flash 设备抽象层,注册与查找 |
fal_part.h / fal_part.c | drivers/fal/ | 分区表管理与分区操作 |
fal_mtd.c | drivers/fal/ | FAL → MTD 设备封装 |
fal_block.c | drivers/fal/ | FAL → Block 设备封装 |
fal_ram.c | drivers/fal/ | RAM 模拟 Flash 实现 |
fal_cfg.h | 用户项目 | 分区表配置文件 |
📖 延伸阅读
- 5.1 设备驱动框架 — 理解设备驱动框架基础
- 第7章 OneOS 常用组件详解 — 文件系统等使用 FAL 的上层组件