Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[SOLVED] Trying to implement UART Transmitter

Status
Not open for further replies.

zrkd51

Newbie level 4
Joined
Nov 13, 2011
Messages
7
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,281
Activity points
1,336
Hello ,
I've been reading a lot of examples of UART codes in VHDL for port RS232, so I wrote my own version, or at least tried, the problem is , I don't get to see a single character when I'm trying to test it with Hyperterminal, I'm using a Nexys2. Am I doing something wrong?
Below, the code, I would appreciate any help, thanks:


Code:
Code:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;




entity main is
    Port ( txd : out  STD_LOGIC := '1';
			  data: inout STD_LOGIC_VECTOR (9 downto 0);
			  clk: in STD_LOGIC;
			  act: inout STD_LOGIC;
			  do: inout STD_LOGIC;
			  swt: in STD_LOGIC_VECTOR (7 downto 0);
			  btn: in STD_LOGIC;
			  led: out STD_LOGIC_VECTOR (7 downto 0));
end main;

architecture Behavioral of main is

begin
led <= swt;
data <= '1' & swt & '0'; --Data Vector

activar: process (clk,btn)
variable cont: integer range 0 to 5000000;
begin
if (rising_edge (clk)) then
	if btn = '1' and cont < 5000000 and do = '0' then
		cont := cont + 1;
		act <= '0';
	elsif btn = '1' and cont >= 5000000 and do = '0' then
			act <= '0';
	elsif btn = '0' and cont < 5000000 and do = '0' then
			cont := 0;
			act <= '0';
	elsif btn = '0' and cont >= 5000000 and do = '0' then
		act <= '1';
		cont := 0;
	end if;
end if;
end process; --Fin Activar


envia: process (act,clk)
variable cont: integer range 0 to 16:=0;
variable cont2: integer range 0 to 8192 := 0;
begin
	if (rising_edge (clk)) then
	 if (cont2 < 5208) then--Counter for 9600 bauds
	 cont2 := cont2 + 1;
	 else
		if (act = '1') then
			if (cont = 0) then
				do <= '1';
				txd <= data (cont);
				cont := cont + 1;
			elsif (cont < 9) then
				txd <= data(cont);
				cont := cont + 1;
			else
				txd <= data(cont);
				cont := 0;
				do <= '0';
			end if;				
		end if;
	 cont2 :=0;
	 end if;
	end if;
end process; 





end Behavioral;
 

You may check : Board clock & clock division logic, UCF file, RS232 cable, Hyperterminal application.
 

RS232 voltage levels? As for cables: there's '1:1 cables' (for example used when connecting a modem to serial port), and nullmodem cable (side A transmit pin goes to receiver pin on side B & vice versa).
 

The easiest way to debug things like this is to use an oscilloscope.
First check if the bits come out correctly from the FPGA, before wasting time debugging Hyperterminal and RS232 cables.
 

Well, thanks for your advice, I'm actually using a USB to Serial adaptor, since my computer does not have a Serial Port, is there any way to test if it's working all right? Or at least know if it is a Null or Direct Cable?
 

Well, thanks for your advice, I'm actually using a USB to Serial adaptor, since my computer does not have a Serial Port, is there any way to test if it's working all right? Or at least know if it is a Null or Direct Cable?
If you short pin 2 and 3 in the DSUB, all characters you type should be echoed back to the screen. Without the short - no echo.

A null modem cable is easy to recognize, it has female connectors in both ends.
 
  • Like
Reactions: zrkd51

    zrkd51

    Points: 2
    Helpful Answer Positive Rating
Ok, so I'm gonna test it as soon as I can, according to the reference Manual of the board, it should worked with a direct cable if it is connected to a computer, I suppose, the USB-Serial adapter, is a direct cable, still I'm not sure, thanks for your help, oh , and another question, Is my code doing serial transmission actually?
 

So, I was thinking, maybe I'm calculating the counter, the wrong way, I'm not really sure, I have a 50 Mhz clock, so if I want a 9600 bps, I have to divide (50 Mhz /9600 Hz) - 1 right? , Or Am I doing something wron?
 

