
搞FPGA固化时SPI Flash选型经常会碰到华邦的W25Q128JVEIQ。这颗128Mbit的片子容量够用、速度也不错在很多开发板和工控板上都能看到但Vivado 2020.2的默认Flash列表里就是没有它。搞FPGA的人应该都懂这个尴尬板子焊好了工程编译通过了最后却卡在“怎么把固件固化进去”这一步。这篇文章就完整讲一遍在Vivado 2020.2里手动添加W25Q128JVEIQ的流程把每一步操作和SPI Flash参数细节都摊开讲适合手里正好有这颗Flash、或者想在Vivado里添加任意非默认Flash的工程师参考。1. 为什么非要手动添加这颗Flash1.1 Vivado默认列表里到底缺了什么Vivado的硬件管理器自带一份“配置存储器数据库”里面收录了Winbond、Spansion、Micron、ISSI等厂商的几十款常见SPI NOR Flash。这个数据库覆盖范围其实不窄但它更多是围绕Xilinx原厂开发板和主流工业级型号来整理的。实际项目里板级工程师选Flash时考虑的是供货稳定性和成本很容易选到一颗列表里没有的型号。W25Q128JVEIQ就是典型例子它在华邦的产品线里属于非常基础的128Mbit SPI NOR Flash性价比高、货源充足偏偏Vivado 2020.2安装完成后搜不到这个名字。手动添加听起来是个挺麻烦的操作其实本质就是向Vivado补一份“这颗Flash怎么用”的说明书。Vivado并不认识具体芯片型号它只知道怎么通过SPI接口发送读、写、擦除指令。只要把容量、页大小、扇区大小、JEDEC ID、指令集这些参数填对Vivado就能正常生成固化文件并通过JTAG把数据写进去、再做校验。换句话说手动添加不是绕过Vivado的偏门操作而是官方流程本来就支持的扩展方式只是用的人少、文档里写得比较简略。1.2 添加Flash前必须搞清的几个概念在动手填参数之前强烈建议先理解三个概念后面能少走很多弯路容量单位、Page/Sector/Block的关系、状态寄存器的角色。容量单位是最容易踩的坑。W25Q128JVEIQ标称128Mbit注意单位是bit不是Byte。128Mbit除以8得到16MB也就是16777216字节。Vivado里配置存储器的容量参数、write_cfgmem命令的-size参数单位都是Mb。所以这颗Flash对应的是128而不是16。很多人把128Mbit记成16MB填参数时写16结果生成的镜像只有目标容量的八分之一编程时报错或者启动失败。Page、Sector、Block是SPI NOR Flash的三个基本操作粒度。W25Q128JVEIQ的Page是256字节编程按页进行一次最多写256字节Sector是4KB擦除的最小单位是SectorBlock是64KB也支持32KB半块擦除。Vivado生成擦除和编程命令时会按照这些粒度计算地址。如果填错比如把Sector大小填成8KB擦除命令和地址就会错位轻则擦不干净重则把不该擦的数据擦掉。状态寄存器是很多人忽略的一块。SPI NOR Flash的写保护、忙碌标志、Quad模式使能位都放在状态寄存器里。W25Q128JVEIQ最常用的是Status Register-1的bit0BUSY和Status Register-2的bit1QE。BUSY位表示Flash是否在忙擦除和编程前必须确认它为0。QE位决定Quad模式是否开启如果要用SPI x4方式固化或者启动这个位必须正确置1否则FPGA上电后无法通过四线模式读取配置数据。手动添加Flash时Vivado会要求把这些参数定义清楚所以先搞清楚状态寄存器结构后面操作才不会束手无策。2. W25Q128JVEIQ核心参数与指令集速查2.1 一颗16MB SPI NOR Flash的关键规格手动添加Flash时用到的参数本质上就是W25Q128JVEIQ数据手册前几页的内容。这里整理成一张速查表后面的GUI操作和Tcl命令都会用到建议直接收藏备查。参数值说明容量128Mbit / 16MB实际可用空间为16MB工作电压2.7V – 3.6V3V系列FPGA板载电压通常兼容Page大小256 Bytes最小编程单位Sector大小4KB最小擦除单位32KB Block32KB支持半块擦除64KB Block64KB全块擦除速度最快JEDEC IDEF 40 18EFWinbond18128Mbit最高时钟133 MHz实际使用时受PCB和FPGA CCLK限制温度等级-40℃ ~ 85℃IQ后缀对应工业级这颗Flash的Sector大小是4KB和市面上大多数SPI NOR Flash一致但不要想当然。有些厂商的Flash Sector是8KB个别甚至按Uniform Sector和Boot Sector区分不同大小。填参数前一定要查对应型号的数据手册确认实际规格不然Vivado生成的擦除策略会出问题。2.2 常用指令与状态寄存器详解手动添加时Vivado会要求填写一组操作码。这些操作码必须和W25Q128JVEIQ数据手册保持一致核心指令如下。功能指令码说明Read Data0x03普通读兼容性最好Fast Read0x0B快速读带Dummy周期Fast Read Dual Output0x3B双线输出读Fast Read Quad Output0x6B四线输出读Fast Read Quad I/O0xEB四线I/O读速度最快Read JEDEC ID0x9F读取3字节芯片IDWrite Enable0x06写之前必须发送Page Program0x02按页编程最多256字节Quad Page Program0x32四线写入Sector Erase0x20擦除4KB32KB Block Erase0x52擦除32KB64KB Block Erase0xD8擦除64KBChip Erase0x60 / 0xC7整片擦除Read Status Register-10x05读取SR1含BUSY位Read Status Register-20x35读取SR2含QE位Write Status Register0x01写状态寄存器状态寄存器这一块值得单独拿出来说。SR1的bit0是BUSYbit1是WEL写使能锁存bit2到bit5是BP0到BP3块保护位bit7是SRP0。SR2的bit1是QE这是Quad模式的总开关。华邦这颗Flash出厂时QE位默认是0也就是默认工作在标准SPI模式。如果要用SPI x4固化必须先把QE位置1否则即使接线支持四线Flash也不会响应四线指令。Vivado在编程选项里提供了相关设置后面实操部分会提到。2.3 硬件连接与Quad模式的关系SPI Flash的标准四线是CS#、CLK、DIMOSI、DOMISO另外两个引脚WP#和HOLD#在普通SPI模式下是功能引脚但在Quad模式下会变成IO2和IO3。这意味着硬件设计上要特别注意如果计划用SPI x4方式固化或启动WP#和HOLD#不能简单接死到电源或地必须通过电阻上拉或直接接到FPGA的可分配IO上。很多开发板为了兼容x1/x2/x4会把这两个引脚各经10kΩ电阻上拉再连到FPGA引脚。实际项目里遇到过一种情况板子为了节省IO把HOLD#引脚直接接了地。这种设计在SPI x1模式下完全没问题因为HOLD#不参与通信。但只要切到Quad模式HOLD#变成IO3电平被拉死数据根本读不回来。如果硬件已经焊死没法改那就只能老老实实用SPI x1模式固化虽然慢一点但可靠。另外7系列FPGA在SPI配置模式下会占用一部分专用引脚作为配置相关功能具体哪些引脚不能乱接要参考板卡原理图和UG570。如果固化后无法启动先把这些物理连接问题排查完再怀疑软件配置。3. Vivado 2020.2手动添加与固化全流程3.1 开始前需要准备什么开始操作前先确认三件事一是Vivado 2020.2已经能正常识别JTAG下载器二是目标板原理图里W25Q128JVEIQ的SPI引脚连接完整三是手头有编译通过、能正常运行的bit文件。JTAG下载器驱动是很多人第一次卡住的地方。Vivado安装目录下有Cable DriversWindows下需要额外的WinPcap或Wireshark驱动支持否则open_hw_target会一直找不到设备。如果确实装不上可以试试以管理员身份运行安装脚本或者换一个USB口。这个坑属于老生常谈但真的很影响开局体验。硬件连接上还建议确认一下Flash供电。W25Q128JVEIQ工作电压是2.7V到3.6V板子上通常用3.3V供电。如果Flash电压域和FPGA的配置引脚电压域不匹配可能出现能识别但编程失败的诡异现象。用万用表量一下Flash VCC和FPGA VCCO实际电压能省掉后面很多排查时间。3.2 在Hardware Manager中手动添加Flash模型连接好硬件并打开Hardware Manager后操作路径如下在Hardware窗口里右键点击FPGA器件选择“Add Configuration Memory Device”。弹出的对话框里默认会按厂商分组显示一批Flash型号搜索框直接输入w25q128通常能找到W25Q128JV系列但不同小版本可能没有JVEIQ这个具体型号。找不到时点击窗口里的“Add”或“Create/Import”按钮打开部件编辑表单。表单里需要填写的核心字段如下NameW25Q128JVEIQManufacturerWinbondDensity128MbPage Size256 BytesSector Size4096 BytesJedec Device IDEF 40 18有的界面需要写成0xEF4018注意按实际输入格式来Read指令0x03Fast Read指令0x0BPage Program指令0x02Sector Erase指令0x20Chip Erase指令0xC7Quad Enable启用QE位定义在Status Register-2的bit1填完保存后这颗Flash会出现在列表中以后新建工程也能直接复用。如果不想在GUI里逐项填写也可以从社区下载现成的Vivado配置部件XML文件通过导入功能加载。导入后建议核对JEDEC ID和Sector大小防止拿到的是其他型号的定义。这里分享一个很实际的经验JEDEC ID一定不能填错。Vivado在编程后校验时会通过0x9F指令回读芯片ID与填写的值比对。ID不一致会直接报错。网上确实有人把W25Q128的ID错写成EF 40 17结果每次烧写都卡在校验环节排查半天才发现是ID填错。手工填写这类参数时最好打开数据手册对着填不要凭记忆。3.3 生成bit流时必须设置的配置参数手动添加完Flash模型后需要在综合实现工程的bit流设置里确认几个和配置相关的参数。第一个是SPI总线宽度对应属性BITSTREAM.CONFIG.SPI_BUSWIDTH。如果硬件上WP#和HOLD#都引出来了建议直接设成4启用Quad模式读取启动速度更快。如果硬件没引出只能设成1或2。第二个是配置时钟频率对应BITSTREAM.CONFIG.CONFIGRATE单位是Hz。建议从33MHz开始试稳定后再往上提。不要一上来就拉满SPI Flash实际读取能力受PCB布线和上拉电阻影响很大频率太高容易读错数据。第三个是配置模式对应BITSTREAM.CONFIG.CONFIG_MODE可以显式指定SPIx1或SPIx4。这几个参数可以在Vivado的“Edit Device Properties”中修改也可以用Tcl直接写在工程里set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 4 [current_design] set_property BITSTREAM.CONFIG.CONFIGRATE 33000000 [current_design] set_property BITSTREAM.CONFIG.CONFIG_MODE SPIx4 [current_design]生成bit流之后再用write_cfgmem命令生成mcs或bin文件。我比较喜欢用Tcl命令比GUI更直观而且方便做版本管理。以下两条命令覆盖了两种常见场景# 生成bin文件SPI x1模式 write_cfgmem -force -format bin -interface spi x1 -size 128 \ -loadbit up 0x0 D:/fpga_project/top.bit \ -file D:/fpga_project/top.bin # 生成mcs文件SPI x4模式Quad write_cfgmem -force -format mcs -interface spi x4 -size 128 \ -loadbit up 0x0 D:/fpga_project/top.bit \ -file D:/fpga_project/top.mcs注意-size参数是128不是16前面已经解释过单位是Mb。-interface参数要和bit流设置里的SPI_BUSWIDTH保持一致。如果bit流按x4生成cfgmem却用x1封装FPGA上电后读取方式对不上一样无法启动。3.4 通过JTAG把固件写进Flash在硬件管理器里选中FPGA器件后右键菜单选择“Program Configuration Memory Device”或者直接用Tcl命令操作。GUI操作时编程选项里建议把Erase、Blank Check、Program、Verify四个都勾上。很多人为了省时间只勾Program结果擦除不干净出现启动后逻辑混乱、部分功能不工作的现象。Verify更是不能省烧写完自动回读校验能在现场暴露连接和参数问题。Tcl方式固化命令块如下open_hw connect_hw_server -url localhost:3121 open_hw_target set_property PROGRAM.FILE {D:/fpga_project/top.mcs} [current_hw_cfgmem] set_property PROGRAM.ERASE 1 [current_hw_cfgmem] set_property PROGRAM.VERIFY 1 [current_hw_cfgmem] program_hw_cfgmem [current_hw_cfgmem]编程时间取决于镜像大小和时钟频率。16MB全片擦除大概要几十秒加上写入和校验整个流程两三分钟很正常。如果超过十分钟还没结束建议检查JTAG链和Flash供电不要一直干等。3.5 上电验证与启动模式确认烧写完不要急着收工。断电把FPGA配置模式引脚切到SPI启动模式重新上电观察FPGA是否正常加载。以7系列为例M[2:0]接到001是Master SPI模式具体以板卡手册为准。如果板子上有DONE指示灯直接看灯最方便DONE亮起说明配置成功。如果上电后没有任何反应大概率不是Flash烧写问题而是配置模式引脚没设对或者FPGA侧初始化失败。这时候先检查模式引脚再用示波器量一下SPI CS#和CLK是否有波形。上电瞬间如果有一个片选拉低的动作、CLK上有一串时钟说明FPGA已经在尝试读取配置数据如果一直安静问题基本在前面不在Flash。4. 固化过程中的常见问题与排查4.1 找不到W25Q128JVEIQ或添加后列表不显示这是手动添加最常遇到的第一个问题。如果GUI里找不到手动添加入口还有一个办法去Vivado安装目录下的部件配置文件里直接加一条记录。不同版本这个文件的位置有点差异大致在安装目录/data/xicom下。在不清楚具体路径时用文件搜索功能搜w25q128这个关键词找到已有W25Q128相关型号的定义文件仿照格式新增一个条目保存重启Vivado后再看。如果不想折腾XML去论坛或GitHub搜现成的配置文件更高效。很多工程师已经把W25Q128JVEIQ的定义做成了XML下载下来导入就能用。导入后注意核对Jedec ID和Sector大小因为网上流传的文件质量参差不齐有的刚好是别的型号改了个名字。4.2 添加成功但写入失败写不进去先查两个地方一个是Flash的WP#引脚是否被拉低另一个是状态寄存器里的块保护位是否被置位。有些板子的WP#默认接到GPIO上GPIO初始化成低电平就把Flash保护了。解决办法是把WP#拉高或者先通过写状态寄存器命令解锁块保护。另一个高频原因是SPI模式选错。手动添加时如果启用了Quad模式但硬件上的HOLD#引脚被直接接地编程时Vivado会通过IO2/IO3与Flash通信信号被拉死自然写不进去。遇到这种情况要么改回SPI x1模式要么从硬件层面把HOLD#释放出来改成经过电阻上拉或者接到FPGA引脚。4.3 固化后FPGA不启动固化成功但上电不启动排查顺序很重要建议按这个思路来配置模式引脚是否正确。7系列FPGA要确认M[2:0]处于SPI模式很多开发板用拨码开关控制拨错位置就是白费功夫。bit流配置里的SPI_BUSWIDTH和Flash实际接线是否一致。x4和x1不匹配是常见的启动失败原因没有之一。用示波器测量Flash的CS#和CLK。上电瞬间应该有读请求如果一直没波形说明FPGA没有发起配置读取。检查bit流是否开启了回退加载Fallback。如果开了Fallback且首地址不是有效镜像FPGA会去回退地址找找不到就卡住。还有一个隐蔽问题比特流里设的CONFIGRATE太高超过Flash实际读取能力。有人图启动快直接设到66MHz结果数据读错FPGA配置失败。稳妥做法是先用33MHz验证全流程确认没问题后再根据裕量调高。4.4 几个很容易踩但很少有人提的细节手动添加Flash型号后最好把工程里生成的mcs文件和Flash型号定义一起纳入版本管理。否则同事用另一台电脑打开工程时可能找不到自定义的Flash定义还得重新导入一遍。write_cfgmem里的-loadbit参数“up 0x0”表示从0地址开始连续加载。如果后续要做多镜像启动要注意镜像对齐到Sector边界。W25Q128JVEIQ的Sector是4KB镜像起始地址尽量按4KB对齐否则无法独立擦除某个镜像。量产阶段建议把编程选项里的Verify保留并且定期抽查。SPI Flash写入受接触电阻影响比较大JTAG连接器氧化、排线松动都会导致偶发编程失败。有了Verify问题能当场暴露不会等到整机测试时才被发现。5. 从一颗Flash扩展到更多场景搞明白了W25Q128JVEIQ换一颗其他SPI Flash其实也是完全一样的流程。只要是符合标准SPI NOR协议的芯片手动添加时把容量、页大小、扇区大小、JEDEC ID、指令集替换成对应数据手册的值就行。区别主要在于某些厂商芯片的QE位位置、状态寄存器定义、以及擦除指令选择这些细节都能在数据手册里查到。如果后续要支持FPGA的Multiboot、Golden Image回退、远程更新这些功能Flash参数的准确性就更重要了。多镜像的地址分配、回退地址、启动顺序都和Sector大小、Block大小有直接关系。把基础参数吃透后面做远程升级会从容很多。个人最后再分享一个习惯我会把常用Flash的型号参数整理成一个表格放在工程docs目录下每次新板子选型时直接对照。换芯片时只改配置文件不用重新摸索。平时多存几个不同厂商Flash定义好的XML文件也能在关键时刻节省不少时间。毕竟FPGA工程里最怕的就是“明明前面都验证过换个芯片又卡住了”这种重复劳动。