UPGRADE YOUR BROWSER

We have detected your current browser version is not the latest one. Xilinx.com uses the latest web technologies to bring you the best online experience possible. Please upgrade to a Xilinx.com supported browser:Chrome, Firefox, Internet Explorer 11, Safari. Thank you!

cancel
Showing results for 
Search instead for 
Did you mean: 
Highlighted
Visitor losspost
Visitor
1,286 Views
Registered: ‎12-02-2018

Usb Communication via RS 232 ?

Jump to solution

Hello.

I am currently trying to connect my PC to my FPGA. I only want to send some text to the board and back but I am Stuck. I first checked if the pin assingment is correct but this seems fine so far. I choose the correct port on my terminal. If I send a letter the RXD led blinks red for a second. But still my Programm doesnt seem to work, it doesnt get any data. Any idea what I can change?

 

module UART(clk,uart_rxd,uart_txd,uart_cts,uart_rts,led_out);



	input clk;
	input uart_rxd;
	output uart_txd;
	//Clear to send
	inout uart_cts;
	//Request to send;
	inout uart_rts; 
	
	output[7:0] led_out;
	
	
	
	localparam baud_counter_value = 5208;
	//localparam baud_counter_value = 2500000;
	reg[10:0] baud_counter;
	//BaudClock
	reg baud_clock_reg;
	wire baud_clock;
	//Inital CTS/RTS register
	reg cts;
	reg rts;
	
	//Data Register
	reg[7:0] data;
	
	//LED Test Register
	reg[7:0] led;
	
	//Counter
	reg counter;
	
	
	//Uart State Register
	localparam
		s_IDLE = 0,
		s_SEND_CLEAR = 1,
		s_SEND = 2,
		s_RECEIVE = 3,
		s_TEST = 4;
		
	reg[4:0] state;
		
		
	
	
	initial begin
		//Initialize Baud Clock
		baud_clock_reg = 0;
		baud_counter = 10'b0;
		cts = 0;
		//rts = 0;
		data = 8'b0;
		led = 8'b0;
		counter = 0;
		//Inital state
		state = 0;
		
	end
	
//Creating a Baud Clock Baudrate = 115200	
/*-------------------------------------------------------------------*/			
	always@(posedge clk) begin
	
		if(baud_counter == baud_counter_value) begin
			baud_clock_reg <= !baud_clock_reg;
			baud_counter = 0;
		end else begin
			baud_counter = baud_counter +1;
		end
	
	end	
/*-------------------------------------------------------------------*/			
//Getting Request from PC to receive Data
/*-------------------------------------------------------------------*/			
	always@(posedge baud_clock) begin
	
		case(state) 
		
			s_IDLE: begin
				//If Host Request to send Data
				
				led <= 8'b00110011;
				if(uart_rts == 0) begin
				led <= 8'b11111111;
					state <= s_SEND_CLEAR;
				end
			end
			
			s_SEND_CLEAR: begin
			//Signal Host That the device is read to receive
				led <= 1;
				cts <= 1;
				state <= s_RECEIVE;
			end
			//Receive the Data
			s_RECEIVE: begin
				//Setting Least Significant Bit
				data <= uart_rxd;
				//Shift 0 bit one to the Left 
				data[0] <= data << 1;
				counter = counter + 1;
			
				if(counter == 10) begin
					
					state <= s_TEST;
				end
			end
			
			s_TEST: begin
				led <= data;
			
			end
		endcase
		
	end

/*-------------------------------------------------------------------*/			


	//Update Baud Clock Signal
	assign baud_clock = baud_clock_reg;
	assign uart_cts = cts;
	assign uart_rts = rts;
	assign led_out = led;


endmodule
0 Kudos
1 Solution

Accepted Solutions
1,251 Views
Registered: ‎01-22-2015

Re: Usb Communication via RS 232 ?

Jump to solution

@losspost

Welcome to the Xilinx Forum!

-good start on writing HDL to read data from a serial communications port !

