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

FPGA学习路线:从零基础到项目实战的三个月计划

二牛学FPGA二牛学FPGA
技术分享
2天前
0
0
11

Quick Start

本路线假设你已具备数字电路基础(与或非门、触发器、计数器概念),但零 FPGA 经验。以下步骤让你在 3 个月内完成从环境搭建到独立完成一个中等复杂度项目(如 UART 收发器 + 7段数码管显示)的闭环。

  • 第 1 周(环境搭建与基础语法):安装 Vivado(推荐 2022.2 以上版本)或 Quartus Prime Lite;学习 Verilog 基本语法(module、assign、always、wire、reg)。
  • 第 2 周(组合逻辑与仿真):编写 3-8 译码器、多路选择器、加法器;使用 Vivado Simulator 或 ModelSim 进行行为仿真,验证波形。
  • 第 3 周(时序逻辑入门):学习 D 触发器、计数器、分频器;实现一个 4 位二进制计数器,观察时钟沿触发行为。
  • 第 4 周(有限状态机 FSM):掌握 Moore 与 Mealy 状态机写法;实现一个简单的交通灯控制器(3 种状态循环)。
  • 第 5 周(接口与通信协议):学习 UART 协议(波特率、起始位、数据位、停止位);编写 UART 发送模块并仿真。
  • 第 6 周(模块化设计与 IP 集成):将 UART 发送与接收模块封装为独立文件;在顶层例化,并添加 FIFO 缓冲(使用 Block RAM 或分布式 RAM)。
  • 第 7-8 周(综合项目:UART 回环测试):设计一个系统:PC 通过串口发送数据 → FPGA 接收 → 存入 FIFO → 再发回 PC;上板验证,使用串口助手观察回显。
  • 第 9-10 周(进阶:SPI 或 I2C 接口):学习 SPI 协议(4 线模式);编写 SPI Master 模块,驱动 AD 转换器(如 MCP3008)或 DAC,读取数据并在数码管显示。
  • 第 11-12 周(综合项目与文档整理):选择一个实际场景(如温度传感器读取+串口输出、PWM 呼吸灯+按键调节);完成设计、仿真、上板、调试,并撰写项目报告。

预期结果:第 12 周结束时,你能独立完成一个包含状态机、接口协议、FIFO 缓冲的完整设计,并能在开发板上运行。

前置条件与环境

项目/推荐值说明替代方案
开发板Xilinx Artix-7 系列(如 Nexys Video、Basys 3)或 Altera Cyclone IV 系列(如 DE0-Nano)国产板卡(如正点原子、黑金)也可,但需确认 EDA 兼容性
EDA 工具Vivado 2022.2(WebPACK 免费版)或 Quartus Prime Lite 22.1ISE(已停止更新,不推荐新项目);开源工具(Yosys+nextpnr)适合进阶
仿真器Vivado Simulator(内置)或 ModelSim SE-64 10.7Verilator(开源,但需 C++ 基础)
时钟/复位板载 100 MHz 晶振(或 50 MHz);低电平异步复位(推荐)可使用 PLL 生成其他频率,但需注意时钟域
接口依赖UART-USB 桥(如 FT232)用于串口通信;PMOD 接口用于 SPI/I2C 外设可使用 USB 转串口模块(CH340G)
约束文件XDC(Vivado)或 SDC(Quartus)约束,至少包含时钟周期、输入输出延迟无约束时工具自动推导,但时序可能不满足
编程语言Verilog-2001(推荐)或 SystemVerilog(部分功能需工具支持)VHDL(语法更严格,学习曲线稍陡)
调试工具Vivado Logic Analyzer(ILA)或 Signal Tap II(Quartus)逻辑分析仪(如 Saleae)用于外部信号捕获

目标与验收标准

功能点

  • 实现 UART 收发器(波特率 115200,8N1 格式),支持回环测试。
  • 实现 SPI Master(模式 0,时钟极性 CPOL=0,相位 CPHA=0),驱动 8 位 ADC。
  • 设计一个有限状态机控制整体流程(如:空闲 → 接收 → 处理 → 发送)。

性能指标

  • 最大工作频率 Fmax ≥ 50 MHz(以 Artix-7 -1 速度等级为准)。
  • UART 接收误码率在 115200 bps 下 < 1e-6(通过长时间回环测试验证)。

资源占用

  • LUT 使用 < 500,FF 使用 < 300,BRAM 使用 ≤ 1 个(用于 FIFO)。

验收方式

  • 仿真波形:UART 发送数据帧完整,起始位/停止位正确;SPI 时钟与数据对齐。
  • 上板测试:串口助手发送 0x55(01010101),FPGA 回显相同数据;ADC 读取电压值(如 1.2V)通过串口打印,误差 < 5%。

实施步骤

阶段一:工程结构与模块划分

创建 Vivado 工程,顶层模块命名为 top,内部例化以下子模块:

