这一篇在干嘛?

调试 FPGA 工程时,串口(UART)是最常用的「耳朵和嘴巴」:把内部状态打印给 PC 看,或从 PC 下发命令。这个实验实现最经典的入门功能——环回(loopback):PC 发什么,FPGA 原样发回什么。实验原文很短,本文把 UART 帧格式和波特率原理展开讲透,并保留全部原文约束与流程。

实验目标与原理

实验目的原文:

上位机通过串口调试助手发送数据给 FPGA,FPGA 通过串口接收数据并将接收到的数据发送给上位机,完成串口数据环回。

RS232 与 USB 转串口

2.1 相关关于 RS232 可以查找相关资料。 2.2 在此开发板上,通过 CH340 芯片由 USB 转串口。相关原理图请查找「开发板手册」。

展开说一下背景:RS232 是古老的串行电气标准,用正负电平表示逻辑 0/1;而现代电脑早已没有 RS232 口,所以板卡上放一颗 CH340 芯片做「翻译」——一端是 USB 协议,另一端是 UART 的 TX/RX 逻辑电平。PC 侧看到的是一个虚拟 COM 口,FPGA 侧看到的就是普通的 TX/RX 两根线。对 FPGA 而言,CH340 完全透明:你按 UART 时序收发即可。

UART 帧格式:没有时钟线,靠约定同步

UART 与 SPI、I2C 最大的不同是没有时钟线。双方只靠事先约定好的波特率(每秒传多少位)各自计时。一帧标准 8N1 数据的构成:

位序内容电平
起始位1 位恒为 0(空闲为 1,拉低表示「开始」)
数据位 D0~D78 位低位在先
校验位(可选)0 或 1 位本实验不用
停止位1 位恒为 1,之后回到空闲

接收方检测到 RX 线从 1 跳到 0,就认定起始位到来,随后在每一位的中点采样数据位——中点采样是为了避开边沿抖动,让采样时刻落在电平最稳定的位置。每一位持续多长?1 / 波特率秒。本实验用 115200bps,一位约 8.68µs;50MHz 系统时钟下一位约 434 个时钟周期,用计数器就能精确对准中点。

波特率必须两端一致

串口调试助手里选错波特率,收到的就是乱码——因为接收方按错误的节拍采样。115200 是调试最常用的档位,误差需控制在约 ±2% 以内,50MHz 分频出的 434 分之一精度足够。如果换成 9600 等低速档,容错更宽,但也别两端各配各的。

设计思路:两个模块、一条通路

原文设计思路:

在 FPGA 内部实现串口接收与串口发送模块,串口接收模块接收上位机发送的数据,然后通过串口发送模块将数据发回上位机,实现串口数据环回。如图 1


图 1

数据流非常干净:

PC 发送 → CH340 → uart_rx(FPGA 接收模块,串转并)→ 数据寄存
→ 通知信号 → 发送模块(并转串)→ uart_tx → CH340 → PC 显示

原文对模块行为的说明:

串口接收模块从串口接收端口接收上位机发送的串行数据,并在一帧数据(8 位)接收结束后给出通知信号为串口发送模块,将接收到的数据通过串口发送端口发送出去在串口通信软件上显示。

「接收完成 → 拉一个通知脉冲 → 发送模块取走字节并回发」,这是典型的握手设计。写自己的 UART 时把这个握手信号显式定义出来,比让发送模块自己去猜「数据什么时候有效」可靠得多。

接线与电平的两个细节

写 UART 模块前先在心里过一遍信号名,避免「自发自收」的低级错误:FPGA 的 uart_rx 接的是 CH340 的 TX 输出,FPGA 的 uart_tx 接的是 CH340 的 RX 输入——你的接收端对着它的发送端,交叉相连

第二个细节是空闲电平:UART 空闲时 TX 线保持高电平,起始位用「拉低」来宣告。所以 FPGA 侧把 uart_rx 配置成上拉输入(见后文引脚约束的 PULLTYPE = PULLUP),保证线缆未插或对方未驱动时不会因为悬空而误判出一个假起始位。