Hi! I dont have much knowledge of VHDL but I cant see where do you form a start bit? data(0) keeps always 0? what is your frame format (STARTBIT(always "0")_NUMBEROFDATABITS(7 or 8 bits)_PARITYBIT(none or even or odd)_STOPBIT(1 or 2 bits, always "1"s))?

I wrote uart rx/tx for 115200 using Verilog, and programed my Nexys2 board with it. To connect my board with computer I've tried two different adapters. The first one is a express usb card and the second one is a usb-to-rs232 converter both of them work fine. Also null-modem cable is needed (female in both ends) between board and your adapter.

So, I was thinking, maybe I'm calculating the counter, the wrong way, I'm not really sure, I have a 50 Mhz clock, so if I want a 9600 bps, I have to divide (50 Mhz /9600 Hz) - 1 right?

Yes you are right. 9600 means your symbol duration time is 1/9600 = 104167 ns. With on-board 50MHz clock generator your counter should count until 104167ns / 20ns = 5208.35 -> 5209 (from 0 to 5208) as you've written in your code...

And...
elsif btn = '0' and cont >= 5000000 and do = '0' then
act <= '1';
cont := 0;
When you release btn and cont >= 5000000 registred act goes "1"...


if (cont2 < 5208) then--Counter for 9600 bauds
cont2 := cont2 + 1;
else
if (act = '1') then
if (cont = 0) then
do <= '1';
txd <= data (cont);
cont := cont + 1;
... but the probability that cont2 will have 5208 when act = 1 is very very small ... so at the next clock edge..
elsif btn = '0' and cont < 5000000 and do = '0' then
cont := 0;
act <= '0';
...act returns to 0.. so nothing work?
 
Last edited:
  • Like
Reactions: zrkd51

    zrkd51

    Points: 2
    Helpful Answer Positive Rating
I don't see how you think this is going to work.

For one, you are doing things at the rated baud rate (50000000/5208) is indeed 9600, which is nice and all. But since your 50 MHz system clock is not synchronous with the remote clock you are guaranteed to miss the start bit, and practically everything else. :p

The general approach is to use oversampling. This is done by a FSM that runs at a multiple of the baud rate. See this here example for the baud generator.
 

Good point. I was indeed thinking RX. Time for coffee.

Regardless of my decaffeinated state, I still suggest taking a look at that fpga4fun UART.
 

Well thanks for all your replies, they all have been helpful, I was able to complete de Serial Transmitter, finally, so, now I'm going with the receiver, my teacher said it was optional, but I want to try, I've been reading some examples, so it says the oversampling should be done, with a clock signal 8 times faster, besides some documents says 16, I guess it's better using 16, well my question comes, from the part when I have to sync signals, I'm not really clear with that. Could someone help me, to figure out how to start?
 

Well thanks for all your replies, they all have been helpful, I was able to complete de Serial Transmitter, finally, so, now I'm going with the receiver, my teacher said it was optional, but I want to try, I've been reading some examples, so it says the oversampling should be done, with a clock signal 8 times faster, besides some documents says 16, I guess it's better using 16, well my question comes, from the part when I have to sync signals, I'm not really clear with that. Could someone help me, to figure out how to start?

Your oversampling process should wait for the '1' to '0' transition on the rx data line. That is the beginning of the start bit.
The rest of the reception for that byte is done just by sampling in the middle of each bit, including the start bit and the stop bit.
This means that the first delay is half a bit to get into the middle of the start bit. After that, each delay is one bit long.
If you see a '1' as the start bit, it is called a "false start bit". The reception is cancelled and the receive state machine is restarted to look for a new '1' to '0' transition..
If you see a '0' as the stop bit, it is a "framing error". A normal UART accepts the byte, but it is tagged with an error flag. Your UART can throw away the data.

16 is the most common oversampling ratio, and the sampling in the middle of each bit is normally a majority vote from 3 consecutive samples.
You can skip the majority voting.You don't have to use 16 as the oversampling ratio. The minimum integer oversampling ratio is 3.
 
  • Like
Reactions: zrkd51

    zrkd51

    Points: 2
    Helpful Answer Positive Rating
