做FPGA开发的人,十有八九是从点灯开始的。但同样是点灯,拿到国产复旦微FMQL45这种ARM+FPGA异构SoC平台,整个流程和纯FPGA开发板还是有明显差别的。FMQL45系列集成了双核ARM Cortex-A9处理器和可编程逻辑,软硬件协同的特性让它比单纯跑Verilog多了一层复杂度,也正是这层复杂度,让一个"LED流水灯"实验从工程创建到硬件调试走下来,能把Vivado的完整开发链路、约束设计、在线调试方法全部串一遍。
这篇文章我一共分七个部分来讲,从FMQL45的芯片架构理解、Vivado环境准备、RTL工程创建、代码与约束设计,到综合实现、比特流生成、JTAG下载和在线调试,全部基于我实际操作的记录整理。适合刚入手国产FPGA平台、之前只玩过纯逻辑FPGA、或者正卡在"工程建好了但板子不亮"这个环节的朋友参考。全程记录我在FMQL45上跑通LED流水灯的每一步操作、每一处报错和对应的解决办法,属于可以直接照着复现的操作笔记。
1. 一块板子两个世界:先搞懂FMQL45到底在做什么
1.1 FMQL45和Zynq-7000的"血缘关系"
拿到复旦微FMQL45开发板,第一件事不是急着开Vivado,而是先理解你手上这块芯片的定位。FMQL45是复旦微电子推出的嵌入式处理器芯片,片内同时集成了PS(Processing System,处理器系统)和PL(Programmable Logic,可编程逻辑)两大部分。PS端是双核ARM Cortex-A9,主频可以跑到1GHz上下,跑Linux、跑裸机程序都没问题;PL端是FPGA逻辑资源,用来做高速并行处理、自定义外设接口。
这套架构和Xilinx Zynq-7000系列非常接近,开发工具链也基本沿用了Vivado生态。所以你在网上搜FMQL45的资料,会发现大量Zynq-7000的实验教程可以直接参考,寄存器地址、AXI总线接口、甚至部分IP核的使用方式都有很高的相似度。但也别高兴太早,国产芯片在细节上一定有你需要注意的地方,比如个别外设的寄存器偏移、时钟管理单元的配置方式、以及开发板上引脚分配的差异,这些都得靠自己看原理图和芯片手册来确认。
这里插一句和你选型相关的经验:FMQL45在不少工业控制、电力电子、机器视觉项目里出现频率很高。原因很简单——国产化需求+ARM和FPGA在一颗芯片里,整板面积和功耗都下来了,通信带宽还比板间互连高一个量级。对于想接触异构SoC开发、又希望技术栈能迁移到实际项目的人来说,这是个很合适的入门平台。
1.2 为什么LED实验并不像看起来那么"简单"
你可能觉得LED实验不就是写个计数器、翻转几个IO吗?在纯FPGA开发板上确实如此。但FMQL45开发板上的LED,接在PL端的IO上,你要让它们亮起来,至少要走通这么几条链路:
- Vivado工程创建时,芯片型号选择必须和板上实际芯片一致;
- RTL逻辑设计需要绑定正确的引脚位置和IO电平标准;
- 综合(Synthesis)、实现(Implementation)、生成比特流(Bitstream)每一步都要没有致命错误;
- 用下载器连接板子时,JTAG链要能被Vivado识别;
- 比特流下载到PL后,时钟、复位、引脚极性任何一环不对,LED都不会按预期工作。
每一步都可能出问题。我见过不少刚上手的工程师,代码写得完全正确,最后卡在"引脚没约束"或者"JTAG识别不到设备"上。所以这篇文章我刻意把"看上去很简单"的步骤也展开讲,因为对FMQL45这类平台来说,工具链的坑往往比逻辑设计的坑更多。
2. 开发环境准备:Vivado装对了,后面才不折腾
2.1 版本选择:不是越新越好
FMQL45开发使用的工具链是Vivado。复旦微官方资料里通常推荐Vivado 2019.2或2020.2版本,这个信息很关键。我最初图省事装了2022.2,结果工程建好之后总觉得别扭——不是说完全不能用,而是部分IP核的默认配置界面变了,早期国产例程的脚本和约束文件在新版本下会有兼容性提醒,排查起来多花时间。
实验下来,我的建议是:尽量和开发板资料包里的Vivado版本保持一致。如果你拿到板子时配套资料是2019.2的例程,那就装2019.2;没有配套资料的情况下,2020.2算是一个兼容性比较好的版本。版本的选择会直接影响后面跑IP核配置、跑综合实现时的行为,别在版本上给自己添堵。
安装本身没什么特别的门道,Windows和Linux都行。我自己调试PL逻辑时在Windows下用Vivado,如果需要把PS端Linux跑起来,再切到Ubuntu环境做交叉编译。装的时候有几个点提醒一下:
- 安装路径不要带中文和空格,不要装在C盘系统目录里,Vivado对路径解析偶尔会出幺蛾子;
- 安装时勾选Vivado HL WebPACK或HL Edition即可,FMQL45的逻辑规模用WebPACK版本够用,不需要Vivado HLx(版本含Vitis相关组件)的完整安装,除非你后面要搞SDSoC/Vitis流程;
- License方面,如果你没有正版授权,可以用评估版License(Vivado会免费提供标准版评估,功能全开),申请完放在指定目录就行。
2.2 下载器驱动:先搞定这个再开干
FMQL45开发板常见的调试下载器有两种:一种是板载的JTAG调试器,插上USB线电脑就能识别;另一种是需要外接的Xilinx平台电缆USB下载器(类似DLC10兼容款)。不论哪种,Windows下都要装驱动。
我第一次接上板子时,Vivado的Hardware Manager里一直显示"No hardware target",设备管理器里看是未知设备。原因很简单,驱动没装上。解决方法是:在Vivado安装目录下找到data/xicom/cable_drivers/nt64这个文件夹,里面有个dpinst_amd64.exe,右键以管理员身份运行,装完重新拔插USB线,设备管理器里就能看到"Xilinx USB Cable"之类的设备了。
另外注意,有些国产开发板的JTAG模式需要拨码开关配合。比如板子上有BOOT模式选择,你需要把启动模式拨到JTAG档,而不是QSPI或SD卡档。这个细节非常容易忽略,我调试时不只一次遇到"啊,拨码没拨过来"的情况。上电前先把板子的跳线和拨码确认一遍,养成习惯。
2.3 软硬件路径的工程化习惯
环境装好后,建议建一个统一的工程目录结构。我自己习惯这样组织:
project/ ├── rtl/ # 所有RTL源码 ├── xdc/ # 约束文件 ├── ip/ # 自定义IP或IP核生成目录 ├── sim/ # 仿真相关文件 ├── vivado/ # Vivado工程文件 └── doc/ # 原理图、数据手册、笔记好处很明显:工程规模一大,文件组织不乱,版本管理也好做。很多初学者喜欢把Vivado工程直接建在桌面上、文件名随便起,等到做集成项目时,几十个文件堆在一起找起来真要命。FMQL45实验阶段规模小,但你迟早要在这块平台上做更复杂的设计,一开始就养成规范,后面省心。
3. 从零创建Vivado工程:每一步都讲清楚为什么
3.1 选择RTL工程而不是IP Integrator
打开Vivado后,创建工程时有几个模板选项。LED实验这种纯PL逻辑设计,选"RTL Project"就行,不要一上来就点"IP Integrator"(Block Design)。
原因很简单:IP Integrator主要用于搭建PS和PL之间的系统级连接,比如把Cortex-A9处理器、AXI总线、DMA控制器这些模块用图形化方式连起来。纯LED流水灯用不到PS端资源,直接在RTL里写逻辑、绑定引脚就够了。等你后面要做PS控制PL外设的实验,再回到IP Integrator,把Zynq PS核拖出来,接上AXI GPIO之类的外设IP,那个流程完全是另一套玩法。
FMQL45的芯片型号在Vivado里怎么选?这里有个细节:复旦微的芯片在Vivado器件列表里对应的可能是FMQL45T900或类似的兼容型号标识。如果你找不到直接叫"FMQL45"的选项,先查一下手头板卡用的具体芯片丝印,再在Vivado的Device列表里按封装、速度等级筛选出对应项。我的经验是参考开发板资料包里的Vivado工程:找到官方例程的.xpr文件,右键用记事本打开,搜索Part字段,里面会明确写着器件型号,照抄就不会错。
3.2 工程创建流程中的几个关键选项
创建RTL工程的流程是:File → New Project → Next → 填工程名和路径 → 选Project Type为RTL Project → Add Sources(暂时可以不加,后面再添加)→ Add Constraints(同样可以后面再加)→ 选择器件型号 → Finish。
这中间有几个选项值得你注意:
- Do not specify sources at this time:推荐勾上,先创建空工程再看结构,避免一次性把文件路径引错,后面全乱;
- Project Location:路径建议直接放到你规划的
vivado/目录下,工程名用led_run这种有意义的命名,不要用test1、test2; - Default Part:选对型号是头等大事,选错了后面综合实现会报各种奇奇怪怪的问题。
工程创建好之后,第一件事是检查左侧Flow Navigator导航栏里的Project Settings,确认一下Top Module名字、目标语言(Verilog)这些基本信息。养成这个习惯,后面添加文件时才不会因为顶层模块指定错误而找不到起点。
3.3 添加源文件:RTL和约束的正确姿势
在Sources窗口里右键 → Add Sources,把rtl/目录下的led_run.v加进来。注意这里有两种添加方式:"Add or create design sources"和"Add or create constraints"。RTL文件归设计源文件,XDC约束文件归约束文件,两者不要混在一起添加。
添加RTL文件时有个常见困惑:Vivado会自动根据模块的例化关系识别顶层,但如果文件里写了多个module,或者文件名和module名不一致,Vivado可能会选错顶层模块。这时你需要在Sources窗口里右键目标模块 → Set as Top。
约束文件也是同理,多个XDC文件存在时,Vivado会按它们在工程里的顺序依次处理。LED实验只有一个XDC文件,不存在这个问题;但当你的设计包含MMCM时钟约束、物理约束、时序例外多条文件时,文件的顺序会影响约束覆盖关系,到时候记得留意。
4. 跑马灯逻辑与约束文件:30行代码背后的三个重点
4.1 Verilog代码设计:计数器与移位寄存器
LED跑马灯的逻辑很简单,核心就是分频计数和移位输出。在我们的开发板上,LED一般有4个或8个,我这里按4个LED的写法来展示,引脚和极性以你手头板子的原理图为准。
module led_run( input wire clk, // 板载时钟,一般50MHz input wire rst_n, // 复位,低有效 output reg [3:0] led // 4个LED ); reg [25:0] cnt; // 计数器:每50_000_000个时钟周期清零一次,对应1秒 always @(posedge clk or negedge rst_n) begin if (!rst_n) cnt <= 26'd0; else if (cnt == 26'd49_999_999) cnt <= 26'd0; else cnt <= cnt + 1'b1; end // 移位:每秒把LED点亮位向左移动 always @(posedge clk or negedge rst_n) begin if (!rst_n) led <= 4'b0001; else if (cnt == 26'd49_999_999) led <= {led[2:0], led[3]}; end endmodule如果你用的板载时钟是100MHz,计数器要改成26'd99_999_999清零;如果是33.333MHz,改成26'd33_333_332。这个计算方式就是"时钟频率减一",举例来说50MHz时钟下,计数49_999_999个周期正好是1秒,因为计数器是从0开始数的,到49_999_999一共数了50_000_000个周期,也就是1秒。
这里有个代码层面的细节:我故意把计数器和移位逻辑写在两个always块里。实际综合时两个块都受同一时钟和复位控制,功能上完全没问题。但如果你把cnt和led的赋值混在同一个always块里,也没有错,只是逻辑看起来不够清晰。我建议按功能划分always块,一个管计数、一个管输出,这种风格在工程代码里更常见,也方便后续把LED的功能扩展成多种显示模式。
4.2 XDC约束:引脚位置和电平标准一个都不能少
写完Verilog只是第一步,真正让代码"落到"板子上的是约束文件。FMQL45开发板的LED引脚并不是固定焊在某个通用IO上,不同厂商的板子引脚分配完全不同。我在XDC里写的是位置约束和电平标准约束,格式如下:
set_property PACKAGE_PIN AA16 [get_ports {led[0]}] set_property IOSTANDARD LVCMOS33 [get_ports {led[0]}] set_property PACKAGE_PIN AB16 [get_ports {led[1]}] set_property IOSTANDARD LVCMOS33 [get_ports {led[1]}] set_property PACKAGE_PIN AC15 [get_ports {led[2]}] set_property IOSTANDARD LVCMOS33 [get_ports {led[2]}] set_property PACKAGE_PIN AD15 [get_ports {led[3]}] set_property IOSTANDARD LVCMOS33 [get_ports {led[3]}] set_property PACKAGE_PIN AB17 [get_ports {clk}] set_property IOSTANDARD LVCMOS33 [get_ports {clk}] create_clock -period 20.000 -name sys_clk [get_ports {clk}] set_property PACKAGE_PIN AB18 [get_ports {rst_n}] set_property IOSTANDARD LVCMOS33 [get_ports {rst_n}]上面的引脚名是我按常见开发板风格写的占位,你拿到自己的FMQL45板子后,一定要按原理图里LED、时钟、复位实际连接的引脚来改。把原理图对应页截图放大看,找到网络标号(比如LED_D1、SYS_CLK、RESET_N),再在芯片引脚列表里查到对应的封装引脚名,填进XDC里。
引脚约束之外,时钟约束也很重要。即使在LED实验这种低速设计里,我仍然建议加上create_clock。它不光是让时序分析有据可依,更重要的是,Vivado在Implementation阶段如果发现时钟端口没有任何约束,会报时序约束不足的警告。养成给所有时钟端口添加时序约束的习惯,等以后做高速接口时会非常受益。
4.3 LED极性问题:低有效还是高有效?
这是LED实验里最容易踩的坑。很多板子的LED一端接电源、另一端通过限流电阻接到FPGA引脚,FPGA输出低电平时LED才亮,这叫低有效;反过来,FPGA输出高电平时LED点亮,叫高有效。
写代码之前先看一眼原理图。如果原理图上LED的阳极接3.3V、阴极通过电阻接到FPGA引脚,那么是低有效,你的RTL里要让某个LED熄灭时输出1,点亮时输出0。上面的示例代码是为高有效设计的,如果板子是低有效,可以在约束里加一句:
set_property DRIVE LOW [get_ports {led[0]}]或者更简单——在RTL里把输出取反:
assign led_high_active = ~led_low_active;总之,LED实验的代码虽然只有几十行,但引脚查错一个、极性搞反一个,板子上的现象就完全不一样。这也是我为什么反复强调"先看原理图,再看例程,最后写代码"的原因。
5. 综合、实现与比特流生成:红线报错处理实录
5.1 完整流程的四个阶段和顺序
Vivado左侧Flow Navigator里从Synthesis到Bitstream是一条线:Run Synthesis → Run Implementation → Generate Bitstream。每一步在运行前都会让你选择运行策略,直接保持默认即可。
这里有一个操作习惯的问题:很多初学者习惯一股脑点"Generate Bitstream",Vivado会弹窗提示"Launch runs on 8 cores"之类的,然后就开始自动跑综合、实现、生成比特流。好消息是如果一切顺利,一条命令就出结果;坏消息是一旦中间哪一步出错,日志里报一串黄线加红线,新手很容易懵。
我的建议是分步操作,每一步看结果再迈下一步:
- 先点Run Synthesis,等综合结束,确认没有error;
- 综合结束后,在打开的Synthesis Design窗口里,点菜单栏的"Open Elaborated Design",先检查一下有没有语法错误、模块例化是否正确;
- 再到约束文件里检查引脚约束是否有效,此时可以用"Edit Constraints"直接添加引脚约束,也可以等Implementation阶段检查;
- 确认无问题后Run Implementation,跑完后看一眼时序报告(Timing Summary)和利用率报告(Utilization);
- 都通过了,再Generate Bitstream。
这个顺序能让你在最短时间里定位问题出在哪个阶段。比如综合报错,大概率是语法错误或模块名写错;实现报错,大概率是引脚约束冲突或逻辑太紧;只有时序违例(比如关键路径WNS为负)需要回到RTL去优化结构或改约束策略。
5.2 常见报错实录:DRC RTSTAT-2和它的朋友们
我在LED实验过程中遇到的第一个红线报错就是DRC RTSTAT-2。这属于Implementation阶段Report DRC检查出来的规则违例,通常是这样的提示:
[DRC RTSTAT-2] I/O port is not constrained: The I/O port led[0] is not constrained ...翻译过来就是:你有IO端口没有做引脚约束。出现这个报错,直接去检查XDC文件有没有成功例化到工程里、引脚名和RTL顶层端口名是否一致。我排查过一次,发现是约束文件里引脚写成了LED[0],而RTL端口名是小写led[0],TCL对大小写敏感,直接匹配不上。
另一个高发报错是时序违例(Timing Violation),LED实验本身逻辑简单,其实不太可能出现严重违例,但如果你把时钟约束的频率写错,比如板子实际是50MHz你却写了create_clock -period 10.000(100MHz),Vivado按照100MHz去布局布线,时序自然紧张,可能报WNS为负。解决办法就是把周期改回实际频率。
还有一类问题不是报错,而是"导出比特流成功但板子上没反应"。这种问题往往出在JTAG链识别、下载器接线、电源供电这些硬件环节,我放到下一节细说。
5.3 比特流文件哪儿去了:三种下载方式对比
Generate Bitstream完成后,Vivado会生成.bit文件,默认路径在工程目录下的.runs/impl_1/里。以LED实验为例,文件名叫led_run.bit。下一步就是把bit文件下载到FMQL45开发板上。
下载bit文件有几种不同方式,我按使用频率列一下:
| 下载方式 | 适用场景 | 特点 |
|---|---|---|
| Vivado Hardware Manager直接下载 | 日常调试 | 最快,点两下就能看现象,掉电丢失 |
| 通过Vivado生成下载配置(Program Flash) | 固化到QSPI Flash | 掉电不丢,上电自动加载 |
| 用SDK/命令行工具下载 | 自动化脚本、批量烧录 | 适合产线或脚本化流程 |
LED实验阶段用第一种就够了。打开Hardware Manager → Open Target → Auto Connect,识别到设备后右键设备 → Program Device,选中bit文件,烧进去。上电后观察LED现象,符合预期就说明整个PL链路是通的。
这里必须提醒一个概念:直接Program Device下载的是bit文件,这种下载方式掉电就没有了。如果想让程序在开发板上电后自动运行,需要把配置固化到QSPI Flash里。固化操作在Hardware Manager里选Add Configuration Memory Device,选择板载Flash型号,生成.bin或.mcs文件再烧写。国产平台的Flash型号有时候在Vivado列表里显示的不是原厂型号,需要手动指定兼容型号,这部分我建议参考开发板资料包里的指导文档,不要盲选。
6. 硬件调试实录:从bit加载失败到LED点亮
6.1 硬件连接和JTAG识别检查
把bit文件下载到FMQL45板上之前,先做一组硬件检查。我的调试顺序是这样:
- 确认开发板电源指示灯亮,核心电压正常;FMQL45的功耗不算低,劣质USB线供电可能导致上电后反复重启,最好用规格匹配的电源适配器;
- 确认JTAG下载器和开发板连接稳固,如果是外接下载器,检查排线方向有没有插反,Pin1对准;如果是板载下载器,USB线直接连电脑;
- 确认BOOT模式拨码在JTAG档位,这点我在前面提过,但值得再强调一次;
- 打开设备管理器,在"通用串行总线设备"或"调试设备"分类下看到Xilinx相关设备再进Vivado。
如果Hardware Manager里Auto Connect后显示"No hardware target",最常见的原因是驱动问题或线缆问题。换一根USB线试试,很多时候数据线只有充电功能,没有数据线芯,这种线接上根本没反应。另外,Vivado版本和下载器固件不兼容也可能导致识别失败,可以到Xilinx官网下载更新一下cable drivers。
6.2 下载bit后的三种现场情况
连接识别正常、点击Program Device后,无外乎三种情况:
情况一:进度条走完、LED按预期跑起来。大功告成,恭喜你,但别急着关掉窗口,后面调试ILA、固化Flash还要用到这个环境。
情况二:下载时报错,比如ERROR: [Labtools 27-2229] Device configuration failed。这种一般是配置时序或电平问题。检查JTAG链路有没有其他设备占用了同一条链;检查板子是不是进入了异常状态;把电源断掉重新上电、Refresh设备后再试一次。有一点需要注意,Vivado识别了设备但配置失败,往往和PS端启动模式有关——FMQL45的PS端如果正在从SD卡启动Linux,PL配置有可能被干扰,把启动拨到JTAG模式通常会解决这个问题。
情况三:下载成功但LED没有任何反应。这个问题最隐蔽,我在后面单独开一节讲排查思路。
6.3 用ILA观察内部信号:调试不止看现象
LED实验如果逻辑没反应,除了肉眼盯着灯看,更高效的排查手段是用Vivado的ILA(Integrated Logic Analyzer)来观测FPGA内部信号。ILA相当于一个可以嵌入到设计里的逻辑分析仪,可以把你想看的信号(比如计数器cnt、LED寄存器led)在FPGA运行时实时抓出来。
加入ILA的常用方式有两种:
- 在RTL代码里直接例化ILA IP核(Vivado IP Catalog里搜ILA),配置探针数量和位宽;
- 综合完成后,在Synthesis Design中右键信号 → "Mark Debug",再走实现流程。
我LED实验里其实没有用到ILA,计数器逻辑一眼就能推断问题,但打个比方:如果你做的是SPI接口的驱动,数据总是不对,凭肉眼是看不出毛病的,ILA就能帮你看到每一个时钟边沿上的信号变化。所以提前了解ILA的使用流程,后面做复杂实验时能省一大半排查时间。
ILA例化的基本思路是:在RTL里把要观察的信号接到ILA IP的probe端口,并把时钟接给ILA。下载bit后,在Hardware Manager里会自动弹出ILA调试界面,配置好触发条件(比如cnt == 26'd123),Run Trigger,就能看到触发边沿前后的波形。实测下来,Vivado的ILA功能完全能胜任低速到百兆级信号的调试,是FMQL45平台上非常趁手的工具。
6.4 LED不亮的排查路线图
下载成功但LED不亮,按优先级排查以下项目,我的实际经验是绝大多数问题出在最后两项:
- 电源检查:万用表量一下板子上3.3V、1.8V、VCC_INT等关键电源轨是否正常,LED本身的供电是否来自3.3V还是独立电源域;
- 时钟检查:确认Vivado的时钟约束的频率和板上晶振一致,用示波器或万用表频率档量一下晶振是否起振;有的板子晶振是PS端专供的,PL端需要用PS的FCLK输出或者板上另有PL时钟晶振;
- 复位检查:确认复位引脚的电平逻辑和代码一致;如果代码是高有效复位,板上默认拉低就会导致一直处于复位态;
- LED极性:低有效和高有效搞反,现象是完全相反的——电路上反了的灯会常亮,代码控制的那一盏不亮,其余常亮;这种问题看着像"没反应",其实是完全亮了;
- 引脚约束:引脚绑错位置,驱动信号根本没到LED那颗引脚上。这种问题最坑,因为Vivado不会报错——你约束的引脚是一个悬空IO,输出电平在那里翻转,但LED根本不在那。
我建议在新板卡上做LED实验时,先把约束文件写成点亮固定某个LED,比如led <= 4'b0001,下载确认这盏灯亮了,再去写流水灯的位移逻辑。这样能把"硬件通路"和"代码逻辑"分成两个步骤验证,排查问题快得多。
7. 常见问题速查表与踩坑记录
7.1 排查表:从报错信息到解决方案
我把FMQL45平台LED实验前后遇到的典型问题整理成了一张速查表,供你直接对照:
| 现象 | 原因 | 解决方案 |
|---|---|---|
| Vivado安装时提示WinPcap安装失败 | Vivado依赖WinPcap用于仿真和部分调试功能,系统权限或安全软件拦截 | 以管理员身份安装WinPcap,或单独下载WinPcap安装后再运行Vivado安装程序 |
| Hardware Manager提示No hardware target | 驱动未安装;USB线是充电线;设备被其他程序占用 | 重装dpinst_amd64.exe驱动;换数据线;关闭其他调试软件 |
| Program Device失败 / Device configuration failed | JTAG模式不对;电源不稳;启动模式拨码在非JTAG档 | 拨到JTAG启动模式;检查电源;重新上电Refresh设备 |
| DRC RTSTAT-2报错 | IO端口没有约束文件或约束名不匹配 | 检查XDC文件是否添加、引脚名是否和RTL端口完全一致 |
| 综合或实现时报错未指定顶层 | 工程未能自动识别顶层模块 | 右键模块 → Set as Top |
| 下载成功但LED全灭 | 可能处于复位态;时钟没来;极性搞反 | 先用固定电平点亮单个LED测试通路;检查复位电平和极性 |
| 下载成功但LED常亮 | 极性搞反(低有效设计成了高有效) | 修改RTL输出极性,或在约束中调整驱动方式 |
| 时序报告WNS为负 | 时钟约束频率大于实际频率;布局布线压力大 | 检查create_clock周期是否符实际;使用更高速度等级或优化代码 |
| 固化到QSPI后上电无反应 | Flash型号选错、启动模式不在QSPI档 | 参考官方资料选兼容Flash型号;把启动拨码拨到QSPI档 |
这张表我建议保存下来,尤其是前几行,工具链相关的问题是最耗时也最影响心情的。
7.2 我的三个独家避坑心得
第一,芯片型号眼看手查,新板卡永远优先以官方例程为准。创建工程时不要想当然,官方例程的工程文件里会直接写明所用器件型号,跟着走比自己猜稳妥得多。这在我第一次创建FMQL45工程时省了不少时间,当时我差点按Zynq-7045的型号去建工程了。
第二,先点亮一颗灯,再写流水灯。这个习惯救了我很多次。每次拿到新板子,我从来不会直接把完整设计烧进去,而是先写一个只有"让LED_D1输出规定的电平"的极简工程,下载后确认这颗灯能亮能灭,再在此基础上扩展逻辑。板上通路验证过了,代码再有问题就只管查代码,不互相甩锅。
第三,日志要分段看,报错要追根。Vivado的日志信息非常多,报错出现时不要只看最后三行。我的经验是:先看综合阶段的critical warning,再看实现阶段的DRC报告,最后才看bitstream生成阶段的错误。很多时候bitstream生成失败只是前面实现阶段遗留问题的连锁反应,根因早就在DRC报告里写明白了。养成从日志里找"第一次出现error的位置"的习惯,比反复重新跑工程有效得多。
第四,针对FMQL45这类国产平台,资料包和官方论坛是最高效的学习入口。复旦微官方提供的例程虽然不多,但每一个都很有参考价值。拿到例程后,我会先把它完整跑一遍,确认环境没问题,然后再从例程里删掉PS部分、修改成自己的逻辑。这样能大幅降低第一次接触不熟悉芯片时的挫败感。
7.3 下一步还能玩什么
LED实验跑通后,意味着你的FMQL45开发环境已经全线打通,Vivado工程创建、RTL编写、约束设计、综合实现、JTAG下载、硬件排错这几个核心环节你都有体感了。这之后有几个值得尝试的方向:
- 在PL里添加一个UART IP核,通过串口把FPGA内部信号发到电脑上看,建立最简单的"FPGA→PC"通信链路;
- 学习PS端的裸机或Linux开发,把双核ARM Cortex-A9跑起来,再通过AXI总线用ARM控制PL端的LED,体会真正的软硬件协同;
- 尝试用IP Integrator搭建一个基于AXI GPIO的Block Design,把CPU和外设连接起来,这算是FMQL45开发的核心玩法了。
我自己在FMQL45上做完LED实验之后,最强烈的感觉是:这个平台的上手曲线确实比纯FPGA要陡一些,因为增加了PS端的知识和工具链的复杂度;但一旦把这条链路跑通,后面做PetaLinux启动、AXI外设扩展、甚至是简单的图像采集处理实验,都会顺畅很多。LED实验的"小",恰恰是它适合作为第一个跑通全流程项目的原因——知识点集中,问题点少,出了问题也容易定位。把这套流程吃透,再往上叠加复杂度时,你就已经站在一个知道"问题出在哪个环节"的起点上了。