2
\$\begingroup\$

I try to implement the following simple UART receiver . The simulations goes fine (image attached). But i encountered some problems in real hardware realization using Nexys 2 board. I try to send a symbol through minicom using the following protocol 1 start bit 8 data bits 1 stop bit 115200 baud rate Also i have 50 Mhz FPGA clock, which i directly use as UART receiver clk. UART counter count to 434 (F = 115200 Hz -> T = 8680 ns -> T = 20 ns * 434) So checking in 233 we will get the center of received bit. While debugging the output of the uart i attached DATA_OUT from receiver to the Nexys board leds.

It seems to me that i get the wrong symbol codes. For example when i send '1' (00110001) i get 10011001 code and so on

'2' 00110010 -> 10011010

'3' 00110011 -> 10011011

'4' 00110100 -> 10011000

So my suggestion is that something is wrong with the VHDL code, but i don't understand what exactly... Can anybody help me please? Thanks.

entity uart_receiver is
 Port ( clk : in STD_LOGIC;
 rx : in STD_LOGIC;
 received : out std_logic;
 en : in STD_LOGIC;
 data_out : out STD_LOGIC_VECTOR (7 down to 0)
 );
end uart_receiver;
architecture Behavioral of uart_receiver is
 signal count : std_logic;
 signal rec : std_logic := '0';
 signal counter : integer range 0 to 433;
begin
 process (clk)
 variable state : integer range 0 to 9 := 0;
 variable data : std_logic_vector (7 downto 0);
 variable rx_p : std_logic;
 begin
 received <= rec;
 if rising_edge(clk) AND en = '1' then
 
 if (rx_p = '1' and rx = '0') then -- 
 count <= '1';
 rx_p := rx;
 else 
 rx_p := rx;
 end if;
 
 if (counter = 216) then
 rec <= '0';
 case (state) is
 when 0 =>
 if (rx = '0') then -- -
 state := 1; 
 else 
 state := 0;
 count <= '0';
 end if;
 when 1 => 
 data(0) := rx; -- 
 state := 2;
 when 2 => 
 data(1) := rx;
 state := 3;
 when 3 => 
 data(2) := rx;
 state := 4;
 when 4 => 
 data(3) := rx;
 state := 5;
 when 5 => 
 data(4) := rx;
 state := 6;
 when 6 => 
 data(5) := rx;
 state := 7;
 when 7 => 
 data(6) := rx;
 state := 8;
 when 8 => 
 data(7) := rx;
 state := 9;
 when 9 => 
 state := 0;
 count <= '0';
 if (rx = '1') then
 data_out <= data; 
 rec <= '1';
 end if;
 end case;
 end if;
 end if;
 end process;
 process (clk)
 begin
 if rising_edge(clk) then 
 if (count = '1') AND (counter < 434) then
 counter <= counter + 1; 
 else 
 counter <= 0;
 end if;
 end if;
end process;

enter image description here

Davide Andrea
30.9k9 gold badges44 silver badges98 bronze badges
asked Oct 3, 2013 at 20:12
\$\endgroup\$
4
  • \$\begingroup\$ Are the results consistently skewed, or does it happen part of the time? \$\endgroup\$ Commented Oct 3, 2013 at 20:49
  • \$\begingroup\$ Are you sure the LEDs are wired up correctly? \$\endgroup\$ Commented Oct 3, 2013 at 22:44
  • \$\begingroup\$ About LEDS - Yes, i tried to output a fixed constant like '00011001' and it's ok. \$\endgroup\$ Commented Oct 4, 2013 at 6:04
  • \$\begingroup\$ About result - I always get the same wrong result when i send '1' for example. \$\endgroup\$ Commented Oct 4, 2013 at 6:09

2 Answers 2

1
\$\begingroup\$

Your implementation looks basically sound. Your 2nd process essentially counts off whole-bit times; then your 1st process detects the leading edge of the start bit, synchronizes the whole-bit counter to that edge, and you then sample the data every time the phase point of the whole-bit counter indicates the middle of the bit has arrived. Implementations vary, but the algorithm is classic - get to the center of the start bit, then sample at regular bit times thereafter.

Your error examples are interesting though. Bearing in mind that the LSB comes first, it looks like your system usually gets the first two, often three bits correct. And in every example, the MSB is incorrectly '1', which suggests the possibility that that '1' is in fact the stop bit.

All in all, it looks quite like a rate problem, specifically, like the sampling rate is just a bit too low compared to the actual data rate. I think I'd try 01000000 for a test vector; if a slow sampling rate is the problem, you're apt to read it as 00100000. Just for laughs you could try dialing down the whole-bit counter range from 434 to say 430 or 425 and see what happens.

And lastly, in the 'have you tried unplugging it and plugging it back in' department, (1) no doubt you've already verified that the oscillator in the real system is in fact the same 50MHz you simulated at, and not something like 48MHz, and (2) you've fed the test signal to some other piece of equipment known to function correctly at 115.2, and vetted that the signal source isn't running fast.

answered Oct 31, 2013 at 2:03
\$\endgroup\$
0
\$\begingroup\$

My experience of UART stuff is normally that some other aspect is wrong. The CTS/RTS pins and possibly some others quite often need to be correctly driven for it to work. I'd suggest a few things:

  • Grab a UART design from OpenCores or similar (or the FPGA vendor may have an IP core for it). Wire that up to your UART and use it as a test-stimulus generator. This will let you verify your design against an existing (hopefully) working one.
  • Get an oscilloscope and have a look at the RX/TX pins etc. and see if the data is coming out in the way you're expecting.
  • There's a number of serial terminal programs that provide a lot more info and configuration options than hyperterm does. That might be of some help while you're debugging
  • answered Oct 4, 2013 at 10:23
    \$\endgroup\$

    Your Answer

    Draft saved
    Draft discarded

    Sign up or log in

    Sign up using Google
    Sign up using Email and Password

    Post as a guest

    Required, but never shown

    Post as a guest

    Required, but never shown

    By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

    Start asking to get answers

    Find the answer to your question by asking.

    Ask question

    Explore related questions

    See similar questions with these tags.