杰理 SDK 文档中心
首页
首页
  • 项目概览

    • SDK 简介与核心特性
    • 芯片平台与硬件资料
    • SDK 版本与发布信息
  • 快速开始

    • 环境搭建与工具链
    • 编译工程
    • 烧录与量产工具
  • 工程结构与构建系统

    • 工程目录布局
    • 构建与链接配置
  • 应用层开发

    • mbox_flash 应用框架
    • 板级支持包 (BSP)
    • 公共应用模块
    • UI 显示子系统
  • 蓝牙子系统

    • BLE 控制器、链路层与 HCI 传输
    • GATT 服务框架
    • BLE 应用示例:遥控器 / Dongle / 对讲机
    • 经典蓝牙支持
  • 音频子系统

    • 音频编解码器
    • 音频设备接口 (DAC / ADC / APA)
    • 音效处理与 EQ
    • 播放、录音与 MIO 工作流
  • 设备与文件系统

    • 存储设备驱动 (NorFlash / SDMMC / USB)
    • 文件系统 (FAT / nor_fs / SYDF)
    • 设备管理框架 (dev_mg)
  • 系统服务与电源管理

    • 消息机制 (msg / hot_msg)
    • 配置与参数存储 (app_config / VM)
    • 电源管理 (SOFT OFF / POWER DOWN)
  • 固件升级

    • 升级框架总览 (code_v1 / code_v2)
    • 双 Bank 升级机制
    • 升级通道:UART / 测试盒 / BLE OTA / USB / SD
  • 补丁包与版本维护

    • 版本升级补丁链 (v1.1.0 → v1.4.0)
    • 问题修复补丁
    • 固件裁剪与资源优化
  • 开发工具与支持

    • 辅助工具与脚本
    • 文档、配置说明与常见问题

文件系统 (FAT / nor_fs / SYDF)

AW30N BLE SDK 通过统一的 VFS(虚拟文件系统)层对底层多种文件系统进行抽象,提供 FAT(TF 卡/U 盘等块设备)、nor_fs(片内 SPI NOR Flash 简易文件系统)以及 SYDF(录音专用文件系统)三类存储后端。本文档从 VFS 挂载框架出发,深入讲解各文件系统的数据结构、API 行为与实际调用链。

Purpose and Scope

本页覆盖以下内容:

  • VFS 抽象层(vfs.h / vfs.c)的挂载、打开、读写分发机制;
  • FAT 文件系统后端(vfs_fat.c)及其基于 FatFs 的操作封装;
  • nor_fs 简易 NOR Flash 文件系统(nor_fs.h)的扇区式存储结构与全部 API;
  • SYDF(挂载类型 "sydfile")在录音场景(enc_in_norfs.c / enc_in_fatfs.c)中的使用方式。

与文件系统相关的媒体播放流程、录音编码流程属于各自独立页面,本页只说明它们如何通过 fs_mount / fs_openbypath 与文件系统交互。底层存储设备驱动(SPI NOR、SD/MMC、USB Mass Storage)也不在本页展开。

Overview

在嵌入式 BLE 音频 SoC(如 AW30N)中,数据存储需求多样:音乐文件需要大容量、可跨设备移植的 FAT 卷(TF 卡/U 盘);录音与系统数据需要掉电可靠、无日志型磨损的片内 Flash 存储;录音文件在低端场景下又需要极简的"顺序扇区追加"模型。SDK 没有让上层业务直接依赖某一具体文件系统,而是定义了 struct vfs_operations 函数表作为统一契约:

  • 每个文件系统后端注册一个 vfs_operations 实例,通过 list_for_each_vfs_operation 链入系统;
  • 上层调用 fs_mount(&pfs, device, type) 时,VFS 遍历函数表,按 fs_type 字符串匹配(例如 "fat"、"norfs"、"sydfile")找到对应后端并执行其 mount;
  • 打开文件、读写、seek、ioctl 等操作全部经由 pvfs->ops 函数指针分发到具体后端。

