NOR FLASH 驱动配置参数指南

5 阅读8分钟

/**

  • NOR FLASH 驱动配置参数指南
  • 本文档详细说明你需要配置的所有参数,以及如何根据硬件实际情况进行调整 */

========================================================================================

第一部分:基础硬件配置(最重要)

========================================================================================

1.1 电源与时钟配置

位置:src/build/config/boards/[你的板子]/config.in

CONFIG_HAS_SFC=y                    ✅ 启用 SFC 控制器
CONFIG_SFC_CLK_GATE=y               ✅ SFC 时钟门控(推荐)
CONFIG_HI_SFC_SPEED_MODE=3          ⚙️  SPI 速度:0=33MHz, 1=66MHz, 2=100MHz, 3=150MHz
CONFIG_SFC_SUPPORT_QUAD=y           ⚙️  是否支持 QUAD SPI(高端芯片)

✅ 验证:确保 SFC 时钟已启用,否则 SFC 读写会失败


1.2 引脚配置

位置:src/board/[你的板子]/board.c 或 board_pin_config.c

需要配置以下 SPI 引脚:

信号用途推荐引脚必需
CLK时钟GPIO_x✅ 必需
MOSI主出从入数据线GPIO_y✅ 必需
MISO主入从出数据线GPIO_z✅ 必需
CS片选GPIO_w✅ 必需
WP写保护(Quad SPI)GPIO_v⭕ Quad SPI 需要
HOLD暂停(Quad SPI)GPIO_u⭕ Quad SPI 需要

配置示例:

hal_gpio_config(GPIO_CLK, GPIO_MODE_AF, GPIO_AF_SFC);
hal_gpio_config(GPIO_MOSI, GPIO_MODE_AF, GPIO_AF_SFC);
hal_gpio_config(GPIO_MISO, GPIO_MODE_AF, GPIO_AF_SFC);
hal_gpio_config(GPIO_CS, GPIO_MODE_AF, GPIO_AF_SFC);

========================================================================================

第二部分:SFC 驱动配置

========================================================================================

2.1 SFC 初始化配置

文件:src/drivers/chips/ws63/porting/sfc/sfc_porting.h

// 宏定义配置
#define SFC_BASE_ADDR               0x40200000   // ✅ SFC 控制器基地址(固定)
#define SFC_AHB_CLOCK_GATE_ADDR     0x4000xxxx   // ⚙️  时钟门控寄存器地址

// Flash 映射配置
#define FLASH_MAPPING_START_ADDR    0x200000     // ⚙️  Flash 在 CPU 地址空间的映射起始
#define FLASH_MAPPING_MAX_SIZE      0x400000     // ⚙️  映射最大大小(通常 4MB)

2.2 SFC 工作模式配置

在初始化时调用:

sfc_flash_config_t sfc_config = {
    .mapping_addr = 0x200000,           // ⚙️  映射地址
    .mapping_size = 0x400000,           // ⚙️  映射大小
    .read_type = QUAD_READ,             // ⚙️  读模式(见下表)
    .write_type = QUAD_PROGRAM,         // ⚙️  写模式(见下表)
    .erase_size = ERASE_4K,             // ⚙️  擦除粒度
    .auto_switch = 1,                   // ✅ 自动降级(降速但兼容)
};

uapi_sfc_init(&sfc_config);

读模式选项(read_type)

模式性能兼容性使用场景
STANDARD_READ33MHz最好✅ 所有芯片通用
FAST_READ50MHz很好稳定性要求高
DUAL_READ66MHz中等需要均衡方案
QUAD_READ150MHz一般✖️ 仅特定芯片支持

优先级:STANDARD_READ → FAST_READ → DUAL_READ → QUAD_READ

写模式选项(write_type)

模式性能说明
PAGE_PROGRAM标准✅ 所有芯片支持(推荐)
QUAD_PROGRAM快速仅部分高端芯片支持

建议:先用 PAGE_PROGRAM,确保基础功能正常


2.3 自动芯片检测与配置

SFC 驱动会自动:

  1. 检测 Flash 芯片 ID
  2. 在 flash_config_info.c 的表中查找

位置:src/drivers/chips/ws63/porting/sfc/flash_config/flash_config_info.c

支持的芯片列表(可在此添加新芯片):

✅ GigaDevice GD25Q32 (1640C8) - 32Mbit, 推荐用于 WS63
✅ Winbond W25Q32 (1660EF) - 32Mbit, 兼容性好
✅ Winbond W25Q64 (1760EF) - 64Mbit
✅ GigaDevice GD25LQ64 (1760C8) - 64Mbit, 低电压
❌ 其他型号需要自己添加配置

========================================================================================

第三部分:littlefs 分区配置

========================================================================================

3.1 分区配置

文件:src/include/middleware/partition/partition_table.h 或 board_config.json