Here’s some thoughts that might help you get things going.

  1. First, bear with me. I am a VHDL programmer with poor knowledge of Verilog. Hopefully, any VHDL terminology that I use here won’t confuse you.
  2. USB is not the same as RS232. However, you can buy USB-to-RS232 convertors (eg. from <here>). I will assume you have done this are using the FPGA to read data from RS232.
  3. Put an oscope on the RS232 line, RXD, that brings data into your FPGA. Ensure that voltage levels on RXD are compatible with the IO standard you are using on the FPGA-pin that receives RXD.
  4. I see that RXD becomes uart_rxd in your HDL. Before this signal reaches your UART module, you should run it through a 2-flip-flop synchronizer. This is necessary to prevent metastability since uart_rxd is toggling asynchronously with the clocks in your FPGA.
  5. I don’t know frequency of your clock called clk. So, in your UART module, I will assume you have divided-down clk properly so that baud_clock is toggling at 115200 Hz, which is appropriate for a RS232 baud rate of 115200 bits-per-second (bps). This baud_clock is not actually a clock, rather it is a signal (also called a toggle) in the “clk” clock-domain.
  6. Instead of toggling baud_clock at the RS232 baud rate, I recommend that you toggle baud_clock at eight-times the RS232 baud rate (for reasons described below).
  7. In your procedure that begins with “always@(posedge baud_clock) begin”, I recommend that you instead use “always@(posedge clk) begin”.  Thus, this procedure will be clocked by a “real” clock (and not a toggle). Also, I recommend that the flow of this procedure go as follows:
    1. Wait to see an edge on uart_rxd that corresponds to RS232 start-bit.
    2. Count 4 tics of baud_clock and then read the start bit from uart_rxd into your data[0]. By waiting 4 tics of baud_clock before reading uart_rxd, you are doing what is called “sampling the RXD data in the middle of the data-eye”.
    3. Left-shift data[.] by 1 – as you are doing.
    4. Count 8 tics of baud_clock and then read the next bit from uart_rxd into data[0].
    5. Continue cycling through the last two steps until you have read all (10?) bits from the RS232 data packet. The number of bits in the RS232 packet will depend on how many start-bits, stop-bits, and parity-bits you have specified for the RS232 port.
    6. Return to the first step and wait for start of next RS232 packet.

-let me know how things turn out.

Mark

Tags (1)
9 Replies
1,252 Views
Registered: ‎01-22-2015

Re: Usb Communication via RS 232 ?

Jump to solution

@losspost

Welcome to the Xilinx Forum!

-good start on writing HDL to read data from a serial communications port !

Here’s some thoughts that might help you get things going.

  1. First, bear with me. I am a VHDL programmer with poor knowledge of Verilog. Hopefully, any VHDL terminology that I use here won’t confuse you.
  2. USB is not the same as RS232. However, you can buy USB-to-RS232 convertors (eg. from <here>). I will assume you have done this are using the FPGA to read data from RS232.
  3. Put an oscope on the RS232 line, RXD, that brings data into your FPGA. Ensure that voltage levels on RXD are compatible with the IO standard you are using on the FPGA-pin that receives RXD.
  4. I see that RXD becomes uart_rxd in your HDL. Before this signal reaches your UART module, you should run it through a 2-flip-flop synchronizer. This is necessary to prevent metastability since uart_rxd is toggling asynchronously with the clocks in your FPGA.
  5. I don’t know frequency of your clock called clk. So, in your UART module, I will assume you have divided-down clk properly so that baud_clock is toggling at 115200 Hz, which is appropriate for a RS232 baud rate of 115200 bits-per-second (bps). This baud_clock is not actually a clock, rather it is a signal (also called a toggle) in the “clk” clock-domain.
  6. Instead of toggling baud_clock at the RS232 baud rate, I recommend that you toggle baud_clock at eight-times the RS232 baud rate (for reasons described below).
  7. In your procedure that begins with “always@(posedge baud_clock) begin”, I recommend that you instead use “always@(posedge clk) begin”.  Thus, this procedure will be clocked by a “real” clock (and not a toggle). Also, I recommend that the flow of this procedure go as follows:
    1. Wait to see an edge on uart_rxd that corresponds to RS232 start-bit.
    2. Count 4 tics of baud_clock and then read the start bit from uart_rxd into your data[0]. By waiting 4 tics of baud_clock before reading uart_rxd, you are doing what is called “sampling the RXD data in the middle of the data-eye”.
    3. Left-shift data[.] by 1 – as you are doing.
    4. Count 8 tics of baud_clock and then read the next bit from uart_rxd into data[0].
    5. Continue cycling through the last two steps until you have read all (10?) bits from the RS232 data packet. The number of bits in the RS232 packet will depend on how many start-bits, stop-bits, and parity-bits you have specified for the RS232 port.
    6. Return to the first step and wait for start of next RS232 packet.

