« Fonctionnement d'un ordinateur/Les bus et liaisons point à point (généralités) » : différence entre les versions

Contenu supprimé Contenu ajouté
m Mewtow a déplacé la page Fonctionnement d'un ordinateur/Bus et cartes-mères vers Fonctionnement d'un ordinateur/Les bus et liaisons point à point (généralités) : Changement structure du plan de cours et réorganisation/segmentation du chapitre
mAucun résumé des modifications
Ligne 165 :
 
[[File:Bus en lecture et écriture.png|centre|Bus en lecture et écriture.]]
 
==Le codage des données/commandes sur un bus==
 
Il faut aussi que le récepteur puisse extraire des informations utiles du flux de bits transmis : quelle est l'adresse du récepteur, quand la transmission se termine-t-elle, et bien d'autres. Les transmissions sur un bus sont standardisées de manière à rendre l'interprétation du flux de bit claire et sans ambiguïté. Deux composants électroniques communiquent entre eux en s'envoyant des '''trames''', des paquets de bits où chaque information nécessaire à la transmission est à une place précise. Le codage des trames indique comment l'émetteur doit envoyer les données sur le bus, ce qui permet aux récepteurs de détecter les données transmises et les interpréter. Le terme trame réfère aux données transmises : toutes les informations nécessaires pour une transmission sont regroupées dans une trame, qui est envoyée telle quelle sur le bus.
 
Sur les bus série, ces trames sont transmises bit par bit grâce à des circuits spécialisés : la trame est mémorisée dans un registre à décalage, qui envoie celle-ci bit par bit sur sa sortie (reliée au bus). Pour les bus parallèles, les choses peuvent être plus variables. Il est possible d'envoyer des trames plus grosses que la largeur du bus : la trame est envoyée par paquets de données, octet par octet ou byte par byte. Mais sur la plupart des bus parallèles, toute la trame est envoyée d'un coup sur le bus : cela simplifie fortement le codage de la trame, vu qu'il n'y a pas besoin de coder la longueur de la trame ou de préciser quand sa transmission est terminée.
 
===Le codage des trames===
 
Une trame doit fournir plusieurs informations. Premièrement, le codage des trames doit permettre une synchronisation des équipements, qui ne fonctionnent pas forcément à la même vitesse. Cela se fait par la transmission d'un signal de synchronisation ou signal d'horloge dans les trames. Enfin, la trame doit contenir toutes les données de la transmission, et de quoi contrôler celle-ci : indiquer les récepteurs, dire quand commence la transmission et quand elle se termine, etc. Dans le cas le plus simple, une trame commence par un octet qui indique le début de la transmission, suivi par l'adresse du récepteur, puis les données à transmettre, et enfin un octet qui indique la fin de la transmission. D'autres trames de ce genre existent, et nous en verrons quelques unes dans ce va suivre.
 
====Le codage du début et de la fin de transmission====
 
La communication sur un bus est légèrement différente de ce qu'on a vu dans les chapitres précédents. Auparavant, quand deux composants devaient communiquer, on se contentait de relier les deux par un fil, et faire en sorte que de nouvelles données soient envoyées à chaque cycle. Mais sur un bus, ce n'est pas toujours le cas : il arrive que le bus soit inutilisé durant un certain temps, sans données transmises. Les composants qui veulent communiquer doivent donc déterminer quand le bus est inutilisé afin de ne pas confondre l'état de repos du bus avec une transmission de données. Une transmission est un flux de bits qui a un début et une fin : le codage des trames doit indiquer quand commence une transmission et quand elle se termine. Le récepteur ne reçoit en effet qu'un flux de bits, et doit détecter le début et la fin des trames. Ce processus de segmentation d'un flux de bits en trames n’est cependant pas simple et l'émetteur doit fatalement ajouter des bits pour coder le début et la fin de la trame. Pour cela, on peut certes ajouter un bit au bus de commande, qui indique si le bus est en train de transmettre une trame ou s'il est inactif. Mais il y a moyen de se passer de ce genre d'artifice avec des méthodes plus ingénieuses.
 
