Search code examples
vhdlfpga

UART Receiver Testbench


I am new to VHDL, and I trying to verify UART receiver how is it works. I synthesized the code below (quoted form the book) and its fine but if needs more let me know :). The frequency for my board is 100 Mhz and the data I want receive is 8 bits, baud rate is 115200, how the clock and tick should be in the testbench or what is the right testbench here?

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.numeric_std.all;
entity uart_rx is
    generic(
        data_bits: integer := 8;      --  #  d a t a   b i t s  
        stop_bit_ticks: integer := 16   --  #  t i c k s   f o r   s t o p   b i t s  
    );
    Port ( rx : in STD_LOGIC;
           clk : in STD_LOGIC;
           reset: in STD_LOGIC;
           tick : in STD_LOGIC;
           rx_done : out STD_LOGIC;
           data_out : out STD_LOGIC_VECTOR (7 downto 0));
end uart_rx;
architecture arch of uart_rx is
    type state_type is (idle, start, data, stop);
    SIGNAL state_reg, state_next: state_type;
    SIGNAL s_reg, s_next: UNSIGNED(3 downto 0);
    SIGNAL n_reg, n_next: UNSIGNED(2 downto 0);
    SIGNAL b_reg, b_next: STD_LOGIC_VECTOR(7 downto 0);
begin
--  FSMD  s t a t e   &  d a t a   r e g i s t e r s  
    process(clk, reset) -- FSMD state and data regs.
    begin
        if (reset = '1') then
            state_reg <= idle;
            s_reg <= (others => '0');
            n_reg <= (others => '0');
            b_reg <= (others => '0');
            --rx_done <= '0';
        --  rx <= '1';
        elsif (clk'event and clk='1') then
            state_reg <= state_next;
            s_reg <= s_next;
            n_reg <= n_next;
            b_reg <= b_next;
        end if;
    end process;
   --  n e x t - s t a t e   l o g i c   &  d a t a   p a t h   f u n c t i o n a l   u n i t s / r o u t i n g
    process (state_reg, s_reg, n_reg, b_reg, tick, rx)
    begin
        state_next <= state_reg;
        s_next <= s_reg;
        n_next <= n_reg;
        b_next <= b_reg;
        rx_done <= '0';
        case state_reg is
        when idle =>
            if (rx = '0') then
            state_next <= start;
            s_next <= (others => '0');
            end if;
        when start =>
            if (tick = '1') then
                if (s_reg = 7) then
                    state_next <= data;
                    s_next <= (others => '0');
                    n_next <= (others => '0');
                else
                    s_next <= s_reg + 1;
                end if;
            end if;
        when data =>
            if (tick = '1') then
                if (s_reg = 15) then
                    s_next <= (others => '0');
                    b_next <= rx & b_reg(7 downto 1);
                    if (n_reg = (data_bits - 1)) then
                        state_next <= stop;
                    else
                        n_next <= n_reg + 1;
                    end if;
                else
                    s_next <= s_reg + 1;
                end if;
            end if;
        when stop =>
            if (tick = '1') then
                if (s_reg = (stop_bit_ticks - 1)) then
                    state_next <= idle;
                    rx_done <= '1';
                else
                    s_next <= s_reg + 1;
                end if;
            end if;
        end case;
    end process;
    data_out <= b_reg; 
end arch;

Solution

  • Typically, UART receivers run at 8 times the bit rate. If your bit rate is 115200, this means a sample rate of 921600. If you are running at 100Mzh, you will need to create a clock divider to get you from 100 MHz to the desired sample rate. To go from 921600 to 100 MHz the following will work:

    100 MHz = 100,000,000 Hz

    921600 samples/sec = 921,600 Hz

    divider = 100,000,000/921,600 = 108.51.

    Thus, you will need a counter that will count up to 109 (we round up as we have to sample at an integer of the clock rate) on rising_edge(clock), then raise an enable signal that tells your component its time to sample the line and reset the counter. The example above assumed 8 samples/bit which is typical to my knowledge. Thus, if you set the period of your main clock in the simulation to be 1ns and set up the counter circuit I described above, you should get the test bench you are looking for.

    EDIT: warning about uneven clock division

    Almost forgot to mention this. Since your clock rate does not divide evenly into the bit rate for the UART, some extra care must be taken when coding up this circuit. Your sample rate will move later and later in the transmission with the scheme I have proposed. You will probably have to add a simple offset to change your counter to 108 on the even bits to keep you more aligned with the incoming data bits.

    See here for some more info: https://electronics.stackexchange.com/questions/42236/uart-receiver-clock-speed