63 / 63 · Conceito
Prática integradora: transmissor UART e temporização de quadros
Combine um contador divisor, um registrador de deslocamento e controle de fluxo para gerar quadros 8N1 e verificar os limites entre bits.
As aulas podem ser lidas gratuitamente. Inscreva-se para salvar o progresso.
Fixar primeiro a especificação do quadro
Conhecimentos prévios: contadores, registradoresRegistrador Circuito que armazena vários bits de estado. Os registradores síncronos deste curso capturam a entrada especificada na borda de clock. Saiba mais de deslocamento, valid/ready e resetReset Controle que retorna o estado a um valor inicial especificado. É preciso definir se é síncrono ou assíncrono e sua prioridade em relação a outros controles. Saiba mais síncrono.
O formato UARTUART Dispositivo de comunicação serial que usa bits de início, dados e parada sem uma linha de clock separada. Transmissor e receptor devem concordar com a taxa de baud e o formato do quadro. 8N1 contém um bit de início, oito bits de dados, nenhum bit de paridade e um bit de parada. O repouso e a parada valem 1; o início vale 0. Os dados são enviados começando pelo LSBLSB Bit de menor peso. É preciso conferir em conjunto o sentido da notação e as regras de indexação. Saiba mais. Todos os bits têm a mesma duração. Esta prática trata somente da transmissão e supõe que o fornecedor de dados usa o mesmo clock.
Com um clock de 48 MHz e uma meta de 115200 baud, pode-se escolher o divisor inteiro D=417. A taxa real é de aproximadamente 115108 baud, com erro de cerca de −0,080%. A tolerância total, incluindo o receptor, deve ser conferida nas especificações dos dispositivos.
Desdobrar 0x53 na ordem real de transmissão
0x53 é escrito como 01010011, mas a linha transmite a partir do bit de menor peso: 1, 1, 0, 0, 1, 0, 1, 0. No diagrama, uma coluna representa um período de bit de D ciclos do clock do sistema. Uma coluna de repouso é mostrada antes e depois para facilitar a comparação.
Ver os dados da forma de onda
| Sinal | Forma de onda | Valores do barramento |
|---|---|---|
| tx | 101.0.10101. | |
| fase | 234523452345 | repouso → início → d0 → d1 → d2 → d3 → d4 → d5 → d6 → d7 → parada → repouso |
Do início ao fim do bit de parada, passam exatamente 10D ciclos de clock. Uns ou zeros consecutivos também ocupam um período de bit cada: a ausência de uma transição na linha não significa que um bit desapareceu.
Capturar cada byte uma única vez
A implementação abaixo exige que CLKS_PER_BIT seja uma constante maior ou igual a 1. Enquanto busy está ativo, nenhuma entrada é aceita, e somente os dados capturados no início do quadro são usados. Não se cria um novo clock de bits: um contador determina quando avançar dentro do domínio de clock 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
endmoduleSe E0 é a borda de aceitação, tx passa ao bit de início, 0. Depois, avança para o próximo bit em intervalos exatos de D ciclos. Em E0+9D, começa o bit de parada; em E0+10D, busy baixa e done é ativado por um ciclo. O último bit de parada também precisa durar D períodos completos.
Como in_ready=0 até imediatamente antes da borda de conclusão, esta implementação só pode aceitar o próximo quadro, no mínimo, na borda posterior. O intervalo entre aceitações de quadros consecutivos é, portanto, de ciclos. Esse ciclo de repouso faz parte do comportamento correto.
Prever manualmente a sequência de bits
Os dados de 8'h53, começando pelo LSB, são 1,1,0,0,1,0,1,0. O quadro completo segue esta ordem:
| Ordem | start | d0 | d1 | d2 | d3 | d4 | d5 | d6 | d7 | stop |
|---|---|---|---|---|---|---|---|---|---|---|
| tx | 0 | 1 | 1 | 0 | 0 | 1 | 0 | 1 | 0 | 1 |
A verificação não deve se limitar a contar mudanças de tx, pois dois bits consecutivos iguais não produzem transição. Use o início do quadro como referência, amostre o centro de cada período de bit e compare com o valor esperado. Confira também a duração dos bits de início e parada. Para testes unitários rápidos, use divisores pequenos, como D=1, 2 e 3.
Estender o projeto com uma FIFO
Uma FIFOFIFO Fila na qual o primeiro dado a entrar é o primeiro a sair. As condições de cheio e vazio e as regras de leitura e escrita simultâneas fazem parte do contrato. Saiba mais com leitura registrada atualiza dout e dout_valid logo após a borda que aceita pop. O circuito seguinte do mesmo clock amostra a resposta na próxima borda de subidaBorda de subida Instante em que o clock passa de 0 para 1. É diferente do nível alto, que abrange todo o intervalo com CLK=1. Saiba mais. Enviar à UART o dout da própria borda que aceita pop pode usar o valor anterior. Adicione um buffer de uma posição para guardar o byte retornado e um estado pending, entregando o byte exatamente uma vez quando a UART estiver ready.
A verificação final inclui 00, FF, 01, 80, 55 e 53, mudanças de entrada durante busy, quadros consecutivos e reset durante um quadro. A política de reset aborta a transmissão e devolve tx ao repouso, 1. O receptor ainda pode ver um quadro válido; portanto, o formato do quadro UART, por si só, não garante a detecção de uma transmissão interrompida. Se os dados afetados tiverem de ser descartados, defina um contrato de sistema que coordene o reset do receptor com o transmissor ou forneça um sinal separado de interrupção da transmissão ao receptor.
Leitura adicional: Microchip — EUSART and 8N1 framing
Experimente
Com CLKS_PER_BIT=4, um dado é aceito em E0. Determine as bordas em que d0 e stop começam e em que done é gerado. Se houver um novo in_valid=1 em E40, o próximo byte será aceito nessa borda?
Ler a explicação
d0 começa logo após E4, stop após E36 e done após E40. Imediatamente antes de E40, busy=1 e in_ready=0, portanto o novo byte ainda não é aceito. O transmissor deve manter valid e data; o próximo byte pode ser aceito em E41. Cada quadro dura 40 ciclos de clock, e o intervalo mínimo entre aceitações é de 41 ciclos.