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

FPGA实习生必备技能清单:从零到Offer的实践指南

二牛学FPGA二牛学FPGA
技术分享
9小时前
0
0
3

Quick Start

  1. 注册GitHub账号,安装Git并配置SSH密钥,克隆一个开源FPGA项目(如PicoRV32或LiteX)。
  2. 安装Vivado或Quartus Prime Lite(免费版),下载对应厂商的器件库(如Xilinx Artix-7或Intel Cyclone V)。
  3. 在IDE中创建一个空工程,添加一个简单的LED闪烁模块(分频+计数器),综合并实现,生成比特流。
  4. 连接开发板(如Nexys A7或DE10-Lite),下载比特流,观察LED按预期频率闪烁。
  5. 编写一个简单的Testbench(使用Verilog或SystemVerilog),用ModelSim或Vivado Simulator仿真LED闪烁模块,验证时序。
  6. 阅读Xilinx或Intel官方文档《ug901 Vivado Synthesis》或《Quartus Prime Handbook》中关于时序约束的章节,为一个寄存器到寄存器的路径添加create_clock约束。
  7. 在GitHub上提交一个Pull Request,修复一个开源FPGA项目的文档或代码小bug(如注释错误或边界条件遗漏)。
  8. 整理一份个人技能清单(本文可作为模板),对照招聘网站(如Boss直聘、猎聘)上的FPGA实习生JD,标记已掌握和待学习项。

前置条件与环境

项目/推荐值说明替代方案
器件/板卡Xilinx Artix-7(如Nexys A7-100T)或Intel Cyclone V(如DE10-Lite)Lattice iCE40(开源工具链)、Gowin GW1N(国产低成本)
EDA版本Vivado 2024.2 / Quartus Prime Lite 24.1ISE 14.7(仅支持老器件)、Yosys+nextpnr(开源)
仿真器Vivado Simulator / ModelSim SE-64 2024.2Verilator(开源,仅支持Verilog/SystemVerilog)、Icarus Verilog
时钟/复位板载100MHz晶振(差分或单端),低电平异步复位PLL生成内部时钟,同步复位(需额外逻辑)
接口依赖UART(USB转串口)、GPIO(LED/按键)、PMOD(扩展)SPI Flash、HDMI输出(需IP核)
约束文件XDC(Vivado)或SDC(Quartus),包含主时钟约束、I/O标准、位置Tcl脚本自动生成,或手动编辑
操作系统Windows 10/11 64位 或 Ubuntu 22.04 LTSmacOS(通过Docker运行EDA)
版本控制Git + GitHub/GitLabSVN(少数公司仍用)

目标与验收标准

  • 功能点:独立完成一个中等复杂度数字系统(如UART收发器、SPI控制器、简易CPU)的RTL设计、仿真、综合与上板验证。
  • 性能指标:设计在目标器件上达到Fmax ≥ 100MHz(典型值,以实际时序报告为准),资源利用率不超过器件总量的70%。
  • 资源/Fmax:综合后LUT+FF占用 ≤ 器件总量的50%(示例),WNS ≥ 0(无时序违例)。
  • 关键波形/日志:仿真波形显示接口协议正确(如UART波特率误差 < 2%),上板后串口打印"Hello FPGA"。

实施步骤

工程结构

推荐使用标准目录结构,便于团队协作与版本管理:

project/
├── rtl/        # 所有RTL源文件(.v/.sv)
├── sim/        # Testbench与仿真脚本
├── constr/     # 约束文件(.xdc/.sdc)
├── ip/         # IP核(如PLL、BRAM)
├── scripts/    # Tcl自动化脚本
├── docs/       # 设计文档与笔记
└── output/     # 综合/实现产物(bit、rpt)

逐行说明

  • 第1行:项目根目录,名称与设计主题一致(如uart_tx)。
  • 第2行:rtl/存放所有可综合的Verilog/SystemVerilog源文件,按模块命名(如uart_tx.v)。
  • 第3行:sim/存放Testbench文件(如tb_uart_tx.v)和仿真脚本(如run.do)。
  • 第4行:constr/存放时序与物理约束,Vivado用.xdc,Quartus用.sdc。
  • 第5行:ip/放置厂商IP核(如Clocking Wizard),避免与RTL混放。
  • 第6行:scripts/存放自动化Tcl脚本,用于批量运行综合/实现/仿真。
  • 第7行:docs/存放设计文档、时序分析笔记、面试准备材料。
  • 第8行:output/存放综合报告(.rpt)、实现报告、比特流文件,便于回溯。