这种设计让业务代码(音乐、录音、升级)与存储介质解耦:同一套 fs_* API 既可用于 FAT 卷,也可用于 nor_fs 卷,切换存储介质只需改变挂载时的 type 参数。

Architecture

flowchart TD
    subgraph sg_App["应用层 (mbox_flash)"]
        Music["music_device.c<br/>fs_mount(type=sydfile)"]
        Record["record/enc_in_fatfs.c<br/>enc_in_norfs.c"]
        PlayFile["simple_play_file.c<br/>fs_mount(type=sydfile)"]
    end

    subgraph sg_VFS["VFS 抽象层 (vfs.c / vfs.h)"]
        VFSInit["vfs_init()<br/>遍历 ops 链调用 init"]
        VFSMount["vfs_mount()<br/>按 fs_type 匹配后端"]
        VFSOpen["vfs_openbypath()<br/>vfs_openbyindex()"]
        Ops["struct vfs_operations 函数表<br/>(read/write/seek/ioctl/format...)"]
        VFSInit --> VFSMount
        VFSMount --> Ops
        VFSOpen --> Ops
    end

    subgraph sg_Backend["文件系统后端"]
        FAT["vfs_fat.c<br/>fs_type='fat'"]
        NORFS["nor_fs_resource.c<br/>fs_type='norfs'"]
        SYDF["SYDF 录音文件系统<br/>fs_type='sydfile'"]
    end

    subgraph sg_Dev["存储设备"]
        SD[(TF卡 / U盘<br/>块设备)]
        NOR[(片内 SPI NOR Flash<br/>页大小 256B)]
    end

    Music --> VFSMount
    Record --> VFSMount
    PlayFile --> VFSMount
    VFSMount --> FAT
    VFSMount --> NORFS
    VFSMount --> SYDF
    FAT --> SD
    NORFS --> NOR
    SYDF --> NOR

