Vivado FPGA 开发实战项目:从入门到上板

1. 引言

FPGA(现场可编程门阵列)凭借其可重构、低延迟、高并行的特性,在通信、图像处理、人工智能加速、汽车电子等领域应用广泛。Xilinx(现属 AMD)推出的 Vivado 设计套件,是目前业界最主流的 FPGA 开发工具之一。本文以一个完整的实战项目为主线,带你从环境搭建、代码编写、仿真验证一路走到上板调试,掌握 Vivado FPGA 开发的核心流程。

2. 开发环境准备

2.1 硬件选型

  • 开发板:推荐 Xilinx Artix-7 系列(如 Nexys A7、Basys 3)或 Zynq-7000 系列,性价比高、资料丰富。
  • 下载器:板载 USB-JTAG 即可,无需额外购买。
  • 外设:LED、按键、拨码开关、UART 接口、HDMI 接口等,便于验证不同功能。

2.2 软件安装

  1. 前往 AMD/Xilinx 官网下载 Vivado ML Standard Edition(免费版,支持 Artix-7 等主流器件)。
  2. 安装时勾选目标器件系列(如 Artix-7),并安装 Vivado HL WebPACK 组件。
  3. 安装完成后,打开 Vivado,确认 License 状态正常。

提示:安装路径不要包含中文和空格,避免后续工程路径解析出错。

3. 实战项目:LED 流水灯 + UART 回环

为了让初学者快速跑通完整流程,我们选择两个经典模块组合成一个项目:

  • LED 流水灯:验证时钟分频与组合/时序逻辑。
  • UART 回环:验证串口收发与状态机设计。

3.1 工程创建

  1. 打开 Vivado,点击 Create Project。
  2. 输入工程名 led_uart_demo,选择存放路径。
  3. 选择目标器件(以 Nexys A7 的 xc7a100tcsg324-1 为例)。
  4. 创建完成后,在 Sources 面板中 Add Sources,新建 Verilog 文件。

创建完成后,Vivado 会自动生成如下工程目录结构:

text 复制代码
led_uart_demo/
├── led_uart_demo.srcs/          # 源码目录(Vivado 自动生成)
│   ├── sources_1/               # 设计源文件
│   │   ├── new/                 # 用户新建的 RTL 文件
│   │   │   ├── top.v           # 顶层模块
│   │   │   ├── uart_rx.v       # UART 接收模块
│   │   │   └── uart_tx.v       # UART 发送模块
│   │   └── ip/                  # IP 核目录(使用 IP 时生成)
│   │       └── ...              # 例化的 IP 核工程
│   ├── constrs_1/               # 约束文件目录
│   │   └── new/                 # 用户新建的 XDC 约束文件
│   │       └── top.xdc         # 引脚与时钟约束
│   └── sim_1/                   # 仿真文件目录
│       └── new/                 # 用户新建的 Testbench
│           └── top_tb.v        # 仿真测试文件
├── led_uart_demo.runs/          # 综合、实现、比特流生成结果
│   ├── synth_1/                 # 综合结果
│   ├── impl_1/                  # 实现结果
│   └── ...
├── led_uart_demo.cache/         # 工程缓存(可删除,不影响工程)
├── led_uart_demo.hw/            # 硬件管理器相关文件
├── led_uart_demo.xpr            # Vivado 工程主文件(双击打开)
└── led_uart_demo.gen/           # 生成的 IP 相关文件

说明:srcs 下的 sources_1、constrs_1、sim_1 分别对应 Vivado 的 Design Sources 、Constraints 、Simulation Sources 三个分组,后续添加文件时注意放入正确的分组。

4. 代码实现

4.1 顶层模块

