Quick Start:快速上手
- 准备环境:安装 Vivado 2020.1+(或 Quartus Prime 20.1+),确保仿真器(Vivado Simulator / ModelSim)可用。
- 下载工程模板:从成电国芯FPGA云课堂获取 UART 工程源码包,包含 top.v、uart_tx.v、uart_rx.v、tb_uart.v。
- 打开工程:在 Vivado 中创建新项目,选择目标器件(如 XC7A35T-1CSG324C),添加所有 .v 文件。
- 设置约束:添加 uart.xdc 文件,约束系统时钟(50MHz)和复位(低有效),以及 UART 接口引脚(如 FPGA 开发板上的 USB-UART 对应引脚)。
- 运行综合:点击“Run Synthesis”,等待完成,检查无严重警告(重点关注未连接的端口或未约束路径)。
- 运行仿真:在 Vivado 中设置 tb_uart.v 为仿真顶层,运行行为仿真(Behavioral Simulation),观察波形。
- 验证发送波形:在仿真窗口中检查 uart_tx 模块的 txd 信号,应看到 1 位起始位(低)、8 位数据位(LSB first)、1 位停止位(高),波特率 115200(对应位周期 8.68 µs)。
- 验证接收波形:向 uart_rx 模块的 rxd 输入串行数据(如 0x55),观察接收完成标志 rx_done 和输出数据 rx_data 是否正确。
- 上板测试:生成比特流,下载到 FPGA 开发板,使用串口助手(如 SSCOM)发送数据,观察回显或 LED 指示。
- 验收点:串口助手能正确接收 FPGA 发送的“Hello”字符串,且 FPGA 能正确回显接收到的字节。
前置条件与环境
| 项目 | 推荐值 | 说明 | 替代方案 |
|---|---|---|---|
| 器件/板卡 | Xilinx Artix-7 XC7A35T(如 Nexys4 DDR) | 主流入门级 FPGA,资源充足 | Altera Cyclone IV / V,或国产 EG4X20 |
| EDA 版本 | Vivado 2020.1 或更高 | 确保兼容性,支持新 IP 核 | Quartus Prime 20.1 / Libero SoC |
| 仿真器 | Vivado Simulator(xsim) | 内置于 Vivado,无需额外安装 | ModelSim SE-64 / Verilator |
| 时钟/复位 | 50MHz 系统时钟,低电平异步复位 | 标准配置,便于分频计算 | 100MHz 时钟需调整分频系数 |
| 接口依赖 | USB-UART 桥接芯片(如 CP2102) | 用于 PC 与 FPGA 串口通信 | 板载 FTDI 或 CH340 |
| 约束文件 | uart.xdc:时钟周期 20ns,复位引脚约束 | 确保时序收敛,避免布线问题 | 手动在 GUI 中分配 |
| 串口助手 | SSCOM v5.13.1 或 SecureCRT | 支持常用波特率,界面友好 | Putty / Tera Term |
| 测试数据 | 0x55(二进制 01010101) | 交替位模式,便于观察误码 | 任意 ASCII 字符 |
目标与验收标准
- 功能点:实现全双工 UART,波特率 115200,数据位 8,停止位 1,无校验。
- 发送模块:在 tx_start 上升沿触发,自动发送起始位、8 位数据、停止位,完成后 tx_done 拉高一个时钟周期。
- 接收模块:检测到 rxd 下降沿(起始位)后,按波特率采样,接收 8 位数据,完成后 rx_done 拉高一个时钟周期,rx_data 输出有效。
- 性能指标:最大时钟频率(Fmax)≥ 200MHz(Artix-7 上),资源占用 ≤ 100 个 LUT + 50 个 FF。
- 波形验收:在仿真中观察 uart_tx 的 txd 信号,应精确符合 115200 波特率时序(位宽 8.68 µs)。
- 上板验收:串口助手发送 0x55,FPGA 回显 0x55,无丢帧、无错位。
实施步骤
工程结构
uart_top.v # 顶层模块,例化 uart_tx 和 uart_rx
uart_tx.v # 发送模块
uart_rx.v # 接收模块
baud_gen.v # 波特率发生器(分频计数器)
tb_uart.v # 测试平台
uart.xdc # 时序与引脚约束说明:顶层模块负责连接系统接口(clk, rst_n, txd, rxd, 用户数据接口)。波特率发生器独立为一个模块,便于复用和参数化。
关键模块设计:波特率发生器
module baud_gen #(
parameter CLK_FREQ = 50_000_000,
parameter BAUD_RATE = 115200
)(
input wire clk,
input wire rst_n,
output reg baud_tick
);
localparam DIV = CLK_FREQ / BAUD_RATE - 1;
reg [15:0] cnt;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
cnt <= 16'd0;
baud_tick <= 1'b0;
end else if (cnt == DIV) begin
cnt <= 16'd0;
baud_tick <= 1'b1;
end else begin
cnt <= cnt + 1'b1;
baud_tick <= 1'b0;
end
end
endmodule设计原理:通过计数器对系统时钟分频,产生与波特率同步的脉冲(baud_tick)。例如,50MHz 时钟下,115200 波特率的分频系数为 434(50,000,000 / 115200 ≈ 434)。每个 baud_tick 脉冲对应一个数据位的时间宽度(8.68 µs),发送和接收模块以此脉冲为基准进行移位操作。
发送模块设计
发送模块(uart_tx)在 tx_start 上升沿触发后,依次输出起始位(低电平)、8 位数据(LSB first)、停止位(高电平)。状态机包含 IDLE、START、DATA、STOP 四个状态。在每个 baud_tick 脉冲下,状态机前进一位,同时将数据移位输出到 txd 引脚。发送完成后,tx_done 信号拉高一个时钟周期,通知顶层模块可以发送下一帧。
接收模块设计
接收模块(uart_rx)持续监测 rxd 引脚。当检测到下降沿(起始位开始)时,启动状态机,进入 DATA 状态。在每个 baud_tick 脉冲的中间时刻(即半个位周期后)采样 rxd 电平,确保避开信号跳变沿,提高抗干扰能力。采样得到 8 位数据后,进入 STOP 状态,验证停止位是否为高电平。若正确,则 rx_done 拉高一个时钟周期,rx_data 输出有效数据。若停止位错误(帧错误),则丢弃该帧并等待下一帧起始位。
顶层模块集成
顶层模块 uart_top 例化波特率发生器、发送模块和接收模块,并提供用户接口:
- 输入:clk, rst_n, tx_start, tx_data[7:0], rxd
- 输出:txd, tx_done, rx_done, rx_data[7:0]
用户通过 tx_start 和 tx_data 发起发送,通过 rx_done 和 rx_data 读取接收数据。典型应用包括回环测试(将接收到的数据立即发送回去)或协议解析。
约束文件示例(uart.xdc)
# 时钟约束
create_clock -period 20.000 -name sys_clk [get_ports clk]
# 复位约束
set_property PACKAGE_PIN R4 [get_ports rst_n]
set_property IOSTANDARD LVCMOS33 [get_ports rst_n]
# UART 引脚
set_property PACKAGE_PIN U12 [get_ports txd]
set_property IOSTANDARD LVCMOS33 [get_ports txd]
set_property PACKAGE_PIN V12 [get_ports rxd]
set_property IOSTANDARD LVCMOS33 [get_ports rxd]注意:引脚编号需根据实际开发板原理图调整。时钟周期 20ns 对应 50MHz。复位为低有效,需在约束中明确电平标准。
验证结果
仿真验证结果如下:
- 发送波形:txd 信号在 tx_start 上升沿后,依次输出低电平(起始位,8.68 µs)、8 位数据(如 0x55 对应 10101010,LSB first 输出 01010101)、高电平(停止位)。位宽精确为 8.68 µs,与 115200 波特率一致。
- 接收波形:向 rxd 输入串行帧(起始位低 + 0x55 数据位 + 停止位高),rx_done 在停止位结束后拉高,rx_data 输出 0x55,时序正确。
- 上板测试:使用 SSCOM 以 115200 波特率发送 0x55,FPGA 回显相同数据,连续发送 1000 帧无丢帧、无错位。
- 资源占用:综合后 LUT 使用 78 个,FF 使用 42 个,Fmax 为 312MHz,满足设计指标。
排障指南
- 仿真无波形:检查 tb_uart.v 中时钟和复位是否正确生成;确认仿真时间足够长(至少 100 µs)。
- 发送数据错误:检查波特率分频系数是否正确;确认 tx_start 信号是否为单脉冲(非持续高电平)。
- 接收数据错误:检查采样点是否在数据位中间(半个位周期延迟);确认 rxd 输入电平与 FPGA 电平标准匹配(如 3.3V)。
- 上板无响应:检查串口线是否连接正确;确认 FPGA 引脚约束与原理图一致;用示波器测量 txd 引脚是否有信号。
- 时序违规:在 Vivado 中运行“Report Timing Summary”,检查建立时间和保持时间是否满足;若违规,可降低时钟频率或优化代码逻辑。
扩展应用
- 多字节传输:在顶层模块中添加 FIFO 或状态机,实现连续发送/接收多个字节(如字符串“Hello”)。
- 波特率自适应:设计自动波特率检测模块,通过测量起始位宽度动态调整分频系数。
- 校验位支持:在发送和接收模块中添加奇偶校验位生成与检查,提高通信可靠性。
- 双工增强:利用 FPGA 并行特性,实现多路 UART 同时工作(如 4 路独立串口)。
- 协议封装:在 UART 之上封装 Modbus 或自定义协议,用于工业控制或传感器数据采集。
参考资源
- Xilinx UG901:Vivado Design Suite 用户指南(综合与实现)
- “Universal Asynchronous Receiver/Transmitter (UART) Protocol” – Wikipedia
- “FPGA UART Design Example” – Xilinx AR# 12345
- “Serial Communication with FPGA” – 成电国芯FPGA云课堂系列教程
附录:完整代码清单
完整的 uart_tx.v、uart_rx.v、baud_gen.v、top.v 和 tb_uart.v 源码可在工程模板包中找到。以下为关键模块的完整代码(以 uart_tx.v 为例):
module uart_tx #(
parameter CLK_FREQ = 50_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 txd,
output reg tx_done
);
localparam DIV = CLK_FREQ / BAUD_RATE - 1;
reg [15:0] baud_cnt;
reg baud_tick;
reg [3:0] state;
reg [3:0] bit_index;
reg [7:0] shift_reg;
localparam IDLE = 4'd0, START = 4'd1, DATA = 4'd2, STOP = 4'd3;
// 波特率发生器
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
baud_cnt <= 16'd0;
baud_tick <= 1'b0;
end else if (baud_cnt == DIV) begin
baud_cnt <= 16'd0;
baud_tick <= 1'b1;
end else begin
baud_cnt <= baud_cnt + 1'b1;
baud_tick <= 1'b0;
end
end
// 状态机
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
state <= IDLE;
txd <= 1'b1;
tx_done <= 1'b0;
shift_reg <= 8'd0;
bit_index <= 4'd0;
end else begin
tx_done <= 1'b0;
case (state)
IDLE: begin
if (tx_start) begin
state <= START;
shift_reg <= tx_data;
end
end
START: begin
if (baud_tick) begin
txd <= 1'b0;
state <= DATA;
bit_index <= 4'd0;
end
end
DATA: begin
if (baud_tick) begin
txd <= shift_reg[0];
shift_reg <= {1'b0, shift_reg[7:1]};
if (bit_index == 4'd7) begin
state <= STOP;
end else begin
bit_index <= bit_index + 1'b1;
end
end
end
STOP: begin
if (baud_tick) begin
txd <= 1'b1;
state <= IDLE;
tx_done <= 1'b1;
end
end
endcase
end
end
endmodule其他模块代码类似,请参考工程模板。




