ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

FPGA固化从Bit到MCS:文件转换、烧录流程与避坑指南

FPGA固化从Bit到MCS:文件转换、烧录流程与避坑指南 做FPGA开发这几年我见过太多人在程序固化这个环节栽跟头。最常见的场景是刚学Vivado的新人把.bit文件用JTAG下载进去看到板子跑起来了就以为完事了结果一断电程序消失得干干净净仿佛什么都没发生过。还有人拿着一个MCS文件却不知道它跟Bit文件到底什么关系烧进去之后设备不启动也不知道从哪排查。这次我把Xilinx FPGA从Bit到MCS的固化流程、文件格式差异、选型逻辑和踩坑经验一次性梳理清楚可以直接照着操作。适合刚接触FPGA开发的学生、转岗工程师以及那些“固化过几次但没系统搞明白原理”的人。1. 为什么固化不能只靠Bit文件——先搞懂FPGA的“失忆”体质1.1 SRAM工艺决定了FPGA断电即失忆理解固化之前必须回到FPGA的硬件本质。绝大多数Xilinx FPGA7系列、UltraScale系列的配置存储单元是SRAM结构这意味着查找表LUT、触发器、BRAM初始化内容、布线开关这些关键配置数据全部依赖SRAM保存。SRAM的特点是速度快、可无限次重写但它是易失性存储一断电数据就全部清零。这个特性带来一个直接结果FPGA芯片本身没有“记住程序”的能力。你把Bit文件烧进去只是把配置数据暂时写进了SRAM属于“临时配置”。这就像一台不带硬盘的电脑每次开机都需要从U盘引导系统U盘里的系统镜像才是真正“固化”下来的东西。在FPGA的世界里这个“U盘”通常就是板上的SPI NOR Flash而“系统镜像”就是MCS文件。所以固化这个动作的本质是把原本只存在于电脑上的Bit文件转换成带地址信息的MCS文件写入外部Flash芯片让FPGA上电后能够自己从Flash里把配置数据读回来并装进内部的SRAM配置单元。1.2 Bit文件和MCS文件的本质差异很多资料把这两个文件说得云里雾里其实站在用途角度一眼就能分清Bit文件是给FPGA的JTAG配置逻辑用的。它是一段连续的比特流开头有同步头、器件ID、配置指令、配置数据、CRC校验等下载器通过JTAG口把这段比特流直接灌进FPGA的配置寄存器让SRAM细胞建立对应连接。MCS文件是给Flash编程器用的。它采用Intel HEX格式每一行都包含地址、数据长度、记录类型和校验和。下载器或编程器根据文件里的地址信息把数据写入Flash对应的存储单元。MCS文件关心的是“哪一段数据写到哪个地址”而Bit文件根本不在乎地址它在意的只是数据流本身。一句话总结Bit是FPGA的“临时配置”MCS是Flash的“永久镜像”。这里要特别纠正一个流传很广的误解有人以为MCS文件就是Bit文件换个后缀名其实完全不是。MCS文件是文本格式可以用文本编辑器打开里面是ASCII字符组成的十六进制记录而Bit文件是二进制格式直接用文本工具打开全是乱码。两者面向的硬件目标完全不同不能混用。1.3 固化链路的完整数据流把整个过程串起来看一条完整的固化链路是这样的Vivado/ISE综合、布局布线生成.bit文件通过Write Configuration Memory Image或iMPACT工具把.bit转换成.mcs文件下载器Platform Cable USB、Digilent JTAG-HS3等把MCS文件通过JTAG口写入板上的SPI Flash断电重上电后FPGA根据配置模式引脚M[2:0]的电平自动进入Master SPI模式主动从Flash读取配置数据配置数据经Flash读出后写入FPGA内部SRAMDONE引脚拉高FPGA开始运行用户逻辑链路里任何一步出了问题最终表现都是“板上没反应”或者“下载失败”。而这其中从步骤2到步骤3之间的文件选型和格式转换是新手最容易糊涂的地方值得单独展开。2. 从Bit到MCS的转换逻辑与地址位宽陷阱2.1 Vivado与ISE的转换入口差别很大不同时代的Xilinx开发环境做文件转换的入口完全不同。在Vivado里流程是工程综合布线完成后先Generate Bitstream生成.bit然后在Tools菜单下选择Configuration Memory Device或者直接在Flow Navigator里选Write Configuration Memory Image。图形界面里需要选格式MCS/BIN/HEX、Flash大小、接口位宽然后加载已经生成的.bit文件执行转换。在ISE 14.7里用的是iMPACT工具。流程是双击Generate Programming File生成.bit然后打开iMPACT选择Create PROM File按向导选SPI Flash、填Flash容量、加载Bit文件最终生成MCS文件。如果习惯用Vivado的Tcl命令也可以直接用一句命令完成转换这是我最常用的方式write_cfgmem -format mcs -interface spi -size 16 -loadbit {up 0x0 E:/project/led/led.bit} -file E:/project/led/led.mcs这条命令的参数含义是生成MCS格式、SPI接口、按16MB Flash地址规划、从0x0地址开始载入led.bit文件输出到指定路径。实际使用时把路径改成自己的工程路径即可。注意最后会生成几个文件包括.mcs和.prm文件.prm是配置过程的记录文件烧录时有时候需要用到。2.2 Flash容量与地址位宽必须对齐MCS文件里记录的地址是真实的Flash存储地址而这个地址的位宽由Flash容量决定这是转换时最容易踩的坑。8MB Flash如W25Q64地址需要23根线对应地址范围0x0 ~ 0x7FFFFF16MB Flash如W25Q128、N25Q128地址需要24根线对应0x0 ~ 0xFFFFFF32MB Flash地址需要25根线对应0x0 ~ 0x1FFFFFF在Vivado转换设置里选错Flash容量导致的后果很隐蔽如果选了比实际Flash小的容量生成的MCS文件地址只覆盖低地址部分超出部分的数据被丢弃高地址的内容自然丢失如果选了更大的容量文件里会出现很多空地址段烧录时间变长不说有些严格的下载器还会提示数据与设备不匹配。所以选Flash容量时务必以板上实际焊接的Flash型号为准别凭感觉。2.3 Intel HEX格式到底长什么样MCS文件用的是Intel HEX格式这个格式本身非常简单但理解了它对你排查问题有奇效。每一行记录的结构是: LL AAAA TT DD...DD CC其中冒号是行起始标记LL是数据长度十六进制占用1字节AAAA是十六进制地址TT是记录类型00表示数据记录01表示文件结束DD是实际数据CC是校验和。校验和的计算方式是把长度、地址、类型、数据所有字节累加取低8位再按位取反加1。换句话说这一行所有十六进制字节不包括冒号加起来应该等于0。举个例子下面这行MCS数据:10000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00长度是0x10地址是0x0000类型是00后面16个字节全是0xFF最后的0x00是校验和。你可以自己验算0x10 0x00 0x00 0x00 0x10*0xFF 后取低字节……算出来确实是0校验通过。知道这个格式对你有什么实际帮助当你在硬件管理器里烧录MCS时如果下载器提示CRC校验失败你可以直接打开MCS文件用UltraEdit或VS Code看它的最后一行是不是以:00000001FF结尾。如果不是说明这个MCS文件在拷贝或者转换过程中损坏了重新生成一份即可省去怀疑硬件的时间。3. 固化前的板级准备模式引脚、Flash接线和下载器驱动3.1 配置模式选择引脚M[2:0]不能设错FPGA上电后的第一个动作是采样配置模式引脚的电平这个引脚组叫M[2:0]有的芯片也叫MODE引脚。它决定FPGA用哪种方式获取配置数据是从SPI Flash主动读还是从BPI并行接口读或者等待JTAG被动灌入。以7系列FPGA为例常见的模式编码是M[2:0]配置模式适用场景001Master SPI从SPI Flash主动加载最常用的固化模式000Master BPI从并行NOR Flash加载少数高速配置场景100JTAG仅通过JTAG下载不主动加载外部存储111Slave Serial由外部主机如ARM、CPLD推送配置数据很多人固化完成后上电不启动第一反应是怀疑Flash没焊好实际上十有八九是M[2:0]的电平组合不对。比如板子上M[2:0]默认是100JTAG模式你把MCS烧进Flash之后重新上电FPGA还是等着JTAG下发数据根本不会理睬Flash里的内容。所以固化之前先确认原理图上M[2:0]的上下拉电阻确保守值对应的是你需要的Master SPI模式。通常设计中这组引脚会通过拨码开关或0欧电阻实现可选拨到正确档位再上电。3.2 SPI Flash的接线与特殊引脚处理SPI Flash与FPGA之间的标准接法是四根信号线加片选CS_n片选低有效CIPO以前叫DO或MISO数据输出FPGA从Flash读数据走这根线COPI以前叫DI或MOSI数据输入FPGA往Flash写数据走这根线CLK时钟由FPGA主控输出但有两个引脚经常被忽视WP_n写保护和HOLD_n暂停输入。这两个引脚在Flash内部有上拉但如果板上处理不当比如直接接地可能导致两个诡异现象WP接地会导致往Flash写数据时直接报写保护错误HOLD接地会导致通信被随机暂停数据在烧录到一半时卡死。正确做法是如果设计上没有特殊需求WP_n和HOLD_n都应通过10k电阻上拉到电源或者直接让FPGA的IO在空闲时输出高电平。我自己就遇到过一块板子把HOLD_n悬空结果烧录成功率不到一半最后查了半天发现是Flash的HOLD引脚受到了旁边数字信号耦合干扰。3.3 下载器的固有坑Vivado识别不到目标板这块内容在热搜词里出现频率极高尤其是“xilinx platform cable USB firmware loader windows无法加载这个硬件的设备驱动”。这个问题的重灾区是Windows 10/11 64位系统配合ISE 14.7自带的Platform Cable USB驱动微软的新签名策略会拒绝加载未签名驱动。我试过两种解法比较有效第一种关闭驱动强制签名后手动安装。系统重启时按F8进入高级启动选项选择“禁用驱动程序强制签名”然后打开设备管理器给识别为未知设备的Platform Cable USB手动指定驱动路径指向ISE安装目录下的驱动文件夹C:\Xilinx\14.7\ISE_DS\common\bin\nt64第二种使用Vivado自带的驱动目录。如果你机器上装了Vivado它的驱动路径通常比ISE的驱动版本新可以尝试在设备管理器里把驱动指向C:\Xilinx\Vivado\2023.1\data\xicom\cable_drivers\nt64\dlc10另外提一句现在很多人直接用Digilent的JTAG-HS3兼容下载器它的驱动是WinUSB在Windows下免驱或只需要Zadig装一次驱动比老款Platform Cable USB省心得多。如果只是为了调试个人板卡更建议用这类下载器。3.4 JTAG链路检查烧录前还要确认JTAG链是否完整。用Vivado打开Hardware Manager如果能看到目标FPGA的型号IDCODE说明JTAG链路正常。这里有个冷知识很多板子在JTAG链上同时挂了CPLD、多个FPGA或者Zynq每个器件的IDCODE都能扫出来但你烧MCS时选择目标还是得手动指定好烧到哪个Flash。有些人的板子JTAG链上既有FPGA又有Flash下载器是通过FPGA的BSCAN间接访问SPI Flash的这种情况下FPGA本身的JTAG链路如果断开Flash烧录也无从谈起。4. 完整固化流程实录从生成到烧录到上电验证4.1 Vivado生成MCS的操作细节下面是基于Vivado 2023.1的完整流程其他版本略有差异但逻辑一致。第一步工程里完成综合和实现后点击Generate Bitstream生成.bit文件。这一步没做完后面的转换无从谈起。第二步在Flow Navigator左侧找到Program and Debug展开后点击Configuration Memory Device。如果是老版本Vivado路径是Tools - Configuration Memory Device。弹窗里需要填这几个关键参数Format选MCS如果后续要用软件端做远程升级建议同时生成BINInterfaceSPIx1或SPIx4。这里要说明SPIx4表示FPGA配置时用Flash的Quad SPI模式一次读4bit速度更快。但前提是Flash芯片支持Quad模式而且你在生成Bitstream前需要把SPI_BUS_WIDTH属性设为4并重新生成Bit文件。Size选择Flash芯片对应的容量比如16MB选16。然后点击OK在配置界面里点击右键或点Add选择要加载的Bit文件起始地址填0x0。最后点击Generate输出MCS文件。整个过程中最容易忽略的细节是SPI_BUS_WIDTH属性。如果你在Vivado里只改了配置生成的Interface为SPIx4但Bit文件本身还是按x1生成的烧录后FPGA按x4模式读取Flash时读到的数据可能是错的表现为上电后DONE引脚死活拉不高。所以要么全程用SPIx1要么从Bitstream属性到MCS生成全部统一到SPIx4不要混搭。4.2 烧录Flash的两种方式对比MCS文件生成后烧录到Flash有两条路方式一通过Add Configuration Memory Device烧录。在Hardware Manager里右键点击FPGA器件选择Add Configuration Memory Device弹出窗口让你选Flash型号。如果你的Flash型号不在列表里有两种处理办法选一个相同容量和指令集兼容的替代型号比如W25Q128替代N25Q128或者手动编辑配置。选定后器件树里会出现Flash节点右键选择Program Configuration Memory Device加载MCS文件烧录。这种方式走的是FPGA内部的边界扫描链下载器通过JTAG口控制FPGA再通过FPGA的SelectMAP/SPI接口间接把数据写进Flash。方式二通过Direct SPI烧录。某些下载器如Platform Cable USB支持直接与SPI Flash通信不经过FPGA。在Hardware Manager的Hardware窗口里右键选择Add Configuration Memory Device选好Flash型号后选择Direct SPI Programming模式。这种方式的好处是FPGA本身没配好也能烧Flash坏处是只能一对一连接不能跨FPGA借道。我实际的建议是新板子首次固化用方式一因为可以通过JTAG先确认FPGA链路良好产线批量烧录用方式二或者专门烧录器不依赖FPGA工作状态效率更高。4.3 上电验证的正确姿势烧录完成后出现Program/Verify操作成功的提示并不代表大功告成。我见过太多人烧录成功后就拔电结果板子不启动。正确的验证姿势是这样第一步断电等待3秒以上让板上电容放完电。不要只按复位键因为配置逻辑看了复位会重新加载但SRAM和电源状态可能残留。第二步重新上电用示波器或万用表观察DONE引脚正常应该在几十毫秒内从低电平变成高电平。可以抓一下启动波形看是否有INIT_B拉低过。如果INIT_B曾经拉低又拉高说明配置过程有过错误出现但可能自恢复如果INIT_B在配置完成后仍为低说明配置失败需要进入后面的排查流程。第三步观察用户逻辑的现象比如LED闪烁、串口打印。这一步看似废话但它其实是“配置成功”和“逻辑正确”两个层面的验证缺一不可。有时候配置确实成功了但你自己写的逻辑有问题现象不对也不能赖固化流程。另外16MB Flash全片擦除加写入MCS实测用Platform Cable USB大概需要3到5分钟用JTAG-HS3会快一些。如果烧录时间明显小于这个量级比如几秒钟就完成基本可以断定数据根本没写进去——要么校验和没开要么Flash选错了型号。5. 固化失败排查链路从驱动报错到启动失败5.1 烧录阶段就失败驱动和链路问题固化失败的第一道坎在烧录阶段。最典型的报错是Vivado提示Cannot find device或No devices detected这类问题优先检查三个点JTAG连接方向是否接反。TCK、TMS、TDI、TDO四根线错一根就会扫描失败。板子上的JTAG座通常都有引脚定义丝印拿万用表确认每根线对应到下载器哪个引脚。板子是否供电。FPGA的JTAG TAP控制器也需要供电如果板子没上电或者供电电流不够扫描不到器件很正常。驱动是否装好。在Windows设备管理器里看确认连接下载器后有没有生成对应设备设备图标带黄色感叹号的话参照3.3节处理驱动。还有一种比较隐蔽的情况JTAG链上有多个器件其中一个器件因为BSCAN被配置做了别的功能或者FPGA内部已经跑起了用户逻辑占用了部分JTAG导致扫描链变得不稳定。此时可以在Vivado里给FPGA强制配置一个空的比特流文件释放JTAG再重新尝试扫描。5.2 烧录成功但上电不启动M[2:0]和Flash焊接问题这是一个非常高频的问题。烧录时一切正常Verify也通过可一断电重上电板子就是没反应。我的排查顺序固定如下第一步量M[2:0]电平。用万用表分别量三个引脚的电平是否与期望模式一致。注意如果M[2:0]通过拨码开关控制有时拨码开关接触不良会导致引脚悬空悬空状态下FPGA内部的上拉/下拉会给出一个不确定的值。第二步量Flash的CS_n引脚在启动过程中是否产生了一段低电平脉冲。如果CS_n一直是高说明FPGA根本没发起Flash读取操作。这时候基本锁定模式引脚或配置时钟问题。第三步如果CS_n确实拉低了用示波器观察CLK信号和CIPO数据。只有CLK翻转而没有CIPO数据多半是Flash的数据输出引脚虚焊或者Flash本身坏了如果连CLK都没有问题在FPGA的配置时钟引脚。第四步实在不行就检查Flash型号与MCS的地址规划是否匹配。比如你用的是8MB Flash但生成MCS时选了16MB虽然烧录不会报错但启动时FPGA按从Flash顶部读取配置头的方式去取数据可能取到的是空区域导致配置失败。这里补充一个细节7系列FPGA从Flash加载时会先读Flash起始地址的数据检查同步头0xAA995566是否匹配。如果数据不对INIT_B拉低并行进入错误状态。所以用示波器能观察到Flash的CIPO线上是否有0xAA 0x99等数据这一招定位问题最快。5.3 回读验证失败多半是Flash型号选错了回读Verify失败的问题通常不在FPGA而在Flash型号指令集不匹配。不同品牌的SPI Flash虽然都遵循JEDEC标准但具体到读ID、读状态寄存器等指令上存在细微差异。最常见的情况是用W25Q128Winbond替代N25Q128Micron时在Vivado的Configuration Memory Device列表中选错了型号。两者容量一样、封装兼容但某些指令的时序参数不同。如果选错最典型的现象是烧录可以成功但Verify总是报Mismatch或者在回读时读到全FF。解决方法是尽量选与板上型号严格一致的Flash型号。如果列表里确实没有就选同一厂商同一容量系列的兼容型号并且在烧录前确认“Erase”选项选了Full Chip Erase而不是Sector Erase避免新旧数据残留导致校验失败。5.4 配置过程中CRC错误时序与环境问题还有一个错误是配置过程中FPGA报CRC错误DONE拉不起来。这类问题排查链路比较长但几个原因最常遇到配置时钟频率太高。FPGA从Flash读配置时SPI时钟默认最高是几十MHz但如果板上走线较长、Flash速度等级较低高频时钟会导致数据采样错误。可以在Vivado里把配置时钟降低比如设成10MHz或更低再重新生成带配置时钟参数的Bit文件和MCS。Flash内容被静默修改。如果板上有其他器件共享SPI总线并且没有做隔离别的器件偶尔会往Flash里写入无效数据造成配置CRC错误。排查方法是重新烧录并断开其他SPI器件。电源噪声干扰。FPGA上电瞬间电流很大如果电源纹波超标配置过程中SRAM写入容易出现位翻转。这种问题最容易间歇性发生让人抓狂。建议示波器看FPGA供电引脚上电瞬间的压降。如果这四类问题都排查完之后仍然不稳定还有一个比较容易忽略的地方Flash的HOLD引脚。因为HOLD引脚在SPI通信中可以被外部的毛刺信号误触发导致数据流暂停FPGA接收到的数据不完整最终CRC错误。把HOLD引脚通过电阻上拉问题通常就能解决。6. 文件选型的实际经验什么时候用Bit、MCS还是BIN6.1 调试用Bit量产用MCS调试阶段用Bit文件下到FPGA里直接跑优点是下载速度快、不需要擦写Flash上电后改代码再下载也很方便。缺点是断电丢配置所以要固化时就必须换成MCS。量产阶段产线人员拿到的是MCS文件甚至不需要打开Vivado直接用对应下载器的命令行工具就能完成烧录。我在实际项目里的习惯是把MCS文件放在和硬件BOM表相同的版本目录下文件命名统一为“项目名_版本号_日期.mcs”同时生成一个MD5校验文件。产线烧录完成后做一次回读校验再核对MD5双保险。6.2 BIN文件在远程升级场景中的特殊地位BIN文件就是去掉地址信息的裸二进制数据硬件角度来说它和MCS内容一致只是格式不同。它在嵌入式场景尤其是Zynq里非常有用如果你要在Linux或裸机环境下通过网口、串口或者PCIe直接往Flash里写镜像MCS带地址的格式反而碍事BIN文件更合适。最简单的方式是在Vivado里配置Configuration Memory Image时同时生成MCS和BIN给产线发MCS给软件同事发BIN各取所需。软件端拿到BIN后可以直接分区写入配合BootROM的MultiBoot功能从Flash指定地址加载。6.3 HEX、SVF、RBT这些冷门格式的适用场景除了Bit、MCS和BIN做FPGA还会偶尔碰到另外几种格式简单说下它们的定位HEX文件和MCS基本同源都是Intel HEX格式只是后缀不同。部分第三方Flash编程器只认.hex后缀可直接改名使用。SVF文件这是JTAG边界扫描的矢量文件用于通过其他工具链给FPGA烧录配置或者做测试功耗和时间开销都比正常烧录大工程上用得少。RBT文件Bit文件的ASCII版本每行代表一帧配置数据主要用于Xilinx官方Tools调试或者FPGA安全启动相关开发普通项目一般用不上。6.4 多镜像和回滚设计中的文件选型最后聊一个进阶话题如果你的产品有在线升级需求需要做Golden镜像和Update镜像双区切换文件选型和地址规划要提前想好。典型方案是把Flash分为两个区0x0地址放Golden镜像0x100000地址放Update镜像。FPGA上电先尝试从Update区加载如果加载失败CRC错误会自动回退到Golden区启动。这时候你生成的MCS文件就不是单一Bit文件拉一条直线了而是需要往不同地址写入不同的Bit文件。在Vivado里Write Configuration Memory Image界面可以同时加载多个Bit文件并给每个文件指定不同的起始地址生成一个包含多镜像的MCS。我用过的最简单的Tcl命令是write_cfgmem -format mcs -interface spi -size 32 \ -loadbit {up 0x000000 good.bit; up 0x100000 update.bit} \ -file multi.mcs这样产线烧录一次就把Golden和Update都写进去了。后续远程升级只需要通过应用层把新的Update镜像写入0x100000之后的区域即可不需要重新烧录整片Flash。多说一句多镜像方案里要注意Flash的扇区擦除边界比如W25Q128的扇区是4KBBlock是64KB你划分分区地址时最好对齐到Block边界否则某个分区的擦除操作可能会越界影响相邻分区造成Golden镜像被意外破坏。这个坑我在量产阶段踩过一次整个批次返工才解决。我自己做固化相关项目时还有一个非常土但很好用的习惯每次烧录完MCS不管Verify是否通过都手动断电再上电一次并在日志里记录DONE引脚的电平变化。别小看这个动作它能帮你快速鉴别“烧录成功”和“配置成功”这两个概念。这种离线验证的习惯比任何调试工具都可靠。以后在新项目里遇到固化问题建议你也从这两个文件、两条链路、三次验证烧录确认、回读校验、上电DONE的角度去排查思路会清晰很多。
返回列表