3
\$\begingroup\$

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
\$\endgroup\$
4
\$\begingroup\$

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     |
\$\endgroup\$
  • \$\begingroup\$ @Tweed: Tell me if I misunderstood your remark but I use a shift register to record the sequence of Rx's bits in order to reconstruct the frame. So Rx is still a asynchronous input going through flip-flops (the 8-bit shift-register). \$\endgroup\$ – anotherCode245 Nov 4 '14 at 19:34
  • \$\begingroup\$ A UART uses an oversample clock (e.g. x16) and a framing mechanism to determine which oversample clock to sample the 'middle' of a receive baud (e.g. the 8th oversample clock after Rx goes low during the start bit). A stop bit gives you time to reset the framing for the next start bit. The oversample clock and picking a sample is done every character and is used to deal with wide clock rate differences between Transmit and Receive. Simply double FF filtering isn't enough - you can't do that with the baud clock (9600Hz). \$\endgroup\$ – user8352 Nov 4 '14 at 20:11
  • \$\begingroup\$ @anotherCode245: See my edits above. \$\endgroup\$ – Dave Tweed Nov 4 '14 at 20:30
  • \$\begingroup\$ @Tweed Why is 2x baud rate not sufficient as second rising edge will happen exactly in the middle of the 9600 baud rate ? \$\endgroup\$ – anotherCode245 Nov 4 '14 at 20:53
  • \$\begingroup\$ No, it won't. Remember, we need to assume that the receive clock is completely asynchronous with respect to the transmit clock. They could have any timing relationship whatsoever. \$\endgroup\$ – Dave Tweed Nov 4 '14 at 21:06
3
\$\begingroup\$

It's usual to clock a UART receiver at 4x or 16x the baud rate. That way it can maintain internal synchronization to the edges, and ensure that the bit sample is taken in the middle of the valid period. More advanced designs will take several samples during the period and have them vote on whether the symbol is '1' or '0'.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.