// littlefs 使用的分区定义
#define CONFIG_LFS_PARTITION_ID     1           // ⚙️  littlefs 分区 ID
#define CONFIG_LFS_START_ADDR       0x200000    // ⚙️  必须与 SFC 映射地址一致
#define CONFIG_LFS_PARTITION_SIZE   0x40000     // ⚙️  littlefs 分区大小(256KB)

分区布局示例

Flash 地址空间(4MB 总容量):

0x000000 ┌─────────────────┐
         │ Boot (512KB)    │ ← Bootloader
0x080000 ├─────────────────┤
         │ App (1.5MB)     │ ← 应用程序
0x200000 ├─────────────────┤
         │ littlefs (256KB)│ ← SFC 映射开始
         │ (4K blocks)     │
0x240000 ├─────────────────┤
         │                 │
         │ User Data Area  │ ← 日志文件区
         │ (3.5MB+ 剩余)   │
         │                 │
0x400000 └─────────────────┘

⚠️ 重点

  • 确保 littlefs 分区与 SFC 映射地址对齐
  • 不要让 app 和 littlefs 分区重叠
  • littlefs 分区 = SFC 映射地址的起点

3.2 littlefs 文件系统配置

文件:src/kernel/osal/include/fs_adapt.h 或 littlefs_adapt.h

// Block 配置(必须与硬件一致)
#define LFS_BLOCK_SIZE      4096      // ✅ 固定 4KB
#define LFS_BLOCKS          256       // ⚙️  block 数量 = 分区大小 / 4KB
                                      //    如果分区 256KB,则 256 blocks

// Cache 配置
#define LFS_CACHE_SIZE      16        // ✅ 推荐 16
#define LFS_LOOKAHEAD       16        // ✅ 推荐 16

// 读写配置
#define LFS_READ_SIZE       16        // ✅ 最小读取单位
#define LFS_PROG_SIZE       256       // ⚙️  编程大小(与 Flash 页大小对应)

========================================================================================

第四部分:日志管理器配置

========================================================================================

4.1 日志存储配置

文件:log_manager.h

// 日志存储位置配置
#define LOG_PARTITION_ID            1           // ⚙️  使用同一个分区
#define LOG_MOUNT_POINT             "/logs"     // ⚙️  littlefs 中的日志目录
#define LOG_MAX_FILE_SIZE           1048576     // ✅ 单个日志文件最大 1MB
#define LOG_MAX_FILES               20          // ⚙️  最多保存 20 个日志文件

// 时间戳配置
#define LOG_TIMESTAMP_FORMAT        "YYYYMMDD_HHMMSS"  // ✅ 日志文件名时间格式

// 清理策略
#define LOG_CLEANUP_THRESHOLD       10          // ⚙️  超过 10 个文件时清理旧文件
#define LOG_AUTO_CLEANUP            1           // ✅ 开启自动清理

4.2 Flash 容量配置

// 日志分配的 Flash 空间
#define LOG_TOTAL_SPACE             (3 * 1024 * 1024)  // ⚙️  3MB 用于日志
#define MIN_FREE_SPACE              (512 * 1024)       // ⚙️  至少保留 512KB

// 监控警告
#define SPACE_WARNING_THRESHOLD     (80)  // ⚙️  空间 80% 满时告警
#define CRITICAL_SPACE_THRESHOLD    (95)  // ⚙️  空间 95% 满时严重告警

========================================================================================

第五部分:调试与验证

========================================================================================

5.1 编译配置

在 CMakeLists.txt 中确保启用调试符号和日志:

# 调试级别
set(CMAKE_BUILD_TYPE Debug)

# 编译选项
add_compile_options(-g)                    # 调试符号
add_compile_options(-O0)                   # 关闭优化(便于调试)
add_compile_options(-DDEBUG_SFC=1)        # ⚙️  SFC 调试日志
add_compile_options(-DDEBUG_LFS=1)        # ⚙️  littlefs 调试日志
add_compile_options(-DDEBUG_LOG=1)        # ⚙️  日志管理器调试

5.2 日志输出配置

启用以下调试输出:

#define DEBUG_SFC           1   // ⚙️  打印 SFC 操作日志
#define DEBUG_LFS           1   // ⚙️  打印 littlefs 操作日志  
#define DEBUG_LOG_MGR       1   // ⚙️  打印日志管理器操作
#define DEBUG_PERF          1   // ⚙️  打印性能指标

========================================================================================

第六部分:常见问题排查

========================================================================================

问题 1:SFC 初始化失败

▶ 症状:uapi_sfc_init() 返回错误

✅ 检查清单:

  1. CONFIG_HAS_SFC=y 已启用
  2. SPI 引脚已正确配置
  3. Flash 芯片与驱动板连接正确
  4. 硬件电源正常(3.3V)
  5. Flash 芯片不是坏的或损坏的

▶ 调试步骤:

