SFUD源码分析

SFUD 源码分析

1. 仓库概览

SFUD(Serial Flash Universal Driver)是一个通用的串行闪存驱动库,专为嵌入式系统设计。它支持多种串行闪存芯片,提供统一的操作接口,简化了闪存的读写、擦除等操作。

主要功能/亮点:

  • 支持多种串行闪存芯片,包括 Winbond、GigaDevice、 Macronix、Cypress 等主流厂商的产品
  • 支持 SPI 和 QSPI 接口模式
  • 支持 SFDP(Serial Flash Discoverable Parameters)标准,自动识别闪存参数
  • 提供统一的 API 接口,简化闪存操作
  • 支持 4 字节地址模式,可处理大于 16MB 的闪存
  • 支持多种擦除模式和写入模式

典型应用场景:

  • 嵌入式系统中的固件存储
  • 配置数据的持久化存储
  • 日志数据的存储
  • 物联网设备中的数据存储

2. 目录结构

SFUD 项目采用清晰的分层架构,将核心功能与平台适配代码分离。核心源码位于 sfud 目录,包含了驱动的主要实现。demo 目录提供了不同平台的示例代码,方便用户快速上手。

t:\MCU\SFUD-master\
├── demo/                 # 示例代码
│   ├── esp32_ext_spi_flash/  # ESP32 平台示例
│   ├── stm32f10x_non_os/     # STM32F10x 无操作系统示例
│   ├── stm32f2xx_rtt/        # STM32F2xx 带 RT-Thread 示例
│   └── readme.md              # 示例说明
├── docs/                 # 文档
│   ├── zh/                 # 中文文档
│   └── readme.md           # 文档说明
├── sfud/                 # 核心源码
│   ├── inc/               # 头文件
│   │   ├── sfud.h          # 主头文件
│   │   ├── sfud_cfg.h      # 配置头文件
│   │   ├── sfud_def.h      # 定义头文件
│   │   └── sfud_flash_def.h # 闪存芯片定义头文件
│   ├── port/              # 平台适配层
│   │   └── sfud_port.c     # 端口实现
│   └── src/               # 源码实现
│       ├── sfud.c          # 主要实现
│       └── sfud_sfdp.c     # SFDP 实现
├── .gitattributes
├── LICENSE
├── README.md
├── library.json
└── note.txt
  • sfud/inc/:包含库的所有头文件,定义了 API 接口、数据结构和常量。
  • sfud/src/:包含库的核心实现,包括闪存操作的主要逻辑。
  • sfud/port/:包含平台适配代码,需要用户根据具体硬件平台实现。
  • demo/:包含不同平台的示例代码,展示如何使用 SFUD 库。

3. 系统架构与主流程

SFUD 采用分层架构设计,将硬件操作与业务逻辑分离,提高了代码的可移植性和可维护性。

系统架构

平台适配层

SPI读写

QSPI读写

延迟函数

锁操作

核心功能层

硬件初始化

软件初始化

闪存识别

操作执行

API层

sfud_init

sfud_read

sfud_write

sfud_erase

sfud_chip_erase

应用层

SFUD API层

核心功能层

平台适配层

硬件层

主流程

  1. 初始化流程

    • 调用 sfud_init() 初始化所有闪存设备
    • 对每个闪存设备调用 sfud_device_init()
    • 执行硬件初始化(hardware_init()):初始化 SPI 接口,读取 JEDEC ID,识别闪存芯片
    • 执行软件初始化(software_init()):设置软件参数
  2. 读写流程

    • 读取操作:调用 sfud_read(),发送读取命令,等待数据返回
    • 写入操作:调用 sfud_write(),发送写使能命令,执行页编程,等待操作完成
    • 擦除操作:调用 sfud_erase(),发送擦除命令,等待操作完成
  3. 闪存识别流程

    • 读取 JEDEC ID(厂商ID、类型ID、容量ID)
    • 尝试读取 SFDP 参数(如果支持)
    • 如果 SFDP 读取失败,从内置的闪存信息表中查找

4. 核心功能模块

4.1 闪存识别模块