verilog 复制代码
module top(
    input  wire       clk,        // 100MHz 系统时钟
    input  wire       rst_n,      // 低电平复位
    input  wire       uart_rx,    // 串口接收
    output wire       uart_tx,    // 串口发送
    output reg  [3:0] led         // 4 个 LED
);

    // 流水灯控制
    reg [25:0] counter;
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n)
            counter <= 26'd0;
        else
            counter <= counter + 1'b1;
    end

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n)
            led <= 4'b0001;
        else if (counter == 26'd49_999_999)   // 0.5s 翻转一次
            led <= {led[2:0], led[3]};
    end

    // UART 回环
    wire [7:0] rx_data;
    wire       rx_done;
    uart_rx #(.CLK_FREQ(100_000_000), .BAUD_RATE(115200))
        u_rx (
            .clk    (clk),
            .rst_n  (rst_n),
            .rx     (uart_rx),
            .data   (rx_data),
            .done   (rx_done)
        );

    uart_tx #(.CLK_FREQ(100_000_000), .BAUD_RATE(115200))
        u_tx (
            .clk    (clk),
            .rst_n  (rst_n),
            .data   (rx_data),
            .send   (rx_done),
            .tx     (uart_tx)
        );

endmodule

4.2 UART 接收模块

verilog 复制代码
module uart_rx #(
    parameter CLK_FREQ = 100_000_000,
    parameter BAUD_RATE = 115200
)(
    input  wire       clk,
    input  wire       rst_n,
    input  wire       rx,
    output reg  [7:0] data,
    output reg        done
);

    localparam BAUD_CNT = CLK_FREQ / BAUD_RATE;

    reg [3:0]   bit_index;
    reg [15:0]  clk_cnt;
    reg         rx_sync1, rx_sync2;
    reg         rx_reg;
    reg         busy;

    // 同步打拍,消除亚稳态
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            rx_sync1 <= 1'b1;
            rx_sync2 <= 1'b1;
        end else begin
            rx_sync1 <= rx;
            rx_sync2 <= rx_sync1;
        end
    end

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            busy      <= 1'b0;
            clk_cnt   <= 16'd0;
            bit_index <= 4'd0;
            data      <= 8'd0;
            done      <= 1'b0;
            rx_reg    <= 1'b1;
        end else begin
            done <= 1'b0;
            if (!busy) begin
                // 检测起始位(下降沿)
                if (rx_sync2 == 1'b0) begin
                    busy      <= 1'b1;
                    clk_cnt   <= 16'd0;
                    bit_index <= 4'd0;
                end
            end else begin
                clk_cnt <= clk_cnt + 1'b1;
                // 在每位中点采样
                if (clk_cnt == BAUD_CNT / 2 - 1) begin
                    rx_reg <= rx_sync2;
                end
                if (clk_cnt == BAUD_CNT - 1) begin
                    clk_cnt <= 16'd0;
                    if (bit_index == 0) begin
                        // 起始位,忽略
                        bit_index <= bit_index + 1'b1;
                    end else if (bit_index <= 8) begin
                        data[bit_index - 1] <= rx_reg;
                        bit_index <= bit_index + 1'b1;
                    end else begin
                        // 停止位
                        busy <= 1'b0;
                        done <= 1'b1;
                    end
                end
            end
        end
    end

endmodule

4.3 UART 发送模块

verilog 复制代码
module uart_tx #(
    parameter CLK_FREQ = 100_000_000,
    parameter BAUD_RATE = 115200
)(
    input  wire       clk,
    input  wire       rst_n,
    input  wire [7:0] data,
    input  wire       send,
    output reg        tx
);

    localparam BAUD_CNT = CLK_FREQ / BAUD_RATE;

    reg [3:0]  bit_index;
    reg [15:0] clk_cnt;
    reg [7:0]  data_reg;
    reg        busy;

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            tx        <= 1'b1;
            busy      <= 1'b0;
            clk_cnt   <= 16'd0;
            bit_index <= 4'd0;
            data_reg  <= 8'd0;
        end else begin
            if (!busy && send) begin
                busy      <= 1'b1;
                data_reg  <= data;
                bit_index <= 4'd0;
                tx        <= 1'b0;   // 起始位
            end else if (busy) begin
                clk_cnt <= clk_cnt + 1'b1;
                if (clk_cnt == BAUD_CNT - 1) begin
                    clk_cnt <= 16'd0;
                    if (bit_index < 8) begin
                        tx        <= data_reg[bit_index];
                        bit_index <= bit_index + 1'b1;
                    end else if (bit_index == 8) begin
                        tx        <= 1'b1;   // 停止位
                        bit_index <= bit_index + 1'b1;
                    end else begin
                        busy <= 1'b0;
                    end
                end
            end
        end
    end