引脚分配

原文引脚约束一字不改。

时钟周期约束与 IO 约束:

set_pin_assignment { clk } { LOCATION = R7; IOSTANDARD = LVCMOS33; PULLTYPE = PULLUP; }
set_pin_assignment { rst_n } { LOCATION = A2; IOSTANDARD = LVCMOS33; PULLTYPE = PULLUP; }
set_pin_assignment { uart_rx } { LOCATION = F12; IOSTANDARD = LVCMOS33; PULLTYPE = PULLUP; }
set_pin_assignment { uart_tx } { LOCATION = D12; IOSTANDARD = LVCMOS33; DRIVESTRENGTH = 8; PULLTYPE = NONE;}

整理成速查表:

信号方向引脚说明
clk输入R750MHz 系统时钟
rst_n输入A2复位(低有效)
uart_rx输入F12串口接收,来自 CH340 TX
uart_tx输出D12串口发送,接 CH340 RX

注意 uart_rx 配置了上拉:UART 空闲电平为高,上拉保证 CH340 未连接或未驱动时接收端不悬空、不误判起始位。

上板流程:驱动安装与调试助手

这一步对第一次玩串口的人最容易卡住,原文流程照录并补充要点。

第一步:连接硬件

准备对应接口的 USB 线,连接 USB 转串口,在连接 USB 转串口的时候,在板子上的左边的接口 Type-c 口。上位机第一次使用 USB 串口线与 FPGA 开发板连接时,需要安装 USB 串口驱动。在开发板资料中找到「驱动软件//CH340 驱动(USB 串口驱动)」的文件夹,双击打开文件夹中的「SETUP.EXE」进行安装,驱动安装界面如图 2 所示。界面中提示 INF 文件为 CH341SER.INF,我们不需要理会(CH330,CH341 驱动是通用的),直接点安装即可。


图 2

第二步:确认驱动装好了

安装完以后,在资源管理器,点开「端口(COM 和 LPT)」,看驱动是否装好,图 3。


图 3

记下这里显示的 COM 号(例如 COM3),稍后调试助手要选同一个口。

第三步:下载程序并打开调试软件

下载,程序下载完毕。找到资料中的「调试软件」,点击如图 4 的标识。


图 4

第四步:环回测试

打开软件后,串口号 COM 口要跟设置驱动的图 3 串口号一致,波特率显示是 115200,在字符串输入框输入字母或数字,点击发送,在上框显示同样的字符。

环回成功≠双向都正常吗?

严格说,环回测试验证的是「接收 + 发送」整条链路能走通,但无法区分哪个环节出问题时(比如 TX 与 RX 接反、波特率不符、COM 口选错),现象都是「收不到回显」。排查顺序建议:确认 COM 口 → 确认波特率 115200 → 确认 Type-c 线是数据线不是纯充电线 → 重新下载程序并复位。

现象与总结

成功标准只有一个:在调试助手的字符串输入框输入字母或数字、点击发送后,上方的接收框出现同样的字符。看到回显,就意味着你独立完成了一次「PC → CH340 → FPGA 接收 → FPGA 发送 → CH340 → PC」的完整数据旅程。

这个实验虽然小,却包含三个值得带走的经验:

  1. 异步串行的本质是「约定 + 计数」:没有时钟线,起始位提供同步锚点,波特率提供节拍,中点采样提供鲁棒性。理解了这三点,9600 到 3M 波特率的所有 UART 都是同一件事。
  2. 握手信号让模块解耦:接收模块完成后给一个脉冲,发送模块据此取数发送——两个模块互不依赖内部细节,这也是所有 FPGA 工程里模块间协作的标准范式。
  3. 先装驱动再上电调试:CH340 驱动、COM 号、波特率是串口调试三大坑。养成先在设备管理器确认 COM 口的习惯,能省掉大量「程序没错就是不通」的时间。

下一步可以试着把环回改成「收到命令后返回固定字符串」,或把波特率参数化,做成可配置 9600/115200 的通用 UART 模块,以后所有工程都能直接复用。

自测