易灵思FPGA入门系列:Ti60F225开发板点亮LED完整流程
第一次接触易灵思EfinixFPGA是帮朋友评估一个图像采集项目。他手里拿的是一块Ti60F225开发板Titanium系列16nm工艺60K级别逻辑单元跟我说这芯片成本香、功耗低、生态也越来越成熟让我认真看看能不能用。说实话在Xilinx和Intel的圈子里泡了挺多年我一开始是持保留态度的但又不得不承认这两年易灵思在项目里的出镜率确实肉眼可见地变高了。真正上手之后我反而觉得Efinix的入门门槛比想象中低很多Efinity IDE免费下载、License免费激活安装包体积比Vivado小一个数量级自带的Quantum架构编译流程也不复杂。所以我想把这段探索过程沉淀成一个超详细的系列教程第一章就做最经典、也最容易被新手卡住的点亮一颗LED。别小看这个例子。它虽然逻辑简单却能帮你完整走通建工程—写RTL—加仿真—加约束—综合—布局布线—下载上板这条开发主线。这条路走通了后面做按键消抖、UART收发、SPI驱动、图像采集都是在这套流程上做加法。这篇教程适合完全没碰过易灵思的新手也适合想快速切换工具链的熟练工程师。1. 先看清手里的牌Ti60F225开发板与Efinity环境搭建1.1 Titanium家族与Ti60F225的真实定位易灵思目前的产品线分两大块TrionT系列和TitaniumTi系列。Trion主打成本敏感型项目型号从T8到T120很多入门学习板和量产的工业控制板都在用。Titanium则明显是冲着性能功耗比去的16nm工艺Ti60、Ti120、Ti180、Ti375一路排开覆盖几千到几十万逻辑单元的设计需求。Ti60F225这个名字可以拆开看Ti代表Titanium系列60表示逻辑单元规模在60K级别具体资源数量以官方手册为准大概落在六万出头这个量级F225是封装代号225球FBGA封装。这个规模放在同行里比大约对应Intel Cyclone V的5CEFA7附近或者Xilinx Artix-7的中端型号做接口协议转换、图像预处理、多轴电机控制这类轻量到中度的任务完全够用。我比较看重的是Ti60F225的片上资源块RAM和DSP模块都有部分封装还集成了硬核MIPI D-PHY很多做摄像头采集的项目就是冲着这个硬核IP选的它。相比同级别竞品这颗片子在静态功耗和单位逻辑成本上确实有优势这也是这几年它出现在各种比赛和项目里的原因。1.2 Efinity IDE安装与免费License下载Efinity IDE要去易灵思官网注册一个账号注册免费之后在下载页面选Windows或Linux版本。安装包大概在1GB上下和动辄二十几个GB的Vivado比轻量得让人感动。安装过程基本一路Next但有两个坑要提前避开第一安装路径不要带中文和空格。老生常谈了但FPGA工具链对路径字符特别敏感Efinity也不例外。第二建议不要在安装过程中顺手改一堆选项保持默认组件完整安装就行IDE里会自带Efinity Designer综合与布局布线和Efinity ProgrammerJTAG下载这两个核心组件。License激活这方面易灵思对个人用户非常大方Efinity IDE是免费许可证注册登录后在软件里绑定本机就能用不用申请商业授权。我实测下来绑定过程几分钟完事之后离线用也不受影响。首次启动如果卡在登录状态重启一次再激活基本就能解决。系统配置方面综合布局布线这个阶段内存越大越好16GB会比较舒服8GB也能跑LED这种小工程但跑大设计时明显吃力。CPU倒不挑现代i5/R5以上都没问题。1.3 板载LED硬件原理高有效还是低有效点灯之前先把开发板的原理图翻出来——这一步比写代码还重要。板载LED电路最常见的是两种接法低有效LED阳极接电源阴极经限流电阻连到FPGA引脚。FPGA输出低电平时LED点亮输出高电平时熄灭。高有效LED阴极接地阳极经限流电阻连到FPGA引脚。FPGA输出高电平时点亮。这个高低有效关系直接决定代码怎么写。我见过不少新手没看原理图按别人的工程照抄逻辑结果点不亮折腾半天发现是高低电平整反了。多数开发板上LED对应的网络名会带LED字样在原理图里搜一下顺着网络一路追到FPGA引脚号顺便看一眼串的限流电阻阻值。常见的是330Ω到1kΩ之间阻值大小不影响你写代码但有参考价值。另外一个必须确认的参数是IO电平。板载LED一般挂在某个BANK的VCCIO上常见1.8V或3.3V。后面写约束时IO_STANDARD必须和这个BANK电压一致。BANK供电是3.3V你就不能用LVCMOS18去约束电平不匹配的话引脚根本拉不到有效电平LED自然不亮。2. 点灯背后的硬件思维时钟、计数器与并行2.1 FPGA不是单片机always块不是语句在STM32里点亮LED一句GPIO_WriteBit就完事代码是一条条顺序执行的指令。但FPGA不是CPU你写的Verilog不是在描述依次运行的语句而是在描述一张电路图。时钟上升沿到来的那一刻所有always块同时求值、同时更新寄存器互不等待。这就是硬件并行。很多初学者会在这儿卡住。比如写LED闪烁第一反应是我写个循环让led每隔一段延时翻转一次。但在Verilog里for循环如果不加generate综合出来并不是你想的顺序延时而是硬件展开。真正做延时要靠计数器数时钟周期让硬件状态在时钟节拍下一拍一拍地推进。这个思维转变是FPGA入门的第一道门槛。为了方便理解我会把时钟想象成整个电路的心跳。CPU是一条腿走路代码执行到哪算哪FPGA是全员齐步走每个人每个寄存器都踩在同一个节拍上换状态。谁掉拍谁的数据就乱了。2.2 时钟与计数器50MHz下数够50000000个沿才闪一下开发板上一般有源晶振提供系统时钟Ti60F225开发板常用的有50MHz和100MHz。我下面以50MHz为例一个周期20ns。做LED闪烁的本质是数周期计数到设定的值翻转一次LED。50MHz下1秒有50000000个时钟周期这个数字用二进制表示需要多少位2的25次方是33554432不够2的26次方是67108864够了。所以计数器位宽取26位计数范围0到49999999数满清零并让LED翻转一次。如果你想要0.5秒翻转一次那计数器上限改成24999999就行想要2秒就改成99999999。这个对应关系在后面做其他定时逻辑时天天用。计数器本身就是一个时序逻辑寄存器每个时钟上升沿做一次加一操作。代码写起来很直接但它背后的意义是你给硬件定义了一个时间基准一切延时、分频、时序握手都是在这个基准上叠加出来的。2.3 极简版本先让LED常亮在引入计数器之前先写一个最简单、最不容易出错的版本——让LED常亮module led_on ( output wire led ); assign led 1b1; // 高有效点亮低有效板子改成1b0 endmodule这种写法本质上是把FPGA引脚直接接到了一个固定电平上完全没用到逻辑资源。它最大的意义是快速验证工程流程通不通、引脚约束对不对如果这个版本下载后LED亮了说明硬件链路和工具链都没问题后面所有麻烦都不是出在基础环节。如果这个版本都不亮那大概率是引脚约束、IO电平或者JTAG下载的问题和你的代码逻辑没关系。确认常亮没问题之后我们再用计数器做出真正的闪烁效果。3. 新建工程实操RTL、仿真与约束3.1 建工程时的器件选择与目录规划打开Efinity IDE选择New Project。工程名建议用小写加下划线比如led_blinky_test避免大小写混用带来的脚本路径问题。工作目录同样别放在有中文或空格的路径下。器件选择是新手最容易出错的一步。如果你是Ti60F225板子在器件列表里找到Titanium系列下对应型号封装选F225。选错封装或者选成Trion系列布局布线阶段会报一堆物理位置错误。如果不确定板子上具体是哪颗芯片看板子丝印或包装盒上的标签然后用Efinity自动识别功能读器件ID确认。工程建好后IDE会生成基本的目录结构。接下来在Design Sources里新建一个Verilog文件在后缀名为.sdc的约束文件如果模板有里准备写约束。如果模板没有约束文件自己新建一个即可。3.2 LED闪烁模块完整RTL代码逐行拆解直接上完整代码timescale 1ns/1ps module led_blinky #( parameter COUNTER_MAX 26d49_999_999 )( input wire clk, input wire rst_n, output reg led ); reg [25:0] cnt; always (posedge clk or negedge rst_n) begin if (!rst_n) cnt 26d0; else if (cnt COUNTER_MAX) cnt 26d0; else cnt cnt 1b1; end always (posedge clk or negedge rst_n) begin if (!rst_n) led 1b0; else if (cnt COUNTER_MAX) led ~led; end endmodule拆开讲几个关键点COUNTER_MAX是Verilog参数默认值对应50MHz时钟下1秒。把这个参数化是为了仿真时能用更小的值快速看到现象后面详细说。rst_n是低有效复位信号这里用了异步复位保证一上电系统能进入确定状态。第一个always块是纯计数器每个时钟沿加一数到上限回零并清空。第二个always块只在cnt COUNTER_MAX那个时钟沿翻转LED。也就是说LED每1秒翻转一次亮1秒灭1秒这就是我们想要的1Hz闪烁。这里有个初学者容易误解的点led ~led不像C语言那样执行一句赋值它描述的是每个特定时钟沿把led寄存器的值取反这个硬件行为。你仔细想想这就是一个T触发器加分频器的组合。写代码时要有这种我在画电路的意识而不是我在写循环。3.3 testbench仿真把1秒钟压缩成12个时钟周期LED闪烁在真实板子上要等1秒才动一次慢得让人没耐心。如果直接上板验证万一逻辑错了你得盯着一块不动的板子发怵很久。所以先做仿真把时间尺度压缩。方法很简单例化模块时把COUNTER_MAX参数改小。比如改成26d910个周期翻转一次50MHz下只要200ns就能看到一个完整的闪烁周期。测试台代码timescale 1ns/1ps module led_blinky_tb; reg clk; reg rst_n; wire led; led_blinky #( .COUNTER_MAX(26d9) ) u_dut ( .clk (clk), .rst_n (rst_n), .led (led) ); initial begin clk 1b0; forever #10 clk ~clk; // 50MHz - 周期20ns半周期10ns end initial begin rst_n 1b0; #50; rst_n 1b1; #2000; $finish; end endmodule把这两个文件加到Efinity的仿真流程里或者你惯用的ModelSim/Verilog仿真器跑完看波形cnt从0数到9然后回零led在cnt等于9的那个时钟沿翻转。确认逻辑符合预期后再恢复COUNTER_MAX为50000000上板下载。这一步花10分钟能帮你省掉好几轮上板调试。这是所有FPGA开发里性价比最高的一笔时间投资。3.4 引脚约束与时钟约束SDC文件格式约束文件是工程里另一个重点。Efinity的约束采用SDC风格后缀通常是.sdc。LED工程至少要有两部分内容时钟约束和引脚约束。# 时钟约束50MHz周期20ns create_clock -name clk -period 20.000 [get_ports clk] # 引脚约束复位按键低有效 set_property PACKAGE_PIN M14 [get_ports rst_n] set_property IO_STANDARD LVCMOS33 [get_ports rst_n] # 引脚约束LED set_property PACKAGE_PIN L14 [get_ports led] set_property IO_STANDARD LVCMOS33 [get_ports led]注意这里M14和L14只是演示用的引脚号绝不能直接抄。每块开发板的原理图都不一样正确姿势是打开原理图搜索LED网络名和复位按键网络名看它们最终连接到FPGA芯片的哪个物理引脚。板载晶振对应的引脚也查一下确认系统时钟确实接在你要用的时钟输入引脚上。如果你不想手写SDCEfinity IDE里提供了Constraints Editor图形化界面下拉选择信号、直接选引脚和IO标准点击生成约束。图形界面不容易写错但只要是复杂工程我仍然建议直接编辑SDC——可追溯、可版本管理、可复用。还有一点IO_STANDARD的值必须和原理图上该BANK的VCCIO一致。查到BANK供电3.3V就用LVCMOS331.8V就用LVCMOS18。这个写错了轻则LED不亮重则IO电气特性异常长期看对器件健康也不利。4. 上板编译下载全流程与排查表4.1 综合、布局布线与生成比特流约束写好后在Efinity IDE里依次点Synthesis、Implementation、Generate Bitstream。每个阶段跑完都要扫一眼Log窗口尤其注意两类警告未约束IO警告说明你漏写了某个引脚的pin constraintEfinity可能随便帮你分配一个物理位置这基本等于信号悬空。见到这个警告回头补约束。时序违规警告LED这种慢速低速设计一般不会超时序如果真报了要么时钟约束写错了要么代码里有很长的组合逻辑链。等做到UART、图像时序这类设计时这里一定要认真对待。布局布线完成后可以打开Timing Analysis看FMAX。LED工程跑出两三百兆赫兹没什么压力这个过程其实就是感受Efinity Quantum架构性能的好机会。比特流生成后output目录下会产出编程文件。Efinity生成的配置文件通常是hex格式下载时选中这个文件即可。4.2 Efinity Programmer下载操作要点打开Efinity Programmer用USB线连接板子JTAG口。Efinity开发板一般用FTDI芯片桥接JTAG电脑设备管理器里能看到USB Serial Converter才算驱动正常。Programmer里确认识别到一颗Ti60F225器件选中刚才生成的hex文件点Program。下载成功后板载LED应该开始按1秒间隔闪烁。拔掉JTAG线再重新上电LED还是继续闪——因为配置已经写进FPGA了。如果用的是SRAM型配置掉电后配置会丢需要重新下载这在开发调试阶段完全正常。这里提一句如果只是想快速验证直接下载到FPGA就行如果需要脱机运行得考虑把配置固化到SPI Flash里那就是另一套流程了。第一章先把前者走通固化后面单独开一篇。4.3 LED不亮排查表对照现象找原因我把调试过程中见过的LED不亮问题归类成一张表遇到问题直接对照现象大概率原因处理方式下载后LED完全不变引脚约束写错或漏写查原理图核对引脚号补全所有IO的pin constraint下载后LED常亮但不闪高低有效理解反了检查原理图接法把led初始值或翻转逻辑倒过来闪烁频率明显不对晶振频率判断错误核对板载时钟标称值重新算COUNTER_MAX复位不起作用rst_n引脚没绑对把复位引脚加进SDC确认为低有效Programmer识别不到器件USB驱动没装好检查FTDI串口设备重装驱动综合报错IO_STANDARD非法IO电平和BANK电压不匹配查BANK供电改成对应的LVCMOS电平这张表解决我至少八成的现场支持问题。如果你遇到的问题不在表里下一步建议是把代码简化到常亮版本先排除工具链和硬件链路问题再逐步加逻辑。5. 折腾几轮之后我建议你注意的细节5.1 参数化设计仿真和上板用同一份代码很多教程会把仿真代码和上板代码分开写仿真文件里用小的计数上限上板文件里改成50000000这其实是个坏习惯。改来改去容易引入人为错误比如改漏一处、改错一个位数。正确做法是像第3节那样把计数上限作为模块参数仿真时例化一个小参数上板时用默认大参数。同一个RTL文件靠参数区分行为既不会改乱也让测试台代码保持干净。这套思路在后面设计FIFO、波特率发生器、PLL参数时都会用到可以说是一本万利的好习惯。我自己的习惯是工程里放两个测试台文件一个叫tb_led_onchip一个叫tb_led_fast一个用真实参数做长时间验证一个用短参数快速看波形。分工明确也方便后人接手。5.2 适应SDC约束风格别硬套XDC习惯从Vivado转过来的读者要留意一点Vivado的XDC和Efinity的SDC虽然都是约束文件但语法和关键字不完全一样。别把XDC命令直接粘进Efinity报一堆错再一头雾水。核心逻辑是相通的create_clock定义时钟set_property定义引脚位置和IO标准。你只要想清楚这个信号放在哪个物理引脚、以什么电平标准驱动剩下的就是查一下对应工具的语法。Efinity的官方文档里有一份SDC约束参考第一次写的时候对着查一遍后面就顺手了。另外Efinity的约束文件管理比Vivado轻便你可以一个工程里放多个SDC按模块拆分约束文件。比如时钟约束单独一个文件引脚约束另一个文件这样多人协作查错时定位更快。5.3 从点灯开始的进阶路线按键、UART、SPI、图像点亮LED只是第一步真正让FPGA发挥价值的是下面的路线。我建议按这个顺序往上走按键消抖 按键控制LED开始接触组合逻辑与时序逻辑的混合设计理解亚稳态和同步化。UART收发这是和单片机协同工作最常用的协议。用FPGA实现一个UART_RX接收模块配合仿真抓波形状态机的概念就立起来了。SPI/I2C外设驱动驱动ADC、DAC、传感器芯片开始接触主从时序和寄存器配置。图像采集与显示MIPI/LVDS接口、FIFO缓冲、行场同步这套组合拳打下来你对Ti60F225这颗片上资源的使用理解会上一个台阶。每走一步都把仿真先行的习惯贯彻下去。比如网上常搜的fpga实现uart_rx接收仿真其实就是把第3节那套testbench思路移植到串口接收模块上。基础打牢了后面这些题目对你来说都只是工作量问题不再是知识盲区。这个系列就按这条路线往后写下一章预计是按键控制和UART初步。如果你在搭建环境或者点灯过程中遇到这篇文章没覆盖的问题推荐顺着排查表的思路先自查一遍大概率能解决八成问题剩下的两成动手改、动手试往往比翻文档更有效。