UART communication For Nexys A7-100t

Started by MCU231 3 years ago1 replylatest reply 3 years ago556 views


I'm new to UART for FPGA and recently I tried a demo project that I found at:

My problem is using RxD_data_ready since I know when RxD_data_ready =1 it will allow TxD to finally transmit data to the target but my problem is when I use Putty and when I type anything I never receive data from the FPGA which makes me think RxD_data_ready never equals to one, but when I do type something it will update the led lights of my board (I have my output for GPout to led constraint) so this is telling me that my board does get the targets data but that board can't transmit data to the terminal. Any help is appreciated and I will lay down my top module, Rx_async, Tx_async. Thank you for any help.


module serialGPIO(

    input clk,

    input RxD,

    output TxD,

    output reg [7:0] GPout,  // general purpose outputs

    input [7:0] GPin  // general purpose inputs


// YAYYYY it will work this way below for transmitting

//wire RxD_data_ready =1;

wire [7:0] RxD_data;

wire RxD_data_ready;

async_receiver RX(.clk(clk), .RxD(RxD), .RxD_data_ready(RxD_data_ready), .RxD_data(RxD_data));

always @(posedge clk) 


        GPout <= RxD_data;

async_transmitter TX(.clk(clk), .TxD(TxD), .TxD_start(RxD_data_ready), .TxD_data(GPin));




module async_receiver(

input clk,

input RxD,

output reg RxD_data_ready = 0,

output reg [7:0] RxD_data = 0,  // data received, valid only (for one clock cycle) when RxD_data_ready is asserted

// We also detect if a gap occurs in the received stream of characters

// That can be useful if multiple characters are sent in burst

//  so that multiple characters can be treated as a "packet"

output RxD_idle,  // asserted when no data has been received for a while

output reg RxD_endofpacket = 0  // asserted for one clock cycle when a packet has been detected (i.e. RxD_idle is going high)


parameter ClkFrequency = 25000000; // 25MHz

parameter Baud = 115200;

parameter Oversampling = 8;  // needs to be a power of 2

// we oversample the RxD line at a fixed rate to capture each RxD data bit at the "right" time

// 8 times oversampling by default, use 16 for higher quality reception


if(ClkFrequency<Baud*Oversampling) ASSERTION_ERROR PARAMETER_OUT_OF_RANGE("Frequency too low for current Baud rate and oversampling");

if(Oversampling<8 || ((Oversampling & (Oversampling-1))!=0)) ASSERTION_ERROR PARAMETER_OUT_OF_RANGE("Invalid oversampling value");



reg [3:0] RxD_state = 0;


wire RxD_bit = RxD;

wire sampleNow = 1'b1;  // receive one bit per clock cycle


wire OversamplingTick;

BaudTickGen #(ClkFrequency, Baud, Oversampling) tickgen(.clk(clk), .enable(1'b1), .tick(OversamplingTick));

// synchronize RxD to our clk domain

reg [1:0] RxD_sync = 2'b11;

always @(posedge clk) if(OversamplingTick) RxD_sync <= {RxD_sync[0], RxD};

// and filter it

reg [1:0] Filter_cnt = 2'b11;

reg RxD_bit = 1'b1;

always @(posedge clk)



if(RxD_sync[1]==1'b1 && Filter_cnt!=2'b11) Filter_cnt <= Filter_cnt + 1'd1;


if(RxD_sync[1]==1'b0 && Filter_cnt!=2'b00) Filter_cnt <= Filter_cnt - 1'd1;

if(Filter_cnt==2'b11) RxD_bit <= 1'b1;


if(Filter_cnt==2'b00) RxD_bit <= 1'b0;


// and decide when is the good time to sample the RxD line

function integer log2(input integer v); begin log2=0; while(v>>log2) log2=log2+1; end endfunction

localparam l2o = log2(Oversampling);

reg [l2o-2:0] OversamplingCnt = 0;

always @(posedge clk) if(OversamplingTick) OversamplingCnt <= (RxD_state==0) ? 1'd0 : OversamplingCnt + 1'd1;

wire sampleNow = OversamplingTick && (OversamplingCnt==Oversampling/2-1);


// now we can accumulate the RxD bits in a shift-register

always @(posedge clk)


4'b0000: if(~RxD_bit) RxD_state <= `ifdef SIMULATION 4'b1000 `else 4'b0001 `endif;  // start bit found?

4'b0001: if(sampleNow) RxD_state <= 4'b1000;  // sync start bit to sampleNow

4'b1000: if(sampleNow) RxD_state <= 4'b1001;  // bit 0

4'b1001: if(sampleNow) RxD_state <= 4'b1010;  // bit 1

4'b1010: if(sampleNow) RxD_state <= 4'b1011;  // bit 2

4'b1011: if(sampleNow) RxD_state <= 4'b1100;  // bit 3

4'b1100: if(sampleNow) RxD_state <= 4'b1101;  // bit 4

4'b1101: if(sampleNow) RxD_state <= 4'b1110;  // bit 5

4'b1110: if(sampleNow) RxD_state <= 4'b1111;  // bit 6

4'b1111: if(sampleNow) RxD_state <= 4'b0010;  // bit 7

4'b0010: if(sampleNow) RxD_state <= 4'b0000;  // stop bit

default: RxD_state <= 4'b0000;


always @(posedge clk)

if(sampleNow && RxD_state[3]) RxD_data <= {RxD_bit, RxD_data[7:1]};

//reg RxD_data_error = 0;

always @(posedge clk)


RxD_data_ready <= (sampleNow && RxD_state==4'b0010 && RxD_bit);  // make sure a stop bit is received

//RxD_data_error <= (sampleNow && RxD_state==4'b0010 && ~RxD_bit);  // error if a stop bit is not received



assign RxD_idle = 0;


reg [l2o+1:0] GapCnt = 0;

always @(posedge clk) if (RxD_state!=0) GapCnt<=0; else if(OversamplingTick & ~GapCnt[log2(Oversampling)+1]) GapCnt <= GapCnt + 1'h1;

assign RxD_idle = GapCnt[l2o+1];

always @(posedge clk) RxD_endofpacket <= OversamplingTick & ~GapCnt[l2o+1] & &GapCnt[l2o:0];





module async_transmitter(

input clk,

input TxD_start,

input [7:0] TxD_data,

output TxD,

output TxD_busy


// Assert TxD_start for (at least) one clock cycle to start transmission of TxD_data

// TxD_data is latched so that it doesn't have to stay valid while it is being sent

parameter ClkFrequency = 25000000; // 25MHz

parameter Baud = 115200;


if(ClkFrequency<Baud*8 && (ClkFrequency % Baud!=0)) ASSERTION_ERROR PARAMETER_OUT_OF_RANGE("Frequency incompatible with requested Baud rate");




wire BitTick = 1'b1;  // output one bit per clock cycle


wire BitTick;

BaudTickGen #(ClkFrequency, Baud) tickgen(.clk(clk), .enable(TxD_busy), .tick(BitTick));


reg [3:0] TxD_state = 0;

wire TxD_ready = (TxD_state==0);

assign TxD_busy = ~TxD_ready;

reg [7:0] TxD_shift = 0;


always @(posedge clk)


if(TxD_ready & TxD_start)

TxD_shift <= TxD_data;


if(TxD_state[3] & BitTick)

TxD_shift <= (TxD_shift >> 1);


4'b0000: if(TxD_start) TxD_state <= 4'b0100;

4'b0100: if(BitTick) TxD_state <= 4'b1000;  // start bit

4'b1000: if(BitTick) TxD_state <= 4'b1001;  // bit 0

4'b1001: if(BitTick) TxD_state <= 4'b1010;  // bit 1

4'b1010: if(BitTick) TxD_state <= 4'b1011;  // bit 2

4'b1011: if(BitTick) TxD_state <= 4'b1100;  // bit 3

4'b1100: if(BitTick) TxD_state <= 4'b1101;  // bit 4

4'b1101: if(BitTick) TxD_state <= 4'b1110;  // bit 5

4'b1110: if(BitTick) TxD_state <= 4'b1111;  // bit 6

4'b1111: if(BitTick) TxD_state <= 4'b0010;  // bit 7

4'b0010: if(BitTick) TxD_state <= 4'b0011;  // stop1

4'b0011: if(BitTick) TxD_state <= 4'b0000;  // stop2

default: if(BitTick) TxD_state <= 4'b0000;



assign TxD = (TxD_state<4) | (TxD_state[3] & TxD_shift[0]);  // put together the start, data and stop bits


[ - ]
Reply by mon2November 25, 2020


1) The referenced IP from fpga4fun works. We tested it on an Altera device about a year or so ago. Jean's website is a great learning tool.

2) Believe that you may have the understanding of the receiver & transmitter IP reversed. That is, the transmitter IP is the FPGA transmitting OUT to the 'outside world' which is your remote PC.

3) With the above (2) frame of reference, force a known ASCII character such as "1" = 0x31 into the transmit buffer, then assert the transmit ready flag to force this transmit IP to spit out your "1". Do this repeatedly and monitor the pin you have assigned for the serial TX out pin.

Respectively, if you are monitoring this output with a remote PC - what are you using? Be sure to note that the output from the FPGA are CMOS levels (most likely swinging @ 3v3 for a high; 0v for a low). These ARE NOT RS232 levels. So if you external USB to serial dongle (assuming what you are using) is being used, you MUST, either convert your CMOS level to RS232 level using an external bridge board / IC OR use a CMOS level USB to UART controller - many on the market but recommend the FTDI line for the best compatibility across Windows / Linux / whatever...

If all goes well, you should see a never ending stream of "1" on your remote PC. If not, check your remote PC for the terminal settings. Are they with HARDWARE flow control DISABLED? This is recommended for now since you are just streaming out data from the FPGA on the TX line and soon you will receive data on the RX line on your FPGA. Either way, you are not yet using hardware flow control = typically RTS & CTS lines are used to halt / continue the streaming between 2 parties.

4) You can consider to simulate your IP using EDAplayground or similar tool. Personally still learning but it helps on cases like this one.