基于FPGA 的UART 串口技术研究
作者: 尹军茹
摘要:针对传统UART集成电路芯片设计复杂、可移植性差、成本较高等诸多缺点,文章提出一种基于DSP+FPGA架构的UART串口设计方案。该方案利用FPGA资源实现高性能、低成本的通用化UART驱动,具有高可配置性、可扩容性和良好的可移植性。文章详细论述了系统架构设计、FPGA软件设计和DSP软件设计,采用差错重传机制和奇偶校验,提高了数据传输的可靠性和正确性。实验结果验证了该方案实现了可靠的全双工串口通信,并具有良好的工程实用性和复用价值。关键词:UART;FPGA;DSP;FIFO;串口接收;串口发送
中图分类号:TP311.52 文献标识码:A
文章编号:1009-3044(2025)04-0076-09 开放科学(资源服务) 标识码(OSID) :
0 引言
UART以其传输线少、可靠性高、波特率可调等优点,广泛应用于短距离、低速率、低成本的通信系统,如无线通信和雷达系统[1]。DSP芯片与UART接口的数据交互是实际应用中的常见需求,但现有的几种实现方式各有不足(详见表1) ,因此研究UART串口设计在工程实际中的简洁高效实现方式成为亟须解决的问题。本文提出一种基于DSP+FPGA 架构的UART 串口设计方案,利用FPGA资源实现高性能、低成本的通用化UART驱动。该方案具有高可配置性、可扩容性和良好的可移植性,能够实现可靠的全双工串口通信。
1 系统架构设计
本文采用DSP+FPGA结构设计,通过FPGA芯片实现UART 接收发送驱动,DSP 与FPGA 之间通过EMIF接口进行数据交互, DSP负责实现接收发送控制。其功能框图如图1所示。
如图2 所示,所有外部接口均由DSP 软件配合FPGA完成控制,DSP通过FPGA完成与外部接口之间的串口通信。利用DSP+FPGA结构设计的可移植性,系统可同时实现多个串口通路,与多个设备交联互不干扰。
2 FPGA 软件设计
FPGA作为一种半定制电路,具有开发周期短、功能强大、现场可编程等优点,适用于实现UART功能。当前大多数UART芯片设计复杂、移植性差,而FPGA 的灵活性使其能够根据项目需求定制UART功能,去除不必要的模块,从而提高系统的效率和稳定性。此外,FPGA支持硬件描述语言(如VHDL、Verilog) 进行编程,便于实现复杂的逻辑功能。从资源需求、接口类型/数量、功耗、成本等方面综合评估后,本文采用深圳市国微电子有限公司的国产芯片SMQ7K325TFFG900,速度等级为-2,封装形式为FFG900,FPGA 芯片工作频率为100 MHz。FPGA软件采用VHDL语言编写,开发环境为Vivado2018.3,主要实现UART接收发送驱动,同时完成与DSP的EMIF总线通信,并实现与外部其他交联设备的互联功能。该设计具有高可配置性、可扩容性、可移植性、低硬件成本以及低开发成本等优点。
2.1 波特率设计
为提高该设计对不同场合应用需求的兼容性,本设计开放了波特率、数据位、停止位、奇偶校验选择等配置参数。通过更改baud_rate_cnt实现波特率配置灵活,可适应不同场合的时钟频率;通过更改data_bits_num、parity_style、stop_bit_len可实现数据位(5-8) 、校验位(奇、偶、无) 和停止位(0.5、1、1.5、2) 的灵活配置。波特率计算公式为:
baud_rate = F / baud_rate_cnt (1)
式中:F为系统时钟频率,baud_rate_cnt为波特率计数(1bit所占的时钟数) 。
利用上述波特率计算公式,得出几种常用波特率与波特率计数对照表,如表2所示。
波特率越高,传输速度越快,但误码率也会增加,同时会增加硬件成本和复杂度。例如,若应用需要传输大量数据,选择较高的波特率(如115 200) 更合适;反之,若数据量不大或实时性要求不高,较低波特率(如9 600) 即可满足需求。在信号质量较差或干扰较多的环境中,较低的波特率可以提供更可靠的通信;在电池供电的设备中,较低的波特率可降低功耗和硬件成本。因此,需要根据具体的应用场景和需求选择合适的波特率,以平衡传输速度、误码率、硬件成本和能耗等因素。
2.2 UART_RX 驱动设计
采用状态机设计以实现复杂的串行通信协议,负责接收串行数据,并将其转换为并行数据存储在接收FIFO缓冲中。该模块检测RX线上的串行数据,添加起始位、数据位、校验位(可选) ,并在接收到停止位后结束接收过程。
串口接收驱动主要程序实现如下:
entity UART_RX is
--波特率计数器位宽
generic(BAUD_COUNTER_WIDTH:integer:=16);
Port(clk:in STD_LOGIC;
--全局复位,高有效
rst:in STD_LOGIC;
--接收数据,数据长度不足8 位时,按最低位对齐
rx_data:out STD_LOGIC_VECTOR(7 downto 0);
--接收完成
rx_end:out STD_LOGIC;
--串行输入
serial_in:out STD_LOGIC;
--接收忙
rx_busy:out STD_LOGIC;
--发送参数设置
--数据位位数: data_bits_num + 1,范围:5~8
data_bits_num:in STD_LOGIC_VECTOR(2 downto 0);
--校验方式: "000"-无校验;"100"-0校验;"101"-1校验;"110"-偶校验;"111"-奇校验;
parity_style:in STD_LOGIC_VECTOR(2 downto 0);
--停止位长度: "00"-0.5位;"01"-1位;"10"-1.5 位;"11"-2位;
stop_bit_len:in STD_LOGIC_VECTOR(1 downto 0);
--波特率计数 (1bit所占的时钟数) = 时钟频率 / 波特率
baud_rate_cnt:in STD_LOGIC_VECTOR(BAUD_COUNTER_WIDTH -1 downto 0);
)
end UART_RX
接收状态机流程图如图3所示。
接收状态机主要程序实现如下:
--采样状态
When RX_BITS=>
--波特率控制
if(rx_baud_cnt < baud_rate_cnt-1)thenrx_baud_cnt <= rx_baud_cnt+1;
else
rx_baud_cnt <= (others=>‘0’);
end if;
if(rx_baud_cnt = baud_rate_cnt-1)then
--当前bit的最大似然判断and移位and校验位计算的预处理
if(sample_0_cnt > CONV_INTEGER(baud_rate_cnt)/2)then
rx_shift_reg(9 downto 0) <= ‘0’& rx_shift_reg(9downto 1);
rx_shift_cnt <= rx_shift_cnt+1;
--起始位应为0
elsif(sample_1_cnt>CONV_INTEGER(baud_rate_cnt)/2)
and(rx_shift_cnt>0)then
rx_shift_reg(9 downto 0) <= ‘1’& rx_shift_reg(9downto 1);
rx_shift_cnt <= rx_shift_cnt+1;
--将所有数据位按位异或进行校验位计算的预处理
if(rx_shift_cnt < (CONV_INTEGER(data_bits_num)+2))then
--异或计算算法,当前输入bit位‘1’,将结果取反;当前输入bit位‘0’,对结果无影响;
calc_partity <= not calc_parity
end if;
else --起始位不为0 or中间位不为0或1
rx_state <= RX_IDLE;
end if;
--下一bit的第一采样点
if(serial_in_dly(2) =‘ 0’)then
sample_0_cnt <=((0)=>’1’,others=>’0’);
sample_1_cnt <=(others=>’0’);
elsif(serial_in_dly(2) =‘ 1’)then
sample_0_cnt <=(others=>’0’);
sample_1_cnt <=((0)=>’1’,others=>’0’);
else
sample_0_cnt <=(others=>’0’);
sample_1_cnt <=(others=>’0’);
endif
if(rx_shift_cnt = rx_bit_num-1)thenrx_state <= RX_STOP;
endif;
else
--当前bit采样
if(serial_in_dly(2) =‘ 0’)then
sample_0_cnt <= sample_0_cnt + 1;
elsif(serial_in_dly(2) =‘ 1’)then
sample_1_cnt <= sample_1_cnt + 1;
endif;
endif;
2.3 UART 发送模块设计
采用状态机设计以实现复杂的串行通信协议,负责发送串行数据,确保每个比特的发送时间准确无误。该模块从发送FIFO缓冲中读取数据,添加起始位、校验位和停止位,形成完整的UART帧格式,并将并行数据转换为串行数据通过TX线发送。串口发送驱动主要程序实现如下:
entity UART_TX is
--波特率计数器位宽
generic(BAUD_COUNTER_WIDTH:integer:=16);
Port(clk:in STD_LOGIC;
--全局复位,高有效
rst:in STD_LOGIC;
--发送数据,数据长度不足8 位时,按最低位对齐