FPGA线上课程平台|最全栈的FPGA学习平台|FPGA工程师认证培训
登录
首页-技术文章/快讯-技术分享-正文

FPGA学习经验:从Verilog入门到独立完成项目的路径

FPGA小白FPGA小白
技术分享
3天前
0
0
10

Quick Start:最短路径跑通第一个FPGA工程

  • 步骤一:安装Vivado/Vitis(推荐2024.2或更新版本,支持Artix-7及以上系列)。
  • 步骤二:创建RTL工程,选择目标器件(如xc7a35tcsg324-1)。
  • 步骤三:编写一个8位计数器(Verilog代码见下方),分配时钟引脚(如E3为50MHz)。
  • 步骤四:添加约束文件(.xdc),定义时钟周期20ns,并约束输出引脚(如LED对应J15)。
  • 步骤五:综合(Synthesis)→ 实现(Implementation)→ 生成比特流(Generate Bitstream)。
  • 步骤六:下载到开发板,观察LED以约0.5Hz闪烁。预期现象:板载LED每1秒亮灭一次。
module counter_led (
    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 <= 26'd0;
        else
            cnt <= cnt + 1'b1;
    end
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n)
            led <= 1'b0;
        else if (cnt == 26'd24999999)
            led <= ~led;
        else
            led <= led;
    end
endmodule

逐行说明

  • 第1行:模块声明,定义时钟clk、复位rst_n(低有效)和输出led。
  • 第2行:定义26位计数器cnt,用于分频50MHz时钟。
  • 第3行:时序逻辑块,敏感列表为clk上升沿和rst_n下降沿(异步复位)。
  • 第4行:复位时cnt清零。
  • 第5行:每个时钟周期cnt加1,实现计数。
  • 第6行:第二个always块,同样时序逻辑,控制led翻转。
  • 第7行:复位时led置0。
  • 第8行:当cnt计数值达到24999999(即50MHz/2-1,约0.5秒周期的一半),翻转led。
  • 第9行:否则保持led状态。

前置条件与环境

项目/推荐值说明替代方案
器件/板卡Xilinx Artix-7(如Nexys A7-50T)Intel Cyclone IV / Lattice iCE40
EDA版本Vivado 2024.2(免费WebPack版)Quartus Prime Lite 23.1
仿真器Vivado Simulator (xsim)ModelSim / Verilator
时钟/复位板载50MHz晶振,全局复位按钮PLL生成时钟,外部复位芯片
接口依赖USB-JTAG下载线(如Digilent HS2)OpenOCD + FT2232H
约束文件XDC格式,定义时钟周期20nsSDC(Synopsys Design Constraints)
操作系统Windows 10/11 或 Ubuntu 22.04 LTSmacOS(需虚拟机)

目标与验收标准

完成本路径后,你应能独立完成以下任务:

  • 功能点:从零编写Verilog模块,实现组合逻辑与时序逻辑(如计数器、状态机、UART收发)。
  • 性能指标:综合后Fmax ≥ 100MHz(示例配置下),资源占用 ≤ 器件逻辑单元30%。
  • 验证通过:仿真波形与预期一致,上板后LED/UART输出正确。
  • 验收方式:运行仿真脚本(do文件)自动比对结果,或使用逻辑分析仪抓取信号。

实施步骤

第一阶段:工程结构与代码规范

  • 创建顶层模块(top.v),例化子模块(如uart_tx.v, counter.v)。
  • 使用参数化设计(parameter)提高复用性,例如定义波特率参数。
  • 遵循命名规范:信号名小写、下划线分隔;模块名首字母大写。
  • 常见坑:避免在always块中混合阻塞赋值(=)和非阻塞赋值(<=),可能导致仿真与综合行为不一致。

第二阶段:关键模块实现——UART发送器

module uart_tx #(
    parameter CLK_FREQ = 50000000,
    parameter BAUD_RATE = 115200
)(
    input  wire       clk,
    input  wire       rst_n,
    input  wire [7:0] data_in,
    input  wire       send_en,
    output reg        tx,
    output reg        busy
);
    localparam BIT_TICKS = CLK_FREQ / BAUD_RATE;
    reg [15:0] baud_cnt;
    reg [3:0]  bit_idx;
    reg        sending;
    wire       tick;
    assign tick = (baud_cnt == BIT_TICKS - 1);
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            baud_cnt &lt;= 16'd0;
            bit_idx  &lt;= 4'd0;
            sending  &lt;= 1'b0;
            tx       &lt;= 1'b1;
            busy     &lt;= 1'b0;
        end else begin
            if (!sending &amp;&amp; send_en) begin
                sending &lt;= 1'b1;
                bit_idx &lt;= 4'd0;
                baud_cnt &lt;= 16'd0;
                busy    &lt;= 1'b1;
            end else if (sending) begin
                if (tick) begin
                    if (bit_idx == 4'd0)
                        tx &lt;= 1'b0; // start bit
                    else if (bit_idx &lt;= 4'd8)
                        tx &lt;= data_in[bit_idx - 1];
                    else if (bit_idx == 4'd9)
                        tx &lt;= 1'b1; // stop bit
                    if (bit_idx == 4'd9) begin
                        sending &lt;= 1'b0;
                        busy    &lt;= 1'b0;
                    end
                    bit_idx &lt;= bit_idx + 1'b1;
                    baud_cnt &lt;= 16'd0;
                end else begin
                    baud_cnt &lt;= baud_cnt + 1'b1;
                end
            end
        end
    end
endmodule

逐行说明

  • 第1行:模块声明,参数化时钟频率和波特率。
  • 第2-3行:输入输出端口定义,包括数据输入、发送使能、串行输出和忙标志。
  • 第4行:计算每个bit所需的时钟周期数(BIT_TICKS)。
  • 第5行:定义波特率计数器baud_cnt、位索引bit_idx、发送状态sending。
  • 第6行:tick信号,当baud_cnt达到BIT_TICKS-1时产生脉冲。
  • 第7行:时序逻辑块,处理复位和发送状态机。
  • 第8-14行:复位初始化所有寄存器。
  • 第15行:检测发送使能且当前空闲,进入发送状态。
  • 第16-19行:设置发送标志、位索引、计数器清零,busy置高。
  • 第20行:发送状态下,每个tick处理一个bit。
  • 第21行:bit_idx=0时输出start bit(低电平)。
  • 第22行:bit_idx=1~8时输出数据位(LSB first)。
  • 第23行:bit_idx=9时输出stop bit(高电平)。
  • 第24-26行:发送完stop bit后清除sending和busy。
  • 第27行:递增bit_idx。
  • 第28-30行:未到tick时继续计数。

第三阶段:时序约束与CDC处理

  • 创建约束文件top.xdc,定义所有时钟周期:create_clock -period 20.000 [get_ports clk]
  • 对于跨时钟域信号(如异步复位),使用两级同步器:reg sync1, sync2; always @(posedge clk) {sync2, sync1} <= {sync1, async_sig};
  • 常见坑:忽略异步复位释放时的亚稳态,必须使用同步释放电路。

第四阶段:仿真验证

// testbench for uart_tx
module tb_uart_tx;
    reg clk = 0;
    reg rst_n = 0;
    reg [7:0] data_in;
    reg send_en;
    wire tx, busy;
    uart_tx #(.CLK_FREQ(50000000), .BAUD_RATE(115200)) uut (.*);
    always #10 clk = ~clk; // 50MHz
    initial begin
        #100 rst_n = 1;
        #200 data_in = 8'h55; send_en = 1;
        #20 send_en = 0;
        #100000 $finish;
    end
endmodule

逐行说明

  • 第1行:testbench模块声明,无端口。
  • 第2-3行:生成时钟和复位信号。
  • 第4行:例化UUT(Unit Under Test),使用.*自动连接同名信号。
  • 第5行:生成50MHz时钟,周期20ns。
  • 第6行:initial块,复位释放、发送数据0x55(二进制01010101,LSB first)。
  • 第7行:等待100us后结束仿真。

常见坑与排查

  • 仿真波形中tx无变化:检查send_en脉冲宽度是否足够(至少一个时钟周期)。
  • 综合后时序违例:检查约束文件是否正确,时钟周期是否匹配实际晶振。
  • 上板后LED不亮:确认引脚约束正确,下载比特流后按复位键。

原理与设计说明

为什么选择UART作为入门项目?UART是典型的串行通信协议,涉及状态机设计、波特率生成、位同步等核心概念。其设计trade-off包括:

  • 资源 vs Fmax:使用计数器分频(资源少) vs 使用PLL(Fmax更高但占用PLL资源)。
  • 吞吐 vs 延迟:UART本身是低速协议(典型115200bps),适合学习而非高速应用。
  • 易用性 vs 可移植性:参数化设计(CLK_FREQ, BAUD_RATE)提高可移植性,但需注意参数范围。

关键机制:波特率生成器通过计数器产生tick信号,每个tick对应一个bit时间。状态机在空闲、发送数据位、发送停止位之间切换。这种设计模式(计数器+状态机)适用于SPI、I2C等协议。

验证与结果

指标测量值(示例)条件
Fmax150 MHzArtix-7, 速度等级-1, 综合策略默认
逻辑单元45 LUTs + 32 FFsUART发送器仅计核心逻辑
延迟10个时钟周期(从send_en到tx输出)仿真测量,含状态机启动时间
吞吐115200 bps波特率参数设定

测量条件:Vivado 2024.2,综合后时序分析报告,仿真波形手动测量。实际结果以具体工程和数据手册为准。

故障排查(Troubleshooting)

  • 现象:综合报错“Unresolved reference”。原因:模块例化时信号名拼写错误。检查:对比模块端口与例化语句。修复:修正拼写。
  • 现象:仿真波形中信号为X。原因:未初始化寄存器或复位未释放。检查:复位信号是否在仿真开始后变为高电平。修复:在testbench中释放复位。
  • 现象:上板后LED常亮。原因:计数器溢出频率过高,人眼无法分辨。检查:计算分频系数,确保LED翻转周期大于100ms。修复:增大分频系数。
  • 现象:UART接收数据乱码。原因:波特率不匹配或时钟频率误差过大。检查:用示波器测量tx波形,计算bit宽度。修复:调整BAUD_RATE参数或使用PLL精确时钟。
  • 现象:实现阶段时序违例。原因:组合逻辑路径过长或未添加约束。检查:查看时序报告中的slack值。修复:添加流水线寄存器或优化逻辑。
  • 现象:下载比特流失败。原因:JTAG驱动未安装或板卡未上电。检查:设备管理器是否识别下载器。修复:安装驱动或更换USB线。
  • 现象:仿真运行缓慢。原因:testbench中时间尺度设置过大。检查:`timescale 1ns/1ps 是否合理。修复:减小仿真时间或使用更高效仿真器。
  • 现象:综合后资源占用异常高。原因:无意中综合了调试逻辑(如ILA)。检查:综合设置中是否包含debug core。修复:移除未使用的debug core。

扩展与下一步

  • 扩展方向一:将UART发送器扩展为全双工收发器,加入接收状态机和FIFO缓冲。
  • 扩展方向二:使用AXI4-Stream接口封装UART模块,便于与Zynq PS系统集成。
  • 扩展方向三:在仿真中加入断言(assertion)和覆盖(coverage),提高验证完备性。
  • 扩展方向四:将设计移植到Lattice iCE40平台,使用开源工具链(Yosys+nextpnr)进行综合。
  • 扩展方向五:学习使用Verilator进行C++级仿真加速,适用于大型设计。

参考与信息来源

  • Xilinx UG901: Vivado Design Suite User Guide (Synthesis)
  • Xilinx UG903: Vivado Design Suite User Guide (Implementation)
  • IEEE Std 1364-2001: Verilog Hardware Description Language
  • Clifford E. Cummings: “Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!”

技术附录

术语表

  • RTL: Register Transfer Level,寄存器传输级描述。
  • CDC: Clock Domain Crossing,跨时钟域同步。
  • Fmax: 最大工作频率,由时序分析报告给出。
  • LUT: Look-Up Table,查找表,FPGA基本逻辑单元。

检查清单

  • 代码规范:无警告、无latch推断、无混合赋值风格。
  • 约束完整:所有时钟已定义、所有输入输出引脚已约束。
  • 仿真通过:波形与预期一致,无X/Z状态。
  • 上板验证:下载比特流后按复位键,观察LED或UART输出。

关键约束速查

# 时钟约束
create_clock -period 20.000 [get_ports clk]
# 输入延迟约束(示例)
set_input_delay -clock clk -max 5 [get_ports data_in]
# 输出延迟约束(示例)
set_output_delay -clock clk -max 5 [get_ports tx]
标签:
本文原创,作者:FPGA小白,其版权均为FPGA线上课程平台|最全栈的FPGA学习平台|FPGA工程师认证培训所有。
如需转载,请注明出处:https://z.shaonianxue.cn/42584.html
FPGA小白

FPGA小白

初级工程师
成电国芯®的讲师哦,专业FPGA已有10年。
43921.93W7.30W34.40W
分享:
成电国芯FPGA赛事课即将上线
2026年5月FPGA行业深度观察:国产芯片、AI边缘计算与RISC-V生态的交叉演进
2026年5月FPGA行业深度观察:国产芯片、AI边缘计算与RISC-V生态的交叉演进上一篇
2026年FPGA行业趋势深度解析:UCIe 2.0、AI数据中心、国产替代与就业技能变革下一篇
2026年FPGA行业趋势深度解析:UCIe 2.0、AI数据中心、国产替代与就业技能变革
相关文章
总数:1.13K
数据中心FPGA加速卡CXL 3.0内存池化实施指南:从工程搭建到性能验证

数据中心FPGA加速卡CXL 3.0内存池化实施指南:从工程搭建到性能验证

QuickStart准备支持CXL3.0的FPGA开发板(如Xili…
技术分享
2天前
0
0
14
0
利用广告点阵屏实现“CQUPT”

利用广告点阵屏实现“CQUPT”

直接上效果,代码在文最后。CQUPT下载
技术分享
11个月前
0
0
397
0
工业控制系统技术选型指南:FPGA、嵌入式与PLC的权衡与实践

工业控制系统技术选型指南:FPGA、嵌入式与PLC的权衡与实践

在工业控制领域,技术选型正从单一的性能指标评估,转向对确定性、灵活性、全…
技术分享
23天前
0
0
35
0
评论表单游客 您好,欢迎参与讨论。
加载中…
评论列表
总数:0
FPGA线上课程平台|最全栈的FPGA学习平台|FPGA工程师认证培训
没有相关内容