/**
- NOR FLASH 驱动快速测试指南
- 本指南帮助你快速验证 NOR Flash 驱动是否工作正常
- 预计花时间:30-60 分钟 */
========================================================================================
快速测试攻略:5 个步骤验证 NOR Flash
========================================================================================
步骤 1️⃣:编译测试套件
# 进入代码目录
cd d:\code\fbb_ws63-master
# 编译整个项目(包括 NOR Flash 驱动)
python src/build.py -b WS63_board -m release
# 或者如果使用 CMake (可选)
cd build
cmake ..
make
编译过程中检查:
- SFC 驱动是否编译成功
- littlefs 驱动是否编译成功
- 日志管理器是否编译成功
- 没有链接错误
步骤 2️⃣:物理硬件检查
在烧录到板子之前,先检查硬件连接:
使用万用表检查
测试项目 标准值 你的测试结果
────────────────────────────────────────────────────────
Flash 电源 (VCC) 3.3V ± 0.2V ┌─────────┐
│ │
└─────────┘
地 (GND) 0V ┌─────────┐
│ OK/NOK │
└─────────┘
Flash 芯片型号 (查看标签) ┌─────────┐
如 GD25Q32 │ │
└─────────┘
使用示波器检查 SPI 信号
信号 频率范围 波形 连接检查
────────────────────────────────────────────────────────
CLK 33-150 MHz ▃▂▃▂▃▂ [ ] 有信号
MOSI 跟随 CLK ▄▅▄▅▄▅ [ ] 有信号
MISO 跟随 CLK ▄▅▄▅▄▅ [ ] 有信号
CS 低电平选中 ╔║╚║╔║ [ ] 有脉冲
✅ 如果所有信号都正常,proceed to step 3
步骤 3️⃣:烧录到板子
# 使用 HiSparkStudio 或命令行工具
# 以 HiSparkStudio 为例:
1. 打开 HiSparkStudio
2. 连接开发板(USB 或 JTAG)
3. 选择项目文件夹
4. 配置编译选项
5. 点击 "Build and Flash"
# 也可以用命令行
python tools/hiflash.py --board WS63_board --image build/ws63_App.bin
烧录进度:
- 0% ─────────────────────────── 100%
步骤 4️⃣:运行测试套件
方法 A:通过串口运行(推荐)
# 1. 打开串口终端工具(如 SecureCRT, Tera Term, PuTTY)
# 2. 连接到开发板的串口
# 3. 波特率:115200
# 4. 数据位:8,停止位:1,校验:None
# 在开发板上运行命令
>> nor_flash_driver_test_suite
# 如果没有这个命令,可能需要在代码中做以下调整
方法 B:在代码中集成测试
如果不能直接执行,修改 main.c:
#include "nor_flash_driver_test_suite.h"
int main(void) {
// app_init();
// 调用测试(可选)
int test_result = test_sfc_device();
if (test_result == 0) {
printf("✅ All tests PASSED!\n");
} else {
printf("❌ Some tests FAILED!\n");
}
// 继续正常应用程序流程
// app_run();
return 0;
}
步骤 5️⃣:检查测试结果
5.1 预期输出示例
════════════════════════════════════════
NOR Flash Driver Test Suite
════════════════════════════════════════
Configuration Summary:
NOR Flash Start: 0x00200000
Max Mapping Size: 4096 KB (4.00 MB)
Read Interface: QUAD_READ (150MHz)
Write Interface: QUAD_PROGRAM
════════════════════════════════════════
Level 1: Hardware Detection
════════════════════════════════════════
[TEST] SFC Driver Initialization
- Mapping address: 0x00200000
- Mapping size: 0x00400000
✅ PASSED: SFC initialization
[TEST] Flash ID Detection
- Detected Flash ID: 0x1640C8
- Chip Name: GigaDevice GD25Q32
✅ PASSED: Flash ID detection
[TEST] Flash Configuration Verification
- Flash chip detection: OK
- Command set loaded: OK
- Protection bits: Verified
✅ PASSED: Flash config verification
════════════════════════════════════════
Level 2: Basic Read/Write/Erase
════════════════════════════════════════
[TEST] Basic Write Test
- Writing 36 bytes at 0x00200000
- Erase 4K block: OK
- Data written: OK
✅ PASSED: Basic write
[TEST] Basic Read Test
- Reading 36 bytes from 0x00200000
- Read data: OK
- Data verify: OK
- Content: Hello NOR Flash! This is a test.
✅ PASSED: Basic read
[TEST] Basic Erase Test
- Writing pattern 0xAA to 4K block
- Erasing 4K block...
- Verifying erased data (should be 0xFF)...
- Erase verification: OK
✅ PASSED: Basic erase
════════════════════════════════════════
Test Summary
════════════════════════════════════════
Total Tests: 12
Passed: 12 (100.0%)
Failed: 0
Skipped: 0
Total Bytes Tested: 5.34 MB
Total Time: 245.63 ms
════════════════════════════════════════
5.2 结果分析
| 结果 | 含义 | 下一步 |
|---|---|---|
| ✅ 100% PASSED | 完美! | 开始集成日志系统 |
| ⚠️ 80-99% PASSED | 大部分功能正常 | 调查失败的测试项 |
| ❌ < 80% PASSED | 有严重问题 | 返回步骤 2,检查硬件 |
5.3 如果测试失败
失败 1:SFC 初始化失败
❌ FAILED: SFC initialization
ERROR: SFC init failed with code 0x xxxxx
✅ 解决方案:
- 检查 CONFIG_HAS_SFC=y
- 检查 SPI 引脚是否正确映射
- 检查 Flash 芯片电源
失败 2:Flash ID 检测失败
❌ FAILED: Flash ID detection
ERROR: Failed to read Flash ID
Detected Flash ID: 0x00000000 或 0xFFFFFFFF
✅ 解决方案:
- 检查 SPI 接线(特别是 MISO 线)
- 使用示波器观察 SPI 信号
- 检查 Flash 芯片是否损坏
失败 3:Basic Write/Read 失败
❌ FAILED: Basic write
ERROR: Erase failed with code 0x xxxxx
✅ 解决方案:
- 检查分区地址是否正确
- 检查 Flash 是否是写保护状态
- 尝试其他读写地址
失败 4:littlefs 挂载失败
❌ FAILED: littlefs mount
ERROR: mount failed with errno xxxxx
✅ 解决方案:
- 确保分区与 SFC 映射地址一致
- 清空 Flash:
fs_adapt_format() - 重新初始化文件系统
========================================================================================
高级测试:逐项验证
========================================================================================
测试 A:单独测试 SFC 驱动
如果完整测试失败,逐项测试以定位问题:
/* 最小化测试代码 */
#include "sfc.h"
int main(void) {
// 1. 测试初始化
printf("1. Testing SFC initialization...\n");
sfc_flash_config_t cfg = {
.mapping_addr = 0x200000,
.mapping_size = 0x400000,
.read_type = STANDARD_READ, // 先用标准模式
.write_type = PAGE_PROGRAM,
};
if (uapi_sfc_init(&cfg) != ERRCODE_SUCC) {
printf("ERROR: SFC init failed!\n");
return -1;
}
printf("✅ SFC initialized\n");
// 2. 测试 ID 读取
printf("\n2. Testing Flash ID detection...\n");
uint32_t flash_id;
if (hal_sfc_get_flash_id(&flash_id) != ERRCODE_SUCC) {
printf("ERROR: Cannot read Flash ID!\n");
return -1;
}
printf("✅ Flash ID: 0x%08X\n", flash_id);
// 3. 测试简单擦除
printf("\n3. Testing erase...\n");
if (uapi_sfc_reg_erase(0x200000, 4096) != ERRCODE_SUCC) {
printf("ERROR: Erase failed!\n");
return -1;
}
printf("✅ Erase successful\n");
// 4. 测试简单写入
printf("\n4. Testing write...\n");
uint8_t test_data[] = "TEST";
if (uapi_sfc_reg_write(0x200000, test_data, 4) != ERRCODE_SUCC) {
printf("ERROR: Write failed!\n");
return -1;
}
printf("✅ Write successful\n");
// 5. 测试简单读取
printf("\n5. Testing read...\n");
uint8_t read_buf[10] = {0};
if (uapi_sfc_reg_read(0x200000, read_buf, 4) != ERRCODE_SUCC) {
printf("ERROR: Read failed!\n");
return -1;
}
printf("✅ Read successful: %s\n", (char *)read_buf);
printf("\n✅ All basic tests passed!\n");
return 0;
}
编译并运行:
gcc -o test_sfc test_sfc.c -lsfc
./test_sfc
# 预期输出:
# ✅ SFC initialized
# ✅ Flash ID: 0x1640C8
# ✅ Erase successful
# ✅ Write successful
# ✅ Read successful: TEST
# ✅ All basic tests passed!
测试 B:单独测试 littlefs
#include "littlefs_adapt.h"
int main(void) {
printf("Testing littlefs...\n");
// 1. 挂载文件系统
printf("1. Mounting...\n");
int ret = fs_adapt_mount();
if (ret != LFS_ERR_OK) {
printf("ERROR: mount failed %d\n", ret);
printf(" Trying format...\n");
fs_adapt_format();
ret = fs_adapt_mount();
if (ret != LFS_ERR_OK) {
printf("ERROR: still failed!\n");
return -1;
}
}
printf("✅ Mounted\n");
// 2. 创建目录
printf("2. Creating directory...\n");
fs_adapt_mkdir("/logs");
printf("✅ Directory created\n");
// 3. 创建文件
printf("3. Creating file...\n");
int fd = fs_adapt_open("/logs/test.txt", O_RDWR | O_CREAT);
if (fd < 0) {
printf("ERROR: open failed\n");
return -1;
}
printf("✅ File created (fd=%d)\n", fd);
// 4. 写入数据
printf("4. Writing data...\n");
const char *data = "Hello littlefs!";
int written = fs_adapt_write(fd, data, strlen(data));
printf("✅ Written %d bytes\n", written);
// 5. 同步
printf("5. Syncing...\n");
fs_adapt_sync(fd);
printf("✅ Synced\n");
// 6. 重新定位
printf("6. Seeking to start...\n");
fs_adapt_lseek(fd, 0, SEEK_SET);
printf("✅ Seeked\n");
// 7. 读取数据
printf("7. Reading data...\n");
char buffer[32] = {0};
int read = fs_adapt_read(fd, buffer, sizeof(buffer));
printf("✅ Read %d bytes: %s\n", read, buffer);
fs_adapt_close(fd);
fs_adapt_unmount();
printf("\n✅ All littlefs tests passed!\n");
return 0;
}
测试 C:性能基准
#include <time.h>
void benchmark_read(void) {
uint8_t buf[4096];
uint32_t start_addr = 0x200000;
clock_t start = clock();
for (int i = 0; i < 100; i++) {
uapi_sfc_reg_read(start_addr, buf, 4096);
}
clock_t end = clock();
double ms = (double)(end - start) / CLOCKS_PER_SEC * 1000;
double throughput = 100.0 * 4096 / 1024 / 1024 / (ms / 1000);
printf("Read Performance:\n");
printf(" 100 x 4KB reads in %.2f ms\n", ms);
printf(" Throughput: %.2f MB/s\n", throughput);
printf(" ✅ Expected: 50-150 MB/s depending on SPI mode\n");
}
void benchmark_write(void) {
uint8_t buf[256];
uint32_t start_addr = 0x200000;
clock_t start = clock();
for (int i = 0; i < 100; i++) {
uapi_sfc_reg_erase(start_addr + i * 4096, 4096);
uapi_sfc_reg_write(start_addr + i * 4096, buf, 256);
}
clock_t end = clock();
double ms = (double)(end - start) / CLOCKS_PER_SEC * 1000;
double throughput = 100.0 * 256 / 1024 / 1024 / (ms / 1000);
printf("\nWrite Performance:\n");
printf(" 100 x (erase 4KB + write 256B) in %.2f ms\n", ms);
printf(" Throughput: %.2f MB/s\n", throughput);
printf(" ✅ Expected: 1-10 MB/s depending on erase time\n");
}
========================================================================================
常见问题快速表
========================================================================================
| 症状 | 可能原因 | 快速解决 |
|---|---|---|
| SFC 初始化 fail | SFC 未启用 | 检查 CONFIG_HAS_SFC=y |
| Flash ID = 0xFFFFFFFF | MISO 线未连接 | 检查 SPI 接线 |
| Flash ID = 0x000000 | SPI 时钟未启用 | 检查时钟门控寄存器 |
| 写入成功但读不出 | 未调用 sync | 添加 fs_adapt_sync(fd) |
| littlefs mount fail | 分区地址错 | 检查 CONFIG_LFS_START_ADDR |
| 读写速度慢 | 用的 STANDARD_READ | 切换到 QUAD_READ |
| 文件损坏 | Flash 寿命已尽 | 更换 Flash 芯片 |
========================================================================================
验证检查表(打印并填写)
========================================================================================
测试项 状态 备注
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
编译成功 [ ] ✅ ❌
烧录成功 [ ] ✅ ❌
SFC 初始化测试 [ ] ✅ ❌
Flash ID 检测 [ ] ✅ ❌ ID: _____
基础写入测试 [ ] ✅ ❌
基础读取测试 [ ] ✅ ❌
基础擦除测试 [ ] ✅ ❌
littlefs 挂载 [ ] ✅ ❌
文件创建测试 [ ] ✅ ❌
文件写入测试 [ ] ✅ ❌
文件读取测试 [ ] ✅ ❌
性能基准测试 [ ] ✅ ❌ 速度: __MB/s
整体测试通过率 ___%
批准人: ________________ 日期: ____________
========================================================================================
后续步骤
========================================================================================
✅ 如果所有测试通过,恭喜!你可以:
-
集成日志管理系统
使用 log_manager.c/h 实现 20+ 文件日志 -
开始应用开发
// 现在可以安心使用文件系统 int fd = fs_adapt_open("/logs/app.log", O_APPEND | O_CREAT); fs_adapt_write(fd, log_data, size); -
性能优化
- 换用 QUAD_READ 获得 150MB/s 性能 - 优化缓冲区大小 - 批量操作减少上下文切换
❌ 如果测试失败,按以下顺序排查:
- 物理硬件连接(看硬件)
- 驱动配置参数(看软件配置)
- 固件烧录(重新烧录)
- 芯片损坏(更换芯片)
祝你测试顺利!🎉