El transmisor Verartog UART envía bytes fuera de orden

7

Tengo el siguiente código Verilog que envía 8 bytes al puerto serie sucesivamente después de presionar un botón.

El problema es que los bytes se envían fuera de orden en cuanto a lo que yo esperaría.

Por ejemplo, si envío los bytes 0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD, 0xBE, 0xEF - la PC obtiene 0xEF, 0xAD, 0xEF, 0xAD y algunas veces no recibe el resto y se cuelga .

He mirado este código muchas veces y parece que no puedo entender por qué esto podría ser. ¿Estoy usando la selección de parte incorrectamente? No lo creo, pero no sé qué otra cosa podría ser el problema.

He adjuntado una segunda versión de este código que funciona (lo que significa que todos los bytes se reciben y están en el orden correcto), pero requiere un ciclo de reloj adicional porque actualiza los datos en el registro de desplazamiento después de cada transmisión. Si puede ver alguna razón por la cual la primera versión publicada no funciona, pero la segunda sí, hágamelo saber.

module transmission_test_2(sysclk, rxd, txd, LED, button);

input sysclk, rxd, button;
output txd;
output reg LED;

wire receiving_complete, isReceiving, isTransmitting, isError;
reg begin_transmit;
reg [7:0] tbyte;

wire [7:0] rbyte;

reg [2:0] state;

reg [63:0] plain_text;

integer byteN;


parameter IDLE = 0, BEGIN_TRANSMISSION = 1, UPDATE_DATA = 2, SEND_BYTES = 3;


uart uart1(
.clk(sysclk),
.rx(rxd),
.tx(txd),
.transmit(begin_transmit),
.tx_byte(tbyte),
.received(receiving_complete),
.rx_byte(rbyte),
.is_receiving(isReceiving), 
.is_transmitting(isTransmitting),
.recv_error(isError)
);


