63 / 63 · Concepto
Práctica integradora: transmisor UART y temporización de tramas
Combine un contador divisor, un registro de desplazamiento y control de flujo para generar tramas 8N1 y verificar los límites entre bits.
Las lecciones se pueden leer gratis. Inscríbete para guardar el progreso.
Fijar primero la especificación de la trama
Conocimientos previos: contadores, registrosRegistro Circuito que almacena varios bits de estado. Los registros síncronos de este curso capturan la entrada especificada en el flanco de reloj. Más información de desplazamiento, valid/ready y resetReset Control que devuelve el estado a un valor inicial especificado. Deben definirse su carácter síncrono o asíncrono y su prioridad frente a otros controles. Más información síncrono.
El formato UARTUART Dispositivo de comunicación serie que usa bits de inicio, datos y parada sin una línea de reloj independiente. Emisor y receptor deben acordar la tasa de baudios y el formato de trama. 8N1 contiene un bit de inicio, ocho bits de datos, ningún bit de paridad y un bit de parada. El reposo y la parada valen 1; el inicio vale 0. Los datos se envían empezando por el LSBLSB Bit de menor peso. Deben comprobarse conjuntamente el sentido de la notación y las reglas de indexación. Más información. Todos los bits duran lo mismo. Esta práctica trata solo la transmisión y supone que el proveedor de datos usa el mismo reloj.
Con un reloj de 48 MHz y un objetivo de 115200 baudios, puede elegirse el divisor entero D=417. La tasa real es de unos 115108 baudios, con un error aproximado del −0,080 %. La tolerancia total, incluido el receptor, debe comprobarse en las especificaciones de los dispositivos.
Desplegar 0x53 en el orden real de transmisión
0x53 se escribe 01010011, pero la línea transmite desde el bit de menor peso: 1, 1, 0, 0, 1, 0, 1, 0. En el diagrama, una columna representa un período de bit de D ciclos de reloj del sistema. Se muestra una columna de reposo antes y después para facilitar la comparación.
Ver los datos de la forma de onda
| Señal | Forma de onda | Valores del bus |
|---|---|---|
| tx | 101.0.10101. | |
| fase | 234523452345 | reposo → inicio → d0 → d1 → d2 → d3 → d4 → d5 → d6 → d7 → parada → reposo |
Desde el inicio hasta el final del bit de parada transcurren exactamente 10D ciclos de reloj. Los unos o ceros consecutivos también ocupan un período de bit cada uno: que la línea no cambie no significa que desaparezca un bit.
Capturar cada byte una sola vez
La implementación siguiente exige que CLKS_PER_BIT sea una constante mayor o igual que 1. Mientras busy está activo no se aceptan entradas y se usan solo los datos capturados al iniciar la trama. No se crea un nuevo reloj de bits: un contador determina cuándo avanzar dentro del dominio de reloj original.
module uart_tx #(
parameter int unsigned CLKS_PER_BIT = 417,
localparam int CW = (CLKS_PER_BIT <= 1) ? 1 : $clog2(CLKS_PER_BIT)
) (
input logic clk, rst,
input logic in_valid,
output logic in_ready,
input logic [7:0] in_data,
output logic tx, busy, done
);
logic [9:0] frame;
logic [3:0] bits_left;
logic [CW-1:0] ticks_left;
assign in_ready = !busy;
always_ff @(posedge clk) begin
if (rst) begin
tx <= 1'b1;
busy <= 1'b0;
done <= 1'b0;
bits_left <= 4'd0;
ticks_left <= '0;
end else begin
done <= 1'b0;
if (!busy) begin
if (in_valid) begin
frame <= {1'b1, in_data, 1'b0};
tx <= 1'b0;
busy <= 1'b1;
bits_left <= 4'd10;
ticks_left <= CW'(CLKS_PER_BIT-1);
end
end else if (ticks_left != 0) begin
ticks_left <= ticks_left - 1'b1;
end else if (bits_left == 4'd1) begin
tx <= 1'b1;
busy <= 1'b0;
done <= 1'b1;
end else begin
frame <= {1'b1, frame[9:1]};
tx <= frame[1];
bits_left <= bits_left - 1'b1;
ticks_left <= CW'(CLKS_PER_BIT-1);
end
end
end
endmoduleSi E0 es el flanco de aceptación, tx pasa al bit de inicio, 0. Después avanza al siguiente bit a intervalos exactos de D ciclos. En E0+9D comienza el bit de parada y en E0+10D baja busy y se activa done durante un ciclo. El último bit de parada también debe durar D períodos completos.
Como in_ready=0 hasta justo antes del flanco de finalización, esta implementación puede aceptar la siguiente trama, como pronto, en el flanco posterior. El intervalo entre aceptaciones de tramas consecutivas es, por tanto, de ciclos. Ese ciclo de reposo forma parte del comportamiento correcto.
Predecir a mano la secuencia de bits
Los datos de 8'h53, empezando por el LSB, son 1,1,0,0,1,0,1,0. La trama completa sigue este orden:
| Orden | start | d0 | d1 | d2 | d3 | d4 | d5 | d6 | d7 | stop |
|---|---|---|---|---|---|---|---|---|---|---|
| tx | 0 | 1 | 1 | 0 | 0 | 1 | 0 | 1 | 0 | 1 |
La verificación no debe limitarse a contar los cambios de tx, porque dos bits consecutivos iguales no producen una transición. Tome el inicio de la trama como referencia, muestree el centro de cada período de bit y compare con el valor esperado. Compruebe también la duración de los bits de inicio y parada. Para pruebas unitarias rápidas, use divisores pequeños como D=1, 2 y 3.
Extender el diseño con una FIFO
Una FIFOFIFO Cola en la que el primer dato que entra es el primero que sale. Las condiciones de lleno y vacío y las reglas de lectura y escritura simultáneas forman parte del contrato. Más información con lectura registrada actualiza dout y dout_valid justo después del flanco que acepta pop. El siguiente circuito del mismo reloj muestrea esa respuesta en el próximo flanco de subidaFlanco ascendente Instante en que el reloj pasa de 0 a 1. Se distingue del nivel alto, que abarca todo el intervalo con CLK=1. Más información. Si se envía al UART el dout del mismo flanco en que se acepta pop, puede usarse el valor anterior. Añada un búfer de una posición para conservar el byte devuelto y un estado pending, y entregue el byte exactamente una vez cuando el UART esté ready.
La verificación final incluye 00, FF, 01, 80, 55 y 53, cambios de entrada durante busy, tramas consecutivas y reset durante una trama. La política de reset aborta la transmisión y devuelve tx al reposo, 1. El receptor puede ver una trama válida pese a la interrupción, por lo que el formato de trama UART por sí solo no garantiza detectar que la transferencia se ha abortado. Si es obligatorio descartar los datos afectados, defina un acuerdo del sistema que coordine el reset del receptor con el transmisor o proporcione una señal de aborto independiente al receptor.
Lectura adicional: Microchip — EUSART and 8N1 framing
Inténtalo tú
Con CLKS_PER_BIT=4, se acepta un dato en E0. Determine los flancos en que comienzan d0 y stop y en que se genera done. Si hay un nuevo in_valid=1 en E40, ¿se acepta el siguiente byte en ese flanco?
Leer la explicación
d0 comienza justo después de E4, stop después de E36 y done después de E40. Justo antes de E40, busy=1 e in_ready=0, por lo que aún no se acepta el nuevo byte. El emisor debe mantener valid y data; el siguiente byte puede aceptarse en E41. Cada trama dura 40 ciclos de reloj y el intervalo mínimo entre aceptaciones es de 41 ciclos.