De nos jours, la quasi-totalité des protocoles utilisent la même technique pour délimiter le début et la fin d'une trame. Ils utilisent un octet spécial (ou une suite d'octet), qui indique le début de la trame, et un autre octet pour la fin de la trame. Ces octets de synchronisation, respectivement nommés START et STOP, sont standardisés par le protocole. Entre ces octets de synchronisation, on trouve un en-tête standardisé, les données à transmettre et éventuellement des données de contrôle d'erreur. Un problème peut cependant survenir : il se peut qu'un octet de la trame soit identique à un octet START ou STOP. Mais il y a moyen de résoudre le problème assez simplement. Pour cela, il suffit de faire précéder ces pseudo-octets START/STOP par un octet d'échappement, lui aussi standardisé. Les vrais octets START et STOP ne sont pas précédés de cet octet d'échappement et seront pris en compte, là où les pseudo-START/STOP seront ignoré car précédés de l'octet d'échappement. Il arrive plus rarement que ces octets de START/STOP soient en réalité codés par des bits spéciaux. Un bon exemple est celui du bit I²C, où les bits de START et STOP sont codés par des fronts sur les bus de données et de commande. Il en est de même sur le BUS RS-232 et RS-485, comme nous le verrons plus tard.
 
[[File:Trame.png|centre|Trame]]
 
Une autre solution consiste à remplacer l'octet/bit STOP par la longueur de la trame. Immédiatement à la suite de l'octet/bit START, l'émetteur va envoyer la longueur de la trame en octet ou en bits. Cette information permettra au récepteur de savoir quand la trame se termine. Cette technique permet de se passer totalement des octets d'échappement : on sait que les octets START dans une trame sont des données et il n'y a pas d'octet STOP à échapper. Ce faisant, le récepteur a moins de travail d'analyse à faire : il n'a pas vraiment à analyser le contenu des octets pour savoir quoi faire, mais a juste à compter les octets qu'il reçoit. Cette méthode et la méthode précédente ont des conséquences différentes sur la taille des trames. Si la trame peut être très longue, la longueur doit être codée sur plusieurs octets : cela prend plus de place que l'octet/bit STOP. Par contre, les octets d’échappement sont économisés. Un autre défaut (très théorique) de cette approche est que la longueur des trames est bornée par le nombre de bits utilisés pour coder la longueur. Dit autrement, elle ne permet pas de trames aussi grandes que possibles. Mais ce défaut est plus théorique qu'autre chose.
 
[[File:Trame - 2.png|centre|Trame - 2]]
 
Dans le cas où les trames ont une taille fixe, à savoir que leur nombre d'octet ne varie pas selon la trame, les deux techniques précédentes sont inutiles. Il suffit d'utiliser un octet/bit de START, les récepteurs ayant juste à compter les octets envoyés à sa suite. Pas besoin de STOP ou de coder la longueur de la trame.
 
====Le codage du récepteur====
 
La trame doit naturellement être envoyée à un récepteur, seul destinataire de la trame. Sur les bus où il n'y a toujours que deux composants de connectés, il n'y a pas besoin de préciser quel est le récepteur. On peut déduire assez facilement que le récepteur est l'autre composant, celui qui n'a pas envoyé la donnée : sa détermination est implicite. Mais sur les bus avec plusieurs composants, la trame doit indiquer à qui elle est destinée. Pour cela, chaque composant se voit attribuer une adresse, il est numéroté. La trame a juste à indiquer quelle est l'adresse du composant de destination. Cela fonctionne aussi pour les composants qui sont des périphériques : on a vu dans le chapitre précédent que chaque périphérique/composant se voyait attribuer une adresse. L'adresse en question est intégrée à la trame et est placée à un endroit précis, le plus souvent à son début. La raison à cela est que les récepteurs espionnent le bus en permanence pour détecter les trames qui leur sont destinées. Ils lisent toujours les trames envoyées sur le bus et en extraient l'adresse de destination : si celle-ci leur correspond, ils lisent le reste de la trame, ou se déconnectent du bus sinon. Pour que la transmission soit la plus rapide, il vaut mieux que les périphériques sachent le plus rapidement si la trame leur est destinée, ce qui demande de mettre l'adresse au plus tôt.
 
===La fiabilité des transmissions sur un bus===
 
[[File:TCP ACK Timeout.png|vignette|ACK TCP]]
 
