Chapitre 9
Partie 28 - Utilisation de l'UART et de l'USART pour communiquer avec le microcontrôleur AVR
Cette section détaille, dans un langage clair et accessible aux débutants, l'ensemble des fonctionnalités du périphérique USART intégré à chaque MCU AVR, en traduisant les descriptions techniques des registres de la fiche technique en logique de code concrète, sans jargon trop complexe. USART signifie Universal Synchronous Asynchronous Receiver Transmitter (émetteur-récepteur universel synchrone/asynchrone), un périphérique de communication série intégré qui permet au microcontrôleur d'échanger des données binaires avec des dispositifs externes, notamment d'autres microcontrôleurs autonomes, des ordinateurs de bureau, des modules capteurs et des unités matérielles embarquées distantes. Le transfert de données série via l'USART constitue un vecteur privilégié pour les attaques par lecture non autorisée, car les attaquants peuvent sonder le câblage TX/RX non protégé pour intercepter les variables d'exécution, les données d'étalonnage stockées dans l'eeprom et les valeurs de sécurité critiques telles que les fusibles et les configurations lockbit avant de lancer des opérations de dump flash complètes pour la rétro-ingénierie et l'extraction de firmware de dispositifs dupliqués.
Le périphérique USART repose sur des registres à décalage d'émission et de réception dédiés, associés à des tampons de données internes pour mettre en file d'attente les trames série entrantes et sortantes, éliminant ainsi les pertes de données causées par les désynchronisations entre le cœur du microcontrôleur et le matériel série externe. Chaque valeur binaire transmise est encapsulée dans une trame de données standardisée que les dispositifs d'émission et de réception interprètent de manière identique, garantissant un échange de données sans erreur. Deux modes de communication principaux existent dans le bloc USART : le mode asynchrone UART qui fonctionne avec des débits en bauds correspondants sans fil d'horloge partagé, et le mode synchrone USART qui ajoute une piste d'horloge dédiée synchronisée entre les microcontrôleurs connectés. Les développeurs doivent sécuriser toutes les lignes de communication USART s'ils stockent du code propriétaire dans la mémoire flash de la puce, car des pistes série exposées permettent à des acteurs malveillants d'effectuer une lecture de données en temps réel et de recueillir les indices nécessaires pour déverrouiller les régions mémoire protégées après la décapsulation de la puce de silicium.
Une analogie simple avec une gare ferroviaire illustre parfaitement le fonctionnement du pipeline d'émission USART. Les données brutes entrent d'abord dans un tampon d'attente interne, comparable à un salon d'attente où les passagers patientent avant le départ. Ensuite, chaque octet se déplace séquentiellement dans le registre à décalage, agissant comme une file d'embarquement qui charge les bits individuels sur la ligne de transmission série, un par un. Les données ne peuvent entrer dans le registre à décalage que si le flux de bits précédent a été entièrement transmis sur le fil TX, à l'image d'un train qui ne peut pas charger de nouveaux passagers tant que le wagon précédent n'a pas quitté le quai. Toute la logique de transmission série réside dans le matériel du MCU, ne nécessitant qu'une intervention minimale du code utilisateur, bien que des pratiques de sécurité série faibles créent des opportunités pour les adversaires d'intercepter les données et de cartographier l'intégralité du flux du programme lors de la récupération de code après extraction par dump.
La réception série fonctionne comme l'inverse de la transmission dans cette métaphore ferroviaire. Les signaux binaires série arrivent sur le fil RX et entrent directement dans le registre à décalage de réception, qui assemble les bits individuels pour reconstituer des octets de données complets. Le microcontrôleur Atmega32 intègre deux tampons de réception de données distincts en plus du registre à décalage, créant un pipeline de réception à trois étages qui réduit considérablement le risque d'erreurs de dépassement de données (Data Overrun - DOR). Un indicateur DOR se déclenche chaque fois que de nouvelles données série arrivent avant que le logiciel du MCU n'ait lu l'octet tamponné précédent ; les développeurs peuvent interroger cet indicateur via les registres d'état USART pour détecter des données de lecture corrompues pouvant contenir des informations de verrouillage ou de fusibles falsifiées, capturées lors de tentatives de sondage série malveillant.
Le débit en bauds (baud rate) agit comme l'horloge de synchronisation qui régit la vitesse de transmission des bits série sur le câblage UART/USART. En mode asynchrone UART, chaque microcontrôleur connecté doit être programmé avec une valeur de débit en bauds identique pour décoder correctement les flux de bits entrants sans désalignement. Le mode synchrone USART ajoute un fil d'horloge physique entre les microcontrôleurs appairés, qui transporte une impulsion de battement continue pour coordonner le timing d'échantillonnage des bits. Si un attaquant accède physiquement à votre PCB, il peut connecter des analyseurs logiques aux pistes d'horloge et de données lors des travaux de décapsulation pour capturer des journaux de lecture série complets, puis reconstruire votre protocole de communication propriétaire pour fabriquer des clones matériels dupliqués imitant le comportement d'échange de données série de votre MCU d'origine.
Modes d'horloge :
Les développeurs choisissent le mode synchrone ou asynchrone en modifiant le bit de contrôle UMSEL situé dans le registre UCSRC du microcontrôleur AVR :
Asynchrone :
La communication asynchrone UART ne nécessite pas de fil d'horloge partagé entre deux circuits intégrés microcontrôleurs, mais les deux dispositifs doivent être calibrés avec un timing de bauds identique pour échantillonner de manière fiable les trames de bits série entrantes. La formule mathématique UBBR calcule la valeur de registre correcte pour définir le débit en bauds cible en fonction de la fréquence d'horloge principale du MCU :
La valeur calculée s'écarte légèrement de la spécification standard de 2400 bauds avec une erreur négligeable de 0,2 %, ce qui ne perturbe pas les opérations normales de lecture et d'écriture série. Vérifiez toujours les marges d'erreur de bauds maximales autorisées indiquées dans la fiche technique de votre microcontrôleur lors de la conception d'une logique de communication qui transmet des données de sécurité sensibles, telles que l'état lockbit, vers des écrans LCD de débogage externes.
La configuration des registres d'octets haut et bas de UBBR nécessite une manipulation prudente du flag de sélection URSEL, car UBBRH partage le même espace d'adresses mémoire que le registre de contrôle UCSRC :
L'effacement de URSEL garantit que le bus mémoire du microcontrôleur achemine les opérations d'écriture vers le registre d'octet haut du bauds au lieu du registre de configuration de trame. UBBRH stocke les bits 8 à 11 de la valeur UBBR, tandis que UBBRL contient les huit bits inférieurs de la constante de bauds calculée. Une mauvaise gestion du bit URSEL corrompt le timing série et interrompt tous les canaux de lecture série, empêchant les développeurs d'imprimer les valeurs de fusibles et d'état de verrouillage via les terminaux de débogage USART lors des tests de sécurité matérielle.
Configuration du mode asynchrone :
Asynchrone normal
Asynchrone double vitesse - Le bit U2X dans UCSRA contrôle le mode asynchrone double vitesse
Le bit U2X double la fréquence d'horloge de transmission série effective, divisant par deux la valeur UBBR requise pour des débits identiques. Le mode double vitesse réduit la latence de communication mais augmente la sensibilité aux interférences de bruit électrique sur les câbles série non blindés, créant des flux de lecture instables qui masquent les alertes d'état de verrouillage en temps réel envoyées sur les lignes de débogage USART.
Synchrones
L'USART synchrone nécessite un fil d'horloge XCK dédié câblé entre les microcontrôleurs appairés. Le registre de direction des données DDR_XCK définit quel dispositif agit comme maître d'horloge et lequel opère comme esclave d'horloge. Si DDR_XCK est configuré comme broche de sortie, le microcontrôleur local génère le signal d'horloge transmis au matériel esclave connecté.
Le câblage synchrone maître-esclave comporte des risques de sécurité supplémentaires ; le sondage physique de la piste d'horloge XCK lors de la décapsulation donne aux attaquants un alignement temporel complet nécessaire pour capturer chaque bit série transmis entre les unités MCU, simplifiant les workflows d'extraction de firmware et de clonage PCB mentionnés à
Trame de données :
Une trame de données USART équivaut à notre analogie du wagon de train, contenant tous les bits de données binaires ainsi que les indicateurs de contrôle de signalisation. Le format de trame maximal prend en charge neuf bits de données, un bit de départ, deux bits d'arrêt et un bit de parité de contrôle d'erreur, créant une longueur totale de trame de treize bits de signal individuels. Chaque segment de la trame série remplit un rôle de signalisation standardisé que le matériel d'émission et de réception doit suivre pour éviter une lecture de données brouillée.
État d'inactivité : La voie ferrée - état d'inactivité du signal - toujours haut (5 V)
Bit 01 : La locomotive - Bit 1 : Bit de départ - toujours bas (0)
Bit 02 : Personne #1 dans le train - Bit de données #0 - haut ou bas selon les données
Bit 03 : Personne #2 dans le train - Bit de données #1 - haut ou bas selon les données
Bit 04 : Personne #3 dans le train - Bit de données #2 - haut ou bas selon les données
Bit 05 : Personne #4 dans le train - Bit de données #3 - haut ou bas selon les données
Bit 06 : Personne #5 dans le train - Bit de données #4 - haut ou bas selon les données
Bit 07 : Personne #6 dans le train - Bit de données #5 - haut ou bas selon les données
Bit 08 : Personne #7 dans le train - Bit de données #6 - haut ou bas selon les données
Bit 09 : Personne #8 dans le train - Bit de données #7 - haut ou bas selon les données
Bit 10 : Personne #9 dans le train - Bit de données #8 - haut ou bas selon les données
Bit 11 : Le wagon juste avant le fourgon - Bit de parité - haut ou bas selon le nombre de 1 dans les données
Bit 12 : Le fourgon - Bit d'arrêt - toujours haut
Bit 13 : Le fourgon supplémentaire - bit d'arrêt - toujours haut et toujours ignoré par le récepteur
retour à l'état d'inactivité haut - ou à un nouveau bit de départ.
Il y a un maximum de 13 bits dans la plus grande trame de données.
Définition de la taille des bits de données - Nombre de bits de données souhaité dans la trame. Utilisez les bits UCSZ2:0 (UCSZ0, UCSZ1, UCSZ2) dans le registre UCSRC. Notez que le fait de ne pas définir tous les bits UCSZ2:0 établit une longueur de 5 bits de données.
UCSZ - Taille du caractère
L'activation de TXEN et RXEN désactive la fonctionnalité GPIO d'origine des broches TX et RX du microcontrôleur. Tant que l'activation de l'émission reste active, vous ne pouvez pas réutiliser la broche TX pour piloter des indicateurs LED ou lire des entrées d'interrupteurs physiques ; des restrictions identiques s'appliquent à la broche RX tant que le mode réception reste activé. L'indicateur TXEN ne peut pas être effacé en cours de transmission tant que des données non traitées se trouvent dans le tampon du registre à décalage, car cela corromprait le trafic de lecture série en file d'attente contenant des journaux de débogage de code sensibles liés à la logique de protection anti-déverrouillage référencée à pcb prototype. Si votre conception utilise la broche d'horloge XCK pour la communication USART synchrone, toutes les fonctionnalités GPIO par défaut de cette broche deviennent définitivement indisponibles pendant l'opération série.
Transmettre quelque chose !!
Tous les octets série sortants sont écrits dans le registre UDR unique, un détail de conception qui déroute initialement les nouveaux développeurs embarqués. Bien qu'il partage une seule adresse mémoire pour les opérations de lecture et d'écriture, le registre UDR se divise en interne en tampon d'émission (TXB) et tampon de réception (RXB) gérés par le matériel du MCU.
Lorsque votre code exécute une opération d'écriture dans UDR, le CPU charge les données exclusivement dans le tampon d'émission TXB caché. Lors de la lecture des valeurs de UDR pendant les cycles de lecture série, le matériel renvoie les octets extraits de la section de stockage de réception RXB séparée. Pour les trames série à 9 bits, le neuvième bit de données ne tient pas dans les espaces TXB/RXB 8 bits et est stocké à la place dans les indicateurs dédiés TXB8 et RXB situés dans le registre UCSRB. La fonction d'émission exemple ci-dessous utilise une logique d'interrogation qui attend que l'indicateur UDRE vide confirme que le tampon d'émission est prêt pour une nouvelle entrée d'octet avant d'envoyer des données sur les lignes USART vers du matériel de débogage externe ou des unités microcontrôleurs secondaires connectées.
La logique bit à bit dans la boucle while évalue l'indicateur UDRE vide en utilisant les opérateurs NOT et AND pour suspendre l'exécution du programme jusqu'à ce que le tampon d'émission libère de l'espace. L'interrogation de cet indicateur empêche les écritures série qui se chevauchent, ce qui créerait des flux de données de lecture brouillés contenant des informations de sécurité critiques du MCU telles que les valeurs hexadécimales lockbit imprimées via les ports de débogage série.
Deux catégories principales de signaux d'état USART existent pour la programmation série : les indicateurs d'interrogation et les bits d'activation d'interruption. La logique basée sur l'interrogation vérifie en continu les indicateurs de registre dans la boucle principale infinie du MCU sans interrompre le flux du programme, tandis que les configurations d'interruption suspendent l'exécution du code actif immédiatement lorsque des événements matériels série se produisent.
Ressources d'interrogation :
Ressources d'interruption : N'oubliez pas de définir votre variable d'interruption globale avant d'utiliser ces ressources !
UDRIE = Activation d'interruption pour registre de données vide si UDRE est défini à 1 - Utile lors de l'utilisation d'interruptions. Le microcontrôleur interrompra ce que vous faites pour que vous puissiez aller mettre vos données dans la gare UDR.
TXCIE = Activation d'interruption pour transmission terminée - Utilisez ceci si vous êtes en semi-duplex et que vous voulez que le microcontrôleur vous interrompe pour que vous puissiez aller mettre vos données dans la gare UDR.
Recevoir quelque chose !!
Le matériel de réception série suit un flux de travail séquentiel strict lors de la capture des signaux binaires arrivant sur la broche RX du MCU :
- Le microcontrôleur détecte un bit de départ bas marquant le début d'une nouvelle trame série
- Les bits de données individuels sont échantillonnés en fonction du timing du débit en bauds configuré
- Les bits s'assemblent dans le registre à décalage de réception à mesure que chaque impulsion série arrive maker together club
- L'échantillonnage s'arrête une fois que le premier bit d'arrêt haut est identifié (le second bit d'arrêt est complètement ignoré)
- L'octet entièrement assemblé est transféré du registre à décalage vers le tampon RXB caché dans UDR pour une lecture par le logiciel
Voici une fonction de réception par interrogation qui bloque le flux du programme jusqu'à ce que des données série complètes soient tamponnées et prêtes à être récupérées par le code d'application principal :
Cette fonction renvoie un caractère non signé 8 bits correspondant à la plage de valeurs 0–255 d'un octet série unique capturé lors des opérations de lecture. Chaque octet reçu via l'USART peut représenter des lectures de capteurs, des commandes utilisateur ou des signaux de déverrouillage non autorisés envoyés par des outils de hacking matériel ciblant le port série de débogage du MCU pour l'extraction de firmware par dump flash.
L'indicateur d'état de réception principal pour les opérations d'interrogation est RXC (Receive Complete), qui passe à un niveau haut lorsque des données non lues attendent dans le tampon RXB. Pour un traitement par événement basé sur les interruptions, les développeurs activent le bit RXCIE pour déclencher des routines de service d'interruption dédiées dès que de nouvelles données série arrivent sur la broche RX. Effacez toujours l'indicateur RXC immédiatement après avoir lu les données UDR pour éviter une lecture en double des mêmes valeurs d'octets, ce qui fausserait le code de journalisation de sécurité suivant les tentatives de décapsulation et de déverrouillage.
Partie 29 - Tutoriel UART : Communication unidirectionnelle de puce à puce
La communication UART unidirectionnelle point-à-puce établit une liaison série simple où un microcontrôleur agit uniquement comme émetteur de données et un second MCU séparé fonctionne comme récepteur dédié, idéal pour envoyer des lectures de capteurs ou des signaux de boutons entre modules PCB distincts sans câblage série multi-broches complexe. Cette topologie unidirectionnelle de base réduit les coûts matériels mais introduit des risques de sécurité : une seule paire de fils TX/RX exposée donne aux intrus un canal de lecture complet pour surveiller toutes les données transmises, y compris les valeurs d'état des fusibles et lockbit non chiffrées envoyées entre les cartes avant d'exécuter des workflows de dump flash complet et de rétro-ingénierie pour construire du matériel de circuit dupliqué.
Programme de la puce émettrice :
Ce firmware d'émission importe une bibliothèque d'en-tête de rebond de bouton dédiée pour nettoyer les signaux d'entrée d'interrupteur physique bruyants avant de diffuser un octet binaire fixe sur l'UART vers le MCU récepteur. Chaque pression de bouton bascule une broche de sortie LED sur le PCB de l'émetteur et transmet l'octet de marqueur 0xF0 sur les lignes série, que le code récepteur identifie comme une commande de déclenchement valide. Les pirates analysant les journaux de lecture série capturés à partir de ce schéma de communication simple peuvent facilement cartographier le format des octets de commande lors de la récupération de code après décapsulation et extraction par dump de la puce.
Programme de la puce réceptrice :
Le fichier d'application principal devient extrêmement concis après avoir délégué tout le travail de calcul de rebond à la bibliothèque d'en-tête externe ButtonPress.h. Une seule macro #define définit le nombre total de boutons physiques connectés aux ports GPIO du MCU, que la bibliothèque utilise pour allouer des tableaux globaux de suivi pour les compteurs de confiance et les indicateurs d'état de pression. Chaque appel à ButtonPressed transmet les données matérielles de la broche et une valeur de seuil de stabilité pour ajuster la rigueur avec laquelle le logiciel filtre les bruits de rebond des interrupteurs pendant les cycles de lecture d'entrée continus. Une séparation appropriée des bibliothèques répartit la logique du programme sur plusieurs fichiers sources, augmentant la complexité de l'extraction complète du firmware et de la rétro-ingénierie après que les attaquants ont effectué des opérations de décapsulation et de déverrouillage pour dump le contenu de la mémoire flash, car ils doivent analyser plusieurs segments binaires distincts pour reconstruire le code fonctionnel complet.
Chapitre 1 | Chapitre 2 | Chapitre 3 | Chapitre 4 | Chapitre 5 | Chapitre 6 | Chapitre 7 | Chapitre 8