always @(posedge sysclk)
begin
    begin_transmit = 1'b0;
    case(state)
    IDLE: begin
        if(button==1'b0) begin
            LED = 1'b1;
            plain_text = 64'hDEADBEEFDEADBEEF;
            state = BEGIN_TRANSMISSION;
        end else begin
            LED <= 1'b0;
        end
    end
    BEGIN_TRANSMISSION: begin
        tbyte = plain_text[7:0];
        begin_transmit = 1'b1;
        byteN = 1;
        state = SEND_BYTES;
    end
    SEND_BYTES: begin
        if(!isTransmitting) begin
            tbyte = plain_text[byteN*8 +: 8];
            begin_transmit = 1'b1;
            byteN = byteN + 1;
            if(byteN == 8) begin
                state = IDLE;
            end
        end
    end
    endcase
end

endmodule

Segunda versión "de trabajo":

module transmission_test(sysclk, rxd, txd, LED, button);


input sysclk, rxd, button;

output txd;

output reg LED;


wire receiving_complete, isReceiving, isTransmitting, isError;

reg begin_transmit;

reg [7:0] tbyte;


wire [7:0] rbyte;


reg [2:0] state;

reg [63:0] plain_text;

integer bytes_remaining;


parameter IDLE = 0, BEGIN_TRANSMISSION = 1, UPDATE_DATA = 2, SEND_BYTES = 3, DONE = 4;


uart uart1(
.clk(sysclk),
.rx(rxd),
.tx(txd),
.transmit(begin_transmit),
.tx_byte(tbyte),
.received(receiving_complete),
.rx_byte(rbyte),
.is_receiving(isReceiving), 
.is_transmitting(isTransmitting),
.recv_error(isError)
);


always @(posedge sysclk)
begin
    begin_transmit = 1'b0;
    case(state)
    IDLE: begin
        if(button==1'b0) begin
            LED = 1'b1;
            plain_text = 64'hDEADBEEFDEADBEEF;
            state = BEGIN_TRANSMISSION;
        end else begin
            LED <= 1'b0;
        end
    end
    BEGIN_TRANSMISSION: begin
        tbyte = plain_text[7:0];
        begin_transmit = 1'b1;
        bytes_remaining = 7;
        state = UPDATE_DATA;
    end
    UPDATE_DATA: begin
        plain_text = plain_text >> 8;
        state = SEND_BYTES;
    end
    SEND_BYTES: begin
        if(!isTransmitting) begin
            tbyte = plain_text[7:0];
            begin_transmit = 1'b1;
            bytes_remaining = bytes_remaining - 1;
            if(bytes_remaining == 0) begin
                state = IDLE;
            end else begin
                state = UPDATE_DATA;
            end
        end
    end
    endcase
end

endmodule

REVISION:

Siguiendo los consejos de @dwikle, en lugar de usar un estado "catch-all" que alterna el envío de los 8 bytes, creé un estado separado para cada byte que se debía enviar.

Aquí está el código:

module transmission_test_3(sysclk, rxd, txd, LED, button);

input sysclk, rxd, button;
output txd;
output reg LED;

wire receiving_complete, isReceiving, isTransmitting, isError, reset;
reg begin_transmit;
reg [7:0] tbyte;

wire [7:0] rbyte;

reg [2:0] state = 4'b0;
reg [63:0] plain_text = 64'h0;

uart uart1(
.clk(sysclk),
.rst(reset),
.rx(rxd),
.tx(txd),
.transmit(begin_transmit),
.tx_byte(tbyte),
.received(receiving_complete),
.rx_byte(rbyte),
.is_receiving(isReceiving), 
.is_transmitting(isTransmitting),
.recv_error(isError)
);

always @(posedge sysclk)
begin
    begin_transmit = 1'b0;
    case(state)
    4'b0000: begin
        if(button==1'b0) begin
            LED = 1'b1;
            plain_text = 64'hDEADBEEFAAABACAD;
            state = 4'b0001;
        end else begin
            LED = 1'b0;
        end
    end
    4'b0001: begin
        tbyte = plain_text[7:0];
        begin_transmit = 1'b1;
        state = 4'b0010;
    end
    4'b0010: begin
        if(!isTransmitting) begin
            tbyte = plain_text[15:8];
            begin_transmit = 1'b1;
            state = 4'b0011;
        end
    end
    4'b0011: begin
            if(!isTransmitting) begin
                tbyte = plain_text[23:16];
                begin_transmit = 1'b1;
                state = 4'b0100;
            end
        end
    4'b0100: begin
        if(!isTransmitting) begin
            tbyte = plain_text[31:24];
            begin_transmit = 1'b1;
            state = 4'b0101;
        end
    end
    4'b0101: begin
        if(!isTransmitting) begin
            tbyte = plain_text[39:32];
            begin_transmit = 1'b1;
            state = 4'b0110;
        end
    end
    4'b0110: begin
        if(!isTransmitting) begin
            tbyte = plain_text[47:40];
            begin_transmit = 1'b1;
            state = 4'b0111;
        end
    end
    4'b0111: begin
        if(!isTransmitting) begin
            tbyte = plain_text[55:48];
            begin_transmit = 1'b1;
            state = 4'b1000;
        end
    end
    4'b1000: begin
        if(!isTransmitting) begin
            tbyte = plain_text[63:56];
            begin_transmit = 1'b1;
            state = 4'b0000;
        end
    end
    endcase
end
endmodule

Sin embargo, los resultados siguen siendo los mismos: recibo todos los demás bytes. ¿Qué da?

¿Alguna idea?

P.S. - He publicado el código UART en mis documentos de Google - si necesita echar un vistazo. :)

módulo UART

ACTUALIZAR :

La pregunta original para este hilo provino de intentar aislar un problema de comunicación en un módulo más grande.

El proyecto simplemente acepta datos de 64 bits (8 bytes) de la PC (cifra los datos con el algoritmo DES) y envía el mensaje cifrado (de nuevo, 64 bits) nuevamente.

La transferencia funciona, pero (lo que parece ser arbitrariamente) cuelga. Al intentar hacer 1000 encriptaciones, en promedio puedo manejar alrededor de 250, a veces haciendo las 1000 correctamente, y otras veces solo 20 o 50.

Pensé que la transferencia era un cuello de botella en el lado de la transmisión de la comunicación, que era cuando estaba reescribiendo la transmisión y, por lo tanto, el propósito de este hilo. Sin embargo, me he dado cuenta de que el problema reside en el lado de la recepción de la transferencia. Lo que parece estar sucediendo es que después de realizar varias ejecuciones exitosas, la máquina de estado recolecta 7 bytes nuevamente y de alguna manera pierde el último byte del fragmento de 64 bits y se queda atascado en el estado buscando el último byte.

He intentado simular el diseño, pero siento que el estímulo que ofrezco no es muy kosher. El banco de pruebas debe enviar datos por valor de 8 bytes a través de la uart, y luego la máquina de estado debe seguir adelante, cifrando y enviando el mensaje.

Sin embargo, proporcionar diferentes vectores de datos a la línea de rx de la uart da resultados drásticamente diferentes. Dependiendo de los datos que estoy usando, el uart a veces recibe solo 7 bytes (que es el problema que estoy viendo con hardware real) o incluso devuelve errores.

Por lo tanto, los problemas que estoy tratando de resolver son:

1) Puedo recibir y transmitir con éxito varias decenas a cientos de cifrados, pero la comunicación se cuelga en puntos arbitrarios, y parece ser que cuando esto sucede, la máquina de estado ha recopilado 7 bytes y está buscando lo último. .

2) Para diagnosticar este problema, intenté ver los resultados de la simulación. Sin embargo, incluso estos parecen dar un comportamiento inesperado, y me temo que quizás esté dando estímulos incorrectamente.

Cualquier comentario o sugerencia para la implementación del banco de pruebas, o lo que pueda estar causando el cese de la comunicación sería muy apreciado. Si estas preguntas parecen elementales, me disculpo, todavía estoy aprendiendo.

He adjuntado un archivo zip en mis documentos de Google con todos los archivos relevantes, incluido el banco de pruebas.

enlace

