基于FPGA的CPU与保密机之间的UART通信设计
2021-09-13李淼李娟娟
李淼 李娟娟
摘 要:在卫星通信系统的信道加密业务中,通常使用FPGA的UART通信实现CPU与保密机之间的交互。文章介绍的UART通信模块,是一种新颖的串口发送和接收的FPGA设计,仅由Verilog中简单的always块就能实现,证明此方法的操作简单且实用性强。仿真测试验证收发模块可实现可靠的全双工串口通信,更容易满足实际设计的需求。
关键词:FPGA;UART通信;always块
0 引言
在卫星通信系统的加密业务中,CPU通过发送不同指令控制/查询保密机的同时,保密机又要向CPU上报状态,由FPGA实现UART串口功能(Universal Asynchronous Receiver/Transmitter)是它们之间通信的一种常用方式,UART将要传输的信息在串行通信与并行通信之间加以轉换[1-3]。其处理方式是FPGA采用状态机设计,并在每一位数据的中点进行数据采样[4-5]。本文设计的基于FPGA的UART通信模块,省去了16倍波特率时钟和复杂的状态机,可实现同样的串口功能及性能。
FPGA在CPU与保密机之间的串行通信接口电路的设计采用了自顶而下的设计方法,主要分为UART发送模块、UART接收模块两大模块。
1 UART发送模块设计
当CPU控制/查询保密机状态时,在固定波特率 (38 400 Hz)下,FPGA将CPU发送的控制信令转化成UART帧数据格式串行数据流发送给保密机,UART串口发送时序如图1所示。
根据图1设计了串口发送程序,伪代码示例如下,其中系统主时钟为60 MHz,波特率为 38 400 Hz,且使能uart_en与数据uart_din对齐,并均与主时钟上升沿对齐。
parameter CLK_FREQ = 60_000_000;//主时钟parameter UART_BPS = 38400;//波特率
parameter BPS_CNT = CLK_FREQ/UART_BPS;
//找到使能uart_en的上升沿
assign en_flag =( ~ uart_en_d1 ) & uart_en_d0;
uart_en_d0 <= uart_en;
uart_en_d1 <= uart_en_d0;
//通过计数器控制tx_flag的长度为9.5个波特率周期
if ( en_flag ) tx_flag <= 1d1;
else if ( ( tx_cnt == 4d9 ) && ( clk_cnt == BPS_CNT/2 - 1b1 ) ) tx_flag <= 1d0;
//一个波特率周期
if ( tx_flag & clk_cnt < BPS_CNT - 1b1 ) clk_cnt <= clk_cnt + 1d1;
//串口一次发送的比特数
if ( tx_flag & clk_cnt == BPS_CNT - 1b1 ) tx_cnt <= tx_cnt + 1d1;
//输出串口数据及起始位和停止位
if ( tx_flag && ( clk_cnt == 16d0 ) )
case ( tx_cnt )
4d0 : uart_txd <= 1d0;4d1 : uart_txd <= tx_data[0];4d2 : uart_txd <= tx_data[1];
4d3 : uart_txd <= tx_data[2];4d4 : uart_txd <= tx_data[3];4d5 : uart_txd <= tx_data[4];
4d6 : uart_txd <= tx_data[5];4d7 : uart_txd <= tx_data[6];4d8 : uart_txd <= tx_data[7];
4d9 : uart_txd <= 1d1;
根据接口时序要求:首先,将计数器clk_cnt对主时钟计数,并计数到波特率周期后清零,即在0 ~ BPS_CNT-1范围内循环计数。其次,tx_flag作为串口输出数据使能,故在数据使能uart_en上升沿置高,然后在满足条件(tx_cnt == 4d9 & clk_cnt == BPS_CNT/2 - 1b1)时置低,此时正好满足tx_flag长度为9.5个波特率周期;其中tx_cnt在0~9计数,为保证每次计数为1bit有效数据宽度,tx_cnt仅在(clk_cnt == BPS_CNT - 1b1),即一个波特率周期时累加。最后,在计数器tx_cnt为0~9时依次输出起始位(0)、8位数据位(从低到高)、停止位(1)。
2 UART接收模块设计
当CPU查询保密机状态后,为接收保密机发送的UART串行数据,可通过FPGA捕获保密机发送UART串行数据,根据UART串口接收时序(见图2),串转并得到的数据发送给CPU。
由图2可知,在一定波特率下,FPGA根据UART串口接收时序依次采集起始位、数据位、停止位。设计的串口接收程序伪代码示例如下:
parameter CLK_FREQ = 60_000_000;//主时钟parameter UART_BPS = 38400;//波特率
parameter BPS_CNT = CLK_FREQ/UART_BPS;
//找到串口数据uart_rxd的下降沿
assign start_flag = uart_rxd_d1 & ( ~uart_rxd_d0 );
uart_rxd_d0 <= uart_rxd;
uart_rxd_d1 <= uart_rxd_d0;
//通过计数器控制rx_flag的长度为9.5个波特率周期
if ( start_flag ) rx_flag <= 1d1;
else if ( ( rx_cnt == 4d9 ) && ( clk_cnt == BPS_CNT/2 - 1b1 ) ) rx_flag <= 1d0;
//一个波特率周期
if ( rx_flag &clk_cnt < BPS_CNT - 1b1 ) clk_cnt <= clk_cnt + 1d1;
////串口一次接收的比特數
if ( rx_flag & clk_cnt == BPS_CNT - 1b1 ) rx_cnt <= rx_cnt + 1d1;
//在中点采集数据
if ( rx_flag && ( clk_cnt == BPS_CNT/2 ) )
case ( rx_cnt )
4d1 : rx_data[0] <= uart_rxd_d1;4d2 : rx_data[1] <= uart_rxd_d1;
4d3 : rx_data[2] <= uart_rxd_d1;4d4 : rx_data[3] <= uart_rxd_d1;
4d5 : rx_data[4] <= uart_rxd_d1;4d6 : rx_data[5] <= uart_rxd_d1;
4d7 : rx_data[6] <= uart_rxd_d1;4d8 : rx_data[7] <= uart_rxd_d1;
//输出串口接收完成标志uart_done
if ( rx_cnt == 4d9 ) uart_done <= 1d1;
uart_data <= rx_data;
根据接口时序要求:首先,通过uart_rx的下降沿start_flag捕获串口的起始位start bit,并同时将串口接收使能rx_flag置高,经过9.5个波特率周期后(rx_cnt == 4d9 & clk_cnt == BPS_CNT/2 - 1b1)置低,其中rx_cnt和clk_cnt两个计数器与发送端保持一致。其次,在rx_cnt为1~8时,同时满足在一个波特率周期的中点(clk_cnt == BPS_CNT/2)位置时,进行串口数据的采样,采样顺序为从低位到高位。最后,在停止位处(rx_cnt == 4d9),输出接收数据和捕获使能信号送给CPU。
3 仿真测试
为了验证2个UART串口测试模块的准确性,搭建仿真自环的条件,即将串口接收模块完成标志uart_done的下降沿作为串口发送模块的发送标志,仿真结果如图3所示。模拟发送3帧数据(0x7E,0x33,0x55)由UART发送模块接收,并转串后直接给接收模块,可以看出在串口接收模块uart_data解码输出的3帧数据与模拟输入数据一致,说明UART串口收发模块通信正确。
4 结语
本文介绍了一种基于FPGA实现CPU与保密机之间的UART模块设计,通过UART接口协议,分别设计了FPGA的UART串口发送时序和UART串口接收时序,采用简单的always块就实现了收发功能。由于采用了一个波特率周期的计数器,接收模块可在每个串行数据的中点进行采样,保证了数据传输的准确性。最后,通过软件仿真,进行收发自环,实现了UART数据的收发功能,这种简单可靠的设计对FPGA在uart串口通信的开发中具有较强的可操作性和应用价值。
[参考文献]
[1]张继国.一种利用FPGA实现串口通信的设计[J].电子世界,2020(12):124-125.
[2]朱玉成,董文学.基于FPGA的串口通信电路设计与实现[J].通讯世界,2018(3):41-42.
[3]王闽.基于FPGA的口通信设计与实现[J].通讯世界,2017(2):52.
[4]王媛斌.FPGA与PC通信的UART串口设计[J].兰州工业学院学报,2020(9):60-65.
[5]陈孟春.基于有限状态机的高速串口通信收发器的FPGA设计[J].计算机应用与软件,2017(12):178-183.
(编辑 姚 鑫)