-let me know how things turn out.

Mark

Tags (1)
Visitor losspost
Visitor
1,221 Views
Registered: ‎12-02-2018

Re: Usb Communication via RS 232 ?

Jump to solution

Hi Thank your for your help.
I've implemented your ideas so far. What I haven't quite understood yet is what you mean by the text length using the start/stop bit. I thought the flow control is controlled by CTS and RTS. And I get different outputs but they have nothing to do with the real value?!The same input sometimes give out different values

 

module UART(clk,uart_rxd,uart_txd,uart_cts,uart_rts,led_out);



	input clk;
	input uart_rxd;
	output uart_txd;
	//Clear to send
	inout uart_cts;
	//Request to send;
	inout uart_rts; 
	
	output[7:0] led_out;
	
	
	//8 times the Baud Freq.
	localparam baud_counter_value = 5208/8;
	//localparam baud_counter_value = 2500000;
	reg[14:0] baud_counter;
	//BaudClock
	reg baud_clock_reg;
	wire baud_clock;
	//Inital CTS/RTS register
	reg cts;
	reg rts;
	
	//Data Register
	reg[7:0] data;
	
	//LED Test Register
	reg[7:0] led;
	
	//Counter
	reg[32:0] counter;
	
	
	//Uart State Register
	localparam
		s_IDLE = 0,
		s_DELAY = 1,
		s_DELAY_RESET =2,
		s_SEND = 3,
		s_RECEIVE = 4,
		s_TEST = 5,
		s_RECEIVE_DELAY_RESET=6;
		
	reg[4:0] state_uart;
		
	//Baud Delay Counter
	//Because baud_clock is baud_clock * 8. We have to wait 8 baud_clocks for 1 baud bid at 9600baud/s
	reg baud_delay;
	reg[4:0] baud_delay_counter;
	reg delay;
	
	initial begin
		//Initialize Baud Clock
		baud_clock_reg = 0;
		baud_counter = 14'b0;
		cts = 0;
		rts = 0;
		data = 8'b0;
		led = 8'b00000001;
		counter = 0;
		baud_delay = 0;
		baud_delay_counter = 4'b0;
		//Inital state
		state_uart = s_IDLE;
		
	end
	
//Creating a Baud Clock Baudrate = 9600	
/*-------------------------------------------------------------------*/			
	always@(posedge clk) begin
		
		if(baud_counter == baud_counter_value-1) begin
			baud_clock_reg <= !baud_clock_reg;
			baud_counter = 0;
		end else begin
			baud_counter <= baud_counter +1;
		end
	
	end	
	

/*-------------------------------------------------------------------*/
//Baud Delay Counter
/*-------------------------------------------------------------------*/
	always@(posedge baud_clock && baud_delay == 1) begin
		case(state_uart)
			s_DELAY: begin
				baud_delay_counter <= baud_delay_counter +1;	
				if(baud_delay_counter == 4) begin
					baud_delay_counter <= 0;
				end
			end
			s_RECEIVE: begin
				baud_delay_counter <= baud_delay_counter +1;
				if(baud_delay_counter == 8) begin
					baud_delay_counter <= 0;
				end
			end
			s_DELAY_RESET: baud_delay_counter <= 0;
			s_RECEIVE_DELAY_RESET: baud_delay_counter <=0;
		endcase
		
	end