Lorsqu'une trame est envoyée, il se peut qu'elle n'arrive pas à destination correctement. Des parasites peuvent déformer la trame et/ou en modifier des bits au point de la rendre inexploitable. Dans ces conditions, il faut systématiquement que l'émetteur et le récepteur détectent l'erreur : ils doivent savoir que la trame n'a pas été transmise ou qu'elle est erronée. Pour cela, il existe diverses méthodes de de détection et de correction d'erreur, que nous avons abordées en partie dans les premiers chapitres du cours. On en distingue deux classes : celles qui ne font que détecter l'erreur, et celles qui permettent de la corriger. Tous les codes correcteurs et détecteurs d'erreur ajoutent tous des bits aux données de base, ces bits étant appelés des bits de correction/détection d'erreur. Ces bits servent à détecter et éventuellement corriger toute erreur de transmission/stockage. Plus le nombre de bits ajoutés est important, plus la fiabilité des données sera importante. Dans le cas le plus simple, on se contente d'un simple bit de parité. Dans d'autres cas, on peut ajouter une somme de contrôle ou un code de Hamming à la trame. Cela permet de détecter les erreurs de transmission.
 
Si l'erreur peut être corrigée par le récepteur, tout va bien. Mais il arrive souvent que ce ne soit pas le cas : l'émetteur doit alors être prévenu et agir en conséquence. Pour cela, le récepteur peut envoyer une trame à l'émetteur qui signifie : la trame précédente envoyée est invalide. Cette trame est appelée un '''accusé de non-réception'''. La trame fautive est alors renvoyée au récepteur, en espérant que ce nouvel essai soit le bon. Mais cette méthode ne fonctionne pas si la trame est tellement endommagée que le récepteur ne la détecte pas. Pour éviter ce problème, on utilise une autre solution, beaucoup plus utilisée dans le domaine du réseau. Celle-ci utilise des '''accusés de réception''', à savoir l'inverse des accusés de non-réception. Ces accusés de réception sont envoyés à l'émetteur pour signifier que la trame est valide et a bien été reçue. Nous les noterons ACK dans ce qui suivra. Après avoir envoyé une trame, l'émetteur va attendra un certain temps que l'ACK correspondant lui soit envoyé. Si l’émetteur ne reçoit pas d'ACK pour la trame envoyée, il considère que celle-ci n'a pas été reçue correctement et la renvoie. Pour résumer, on peut corriger et détecter les erreurs avec une technique qui mélange ACK et durée d'attente : après l'envoi d'une trame, on attend durant un temps nommé ''time-out'' que l'ACK arrive, et on renvoie la trame au bout de ce temps si non-réception. Cette technique porte un nom : on parle d''''''Automatic repeat request'''''.
 
