03_Serial port RS232
1. Theoretical study
1.1 Introduction to serial port terminology
1.1.1 Asynchronous communication
The difference between UART and SPI and IIC is that it is an asynchronous communication interface. The receiver in asynchronous communication
does not know when the data will arrive, so both parties must have their own clocks. During the data transmission process, no clock is needed. The time interval of sending by the sender can be uneven, and the receiver realizes information synchronization with the help of the start bit and stop bit of the data.
1.1.2 Synchronous communication
SPI and IIC are synchronous communication interfaces (details will be introduced in later chapters).
In synchronous communication, both parties use clocks with the same frequency. During data transmission, the clock is transmitted along with the data. The clocks used by the sender and receiver are provided by the host.
1.1.3 Full duplex
Full-duplex, that is, data can be sent and received at the same time.
1.1.4 Half-duplex
Only one of sending data and receiving data can be in progress at the same time.
1.1.5 UART communication
There are only two signal lines in UART communication, one is the sending data port line called tx, and the other is the receiving data port line called rx. For the PC, its tx should be connected with the FPGA’s rx. Similarly, the PC’s rx should be connected with the FPGA’s tx. If two tx or two rx are connected, the data cannot be sent and received normally, so don’t get confused, remember that rx and tx are relative to the main body. UART can achieve full duplex, that is, it can send data and receive data at the same time.
1.2 RS-232 signal line
The RS-232 signal line port standard is often used for communication between computers, routers and modems (MODEN, commonly known as
"cat"). In this communication system, the equipment is divided into data terminal equipment DTE (computer, router) and data communication equipment DCE (modem). We use this communication model to explain their signal line connection and the role of each signal line. In the old desktop computers, there is usually a RS-232 standard COM port (also known as the DB9 interface). The
signal line of the DB9 interface indicates
the "straight-through" serial port connection
1.3 Introduction to RS232 Communication Protocol
1) RS232 is a kind of UART, there is no clock line, only two data lines, namely rx and tx, both of which are 1bit wide. Where rx is the line for receiving data and tx is the line for sending data.
2) The rx bit width is 1 bit. When the PC sends 8-bit data to the FPGA through the serial port debugging assistant, the FPGA receives bit by bit through the serial port rx, from the lowest bit to the highest bit, and finally the bits are spliced into 8-bit data in the FPGA. (The received data is finally spliced into 8-bit data, one-bit data)
3) The tx bit width is 1 bit. When the FPGA sends 8-bit data to the PC through the serial port, the FPGA transmits the 8-bit data to the PC one by one through the tx line, and sends them sequentially from the lowest bit to the highest bit. Finally, the host computer splices the bit-by-bit data bits into 8-bit data through the serial port assistant according to the RS232 protocol.
4) The sending and receiving of serial port data is based on the frame structure, that is, sending and receiving data frame by frame. In addition to containing 8 bits of valid data in the middle, each frame must have a start bit at the beginning of each frame, which is fixed to 0; at the end of each frame, there must also be a stop bit, which is fixed to 1, that is, the most basic frame structure (excluding parity, etc.) has 10 bits . In the case of not sending or receiving data, rx and tx are in the idle state . At this time, the rx and tx lines are kept at
high level. If there is a data frame transmission, there will be a start bit first, then 8bit data bits, and then a 1bit stop bit. Then rx and tx continue to enter the idle state, and then wait for the next data transmission. As shown in the figure is a basic RS232 frame structure.
5) Baud rate: In the information transmission channel, the signal unit carrying data information is called a symbol (because the serial port is 1bit for transmission, so the symbol represents a binary number), the number of symbols transmitted through the signal per second is called the transmission rate of the symbol, referred to as the baud rate, commonly used symbol "Baud", and its unit is "baud per second (Bps)". Common baud rates of serial ports are 4800, 9600, 115200, etc. We choose 9600 baud rate to explain the serial port chapter.
6) Bit rate: The amount of information transmitted by the communication channel per second is called the bit transmission rate, referred to as the bit rate, and its unit is "bits per second (bps)". The bit rate can be calculated from the baud rate, the formula is: bit rate = baud rate * binary digits corresponding to a single modulation state. If the baud rate is 9600, the bit rate of the serial port is: 9600Bps 1bit= 9600bps.
7) The difference between baud rate and bit rate
To discuss the relationship between bit rate and baud rate, it is necessary to understand the relationship between decoding element and bit. Just like the buses, subways, and taxis mentioned in the example just now can take different numbers of passengers, different code elements can also be represented by bits of different digits. The number of bits required for a symbol is determined by the number of states supported by the symbol.
8) Calculation: If the baud rate is 9600, the calculated time for the serial port to send or receive 1 bit data is one baud, that is, 1/9600 second. If a 50MHz (period is 20ns) system clock is used to count, the number to be counted is cnt = (1s * 10^9)ns / 9600bit)ns / 20ns ≈ 5208 system clock cycles, that is, the interval between each bit of data must be at a clock frequency of 50MHz Down count 5208 times.
9) When the host computer sends 8-bit data through the serial port, it will automatically send a start bit of baud time before sending 8-bit valid data, and will automatically send a stop bit after sending 8-bit valid data. In the same way, before the serial port assistant receives the data sent by the host computer, it must detect the start bit of a baud time to start receiving data. After receiving the 8bit data, it will receive a stop bit of the baud time.
2. Metastable state
2.1 Take the first beat
1) Why take the first beat, because the incoming rx and the clock signal are not synchronized, and the rx signal must be synchronized with the clock signal.
2) Since the baud rate and the rx signal in the PC are synchronous, and the rx signal and the system clock sys_clk of the FPGA are asynchronous, what we need to do at this time is to synchronize the rx signal in the slow clock domain (the baud rate in the PC) system to the fast clock domain (sys_clk in the FPGA) system.
2.2 Continuous beat
1) What is metastable state?
Because when transmitting data on the serial port, when you use an oscilloscope to amplify the rising or falling edge of a rectangular pulse, you will find that its rising and falling edges are not pulled up or pulled down instantaneously, but have a slope change process, which is called "slew rate" in the op amp. At this time, the output terminal of the FPGA's first-level register is in an uncertain state for a long period of time after the clock edge arrives, and is in an oscillating state between 0 and 1, rather than equal to the determined rx value of the serial port input.
2) How is the metastable state generated?
The setup time Tus, the hold time Th, the RS setup time and the save time do not meet the conditions, the register delay Tco, the decision time Tmet, and the signal input register does not guarantee its setup time and hold time.
3) How to solve the metastable state?
Use multi-level registers to reduce the harm of metastability to the system. Generally hit
2 beats.
3. Experimental objectives
Design and realize the data receiving and sending module based on serial port RS232, use the receiving and sending module to complete the serial port data loopback experiment.
4. Hardware resources
MAX3232 is an RS232 transceiver chip. Since the signals of the RS-232 level standard cannot be directly recognized by the controller, these signals will be converted into "TTL" level signals that the controller can recognize through a "level conversion chip" to realize communication.
5. Modular design
5.1 Top-level module block diagram
5.2 Serial port data receiving module
Why is it necessary to output a valid flag signal accompanying the parallel data? This is because the subsequent module or system may not know whether the sampled data at that moment is stable and valid when using the parallel data, and the arrival of the data valid flag signal indicates that the data is stable and valid at that moment, which serves as an indicator. When the data valid flag signal is high, the parallel data can be used by the subsequent module or system.
Send 87654321 —> 87654321
5.3 Serial data sending module
6. Waveform diagram
6.1 Serial data receiving module
start_nedge: Falling edge, start flag signal, sometimes the rex_reg signal will also have 0, 1 jump, and there will be a falling delay in the data bit. In order to avoid this situation, set an enable signal work_en, and the work_en signal can judge that the start_nedge flag signal that appears at this time is not the initial falling edge of the serial port frame we want, so that it can be filtered out.
baud_cnt: distinguish between 10 bit and 10 bit data
bit_flag in a frame of data to extract data and find the most stable state.
Extract 8bit data, valid data 1-8,
after the effective signal ends, work_en is pulled low, the counter is also cleared to 0,
and then the data splicing operation is performed, and finally the data is output and the signal po_flag is pulled high.
6.2 Serial data sending module
7. RTL
7.1 uart_rx
`timescale 1ns/1ns
module uart_rx
#(
parameter UART_BPS = 'd9600, //串口波特率
parameter CLK_FREQ = 'd50_000_000 //时钟频率
)
(
input wire sys_clk , //系统时钟50MHz
input wire sys_rst_n , //全局复位
input wire rx , //串口接收数据
output reg [7:0] po_data , //串转并后的8bit数据
output reg po_flag //串转并后的数据有效标志信号
);
//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
//localparam define
localparam BAUD_CNT_MAX = CLK_FREQ/UART_BPS ;
//reg define
reg rx_reg1 ;
reg rx_reg2 ;
reg rx_reg3 ;
reg start_nedge ;
reg work_en ;
reg [12:0] baud_cnt ;
reg bit_flag ;
reg [3:0] bit_cnt ;
reg [7:0] rx_data ;
reg rx_flag ;
//********************************************************************//
//***************************** Main Code ****************************//
//********************************************************************//
//插入两级寄存器进行数据同步,用来消除亚稳态
//rx_reg1:第一级寄存器,寄存器空闲状态复位为1
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
rx_reg1 <= 1'b1;
else
rx_reg1 <= rx;
//rx_reg2:第二级寄存器,寄存器空闲状态复位为1
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
rx_reg2 <= 1'b1;
else
rx_reg2 <= rx_reg1;
//rx_reg3:第三级寄存器和第二级寄存器共同构成下降沿检测
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
rx_reg3 <= 1'b1;
else
rx_reg3 <= rx_reg2;
//start_nedge:检测到下降沿时start_nedge产生一个时钟的高电平
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
start_nedge <= 1'b0;
else if((~rx_reg2) && (rx_reg3))
start_nedge <= 1'b1;
else
start_nedge <= 1'b0;
//work_en:接收数据工作使能信号
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
work_en <= 1'b0;
else if(start_nedge == 1'b1)
work_en <= 1'b1;
else if((bit_cnt == 4'd8) && (bit_flag == 1'b1))
work_en <= 1'b0;
//baud_cnt:波特率计数器计数,从0计数到BAUD_CNT_MAX - 1
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
baud_cnt <= 13'b0;
else if((baud_cnt == BAUD_CNT_MAX - 1) || (work_en == 1'b0))
baud_cnt <= 13'b0;
else if(work_en == 1'b1)
baud_cnt <= baud_cnt + 1'b1;
//bit_flag:当baud_cnt计数器计数到中间数时采样的数据最稳定,
//此时拉高一个标志信号表示数据可以被取走
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
bit_flag <= 1'b0;
else if(baud_cnt == BAUD_CNT_MAX/2 - 1)
bit_flag <= 1'b1;
else
bit_flag <= 1'b0;
//bit_cnt:有效数据个数计数器,当8个有效数据(不含起始位和停止位)
//都接收完成后计数器清零
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
bit_cnt <= 4'b0;
else if((bit_cnt == 4'd8) && (bit_flag == 1'b1))
bit_cnt <= 4'b0;
else if(bit_flag ==1'b1)
bit_cnt <= bit_cnt + 1'b1;
//rx_data:输入数据进行移位
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
rx_data <= 8'b0;
else if((bit_cnt >= 4'd1)&&(bit_cnt <= 4'd8)&&(bit_flag == 1'b1))
rx_data <= {
rx_reg3, rx_data[7:1]};
//rx_flag:输入数据移位完成时rx_flag拉高一个时钟的高电平
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
rx_flag <= 1'b0;
else if((bit_cnt == 4'd8) && (bit_flag == 1'b1))
rx_flag <= 1'b1;
else
rx_flag <= 1'b0;
//po_data:输出完整的8位有效数据
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
po_data <= 8'b0;
else if(rx_flag == 1'b1)
po_data <= rx_data;
//po_flag:输出数据有效标志(比rx_flag延后一个时钟周期,为了和po_data同步)
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
po_flag <= 1'b0;
else
po_flag <= rx_flag;
endmodule
7.2 uart_tx
`timescale 1ns/1ns
module uart_tx
#(
parameter UART_BPS = 'd9600, //串口波特率
parameter CLK_FREQ = 'd50_000_000 //时钟频率
)
(
input wire sys_clk , //系统时钟50MHz
input wire sys_rst_n , //全局复位
input wire [7:0] pi_data , //模块输入的8bit数据
input wire pi_flag , //并行数据有效标志信号
output reg tx //串转并后的1bit数据
);
//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
//localparam define
localparam BAUD_CNT_MAX = CLK_FREQ/UART_BPS ;
//reg define
reg [12:0] baud_cnt;
reg bit_flag;
reg [3:0] bit_cnt ;
reg work_en ;
//********************************************************************//
//***************************** Main Code ****************************//
//********************************************************************//
//work_en:接收数据工作使能信号
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
work_en <= 1'b0;
else if(pi_flag == 1'b1)
work_en <= 1'b1;
else if((bit_flag == 1'b1) && (bit_cnt == 4'd9))
work_en <= 1'b0;
//baud_cnt:波特率计数器计数,从0计数到BAUD_CNT_MAX - 1
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
baud_cnt <= 13'b0;
else if((baud_cnt == BAUD_CNT_MAX - 1) || (work_en == 1'b0))
baud_cnt <= 13'b0;
else if(work_en == 1'b1)
baud_cnt <= baud_cnt + 1'b1;
//bit_flag:当baud_cnt计数器计数到1时让bit_flag拉高一个时钟的高电平
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
bit_flag <= 1'b0;
else if(baud_cnt == 13'd1)
bit_flag <= 1'b1;
else
bit_flag <= 1'b0;
//bit_cnt:数据位数个数计数,10个有效数据(含起始位和停止位)到来后计数器清零
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
bit_cnt <= 4'b0;
else if((bit_flag == 1'b1) && (bit_cnt == 4'd9))
bit_cnt <= 4'b0;
else if((bit_flag == 1'b1) && (work_en == 1'b1))
bit_cnt <= bit_cnt + 1'b1;
//tx:输出数据在满足rs232协议(起始位为0,停止位为1)的情况下一位一位输出
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
tx <= 1'b1; //空闲状态时为高电平
else if(bit_flag == 1'b1)
case(bit_cnt)
0 : tx <= 1'b0;
1 : tx <= pi_data[0];
2 : tx <= pi_data[1];
3 : tx <= pi_data[2];
4 : tx <= pi_data[3];
5 : tx <= pi_data[4];
6 : tx <= pi_data[5];
7 : tx <= pi_data[6];
8 : tx <= pi_data[7];
9 : tx <= 1'b1;
default : tx <= 1'b1;
endcase
endmodule
7.3 rs232
`timescale 1ns/1ns
module rs232
(
input wire sys_clk , //系统时钟50MHz
input wire sys_rst_n , //全局复位
input wire rx , //串口接收数据
output wire tx //串口发送数据
);
//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
//parameter define
parameter UART_BPS = 14'd9600 , //比特率
CLK_FREQ = 26'd50_000_000 ; //时钟频率
//wire define
wire [7:0] po_data;
wire po_flag;
//********************************************************************//
//*************************** Instantiation **************************//
//********************************************************************//
//------------------------ uart_rx_inst ------------------------
uart_rx
#(
.UART_BPS (UART_BPS ), //串口波特率
.CLK_FREQ (CLK_FREQ ) //时钟频率
)
uart_rx_inst
(
.sys_clk (sys_clk ), //input sys_clk
.sys_rst_n (sys_rst_n ), //input sys_rst_n
.rx (rx ), //input rx
.po_data (po_data ), //output [7:0] po_data
.po_flag (po_flag ) //output po_flag
);
//------------------------ uart_tx_inst ------------------------
uart_tx
#(
.UART_BPS (UART_BPS ), //串口波特率
.CLK_FREQ (CLK_FREQ ) //时钟频率
)
uart_tx_inst
(
.sys_clk (sys_clk ), //input sys_clk
.sys_rst_n (sys_rst_n ), //input sys_rst_n
.pi_data (po_data ), //input [7:0] pi_data
.pi_flag (po_flag ), //input pi_flag
.tx (tx ) //output tx
);
endmodule
8. Testbench
8.1 tb_uart_rx
`timescale 1ns/1ns
module tb_uart_rx();
//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
//reg define
reg sys_clk;
reg sys_rst_n;
reg rx;
//wire define
wire [7:0] po_data;
wire po_flag;
//********************************************************************//
//***************************** Main Code ****************************//
//********************************************************************//
//初始化系统时钟、全局复位和输入信号
initial begin
sys_clk = 1'b1;
sys_rst_n <= 1'b0;
rx <= 1'b1;
#20;
sys_rst_n <= 1'b1;
end
//模拟发送8次数据,分别为0~7
initial begin
#200
rx_bit(8'd0); //任务的调用,任务名+括号中要传递进任务的参数
rx_bit(8'd1);
rx_bit(8'd2);
rx_bit(8'd3);
rx_bit(8'd4);
rx_bit(8'd5);
rx_bit(8'd6);
rx_bit(8'd7);
end
//sys_clk:每10ns电平翻转一次,产生一个50MHz的时钟信号
always #10 sys_clk = ~sys_clk;
//定义一个名为rx_bit的任务,每次发送的数据有10位
//data的值分别为0~7由j的值传递进来
//任务以task开头,后面紧跟着的是任务名,调用时使用
task rx_bit(
//传递到任务中的参数,调用任务的时候从外部传进来一个8位的值
input [7:0] data
);
integer i; //定义一个常量
//用for循环产生一帧数据,for括号中最后执行的内容只能写i=i+1
//不可以写成C语言i=i++的形式
for(i=0; i<10; i=i+1) begin
case(i)
0: rx <= 1'b0;
1: rx <= data[0];
2: rx <= data[1];
3: rx <= data[2];
4: rx <= data[3];
5: rx <= data[4];
6: rx <= data[5];
7: rx <= data[6];
8: rx <= data[7];
9: rx <= 1'b1;
endcase
#(5208*20); //每发送1位数据延时5208个时钟周期
end
endtask //任务以endtask结束
//********************************************************************//
//*************************** Instantiation **************************//
//********************************************************************//
//------------------------uart_rx_inst------------------------
uart_rx uart_rx_inst(
.sys_clk (sys_clk ), //input sys_clk
.sys_rst_n (sys_rst_n ), //input sys_rst_n
.rx (rx ), //input rx
.po_data (po_data ), //output [7:0] po_data
.po_flag (po_flag ) //output po_flag
);
endmodule
8.2 tb_uart_tx
`timescale 1ns/1ns
/
module tb_uart_tx();
//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
//reg define
reg sys_clk;
reg sys_rst_n;
reg [7:0] pi_data;
reg pi_flag;
//wire define
wire tx;
//********************************************************************//
//***************************** Main Code ****************************//
//********************************************************************//
//初始化系统时钟、全局复位
initial begin
sys_clk = 1'b1;
sys_rst_n <= 1'b0;
#20;
sys_rst_n <= 1'b1;
end
//模拟发送7次数据,分别为0~7
initial begin
pi_data <= 8'b0;
pi_flag <= 1'b0;
#200
//发送数据0
pi_data <= 8'd0;
pi_flag <= 1'b1;
#20
pi_flag <= 1'b0;
//每发送1bit数据需要5208个时钟周期,一帧数据为10bit
//所以需要数据延时(5208*20*10)后再产生下一个数据
#(5208*20*10);
//发送数据1
pi_data <= 8'd1;
pi_flag <= 1'b1;
#20
pi_flag <= 1'b0;
#(5208*20*10);
//发送数据2
pi_data <= 8'd2;
pi_flag <= 1'b1;
#20
pi_flag <= 1'b0;
#(5208*20*10);
//发送数据3
pi_data <= 8'd3;
pi_flag <= 1'b1;
#20
pi_flag <= 1'b0;
#(5208*20*10);
//发送数据4
pi_data <= 8'd4;
pi_flag <= 1'b1;
#20
pi_flag <= 1'b0;
#(5208*20*10);
//发送数据5
pi_data <= 8'd5;
pi_flag <= 1'b1;
#20
pi_flag <= 1'b0;
#(5208*20*10);
//发送数据6
pi_data <= 8'd6;
pi_flag <= 1'b1;
#20
pi_flag <= 1'b0;
#(5208*20*10);
//发送数据7
pi_data <= 8'd7;
pi_flag <= 1'b1;
#20
pi_flag <= 1'b0;
end
//sys_clk:每10ns电平翻转一次,产生一个50MHz的时钟信号
always #10 sys_clk = ~sys_clk;
//********************************************************************//
//*************************** Instantiation **************************//
//********************************************************************//
//------------------------uart_rx_inst------------------------
uart_tx uart_tx_inst(
.sys_clk (sys_clk ), //input sys_clk
.sys_rst_n (sys_rst_n ), //input sys_rst_n
.pi_data (pi_data ), //output [7:0] pi_data
.pi_flag (pi_flag ), //output pi_flag
.tx (tx ) //input tx
);
endmodule
8.3 tb_rs232
`timescale 1ns/1ns
module tb_rs232();
//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
//wire define
wire tx ;
//reg define
reg sys_clk ;
reg sys_rst_n ;
reg rx ;
//********************************************************************//
//***************************** Main Code ****************************//
//********************************************************************//
//初始化系统时钟、全局复位和输入信号
initial begin
sys_clk = 1'b1;
sys_rst_n <= 1'b0;
rx <= 1'b1;
#20;
sys_rst_n <= 1'b1;
end
//调用任务rx_byte
initial begin
#200
rx_byte();
end
//sys_clk:每10ns电平翻转一次,产生一个50MHz的时钟信号
always #10 sys_clk = ~sys_clk;
//创建任务rx_byte,本次任务调用rx_bit任务,发送8次数据,分别为0~7
task rx_byte(); //因为不需要外部传递参数,所以括号中没有输入
integer j;
for(j=0; j<8; j=j+1) //调用8次rx_bit任务,每次发送的值从0变化7
rx_bit(j);
endtask
//创建任务rx_bit,每次发送的数据有10位,data的值分别为0到7由j的值传递进来
task rx_bit(
input [7:0] data
);
integer i;
for(i=0; i<10; i=i+1) begin
case(i)
0: rx <= 1'b0;
1: rx <= data[0];
2: rx <= data[1];
3: rx <= data[2];
4: rx <= data[3];
5: rx <= data[4];
6: rx <= data[5];
7: rx <= data[6];
8: rx <= data[7];
9: rx <= 1'b1;
endcase
#(5208*20); //每发送1位数据延时5208个时钟周期
end
endtask
//********************************************************************//
//*************************** Instantiation **************************//
//********************************************************************//
//------------------------ rs232_inst ------------------------
rs232 rs232_inst
(
.sys_clk (sys_clk ), //input sys_clk
.sys_rst_n (sys_rst_n ), //input sys_rst_n
.rx (rx ), //input rx
.tx (tx ) //output tx
);
endmodule