63 / 63 · Concept
Projet pratique : émetteur UART et timing des trames
Combiner division d'horloge, décalage et contrôle de flux pour une trame 8N1, puis vérifier les limites de bits.
Les leçons sont gratuites. Inscrivez-vous pour enregistrer vos progrès.
Fixer d'abord la trame
Prérequis : compteurs, registres à décalageRegistre Circuit stockant plusieurs bits d'état. Les registres synchrones du cours capturent leur entrée définie sur un front d'horloge. En savoir plus, valid/ready et reset synchroneReset Commande ramenant l'état à la valeur initiale spécifiée. Son caractère synchrone/asynchrone et sa priorité sur les autres commandes doivent être définis. En savoir plus.
Le format UARTUART Dispositif de communication série utilisant bits de départ, données et arrêt sans ligne d'horloge séparée. Émetteur et récepteur doivent convenir du débit en baud et du format de trame. 8N1 contient un bit de départ, huit bits de données, aucune parité et un bit d'arrêt. Idle et stop valent 1, start vaut 0, et les données partent LSBLSB Bit de poids le plus faible. Vérifiez ensemble sens d'écriture et règles d'indexation. En savoir plus d'abord. Tous les bits ont la même durée. Ce TP traite seulement l'émission avec un fournisseur de données dans le même domaine d'horloge.
Pour 48MHz et 115200 baud visés, choisissez par exemple le diviseur entier D=417. Le débit réel vaut environ 115108 baud, soit −0.080 %. La tolérance incluant le récepteur doit être vérifiée dans les spécifications des composants.
Dérouler 0x53 dans l'ordre transmis
0x53 s'écrit 01010011, mais les données sur le fil sont 1,1,0,0,1,0,1,0. Une case du dessin est une durée de bit de D cycles système, pas un cycle. Les intervalles idle avant et après sont montrés chacun sur une case pour comparaison.
Voir les données du chronogramme
| Signal | Forme d'onde | Valeurs du bus |
|---|---|---|
| tx | 101.0.10101. | |
| phase | 234523452345 | repos → départ → d0 → d1 → d2 → d3 → d4 → d5 → d6 → d7 → arrêt → repos |
De start à la fin de stop, il y a exactement 10D cycles. Deux bits égaux successifs occupent chacun leur durée ; l'absence de transition ne supprime pas un bit.
Capturer l'octet une seule fois
CLKS_PER_BIT est une constante ≥1. Pendant busy, aucune entrée n'est acceptée ; seule la donnée capturée au début est utilisée. Un compteur dans l'horloge originale commande le déplacement, sans créer une nouvelle horloge de bit.
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 l'acceptation est à E0, tx passe au start=0. Chaque bit suivant commence exactement D cycles plus tard. Stop commence à E0+9D ; busy tombe et une impulsion apparaît sur done à E0+10D. Le dernier stop doit aussi durer D périodes.
in_ready reste à 0 jusqu'avant le front d'achèvement. La trame suivante n'est donc acceptée qu'au front suivant au plus tôt, pour un intervalle minimal cycles. Ce cycle idle supplémentaire fait partie du fonctionnement normal.
Prédire les bits à la main
Les données de 8'h53, LSB d'abord, sont 1,1,0,0,1,0,1,0. La trame complète est :
| Position | start | d0 | d1 | d2 | d3 | d4 | d5 | d6 | d7 | stop |
|---|---|---|---|---|---|---|---|---|---|---|
| tx | 0 | 1 | 1 | 0 | 0 | 1 | 0 | 1 | 0 | 1 |
Ne comptez pas seulement les changements de tx : deux bits égaux ne créent aucune transition. Échantillonnez au milieu de chaque intervalle depuis le début de trame, comparez les bits et vérifiez les durées start/stop. Utilisez aussi D=1,2,3 pour des tests unitaires rapides.
Prolongement avec un FIFO
Un FIFOFIFO File où la première donnée entrée sort en premier. Les règles à plein, à vide et en lecture/écriture simultanée font partie du contrat. En savoir plus à lecture enregistrée actualise dout et dout_valid après le front acceptant pop. Le circuit suivant sur la même horloge capture au prochain front montantFront montant Instant où l'horloge passe de 0 à 1, distinct du niveau désignant tout l'intervalle CLK=1. En savoir plus. Envoyer dout à l'UART dès le front de pop peut donc transmettre l'ancienne donnée. Ajoutez un tampon d'un octet et un état pending pour conserver la réponse et la transmettre exactement une fois lorsque l'UART est prêt.
Testez 00,FF,01,80,55,53, les changements d'entrée pendant busy, les trames consécutives et un reset en cours de trame. La politique de reset interrompt l'émission et remet tx à idle=1 ; le récepteur peut néanmoins voir une trame valide, de sorte que le seul contrôle du format UART ne garantit pas la détection de l’interruption. Si les données concernées doivent être rejetées, définissez un contrat système qui coordonne le reset du récepteur avec l’émetteur ou transmet un signal d’abandon de transmission distinct au récepteur.
Pour aller plus loin : Microchip — EUSART and 8N1 framing
Essayez vous-même
Avec CLKS_PER_BIT=4 et une acceptation à E0, donnez les fronts de début d0, début stop et done. Un nouveau in_valid=1 à E40 est-il accepté sur ce front ?
Lire l’explication
d0 commence à E4, stop à E36 et done après E40. Avant E40 busy=1, donc in_ready=0 : le nouvel octet n'est pas accepté. L'émetteur garde valid et data jusqu'à E41, première acceptation possible. Chaque trame dure 40 cycles et l'intervalle minimal d'acceptation est 41 cycles.