errcode_t ret = uapi_sfc_init(&config);
printf("SFC init result: 0x%X\n", ret);
if (ret != ERRCODE_SUCC) {
    printf("Error code meaning: %s\n", get_error_string(ret));
}

问题 2:Flash ID 检测失败

▶ 症状:读到的 ID 是 0xFFFFFFFF 或 0x000000

✅ 检查清单:

  1. SPI CLK 信号是否正常
  2. MISO 线连接有无松动
  3. CS 线是否被正确拉低
  4. 检查示波器上是否有时序波形

▶ 调试步骤:

uint32_t flash_id;
hal_sfc_get_flash_id(&flash_id);
printf("Flash ID: 0x%06X\n", flash_id & 0xFFFFFF);

// 查询支持列表
if (flash_id not in supported_list) {
    printf("Warning: Flash chip not in support list!\n");
}

问题 3:littlefs 挂载失败

▶ 症状:fs_adapt_mount() 失败或 fs_adapt_open() 返回错误

✅ 检查清单:

  1. 分区地址与 SFC 映射地址一致
  2. littlefs 分区不能与其他分区重叠
  3. 上次未正常卸载文件系统
  4. Flash 空间不足

▶ 调试步骤:

int ret = fs_adapt_mount();
if (ret != LFS_ERR_OK) {
    printf("littlefs mount failed: %d\n", ret);
    // 尝试格式化
    fs_adapt_format();  // ⚠️  这会清除所有数据!
}

问题 4:文件读写正教失败

▶ 症状:写入成功但读不出来

✅ 检查清单:

  1. 是否调用了 fs_adapt_sync() 或 fsync()
  2. 文件指针是否在正确位置
  3. 有无缓冲区溢出
  4. Flash 是否损坏

▶ 调试步骤:

int fd = fs_adapt_open("/test.txt", O_RDWR | O_CREAT);
int written = fs_adapt_write(fd, "test", 4);
fs_adapt_sync(fd);  // ⚠️  必须调用
fs_adapt_lseek(fd, 0, SEEK_SET);  // 重置指针
char buf[10];
int read = fs_adapt_read(fd, buf, 4);
printf("Wrote %d, Read %d\n", written, read);

问题 5:性能低于预期

▶ 症状:读写速度 < 10MB/s(预期 150MB/s)

✅ 检查清单:

  1. 是否使用了 QUAD_READ 模式
  2. SFC 时钟频率是否设置最高 (150MHz)
  3. 是否有系统滴答中断影响
  4. Cache 是否启用

▶ 调试步骤:

// 检查配置
printf("SFC Read Mode: %d (0=STANDARD, 3=QUAD)\n", sfc_config.read_type);
printf("SFC Clock: %dMHz\n", sfc_get_clock_mhz());

// 运行性能测试
test_read_performance();

========================================================================================

第七部分:配置清单(实施步骤)

========================================================================================

第一步:物理硬件验证

  • 确认 Flash 芯片型号(标签上印的)
  • 检查 SPI 接线:CLK, MOSI, MISO, CS
  • 使用万用表测量电源电压(3.3V ± 0.2V)
  • 用示波器观察 SPI 时序

第二步:驱动配置

  • 在 build config 中启用 SFC (CONFIG_HAS_SFC=y)
  • 配置 SPI 引脚映射
  • 检查 Flash 芯片是否在 flash_config_info.c 支持列表中
  • 设置 SFC 时钟频率为 150MHz

第三步:分区配置

  • 确定 littlefs 分区起始地址和大小
  • 更新 CONFIG_LFS_START_ADDR 与 SFC 映射地址对齐
  • 确保分区不重叠

第四步:littlefs 配置

  • 设置 LFS_BLOCK_SIZE = 4096
  • 计算 LFS_BLOCKS = 分区大小 / 4096
  • 设置 LFS_PROG_SIZE = 256

第五步:日志管理器配置

  • 设置 LOG_MOUNT_POINT = "/logs"
  • 设置 LOG_MAX_FILE_SIZE = 1MB
  • 设置 LOG_MAX_FILES = 20

第六步:编译与测试

  • 编译驱动:make
  • 烧录到板子
  • 运行测试套件:nor_flash_driver_test_suite
  • 查看测试结果报告

========================================================================================

总结

========================================================================================

配置项文件位置优先级说明
CONFIG_HAS_SFCboard config🔴 必须启用 SFC
SPI 引脚映射board.c🔴 必须CLK/MOSI/MISO/CS
Flash 芯片型号flash_config_info.c🔴 必须决定支持的模式
SFC 时钟频率sfc_porting.h🟡 重要影响性能
littlefs 分区地址partition.h🔴 必须与 SFC 映射对齐
littlefs 分区大小partition.h🟡 重要决定容量
日志目录log_manager.h🟢 次要默认即可
日志文件大小限制log_manager.h🟢 次要默认 1MB 即可

下一步:运行 nor_flash_driver_test_suite 验证所有配置是否正确!