1. 为什么“下载成功”不等于“固化完成”
很多刚接触 FPGA 的朋友第一次把比特流下载进板子,看到 LED 闪起来、串口有输出,就以为大功告成。结果一断电再上电,板子像什么都没发生过一样——程序没了。这不是板子坏了,也不是工程有问题,而是你只完成了下载到 FPGA 内部 SRAM这一步,没有做固化到外部 Flash。
FPGA 的主流架构是基于 SRAM 的查找表结构,SRAM 有个天然特性:掉电即失。配置数据存在 FPGA 内部的配置存储器里,断电就清空。所以每次上电,FPGA 都需要从外部非易失存储器(通常是 SPI Flash 或 BPI Flash)重新读取配置数据。固化这件事的本质,就是把 PC 上生成的比特流文件,转换成 Flash 能识别的格式,再写进板载 Flash 芯片里,让 FPGA 上电时能自己“读回来”。
这里要区分三个容易混淆的概念:
- 比特流文件(.bit):Vivado 综合实现后生成的原始配置文件,面向 FPGA 内部配置存储器,不能直接烧进 Flash。
- MCS 文件:把 .bit 按 Flash 的地址空间和位宽重新编排后的文件,是烧录器真正写进 Flash 的内容。
- 下载(Program):通过 JTAG 把 .bit 直接灌进 FPGA,掉电丢失,用于调试。
- 固化(Program Configuration Memory Device):通过 JTAG 把 .mcs 写进板载 Flash,掉电不丢,用于量产和交付。
新手最容易卡在“MCS 文件怎么生成”和“生成完怎么烧”这两步。下面我按实际操作的顺序,把整条链路拆开讲清楚,包括每一步背后的原因、参数怎么选、以及我踩过的那些坑。
提示:固化操作会覆盖 Flash 里原有的内容。如果板子上有出厂固件或别人的程序,先确认是否可以擦除,必要时先备份。
2. 固化前的硬件与工程确认清单
在动手生成 MCS 之前,有几件事必须先确认,否则后面大概率会报错或者烧进去不启动。这部分是很多教程跳过、但实际最耗时间的环节。
2.1 确认 Flash 型号与连接方式
打开原理图,找到 FPGA 配置相关的 Flash 芯片,记录以下信息:
| 需要确认的信息 | 为什么重要 | 常见取值 |
|---|---|---|
| Flash 型号 | 决定容量、扇区大小、烧录算法 | W25Q128、W25Q64、S25FL128 等 |
| 接口类型 | 决定 MCS 的位宽和数据排列 | SPI x1 / x2 / x4 |
| 容量 | 决定 MCS 文件大小是否放得下 | 16Mb、64Mb、128Mb |
| 数据位宽 | 影响 MCS 生成时的位宽设置 | 1、2、4 |
| 是否与 FPGA 配置专用引脚相连 | 决定上电能否自动加载 | 通常接在专用配置 Bank |
如果原理图不在手边,可以在 Vivado 硬件管理器里连上板子后,通过Open Hardware Manager → Add Configuration Memory Device搜索型号。但更稳妥的做法还是查原理图,因为自动识别有时会因为 JTAG 链路问题识别不到。
2.2 确认工程已经成功生成比特流
MCS 是从 .bit 转换来的,所以前提是工程已经完成综合、实现、生成比特流,且没有严重错误。如果你在Implementation阶段看到implement design变红,或者生成比特流时报 DRC 错误(比如DRC RTSTAT-2),那要先解决这些问题,固化的事往后放。
一个快速判断方法:在 Vivado 的Design Runs里看write_bitstream是否显示Complete,并且能在工程目录下找到.bit文件。路径通常在:
<工程目录>/<工程名>.runs/impl_1/<顶层模块名>.bit2.3 确认板子上电顺序和模式引脚
FPGA 上电后从哪种模式加载配置,由模式引脚(M[2:0])决定。常见的有:
- Master SPI 模式:FPGA 主动从 SPI Flash 读配置,这是最常见的固化场景。
- JTAG 模式:只用于调试下载,不用于固化启动。
- Slave 模式:由外部主控给 FPGA 送配置数据。
如果模式引脚设置不对,即使 Flash 里烧了正确的 MCS,上电也不会自动加载。所以固化前务必确认模式引脚跳线或电阻配置符合 Master SPI 的要求。具体电平组合查对应 FPGA 型号的配置手册,不同系列不一样。
注意:有些开发板用拨码开关切换模式,烧录时可能需要在 JTAG 模式和 Master SPI 模式之间切换。烧完记得拨回启动模式再重新上电验证。
3. 用 Vivado 生成 MCS 文件的完整流程
这一步是整篇的核心。Vivado 生成 MCS 有两条路:图形界面操作和 Tcl 命令。图形界面适合新手,Tcl 适合批处理和复现。我把两种都讲一遍,并解释每个参数的含义。
3.1 图形界面操作:从 Add Configuration Memory Device 开始
打开 Vivado,确保硬件连接正常(JTAG 下载器插好,板子上电)。然后按以下步骤走:
- 在左侧 Flow Navigator 底部找到Open Hardware Manager,点击Open Target → Auto Connect。如果连不上,检查下载器驱动和 JTAG 链路。
- 连接成功后,在 Hardware 窗口里右键 FPGA 器件,选择Add Configuration Memory Device。
- 在弹出的搜索框里输入 Flash 型号(比如
w25q128),选中匹配的器件,点击 OK。 - Vivado 会弹出对话框,询问是否现在就要烧录配置存储器。这里先选Cancel,因为我们还没生成 MCS 文件。
- 此时 Hardware 窗口里会多出一个 Flash 器件节点。右键它,选择Program Configuration Memory Device。
- 在配置对话框里,
Configuration file一栏点击浏览,选择你的.bit文件。Vivado 会自动提示是否要生成 MCS,或者你也可以在Configuration file旁边勾选生成 MCS 的选项。
但更规范的做法是先生成 MCS,再单独烧录。生成 MCS 的入口在:
Tools → Generate Memory Configuration File
这个对话框里的参数是重点,逐个说:
- Format:选
MCS。也有BIN格式,但 MCS 是带地址信息的 ASCII 格式,通用性更好。 - Memory Part:选你的 Flash 型号。这个必须和实际芯片一致,否则地址映射会错。
- Interface:根据 Flash 接口选
SPIx1、SPIx2、SPIx4。大多数小容量 Flash 用 SPIx1,大容量高速加载用 SPIx4。 - Data Width:和 Interface 对应,SPIx1 就是 1,SPIx4 就是 4。
- Start Address:一般填
0x00000000,除非你有特殊的分区需求。 - Load Bitstream files:勾选后添加你的
.bit文件。 - File name:指定输出的
.mcs路径。
填完之后点 OK,Vivado 会在后台调用write_cfgmem命令生成 MCS。生成成功后在指定目录能看到.mcs和.prm两个文件,.prm是烧录时用的参数文件,别删。
3.2 Tcl 命令方式:可复现的批处理写法
如果你要反复生成,或者想把流程写进脚本,用 Tcl 更省事。在 Vivado 的 Tcl Console 里执行:
write_cfgmem -format MCS \ -interface SPIx1 \ -size 16 \ -loadbit "up 0x00000000 ./top.bit" \ -file ./output/top.mcs参数解释:
-format MCS:输出 MCS 格式。-interface SPIx1:SPI 单线模式,对应 Data Width 1。-size 16:Flash 容量,单位是 Mb。这里 16 表示 16Mb,即 2MB。这个值必须大于等于比特流实际大小,否则会报空间不足。-loadbit "up 0x00000000 ./top.bit":up表示从起始地址向上加载,0x00000000是起始地址,后面是比特流路径。-file:输出文件路径。
执行后如果看到类似Writing MCS file...的日志,说明生成成功。可以用文本编辑器打开.mcs看一眼,开头是:020000040000FA这样的 Intel HEX 格式记录,说明格式正确。
3.3 MCS 文件大小与 Flash 容量的匹配计算
很多人烧录时报not enough space或者烧完不启动,根源是 MCS 大小和 Flash 容量没对上。这里给一个简单的估算方法:
比特流文件大小 ≈ 配置比特数 / 8。比如一个中等规模的 FPGA 工程,比特流可能是 3MB 到 8MB 不等。MCS 因为是 ASCII 编码,体积会比原始二进制大约 2 倍多。所以:
- 16Mb Flash(2MB)通常只够放很小的工程。
- 64Mb Flash(8MB)能放大多数中小规模工程。
- 128Mb Flash(16MB)适合大工程或多镜像。
在 Vivado 里可以直接看.bit文件大小,然后乘以 2.2 左右估算 MCS 大小,再和 Flash 容量对比。如果不够,要么换更大 Flash,要么压缩设计(比如开启比特流压缩)。
提示:Vivado 生成比特流时可以勾选
Enable bitstream compression,能显著减小比特流体积,对容量紧张的板子很有用。但压缩后的比特流加载时会稍慢一点,属于用时间换空间。
4. 把 MCS 烧进 Flash 的实操与验证
MCS 生成好之后,下一步是烧录。这一步的坑主要集中在“烧录器识别不到 Flash”和“烧完不启动”两类。
4.1 在 Hardware Manager 里烧录 MCS
操作路径:
- 打开 Hardware Manager,连接目标板。
- 右键 FPGA 器件,Add Configuration Memory Device,选好 Flash 型号。
- 右键新增的 Flash 节点,选择Program Configuration Memory Device。
- 在对话框里:
Configuration file选择刚才生成的.mcs。PRM file会自动关联,如果没有就手动选.prm。- 勾选
Verify可以在烧录后校验。 - 勾选
Erase会先擦除再烧,首次烧录建议勾上。
- 点击 OK,等待进度条走完。烧录时间取决于 Flash 容量和 JTAG 速度,128Mb 的 Flash 可能要几分钟。
烧录过程中如果报error: flash download failed - target dll has been cancelled,通常是 JTAG 连接不稳定或者 Flash 型号选错。先检查下载器接触、板子供电,再确认型号。
4.2 烧完之后的验证步骤
烧录完成不代表成功,必须验证。验证分两步:
第一步:不断电,用 JTAG 重新加载一次比特流,确认 FPGA 本身工作正常。这一步排除工程问题。
第二步:断电,等几秒,重新上电。观察板子是否自动启动。如果启动了,说明固化成功。如果没启动,按下面的顺序排查:
- 模式引脚是否在 Master SPI 位置。
- Flash 型号是否选对,特别是容量和扇区结构。
- MCS 起始地址是否和 FPGA 配置加载地址一致(通常都是 0)。
- 比特流是否真的对应这个板子的 FPGA 型号和封装。
- Flash 的写保护引脚是否被拉低导致写入失败。
我遇到过一种情况:烧录显示成功,但上电不启动,最后发现是 Flash 的HOLD或WP引脚在板子上被错误拉低,导致 FPGA 读取时数据被保持。这种硬件层面的问题,软件层面怎么查都查不出来,只能对着原理图量引脚电平。
4.3 常见报错与对应处理
| 报错信息 | 可能原因 | 处理方式 |
|---|---|---|
cannot load flash device description | Flash 型号不在 Vivado 数据库 | 手动添加或换用兼容型号 |
warning: failed to communicate with the flash chip | JTAG 链路或 Flash 供电异常 | 检查连接、供电、复位 |
not enough space | MCS 大于 Flash 容量 | 换大容量 Flash 或压缩比特流 |
| 烧录成功但上电不启动 | 模式引脚、地址、引脚电平 | 逐项排查硬件配置 |
implement design变红 | 工程本身未通过实现 | 先解决时序和 DRC 问题 |
5. 几个让固化更省心的经验技巧
做了很多次固化之后,我总结了几条能明显减少返工的习惯。
第一,把 MCS 生成和烧录分开做。不要图省事在烧录对话框里临时生成,因为那样参数不好复用。先生成好.mcs和.prm,归档到工程目录,烧录时直接选文件,出问题也容易定位。
第二,给 Flash 留一份“救砖”镜像。如果板子支持,可以在 Flash 里烧两个镜像,一个主用一个备份,通过地址偏移区分。主镜像损坏时还能切到备份启动。这对量产和现场升级很有价值。
第三,记录每次固化的参数。Flash 型号、接口模式、起始地址、比特流版本,这些信息写在一个flash_config.txt里放在工程根目录。过几个月再回来烧,不用重新翻原理图。
第四,注意 Vivado 版本和 Flash 数据库的匹配。有些新 Flash 型号在老版本 Vivado 里没有,需要手动添加或升级软件。如果公司环境不能随便升级,就选数据库里已有的兼容型号。
第五,固化后做一次完整的上电循环测试。至少断电三次、上电三次,确认每次都能正常启动。有些偶发问题只在特定上电时序下出现,单次测试发现不了。
最后说一个我自己的习惯:每次固化成功后,把当次的.bit、.mcs、.prm和参数记录打包存一份,命名带上日期和版本号。FPGA 项目迭代快,过一阵子回头看,没有这些归档,根本记不清哪版烧的是哪个文件。这个习惯帮我省过好几次重新生成和重新验证的时间。