该模块负责识别闪存芯片的型号和参数,是 SFUD 能够支持多种闪存的基础。

  • JEDEC ID 读取:通过 read_jedec_id() 函数读取闪存的 JEDEC ID,包含厂商ID、类型ID和容量ID
  • SFDP 参数读取:通过 sfud_read_sfdp() 函数读取闪存的 SFDP 参数,获取更详细的闪存信息
  • 闪存信息表:当 SFDP 读取失败时,从内置的 flash_chip_table 中查找匹配的闪存信息

4.2 读写操作模块

该模块提供了闪存的读写操作,支持不同的写入模式。

  • 读取操作sfud_read() 函数支持普通读取和快速读取模式
  • 写入操作
    • page256_or_1_byte_write():支持页编程(256字节)和字节写入模式
    • aai_write():支持自动地址递增写入模式
  • 擦除操作
    • sfud_erase():支持扇区擦除
    • sfud_chip_erase():支持整片擦除

4.3 QSPI 支持模块

该模块提供了对 QSPI 接口的支持,提高了数据传输速度。

  • 快速读取sfud_qspi_fast_read_enable() 函数启用 QSPI 快速读取模式
  • 命令格式设置qspi_set_read_cmd_format() 函数设置 QSPI 读取命令格式

4.4 SFDP 解析模块

该模块负责解析闪存的 SFDP 参数,获取闪存的详细信息。

  • SFDP 头部读取read_sfdp_header() 函数读取 SFDP 头部信息
  • 基本参数表读取read_basic_table() 函数读取 JEDEC 基本参数表
  • 擦除参数获取sfud_sfdp_get_suitable_eraser() 函数获取合适的擦除参数

5. 核心 API/类/函数

5.1 初始化相关函数

函数名描述参数返回值
sfud_init()初始化 SFUD 库sfud_err:操作结果
sfud_device_init()初始化指定的闪存设备sfud_flash *flash:闪存设备指针sfud_err:操作结果
sfud_get_device()获取指定索引的闪存设备size_t index:设备索引sfud_flash *:闪存设备指针
sfud_get_device_num()获取闪存设备总数size_t:设备数量

5.2 读写操作函数

函数名描述参数返回值
sfud_read()读取闪存数据const sfud_flash *flash:闪存设备
uint32_t addr:起始地址
size_t size:读取大小
uint8_t *data:数据缓冲区
sfud_err:操作结果
sfud_write()写入闪存数据(不擦除)const sfud_flash *flash:闪存设备
uint32_t addr:起始地址
size_t size:写入大小
const uint8_t *data:数据缓冲区
sfud_err:操作结果
sfud_erase()擦除闪存数据const sfud_flash *flash:闪存设备
uint32_t addr:起始地址
size_t size:擦除大小
sfud_err:操作结果
sfud_erase_write()先擦除后写入闪存数据const sfud_flash *flash:闪存设备
uint32_t addr:起始地址
size_t size:操作大小
const uint8_t *data:数据缓冲区
sfud_err:操作结果
sfud_chip_erase()擦除整个闪存const sfud_flash *flash:闪存设备sfud_err:操作结果

5.3 状态操作函数

函数名描述参数返回值
sfud_read_status()读取闪存状态寄存器const sfud_flash *flash:闪存设备
uint8_t *status:状态缓冲区
sfud_err:操作结果
sfud_write_status()写入闪存状态寄存器const sfud_flash *flash:闪存设备
bool is_volatile:是否为易失性写入
uint8_t status:状态值
sfud_err:操作结果

5.4 QSPI 相关函数

函数名描述参数返回值
sfud_qspi_fast_read_enable()启用 QSPI 快速读取模式sfud_flash *flash:闪存设备
uint8_t data_line_width:数据总线宽度
sfud_err:操作结果

5.5 核心数据结构