También publicaré el módulo de nivel superior aquí como referencia.

module rs232_neek(sysclk, rxd, txd, reset, LED);

input sysclk, rxd, reset;
output txd;
wire receiving_complete, isTransmitting, isReceiving, isError;

output reg [3:0] LED;   //The LEDs are used simply as debug - to determine which state the machine gets held-up in.

reg begin_transmit;
reg [7:0] tbyte;

wire [7:0] rbyte;

parameter FIRST_BYTE = 0, GET_BYTES = 1, BEGIN_ENC = 2, CHECK_ENC_STATUS = 3,     BEGIN_TRANSMISSION = 4, SEND_BYTES = 5;

reg [2:0] state = 3'b0;
integer byteN = 0;

reg [3:0] sel = 4'b0;
reg [63:0] plain_text;
reg [63:0] cipher_text;
wire [63:0] cipher_net;

uart uart1(
.clk(sysclk),
 .rst(~reset),
.rx(rxd),
.tx(txd),
.transmit(begin_transmit),
.tx_byte(tbyte),
.received(receiving_complete),
.rx_byte(rbyte),
.is_transmitting(isTransmitting),
.is_receiving(isReceiving),
.recv_error(isError)
);

des des1(
 .clk(sysclk),
 .key(56'h0),
 .roundSel(sel),
 .decrypt(1'b0),
 .desIn(plain_text),
 .desOut(cipher_net)
 );

always @(posedge sysclk)
begin

    if(~reset) begin
        state = FIRST_BYTE;
    end

    LED = 4'b1111;

    case(state)
        FIRST_BYTE: begin
            LED[0] = 1'b0;
            begin_transmit = 1'b0;
            if(receiving_complete) begin
               plain_text[7:0] = rbyte;
                byteN = 1;
                state = GET_BYTES;
            end
        end
        GET_BYTES: begin
            LED[1] = 1'b0;
            if(receiving_complete) begin
                plain_text[byteN*8 +: 8] = rbyte;
                byteN = byteN + 1;
                if(byteN == 8) begin
                    state = BEGIN_ENC;
                end
            end
        end
        BEGIN_ENC: begin
            sel = 4'b0;
            state = CHECK_ENC_STATUS;
        end
        CHECK_ENC_STATUS: begin
            LED[2] = 1'b0;
            sel = sel + 1;
            if(sel == 15) begin
                state = BEGIN_TRANSMISSION;
            end
        end
        BEGIN_TRANSMISSION: begin
            cipher_text = cipher_net;
            tbyte = cipher_text[7:0];
            begin_transmit = 1'b1;
            byteN = 1;
            state = SEND_BYTES;
        end
        SEND_BYTES: begin
            LED[3] = 1'b0;
            if(!isTransmitting && !begin_transmit) begin
                tbyte = cipher_text[byteN*8 +: 8];
                begin_transmit = 1'b1;
                byteN = byteN + 1;
                if(byteN == 8) begin
                    state = FIRST_BYTE;
                end
            end else begin
                begin_transmit = 1'b0;
            end
        end
    endcase
end

endmodule
    
pregunta kbarber

2 respuestas

4

El problema es que su código de "transmisión_test" se escribe de tal manera que asume que "is_transmitting" desde el UART se cumple antes del límite del reloj que sigue a la afirmación de "begin_transmit". No es así: requiere un ciclo de reloj antes de que el transmisor UART salga de su estado "inactivo", después de lo cual "is_transmitting" es verdadero.

Como resultado, su máquina de estado "transmission_test" está avanzando dos estados por cada byte transmitido, y verá solo cada otro byte en la salida del UART.

Hay muchos problemas menores con sus ejemplos de código, pero lo principal que debe solucionar es verificar que "is_transmitting" se haya cumplido antes de avanzar al siguiente byte en el mensaje.

Esto hubiera sido bastante obvio si se hubiera tomado el tiempo de simular este proyecto. No puedo dejar de enfatizar la importancia de la simulación en la verificación del código FPGA. Tómese el tiempo para familiarizarse con su simulador y aprenda a escribir buenos bancos de prueba de módulos.

    
respondido por el Dave Tweed
0

Sin conocer los requisitos de la UART, supongo que el problema reside en begin_transmit . En su caso "de trabajo", begin_transmit se borrará para cada byte ya que se está moviendo a través del estado UPDATE_DATA . Sin embargo, para el caso que no funciona, permanecerá en el estado SEND_BYTES para toda la transmisión, y begin_transmit solo se borrará si isTransmitting == 1 . (Tenga en cuenta que begin_transmit se asigna a 0 antes de la declaración del caso, creando una asignación predeterminada).

Simulé el caso que no funciona y begin_transmit solo está pulsando cada otro byte, lo que explicaría lo que está viendo si el UART espera ver una posición en begin_transmit . Sin el modelo UART, modelé a isTransmitting así para la simulación.

always @(posedge sysclk) begin
  isTransmitting <= begin_transmit;
end
    
respondido por el dwikle

Lea otras preguntas en las etiquetas