Up to this moment, this is what I've written, well it is not functional, I would really appreciate some sugestions, the signal rxclk, is the clock 8x, guessing I'm dividing it the right way tx_clk/8, to have my counter, following what std_match said, this is what I have. rx_in, is the input from the UART, cont1 and cont2 are the counters cont1 to count the 8 clock cycles, and cont2, to count the bit that is been written.


Code:
receptor:
process (rxclk)
variable cont1: integer range 0 to 8;
variable cont2: integer range 0 to 16;
variable busy : STD_LOGIC;
--variable exito: STD_LOGIC;
begin
if rising_edge (rxclk) then

	if (falling_edge (rx_in) and busy ='0') then
		busy := '1';
	end if;
	
	if (cont2 = 0) then
		if (cont1 = 0 AND busy = '1') then
			cont1 := cont1 + 1;
			
		elsif (cont1 /= 3) then
			cont1 := cont1 +1;
			
		elsif (cont1 = 3) then
			if rx_in = '0' then 
				cont2 := cont2 + 1;
				cont1 := 0;
				
			else
				busy := '0';
				cont1 := 0;
				cont2 := 0;
			end if;
			
	elsif (cont2 > 0 AND cont2 < 9) then
		if (cont1 < 7) then
			cont1 := cont1 + 1;
		else
			rx_reg (cont2 - 1) <= rx_in;
			cont2 := cont2 + 1;
			cont1 := 0;
		end if;
		
	elsif (cont2 = 9) then
		if (cont1 < 7) then
			cont1 := cont1 + 1;
		else 
			--if (rx_in = '1') then
			 led <= rx_reg;
			 busy := '0';
		 end if;	
	end if;	
		
end if;
 
Last edited:

Here are some comments to put you in the right direction:

1. Minimize the number of clocks and clock domains.

In simulation, it is easy use a lot of different clocks, but that is not the case in a real circuit. Use the same clock as for the transmitter, and use "clock enable" instead. Here is an example for "clock enable":

[VHDL] -- here is our clock enable module. We will take the incoming clock, lets say 1 - Pastebin.com

Please note that "clock enable" is not the same as "clock gating".


2. You can't detect the start bit with "falling_edge".

"rising_edge" and "falling_edge" are for the clock that drives the process. You must detect the edge by delaying the "rx_in" signal and look for a "10" pattern:

Code:
  rx_in_d <= rx_in;
  if(rx_in_d = '1' and rx_in = '0') then
    -- falling edge detected


3. rx_in must be syncronized

To avoid problem caused by metastability, all asynchronous signals that enter a clock domain should be clocked thru 2 or 3 registers before they are used. You can do this in the UART receiving process or in a separate process.

---------- Post added at 15:04 ---------- Previous post was at 14:07 ----------


I used Google to find the example, but it is buggy. Code is missing for incrementing and wrapping "count".

Some more comments:

4. Clocked processes normally need a reset.


5. Use "unsigned" and "signed" from numeric_std instead of "integer" for signals.

The synthesis tools can do more checks.
Other designers may disagree about this.


6. Use "signal" instead of "variable" for physical signals.

This is not always true.
It is easier to understand what the tools will do if you use signals.
It is sometime easier to minimize the latency with variables.
Variables should be used for "virtual" signals that only exist during one evaluation
(no memory from the previous clock cycle).
 
  • Like
Reactions: zrkd51

    zrkd51

    Points: 2
    Helpful Answer Positive Rating
Code:
rx_reg (cont2 - 1) <= rx_in;
Don't access individual bits in a vector using an index if you can avoid it.
For the UART transmitter and receiver, it is better to use shift registers.

For the receiver, this means that you always copy "rx_in" to the same bit.
For the transmitter, "txd" will always be set from the same bit.

It may not be obvious, but the synthesized result will probably be simpler and use less resources in the FPGA.
I doubt that the tools are intelligent enough to optimize your current code to the same end result.
 
  • Like
Reactions: zrkd51

    zrkd51

    Points: 2
    Helpful Answer Positive Rating
Well, I managed to make the Transmitter as well as the receiver on time haha, so thanks to all your helpful comments, I will set this thread to SOLVED, thanks again.
 

Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top