Fallos del receptor UART

3

Encuentro problemas con mi módulo receptor UART. Se supone que funciona a 9600 baudios sin bit de paridad y solo un bit de parada.

El problema es que mi UART pierde algunos caracteres (o para indicar que recibió algunos caracteres) de una manera no determinista.

Mis dos ideas principales pero no exitosas sobre este problema fueron

1) un problema con la recepción con el reloj a 9600Hz, tal vez no sea lo suficientemente preciso o no tengo margen de error. Intenté el muestreo excesivo pero no resolvió el problema.

2) Un problema con el reconocimiento proveniente del exterior (CPU). Uso un pequeño truco con un DFF para que la CPU reconozca correctamente su lectura mientras tiene un reloj mucho más alto que el receptor (50MHz frente a 9600Hz).

Estoy perfectamente seguro de que mi reloj está en 9600Hz (puedo recibir correctamente muchos caracteres).

Aquí está el pequeño código del receptor que utilizo.

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
    
pregunta anotherCode245

2 respuestas

4

Una vez caí en la misma trampa.

Recuerde, la "A" en "UART" significa "asíncrono"! Debe tratar la señal Rx como una entrada asíncrona y sincronizarla con su reloj interno ejecutándola a través de un par de flip-flops antes de hacer cualquier otra cosa con ella.

Tenga en cuenta que en su código (específicamente, if counter = 0 and Rx = '0' then ), la entrada Rx afecta a múltiples flip-flops ( counter ) en paralelo. Puede pensar en los cuatro flip-flops que mantienen el valor de conteo como impulsado por un multiplexor que selecciona (others => '0') o counter + 1 para cargarlos. La señal Rx alimenta la lógica que controla este multiplexor. Si es asíncrono, podría estar cambiando justo cuando llega el borde del reloj. Si esto sucede, algunos de los flip-flops obtendrán bits de un valor, y algunos de ellos obtendrán bits del otro. El resultado será un estado completamente aleatorio.

Pero también, como lo señala David Koontz, realmente necesita remuestrear Rx en la máquina de estados para que pueda asegurarse de que los bits que está cambiando en su registro de desplazamiento NO se muestren cerca de las transiciones. El muestreo excesivo de 4 × se debe considerar como mínimo, y el estándar de facto de la industria es el de sobremuestreo a 16 ×, con "votación" opcional entre múltiples muestras cerca del centro de cada bit para obtener una inmunidad al ruido adicional.

Aquí hay algunos diagramas de tiempo para ayudar a ilustrar el problema que resuelve el sobremuestreo. En cada caso, la línea vertical de '*' representa el punto en el que la máquina de estado reconoce el bit de inicio entrante y las líneas verticales subsiguientes de '|' Representar cuando se muestrean los bits. La señal Rx puede llegar temprano o tarde con respecto al reloj, por lo que se muestran los dos extremos.

Con un reloj de 1 ×, en cualquier extremo, los bits de datos se pueden muestrear muy cerca de donde podrían estar cambiando. Si la fase del reloj de transmisión se desvía un poco con respecto al reloj de recepción, se producirán errores de bits.

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

Con un reloj de 2 ×, el problema con el extremo "tardío" se ha eliminado, pero el problema con el extremo "temprano" permanece. Todavía hay una posibilidad de errores de bits.

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

El reloj 4 × elimina completamente el problema para ambos extremos de tiempo. Los bits se muestrearán en algún lugar entre el 50% y el 75% del período de bits.

                  __   *__    __   |__    __    __    __   |__    __    __   
  4x clock ______/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  
           _______     *           |       ________________|___ __________
  Rx (early)      \____*___________|______X________________|___X__________
                      start        |          data         |       data
           ___________ *           |           ____________|__________ ___
  Rx (late)           \*___________|__________X____________|__________X___
                       *  start    |              data     |
    
respondido por el Dave Tweed
3

Es habitual sincronizar un receptor UART a 4x o 16x la velocidad de transmisión. De esa manera, puede mantener la sincronización interna con los bordes y garantizar que la muestra de bits se tome en la mitad del período válido. Los diseños más avanzados tomarán varias muestras durante el período y harán que voten si el símbolo es '1' o '0'.

    
respondido por el pericynthion

Lea otras preguntas en las etiquetas