Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
11 years ago

Problem of receiving data from UART RS232

Hello everyone. I am now working on a project and it has to receive data from the COM port (RS232). I have written a receiver in VHDL.

However, the code does not always receive correct data byte but I cannot figure out the problem on the code...

I now paste the process for receiving data and hope that anyone can help for spotting out the problem.

The baud rate used is 115200bit/second and the clock used by the process is 50MHz.

LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_unsigned.all;
entity rs232 is
  port(
    recvdata    :    OUT STD_LOGIC_VECTOR(7 DOWNTO 0);    --received data
    Clock_50M    :    IN    STD_LOGIC;
    RxD            :    IN    STD_LOGIC                        --pin for receiving data
    );
end rs232;
architecture a of rs232 is
    type recv_state is(detect_start, check_start, receiving, detect_finish);
    signal rstate: recv_state:=detect_start;            --state of receiving
    signal rcount: integer range 0 to 434:=0;            --50MHz/115200=434 434 clk cycles=1 bit data
    signal rindex: integer range 0 to 8:=0;
    signal indata: STD_LOGIC_VECTOR (7 DOWNTO 0);        --buffer of received data    
begin
    process(Clock_50M)                                        --process for receiving
    begin
        if (rising_edge(Clock_50M)) then
            case rstate is
                when detect_start =>                    --waiting start signal
                    if(RxD='0') then                    --start signal received
                        rstate<=check_start;            --move to receive state
                        rcount<=0;
                    else
                        rstate<=detect_start;
                        rcount<=0;
                    end if;
                when check_start =>
                    if(rcount=217) then                    --read data at middle (434/2=217)
                        if (RxD='0')then                --still exist start signal
                            rstate<=receiving;
                            rcount<=0;
                        else
                            rstate<=detect_start;
                        end if;
                    else
                        rstate<=check_start;
                    end if;
                when receiving =>
                    if(rcount=217) then                    --read data at middle (434/2=217)
                        if (rindex=7)then                --the 8th bit data is received
                            indata(rindex)<=RxD;
                            rindex<=0;
                            rstate<=detect_finish;
                        else                            --receive the next bit
                            indata(rindex)<=RxD;
                            rindex<=rindex+1;
                            rstate<=receiving;
                            rstate<=receiving;
                        end if;
                    else
                        rstate<=receiving;
                    end if;
                when detect_finish =>                    --wait the finish signal
                    if(rcount=217) then                    --read at middle (434/2=217)
                        if(RxD='1') then
                            rstate<=detect_start;
                            recvdata<=indata;
                        else                            --if no correct finish signal, discard the data
                            rstate<=detect_start;
                        end if;
                    else
                        rstate<=detect_finish;
                    end if;
            end case;
            if(rcount=434) then                                --reset the counter if it reach 434th clock cycle
                rcount<=0;
            else                                            --increase the counter
                rcount<=rcount+1;
            end if;
        end if;
    end process;
end a;

Thank you for checking my code.

8 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    You have a duplicate line in your receiving state, but that is no problem.

    As far as I can tell there is nothing wrong. Are you sure the problem is in this entity?
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    I am sure because I just assign the 'recvdata' to the LEDs with only this entity. When I send 0x33 to the fpga again and again, sometimes it will show 0xF3, 0xF7 which are not correct and 0x33 which is correct.

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    I assume it works ok in simulation, do you send with the same speed, with the same start and stopbits?

    What happens if you always put the indata on rcvdata?
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Same result if I always put the indata on rcvdata.

    It should have same speed with the same start and stop bit as the specification and the program to send data is provided by the course.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Than I am all out of ideas, Maybe someone else can find what's wrong.

    [edit] The input is asynchrone, so you need to synchronise the signal. I don't know if this solves your problem, but it is good practise anyway.[/edit]
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    The data signal can change outside the clock edge.

    The datain signal becomes metastable, it is neither '1' nor '0'. You need it to be stable.

    You can do this very simple, by clocking it trough at least two registers. (Search the web for metastability for more info on this.)

    In this way your data may not be correct, but it is the same troughout the entire circuit.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    What I think is the problem is:

    In check_start, you test at rcount = 217 if RxD = 0. If so, you reset the counter and proceed to receiving. That is a half the bit time. Then you test in receiving at again at rcount=217 that's agiain at half a bit time, so that's around the signal transition of the RxD signal. You should wait a full rcount cycle to test again.