Electronic – UART Receiver glitches

uartvhdl

I encounter problems with my UART receiver module. It is supposed to work at 9600 bauds without parity bit and only one stop bit.

The problem is that my UART misses some characters (or to indicate that it received some characters) in a non-deterministic way.

My two main but unsucessful ideas about this problem were

1) a problem with the reception with the clock at 9600Hz, it is maybe not accurate enough or I don't have any error margin. I tried oversampling but it did not solve the problem.

2) A problem with the acknowledge coming from the outside (CPU). I use a little trick with a DFF to let the CPU acknowledge correctly his reading while having a much higher clock that the receiver (50MHz vs 9600Hz).

I am perfectly sure that my clock is at 9600Hz (I am able to receive correctly a lot of characters).

Here is the small code of the receiver I use.

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity UART_Receive is
    port(
        clk_9600Hz   : in std_logic;
        reset_n      : in  std_logic;
        ackNewData   : in  std_logic;
        ready        : out std_logic;
        dataToRead   : out std_logic_vector(7 downto 0);
        Rx           : in  std_logic
    );
end entity UART_Receive;

architecture RTL of UART_Receive is
    signal counter     : unsigned(3 downto 0);
    signal buffer_read : std_logic_vector(7 downto 0);
    signal lastData    : std_logic_vector(7 downto 0);
    signal newDataReady: std_logic;
begin
    dataToRead <= lastData;

    process(ackNewData, newDataReady)
    begin
        if(ackNewData = '1') then
            ready <= '0';
        elsif(rising_edge(newDataReady)) then
            ready <= '1';
        end if;
    end process;

    process(clk_9600Hz, reset_n) is
    begin
        if reset_n = '0' then
            lastData    <= (others => '0');
            counter     <= (others => '0');
            buffer_read <= (others => '0');

        elsif rising_edge(clk_9600Hz) then
            if counter = 0 and Rx = '0' then
                counter <= counter + 1;
            elsif counter = 9 then
                counter  <= (others => '0');
                lastData <= buffer_read;
                newDataReady <= '1';
            elsif counter /= 0 then
                buffer_read <= Rx & buffer_read(7 downto 1);
                counter     <= counter + 1;
            end if;

        end if;
    end process reg_slow_process;

end architecture RTL

Best Answer

I once fell into the same trap myself.

Remember, the "A" in "UART" means "asynchronous"! You need to treat the Rx signal as an asynchronous input, and synchronize it to your internal clock by running it through a pair of flip-flops before you do anything else with it.

Note that in your code (specifically, if counter = 0 and Rx = '0' then), the Rx input affects multiple flip-flops (counter) in parallel. You can think of the four flip-flops that hold the count value as being driven by a multiplexer that selects either (others => '0') or counter + 1 to be loaded into them. The Rx signal feeds the logic that drives this multiplexer. If it is asynchronous, it could be changing just as the clock edge arrives. If this happens, some of the flip-flops will get bits from one value, and some of them will get bits from the other. The result will be a completely random state.

But also, as David Koontz points out, you really need to oversample Rx in the state machine so that you can ensure that the bits you're shifting into your shift register are NOT sampled close to the transitions. 4× oversampling should be considered a minimum, and the de-facto industry standard is to oversample at 16×, with optional "voting" among multiple samples near the center of each bit for extra noise immunity.

Here are some timing diagrams to help illustrate the issue that oversampling solves. In each case, the vertical line of '*' represents the point at which the state machine recognizes the incoming start bit, and the subsequent vertical lines of '|' represent when the bits are sampled. The Rx signal can arrive early or late with respect to the clock, so both extremes are shown.

With a 1× clock, at either extreme, the data bits might be sampled very close to where they might be changing. If the transmit clock phase drifts a bit with respect to the receive clock, bit errors will occur.

                  ______       *______       |______       |______
  1x clock ______/      \______/      \______/      \______/      \______
           _______             * ____________| ____________| _____________
  Rx (early)      \____________*X_____________X_____________X_____________
                      start    *    data     |    data     |    data
           ___________________ *             |____________ |____________ 
  Rx (late)                   \*____________X_____________X_____________X
                               *    start    |    data     |    data

With a 2× clock, the problem with the "late" extreme has been eliminated, but the problem with the "early" extreme remains. There's still a possibility of bit errors.

                  ___    *___    |___     ___    |___     ___    |___    
  2x clock ______/   \___/   \___/   \___/   \___/   \___/   \___/   \___
           _______       *       | ______________| ______________| _______
  Rx (early)      \______*_______|X______________|X______________|X_______
                      start      |    data       |    data       |    data
           _____________ *       |       ________|______ ________|______ _
  Rx (late)             \*_______|______X________|______X________|______X_
                         *  start|          data |          data |

The 4× clock completely eliminates the problem for both timing extremes. The bits will be sampled somewhere between 50% and 75% of the bit period.

                  __   *__    __   |__    __    __    __   |__    __    __   
  4x clock ______/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  
           _______     *           |       ________________|___ __________
  Rx (early)      \____*___________|______X________________|___X__________
                      start        |          data         |       data
           ___________ *           |           ____________|__________ ___
  Rx (late)           \*___________|__________X____________|__________X___
                       *  start    |              data     |
Related Topic