
这期接着上一回聊 i.MX RTxxx 系列启动话题把 FlexSPI NOR 的连接方式彻底摊开讲。很多人拿到芯片先查参考手册但真到自己画板子、焊 flash、跑程序的时候往往在连线这一关就开始踩坑DQS 到底接不接SCLK 要不要串电阻多片 flash 怎么并联启动配置里的几个 bit 又是什么意思这些问题如果没搞清楚后面 Debug 起来特别痛苦。这篇我直接用项目里沉淀下来的经验把连接方式、引脚定义、启动配置一次性说透。1. 先从 FlexSPI 外设说起它到底管什么1.1 FlexSPI 不止是“SPI 控制器”很多人把 FlexSPI 当成普通 SPI 主机用其实它的能力边界比想象中大得多。FlexSPI 是恩智浦在 i.MX RT 系列上专门为串行 NOR Flash 设计的高速接口支持单线、双线、四线、八线多种数据位宽还内置了 AHB 总线映射和 XIP 执行逻辑。简单类比普通 SPI 像一条单车道的乡道一次只能过一辆车FlexSPI 的 DQ0–DQ7 就像双向八车道地址、命令、数据都能并行传输。启动时 CPU 直接从 NOR 里取指执行这个过程中 FlexSPI 既要承担翻译 NOR 命令的角色又要处理好 AHB 总线上突发的读请求任何一个环节卡住系统都起不来。我在实际调试中见过一种常见误解把 FlexSPI 的 DQS 信号当成可有可无的东西。在 SDR 模式下不接 DQS 确实能跑但一旦进入 DDR 模式或者外部 flash 的工作频率超过 60MHzDQS 就是决定时序收敛的关键信号。后面我会专门展开讲。1.2 为什么 NOR 是启动介质的首选i.MX RTxxx 系列没有内部非易失性存储器BootROM 必须从外部读取启动镜像。可供选择的无非是串行 NOR、串行 NAND、SD/eMMC、EEPROM 这些。NOR 之所以是绝对主流原因很朴素NOR 支持 XIP代码可以直接在 flash 上执行不需要先搬运到 RAM接口简单最少 4 根线就能完成启动读取延迟低适合时序敏感型应用厂商多、工具链成熟、烧录方便。但 NOR 也有硬伤容量小、写速度慢、价格偏高。所以实际项目中常见做法是小容量 NOR 放启动代码和关键配置大容量 NAND 或 eMMC 放文件系统和数据。这也是为什么理解 FlexSPI NOR 连接方式是所有 i.MX RT 项目的地基。2. 连接方式分类从单线到八线从单片到多片2.1 最基础的单线 SPI 模式SDR单线模式就是标准 SPISCLK、CS、MOSI、MISO 四根线。FlexSPI 里对应的是 SCK、CS0、DQ0输出、DQ1输入。这种方式兼容性最好市面上随便一颗 SPI NOR 都能用缺点是吞吐量太差1-bit 位宽下代码执行速度会被 flash 读带宽卡死。我接触的几个量产项目单线模式基本只用于两个场景一是极小容量1Mbit 以下的配置存储二是验证阶段临时用等硬件稳定后再切回 Quad 模式。如果你只是为了把系统跑起来单线模式确实是最快路径但别指望它跑出什么高性能。连接方式没有任何悬念直接照着原理图连就行。唯一要提醒的是SCLK 信号尽量靠近 IC 引脚走别绕远路CS 上拉到 VDD 的电阻建议保留防止上电瞬间 flash 误选中。2.2 双线Dual和四线Quad模式双线模式把地址/命令阶段的数据脚从 1 根扩到 2 根DQ0、DQ1四线模式再扩展 DQ2、DQ3。Quad 模式是当前 NOR 启动的绝对主力几乎所有主流 NOR flash 都支持读命令是 0xEBQuad Output Fast Read带宽是单线模式的 4 倍。连接方式上四线比单线多出两根数据线但注意这四根线都是双向的。IO 方向切换由 FlexSPI 内部控制硬件上不需要额外的方向控制芯片直接和 flash 对应引脚连即可。原理图里最常见的纠结点是 WP 和 HOLD 引脚WPWrite Protect建议接高电平或通过 10k 电阻上拉HOLDReset/Hold如果不用必须接高电平否则 Quad 模式下 DQ3 会被 Hold 信号干扰导致通信错乱。这两个脚在很多国产 flash 上是复用功能务必看数据手册确认是否支持 Quad 模式。我踩过一颗 flash 的坑脚位和标准型号兼容但内部没有把 HOLD 功能做进去四线读取直接死机换成另一款芯片立马正常。2.3 八线Octal模式新一代 flash 的高带宽路线八线模式是趋势。DTRDouble Transfer Rate加上 Octal 位宽理论上读带宽能跑到 200MB/s 以上这个性能已经接近并口 NOR 的水平。i.MX RT 系列部分型号支持 Octal 模式配合 Macronix MX25UM51345G、Adesto EcoXiP 这类芯片可以实现真正意义上的“内存映射启动”。连接方式上八线模式需要 8 根数据线DQ0–DQ7外加 DQS 信号。DQS 在 Octal DDR 模式下负责数据对齐类似 DDR 内存里的 DQS 功能。这里有个非常重要的细节DQS 不是所有 octal flash 都采用独立引脚有些芯片把 DQS 复用为 RESET 引脚要先发命令切换功能。如果你用的是这种 flash启动镜像里的 FlexSPI 配置块必须正确设置 DQS 引脚复用选项否则 BootROM 读不到数据。2.4 双片选与多 flash 扩展FlexSPI 外设支持最多 4 个片选CS0–CS3每个片选可以独立挂一颗 flash也可以把两片 flash 并联在同一组数据线上组成双倍容量。这就涉及到连接方式里的并联与级联并联Parallel两片 flash 共享数据线地址线分开用不同的 CS。启动时会读取搭载同一镜像的两颗 flash或按地址连续映射成一片大容量设备。级联Daisy-chain串行连接通常用于减少 GPIO 占用但 FlexSPI 原生不支持标准的 daisy-chain NOR 连接所以实际很少这么干。从 BootROM 的角度看它只会读取默认配置里的 CS0。如果你把启动镜像放在 CS1 上必须在 fuse 或 GPIO 配置里把 FlexSPI CS0 映射到外部引脚为 CS1。具体的映射方式参考芯片参考手册里的 Boot ROM 配置表。我自己做过一个双 flash 设计CS0 挂一颗 8MB NORCS1 挂一颗 32MB NOR两个区分别保存启动镜像和文件系统。操作上不复杂关键是 PCB 布局要把 CS 信号分开走别为了省事把两根 CS 信号线靠得太近末端反射会造成片选误触发。2.5 FlexSPI 引脚映射与复用说明i.MX RTxxx 系列的 FlexSPI 信号并非固定引脚而是通过 IOMUX 映射到不同 GPIO。常见映射如下功能信号常见引脚组 A常见引脚组 B备注SCKGPIO_AD_B0_15GPIO_SD_B1_07需要尽量短、等长CS0GPIO_AD_B0_10GPIO_SD_B1_11启动片选DQ0GPIO_AD_B0_09GPIO_SD_B1_06数据线DQ1GPIO_AD_B1_01GPIO_SD_B1_05数据线DQ2GPIO_AD_B1_02GPIO_SD_B1_04数据线DQ3GPIO_AD_B1_03GPIO_SD_B1_03数据线DQSGPIO_AD_B1_04GPIO_SD_B1_02可选Octal/DDR 用注意BootROM 启动时只会使用一组默认的 FlexSPI 引脚映射具体是哪一组取决于芯片的 boot mode 配置和 fuse 设定。如果你的应用代码里把 FlexSPI 引脚重新映射到了其他引脚组必须保证在 BootROM 阶段就已经选对了组否则启动根本进不来。3. 启动配置与 BOOT 引脚连接方式只是第一步3.1 启动模式引脚配置i.MX RTxxx 系列通常有几个 BOOT 相关引脚在上电复位时被采样。通过这些引脚的电平组合BootROM 决定从哪个外设启动。和 FlexSPI NOR 相关的配置通常包括BOOT_MODE0 / BOOT_MODE1选择串行下载Serial Downloader还是 Internal BootBOOT_CFG 引脚配置 FlexSPI 的位宽、频率、DQS 使能等参数。实际项目中不要依赖默认配置建议原理图上给这些 BOOT 引脚预留出跳线或 0 欧电阻位方便调试时切换启动介质。我曾经在产线上碰到过一批板子无法启动查到最后是 BOOT_CFG 引脚被外部下拉误拉低导致 BootROM 把 FlexSPI 配置成了错误的位宽。3.2 烧写 fuses 还是用 GPIO 配置FlexSPI NOR 启动参数有两条配置路径BootROM 先读取 BOOT_CFG GPIO 的默认电平如果 GPIO 配置无效或需要更大灵活性再读取 eFuse。eFuse 是一次性可编程的烧错就会废掉芯片。我的建议是调试阶段不要碰 eFuse优先使用 GPIO 配置等到进入量产、板级配置稳定后再考虑把关键参数固化到 eFuse。合理的流程是先用串行下载器配合烧录工具把启动镜像烧进 NOR然后通过 BOOT_CFG 引脚配置好 FlexSPI 参数验证通过后再决定是否烧 fuses。3.3 FlexSPI 配置块Flash Configuration Block详解BootROM 启动时会从 NOR Flash 的固定偏移地址读取 FlexSPI Configuration Block这个结构体里存放了 flash 厂商、容量、命令序列、时序参数等关键信息。对于使用“Serial NOR”通用启动方式的镜像这一块尤其重要。配置块里的几个关键字段字段作用常见值tag标识符0x42464346‘FCFB’version配置块版本0x0100 / 0x0101readSampleClkSrc读采样时钟源0内部 Loopback1DQScsHoldTime / csSetupTime片选保持/建立时间一般 0x01columnAddressWidth列地址宽度38-bit或 416-bitdeviceModeCfgEnable是否配置 Octal/DDR 模式1 表示需要发送模式配置命令deviceType设备类型0NOR1NANDsflashPadType引脚位宽0单线1双线2四线3八线serialClockFreq串行时钟频率0x0C约 60MHz等这个配置块一旦出错现象往往是启动时 BootROM 一直卡在 flash ID 读取阶段。我调试时最常用的排查手段就是打开 MCU 的 BootROM 日志一般能看到 “Identify the NOR device failed” 之类的提示。3.4 镜像布局IVT 和 Boot Data 的位置NOR Flash 上的启动镜像布局遵循 i.MX 系列固定格式偏移 0x0000保留区域偏移 0x1000或被配置的偏移Image Vector TableIVTIVT 之后是 Boot Data再往后才是真正的应用代码。IVT 里最关键的是 self 和 entry 两个字段。entry 指向应用代码首地址FlexSPI 控制器会从该地址开始做 XIP 映射。如果连接方式和实际 flash 不匹配即使 IVT 偏移正确CPU 取指时读到的数据也是错的典型表现就是执行第一条指令直接 hard fault。我建议在工程里专门写一个启动头脚本把 IVT 放在 0x60000000内存映射后的 NOR 基地址 0x1000 的位置。这样既能满足 BootROM 的读取要求也能让调试器直接识别到代码入口。4. 调试手法与常见故障定位4.1 用 MCU 工具直接验证连接到了调试阶段硬件连接有没有问题最好在工作台上直接验证。步骤不复杂把芯片切成 Serial Downloader 模式通过 USB 或 UART 连接 MCU 工具使用工具里的 FlexSPI 烧录功能先读取 flash ID如果 ID 读不到优先检查引脚连接和电源如果 ID 能读到但校验失败检查 SCLK 频率和时序参数。这一步能在 5 分钟内区分“硬件连接错误”和“软件配置错误”比反复擦写 flash 高效得多。有些工具还支持直接在内存映射地址读写 flash 内容可以快速验证 XIP 是否正常。4.2 FlexSPI NOR 连接典型故障速查故障现象可能原因排查建议读不到 flash IDCS 没拉低、SCK 不对示波器看 CS 和 SCK 波形能读 ID 但代码跑飞位宽不匹配实际走 Quad 但配置单线检查 sflashPadType高频下数据错乱DQS 信号没连或配置不对尝试降低频率验证代码能跑但偶发死机电源纹波大、flash 供电电压偏低万用表测 flash VDD确认 3.3V/1.8V启动时一直卡在 BootROMBOOT_CFG 配置错误检查 BOOT_CFG 电平组合镜像校验通过但跳转失败IVT entry 地址错误核对 link 脚本偏移4.3 使用示波器观察关键时序FlexSPI 调试最直观的手段还是抓波形。我通常会把示波器探头挂在这四个位置SCLK、CS0、DQ0/DQ1。启动时观察是否有正常的帧序列CS 拉低发送命令字节例如读 ID 命令 0x9F数据线上返回 flash IDCS 拉高。如果命令发出去了但 MISO 一直为空基本可以判断 flash 侧出了问题比如焊接虚焊或 flash 进入了意外的低功耗模式。如果命令波形根本不完整那就是 FlexSPI 控制器端的时钟或复位没就绪。5. 几个实战案例连接方式不同坑也不同5.1 案例一四线模式忘记给 HOLD 引脚上拉一块新板子原理图参照旧项目改的flash 型号从 W25Q64 换成了 GD25Q64。烧录器能正常识别 flash但 BootROM 启动失败。排查发现 GD25Q64 的 HOLD 引脚在旧方案里悬空旧 flash 默认内部上拉所以没暴露问题新 flash 内部配置不同悬空导致 DQ3 被 Hold 信号干扰。解决方法是把 HOLD 引脚通过 10k 电阻上拉到 VCC同时在 fuse 里把 Quad 模式使能位确认正确。5.2 案例二Octal 模式的 DQS 配置失误另一块板子用的是支持 Octal 的 Adesto flash原理图上 DQS 连接的是 RESET 引脚。由于配置块里没有把 DQS 引脚复用开启BootROM 发完读命令后采样不到对齐信号整个启动卡死在 flash 初始化。后来在配置块里把 readSampleClkSrc 设为 DQS并正确配置 DQS 引脚功能才跑通。这里想强调一点Octal flash 不一定默认工作在 Octal 模式必须通过配置命令把器件切进去有些型号还要先发 enable octal 命令顺序不能错。5.3 案例三并联双片导致启动不稳有客户为扩大容量把两颗 flash 并联使用结果发现偶尔启动不稳定。本质问题出在并联总线的负载过大FlexSPI 的驱动能力有限多设备负载造成信号边沿劣化。解决措施是在数据线上加了 22Ω 串阻并将 SCLK 频率从 60MHz 降到 30MHz。代价是性能降低但稳定性显著提升。并联扩展容量这种方案不能只看容量翻倍电气性能的牺牲必须有预案。6. 连接方式的选择建议选连接方式时先问自己三个问题代码要直接在 flash 里跑还是搬运到 RAM需要 XIP 就把频率和位宽放在优先位工作温度范围是多少高温下时序裕量变小四线高频可能跑不稳供应链里主推哪家 flash不同厂商的引脚兼容性没想象中那么统一。从性价比角度我目前最推荐的是四线 SDR 100MHz 频率组合。这个组合几乎能覆盖所有 i.MX RTxxx 项目性能和成本都相对平衡。追求极致性能的项目可以上 Octal DTR DQS但必须接受调试复杂度和信号完整性设计上的额外成本。如果让我给一个起步模板是这样的原理图上 FlexSPI 引脚全部复用一组固定 GPIO方便驱动代码统一管理HOLD/WP 全部上拉DQS 预留焊盘先不贴SCLK、DQ 线上预留 22Ω 串阻位置;BOOT_CFG 引脚全部加跳线至 VCC/GND方便现场切换配置。这套模板已经帮我节省了多次改板时间建议新项目直接套用。7. 从启动到正常运行一个小技巧最后分享一个实践小技巧调试 FlexSPI NOR 启动时别一直在 BootROM 阶段打转。如果 BootROM 已经把控制权交给你了但应用代码里对外设重新初始化后反而跑飞不妨查一下 FlexSPI 控制器的 AHB RX Buffer 和中断配置。BootROM 默认配置下的 buffer 大小和 cache 策略和应用代码里的预期未必一致这不算连接问题但表现特别像硬件连线错误。另一个实用做法是给 SDK 里的flexspi_nor_config.c里的时序参数加注释把每一次改动的硬件依据写清楚。项目过去几个月后你再回头看这些参数不会一头雾水。我手里还攒了不少和 FlexSPI 相关的调试案例涉及不同 flash 厂商的兼容性差异、DQS 在高温下的眼图变化、以及把启动镜像和固件升级放同一颗粒的布局技巧。后面有机会再单独写几篇展开。