)
嵌入式开发实战为U-Boot添加XT25F128B SPI Nor Flash支持全流程解析拿到一块新开发板时最令人头疼的莫过于发现U-Boot无法识别板载的SPI Nor Flash。屏幕上赫然显示着unrecognized JEDEC id bytes: 0b, 40, 18这样的错误信息对于刚接触嵌入式开发的工程师来说这就像一堵无形的墙。本文将带你从零开始一步步解决这个问题以XT25F128B为例完整呈现从错误分析到源码修改的全过程。1. 理解SPI Nor Flash识别机制1.1 JEDEC ID的核心作用SPI Nor Flash的识别依赖于JEDEC标准定义的制造商ID和设备ID。当U-Boot启动时会通过SPI总线发送JEDEC ID读取命令(0x9F)Flash芯片会返回3个字节的响应第1字节制造商ID如0x0B代表XTX第2-3字节设备ID具体型号/* U-Boot中读取JEDEC ID的典型代码 */ static int spi_flash_read_id(struct spi_flash *flash, u8 *id) { u8 cmd CMD_READ_ID; return spi_flash_read_common(flash, cmd, 1, id, SPI_FLASH_MAX_ID_LEN); }1.2 U-Boot的Flash识别流程U-Boot通过以下步骤识别SPI Flash发送JEDEC ID读取命令将读取到的ID与spi_flash_ids[]数组中的条目比对找到匹配项后加载对应的参数容量、扇区大小等初始化Flash操作函数指针当找不到匹配的ID时就会抛出我们看到的unrecognized JEDEC id错误。2. 定位问题与源码分析2.1 从错误信息入手看到错误信息unrecognized JEDEC id bytes: 0b, 40, 18时我们需要记录这三个字节0x0B, 0x40, 0x18查阅XT25F128B的数据手册确认这是否是该Flash的合法JEDEC ID在XT25F128B的规格书中我们确实能找到对应的ID信息字节位置值含义第1字节0x0B制造商XTX第2字节0x40设备ID高字节第3字节0x18设备ID低字节2.2 追踪U-Boot源码在U-Boot源码中Flash识别主要涉及以下文件drivers/mtd/spi/spi_flash.c核心识别逻辑drivers/mtd/spi/spi_flash_ids.cFlash型号数据库include/spi_flash.h数据结构定义关键数据结构spi_flash_params定义了U-Boot如何描述一个Flash芯片struct spi_flash_params { const char *name; u8 id[SPI_FLASH_MAX_ID_LEN]; u16 page_size; u16 sector_size; u16 nr_sectors; u32 size; u32 flags; };3. 添加新Flash型号支持3.1 修改spi_flash_ids.c找到drivers/mtd/spi/spi_flash_ids.c文件我们需要在spi_flash_ids[]数组中添加XT25F128B的条目。观察现有条目会发现类似W25Q128FV的配置可能是很好的参考{ .name W25Q128FV, .id {0xef, 0x40, 0x18}, .page_size 256, .sector_size 4096, .nr_sectors 4096, .size 0x1000000, .flags SPI_FLASH_HAS_SST_WRITE, }对于XT25F128B我们修改为{ .name XT25F128B, .id {0x0b, 0x40, 0x18}, // 匹配报错的JEDEC ID .page_size 256, .sector_size 4096, // 4KB扇区 .nr_sectors 4096, // 16MB容量 .size 0x1000000, .flags SPI_FLASH_HAS_NORMAL_WRITE, }3.2 理解INFO宏的奥秘U-Boot中常用INFO宏简化Flash定义其参数含义如下#define INFO(_name, _jedec_id, _ext_id, _sector_size, _n_sectors, _flags)注意_ext_id用于需要额外ID字节的Flash大多数现代SPI Nor Flash不需要。对于XT25F128B使用INFO宏的定义方式为INFO(XT25F128B, 0x0b4018, 0, 4096, 4096, SPI_FLASH_HAS_NORMAL_WRITE)4. 设备树同步修改4.1 检查SPI控制器配置即使U-Boot能识别Flash仍需要确保SPI控制器的设备树配置正确。在arch/arm/dts/目录下找到对应板子的.dts文件检查以下内容SPI控制器的兼容性字符串时钟频率设置SPI模式通常mode0spi0 { status okay; flash0 { #address-cells 1; #size-cells 1; compatible jedec,spi-nor; reg 0; spi-max-frequency 50000000; spi-tx-bus-width 1; spi-rx-bus-width 1; }; };4.2 Flash分区适配根据实际需求可能还需要调整Flash的分区布局partitions { compatible fixed-partitions; #address-cells 1; #size-cells 1; partition0 { label u-boot; reg 0x0 0x100000; }; partition100000 { label kernel; reg 0x100000 0x800000; }; partition900000 { label rootfs; reg 0x900000 0x700000; }; };5. 编译与验证5.1 编译U-Boot完成代码修改后执行编译流程make clean make menuconfig # 确认SPI Flash驱动已启用 make -j$(nproc)常见问题如果修改后编译报错检查是否在正确的位置添加了Flash定义以及所有大括号和逗号是否正确闭合。5.2 烧录与测试将生成的u-boot.bin烧录到开发板后启动时观察输出U-Boot 2023.04 (Jun 15 2023 - 14:20:35 0800) CPU: Freescale i.MX6ULL rev1.1 528 MHz (running at 396 MHz) DRAM: 512 MiB Flash: 16 MiB In: serial Out: serial Err: serial Net: FEC0 SF: Detected XT25F128B with page size 256 Bytes, erase size 4 KiB, total 16 MiB看到Detected XT25F128B表示Flash已成功识别。可以进一步使用U-Boot命令验证 sf probe SF: Detected XT25F128B with page size 256 Bytes, erase size 4 KiB, total 16 MiB sf read 82000000 0 1000 md 820000006. 进阶调试技巧6.1 当ID仍然不匹配时如果添加定义后U-Boot仍然报错可能是SPI通信问题用示波器检查CLK、MOSI、MISO信号电压不匹配确认Flash工作电压与板子供电一致上拉电阻缺失SPI总线需要适当的上拉6.2 性能优化建议在设备树中调整SPI时钟频率可以提升读写性能spi-max-frequency 50000000; /* 从25MHz提升到50MHz */但需注意提高SPI时钟可能导致信号完整性问题建议逐步增加频率并通过读写测试验证稳定性6.3 多Flash芯片支持对于板载多个SPI Flash的情况需要在设备树中添加多个flashx节点并为每个芯片指定不同的片选信号(reg属性)flash0 { compatible jedec,spi-nor; reg 0; /* 其他参数 */ }; flash1 { compatible jedec,spi-nor; reg 1; /* 其他参数 */ };7. 常见问题与解决方案7.1 典型错误排查表错误现象可能原因解决方案unrecognized JEDEC idFlash未在U-Boot中定义添加正确的Flash定义SF: unrecognized flashID读取失败检查SPI连线与电源timeout waiting for flash擦除/写入超时检查Flash状态寄存器write failed写保护使能检查WP引脚或发送WREN命令read returns wrong dataSPI模式不匹配确认设备树中的spi-rx/tx模式7.2 调试工具推荐逻辑分析仪Saleae Logic Pro 16捕获SPI总线通信解码JEDEC ID读取过程OpenOCDopenocd -f interface/cmsis-dap.cfg -f target/imx6ull.cfg通过JTAG/SWD接口直接调试U-Boot命令sf probe初始化SPI Flashsf read/md组合验证读取功能sf erase测试擦除操作在实际项目中遇到Flash识别问题时保持耐心是关键。记得有一次在调试一块定制板时花了三天时间才发现问题竟然是Flash的VCC引脚虚焊。这种经验告诉我当软件修改无效时一定要回头检查硬件基础。