做FPGA开发的第一道坎,往往不是写代码,而是把整套工具链和开发板打通。很多新手在Quartus II里画好了图、写好了代码,结果卡在管脚分配上,或者编译能过却下载不进去,折腾一整天连灯都没点亮。我最早接触Quartus II的时候也是这样,对着密密麻麻的管脚表格一头雾水,后来经过几次完整的“从绘图到下载”流程,才把EDA工具和开发板之间的关系彻底理清楚。这篇内容我就用一套最简单的LED实验,把Quartus II连接开发板的完整链路拆开讲清楚,覆盖工程建立、原理图绘图、管脚分配、全编译流程、程序下载这几大块,还会附上我自己踩过的坑和排查方法。如果你手上有任意一块Altera或Intel FPGA开发板,并且刚走到“画完图不知道下一步怎么办”这一步,这篇文章就是给你准备的。
1. 开工前先把环境弄清楚:Quartus II版本、驱动与开发板选型
1.1 选对版本比会装软件更关键
Quartus II的版本选择是很多人忽略的第一步。网上搜“quartus ii安装教程”,跳出来的结果五花八门,有13.0、13.1、15.0、18.1甚至Prime系列。别急着下最新版,先看你的开发板主芯片是什么型号,再决定用哪个版本,这一步错了后面全是麻烦。
Quartus II 13.1是个分水岭版本。它支持Cyclone IV、Cyclone V、Stratix V等主流器件,而且界面经典、资料多、破解和教程齐全,很多高校实验室和开发板厂家把13.1作为配套版本。如果你的板子是Cyclone IV系列(比如EP4CE6、EP4CE10、EP4CE22),用13.1基本不会错。Cyclone 10 LP和MAX 10这类稍新的器件,建议用Quartus Prime 17.1或18.1。Intel接手之后把Quartus II改名成Quartus Prime,免费版叫Lite版,支持中小容量器件,对个人学习完全够用。
另外提醒一句,安装路径不要带中文和空格,尽量放在纯英文目录下,否则后面综合编译时偶尔会冒出来一些莫名其妙的环境变量问题。安装完成后先确认Device选项里能看到你需要的芯片系列,如果找不到,说明安装时器件支持包勾选不全,需要补装设备库。
1.2 开发板选型与芯片型号的对应关系
市面上常见的FPGA开发板大致分几类:一类是高校实验室常见的DE系列,比如DE0、DE10-Lite;一类是国内厂商做的黑金、正点原子、小脚丫、米联客这些;还有一类是核心板加扩展底板的方式,比如AXU15EG(Zynq UltraScale+)。无论是哪种,拿到板子第一件事不是急着插电,而是找到板子对应的原理图PDF和芯片型号。
拿Cyclone IV系列举例,EP4CE10F17C8这个型号拆开看:EP代表Cyclone系列,4CE是Cyclone IV E,10代表逻辑单元数量大概10K级别,F17是封装类型(BGA),C8是速度等级。管脚分配时Pin Planner里显示的引脚名称,比如PIN_M1、PIN_E1这些,必须和开发板原理图上的网络标号对上。最简单的确认方法就是打开原理图,搜索“LED”字样,找到LED灯连接的FPGA引脚编号,比如LED1连接的是PIN_M1,那你的管脚约束就要写成PIN_M1。
如果你是照着一块新板子做实验,先花半小时把以下信息记下来:时钟引脚(通常连接到50MHz有源晶振)、复位按键引脚、LED引脚、数码管段选和位选引脚、UART引脚。这些是练手阶段最高频用到的外设。
1.3 USB-Blaster驱动与硬件连接
Altera/Intel FPGA的下载器通常叫USB-Blaster,分原厂版和兼容版。USB-Blaster的驱动在Quartus II安装目录的drivers文件夹里能找到,但在Windows 10/11上,第一次插入USB-Blaster时经常出现“设备无法启动”或“未知设备”的提示,这是驱动签名问题。
处理方法是:在Windows的“高级启动”选项里,选择“禁用驱动程序强制签名”,重启后手动更新驱动,指向Quartus安装目录下的drivers\usb-blaster文件夹。我这里强调一下,必须先禁用驱动签名再装驱动,顺序反了反复插拔也没用。装好后打开设备管理器,能看到“Altera USB-Blaster”出现在通用串行总线设备下,带黄色感叹号就是不正常。
连接顺序也有讲究。USB-Blaster一端接电脑USB口,另一端是10针或者14针的JTAG排线,插到开发板的JTAG口上。注意排线1脚位置,一般开发板上会标注,反插轻则识别不到,重则烧坏下载器。开发板先上电,再连接USB-Blaster,最后打开Quartus II。虽然大部分时候先开软件再上电也能用,但这个顺序能避开很多“No Hardware”的尴尬。
2. 从画图开始:原理图输入与模块化设计
2.1 新建工程时最容易忽略的几个设置
打开Quartus II 13.1,File -> New Project Wizard,一路点Next到器件选择页面。这里要选择你开发板对应的芯片家族和具体型号。如果列表里没有,说明安装时的Device支持包不全。做完器件选择后,还有一个容易被忽略的页面是EDA Tool Settings,Quartus会问你要不要关联第三方工具,比如ModelSim-Altera。
我建议在这个页面就把仿真工具设置成ModelSim-Altera,版本选匹配的(Quartus II 13.1对应ModelSim-Altera 10.1e),这样后面生成仿真网表的时候路径都是自动配好的。如果现在不设置,后面综合出网表再想加,就要去Assignments -> Settings -> EDA Tool Settings里单独加,步骤更多。
工程路径同样建议用纯英文,工程名也不要带空格。比如 d:/fpga/led_test。我见过有人把工程放在桌面中文文件夹里,结果编译到一半报一堆诡异错误,复制到英文路径后不治而愈。Quartus对路径的容忍度比VS还要低,这已经算是个普遍经验了。
2.2 原理图绘图:从摆放元件到连线
标题里说的“绘图”,在Quartus II里对应的就是原理图输入(Schematic)。这种方式对新手非常友好,不用写一行HDL代码,全靠拖元件和连线完成一个简单设计。
新建方式:File -> New -> Block Diagram/Schematic File,生成一个.bdf文件。双击空白处打开Symbol窗口,在库目录里找到primitives -> logic,能看到AND2、OR2、NOT这些基础门电路;在primitives -> pin里能找到input、output引脚。从一个最简单的二输入与门开始:拖一个AND2进来,再拖两个input和一个output,把线连好。
连线的细节:鼠标左键从一个引脚端点开始拖,会出现十字光标,到目标端点松手。线必须是实心蓝色,虚线的线说明没连上。每条线要起网络名,双击input引脚就能改名字,比如key1、key2、led_out。命名规范强烈建议用有意义的信号名,别用node1、node2这种,后面管脚分配全靠名字找信号。
保存后最好马上做一次“Create Symbol Files for Current File”,也就是把当前.bdf封装成一个符号。这个操作很多人不知道,但它能让一个原理图模块被上一层级调用,是模块化设计的基础。
2.3 把模块封装成符号,为复用留好退路
一个完整的FPGA设计很少是只有一个门的逻辑,所以从画图的第一天起就应该建立模块化意识。比如你画了一个按键消抖模块,画好连线后,File -> Create/Update -> Create Symbol Files for Current File,Quartus会生成一个.bsf符号文件。之后新建一个顶层bdf文件,双击空白处,在Project目录下就能找到刚才生成的符号,可以直接拖进顶层图里使用。
这样做最大的好处是:每个模块独立编译、独立验证,出了问题不用在几百条连线里找。而且做完LED流水灯实验后,这个流程可以直接复用到数码管扫描、UART收发等项目上。后续如果你转用Verilog/VHDL写代码,也可以在File -> Create/Update里把HDL文件转成符号,混用原理图和HDL,这在大项目里很常见。
绘图阶段常见的低级错误包括:多个output拼在一个信号上产生多驱动冲突、input引脚悬空、信号名大小写不一致。Quartus对信号名是大小写敏感的,key1和KEY1是两个不同的信号,这个细节在后续管脚分配时最容易坑人。
3. 管脚分配实战:别直接在代码里写死引脚
3.1 拿到开发板原理图先看什么
管脚分配是整个流程中对新手最不友好的环节,但只要建立好方法,其实机械性很强。我习惯拿到一块开发板后,先打开原理图PDF,按功能搜索关键字:LED、CLOCK、KEY、UART。每搜到一个外设,就把对应的FPGA引脚号记录下来,整理成一个表格。
举个例子,某开发板的LED接线可能是这样:
| 信号名 | FPGA引脚号 | 网络标号 |
|---|---|---|
| LED1 | PIN_M1 | led[0] |
| LED2 | PIN_M2 | led[1] |
| LED3 | PIN_L1 | led[2] |
| CLK_50M | PIN_E1 | clk |
整理这个表格的功夫不能省,因为Quartus的Pin Planner里列出的引脚是芯片物理引脚,不是你代码里的信号名。如果不做这个映射,你根本不知道哪个信号应该填哪个位置。更关键的是,管脚分配要参考开发板原理图中的“bank电压”,Cyclone IV的BANK1如果接了3.3V,那么分配到BANK1的I/O Standard就填3.3-V LVTTL,填错会导致下载后信号电平不匹配。
3.2 Pin Planner操作的细节
做完原理图和编译后,点击Assignments -> Pin Planner,会弹出图形化的引脚视图,左边是引脚列表,右边是芯片封装图。在列表的“Node Name”列找到你的信号名,双击“Location”那一列,下拉选择对应的引脚编号。
这里要强调两点。第一,“Location”下拉框里显示的是芯片物理引脚,比如PIN_M1,不是信号名。很多人在这里把信号名当成引脚填进去,保存后编译就报“Can't find pin location”。第二,如果同一个信号被多个引脚占用,或者同一个引脚分配给了两个信号,Pin Planner会直接在左侧用红色标记,鼠标悬停能看到冲突原因。
分配完之后不要忘记填写I/O Standard。Quartus II默认会自动匹配,但强烈建议手动设置为3.3-V LVTTL,因为有些开发板的外设接口用了不同电压标准,比如LVCMOS、TTL,默认值可能跟板子实际电平不匹配。我遇到过下载后LED输出高电平电压不对的情况,排查下来就是I/O Standard没设置对。
保存管脚分配后,Quartus会把约束写进.qsf文件。如果你重新打开了工程,发现之前的管脚分配还在,就是这个文件在起作用。
3.3 用QSF文件管理管脚约束
Pin Planner操作的底层其实是编辑QSF(Quartus Settings File)文件,格式如下:
set_location_assignment PIN_M1 -to led[0] set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to led[0]当你需要复刻一个工程,或者把别人的工程管脚配置快速搬到自己的工程时,直接编辑QSF比在图形界面上翻更快。用记事本打开工程的.qsf文件,找到set_location_assignment开头的行,按上面的格式逐行添加即可。如果把信号定义成数组形式,比如output [7:0] led,管脚分配也可以逐位写:
set_location_assignment PIN_M1 -to led[0] set_location_assignment PIN_M2 -to led[1]注意QSF里的信号名必须和设计里的信号名完全一致,包括大小写。我试过一次把led[0]写成了led0,编译时Quartus直接忽略这条分配,直到下载到板子上才发现引脚根本没约束上。使用QSF文件还有一个好处,就是可以把整个工程的管脚分配做成模板,不同实验之间复用,省去重复手动操作。
4. 编译不是点一下就行:全流程拆解与常见警告
4.1 全编译五步走,每一步在干什么
Quartus II的编译按钮边上有个下拉箭头,点开可以看到Analysis & Synthesis、Fitter、Assembler、Timing Analyzer、EDA Netlist Writer等选项。直接点“Start Compilation”是跑全流程,但理解每一步在干什么,才能看懂报错和警告。
第一步Analysis & Synthesis(分析和综合),负责检查语法错误、分析原理图连接关系,然后把设计转换成一个由逻辑单元和查找表组成的网表。这一步报错的通常是语法问题、信号未定义、模块端口不匹配等。第二步Fitter(布局布线),把网表里的逻辑单元放到FPGA实际的逻辑阵列中,并完成连线。第三步Assembler(装配),根据布线结果生成用来下载的配置文件,包括.sof和.pof文件。第四步Timing Analyzer(时序分析),检查设计能否在指定的时钟频率下满足建立时间和保持时间要求。第五步EDA Netlist Writer(仿真网表生成),供ModelSim等外部工具做功能仿真。
我见过有人每次都点全编译,但对“编译到底做了什么”一无所知。实际排查问题的时候,看Compilation Report里的某个步骤,尤其是Fitter后的资源使用情况、管脚分配报告,能快速定位问题。比如管脚分配后,可以在Fitter -> Pin Out File里查看最终所有引脚的分配状态。
4.2 编译报错与警告的正确处理姿势
编译过程中的Error和Warning要认真区分对待。Error不处理就一定不能下载,Warning则要分类:有些Warning可以忽略,有些Warning是在提示你设计可能有隐患。
常见Error之一:“Can't place multiple assignments to same destination pin”。这个是由于两个信号分配到了同一个引脚导致,去Pin Planner里检查重复项就好。另一个常见Error是“Can't find design node”,多半是信号名和管脚分配里的名字不一致。修改后必须重新全编译,Quartus不会自动把修改过的管脚约束同步到已经生成的文件里。
比较隐蔽的是Warning。比如“Warning (10028): Can't resolve multiple constant drivers for net”,说明你的设计里有多个驱动源同时连到一个信号上,通常表现为原理图里两个输出口接到同一条线,这在组合逻辑里会产生竞争,必须改掉。再比如“Critical Warning: Pin led[7] not assigned to an output pin”,说明你还有未分配管脚的信号,这种Warning如果不处理,下载后板上那个信号就是悬空的,功能肯定不对。
我的习惯是编译完成后,先从Compilation Report里看“Processing”标签下有没有红色Error,再筛“Critical Warning”。普通Warning可以先记录放到一边,但只要涉及管脚未分配、时钟未约束、多驱动的必须当场解决。
4.3 时序问题:从slack为负说起
当你跑一个LED闪烁实验,10MHz或50MHz的时钟下基本不会遇到时序问题。但当设计复杂度上来,时钟频率提高,就会在Timing Analyzer报告里看到类似“slack:-2.345ns”这样的信息。Slack为负,代表时序不满足要求,也就是数据传输在一个时钟周期内来不及稳定。
遇到负slack,优先检查三个地方:时钟约束是否设置了正确的时钟频率(Assignments -> Settings -> Timing Analysis Settings里添加时钟约束);代码或原理图中是否存在过长的组合逻辑链;Fitter报告里是否提示关键路径走得太远。降低工作时钟频率是最直接的应急手段,但如果是在做高频设计,就需要重新审视流水线划分了。初学阶段,只要时钟约束填对了,50MHz以下的简单逻辑很难把slack做负。
还有一点,Quartus II 13.1默认的时序分析流程里,如果没有手动添加时钟约束,Timing Analyzer基本是“哑巴”状态,不报错但也不代表你的设计时序是收敛的。养成写约束、看时序报告的习惯,是走向正经FPGA开发的分水岭。
5. 下载到板子:JTAG与AS模式到底怎么选
5.1 Programmer界面操作全流程
编译通过后,点击Tools -> Programmer打开下载界面。第一次进来Hardware Setup那里多半是显示“No Hardware”,不要慌,点Hardware Setup,选USB-Blaster,如果能识别出设备,界面上会显示“USB-Blaster [USB-0]”。
接着在Mode下拉框选JTAG,点击Add File把你工程目录下的.sof文件加载进来。然后勾选Program/Configure那一列,最后点Start。下载完成后Quartus下方的进度条会显示“100% (Successful)”,此时开发板上的设计应该已经跑起来了。
如果点Start之后,进度条卡在0%不动,或者立刻报错,先把开发板断电,然后重新上电再试一次。JTAG下载对供电稳定性有一定要求,有的板子USB口供电不足,就会导致下载到一半失败。这种情况接上外部电源基本能解决。
5.2 SOF和POF的文件转换与固化
JTAG模式下载的是.sof文件,这个文件有个特点:掉电即失。也就是说,开发板断电重启后,程序就没了,LED也不闪了。要让程序上电自动加载,需要用AS模式把配置写进FPGA的配置芯片(EPCS系列),或者使用支持内部flash的器件(如MAX 10)。
先把.sof转换成.pof:File -> Convert Programming Files,Programming file type选Programmer Object File (.pof),Mode选Active Serial,然后在Input files to convert里添加.sof文件,点击Generate生成.pof。回到Programmer界面,Mode切换为Active Serial Programming,添加刚才生成的.pof文件,勾选Program/Configure,点击Start。这样烧录完成后,开发板重新上电也会自动加载配置。
需要注意,不是所有开发板的下载器都支持AS模式,有的简易下载器只做了JTAG电路。如果你手头的板子只支持JTAG,但又想上电自启,可以查一下你的FPGA芯片是否支持内部配置flash(比如MAX 10),或者只能外接EPCS芯片。AS模式烧录前,记得把下载器的AS排线跳线帽拨到AS一侧,很多下载器的JTAG和AS是物理复用同一根排线的。
5.3 烧录后不跑,先查这四件事
程序下载成功但板子上没反应,这是新手最容易卡住的场景。根据我的经验,按优先级查以下四件事:
第一,时钟是否进来。用示波器或者万用表量FPGA的时钟引脚,确认有正常的方波信号。很多设计的逻辑没有问题,但板子的晶振没焊好或者没上电,导致FPGA内部没有时钟翻转,所有时序逻辑全部停摆。第二,复位逻辑是否正常。如果设计里用了异步复位且复位按键默认按下,那程序可能就是一直处于复位状态,看起来像没运行。第三,管脚分配是否真的生效。在Compilation Report -> Fitter -> Pin Out File里搜索你的LED信号名,确认物理引脚号和你分配的完全一致。第四,电平标准是否匹配。如果你的LED信号分配到了1.8V的BANK,而LED灯电路是3.3V的,那点亮条件就会比较诡异,表现为灯微亮或者不亮。
我遇到过一次特别迷惑的情况:下载100%成功,LED却全灭。找了一圈发现是Pin Planner里LED信号的名字大小写和原理图不一致,导致管脚分配实际上失效,Quartus把那个信号默认分配到了一个任意引脚上。所以烧录后异常,先别怀疑代码,先怀疑约束。
6. 常见问题排查实录:从驱动识别到下载失败
6.1 电脑识别不到USB-Blaster
现象是打开Programmer的Hardware Setup,设备列表空白,设备管理器里看到未知设备或带感叹号的Altera USB-Blaster。这个问题的概率很高,主要是驱动签名和驱动路径两个原因。
如果是新的Win10/Win11系统,第一步就是进“恢复”->“高级启动”->“立即重新启动”,选择“疑难解答”->“高级选项”->“启动设置”->“重启”,然后按数字键7选择“禁用驱动程序强制签名”。然后在设备管理器里右键未知设备,选择更新驱动程序,手动指向Quartus安装目录下drivers\usb-blaster文件夹。安装成功后设备名称显示为“Altera USB-Blaster”。
这里有个细节:如果安装后依然显示感叹号,右键驱动文件可以看错误代码。代码31通常是因为驱动版本不兼容,可以试试手动选择过时版本的驱动;代码10一般是USB口供电或接触不良,换一个直连的USB口,尽量别用前置面板或者USB Hub。我自己一直用的是电脑后置USB 2.0接口来连USB-Blaster,兼容性最稳。
6.2 下载时报Device Chain Error
下载时出现“Unable to access JTAG chain”或“Device chain error”的报错,通常不是软件问题,而是JTAG链路上没有识别到目标FPGA。排查顺序是:确认开发板电源已打开并且电源指示灯亮;确认JTAG排线方向正确、接触良好;确认Mode模式下JTAG链检测到的器件数量是否为1。
如果用了多个JTAG设备串联,比如FPGA和CPLD串在同一根链上,Quartus会显示多个器件。而有的下载器需要手动指定JTAG链上的器件数量,在Programmer界面点击Auto Detect可以自动识别。如果Auto Detect识别不到任何器件,那基本可以判断是物理链路问题。
还有一个隐蔽的点:部分开发板的JTAG口和AS口是复用的,跳线帽位置不对时,JTAG链上就检测不到FPGA。这种板子在原理图里通常有“JTAG/AS Select”字的跳线说明,动手前翻一翻板子旁边的丝印或者用户手册。
6.3 SignalTap抓信号:让内部节点露出水面
当代码功能不符合预期时,除了下载后看现象,更常用的调试手段是使用Quartus自带的SignalTap II逻辑分析仪。它相当于把示波器的探针放进FPGA内部,抓取想看的那几个信号。
用法是:新建一个.qst文件,在Node List里点击“List”添加要观察的内部信号,设置采样时钟(通常是系统时钟),设置采样深度,然后保存。编译时会自动把SignalTap的调试逻辑加进去,重新下载后,点击运行触发,SignalTap就会把波形显示出来。我第一次用SignalTap定位流水灯异常的时候,发现就是复位信号一直处于低电平,问题一目了然,效率远高于反复猜测。
不过SignalTap会占用额外的逻辑资源和存储块,调试完记得禁用SignalTap节点再重新编译下载,否则正式版的程序里也会带着调试逻辑,资源浪费倒还好,时序可能会被悄悄改变。这也是一个很实际的工程习惯。
最后分享一个很实用的小习惯
项目越做越多之后,我最大的体会是:Quartus II这套全链路流程,真正难的从来不是软件操作,而是对整个链路每个环节的“敬畏”。从环境安装、版本选择、绘图、管脚约束到编译下载,每一步都藏着一堆“看着小、影响大”的细节。如果你正在学FPGA,建议从最简单的LED实验开始,逼着自己完整地走完至少三次全流程——第一次用原理图,第二次改成Verilog,第三次加上SignalTap调试,三次下来你对“从绘图到下载”这件事的理解会有质的飞跃。另外,每次做完一个工程,把引脚约束、工程设置、遇到的问题整理成笔记,日后再做新项目直接抄自己的作业,比到处百度高效太多。