/*-------------------------------------------------------------------*/			
//Getting Request from PC to receive Data
/*-------------------------------------------------------------------*/			
	always@(posedge clk) begin
	
		case(state_uart) 
		
			s_IDLE: begin
				//If Host Request to send Data
			
				//Waiting for start bit
				if(uart_rxd == 0) begin
					state_uart <= s_DELAY;
				end
			end
			
			s_DELAY: begin
				
				//Wait for 4 Baud Ticks to "sample Data"
				if(baud_delay_counter == 4) begin
					baud_delay <= 0;
					state_uart <= s_DELAY_RESET;
					
				end 
				//Activate Baud Counter
				baud_delay <= 1;
				
				
			end
			
			s_DELAY_RESET: begin
				if(baud_delay_counter == 0) begin
					state_uart <= s_RECEIVE;
				
				end
			end
			//Receive the Data
			s_RECEIVE: begin
				//Waiting for one "real" baud tick
				baud_delay <= 1;
				if(baud_delay_counter == 8) begin
					//Setting Least Significant Bit
					data[0] = uart_rxd;
					//Shift 0 bit one to the Left 
					//= because its only getting executed after the previous line was executed
					data = data << 1;
					counter = counter + 1;
					state_uart <= s_RECEIVE_DELAY_RESET;
				end
				
				if(counter == 8) begin
					baud_delay <= 0;
					state_uart <= s_TEST;
	
				end
			end
			
			s_RECEIVE_DELAY_RESET: begin
				if(baud_delay_counter == 0)begin
					state_uart <= s_RECEIVE;
				end
			end
			
			s_TEST: begin
				led <= data;
				data = 8'b0;
				counter = 0;
			
					
				state_uart <= s_IDLE;
	
			
			end
		endcase
		
	end

/*-------------------------------------------------------------------*/			


	//Update Baud Clock Signal
	assign baud_clock = baud_clock_reg;
	assign uart_cts = cts;
	assign uart_rts = rts;
	assign led_out = led;


endmodule

 

0 Kudos
1,206 Views
Registered: ‎01-22-2015

Re: Usb Communication via RS 232 ?

Jump to solution

@losspost

Sounds like you got things kinda working. Congratulations!

You might want to ignore CTS and RTS and all “flow-control” for now. These can be necessary if you have a fast transmitter talking to a slow receiver, since the receiver may sometimes need to slow up the transmitter by toggling the flow-control lines. This should not be a problem for you since you are sending data to the FPGA – which is definitely not a slow receiver.

RS232 communication consists of packets that have 8-bits data padded on the front by a start-bit(s) and on the back by a parity-bit and stop-bit(s) as shown <here>.   There will be dead-time between these packets where the line idles in the high(1) state. The number of start-bits, stop-bits, and whether-or-not to use a parity bit are things that you must tell the RS232-transmitter.

So, your job is to wait for the start-bit (a high-to-low transition) and then read all the bits (no-more and no-less) from the RS232 packet that follows. -and then wait for the next start-bit.

Mark

0 Kudos
Visitor losspost
Visitor
1,183 Views
Registered: ‎12-02-2018

Re: Usb Communication via RS 232 ?

Jump to solution

markg@prosensing.com

Its almost working. Sadly its receive wrong values. So I decided to send the same signal back which I send to the device. This are the results:

22 -> 0E

2->þ

3425 -> >þ

0 -> þ

It seems like there is a problem with the baud freq.

My FPGA Clock has works at 50Mhz. So i divide it by 9600 to get my counter value, or is this wrong?

0 Kudos
1,171 Views
Registered: ‎01-22-2015

Re: Usb Communication via RS 232 ?

Jump to solution

@losspost

For 9600bps baud rate, your 8x baud_clock needs to have a frequency of (8*9600=76800Hz).  So, if you divide your 50MHz clock by 651 then you get a baud_clock frequency of 76805 Hz, which differs from 76800Hz by less than 0.01%.  Baud clock errors up to 3.0% are usually acceptable.

Mark

0 Kudos
Visitor losspost
Visitor
1,166 Views
Registered: ‎12-02-2018