sfud_flash 结构
typedef struct {
    char *name;                                  /**< 串行闪存名称 */
    size_t index;                                /**< 闪存设备信息表中的索引 */
    sfud_flash_chip chip;                        /**< 闪存芯片信息 */
    sfud_spi spi;                                /**< SPI 设备 */
    bool init_ok;                                /**< 初始化成功标志 */
    bool addr_in_4_byte;                         /**< 闪存是否处于 4 字节寻址模式 */
    struct {
        void (*delay)(void);                     /**< 每次重试的延迟 */
        size_t times;                            /**< 默认错误重试次数 */
    } retry;
    void *user_data;                             /**< 用户数据 */

#ifdef SFUD_USING_QSPI
    sfud_qspi_read_cmd_format read_cmd_format;   /**< 快速读取命令格式 */
#endif

#ifdef SFUD_USING_SFDP
    sfud_sfdp sfdp;                              /**< 串行闪存可发现参数 */
#endif

} sfud_flash, *sfud_flash_t;
sfud_spi 结构
typedef struct __sfud_spi {
    /* SPI 设备名称 */
    char *name;
    /* SPI 总线读写数据函数 */
    sfud_err (*wr)(const struct __sfud_spi *spi, const uint8_t *write_buf, size_t write_size, uint8_t *read_buf,
                   size_t read_size);
#ifdef SFUD_USING_QSPI
    /* QSPI 快速读取函数 */
    sfud_err (*qspi_read)(const struct __sfud_spi *spi, uint32_t addr, sfud_qspi_read_cmd_format *qspi_read_cmd_format,
                          uint8_t *read_buf, size_t read_size);
#endif
    /* 锁定 SPI 总线 */
    void (*lock)(const struct __sfud_spi *spi);
    /* 解锁 SPI 总线 */
    void (*unlock)(const struct __sfud_spi *spi);
    /* 用户数据 */
    void *user_data;
} sfud_spi, *sfud_spi_t;

6. 技术栈与依赖

技术/依赖用途来源
C 语言主要开发语言标准库
SPI 接口与闪存通信硬件平台
QSPI 接口高速数据传输硬件平台(可选)
SFDP 标准闪存参数自动识别JEDEC 标准
JEDEC ID闪存芯片识别闪存芯片

7. 关键模块与典型用例

7.1 基本读写操作

功能说明:实现闪存的基本读写操作,包括读取、写入和擦除。

配置与依赖

  • 需要在 sfud_cfg.h 中配置闪存设备信息表 SFUD_FLASH_DEVICE_TABLE
  • 需要实现 sfud_spi_port_init() 函数初始化 SPI 接口

使用示例

#include "sfud.h"

int main(void) {
    sfud_err result;
    uint8_t read_buf[256];
    uint8_t write_buf[256] = "Hello, SFUD!";
    
    // 初始化 SFUD 库
    result = sfud_init();
    if (result != SFUD_SUCCESS) {
        printf("SFUD init failed: %d\n", result);
        return -1;
    }
    
    // 获取第一个闪存设备
    sfud_flash *flash = sfud_get_device(0);
    if (!flash) {
        printf("Get flash device failed\n");
        return -1;
    }
    
    // 擦除指定区域
    result = sfud_erase(flash, 0x0, 256);
    if (result != SFUD_SUCCESS) {
        printf("Erase failed: %d\n", result);
        return -1;
    }
    
    // 写入数据
    result = sfud_write(flash, 0x0, 256, write_buf);
    if (result != SFUD_SUCCESS) {
        printf("Write failed: %d\n", result);
        return -1;
    }
    
    // 读取数据
    result = sfud_read(flash, 0x0, 256, read_buf);
    if (result != SFUD_SUCCESS) {
        printf("Read failed: %d\n", result);
        return -1;
    }
    
    printf("Read data: %s\n", read_buf);
    
    return 0;
}

7.2 QSPI 快速读取

功能说明:启用 QSPI 快速读取模式,提高数据读取速度。

配置与依赖

  • 需要在 sfud_cfg.h 中定义 SFUD_USING_QSPI
  • 需要实现 qspi_read 函数

使用示例

#include "sfud.h"