关键模块:UART发送器

以下是一个可综合的UART发送器RTL(8位数据,1位起始位,1位停止位,无校验):

module uart_tx #(
    parameter CLK_FREQ = 100_000_000, // 输入时钟频率 (Hz)
    parameter BAUD_RATE = 115200      // 目标波特率
) (
    input wire clk,
    input wire rst_n,
    input wire tx_start,
    input wire [7:0] tx_data,
    output reg tx_busy,
    output reg txd
);

localparam BIT_PERIOD = CLK_FREQ / BAUD_RATE; // 每比特时钟周期数
localparam CNT_W = $clog2(BIT_PERIOD);         // 计数器位宽

reg [CNT_W-1:0] baud_cnt;
reg [3:0] bit_cnt;
reg sending;

// 状态机与计数逻辑
// ... (完整代码见附录)

endmodule

逐行说明

  • 第1行:模块定义,使用parameter实现参数化设计,便于复用。
  • 第2行:CLK_FREQ参数,典型值100MHz,需与板载时钟一致。
  • 第3行:BAUD_RATE参数,标准值115200,也可设为9600或460800。
  • 第4-5行:输入端口,clk为系统时钟,rst_n为低电平异步复位。
  • 第6行:tx_start为发送启动信号,高电平有效,至少保持一个时钟周期。
  • 第7行:tx_data为待发送的8位并行数据。
  • 第8行:tx_busy输出,高电平表示正在发送,发送完成后自动拉低。
  • 第9行:txd输出,串行数据线,空闲时为高电平。
  • 第11行:localparam BIT_PERIOD,通过除法计算每比特所需时钟周期数,需确保除尽或误差在可接受范围(< 2%)。
  • 第12行:localparam CNT_W,使用$clog2函数自动计算计数器位宽,避免手动计算错误。
  • 第14-16行:内部寄存器定义,baud_cnt为波特率计数器,bit_cnt为已发送比特数计数器,sending为发送状态标志。
  • 第18-19行:状态机与计数逻辑的占位注释,完整实现需包含状态转移、波特率时钟生成、串行移位输出等逻辑。
  • 第21行:endmodule结束模块定义。

验证结果

完成上述步骤后,应验证以下内容:

  • 仿真波形中txd信号按UART协议输出起始位、8位数据(LSB first)、停止位,波特率误差 < 2%。
  • 综合后时序报告显示WNS ≥ 0,无建立时间违例。
  • 上板后通过串口助手(如Putty)接收数据,与发送数据一致。

排障

  • 问题:仿真波形无输出或数据错误——检查复位时序是否正确(rst_n低电平有效),tx_start脉冲宽度是否足够。
  • 问题:综合时报错"cannot evaluate non-constant parameter"——确认BIT_PERIOD和CNT_W在编译时可计算,避免使用运行期变量。
  • 问题:上板后串口无输出——检查约束文件中I/O标准(如LVCMOS33)和引脚分配是否正确,开发板跳线是否设置正确。

扩展

  • 为UART发送器添加FIFO缓冲,支持连续发送多字节。
  • 实现UART接收器,并与发送器组成回环测试。
  • 使用PLL生成不同时钟域,练习跨时钟域同步(CDC)处理。
  • 参考开源项目(如ZipCPU、Serv)实现一个简单RISC-V CPU。

参考

  • Xilinx UG901: Vivado Design Suite User Guide - Synthesis
  • Intel Quartus Prime Handbook, Volume 1: Design and Synthesis
  • PicoRV32: A Size-Optimized RISC-V CPU (GitHub)
  • LiteX: A Migen-based SoC builder (GitHub)

附录

完整UART发送器RTL代码(含状态机与计数逻辑)可参考以下实现:

module uart_tx #(
    parameter CLK_FREQ = 100_000_000,
    parameter BAUD_RATE = 115200
) (
    input wire clk,
    input wire rst_n,
    input wire tx_start,
    input wire [7:0] tx_data,
    output reg tx_busy,
    output reg txd
);