架构要点:

  • VFS 层是无状态分发器:vfs_mount 为每个挂载点分配 imount 句柄(vfs_hdl_malloc),成功后将 pvfs->ops 指向匹配后端的 vfs_operations;后续所有操作都通过该函数表间接调用(见 vfs.c)。
  • norfs 是默认后备后端:vfs_mount 在 type == NULL 时会显式跳过 "norfs" 类型,优先尝试 FAT 等可移动卷,避免误挂载片内 Flash(vfs.c)。
  • SYDF 复用 nor_fs 物理层:"sydfile" 挂载点用于录音场景,底层仍落在片内 NOR Flash 上,但提供录音专用的文件组织语义(见 enc_in_norfs.c 的 #pragma bss_seg(".enc_in_norfs.data.bss") 分区,enc_in_norfs.c)。

VFS 抽象层详解

统一操作契约:struct vfs_operations

所有文件系统后端必须实现 struct vfs_operations 函数表(vfs.h)。它包含 24 个函数指针,覆盖文件系统全生命周期:

指针成员职责
fs_type类型名("fat" / "norfs" / "sydfile"),挂载匹配依据
init后端初始化,由 vfs_init() 批量调用
mount挂载设备到 void **ppfs
openbypath / openbyindex / openbyfile / openbyclust四种打开方式:按路径、按索引、按已有文件、按簇号
createfile创建新文件,返回文件索引
read / write / seek顺序读写与定位
close_fs / close_file卸载文件系统 / 关闭文件
fdelete / fget_attr / flen / ftell / name删除、取属性、取长度、取偏移、取文件名
ioctl扩展控制命令(见下方 FS_IOCTL 枚举)
fscan_interrupt / fscan_release / fsel可中断扫描、扫描资源释放、文件选择
file_crc文件 CRC 校验
format格式化分区(clust_size、create_new)

挂载分发逻辑(vfs_mount)

u32 vfs_mount(void **ppvfs, void *device, void *type)
{
    if ((void *)NULL == *ppvfs) {
        *ppvfs = vfs_hdl_malloc();          // 分配挂载句柄
        if ((void *)NULL == *ppvfs) {
            return E_NO_VFS;                // 句柄池耗尽
        }
    }

    struct imount *pvfs = *ppvfs;
    struct vfs_operations *ops;
    list_for_each_vfs_operation(ops) {      // 遍历注册表
        if (NULL != ops->mount) {
            if (NULL != type) {             // 指定类型:精确匹配
                if (0 != strcmp(ops->fs_type, type)) {
                    continue;
                }
            } else {                        // 未指定:跳过 norfs
                if (0 == strcmp(ops->fs_type, "norfs")) {
                    continue;
                }
            }
            if (0 == ops->mount(&(pvfs->pfs), device)) {
                pvfs->ops = ops;            // 绑定函数表
                return 0;
            } else {
                if (NULL != ops->close_fs) {
                    ops->close_fs(&pvfs->pfs);  // 失败清理
                }
            }
        }
    }
    *ppvfs = vfs_fhdl_free(*ppvfs);         // 全部失败则释放句柄
    return E_NO_FS;
}

Source: vfs.c

设计意图:挂载失败时逐后端尝试(fallback),未指定类型时自动避开 "norfs",保证默认路径优先挂载可移动媒体;每次失败都会调用 close_fs 清理半初始化状态,最后统一返回 E_NO_FS 并归还句柄,避免句柄泄漏。

FS_IOCTL 扩展命令

vfs_operations.ioctl 通过 FS_IOCTL_* 枚举(vfs.h)向应用暴露后端能力,包括:

  • 扫描/目录:FS_IOCTL_GET_FILE_NUM、FS_IOCTL_FILE_CHECK、FS_IOCTL_OPEN_DIR、FS_IOCTL_ENTER_DIR、FS_IOCTL_EXIT_DIR、FS_IOCTL_GET_DIR_INFO、FS_IOCTL_MK_DIR、FS_IOCTL_DIR_FILE_TOTAL
  • 命名:FS_IOCTL_SET_NAME_FILTER(文件过滤)、FS_IOCTL_SET_LFN_BUF / FS_IOCTL_SET_LDN_BUF(长文件名/长目录名缓冲,512B)、FS_IOCTL_GET_DISP_INFO(长文件名获取)、FS_IOCTL_GETFILE_BYNAME_INDIR
  • 容量/属性:FS_IOCTL_FILE_TOTAL、FS_IOCTL_FS_TOTAL、FS_IOCTL_FILE_ATTR、FS_IOCTL_GET_PARTITION_INFO(簇大小/容量)、FS_IOCTL_GET_FREE_SPACE、FS_IOCTL_SET_VOL(卷标)
  • 同步/索引:FS_IOCTL_FILE_SYNC、FS_IOCTL_FILE_INDEX、FS_IOCTL_FS_INDEX、FS_IOCTL_RESET_VFSCAN、FS_IOCTL_GET_PATH
  • 录音:FS_IOCTL_GET_ENCFOLDER_INFO(获取录音文件信息)
  • 未实现项:FS_IOCTL_GET_ERR_CODE(注释标明"暂不支持")

FAT 文件系统后端

FAT 后端实现在 sdk/apps/app/bsp/common/fs/vfs_fat.c,对外头文件为 vfs_fat.h。其内部基于 FatFs(fat/ff_opr.h、fat/fat_resource.h)实现:

  • 适用于 TF 卡、U 盘等块设备;支持目录树、长文件名(配合 FS_IOCTL_SET_LFN_BUF 提供 512B 缓冲)、多分区(FS_IOCTL_GET_PARTITION_INFO 返回簇大小与容量)。
  • 提供 fscan_interrupt 可中断扫描,配合回调函数避免扫描大容量卡时阻塞系统,这对音频播放器"上电枚举曲目"场景至关重要。
  • format 操作支持指定 clust_size 与 create_new 标志,用于录音文件系统的按簇格式化。

vfs_fat.c 与 nor_fs_resource.c 同目录(bsp/common/fs/),说明 FAT 后端与 nor_fs 后端共享同一套 VFS 注册机制(通过 list_for_each_vfs_operation 链入,见 vfs_resource.c 与 nor_fs_resource.c)。

nor_fs:片内 NOR Flash 简易文件系统

设计定位

nor_fs 是杰理自研的轻量文件系统,专门面向片内 SPI NOR Flash 的录音/系统数据存储。它不维护目录树、不做磨损均衡,而是采用固定扇区 + 文件索引表的极简模型:每个文件占据若干 256B 扇区,文件系统头部记录索引号与起始扇区。这种设计换取了极低的 RAM/ROM 占用(句柄仅几十字节)和确定性的写入行为,适合录音这类"顺序追加、少量文件"的场景。

核心数据结构(nor_fs.h)

#define NORFS_MAGIC_NUM     0X11223344   // Flash 头部魔数
#define REC_FILE_END        0xFE          // 文件结束标记

// 文件索引:索引号 + 所在扇区
typedef struct __RECF_INDEX_INFO {
    u32 index;      // 文件索引号
    u16 sector;     // 文件所在扇区
} RECF_INDEX_INFO;

// 文件系统句柄
typedef struct __RECFILESYSTEM {
    RECF_INDEX_INFO index;
    u16 total_file;     // 文件总数
    u16 first_sector;   // 起始扇区
    u16 last_sector;    // 结束扇区
    u8  sector_bits;    // 扇区大小(以 bit 表达,决定寻址粒度)
    void *hdev;         // 底层设备句柄
} NORFS, RECFILESYSTEM, *PRECFILESYSTEM;

// 文件句柄
typedef struct __REC_FILE {
    RECF_INDEX_INFO index;   // 文件索引
    RECFILESYSTEM *pfs;      // 所属文件系统
    u32 len;                 // 文件总长度
    u32 w_len;               // 已写入长度
    u32 rw_p;                // 当前读写指针
    u16 sr;                  // 起始扇区(start sector)
    char name[16];           // 文件名(固定 16 字节)
} NORFILE, REC_FILE;

Source: nor_fs.h

关键设计点:

  • FLASH_PAGE_SIZE 256 与 NORF_SECTOR_SIZE 相等,说明 nor_fs 的扇区粒度直接对齐 NOR Flash 编程页,一次写入恰好一页,简化了驱动适配;
  • sector_bits 以 bit 表达扇区大小(如 8 表示 256B),内部换算成地址位移,避免乘除法开销;
  • REC_FILE.name[16] 使用定长 8.3 风格名称,符合 FAT 兼容的短文件名约定;
  • norfs_flash_info_t(含 norfs_magic_num / first_sector / last_sector / sector_size)用于在 Flash 中持久化分区几何信息,挂载时据此校验。

对外 API 一览

nor_fs 暴露过程式 C API(非函数表),供 nor_fs_resource.c 封装成 vfs_operations 后接入 VFS:

函数行为
norfs_init_api(void)初始化 nor_fs 内部状态
norfs_init(start, end, sector_bit)划定 Flash 扇区区间并设置扇区粒度
norfs_mount(RECFILESYSTEM **ppfs, void *p_device)挂载设备,读取头部索引信息
norfs_createfile(pfs, REC_FILE **ppfile, u32 *pindex)创建新文件并分配索引
norfs_openbyindex(pfs, REC_FILE **ppfile, u32 index)按索引打开既有文件
norfs_read(pfile, buff, btr) / norfs_write(pfile, buff, btw)顺序读写,返回实际读写字节数
norfs_seek(pfile, offsize, type)按 SEEK_SET/CUR/END 定位
norfs_closefile(REC_FILE **ppfile) / norfs_filelen(pfile, plen)关闭文件 / 查询长度
norfs_save_sr(pfile, sr)保存起始扇区(掉电恢复用)
norfs_ioctl(pfile, cmd, arg)扩展控制
norfs_name(pfile, name, len)取文件名

这些 API 的签名全部来自 nor_fs.h,是上层封装的唯一依据。

SYDF:录音文件系统(挂载类型 "sydfile")

SYDF 不是独立的第三套实现,而是面向录音应用的文件系统视图:上层以 "sydfile" 类型挂载,实际落到 nor_fs(片内 Flash)或 FAT(外部卡)之上,由录音编码层决定物理后端。

挂载入口

音乐与录音业务通过 fs_mount 指定 "sydfile" 类型:

if (INNER_FLASH_RO == dev_index) {
    err = fs_mount(&ppctl->pfs, p_device, (void *)"sydfile");
    if (0 != err) {
        // 挂载失败处理
    }
}
...
if (0 == memcmp(fs_name, "sydfile", sizeof("sydfile"))) {
    /* 按 sydfile 语义处理目录/文件 */
}

Source: music_device.c

录音文件的实际写入由两个编码入口完成,按存储介质分流:

  • enc_in_norfs.c:录音写入 nor_fs(片内 Flash),文件头使用 #pragma bss_seg(".enc_in_norfs.data.bss") 等段属性,将数据固定在独立内存段,避免与播放缓冲竞争;
  • enc_in_fatfs.c:录音写入 FAT 卷(外部存储),同样通过段属性隔离(.enc_in_fatfs.*)。

两者对应 FS_IOCTL_GET_ENCFOLDER_INFO 命令——上层查询录音文件夹信息时,由 VFS 分发到当前挂载的后端,从而统一了"录音文件浏览"逻辑,无论录音落在片内还是卡上。

简单的播放路径示例

u32 err = fs_mount(&ppctl->pfs, ppctl->device, "sydfile");
if (err) {
    // 挂载失败处理
}

Source: simple_play_file.c

VFS 还内置了演示函数 vfs_demo_sydfs()(vfs.c),展示 SYDF 挂载-打开-读取的完整调用序列,主程序 main.c 中以注释形式保留了调用示例(main.c)。

Core Flow:文件系统挂载与读写调用链

挂载 → 打开 → 读取(SYDF 场景)

sequenceDiagram
    participant App as 应用 (music_device)
    participant VFS as VFS (vfs.c)
    participant Ops as vfs_operations 表
    participant NOR as nor_fs 后端
    participant FLASH as SPI NOR Flash

    App->>VFS: fs_mount(&pfs, device, "sydfile")
    activate VFS
    VFS->>VFS: vfs_hdl_malloc() 分配 imount
    VFS->>VFS: list_for_each_vfs_operation 匹配 fs_type
    VFS->>Ops: ops->mount(&pfs, device)
    Ops->>NOR: norfs_mount(&pfs, device)
    NOR->>FLASH: 读取头部 (magic/first_sector)
    FLASH-->>NOR: norfs_flash_info_t
    NOR-->>Ops: 0 (成功)
    Ops-->>VFS: 0
    VFS->>VFS: pvfs->ops = ops (绑定函数表)
    VFS-->>App: 0
    deactivate VFS

    App->>VFS: fs_openbyindex(pfs, &pfile, index)
    activate VFS
    VFS->>Ops: ops->openbyindex(pfs, &pfile, index, NULL)
    Ops->>NOR: norfs_openbyindex(pfs, &pfile, index)
    NOR-->>Ops: 0
    Ops-->>VFS: 0
    VFS-->>App: pfile 就绪
    deactivate VFS

    App->>VFS: fs_read(pfile, buf, len)
    activate VFS
    VFS->>Ops: ops->read(pfile, buf, len)
    Ops->>NOR: norfs_read(pfile, buf, btr)
    NOR->>FLASH: 读 256B 页
    FLASH-->>NOR: 数据
    NOR-->>Ops: 实际字节数
    Ops-->>VFS: 实际字节数
    VFS-->>App: 实际字节数
    deactivate VFS

调用链要点:VFS 层自身不做任何介质操作,所有读写最终都落在后端函数上;imount.ops 在 mount 成功那一刻被绑定,之后文件操作无需再查表,避免每次调用都遍历注册链。

录音写入(nor_fs 顺序追加模型)

flowchart TD
    Start([录音开始]) --> Create["norfs_createfile<br/>分配索引 index + 起始扇区 sr"]
    Create --> Write["norfs_write<br/>按 256B 页顺序写入<br/>更新 w_len / rw_p"]
    Write --> Full{"扇区写满?"}
    Full -->|"否"| Write
    Full -->|"是"| Next["推进到下一扇区<br/>sector + 1"]
    Next --> More{"录音继续?"}
    More -->|"是"| Write
    More -->|"否"| Save["norfs_save_sr(pfile, sr)<br/>持久化起始扇区"]
    Save --> Close["norfs_closefile<br/>记录 REC_FILE_END (0xFE)"]
    Close --> End([录音结束])

nor_fs 的写入不覆盖既有数据、只做顺序追加,天然适配 NOR Flash "只能 1→0、擦除按块" 的物理特性;norfs_save_sr 在关闭前落盘起始扇区,保证掉电后仍能通过索引恢复文件。

Usage Examples

示例 1:按设备类型选择文件系统挂载

if (INNER_FLASH_RO == dev_index) {
    err = fs_mount(&ppctl->pfs, p_device, (void *)"sydfile");
    if (0 != err) {
        log_info("mount sydfile err 0x%x", err);
    }
} else {
    err = fs_mount(&ppctl->pfs, p_device, (void *)"fat");
}

Source: music_device.c

内部分区(INNER_FLASH_RO)挂 SYDF/nor_fs,外部可移动设备挂 FAT——这正是 VFS 多后端共存的典型用法。

示例 2:nor_fs 原生 API 调用序列

RECFILESYSTEM *pfs = NULL;
REC_FILE *pfile = NULL;
u32 index = 0, len = 0;

norfs_init(0, 4096, 8);                    // 扇区 0~4095,每扇区 256B
norfs_mount(&pfs, flash_dev);              // 挂载设备
norfs_createfile(pfs, &pfile, &index);     // 创建文件,分配索引
norfs_write(pfile, audio_data, 1024);      // 顺序写入
norfs_filelen(pfile, &len);                // 查询长度
norfs_closefile(&pfile);                   // 关闭

Source: nor_fs.h(API 原型依据)

注:上例为基于头文件原型的示意调用序列;实际封装见 nor_fs_resource.c 对 vfs_operations 的实现。

示例 3:VFS 全量初始化与挂载失败兜底

void vfs_init(void)
{
    struct vfs_operations *ops;
    list_for_each_vfs_operation(ops) {
        if (NULL != ops->init) {
            log_info("%s ops_init!!!\n", ops->fs_type);
            ops->init();
        }
    }
}

Source: vfs.c

vfs_init 在系统启动早期调用,遍历注册链完成所有后端的初始化;每个后端在 init 中打印 fs_type,便于日志定位。

Configuration Options

配置项类型默认值/取值说明
NORFS_MAGIC_NUM宏0x11223344nor_fs 卷头魔数,挂载时校验介质合法性
REC_FILE_END宏0xFE文件结束标记字节
FLASH_PAGE_SIZE / NORF_SECTOR_SIZE宏256nor_fs 扇区/页大小,对齐 NOR 编程页
norfs_init 的 sector_bit参数如 8扇区大小以 bit 表达(8 → 256B),决定地址换算
FS_IOCTL_SET_LFN_BUFioctl512BFAT 长文件名缓冲(FS_IOCTL_SET_LDN_BUF 同规格)
FS_IOCTL_SET_NAME_FILTERioctl后端相关设置文件过滤规则,扫描时生效
FS_IOCTL_SET_EXT_TYPEioctl后端相关设置后缀类型过滤
FS_IOCTL_SET_VOLioctl字符串设置 FAT 卷标
FS_IOCTL_GET_FREE_SPACEioctlu32查询剩余空间(FAT 后端)
FS_IOCTL_GET_PARTITION_INFOioctl结构体获取簇大小、容量等分区信息
FS_IOCTL_GET_ENCFOLDER_INFOioctl结构体获取录音文件夹信息(SYDF 场景)
FS_IOCTL_GET_ERR_CODEioctl—暂不支持(枚举注释明确标注)

配置方式说明:宏在编译期生效(nor_fs.h);运行时行为通过 vfs_operations.ioctl 的 FS_IOCTL_* 命令按需设置,属于典型的"编译期定结构、运行期定策略"嵌入式设计。

API Reference

VFS 层(vfs.h)

vfs_mount(void **ppvfs, void *device, void *type): u32

  • 参数:ppvfs 挂载句柄指针(可传入 NULL 让 VFS 分配);device 底层设备句柄;type 后端类型字符串(NULL 表示自动探测并跳过 "norfs")。
  • 返回:0 成功;E_NO_VFS 句柄池耗尽;E_NO_FS 无后端可挂载。
  • 行为:遍历 vfs_operations 注册链,匹配 fs_type 后调用 ops->mount;失败自动 close_fs 清理并释放句柄。

vfs_openbypath(void *pvfs, void **ppvfile, const char *path): u32

  • 参数:已挂载的 pvfs;文件句柄指针(NULL 则分配);path 文件路径。
  • 返回:0 成功;E_NO_VFS 句柄分配失败;后端错误码透传。
  • 行为:先分配 imount 文件句柄,再经 pvfs->ops->openbypath 分发(vfs.c)。

vfs_type_name(void *p_vfs): void *

  • 返回当前挂载点 ops->fs_type 字符串(NULL 入参返回 NULL),用于判断已挂载文件系统类型(vfs.c)。

nor_fs 层(nor_fs.h)

norfs_mount(RECFILESYSTEM **ppfs, void *p_device): u32

  • 参数:ppfs 文件系统句柄输出;p_device NOR Flash 设备句柄。
  • 返回:0 成功;非 0 失败(介质魔数不符等)。

norfs_createfile(RECFILESYSTEM *pfs, REC_FILE **ppfile, u32 *pindex): u32

  • 参数:pfs 已挂载句柄;ppfile 文件句柄输出;pindex 分配到的文件索引号输出。
  • 返回:0 成功;E_* 空间不足/索引耗尽。

norfs_read(REC_FILE *pfile, u8 *buff, u16 btr): u16

  • 参数:pfile 文件句柄;buff 目标缓冲;btr 请求字节数。
  • 返回:实际读取字节数(可能小于 btr,文件末尾截断)。
  • 说明:rw_p 游标前移;读到 REC_FILE_END (0xFE) 标记视为文件结束。

norfs_write(REC_FILE *pfile, u8 *buff, u16 btw): u16

  • 参数:pfile 文件句柄;buff 源数据;btw 请求写入字节数。
  • 返回:实际写入字节数;更新 w_len / rw_p。

norfs_seek(REC_FILE *pfile, u32 offsize, u32 type): u32

  • 参数:type 取 SEEK_SET(0) / SEEK_CUR(1) / SEEK_END(2)(vfs.h)。

norfs_closefile(REC_FILE **ppfile): u32 / norfs_filelen(REC_FILE *pfile, u32 *plen): u32 / norfs_save_sr(REC_FILE *pfile, u16 sr) / norfs_name(REC_FILE *pfile, char *name, u32 len): u32 / norfs_ioctl(REC_FILE *pfile, int cmd, int arg): int

  • 分别完成:关闭并释放句柄、查询文件长度、持久化起始扇区、拷贝 16B 文件名、扩展控制。

属性与常量

  • 文件属性位:F_ATTR_RO(0x01) 只读、F_ATTR_ARC(0x02) 归档、F_ATTR_DIR(0x04) 目录、F_ATTR_VOL(0x08) 卷标(vfs.h);
  • struct vfs_attr:attr(属性位)、fsize(文件大小)、sclust(起始簇/地址),由 ops->fget_attr 填充(vfs.h)。

Failure Modes、边界情况与并发

挂载失败路径

  • E_NO_VFS:VFS 句柄池耗尽(vfs_hdl_malloc 失败)。句柄池大小在 vfs_resource.c 中静态定义,多路同时挂载(音乐 + 录音 + 升级)时可能撞池,属可恢复错误,业务应重试或先卸载。
  • E_NO_FS:所有后端 mount 均失败,常见于:介质未就绪(卡未插好)、nor_fs 魔数不符(Flash 被擦除或分区信息损坏)、设备句柄非法。
  • type == NULL 时主动跳过 "norfs":防止无类型探测误挂片内 Flash,但也意味着片内卷必须显式传类型,这是常见误用点。

nor_fs 边界与一致性

  • 扇区耗尽:last_sector 写满后 norfs_createfile 返回失败——nor_fs 无碎片回收,录音满后需格式化(vfs_operations.format)才能复用空间。
  • 写中断/掉电:norfs_save_sr 只保存起始扇区,w_len 不落盘;掉电恢复后长度可能偏大,上层需以 REC_FILE_END 标记截断。这是"顺序追加 + 标记结束"模型的固有取舍。
  • 256B 页对齐:跨扇区写由 sector_bits 换算推进;非页对齐的读写长度在驱动层补齐,业务层应尽量按页对齐以获得确定性写时间。

并发与共享

  • VFS 句柄(imount/imount-file)由专用句柄池管理,同一挂载点的读写不保证线程安全;SDK 中 FAT/nor_fs 通常在单任务(如播放/录音任务)内串行访问。
  • enc_in_norfs.c / enc_in_fatfs.c 通过 #pragma bss_seg/.data_seg/.const_seg/.code_seg 把录音栈数据隔离到独立内存段,避免与播放 DMA 缓冲冲突——这是 SoC 内存分区约束下的显式并发防护。
  • FAT 后端的 fscan_interrupt 支持扫描中断回调,长扫描期间释放 CPU,播放任务可穿插执行,避免卡顿。

Performance 与运维提示

  • nor_fs 写入路径短:无目录树、无日志,一次写仅更新 rw_p/w_len,适合录音高频小块写入;代价是索引线性、文件数上限受 u16 total_file 约束。
  • FAT 扫描开销:TF 卡曲目枚举走 fscan_interrupt,大容量卡扫描耗时可观;FS_IOCTL_SET_NAME_FILTER / FS_IOCTL_SET_EXT_TYPE 可在扫描期过滤,显著减少回调解包。
  • 缓存释放:FS_IOCTL_FREE_CACHE 可主动释放 FAT 缓存,在内存紧张(如录音与播放并发)时调用。
  • 日志定位:vfs_init 打印各后端 fs_type;vfs_type_name 可运行时确认挂载类型,排障时先核对挂载类型是否与设备匹配。

Extension Points

  • 新增文件系统后端:实现 struct vfs_operations(fs_type、mount、openby*、read/write/seek 等)并注册到 list_for_each_vfs_operation 链(参见 vfs_fat.c 与 nor_fs_resource.c 的注册方式),上层无需改动即可通过 fs_mount(type) 使用。
  • 自定义 ioctl:在 FS_IOCTL_* 枚举后追加命令号,由各后端 ioctl 自行实现;注意 FS_IOCTL_GET_ERR_CODE 已预留但"暂不支持",可作为扩展位。
  • 格式化策略:vfs_operations.format(p_fs_hdl, device, clust_size, create_new) 暴露了按簇格式化能力,录音满盘恢复与量产初始化均可复用。

Related Links

  • nor_fs.h(nor_fs 全部 API 与数据结构)
  • vfs.h(VFS 函数表与 FS_IOCTL 定义)
  • vfs.c(VFS 实现:init/mount/openbypath/demo)
  • vfs_fat.c(FAT 后端实现)
  • vfs_fat.h(FAT 后端对外接口)
  • nor_fs_resource.c(nor_fs 的 vfs_operations 封装)
  • music_device.c(sydfile/fat 挂载调用方)
  • enc_in_norfs.c / enc_in_fatfs.c(录音编码写入层)
  • 相关目录页:存储设备驱动、录音流程、音乐播放流程
Prev
存储设备驱动 (NorFlash / SDMMC / USB)
Next
设备管理框架 (dev_mg)