Dans le cas le plus simple, les trames sont envoyées unes par unes au rythme d'une trame après chaque ACK. En clair, l'émetteur attend d'avoir reçu l'ACK de la trame précédente avant d'en envoyer une nouvelle. Parmi les méthodes de ce genre, la plus connue est le '''protocole Stop-and-Wait'''. Cette méthode a cependant un problème pour une raison simple : les trames mettent du temps avant d'atteindre le récepteur, de même que les ACK mettent du temps à faire le chemin inverse. Une autre conséquence des temps de transmission est que l'ACK peut arriver après que le time-out (temps d'attente avant retransmission de la trame) soit écoulé. La trame est alors renvoyée une seconde fois avant que son ACK arrive. Le récepteur va alors croire que ce second envoi est en fait l'envoi d'une nouvelle trame ! Pour éviter cela, la trame contient un bit qui est inversé à chaque nouvelle trame. Si ce bit est le même dans deux trames consécutives, c'est que l'émetteur l'a renvoyée car l'ACK était en retard. Mais les temps de transmission ont un autre défaut avec cette technique : durant le temps d'aller-retour, l'émetteur ne peut pas envoyer de nouvelle trame et doit juste attendre. Le support de transmission n'est donc pas utilisé de manière optimale et de la bande passante est gâchée lors de ces temps d'attente.
 
Les deux problèmes précédents peuvent être résolu en utilisant ce qu'on appelle une '''fenêtre glissante'''. Avec cette méthode, les trames sont envoyées les unes après les autres, sans attendre la réception des ACKs. Chaque trame est numérotée de manière à ce que l'émetteur et le récepteur puisse l’identifier. Lorsque le récepteur envoie les ACK, il précise le numéro de la trame dont il accuse la réception. Ce faisant, l'émetteur sait quelles sont les trames qui ont étés reçues et celles à renvoyer (modulo les time-out de chaque trame). On peut remarquer qu'avec cette méthode, les trames sont parfois recues dans le désordre, alors qu'elles ont été envoyées dans le désordre. Ce mécanisme permet donc de conserver l'ordre des données envoyées, tout en garantissant le fait que les données sont effectivement transmises sans problèmes. Avec cette méthode, l'émetteur va accumuler les trames à envoyer/déjà envoyées dans une mémoire. L'émetteur devra gérer deux choses : où se situe la première trame pour laquelle il n'a pas d'ACK, et la dernière trame envoyée. La raison est simple : la prochaine trame à envoyer est l'une de ces deux trames. Tout dépend si la première trame pour laquelle il n'a pas d'ACK est validée ou non. Si son ACK n'est pas envoyé, elle doit être renvoyée, ce qui demande de savoir quelle est cette trame. Si elle est validée, l'émetteur pourra envoyer une nouvelle trame, ce qui demande de savoir quelle est la dernière trame envoyée (mais pas encore confirmée). Le récepteur doit juste mémoriser quelle est la dernière trame qu'il a recue. Lui aussi va devoir accumuler les trames recues dans une mémoire, pour les remettre dans l'ordre.
 
===Les codes en ligne : le codage des bits sur un bus===
 
Chaque fil d'un bus transmet un signal, qui peut être codé de diverses manières. Il existe des méthodes relativement nombreuses pour coder un bit de données pour le transmettre sur un bus : ces méthodes sont appelées des codages en ligne. Toutes codent celui-ci avec une tension, qui peut prendre un état haut (tension forte) ou un état bas (tension faible, le plus souvent proche de 0 volts). Outre le codage des données, il faut prendre aussi en compte le codage des commandes. En effet, certains bus série utilisent des fils dédiés pour la transmission des bits de données et de commande. Cela permet d'éviter d'utiliser trop de fils pour un même procédé.
 
====Les codes non-différentiels====
 
La plupart des méthodes se contentent d'une seule tension, d'un seul fil, pour coder les bits.
* La première de ces méthodes, le '''codage NRZ-L''', utilise l'état haut pour coder un 1 et l'état bas pour le zéro (ou l'inverse).
* Le codage '''NRZ-M''' fonction ne différemment : un état haut signifie que le bit envoyé est l'inverse du précédent, tandis que l'état bas indique que le bit envoyé est identique au précédent.
* Le codage '''NRZ-S''' est identique au codage NRZ-M si ce n'est que l'état haut et bas sont inversés.
* Le '''codage RZ''' est similaire au codage NRZ, si ce n'est que la tension retourne systématiquement à l'état bas après la moitié d'un cycle d'horloge. Celui-ci permet une meilleure synchronisation avec le signal d'horloge, notamment dans les environnements bruités.
* Le '''codage Manchester''', aussi appelé codage biphasé, code un 1 par un front descendant, alors qu'un 0 est codé par un front montant (ou l'inverse, dans certaines variantes). Ce codage s'obtient en faisant un OU logique entre l'horloge et le flux de bits à envoyer (codé en NRZ-L).
 
D'autres variantes existent, qui codent un 1 ou un 0 avec un front, tandis que l'autre bit est codé comme en NRZ-L. Ces différentes méthodes se distinguent par des caractéristiques électriques qui sont à l’avantage ou au désavantage de l'un ou l'autre suivant la situation : meilleur spectre de bande passante, composante continue nulle/non-nulle, etc.
 
[[File:Binary Line Code Waveforms.png|centre|Illustration des différents codes en ligne.]]
 
====Les codes différentiels====
 
Pour plus de fiabilité, il est possible d'utiliser deux fils pour envoyer un bit (sur un bus série). Ces deux fils ont un contenu qui est inversé électriquement : le premier utilise une tension positive pour l'état haut et le second une tension négative. Ce faisant, on utilise la différence de tension pour coder le bit, ce qui est plus fiable que d'utiliser des tensions deux fois plus élevées, pour des raisons que nous passerons sous silence. Un tel codage est appelé un '''codage différentiel'''. Il est notamment utilisé sur le protocole USB. Sur ce protocole, deux fils sont utilisés pour transmettre un bit, via codage différentiel. Dans chaque fil, le bit est codé par un codage NRZ-L.
 
[[File:USB signal example.svg|centre|Signal USB : exemple.]]
 
==L'arbitrage du bus==