localparam BIT_PERIOD = CLK_FREQ / BAUD_RATE;
localparam CNT_W = $clog2(BIT_PERIOD);

reg [CNT_W-1:0] baud_cnt;
reg [3:0] bit_cnt;
reg sending;
reg [7:0] data_reg;

// 波特率时钟生成与状态机
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        baud_cnt &lt;= 0;
        bit_cnt &lt;= 0;
        sending &lt;= 0;
        txd &lt;= 1'b1;
        tx_busy &lt;= 1'b0;
        data_reg &lt;= 0;
    end else begin
        if (!sending &amp;&amp; tx_start) begin
            // 启动发送
            sending &lt;= 1'b1;
            tx_busy &lt;= 1'b1;
            data_reg &lt;= tx_data;
            baud_cnt &lt;= 0;
            bit_cnt &lt;= 0;
            txd &lt;= 1'b0; // 起始位
        end else if (sending) begin
            if (baud_cnt == BIT_PERIOD - 1) begin
                baud_cnt &lt;= 0;
                if (bit_cnt &lt; 8) begin
                    // 发送数据位 (LSB first)
                    txd &lt;= data_reg[bit_cnt];
                    bit_cnt &lt;= bit_cnt + 1;
                end else if (bit_cnt == 8) begin
                    // 发送停止位
                    txd &lt;= 1'b1;
                    bit_cnt &lt;= bit_cnt + 1;
                end else begin
                    // 发送完成
                    sending &lt;= 1'b0;
                    tx_busy &lt;= 1'b0;
                end
            end else begin
                baud_cnt &lt;= baud_cnt + 1;
            end
        end
    end
end

endmodule

逐行说明

  • 第1-3行:模块定义与参数声明,同前。
  • 第4-9行:端口声明,同前。
  • 第11-12行:localparam定义,同前。
  • 第14-18行:内部寄存器,新增data_reg用于暂存待发送数据。
  • 第20行:always块,敏感列表包含clk上升沿和rst_n下降沿(异步复位)。
  • 第21-28行:复位逻辑,将所有寄存器清零,txd置为高电平(空闲态),tx_busy置低。
  • 第29-36行:检测到tx_start且当前未发送时,启动发送:设置sending和tx_busy,锁存数据,计数器清零,输出起始位(低电平)。
  • 第37-56行:发送状态下的逻辑:当baud_cnt计数到BIT_PERIOD-1时,产生一个波特率时钟脉冲;根据bit_cnt的值依次发送数据位(LSB first)、停止位,完成后清除sending和tx_busy。
  • 第57行:endmodule结束模块。
标签:
本文原创,作者:二牛学FPGA,其版权均为FPGA线上课程平台|最全栈的FPGA学习平台|FPGA工程师认证培训所有。
如需转载,请注明出处:https://z.shaonianxue.cn/41108.html
二牛学FPGA

二牛学FPGA

初级工程师
这家伙真懒,几个字都不愿写!
95819.46W4W3.67W
分享:
成电国芯FPGA赛事课即将上线
FPGA校招备战:2026年常见面试题与高频考点实践指南
FPGA校招备战:2026年常见面试题与高频考点实践指南上一篇
2026年FPGA实习生简历优化指南:项目描述与关键词策略下一篇
2026年FPGA实习生简历优化指南:项目描述与关键词策略
相关文章
总数:991
从FPGA到流片:芯片验证工程师的成长通关指南

从FPGA到流片:芯片验证工程师的成长通关指南

在芯片设计这条既漫长又精密的道路上,验证是确保芯片功能正确、性能达标的“…
技术分享
1个月前
0
0
88
0
FPGA动态重配置在AI边缘设备中的2026年新应用

FPGA动态重配置在AI边缘设备中的2026年新应用

QuickStart步骤1:准备硬件平台——使用XilinxZynq…
技术分享
1天前
0
0
6
0
FPGA &#8211; 基于FPGA的HDMI显示

FPGA &#8211; 基于FPGA的HDMI显示

写在前面HDMI接口很早之前就想调试了,由于没有时间,就拖到了现…
工程案例, 技术分享
9个月前
0
0
407
0
评论表单游客 您好,欢迎参与讨论。
加载中…
评论列表
总数:0
FPGA线上课程平台|最全栈的FPGA学习平台|FPGA工程师认证培训
没有相关内容