4. 第一个工程:点亮LED

好了,到了真正动手的时候了。

前面几章我们聊了开发板、聊了工具链,都是热身。这一章,咱们要真刀真枪地干一把——写一段Verilog代码,让板子上的LED听我们的话。说白了,就是按键按下去,灯亮;松手,灯灭。听起来简单?嗯,但这是FPGA开发的“Hello World”,背后藏着综合、布局布线、生成Bitstream、下载这一整套流程。

4.1 硬件连接:先搞清楚谁跟谁连

动手写代码前,我习惯先看一眼原理图。你想想看,FPGA的引脚那么多,你得知道按键接到了哪个管脚,LED又接到了哪个管脚。

以我手头这块ECP5开发板为例:

  • 按键:接在 P4 引脚,按下为低电平(0),松开为高电平(1)。
  • LED:接在 N5 引脚,输出高电平(1)时点亮,低电平(0)时熄灭。
注意:不同开发板的引脚定义可能不同。我在项目中就吃过这个亏——拿着别人的代码直接烧,结果灯死活不亮。后来一查,原来是引脚号对不上。所以,一定要先看自己的原理图

4.2 编写Verilog代码:从想法到描述

硬件描述语言和C语言不一样。C语言是“告诉计算机怎么做”,Verilog是“描述硬件长什么样”。

我们这个功能,说白了就是一个反相器:按键按下(低电平),LED亮(高电平);按键松开(高电平),LED灭(低电平)。

代码很简单,但每一步都有讲究。来看:

module led_control (
    input  wire key,   // 按键输入
    output wire led    // LED输出
);

    // 按键按下为低电平,LED高电平点亮
    // 所以直接把按键信号取反,送给LED
    assign led = ~key;

endmodule

嗯,就这么几行。但我要多说两句:

  • input wire key:声明一个输入端口,类型是wire(线网)。按键信号进来,就是一根线。
  • output wire led:声明一个输出端口,也是wire类型。
  • assign led = ~key;:连续赋值语句。意思就是“LED这个输出,永远等于按键输入取反”。

你可能会问:为什么不用 reg 类型?因为这里没有时序逻辑,纯组合逻辑,用 wire 就够了。我个人习惯是:能不用reg就不用reg,代码更清晰,综合出来的资源也更少。

4.3 综合:把代码变成网表

代码写完了,下一步是综合。综合是什么?就是把你的Verilog描述,翻译成FPGA内部的基本逻辑单元——查找表(LUT)、触发器(FF)、布线资源等等。

在Lattice Diamond软件里,操作很简单:

  1. 点击 Synthesize Design 按钮。
  2. 等几秒钟,看控制台输出。
  3. 如果没有错误,会显示 “Synthesis completed successfully”
小技巧:综合完成后,可以打开 Map Report 看看用了多少资源。我们这个工程,应该只用了1个LUT,非常小。如果你看到用了好几百个LUT,那就要检查一下代码是不是写复杂了。

4.4 布局布线:把网表放到芯片上

综合完,我们有了网表。但网表是抽象的,它不知道每个逻辑单元该放在芯片的哪个位置。布局布线就是干这个的——把逻辑单元分配到具体的逻辑块(PLC),然后连起来。

这一步,软件会自动完成。你只需要点击 Place & Route 按钮。

我记得第一次做布局布线时,等了很久,心里直打鼓:“是不是死机了?”其实不是,布局布线确实需要一些时间,尤其是复杂设计。但像我们这种小工程,几秒钟就搞定了。

完成后,可以看 PAR Report,里面会告诉你:

  • 用了多少个Slice
  • 最大路径延迟是多少
  • 有没有时序违规

对于这个简单设计,时序肯定没问题。但如果是复杂设计,布局布线后一定要检查时序报告,不然烧进去可能跑不起来。

4.5 生成Bitstream:最后的打包

布局布线完成后,我们得到的是一个物理映射文件。但这个文件还不能直接下载到FPGA。我们需要把它转换成FPGA能识别的比特流文件——也就是 Bitstream(.bit 或 .jed 文件)。

点击 Generate Bitstream,软件会做最后一步处理:

  • 把配置信息打包
  • 添加校验位
  • 生成最终下载文件
重要:Bitstream 是FPGA的“灵魂”。没有它,FPGA就是一块白板,什么功能都没有。每次上电,FPGA都需要重新加载Bitstream。

4.6 下载到开发板:见证奇迹的时刻

终于到了最后一步。把开发板用USB线连到电脑,打开Diamond的 Programmer 工具:

  1. 点击 Detect Cable,软件会自动识别下载器。
  2. 选择刚才生成的Bitstream文件。
  3. 点击 Program 按钮。

下载过程中,开发板上的指示灯会闪烁。几秒钟后,提示 “Programming successful”

这时候,你按下板子上的按键——LED亮了!松开——LED灭了!

嗯,我第一次成功的时候,虽然知道原理,但还是有点小激动。毕竟,这是自己写的代码,真正在硬件上跑起来了。

4.7 避坑指南:我踩过的几个坑

做这个实验,有几个地方容易出问题。我一个个说:

  • 引脚约束没加:代码里写了 keyled,但没告诉软件它们对应哪个物理引脚。结果综合、布局布线都过了,下载后灯就是不亮。解决办法:在Diamond里添加 Pin Constraint,把 key 映射到 P4led 映射到 N5
  • 下载线没插好:有一次我折腾了半天,Programmer一直报错“No cable detected”。后来发现是USB线松了。嗯,这种低级错误,谁都会犯。
  • 按键抖动:我们这个设计没做消抖,所以按键按下或松开时,LED可能会闪烁一下。对于这个简单实验,不影响。但如果是做计数器、状态机,一定要加消抖,不然会误触发。

4.8 核心逻辑流程图

下面这张图,把整个流程串起来了。你可以对照着看,每一步都做了什么:

FPGA开发流程:从代码到LED点亮 1. 编写Verilog代码 led_control.v 2. 综合 生成网表 3. 布局布线 Place & Route 4. 生成Bitstream .bit / .jed文件 5. 下载到开发板 Programmer工具 6. 验证功能 按键控制LED亮灭 7. 调试优化 检查引脚/时序 发现问题,返回修改

4.9 小结

这一章,我们走完了FPGA开发的完整流程:

  • 写了Verilog代码,用 assign 实现了按键控制LED
  • 做了综合,把代码转成了网表
  • 做了布局布线,把网表放到了芯片上
  • 生成了Bitstream,打包成下载文件
  • 下载到开发板,看到了LED亮灭

整个过程,看起来步骤不少,但熟练之后,几分钟就能走一遍。这个流程,是所有FPGA项目的基础。后面更复杂的设计,比如PWM、串口通信、图像处理,都是在这个流程上叠加的。

嗯,第一个工程跑通了,恭喜你。接下来,可以试试改改代码——比如让LED闪烁,或者用两个按键控制不同的灯。动手试试,比光看文章强得多。


专注资料整理