int main(void) {
    sfud_err result;
    
    // 初始化 SFUD 库
    result = sfud_init();
    if (result != SFUD_SUCCESS) {
        printf("SFUD init failed: %d\n", result);
        return -1;
    }
    
    // 获取第一个闪存设备
    sfud_flash *flash = sfud_get_device(0);
    if (!flash) {
        printf("Get flash device failed\n");
        return -1;
    }
    
    // 启用 QSPI 快速读取模式,数据总线宽度为 4
    result = sfud_qspi_fast_read_enable(flash, 4);
    if (result != SFUD_SUCCESS) {
        printf("QSPI fast read enable failed: %d\n", result);
        return -1;
    }
    
    // 后续的读取操作将使用 QSPI 快速读取模式
    
    return 0;
}

8. 配置、部署与开发

8.1 配置选项

SFUD 提供了多个配置选项,可在 sfud_cfg.h 文件中设置:

配置项描述默认值
SFUD_DEBUG_MODE启用调试模式未定义
SFUD_USING_SFDP启用 SFDP 支持未定义
SFUD_USING_QSPI启用 QSPI 支持未定义
SFUD_USING_FLASH_INFO_TABLE启用闪存信息表未定义
SFUD_USING_FAST_READ启用快速读取未定义
SFUD_FLASH_DEVICE_TABLE闪存设备信息表必须定义

8.2 平台适配

使用 SFUD 时,需要实现以下平台适配函数:

  1. sfud_spi_port_init():初始化 SPI 接口
  2. spi.wr():SPI 读写函数
  3. spi.lock()spi.unlock():SPI 总线锁定/解锁函数()
  4. delay 延时函数()

8.3 开发流程

  1. 配置 SFUD:在 sfud_cfg.h 中设置配置选项和闪存设备信息表
  2. 实现平台适配:实现 SPI 接口和必要的回调函数
  3. 初始化 SFUD:调用 sfud_init() 初始化库
  4. 使用 API:调用 SFUD 提供的 API 进行闪存操作

9. 监控与维护

9.1 错误处理

SFUD 提供了错误码机制,通过 sfud_err 枚举定义了各种错误类型:

typedef enum {
    SFUD_SUCCESS = 0,                                      /**< 成功 */
    SFUD_ERR_NOT_FOUND = 1,                                /**< 未找到或不支持 */
    SFUD_ERR_WRITE = 2,                                    /**< 写入错误 */
    SFUD_ERR_READ = 3,                                     /**< 读取错误 */
    SFUD_ERR_TIMEOUT = 4,                                  /**< 超时错误 */
    SFUD_ERR_ADDR_OUT_OF_BOUND = 5,                        /**< 地址超出闪存范围 */
} sfud_err;

9.2 日志系统

SFUD 提供了日志系统,可通过以下函数输出日志:

  • sfud_log_debug():调试日志
  • sfud_log_info():信息日志

用户需要在平台适配层实现这些函数。

9.3 常见问题与解决方案

问题原因解决方案
初始化失败SPI 接口未正确初始化检查 SPI 初始化代码
读写失败闪存保护位已设置调用 sfud_write_status() 清除保护位
地址错误地址超出闪存范围检查地址和大小是否正确
QSPI 模式失败QSPI 接口未正确实现检查 QSPI 相关代码

10. 总结与亮点回顾

SFUD 是一个设计精良的串行闪存驱动库,具有以下亮点:

  1. 通用性:支持多种串行闪存芯片,提供统一的操作接口
  2. 灵活性:支持 SPI 和 QSPI 接口,可根据硬件平台选择
  3. 智能识别:支持 SFDP 标准,可自动识别闪存参数
  4. 可移植性:平台适配层与核心逻辑分离,易于移植到不同平台
  5. 可靠性:完善的错误处理和重试机制
  6. 高性能:支持 QSPI 快速读取模式,提高数据传输速度

SFUD 的设计思路值得学习:

  • 分层架构:将硬件操作与业务逻辑分离,提高代码可维护性
  • 模块化设计:核心功能模块化,便于扩展和测试
  • 标准支持:遵循 JEDEC 标准,提高兼容性
  • 配置灵活:通过配置选项可裁剪功能,适应不同场景

SFUD 不仅是一个实用的闪存驱动库,也是嵌入式系统中设备驱动设计的优秀范例。它的设计思想和实现技术对于理解嵌入式系统中的设备驱动开发具有参考价值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值