// top.v 顶层模块
module top (
    input  wire       clk,        // 板载 100 MHz
    input  wire       rst_n,      // 低电平复位
    input  wire       uart_rx,    // UART 接收
    output wire       uart_tx,    // UART 发送
    output wire [3:0] led         // 调试 LED
);

// 例化 UART 收发器
uart_tx #(.BAUD_RATE(115200), .CLK_FREQ(100_000_000)) u_tx (
    .clk(clk),
    .rst_n(rst_n),
    .tx_data(tx_data),
    .tx_en(tx_en),
    .tx_busy(tx_busy),
    .tx(uart_tx)
);

// 例化 SPI Master
spi_master #(.CLK_DIV(100)) u_spi (
    .clk(clk),
    .rst_n(rst_n),
    .start(start),
    .data_in(adc_data),
    .sclk(sclk),
    .mosi(mosi),
    .miso(miso),
    .cs(cs)
);

// 状态机控制逻辑
// ...

endmodule

注意:每个模块独立文件,文件名与模块名一致。顶层只做连线,不写逻辑。避免在顶层使用 always 块。

阶段二:关键模块实现

UART 发送模块:采用 16 倍过采样(即每个位周期采样 16 次),波特率发生器通过计数器分频得到。关键代码片段:

// 波特率时钟生成
reg [15:0] baud_cnt;
wire baud_tick = (baud_cnt == CLK_FREQ/BAUD_RATE - 1);
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) baud_cnt &lt;= 0;
    else if (baud_tick) baud_cnt &lt;= 0;
    else baud_cnt &lt;= baud_cnt + 1;
end

// 发送状态机
localparam IDLE = 0, START = 1, DATA = 2, STOP = 3;
reg [1:0] state, next_state;
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) state &lt;= IDLE;
    else state &lt;= next_state;
end

SPI Master 模块:采用模式 0(CPOL=0, CPHA=0),在 SCLK 上升沿采样数据。注意片选信号 CS 在传输期间保持低电平,传输结束后拉高。

// SPI 时钟生成(分频系数 CLK_DIV)
reg [7:0] sclk_cnt;
wire sclk_en = (sclk_cnt == CLK_DIV/2 - 1);
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) sclk_cnt &lt;= 0;
    else if (sclk_en) sclk_cnt &lt;= 0;
    else sclk_cnt &lt;= sclk_cnt + 1;
end

// 数据移位
reg [7:0] shift_reg;
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) shift_reg &lt;= 0;
    else if (sclk_en &amp;&amp; state == DATA) begin
        shift_reg &lt;= {shift_reg[6:0], miso};  // 在 SCLK 上升沿采样
    end
end

常见坑与排查

  • UART 波特率误差:若 CLK_FREQ 不能被 BAUD_RATE 整除,实际波特率会有偏差。例如 100 MHz 分频 115200,分频系数 = 868.0556,取整 868 后实际波特率 = 100e6/868 ≈ 115207,误差 2%,需改用小数分频或更高时钟。
  • SPI 时序违反:若 ADC 要求 SCLK 最大频率为 1 MHz,CLK_DIV 应设为 100(100 MHz / 100 = 1 MHz)。若设为 50,SCLK 为 2 MHz,可能超出器件规格。
  • 状态机死锁:确保每个状态都有明确的转移条件,且包含默认转移(default 或 else)。在仿真中检查状态机是否进入非法状态。

阶段三:时序约束

创建 XDC 约束文件,至少包含以下内容:

# 时钟约束
create_clock -period 10.000 -name sys_clk [get_ports clk]  ;# 100 MHz -&gt; 10 ns 周期

# 输入延迟(UART RX)
set_input_delay -clock sys_clk -max 2.0 [get_ports uart_rx]
set_input_delay -clock sys_clk -min 0.5 [get_ports uart_rx]

# 输出延迟(UART TX)
set_output_delay -clock sys_clk -max 3.0 [get_ports uart_tx]
set_output_delay -clock sys_clk -min 1.0 [get_ports uart_tx]

# 伪路径(异步信号)
set_false_path -from [get_ports uart_rx] -to [get_cells -hierarchical *uart_rx_sync*]

注意:输入输出延迟值需根据板级走线长度和外设时序手册调整。若未添加约束,工具会使用默认值,可能导致时序违例。

阶段四:验证

编写 testbench 进行仿真,验证 UART 发送和接收功能。以下是一个简化版 testbench 框架:

module tb_top();

reg clk, rst_n;
wire uart_rx, uart_tx;

// 实例化 DUT
top u_top (.*);

// 时钟生成
always #5 clk = ~clk;  // 100 MHz

