Xilinx Risc-V Board Tutorial : Asynchronous Serial Port Design and Experiment – FII-PRX100 FPGA Board Experiment 11
Experiment 11 Asynchronous Serial Port Design and Experiment
1.Experiment Objective
- Because asynchronous serial ports are very common in industrial control, communication, and software debugging, they are also vital in FPGA development.
- Learning the basic principles of asynchronous serial port communication, handshake mechanism, data frame
- Master asynchronous sampling techniques
- Review the frame structure of the data packet
- Learning FIFO
- Joint debugging with common debugging software of PC (SSCOM, teraterm, etc.)
2.Experiment Requirement
-
- Design and transmit full-duplex asynchronous communication interface Tx, Rx
- Baud rate of 11520 bps, 8-bit data, 1 start bit, 1 or 2 stop bits
- Receive buffer (Rx FIFO), transmit buffer (Tx FIFO)
- Forming a data packet
- Packet parsing
3.Experiment Design
- Build new project named uart_frame, select XC7A100TFGG676-2 for device.
- Add new file named uart_top, add a PLL (can be copied from the previous experiment)
module uart_top
(
input inclk,
input rst,
Input baud_sel,
input rx,
output intx
);
wire sys_clk;
wire uart_clk;
wire sys_rst;
wire uart_rst;
pll_sys_rst pll_sys_rst_inst
(
.inclk (inclk),
.sys_clk (sys_clk),
.uart_clk (uart_clk),
.sys_rst (sys_rst),
.uart_rst(uart_rst)
);
endmodule
- New baud rate generator file
-
-
-
- Input clock 7.3728MHz (64 times 115200). The actual value is 7.377049MHz, which is because the coefficient of the PLL is an integer division, while the error caused by that is not large, and can be adjusted by the stop bit in asynchronous communication. See Fig 11. 1.
-
-
-
Fine solution
-
-
- Implemented with a two-stage PLL for a finer frequency
- The stop bit is set to be 2 bits, which can effectively eliminate the error.
-
This experiment will not deal with the precision. The default input frequency is 7.3728 MHz.
Fig 11. 1 PLL setting
- Supported baud rates are 115200,57600,38400,19200
- The default baud rate is 115200
- Design of baud rate
-
-
-
- Instantiate and set it top-level entity
-
-
-
wire tx_band;
Wire tx_band;
baud_rate
#(.div(64))
baud_rate_inst
(
.rst (uart_rst),
.inclk (uart_clk),
.baud_sel (baud_sel),
.baud_tx (baud_tx),
);
-
-
-
-
- Baud rate design source file
-
-
-
`timescale 1ns / 10ps
module baud_rate
#(parameter div=64)
(
input rst,
input inclk,
input [1:0] baud_sel,
output reg baud_tx,
output reg baud_rx
);
//Send baud rate, clock frequency division selection
wire [8:0] frq_div_tx;
assign frq_div_tx=(baud_sel==2’b0)?9’d63:
(baud_sel==2’b01)?9’d127:
(baud_sel==2’b10)?9’d255:9’d511;
reg [8:0] count_tx=9’d0;
always@(posedge inclk)
if(rst) begin
count_tx <=9’d0;
baud_tx <=1’b0;
end
else begin
if(count_tx==frq_div_tx) begin
count_tx <=9’d0;
baud_tx<=1’b1;
end
else begin
count_tx<=count_tx+1’b1;
baud_tx<=1’b0;
end
end
//Accept partial baud rate design
wire [6:0] frq_div_rx;
assign frq_div_rx=(baud_sel==2’b0)?7’d7:
(baud_sel==2’b01)?7’d15:
(baud_sel==2’b10)?7’d31:7’d63;
reg [8:0] count_rx=9’d0;
always@(posedge inclk)
if(rst) begin
count_rx <=9’d0;
baud_rx <=1’b0;
end
else begin
if(count_rx==frq_div_rx) begin
count_rx <=9’d0;
baud_rx<=1’b1;
end
else begin
count_rx<=count_rx+1’b1;
baud_rx<=1’b0;
end
end
endmodule
- Design the buffer file tx_buf
- 8-bit FIFO, depth is 256, read/write clock separation, full flag, read empty flag
- Interface and handshake
-
- rst reset signal
- wr_clk write clock
- tx_clk send clock
- 8-bit write data tx_data
- wr_en write enable
- ctrl writes whether the data is a data or a control word
- rdy buffer ready, can accept the next data frame
-
- Send buffer instantiation file
tx_buf
#(.TX_BIT_LEN(8),.STOP_BIT(2))
tx_buf_inst
(
.sys_rst (sys_rst),
.uart_rst (uart_rst),
.wr_clk (sys_clk),
.tx_clk (uart_clk),
.tx_baud (tx_baud),
.tx_wren (tx_wren),
.tx_ctrl (tx_ctrl),
.tx_datain (tx_data),
.tx_done (tx_done),
.txbuf_rdy (txbuf_rdy),
.tx_out (tx_out)
);
- Send buffer source file
`timescale 1ns / 10ps
module tx_buf
#(
parameter TX_BIT_LEN=8,
parameter STOP_BIT=1
)
(
input sys_rst,
input uart_rst,
input wr_clk,
input tx_clk,
input tx_baud,
input tx_wren,
input tx_ctrl,
input tx_done,
input [7:0] tx_datain,
output reg txbuf_rdy,
output tx_out
);
parameter [2:0] TXWR_IDLE=0,
TXWR_RST=1,
TXWR_INIT=2,
TXWR_WAIT=3,
TXWR_WR =4,
TXWR_DONE=5;
parameter [2:0] TXRD_IDLE =0,
TXRD_INIT =1,
TXRD_WAIT0 =2,
TXRD_WAIT1 =3,
TXRD_SEND0 =4,
TXRD_SEND1 =5,
TXRD_DONE =6;
reg wr_clr=1’b1;
reg wr_en;
reg [8:0] wr_data;
reg [5:0]delay;
wire rst_done=(delay==0);
wire trans_rdy;//from low level transmit module
wire wr_full;
reg rd_ack;
wire [8:0] txbuf_q;
reg tx_en;
reg [7:0] tx_len;
wire rd_empty;
reg [7:0] tx_data;
reg [2:0] wr_st,wr_st_nxt;
always@(posedge wr_clk)
if(sys_rst)
wr_st<=TXWR_IDLE;
else
wr_st<=wr_st_nxt;
always@(*) begin
case(wr_st)
TXWR_IDLE: wr_st_nxt=TXWR_RST;
TXWR_RST: begin
if(rst_done)
wr_st_nxt=TXWR_INIT;
else
wr_st_nxt=wr_st;
end
TXWR_INIT: wr_st_nxt=TXWR_WAIT;
TXWR_WAIT:begin
if(!wr_full)
wr_st_nxt=TXWR_WR;
else
wr_st_nxt=wr_st;
end
TXWR_WR: begin
if(tx_done)
wr_st_nxt=TXWR_DONE;
else if(wr_full)
wr_st_nxt=TXWR_WAIT;
else
wr_st_nxt=wr_st;
end
TXWR_DONE: begin
wr_st_nxt=TXWR_INIT;
end
endcase
end
always@(posedge wr_clk) begin
if(wr_st==TXWR_IDLE) begin
wr_clr <=1’b1;
wr_en <=1’b0;
wr_data<=9’b0;
txbuf_rdy <=1’b0;
delay <=31;
end
if(wr_st==TXWR_RST) begin
delay<=delay-1’b1;
end
if(wr_st==TXWR_INIT) begin
wr_clr <=1’b0;
wr_en <=1’b0;
wr_data<=9’b0;
txbuf_rdy <=1’b0;
end
if(wr_st==TXWR_WAIT) begin
wr_clr <=1’b0;
wr_en <=1’b0;
wr_data<=9’b0;
txbuf_rdy <=1’b0;
end
if(wr_st==TXWR_WR) begin
if(tx_done)
txbuf_rdy <=1’b0;
else
txbuf_rdy <=1’b1;
if(tx_wren) begin
wr_en <=1’b1;
wr_data<={tx_ctrl,tx_datain};
end
end
if(wr_st==TXWR_DONE) begin
wr_en <=1’b0;
wr_data<=9’b0;
txbuf_rdy <=1’b0;
end
end
reg [2:0] rd_st,rd_st_nxt;
always@(posedge tx_clk)
if(uart_rst)
rd_st<=TXRD_IDLE;
else
rd_st<=rd_st_nxt;
always@(*)
case(rd_st)
TXRD_IDLE:rd_st_nxt=TXRD_INIT;
TXRD_INIT:begin
if(!rd_empty)
rd_st_nxt=TXRD_WAIT0;
end
TXRD_WAIT0:begin
if(txbuf_q[8])
rd_st_nxt=TXRD_WAIT1;
else if(rd_empty)
rd_st_nxt=TXRD_INIT;
else
rd_st_nxt=rd_st;
end
TXRD_WAIT1:begin
if(trans_rdy)
rd_st_nxt=TXRD_SEND0;
else
rd_st_nxt=rd_st;
end
TXRD_SEND0:begin
rd_st_nxt=TXRD_SEND1;
end
TXRD_SEND1:begin
if(tx_len==0)
rd_st_nxt=TXRD_DONE;
else if(!rd_empty)
rd_st_nxt=TXRD_WAIT1;
else
rd_st_nxt=rd_st;
end
TXRD_DONE:rd_st_nxt=TXRD_INIT;
endcase
always@(posedge tx_clk) begin
case(rd_st)
TXRD_IDLE: begin
rd_ack <=1’b0;
tx_en <=1’b0;
tx_len <=8’b0;
tx_data <=8’b0;
end
TXRD_INIT: begin
rd_ack <=1’b0;
tx_en <=1’b0;
tx_len <=8’b0;
tx_data <=8’b0;
end
TXRD_WAIT0: begin
rd_ack <=1’b1;
tx_en <=1’b0;
tx_len <=txbuf_q[7:0];
tx_data <=txbuf_q[7:0];
end
TXRD_WAIT1: begin
rd_ack <=1’b0;
if(trans_rdy) begin
tx_en <=1’b1;
tx_len <=tx_len -1;
end
else begin
tx_en <=1’b0;
end
end
TXRD_SEND0: begin
rd_ack <=1’b0;
tx_en <=1’b0;
end
TXRD_SEND1: begin
tx_data <=txbuf_q[7:0];
if(trans_rdy)begin
rd_ack <=1’b1;
tx_en <=1’b1;
end
else begin
rd_ack <=1’b0;
tx_en <=1’b0;
end
end
TXRD_DONE: begin
rd_ack <=1’b0;
tx_en <=1’b0;
end
default:;
endcase
end
- Serial transmission, interface and handshake file design
- Interface design
-
-
- tx_rdy, send vacancy, can accept new 8-bit data
- tx_en, send data enable, pass to the sending module 8-bit data enable signal
- tx_data, 8-bit data to be sent
- tx_clk, send clock
- tx_baud, send baud rate
-
-
- Instantiation
tx_transmit
#(.DATA_LEN(TX_BIT_LEN),
.STOP_BIT(STOP_BIT)
)
tx_transmit_inst
(
.tx_rst (uart_rst),
.tx_clk (tx_clk),
.tx_baud (tx_baud),
.tx_en (tx_en),
.tx_data (tx_data),
.tx_rdy (trans_rdy),
.tx_out (tx_out)
);
- Source file
`timescale 1ns / 10ps
module tx_transmit
#(parameter DATA_LEN=8,
parameter STOP_BIT=1
)
(
input tx_rst,
input tx_clk,
input tx_baud,
input tx_en,
input [7:0] tx_data,
output reg tx_rdy,
output reg tx_out
);
parameter [2:0] TX_IDLE=0,
TX_INIT=1,
TX_WAIT=2,
TX_SEND_START=3,
TX_SEND_DATA=4,
TX_SEND_STOP1=5,
TX_SEND_STOP2=6,
TX_DONE=7;
reg [1:0] stop_bit=STOP_BIT;
reg [3:0] tx_len;
reg [8:0] tx_data_r;
reg [2:0] tx_st,tx_st_nxt;
//wire[2:0] tx_len=(stop_bit==0)?7: //8bit
// (stop_bit==1)?6: //7bit
// (stop_bit==2)?5:4; //6bit:5bit
always@(posedge tx_clk)
if(tx_rst)
tx_st<=TX_IDLE;
else
tx_st<=tx_st_nxt;
always@(*)
case(tx_st)
TX_IDLE: tx_st_nxt=TX_INIT;
TX_INIT: tx_st_nxt=TX_WAIT;
TX_WAIT: begin
if(tx_en)
tx_st_nxt=TX_SEND_START;
end
TX_SEND_START: begin
if(tx_baud)
tx_st_nxt=TX_SEND_DATA;
end
TX_SEND_DATA: begin
if((tx_len==0)&tx_baud)
tx_st_nxt=TX_SEND_STOP1;
end
TX_SEND_STOP1: begin
if(tx_baud) begin
if(stop_bit==2’b01)
tx_st_nxt=TX_DONE;
else
tx_st_nxt=TX_SEND_STOP2;
end
end
TX_SEND_STOP2: begin
if(tx_baud)
tx_st_nxt=TX_DONE;
else
tx_st_nxt=tx_st;
end
TX_DONE:begin
tx_st_nxt=TX_IDLE;
end
default:tx_st_nxt=TX_IDLE;
endcase
always@(posedge tx_clk) begin
case(tx_st)
TX_IDLE:begin
tx_rdy <=1’b0;
tx_data_r <=’b0;
tx_len <=3’d0;
tx_out <=1’b1;
end
TX_INIT:begin
tx_rdy <=1’b1;
tx_data_r <=8’b0;
tx_len <=4’d8;
tx_out <=1’b1;
end
TX_WAIT:begin
tx_rdy <=1’b1;
tx_len <=4’d8;
tx_data_r <=tx_data;
tx_out <=1’b1;
end
TX_SEND_START:begin
tx_rdy <=1’b0;
if(tx_baud)
tx_out <=1’b0;
end
TX_SEND_DATA:begin
if(tx_baud) begin
tx_len <=tx_len-1’b1;
tx_out <=tx_data_r[0];
tx_data_r <={1’b0,tx_data_r[7:1]};
end
end
TX_SEND_STOP1:begin
tx_len <=0;
if(tx_baud) begin
tx_out <=1’b1;
end
end
TX_SEND_STOP2:begin
if(tx_baud) begin
tx_out <=1’b1;
end
end
TX_DONE:begin
tx_rdy <=1’b0;
tx_out <=1’b1;
end
default:;
endcase
end
Endmodule
- Send testbench.v
`timescale 1ns / 10ps
module tb_uart(
);
reg inclk;
parameter PERIOD = 20;
initial begin
inclk = 1’b0;
//#(PERIOD/2);
end
always
#(PERIOD/2) inclk = ~inclk;
reg rst=0;
wire [1:0] baud_sel=2’b00;
reg tx_wren=0;
reg tx_ctrl=0;
reg [7:0] tx_data=0;
reg [7:0] tx_len=0;
reg tx_done;
wire txbuf_rdy;
wire sys_clk;
wire sys_rst;
reg rx_in=0;
wire tx_out;
initial begin
rst=1’b1;
#100 rst=1’b0;
end
//transmit test
reg [7:0] count=0;
reg [3:0] trans_st;
always@(posedge sys_clk)
if(sys_rst)begin
trans_st <=0;
tx_wren <=1’b0;
tx_ctrl <=1’b0;
tx_data <=8’b0;
tx_done <=1’b0;
tx_len <=0;
tx_len <=0;
count <=8’d0;
end
else case(trans_st)
0:begin
trans_st <=1;
tx_wren <=1’b0;
tx_ctrl <=1’b0;
tx_data <=8’b0;
tx_done <=1’b0;
tx_len <=16;
end
1:begin
tx_wren <=1’b0;
tx_ctrl <=1’b0;
tx_data <=8’b0;
tx_done <=1’b0;
if(txbuf_rdy)
trans_st <=2;
end
2:begin
tx_wren <=1’b1;
tx_ctrl <=1’b1;
tx_data <=tx_len;
trans_st <=3;
end
3:begin
tx_wren <=1’b0;
tx_ctrl <=1’b0;
if(tx_len==0)
trans_st <=4;
else if(txbuf_rdy) begin
tx_data <=count;
count <=count+1;
tx_wren <=1’b1;
tx_len <=tx_len-1;
end
end
4:begin
tx_wren <=1’b0;
tx_ctrl <=1’b0;
tx_data <=0;
tx_len <=16;
tx_done <=1’b1;
trans_st <=5;
end
5:begin
tx_done <=1’b0;
trans_st <=1;
end
endcase
uart_top uart_top_dut
(
.inclk (inclk),
.rst (rst),
.baud_sel (baud_sel),
.tx_wren (tx_wren),
.tx_ctrl (tx_ctrl),
.tx_data (tx_data),
.tx_done (tx_done),
.txbuf_rdy (txbuf_rdy),
.sys_clk (sys_clk),
.sys_rst (sys_rst),
.rx_in (rx_in),
.tx_out (tx_out)
);
endmodule
- Send Modelsim simulation. See Fig 11. 2.
Fig 11. 2 ModelSim simulation waves sent by serial
- Extended design (extended content is only reserved for users to think and practice)
- Design the transmitter to support 5, 6, 7, 8-bit PHY (Port physical layer)
- Support parity check
- The settings of the above steps involve FIFO, PLL, etc. (Refer to uart_top project file)
UART accept file design
- Design of rx_phy.v
Design strategies and steps
Use 8 times sampling: so rx_baud is different from tx_baud, here sampling is rx_band = 8*tx_band
Adopting multiple judgments to realize the judgment of receiving data. Determine whether the data counter is greater than 4 after the sampling value is counted.
Steps to receive data:
- Synchronization: refers to how to find the start bit from the received 0101… sync_dtc
- Receive start bit (start)
- Cyclically receive 8-bit data
- Receive stop bit (determine whether it is one stop bit or two stop bits)
Determine if the stop bit is correct
Correct, jump to step 2)
Error, jump to step 1), resynchronize
Do not judge, jump directly 2), this design adopts the scheme of no judgment
- rx_phy source file
module rx_phy
#(
parameter DATA_LEN=8,
parameter STOP_BIT=1
)
(
input rst,
input rx_clk,
input rx_baud,
input rx_in,
output reg [7:0]rx_byte,
output reg rx_rdy
);
localparam [3:0] RX_IDLE=0,
RX_INIT=1,
RX_SYNC=2,
RX_START_DTC=3,
RX_START1=4,
RX_START2=5,
RX_DATA1=6,
RX_DATA2=7,
RX_STOP1=8,
RX_STOP2=9,
RX_DONE=10;
wire [1:0] stop_bit=STOP_BIT;
reg rx_inr=1’b1;
reg [3:0] bit_len=4’d0;
reg [6:0] sync_len=7’b0;
reg [3:0] sample_len=4’d0;
reg [3:0] sample_count=4’d0;
wire bit_value=(sample_count>4);
wire sync_done=(sync_len==0);
reg start_det=1’b0;
reg [3:0] rx_st,rx_st_nxt;
always@(rx_clk)
if(rst)
rx_inr<=1’b1;
else
rx_inr<=rx_in;
always@(posedge rx_clk)
if(rst)
rx_st<=RX_IDLE;
else
rx_st<=rx_st_nxt;
always@(*)
case(rx_st)
RX_IDLE: rx_st_nxt=RX_INIT;
RX_INIT: begin
rx_st_nxt=RX_SYNC;
end
RX_SYNC: begin
if(sync_done)
rx_st_nxt=RX_START_DTC;
else
rx_st_nxt=rx_st;
end
RX_START_DTC:begin
if(start_det)
rx_st_nxt=RX_START1;
else
rx_st_nxt=rx_st;
end
RX_START1:begin
if(sample_len==0)
rx_st_nxt=RX_START2;
else
rx_st_nxt=rx_st;
end
RX_START2:begin
if(sample_count>4)
rx_st_nxt=RX_DATA1;
else
rx_st_nxt=RX_START_DTC;
end
RX_DATA1:begin
if(sample_len==0)
rx_st_nxt=RX_DATA2;
else
rx_st_nxt=rx_st;
end
RX_DATA2:begin
if(bit_len==0)begin
if(stop_bit==2)
rx_st_nxt=RX_STOP1;
else
rx_st_nxt=RX_STOP2;
end
else
rx_st_nxt=RX_DATA1;
end
RX_STOP1:begin
if(rx_baud&(sample_len==0))
rx_st_nxt = RX_STOP2;
end
RX_STOP2:begin
if(rx_baud&(sample_len==0))
rx_st_nxt=RX_DONE;
end
RX_DONE:begin
rx_st_nxt=RX_START_DTC;
end
endcase
always@(posedge rx_clk)
case(rx_st)
RX_IDLE: begin
bit_len <=4’d0;
sync_len<=7’d0;
rx_rdy <=1’b0;
sample_count<=4’d0;
rx_byte <=8’b0;
end
RX_INIT:begin
bit_len <=4’d8;
sync_len <=7’d81;
sample_len <=4’d8;
sample_count<=4’d0;
rx_rdy <=1’b0;
rx_byte <=8’b0;
end
RX_SYNC:begin
if (rx_baud) begin
if(rx_inr)
sync_len<=sync_len-1’b1;
else
sync_len<=7’d81;
end
end
RX_START_DTC:begin
rx_rdy<=1’b0;
sync_len<=7’d81;
rx_byte <=8’b0;
sample_len<=4’d7;
if (rx_baud) begin
if(!rx_inr) begin
start_det<=1’b1;
sample_count<=4’d1;
end
end
end
RX_START1: begin
start_det<=1’b0;
if (rx_baud) begin
if(!rx_inr) begin
sample_count<=sample_count+4’d1;
end
sample_len<=sample_len-1’b1;
end
end
RX_START2:begin
sample_count<=0;
sample_len<=4’d8;
end
RX_DATA1:begin
if (rx_baud) begin
if(rx_inr) begin
sample_count<=sample_count+4’d1;
end
sample_len<=sample_len-1’b1;
end
end
RX_DATA2:begin
sample_len<=4’d8;
sample_count<=0;
bit_len<=bit_len-4’d1;
rx_byte<={bit_value,rx_byte[7:1]};
end
RX_STOP1:begin
bit_len<=4’d7;
if (rx_baud) begin
if(sample_len==0) begin
sample_len<=4’d8;
end
else
sample_len<=sample_len-1’b1;
end
end
RX_STOP2:begin
bit_len<=4’d7;
if (rx_baud) begin
if(sample_len==0) begin
sample_len<=4’d8;
end
else
sample_len<=sample_len-1’b1;
end
end
RX_DONE:begin
rx_rdy<=1’b1;
end
endcase
Endmodule
- The design of rx_buf
Design strategies and steps
- Add 256 depth, 8-bit fifo
-
-
- Read and write clock separation
- Asynchronous clear (internal synchronization)
- Data appears before the rdreq in the read port
-
-
- Steps:
- Initialization: fifo, rx_phy
- Wait: FIFO full signal (wrfull) is 0
- Write: Triggered by rx_phy: rx_phy_byte, rx_phy_rdy
- End of writing
- Back to ii and continue to wait
Rx_buf.v source code
module rx_buf
#(
parameter DATA_LEN=8,
parameter STOP_BIT=1
)
(
input sys_clk,
input rx_clk,
input sys_rst,
input uart_rst,
input rx_in,
input rx_baud,
input rx_rden,
output [7:0] rx_byte,
output reg rx_byte_rdy
);
localparam [2:0] WR_IDLE=0,
WR_RST =1,
WR_INIT=2,
WR_WAIT=3,
WR_WR =4,
WR_DONE=5;
wire wr_full;
wire rd_empty;
wire wr_rst_busy;
reg wr_clr=0;
reg wr_en=0;
reg [7:0] wr_data=0;
wire [7:0] rx_phy_byte;
wire rx_phy_rdy;
//wire rd_rst_busy;
reg [2:0] wr_st,wr_st_nxt;
always@(posedge sys_clk)
if(sys_rst)
rx_byte_rdy<=1’b0;
else
rx_byte_rdy<=!rd_empty;
always@(posedge rx_clk)
if(uart_rst)
wr_st<= WR_IDLE;
else
wr_st<=wr_st_nxt;
always@(*)
case(wr_st)
WR_IDLE: wr_st_nxt=WR_RST;
WR_RST : begin
// if(wr_rst_busy)
// wr_st_nxt=wr_st;
// else
wr_st_nxt=WR_INIT;
end
WR_INIT: begin
wr_st_nxt=WR_WAIT;
end
WR_WAIT: begin
if(!wr_full)
wr_st_nxt=WR_WR;
end
WR_WR: begin
if(rx_phy_rdy)
wr_st_nxt=WR_DONE;
end
WR_DONE: begin
wr_st_nxt=WR_WAIT;
end
endcase
always@(posedge rx_clk)
case(wr_st)
WR_IDLE:begin
wr_clr <=1’b1;
wr_en <=1’b0;
wr_data <=8’d0;
end
WR_RST: begin
wr_clr <=1’b0;
wr_en <=1’b0;
wr_data <=8’d0;
end
WR_INIT: begin
wr_clr <=1’b0;
wr_en <=1’b0;
wr_data <=8’d0;
end
WR_WAIT: begin
wr_clr <=1’b0;
wr_en <=1’b0;
wr_data <=8’d0;
end
WR_WR:begin
wr_en <=rx_phy_rdy;
wr_data <=rx_phy_byte;
end
WR_DONE: begin
wr_en <=1’b0;
wr_data <=8’d0;
end
endcase
rx_phy
#(
.DATA_LEN(8),
.STOP_BIT(1)
)
rx_phy_inst
(
.rst (uart_rst),
.rx_clk (rx_clk),
.rx_baud (rx_baud),
.rx_in (rx_in),
.rx_byte (rx_phy_byte),
.rx_rdy (rx_phy_rdy)
);
rx_fifo rx_fifo_inst
(
.aclr (wr_clr),
.data (wr_data),
.rdclk (sys_clk),
.rdreq (rx_rden),
.wrclk (rx_clk),
.wrreq (wr_en),
.q (rx_byte),
.rdempty (rd_empty),
.wrfull (wr_full)
//.wr_rst_busy (wr_rst_busy),
// .rd_rst_busy (rd_rst_busy)
);
Endmodule
-
- Receive simulation incentive
Content and steps
-
-
- tx, rx loopback test (assign rx_in = tx_out)
- Continue to use the incentive file in the TX section
- Writing the incentive part of rx
-
Some parts of tb_uart.v
assign rx_in=tx_out;
wire [7:0] rx_byte;
wire rx_byte_rdy;
reg [7:0] rx_byte_r;
reg rx_rden;
always@(posedge sys_clk)
if(rx_byte_rdy)begin
rx_rden <=1’b1;
rx_byte_r<=rx_byte;
end
else begin
rx_rden<=1’b0;
end
uart_top uart_top_dut
(
.inclk (inclk),
.rst (rst),
.baud_sel (baud_sel),
.tx_wren (tx_wren),
.tx_ctrl (tx_ctrl),
.tx_data (tx_data),
.tx_done (tx_done),
.txbuf_rdy (txbuf_rdy),
.rx_rden (rx_rden),
.rx_byte (rx_byte),
.rx_byte_rdy(rx_byte_rdy),
.sys_clk (sys_clk),
.sys_rst (sys_rst),
.rx_in (rx_in),
.tx_out (tx_out)
);
-
- ModelSim simulation. See Fig 11. 3.
Fig 11. 3 Simulation
Reflection and expansion
- Modify the program to complete the 5, 6, 7, 8-bit design
- Completing the design of the resynchronization when the start and stop have errors of the receiving end rx_phy
- Complete the analysis and packaging of the receipt frame of rx_buf
- Using multi-sampling to design 180° alignment of data, compare with FPGA resources, timing and data recovery effects
Hardware test
-
-
- Use develop board to test
-
Fig 11. 4 USB to serial conversion
Write a hardware test file.
-
-
- Development board J3 is connected to the host USB interface
- Using test software such as teraterm, SSCOM3, etc. You can also write a serial communication program (C#, C++, JAVA, Python…).
- PC sends data in a certain format
- The test end uses a counter to generate data in a certain format.
- Development board J3 is connected to the host USB interface
-
The test procedure is as follows module hw_tb_uart
(
input inclk,
input rst,
input [1:0] baud_sel,
input rx_in,
output tx_out
);
reg tx_wren=0;
reg tx_ctrl=0;
reg [7:0] tx_data=0;
reg [7:0] tx_len=0;
reg tx_done;
wire txbuf_rdy;
wire sys_clk;
wire sys_rst;
//transmit test
reg [7:0] count=0;
reg [3:0] trans_st;
always@(posedge sys_clk)
if(sys_rst)begin
trans_st <=0;
tx_wren <=1’b0;
tx_ctrl <=1’b0;
tx_data <=8’b0;
tx_done <=1’b0;
tx_len <=0;
tx_len <=0;
count <=8’d0;
end
else case(trans_st)
0:begin
trans_st <=1;
tx_wren <=1’b0;
tx_ctrl <=1’b0;
tx_data <=8’b0;
tx_done <=1’b0;
tx_len <=16;
end
1:begin
tx_wren <=1’b0;
tx_ctrl <=1’b0;
tx_data <=8’b0;
tx_done <=1’b0;
if(txbuf_rdy)
trans_st <=2;
end
2:begin
tx_wren <=1’b1;
tx_ctrl <=1’b1;
tx_data <=tx_len;
trans_st <=3;
end
3:begin
tx_wren <=1’b0;
tx_ctrl <=1’b0;
if(tx_len==0)
trans_st <=4;
else if(txbuf_rdy) begin
tx_data <=count;
count <=count+1;
tx_wren <=1’b1;
tx_len <=tx_len-1;
end
end
4:begin
tx_wren <=1’b0;
tx_ctrl <=1’b0;
tx_data <=0;
tx_len <=16;
tx_done <=1’b1;
trans_st <=5;
end
5:begin
tx_done <=1’b0;
trans_st <=1;
end
endcase
wire [7:0] rx_byte;
wire rx_byte_rdy;
reg [7:0] rx_byte_r;
reg rx_rden;
always@(posedge sys_clk)
if(rx_byte_rdy)begin
rx_rden <=1’b1;
rx_byte_r<=rx_byte;
end
else begin
rx_rden<=1’b0;
end
uart_top uart_top_dut
(
.inclk (inclk),
.rst (rst),
.baud_sel (baud_sel),
.tx_wren (tx_wren),
.tx_ctrl (tx_ctrl),
.tx_data (tx_data),
.tx_done (tx_done),
.txbuf_rdy (txbuf_rdy),
.rx_rden (rx_rden),
.rx_byte (rx_byte),
.rx_byte_rdy(rx_byte_rdy),
.sys_clk (sys_clk),
.sys_rst (sys_rst),
.rx_in (rx_in),
.tx_out (tx_out)
);
endmodule
- Lock the pins, and test
Signal Name | Port Description | Network Label | FPGA Pin |
clk | System clock, 50 MHz | C10_50MCLK | U22 |
rst_n | Reset, high by default | KEY1 | M4 |
tx_data[0] | Switch input | GPIO_DIP_SW0 | N8 |
tx_data[1] | Switch input | GPIO_DIP_SW1 | M5 |
tx_data[2] | Switch input | GPIO_DIP_SW2 | P4 |
tx_data[3] | Switch input | GPIO_DIP_SW3 | N4 |
tx_data[4] | Switch input | GPIO_DIP_SW4 | U6 |
tx_data[5] | Switch input | GPIO_DIP_SW5 | U5 |
tx_data[6] | Switch input | GPIO_DIP_SW6 | R8 |
tx_data[7] | Switch input | GPIO_DIP_SW7 | P8 |
tx_out | Serial output | TTL_RX | L18 |
rx_in | Serial input | TTL_TX | L17 |
txbuf_rdy | Segment a | SEG_PA | P24 |
rx_byte_rdy | Segment h | SEG_DP | K26 |
weixuan | Segment 1 | SEG_3V3_D0 | R16 |
rx_byte[0] | LED 0 | LED0 | N17 |
rx_byte[1] | LED 1 | LED1 | M19 |
rx_byte[2] | LED 2 | LED2 | P16 |
rx_byte[3] | LED 3 | LED3 | N16 |
rx_byte[4] | LED 4 | LED4 | N19 |
rx_byte[5] | LED 5 | LED5 | P19 |
rx_byte[6] | LED 6 | LED6 | N24 |
rx_byte[7] | LED 7 | LED7 | N23 |
tx_wren | Write control | KEY2 | L4 |
tx_ctrl | Write data control | KEY3 | L5 |
tx_done | Write ending control | KEY4 | K5 |
rx_rden | Read enable | KEY5 | R1 |
- Observe the data received
- Using ILA to observe the data sent by FPGA
- See Fig 11. 5, when FPGA sends A0
Fig 11. 5 Sending A0
Fig 11. 6 Data receive by host computer
- The receiving part has been eliminated here. You are encouraged to try it on your own.