Experimental Manuals FPGA Tutor PRX100 Risc-V

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

  1. Because asynchronous serial ports are very common in industrial control, communication, and software debugging, they are also vital in FPGA development.
  2. Learning the basic principles of asynchronous serial port communication, handshake mechanism, data frame
  3. Master asynchronous sampling techniques
  4. Review the frame structure of the data packet
  5. Learning FIFO
  6. Joint debugging with common debugging software of PC (SSCOM, teraterm, etc.)

2.Experiment Requirement

    1. Design and transmit full-duplex asynchronous communication interface Tx, Rx
    2. Baud rate of 11520 bps, 8-bit data, 1 start bit, 1 or 2 stop bits
    3. Receive buffer (Rx FIFO), transmit buffer (Tx FIFO)
    4. Forming a data packet
    5. Packet parsing

3.Experiment Design

  1. Build new project named uart_frame, select XC7A100TFGG676-2 for device.
  2. 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

  1. New baud rate generator file
          1. 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

      1. Implemented with a two-stage PLL for a finer frequency
      2. 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

  1. Supported baud rates are 115200,57600,38400,19200
  2. The default baud rate is 115200
  3. Design of baud rate
          1. 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),

);

          1. 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

  1. Design the buffer file tx_buf
  2. 8-bit FIFO, depth is 256, read/write clock separation, full flag, read empty flag
  3. Interface and handshake
      1. rst reset signal
      2. wr_clk write clock
      3. tx_clk send clock
      4. 8-bit write data tx_data
      5. wr_en write enable
      6. ctrl writes whether the data is a data or a control word
      7. rdy buffer ready, can accept the next data frame
  4. 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)

);

  1. 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

  1. Serial transmission, interface and handshake file design
  2. Interface design
        1. tx_rdy, send vacancy, can accept new 8-bit data
        2. tx_en, send data enable, pass to the sending module 8-bit data enable signal
        3. tx_data, 8-bit data to be sent
        4. tx_clk, send clock
        5. tx_baud, send baud rate
  3. 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)

 

);

  1. 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

  1. 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

  1. Send Modelsim simulation. See Fig 11. 2.

Fig 11. 2 ModelSim simulation waves sent by serial

  1. Extended design (extended content is only reserved for users to think and practice)
  2. Design the transmitter to support 5, 6, 7, 8-bit PHY (Port physical layer)
  3. Support parity check
  4. The settings of the above steps involve FIFO, PLL, etc. (Refer to uart_top project file)

UART accept file design

  1. 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:

  1. Synchronization: refers to how to find the start bit from the received 0101… sync_dtc
  2. Receive start bit (start)
  3. Cyclically receive 8-bit data
  4. 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

  1. 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

  1. The design of rx_buf

Design strategies and steps

  1. Add 256 depth, 8-bit fifo
        1. Read and write clock separation
        2. Asynchronous clear (internal synchronization)
      1. Data appears before the rdreq in the read port
  2. Steps:
  3. Initialization: fifo, rx_phy
  4. Wait: FIFO full signal (wrfull) is 0
  5. Write: Triggered by rx_phy: rx_phy_byte, rx_phy_rdy
  6. End of writing
  7. 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

    1. Receive simulation incentive

Content and steps

      1. tx, rx loopback test (assign rx_in = tx_out)
      2. Continue to use the incentive file in the TX section
      3. 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)

);

    1. ModelSim simulation. See Fig 11. 3.

Fig 11. 3 Simulation

Reflection and expansion

  1. Modify the program to complete the 5, 6, 7, 8-bit design
  2. Completing the design of the resynchronization when the start and stop have errors of the receiving end rx_phy
  3. Complete the analysis and packaging of the receipt frame of rx_buf
  4. Using multi-sampling to design 180° alignment of data, compare with FPGA resources, timing and data recovery effects

Hardware test

      1. Use develop board to test
write a hardware test file
write a hardware test file

Fig 11. 4 USB to serial conversion

Write a hardware test file.

      1. Development board J3 is connected to the host USB interface
        1. Using test software such as teraterm, SSCOM3, etc. You can also write a serial communication program (C#, C++, JAVA, Python…).
        2. PC sends data in a certain format
        3. The test end uses a counter to generate data in a certain format.

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

  1. 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
  1. Observe the data received
  2. Using ILA to observe the data sent by FPGA
  3. See Fig 11. 5, when FPGA sends A0

Fig 11. 5 Sending A0

Fig 11. 6 Data receive by host computer

  1. The receiving part has been eliminated here. You are encouraged to try it on your own.

Related posts