1. 问题现象与背景拆解1.1 这个报错到底在说什么J-Flash 弹出Could not find CFI compliant flash device字面意思是“找不到符合 CFI 规范的 Flash 设备”。CFI 全称 Common Flash Interface是 NOR Flash 芯片用来向外部工具“自我介绍”的一套标准查询协议。J-Flash 在连接上芯片内核之后会尝试通过 CFI 命令去读取外部 Flash 的厂商 ID、设备 ID、扇区布局等信息读不到就报这个错。关键在于这个报错针对的是外部 NOR Flash不是 STM32F405OG 内部的 Flash。STM32F405OG 是 ST 的 Cortex-M4 芯片封装为 WLCSP90内部有 1MB Flash但很多实际项目里工程师会把代码或数据放到板载的外部 NOR Flash比如 W25Q 系列、S25FL 系列上或者干脆是芯片选型时用了外扩存储的板子。J-Flash 的工程配置如果指向了外部 Flash 的烧录算法而实际硬件上那颗 Flash 没焊、型号不匹配、或者引脚没连通就会直接触发这个报错。我见过太多人第一反应是“芯片坏了”或者“J-Link 坏了”其实大部分情况下是工程配置和实际硬件对不上。这个报错本身不可怕可怕的是不知道它从哪来。1.2 为什么 STM32F405OG 特别容易踩这个坑STM32F405OG 属于 STM32F4 系列里的高配型号主频 168MHz带 FPU很多工业控制、音频处理、电机驱动的板子会用它。这类板子常见的设计是MCU 内部 Flash 放 bootloader 和核心逻辑外部挂一颗 SPI NOR Flash 放字库、音频采样、日志数据或者固件备份。于是烧录时就有两种需求只烧内部 Flash用 J-Flash 选 STM32F405OG 的内部 Flash 算法即可一般不会报 CFI 错。同时烧外部 Flash需要给 J-Flash 指定外部 Flash 的烧录算法.FLM 文件或 J-Flash 自带的 Flash 数据库这时候 CFI 检测就会介入。问题就出在第二种场景。外部 Flash 的型号五花八门J-Flash 自带的数据库不一定覆盖你板子上那颗或者你的 Flash 是通过 SPI 挂载的而 J-Flash 默认按并行 NOR 的 CFI 方式去探测协议层就不匹配。再加上 STM32F405OG 的引脚复用灵活SPI 引脚可能被重映射到不同端口硬件上如果没接对J-Flash 自然读不到 CFI 信息。还有一个隐蔽点STM32F405OG 的 BOOT 引脚配置会影响启动模式。如果 BOOT0 拉高进入了系统存储器启动模式J-Flash 连接时可能识别到的是 ROM bootloader 而不是用户 Flash后续 CFI 探测也会失败。这个细节后面会展开。1.3 解决思路总览针对这个报错我总结下来三条主线按排查优先级排列确认目标你到底要烧内部 Flash 还是外部 Flash工程配置里的地址范围对不对确认硬件外部 Flash 是否实际存在、型号是否匹配、SPI 连线是否正常、供电是否到位。确认工具链J-Flash 版本、J-Link 驱动、烧录算法文件是否匹配 STM32F405OG 和你的外部 Flash。下面按这三个方向逐一拆解每种方法都给出可复现的操作步骤和判断依据。2. 方法一修正 J-Flash 工程配置与烧录地址2.1 先搞清楚 J-Flash 工程里配了什么打开 J-Flash点File - Open Project或者直接看当前工程设置。重点看三个地方Target Interface是 SWD 还是 JTAG。STM32F405OG 常用 SWD两根线 SWCLK 和 SWDIO加上 GND 和 VCC参考电平。如果这里选错连都连不上更别说 CFI 了。CPU是否选的是 STM32F405OG 或同系列。选错型号会导致 Flash 算法加载错误。Flash选项卡这里列出了当前工程要烧录的 Flash 区域。如果里面有一行地址范围不在 STM32F405OG 内部 Flash 的 0x08000000~0x080FFFFF 之内比如 0x90000000 或 0x00000000 开头的外部地址那 J-Flash 就会去探测外部 Flash触发 CFI 检测。我遇到过一个典型案例工程师从别人那里拷来一个 J-Flash 工程里面配了外部 Flash 的烧录算法地址从 0x90000000 开始但他自己的板子根本没焊外部 Flash。结果每次烧录都报 CFI 错。把那一行删掉只保留内部 Flash 区域问题立刻消失。2.2 只烧内部 Flash 的正确配置如果你的需求只是把固件烧进 STM32F405OG 内部 Flash操作如下打开 J-FlashFile - New Project新建一个干净工程。Target Interface选SWD速度先设 1000kHz稳定后再往上调。CPU里搜索STM32F405OG选中对应型号。如果没有完全一致的选STM32F405RG或同系列同 Flash 大小的型号通常也能兼容因为内核和 Flash 控制器一致。进入Flash选项卡确认只有一行起始地址0x08000000大小0x1000001MB。这是 STM32F405OG 内部 Flash 的标准映射。在Production Programming里指定要烧录的 .hex 或 .bin 文件。如果是 .bin需要手动填起始地址 0x08000000。点Target - Connect连接成功后点Target - Program Verify。这套流程走下来只要硬件没问题不会出现 CFI 报错。因为 J-Flash 用的是 STM32F405OG 内部 Flash 的编程算法不涉及外部 CFI 探测。注意如果你用的是 .bin 文件务必确认起始地址。.bin 不带地址信息填错地址会导致程序跑飞而且 J-Flash 不会报错因为它只管按你给的地址写。2.3 需要烧外部 Flash 时的配置要点如果确实要烧外部 SPI NOR FlashJ-Flash 的配置就复杂一些。以常见的 W25Q128 为例在Flash选项卡里添加一行起始地址填外部 Flash 映射到的 MCU 地址空间。比如 STM32F405OG 通过 FSMC 或 SPI 映射地址可能是 0x90000000 或 0xA0000000具体看你的硬件设计。选择对应的 Flash 算法。J-Flash 自带一些常见 NOR Flash 的算法如果没有你的型号需要自己用 J-Flash 的Flash Algorithm工具生成或者从 Flash 厂商官网下载 .FLM 文件。如果外部 Flash 是 SPI 接口J-Flash 默认的 CFI 探测可能不适用因为 CFI 主要针对并行 NOR。这时候需要在算法里指定 SPI 命令序列或者改用支持 SPI Flash 的烧录方式。这里有个经验J-Flash 对外部 SPI Flash 的支持不如对内部 Flash 那么直接。很多工程师最后改用 STM32CubeProgrammer 或者自己写 bootloader 来烧外部 Flash反而更省事。J-Flash 更适合内部 Flash 和并行 NOR。2.4 地址范围与芯片实际容量的匹配检查STM32F405OG 内部 Flash 是 1MB地址范围 0x08000000 到 0x080FFFFF。如果你在 J-Flash 里配的范围超过了这个比如配到 0x08100000J-Flash 可能会尝试访问不存在的地址导致连接异常或 CFI 误报。检查方法很简单在 J-Flash 的Flash选项卡里看每一行的Start和Size。内部 Flash 那行必须是0x08000000和0x100000。多出来的行要么是外部 Flash要么是误配根据实际硬件决定保留还是删除。另外STM32F405OG 的选项字节Option Bytes里可以配置读写保护。如果芯片被读保护了J-Flash 连接后可能无法正确读取 Flash 信息也可能间接导致 CFI 报错。用 ST-Link Utility 或 STM32CubeProgrammer 解除读保护后再试。3. 方法二排查硬件连接与外部 Flash 实际状态3.1 SWD 连接质量直接影响 CFI 探测CFI 探测是在 J-Link 成功连接芯片内核之后进行的。如果 SWD 连接不稳定J-Flash 可能连内核都没连上却报了一个 CFI 错误让人误以为是 Flash 问题。所以第一步永远是确认 SWD 连接可靠。检查清单SWCLK 和 SWDIO 是否接对STM32F405OG 的 SWD 引脚默认是 PA13SWDIO和 PA14SWCLK但有些板子会复用或重映射确认原理图。上拉电阻是否到位SWDIO 通常需要 10k 上拉SWCLK 需要 10k 下拉有些设计省略但建议保留。参考电压是否接J-Link 的 VTref 要接到板子的 VDD通常是 3.3V。不接的话 J-Link 无法识别目标电平。线缆是否过长SWD 在高速下对线长敏感超过 20cm 就容易出问题。先降到 500kHz 试试。板子是否独立供电如果板子靠 J-Link 供电电流不够会导致芯片工作异常。STM32F405OG 功耗不低建议外部供电。我实测过一根劣质杜邦线SWD 连接时好时坏J-Flash 偶尔报 CFI 错偶尔报SWD/JTAG communication failure。换了一根短而粗的线问题全消。所以别忽视线材。3.2 外部 Flash 是否真的存在如果你板子上根本没有外部 Flash但 J-Flash 工程里配了外部 Flash 算法那报 CFI 错是必然的。确认方法看原理图有没有 SPI NOR Flash 芯片型号是什么。看 PCB芯片是否焊接引脚是否有虚焊。用万用表测 Flash 的 VCC 引脚是否有 3.3V 供电。如果 Flash 是 BGA 封装肉眼看不出来可以用热风枪补焊一下再试。有个客户案例板子设计时有外部 Flash但生产时为了省成本没焊固件却按有 Flash 的配置烧录。J-Flash 每次报 CFI 错工程师以为是软件问题折腾了两天。最后发现是硬件没焊补上芯片就好了。3.3 SPI 引脚映射与复用检查STM32F405OG 的 SPI 接口可以映射到多组引脚。比如 SPI1 默认是 PA5/PA6/PA7但可以重映射到 PB3/PB4/PB5。如果 J-Flash 的烧录算法里假设的是默认引脚而你的硬件用的是重映射引脚那算法发出的 SPI 命令就到不了 FlashCFI 探测自然失败。解决办法确认硬件原理图上外部 Flash 接的是哪组 SPI 引脚。如果用的是重映射引脚需要在烧录算法里对应修改或者改用支持引脚配置的烧录工具。有些 J-Flash 的 Flash 算法支持通过初始化脚本配置引脚可以在算法工程里改。这个点比较隐蔽因为 J-Flash 不会告诉你“引脚不对”它只会说“找不到 CFI 设备”。所以硬件排查时SPI 引脚是重点。3.4 供电与复位电路的影响外部 Flash 的供电不稳会导致 CFI 读取失败。用示波器看 Flash 的 VCC 引脚上电时是否有过冲或跌落。如果 J-Link 连接时板子电流突变Flash 可能瞬间掉电导致探测失败。复位电路也有关。STM32F405OG 的 NRST 引脚如果悬空或电容过大芯片复位不正常J-Link 连接后可能处于异常状态。建议 NRST 接 100nF 电容到地并接 10k 上拉到 VDD。另外如果板子上有看门狗烧录时可能被复位。J-Flash 连接时可以选择Connect under reset在复位状态下连接避免程序干扰。4. 方法三更新工具链与替换烧录算法4.1 J-Flash 版本与 J-Link 驱动匹配J-Flash 和 J-Link 驱动版本不匹配是常见坑。比如 J-Flash 是旧版J-Link 驱动是新版或者反过来可能导致 Flash 算法加载异常进而报 CFI 错。建议去 SEGGER 官网下载最新的 J-Link 驱动包里面自带 J-Flash。安装时选择完整安装确保 Flash 算法库是最新的。如果项目要求固定版本至少保证 J-Flash 和 J-Link 驱动来自同一个安装包。我遇到过 J-Flash V6.xx 配 J-Link 驱动 V7.xx连接 STM32F405OG 时频繁报 CFI 错。统一升级到 V7.xx 后问题消失。所以版本一致性很重要。4.2 手动指定 Flash 算法文件J-Flash 自带的 Flash 算法不一定覆盖你的外部 Flash 型号。这时候可以手动指定 .FLM 文件在 J-Flash 的Flash选项卡里点Add选择Flash Algorithm。浏览到你的 .FLM 文件。这个文件通常由 Flash 厂商提供或者用 Keil 的 Flash 算法生成工具制作。指定地址范围确保和硬件映射一致。保存工程重新连接。如果找不到现成的 .FLM可以用 Keil MDK 的Flash Algorithm功能基于你的 Flash 型号生成一个。具体做法是在 Keil 里新建一个 Flash 算法工程选择对应的器件编译生成 .FLM然后导入 J-Flash。4.3 改用 STM32CubeProgrammer 作为替代方案如果 J-Flash 死活搞不定外部 Flash可以换 STM32CubeProgrammer。ST 官方的工具对 STM32F405OG 支持更好尤其是内部 Flash 和选项字节操作。操作步骤下载安装 STM32CubeProgrammer。选择 SWD 接口连接 STM32F405OG。在Erasing Programming里选择 .hex 或 .bin 文件指定地址。点Start Programming。对于外部 FlashSTM32CubeProgrammer 支持通过外部加载器External Loader来烧录。你需要一个对应 Flash 型号的 .stldr 文件放到 STM32CubeProgrammer 的 ExternalLoader 目录下。ST 官网和社区有一些现成的加载器也可以自己用 STM32CubeIDE 生成。4.4 用 OpenOCD 或 pyOCD 绕过 J-Flash如果 J-Flash 的 CFI 探测机制本身和你的硬件不兼容可以考虑用 OpenOCD 或 pyOCD。这些开源工具不依赖 CFI 探测而是通过配置文件指定 Flash 算法。以 OpenOCD 为例配置文件里指定source [find interface/jlink.cfg] transport select swd source [find target/stm32f4x.cfg]然后通过flash write_image命令烧录。OpenOCD 对 STM32F405OG 的支持很成熟外部 Flash 可以通过自定义脚本处理。pyOCD 更简单Python 环境下pip install pyocd然后pyocd flash -t stm32f405og firmware.hex。它内部用的是 CMSIS-Pack 里的 Flash 算法不涉及 CFI 探测所以不会报这个错。4.5 烧录算法与芯片型号的对应关系不同 Flash 型号的烧录算法不能混用。比如 W25Q128 的算法不能用于 S25FL128因为扇区大小、命令集可能不同。J-Flash 报 CFI 错有时候就是因为算法选错了型号。对照表Flash 型号厂商常见算法文件备注W25Q128WinbondW25Q128.FLMSPI NOR扇区 4KBS25FL128CypressS25FL128.FLMSPI NOR扇区 64KBMT25QL128MicronMT25QL128.FLMSPI NOR支持 QSPISST25VF016BMicrochipSST25VF016B.FLMSPI NOR扇区 4KB选算法时型号要完全匹配或者至少同系列同容量。不确定的话查 Flash 的数据手册看厂商 ID 和设备 ID然后在 J-Flash 的算法库里搜索。5. 常见问题速查与避坑经验5.1 报错排查速查表现象可能原因排查动作解决方式报 CFI 错但只烧内部 Flash工程里误配了外部 Flash 区域检查 Flash 选项卡删除外部 Flash 行报 CFI 错外部 Flash 存在算法型号不匹配核对 Flash 型号换对应 .FLM报 CFI 错SWD 连接不稳线材差、引脚虚焊降速、换线、补焊修复硬件报 CFI 错SPI 引脚重映射算法引脚配置不对查原理图改算法或换工具报 CFI 错芯片读保护选项字节被锁用 CubeProgrammer 查看解除读保护报 CFI 错J-Flash 版本旧算法库不匹配升级 J-Link 驱动统一版本5.2 独家避坑技巧技巧一先用 J-Link Commander 确认连接。在命令行里跑JLink.exe输入connect选 STM32F405OG选 SWD。如果这里能连上说明硬件和驱动没问题问题在 J-Flash 工程配置。如果这里都连不上先修硬件。技巧二用 J-Flash 的Read Back功能验证。连接成功后点Target - Read Back选Entire Chip看能不能读出数据。如果能读出说明 Flash 访问正常CFI 报错可能是探测阶段的误报可以尝试手动指定算法绕过。技巧三外部 Flash 先单独测试。写一个简单的 SPI 读取程序烧进 STM32F405OG通过串口打印 Flash 的厂商 ID。如果能读到正确的 ID比如 Winbond 是 0xEF说明硬件没问题问题在 J-Flash 配置。如果读不到查 SPI 连线。技巧四备份 J-Flash 工程。每次改配置前先File - Save Project As备份一份。这样出问题了可以快速回滚不用从头配。技巧五注意 J-Flash 的Production Programming模式。这个模式下 J-Flash 会自动连接、擦除、烧录、校验、复位。如果中间任何一步失败都会报错。调试阶段建议用手动模式一步步来方便定位问题。5.3 关于 STM32F405OG 的特殊注意事项STM32F405OG 是 WLCSP90 封装引脚间距小焊接难度高。如果板子是手工焊接的虚焊概率不小。SWD 引脚和 SPI 引脚如果有虚焊就会导致连接不稳定或 CFI 探测失败。建议用 X-Ray 检查焊接质量或者用飞线直接引出关键引脚测试。另外STM32F405OG 的 BOOT0 引脚在 WLCSP 封装里可能和某个 GPIO 复用确认原理图上的 BOOT0 配置。如果 BOOT0 被拉高芯片进入系统存储器启动模式J-Flash 连接后可能识别不到用户 Flash。烧录时确保 BOOT0 为低电平。还有STM32F405OG 的 VDD 和 VDDA 要都供电VDDA 是模拟部分供电如果不接芯片可能部分功能异常影响 SWD 连接稳定性。用万用表确认每个电源引脚都有 3.3V。5.4 烧录文件格式的选择J-Flash 支持 .hex、.bin、.srec 等格式。.hex 自带地址信息推荐优先使用。.bin 需要手动指定地址容易出错。如果只有 .bin务必确认起始地址是 0x08000000内部 Flash或外部 Flash 的映射地址。烧录前可以用J-Flash的File - Merge功能把多个 .hex 合并成一个避免多次烧录。合并时注意地址不要重叠。校验环节不要跳过。J-Flash 的Verify功能会逐字节比对确保烧录成功。如果校验失败可能是 Flash 坏块或供电不稳换芯片或修电源。6. 实操复盘与个人体会这个报错我前前后后遇到过七八次每次原因都不一样。最离谱的一次是 J-Flash 工程里配了一个 0x00000000 起始地址的外部 Flash 区域而 STM32F405OG 的 0x00000000 是别名到 0x08000000 的内部 Flash。J-Flash 按外部 Flash 去探测自然找不到 CFI 设备。把那一行删掉就好了。还有一次是客户板子上的 SPI Flash 供电引脚虚焊时好时坏。J-Flash 偶尔能连上偶尔报 CFI 错。补焊后彻底解决。所以硬件问题永远优先排查别一上来就折腾软件。工具链方面我现在习惯用 STM32CubeProgrammer 烧内部 Flash用 OpenOCD 烧外部 Flash。J-Flash 只在客户要求时用。不是说 J-Flash 不好而是它的 CFI 探测机制在某些场景下太“固执”不如开源工具灵活。最后分享一个小技巧如果你不确定 J-Flash 工程里哪一行配置导致了 CFI 错可以先把所有 Flash 区域删掉只留内部 Flash 那一行然后逐步添加外部 Flash 区域每加一行就连接一次。哪一行加上去后报错问题就在那一行。这个方法虽然笨但定位问题非常准。外部 Flash 的烧录算法文件建议平时就收集好按型号分类存到一个文件夹里。用到的时候直接导入不用临时找。我自己的算法库里有几十个 .FLM 文件覆盖了 Winbond、Micron、Cypress、GigaDevice 等常见品牌省了很多时间。STM32F405OG 这颗芯片本身很稳只要硬件设计没问题烧录不应该出幺蛾子。遇到 CFI 报错按“先软后硬、先内后外、先简后繁”的顺序排查基本都能解决。