Re: Usb Communication via RS 232 ?

Jump to solution

markg@prosensing.com

Ok I can see in the simulation why the data i send back doesnt work. But My FPGA shows the wrong value it receives with the led's. But in the simulation I see that the receiving the data works fine in the simulation but not on the real FPGA

 

image.png

0 Kudos
1,146 Views
Registered: ‎01-22-2015

Re: Usb Communication via RS 232 ?

Jump to solution

     …in the simulation I see that the receiving the data works fine..
Good job!

     But My FPGA shows the wrong value it receives with the led's…
Be sure to route the RS232 data through a 2-flip-flop synchronizer before it reaches your UART module as uart_rxd.  Also, for each flip-flop in the synchronizer, set ASYNC_REG= TRUE using constraints like the following in your Vivado XDC constraints file.     
     set_property ASYNC_REG TRUE [ get_cells <netlist name of the flip-flip> ]

These constraints will cause the two flip-flops of the synchronizer to be placed close together - so they act properly as a synchronizer.

0 Kudos
1,118 Views
Registered: ‎01-22-2015

Re: Usb Communication via RS 232 ?

Jump to solution

@losspost

How’s the work going?  If things are still not working, try using an oscope on the RXD line to see if the RS232 transmitter is sending the correct number of bits in each RS232 packet.

FYI – we do almost exactly what you are doing for RS232 communications and run at baud rates near 1Mb/s (over short distances).

Mark

0 Kudos
744 Views
Registered: ‎01-22-2015

Re: Usb Communication via RS 232 ?

Jump to solution

@serano

Welcome to the Xilinx Forum!

     I haven't quite understood yet is what you mean by the text length using the start/stop bit.
The following waveform is from <here> and is typical of what you will see on a RS232 data-line.  Note that the idle state for the RS232 data-line is the high (H) state.

RS232_waveform.jpg

RS232 communication consists of packets that have 8 data-bits and “other” bits.  Bits are sent by simply toggling the data-line to a position (H or L) and holding the data-line in this position for tB seconds.  For example, if the RS232 communication speed is 9600 bits-per-second (bps) then tB = 1/9600 = 0.104ms. 

The RS232 packet in the image above is used to transmit the text character, “U”.  Note how the 8 data-bits (MSB-downto-LSB) are the <ASCII representation>, 01010101, for “U”.  The image shows two “other” bits in the packet called the start-bit and the stop-bit.  The start-bit is simply the data-line toggling out of the idle state.  That is, the start-bit indicates the start of the RS232 packet.  After the start-bit comes the 8 data-bits.  Finally, there is a stop-bit, which is simply the data-line returning to the idle state.  Like all the other bits, the stop-bit lasts for tB seconds and prevents the next RS232 packet from starting immediately.  Thus, the RS232 packet in the image above has 10 bits in total (1-start-bit, 8-data-bits, 1-stop-bit).  Your software needs to save only the 8 data-bits (and can discard the start-bit and stop-bit).

Sometimes you will see an “other” bit in the packet called the parity-bit.  The parity-bit can be used to detect transmission errors (caused by noise) in the 8 data-bits.  You can learn more about this by searching the internet for “RS233 parity bit”.

The RS232 device that is sending data to you must be configured by you.  That is, you must tell the RS232 device several things (or find what default settings it is using for these things):

  • Communication speed in bps (also called baud rate)
  • Do you want to use flow-control (CTS and RTS)?  I suggest NO for now.
  • How many stop-bits do you want? (1 is typical)
  • Do you want the parity-bit?  I suggest NO for now.

    
     I thought the flow control is controlled by CTS and RTS…

You are correct.  However, to keep things simple (for now), I suggest that you turn-off flow-control for your RS232 communications, which means your code can ignore the flow-control lines (CTS and RTS).  Later, flow-control may be necessary if you have a fast transmitter talking to a slow receiver.  That is, the receiver may sometimes need to slow up the transmitter by toggling the flow-control lines.

Cheers,
Mark

Tags (2)
0 Kudos