endmodule

5. 约束文件与综合实现

5.1 引脚约束(XDC)

以 Nexys A7 为例,创建约束文件 top.xdc:

tcl 复制代码
set_property PACKAGE_PIN E3 [get_ports clk]
set_property IOSTANDARD LVCMOS33 [get_ports clk]
create_clock -period 10.000 -name sys_clk [get_ports clk]

set_property PACKAGE_PIN J15 [get_ports uart_rx]
set_property IOSTANDARD LVCMOS33 [get_ports uart_rx]
set_property PACKAGE_PIN K15 [get_ports uart_tx]
set_property IOSTANDARD LVCMOS33 [get_ports uart_tx]

set_property PACKAGE_PIN H17 [get_ports {led[0]}]
set_property PACKAGE_PIN K17 [get_ports {led[1]}]
set_property PACKAGE_PIN M14 [get_ports {led[2]}]
set_property PACKAGE_PIN N15 [get_ports {led[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {led[*]}]

注意:不同开发板的引脚定义不同,请以板卡原理图为准。

5.2 综合与实现

  1. 点击 Run Synthesis,等待综合完成。
  2. 综合通过后点击 Run Implementation。
  3. 实现完成后点击 Generate Bitstream,生成比特流文件。

6. 仿真验证

6.1 编写 Testbench

verilog 复制代码
module top_tb;

    reg        clk;
    reg        rst_n;
    reg        uart_rx;
    wire       uart_tx;
    wire [3:0] led;

    top dut(
        .clk    (clk),
        .rst_n  (rst_n),
        .uart_rx(uart_rx),
        .uart_tx(uart_tx),
        .led    (led)
    );

    initial begin
        clk = 0;
        forever #5 clk = ~clk;   // 100MHz
    end

    initial begin
        rst_n = 0;
        uart_rx = 1;
        #100;
        rst_n = 1;
        // 发送 0x55,验证回环
        send_byte(8'h55);
        #2000;
        $finish;
    end

    task send_byte(input [7:0] byte);
        integer i;
        begin
            uart_rx = 0;              // 起始位
            #8680;
            for (i = 0; i < 8; i = i + 1) begin
                uart_rx = byte[i];
                #8680;
            end
            uart_rx = 1;              // 停止位
            #8680;
        end
    endtask

endmodule

6.2 运行仿真

  1. 在 Sources 中右键 Testbench 文件,选择 Set as Top。
  2. 点击 Run Simulation → Run Behavioral Simulation。
  3. 在波形窗口中观察 led 的循环移位和 uart_tx 的输出,确认逻辑正确。
添加内部信号到波形窗口

默认情况下,波形窗口只显示 Testbench 顶层模块的端口信号(如 clk、rst_n、uart_rx、uart_tx、led)。要观察 counter、rx_data、tx 等内部信号,需要手动添加:

  1. 在仿真运行后,打开 Scope 面板,展开 top 层级。
  2. 在 top 下找到 u_rx(UART 接收模块)和 u_tx(UART 发送模块)实例。
  3. 展开对应实例,选中 counter、rx_data、tx、busy、bit_index 等信号,右键选择 Add to Wave Window。
  4. 也可以直接在波形窗口左侧的 Name 区域右键,选择 Add Signals,在弹出的对话框中搜索并添加所需信号。

提示:添加内部信号后,建议点击 Restart 重新运行仿真,再点击 Run All,这样波形会从 0 时刻开始完整记录,便于观察 UART 收发时序。

波形特征说明

下图展示了 UART 回环仿真中关键信号的典型时序(可用文字描述代替截图):

text 复制代码
clk       ─╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
uart_rx   ───────╲___╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
                 起始位  0x55 的 8 个数据位  停止位
rx_data    ───────XXXXXXXXXXXXXXXXXXXXXXXX───────
                 采样完成后变为 0x55
rx_done    ───────________________________╱‾‾‾‾‾‾
                 rx_done 在停止位采样后拉高一拍
uart_tx    ───────╲___╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
                 回环发送同样的 0x55 帧

从波形中可以直观看到:

  • 起始位 :uart_rx 从高电平拉低,标志一帧数据的开始。
  • 数据位 :uart_rx 依次呈现 0x55 的 8 个比特(LSB 在前),rx_data 在采样完成后更新为 0x55。
  • 停止位 :uart_rx 恢复高电平,rx_done 拉高一拍,触发 uart_tx 回环发送。
  • 回环输出 :uart_tx 输出与 uart_rx 相同的帧格式,验证收发链路正确。

7. 上板调试

  1. 连接开发板 USB 线,点击 Program Device ,选择生成的 .bit 文件下载。
  2. 观察 LED 是否按 0.5s 间隔循环点亮。
  3. 打开串口助手(如 SSCOM、PuTTY),设置波特率 115200、8 数据位、无校验、1 停止位。
  4. 发送任意字符,观察串口是否原样回显,验证 UART 回环功能。

8. 常见问题与排查

现象 可能原因 解决方法
综合报错 [Synth 8-3331] 端口未连接或位宽不匹配 检查顶层模块端口与子模块例化
上板后 LED 不亮 引脚约束错误或时钟未约束 核对 XDC 引脚,添加 create_clock
串口乱码 波特率不匹配或时钟频率错误 核对 CLK_FREQ 与 BAUD_RATE 参数
时序收敛失败 时钟频率过高或逻辑过长 降低频率、增加流水线级数
综合报错 [Synth 8-3331] 日志示例

当顶层模块端口与子模块例化不匹配时,Vivado 综合阶段会报出类似下面的错误日志:

text 复制代码
[Synth 8-3331] design "top" has unconnected port "rx_data"
[Synth 8-3331] design "top" has unconnected port "rx_done"
[Synth 8-3331] design "top" has unconnected port "led"
ERROR: [Synth 8-3331] design "top" has unconnected port "uart_tx"

关键错误行定位 :[Synth 8-3331] design "top" has unconnected port "xxx" 中的 xxx 就是未连接的端口名。例如报错指向 uart_tx,说明顶层模块的 uart_tx 输出端口没有正确连接到任何逻辑。

修改步骤:

  1. 打开 top.v,检查顶层模块端口声明是否完整,确认 uart_tx、led 等端口都已声明为 output。
  2. 检查子模块例化部分,确认 u_rx 的 .done(rx_done)、.data(rx_data) 以及 u_tx 的 .tx(uart_tx) 等连接是否一一对应。
  3. 若端口位宽不匹配(如 [7:0] 与 [3:0]),需统一位宽声明,例如将 rx_data 声明为 wire [7:0]。
  4. 修改后重新点击 Run Synthesis ,观察日志中是否还有 [Synth 8-3331] 报错。
时序收敛失败日志示例

当设计时序无法满足约束时,实现阶段会报出类似下面的时序错误日志:

text 复制代码
[Vivado 12-501] Cannot meet timing constraints
[Vivado 12-502] 1 timing constraint is not met
[Vivado 12-503] Worst slack: -0.456 ns
[Vivado 12-504] Failing endpoint: u_rx/clk_cnt_reg[15]/C
[Vivado 12-505] Failing path: clk (rise) to u_rx/clk_cnt_reg[15]/D

关键错误行定位 :[Vivado 12-503] Worst slack: -0.456 ns 中的负值 -0.456 ns 表示时序违例的严重程度;[Vivado 12-504] Failing endpoint: u_rx/clk_cnt_reg[15]/C 则直接指出违例路径的终点寄存器,这里是 UART 接收模块中的 clk_cnt 计数器第 15 位。

修改步骤:

  1. 打开 Implementation → Report Timing Summary,查看具体违例路径的起点与终点。
  2. 若违例路径集中在 clk_cnt 等计数器上,说明组合逻辑过长,可尝试将计数器拆分为多级流水线,或在关键路径上插入寄存器打拍。
  3. 检查时钟约束是否正确,确认 create_clock -period 10.000 与板卡实际时钟频率一致。
  4. 若仍无法收敛,可适当降低时钟频率(如将 100 MHz 改为 50 MHz),或优化 UART 模块中的组合逻辑,减少路径延迟。
  5. 修改后重新运行 Run Implementation ,确认 Worst slack 变为正值。

9. 进阶方向

完成本项目后,你可以继续探索以下方向:

  • 图像处理:基于 HDMI 接口实现摄像头采集与 VGA 显示。
  • 高速接口:学习 PCIe、Ethernet、DDR3/DDR4 控制器设计。
  • 片上系统:使用 Zynq 平台搭建 ARM + FPGA 异构系统。
  • HLS 开发:用 C/C++ 描述算法,通过 Vivado HLS 自动生成 RTL。
实战项目预告:基于 Zynq 的 AXI-Lite 接口自定义 IP 设计

下一篇教程将带你实现一个更进阶的实战项目------基于 Zynq 的 AXI-Lite 接口自定义 IP 设计。该项目将把 FPGA 逻辑封装成标准 AXI 外设,挂载到 Zynq 的 PS(处理系统)总线上,实现 ARM 与 PL(可编程逻辑)之间的数据交互。

学习目标:

  • 掌握 AXI 总线协议:理解 AXI-Lite 的读/写通道、握手信号与地址映射机制。
  • 掌握 IP 封装流程:学会使用 Vivado IP Packager 将自定义 RTL 封装为可复用的 IP 核。
  • 掌握 SDK 驱动开发:在 Xilinx SDK 中编写 C 语言驱动,通过 AXI 寄存器控制 PL 侧逻辑。

预备知识点(建议提前预习):

  1. AXI-Lite 信号时序 :熟悉 AWVALID/AWREADY、WVALID/WREADY、BVALID/BREADY、ARVALID/ARREADY、RVALID/RREADY 等握手信号的时序关系。
  2. Vivado IP Packager 使用:了解如何创建 IP 工程、配置接口、打包并添加到 Block Design。
  3. Xilinx SDK 基础操作:掌握新建应用工程、编写裸机程序、下载调试的基本流程。

建议在阅读下一篇教程前,先自行查阅 AXI 协议白皮书(如 AMBA AXI4-Lite 规范)和 Vivado 官方 IP 封装文档,打好基础。

对比方案:状态机 vs 计数器实现流水灯

在 4.1 节中,我们使用计数器 实现流水灯:通过一个 26 位计数器分频产生 0.5 s 的节拍,再对 led 做循环移位。这是最直观、最省资源的方式。除此之外,还可以用状态机来描述流水灯的各个状态,两种设计风格各有优劣。

对比维度 计数器实现 状态机实现
资源占用 低,仅需 1 个计数器 + 移位寄存器 略高,需要状态寄存器 + 状态译码逻辑
可读性 代码简洁,逻辑直观,适合简单流水 状态清晰,便于表达复杂时序与多模式切换
扩展性 扩展多模式(如变速、反向)需额外加判断 天然适合扩展,新增状态即可增加功能
适用场景 简单循环、固定节拍的流水灯 需要多状态切换、按键控制、模式选择的场景

下面给出状态机实现流水灯的核心 Verilog 代码片段(约 20 行),帮助读者理解不同设计风格:

verilog 复制代码
// 状态机实现流水灯:4 个状态循环移位
reg [1:0] state, next_state;
localparam S0 = 2'd0, S1 = 2'd1, S2 = 2'd2, S3 = 2'd3;

always @(posedge clk or negedge rst_n) begin
    if (!rst_n) state <= S0;
    else        state <= next_state;
end

always @(*) begin
    case (state)
        S0: next_state = S1;
        S1: next_state = S2;
        S2: next_state = S3;
        S3: next_state = S0;
        default: next_state = S0;
    endcase
end

always @(posedge clk or negedge rst_n) begin
    if (!rst_n) led <= 4'b0001;
    else begin
        case (state)
            S0: led <= 4'b0001;
            S1: led <= 4'b0010;
            S2: led <= 4'b0100;
            S3: led <= 4'b1000;
        endcase
    end
end

可以看到,状态机把「当前亮哪个灯」抽象为独立状态,后续若要加入按键切换方向、调节速度等需求,只需在状态转移逻辑中增加分支即可,扩展性明显优于计数器方案。对于本项目这种固定节拍的简单流水灯,计数器实现更简洁高效;而当你需要设计更复杂的控制逻辑时,状态机是更合适的选择。

10. 参考资料

以下是本教程涉及的核心官方文档与协议规范,建议在开发过程中按需查阅:

  1. AMD/Xilinx Vivado 官方用户指南(UG910、UG892):分别介绍 Vivado 的工程创建、综合、实现与仿真流程,是使用 Vivado 进行 FPGA 开发的基础参考。
  2. Nexys A7 板卡参考手册(含引脚定义):提供板载外设的引脚映射、时钟与接口说明,编写 XDC 约束文件时需对照此手册。
  3. AMBA AXI4-Lite 协议规范白皮书:定义 AXI-Lite 总线的读/写通道、握手信号与地址映射机制,是学习 Zynq 自定义 IP 设计的前置资料。
  4. Xilinx UG949(Vivado 设计流程指南):系统讲解从 RTL 到比特流的完整设计方法论,涵盖时序约束、功耗优化与调试技巧。
  5. UART 串口通信协议标准文档:说明异步串口的帧格式、波特率与起始/停止位定义,是理解本教程 UART 收发模块设计的基础。

11. 总结

下篇预告:基于 Zynq 的 AXI-Lite 接口自定义 IP 设计

恭喜你完成了「LED 流水灯 + UART 回环」这个入门实战项目!在下一篇教程中,我们将进入更进阶的领域------基于 Zynq 的 AXI-Lite 接口自定义 IP 设计。

核心内容:该项目将把 FPGA 逻辑封装成标准 AXI 外设,挂载到 Zynq 的 PS(处理系统)总线上,实现 ARM 与 PL(可编程逻辑)之间的数据交互。你将学会使用 Vivado IP Packager 将自定义 RTL 封装为可复用的 IP 核,并在 Xilinx SDK 中编写 C 语言驱动,通过 AXI 寄存器控制 PL 侧逻辑。

建议提前掌握的知识点:

  1. AXI-Lite 信号时序 :熟悉 AWVALID/AWREADY、WVALID/WREADY、BVALID/BREADY、ARVALID/ARREADY、RVALID/RREADY 等握手信号的时序关系。
  2. Vivado IP Packager 使用:了解如何创建 IP 工程、配置接口、打包并添加到 Block Design。
  3. Xilinx SDK 基础操作:掌握新建应用工程、编写裸机程序、下载调试的基本流程。

建议在阅读下一篇教程前,先自行查阅 AXI 协议白皮书(如 AMBA AXI4-Lite 规范)和 Vivado 官方 IP 封装文档,打好基础,届时学习会更顺畅。

10. 总结

本文通过一个「LED 流水灯 + UART 回环」的完整实战项目,带你走通了 Vivado FPGA 开发的全部核心流程:环境搭建、工程创建、RTL 设计、约束编写、仿真验证、综合实现与上板调试。掌握这套流程后,你就能在此基础上扩展出更复杂的数字系统设计。建议动手把每个步骤都亲自跑一遍,遇到问题多查日志、多看波形,这是提升 FPGA 开发能力最有效的方式。

相关推荐
NamoAmitabha1286 小时前
BSP,板级支持包--deepseek
单片机·嵌入式硬件·fpga开发
szxinmai主板定制专家6 小时前
ARM 还是 x86?CODESYS 数控机床控制器选型、FPGA 取舍与实时性真相
arm开发·人工智能·fpga开发·zynq·1024程序员节·codesys
星夜离尘5621 小时前
FPGA 小数据字如何纠错:完整实现并验证扩展 Hamming (13,8) SECDED
fpga开发
通信王661 天前
ZYNQ架构下的AXI_Lite 总线详解(1)
fpga开发
星夜离尘561 天前
FPGA 不用浮点开平方:逐位恢复整数平方根、余数与完整握手验证
fpga开发
Enclustra_China1 天前
FPGA设计的隐藏难题:算力、功耗与散热如何平衡?
fpga开发·fpga·fpga解决方案
好焊孙辉1 天前
从六代螺柱焊机到AI质检:鸿栢科技的螺柱焊国产化路径
人工智能·python·科技·fpga开发
unicrom_深圳市由你创科技1 天前
高帧率机器视觉 FPGA 图像板卡及传输开发定制解决方案
fpga开发
幻智星科技2 天前
纯FPGA网络通信实现微秒级确定性延迟
网络协议·fpga开发·硬件架构