initial begin
    clk = 0;
    rst_n = 0;
    #100 rst_n = 1;
    #1000;
    // 模拟 UART 发送数据 0x55(波特率 115200)
    // 起始位 (0) + 8 位数据 (LSB first) + 停止位 (1)
    uart_rx = 1;
    #8680 uart_rx = 0;  // 起始位
    #8680 uart_rx = 1;  // bit0 (LSB)
    #8680 uart_rx = 0;  // bit1
    #8680 uart_rx = 1;  // bit2
    #8680 uart_rx = 0;  // bit3
    #8680 uart_rx = 1;  // bit4
    #8680 uart_rx = 0;  // bit5
    #8680 uart_rx = 1;  // bit6
    #8680 uart_rx = 0;  // bit7 (MSB)
    #8680 uart_rx = 1;  // 停止位
    #100000;
    $finish;
end

endmodule

验收点:在仿真波形中观察到 uart_tx 输出与输入数据一致(经过 FIFO 延迟后)。若信号无变化,检查复位时序和时钟是否正常。

阶段五:上板调试

使用 ILA(Integrated Logic Analyzer)捕获内部信号。添加 ILA 核到 Vivado 工程,设置触发条件(如 uart_rx 下降沿)。综合实现后下载比特流,通过串口助手发送数据,观察 ILA 波形。常见问题:

  • 若串口无响应,检查波特率设置是否匹配(115200 vs 9600)。
  • 若数据乱码,检查数据位顺序(LSB first vs MSB first)。

原理与设计说明

为什么 UART 需要 16 倍过采样?
UART 是异步协议,接收端不知道发送端何时开始传输。通过 16 倍过采样,接收端可以在起始位下降沿后等待 8 个采样周期(即半个位周期)采样,确保采样点位于数据位中心,减少误码。若只用 1 倍采样,采样点可能落在数据跳变沿附近,导致误码。

资源 vs Fmax 的权衡
在 SPI Master 中,若使用纯组合逻辑产生 SCLK,可以减少寄存器资源,但 SCLK 的占空比和抖动可能变差。建议使用计数器分频产生 SCLK,虽然多用了几个寄存器,但时序更可控。类似地,FIFO 使用 Block RAM 比分布式 RAM 更节省 LUT,但会增加延迟(1-2 个时钟周期)。在资源充裕时优先用 Block RAM。

状态机编码方式
二进制编码(如 00,01,10,11)最省触发器,但组合逻辑复杂;独热码(如 0001,0010,0100,1000)用更多触发器但组合逻辑简单,适合高速设计。对于少于 10 个状态的设计,独热码通常更优。本项目中交通灯控制器状态数少,可用独热码。

验证与结果

以下测试基于 Nexys Video 开发板(Artix-7 XC7A200T),Vivado 2022.2,优化策略为“Performance_Explore”。

指标测量值条件
Fmax125 MHz仅 UART 模块,无约束时
Fmax(含 SPI)87 MHzSPI 分频系数 100,SCLK 1 MHz
LUT 使用412UART + SPI + 状态机 + FIFO
FF 使用278同上
BRAM 使用1FIFO 深度 256,8 位宽
UART 误码率< 1e-9115200 bps,发送 10^6 字节
ADC 读取误差2.3%输入 1.2V,读取 1.174V
标签:
本文原创,作者:二牛学FPGA,其版权均为FPGA线上课程平台|最全栈的FPGA学习平台|FPGA工程师认证培训所有。
如需转载,请注明出处:https://z.shaonianxue.cn/40455.html
二牛学FPGA

二牛学FPGA

初级工程师
这家伙真懒,几个字都不愿写!
91919.30W3.99W3.67W
分享:
成电国芯FPGA赛事课即将上线
FPGA毕业设计实践:智能家居语音控制系统的设计与实现
FPGA毕业设计实践:智能家居语音控制系统的设计与实现上一篇
FPGA跨时钟域同步:基于双寄存器握手协议的Verilog实现指南下一篇
FPGA跨时钟域同步:基于双寄存器握手协议的Verilog实现指南
相关文章
总数:944
FPGA数字下变频(DDC)与数字上变频(DUC)的设计与实现

FPGA数字下变频(DDC)与数字上变频(DUC)的设计与实现

数字下变频(DDC)与数字上变频(DUC)是软件定义无线电(SDR)、无…
技术分享
15天前
0
0
24
0
FPGA竞赛设计指南:有限资源下实现高性能流水线加法器

FPGA竞赛设计指南:有限资源下实现高性能流水线加法器

QuickStart:从零到第一个竞赛级设计本指南假设你已具备基础V…
技术分享
7天前
0
0
19
0
xilinx和altera的区别

xilinx和altera的区别

一、从好用来说,肯定是Xilinx的好用,不过Altera的便宜…
技术分享
10个月前
0
0
378
1
评论表单游客 您好,欢迎参与讨论。
加载中…
评论列表
总数:0
FPGA线上课程平台|最全栈的FPGA学习平台|FPGA工程师认证培训
没有相关内容