4. Le PC

  Dans ce paragraphe, nous allons considérer ce qui a trait au PC, mais uniquement dans le cadre qui nous intéresse, c'est à dire l'utilisation de la liaison RS-232. La figure 11 décrit les principaux composant du PC entrant en jeu dans la gestion de la RS-232.

Architecture du PC
Figure 11 : Architecture du PC pour la gestion de la RS-232

  Dans ce schéma, l'UART fait l'interface entre la RS-232, fondamentale série, et le bus du PC, qui est parallèle sur au moins 8 bits. Le microprocesseur gère les flux de caractères entrant et sortant. La ROM contient les procédures de gestion de l'UART (enfin, quand elles ne sont pas remplacées par des routines plus efficaces chargées depuis le disque dur…). La RAM contient les données à envoyer et celles reçues, ainsi que différentes informations sur l'état de l'UART comme l'adresse de base, le numéro de ligne d'IRQ (Interrupt ReQuest, numéro d'interruption matérielle - il y en a 15 différentes dans un PC), etc. Le PIC (Programmable Interrupt Controler) n'est utilisé, comme son nom l'indique, que dans la gestion par interruptions.

  Il existe deux moyens principaux de contrôler la liaison RS-232 : l'attente active et les interruptions.

4.1 La gestion par attente active

  Cette méthode, aussi appelée polling, consiste en une interrogation incessante du demandeur au fournisseur (de données, d'information, etc.). Dans notre cas, c'est le microprocesseur qui passe son temps à interroger l'UART. En effet, un bit dans l'UART informe le lecteur de l'arrivée d'un caractère, et un autre bit qu'un caractère a fini d'être transmis. Cette technique a l'énorme avantage d'être très simple à programmer ; par exemple, pour une simple réception de caractères, la boucle suivante suffit :

repeat
  repeat until UART_received_something;
  read_character_from_UART;
until false;

  Cette technique a cependant un défaut énorme : dans le cas de systèmes multitâches, elle occupe perpétuellement le processeur, et pour ne produire aucun effet quand le modem n'émet rien, ce qui peut durer longtemps. De plus, si le processeur n'est pas "en attente" au moment ou des caractères arrivent (il est par exemple en train de sauver les derniers arrivés dans un fichier), ils vont s'écraser les uns les autres dans le tampon de réception de l'UART, limité à un seul caractère. Enfin, lorsque l'on doit gérer à la fois l'émission et la réception, la programmation se complique un peu, même si cela n'a rien de critique :

repeat
  if UART_received_something
    then read_character_from_UART;
  if (UART_finished_sending and there_is_something_to_send)
    then send_character_to_UART;
until false;

Une solution plus performante en matière de gestion de la RS-232 consiste à utiliser une politique par interruptions.

4.2 La gestion par interruptions

  Cette méthode, aussi appelée callback, consiste, pour le fournisseur d'information, à faire remonter celle-ci jusqu'à son ou ses consommateur(s). Elle est bien plus complexe à programmer, mais donne des résultats naturellement meilleurs dans un système multitâches : le processeur ne s'intéresse à la RS-232 que lorsque l'UART lui signale que c'est nécessaire. Mais il faut alors gérer tout un nombre de problèmes périphériques : informer le système de la manière dont l'UART va signaler l'arrivée d'informations (numéro de ligne d'IRQ et routine de traitement associée, cf. plus loin), programmer PIC pour que cette ligne d'IRQ soit validée, gérer la communication avec les consommateurs de l'information que l'on obtient de l'UART, si ce n'est pas notre programme lui-même. Un exemple basique de programmation (il n'implante pas le chaînage et ne fonctionnerait sans doute pas s'il est programmé de manière aussi simpliste !) est proposé ci-dessous :

procedure installCallback;
  oldCallback = get_irq_vector(IRQ);
  set_irq_vector(IRQ, myCallback);
  oldIRQstat = PIC_get_line_stat(IRQ)
  PIC_enable_line(IRQ);
  oldCauses = UART_get_interrupt_causes;
  UART_enable_interrupt_causes(ALL_CAUSES);
end;

interrupt procedure myCallback;
  repeat
    case UART_most_important_interrupt_cause of
      character_received :
        read_character_from_UART;
      character_sent :
        if there_is_something_to_send
          then send_character_to_UART;
      modem_status_changed :
        read_modem_status_from_UART;
      transmission_error :
        get_error_status;
        handle_error_if_possible;
      noMoreCauses :
        PIC_signal_end_of_interrupt;
        exit_interrupt_procedure;
    end;
  until false;
end;

procedure releaseCallback;
  UART_enable_interrupt_causes(oldCauses);
  if (oldIRQstat)
    then PIC_enable_line(IRQ)
    else PIC_disbale_line(IRQ);
  set_irq_vector(IRQ, oldCallBack)
end;

  Comme on le voit, cette technique nécessite une programmation plus délicate, d'autant plus que les choses sont souvent un peu plus compliquées que cela ; la ligne d'IRQ peut par exemple être partagée entre plusieurs périphériques, et des IRQ risquent d'arriver à des instants impromptus, comme quand on programme le PIC…

  Pour bien comprendre ce qui se passe, regardons par exemple comment se déroule la réception d'un caractère depuis la RS-232. Un caractère arrive donc sur la ligne RD de la RS-232. L'UART le stocke dans son RSR, et lorsque le(s) bit(s) de stop sont arrivés, effectue des contrôles basiques (parité, régularité de la vitesse, etc.). Si tout s'est bien passé (ce que l'on va supposer), le caractère est déposé dans le RHR. Le bit 0 du LSR est mis à 1, pour signaler qu'un caractère a été reçu. Il peut donc maintenant être lu par polling. Ensuite, l'UART vérifie si les interruptions sont validées, et si la réception d'un caractère est une cause autorisée d'interruption. Si c'est le cas, l'UART émet au PIC un signal particulier, une IRQ (principe de remontée de l'information de celui qui la possède vers ceux qui l'utilisent). Le PIC commence par vérifier que cette IRQ a bien été démasquée par le microprocesseur, faute de quoi le processus s'arrêterait là. Cette IRQ est ensuite placée dans une liste des IRQ en attente à l'intérieur du PIC. Au bout d'un certain temps (qui peut-être relativement long, du moins à l'échelle électronique), l'IRQ de l'UART sera la plus prioritaire des interruptions en attente, et plus prioritaire que toutes les interruptions en service. La PIC émet alors pour son compte un signal INT (INTerrupt, tout simplement) vers le microprocesseur. Celui-ci, dès qu'il rencontre une fin d'instruction en étant en mode ininterruptible, interrompt son traitement en cours pour reconnaître l'interruption par l'émission en retour du signal INTA (INTerrupt Acknowledge). Le PIC sait qu'il a alors l'attention du microprocesseur et émet vers ce dernier un numéro d'interruption logicielle, lequel est obtenu par l'ajout d'une base préprogrammée par le microprocesseur au numéro d'IRQ actuellement la plus prioritaire (une autre peut avoir doublé l'IRQ de l'UART depuis l'émission du signal INT, mais on supposera que ce n'est pas le cas ici). L'IRQ de l'UART passe alors dans la file des interruptions en service. Les interruptions logicielles sont des déroutements programmés (au nombre de 256) dont les point d'entrée sont stockées dans un tableau (dit « Table des vecteurs d'interruption ») en mémoire. Le microprocesseur va donc chercher dans cette table le point d'entrée de l'interruption logicielle qui lui a été fournie par le PIC (dans notre cas, c'est la position en mémoire de la routine myCallback), et commence à exécuter cette routine. Il résout donc de ce fait toutes les causes possibles d'interruption, puis signale enfin au PIC que la procédure d'interruption est terminée. Le PIC ôte donc l'IRQ de l'UART de la liste des IRQ en service (ce qui peut éventuellement amener au déclenchement d'une nouvelle interruption). Le microprocesseur reprend alors son traitement interrompu.

  Cette opération semble souvent lourde à mettre en œuvre, et certains voient mal comment elle peut être plus rapide que la méthode par polling. Quand on sait qu'au niveau du microprocesseur, tout ceci ne se traduit que par l'exécution d'une centaine d'instructions supplémentaire, on comprend que ce soit plus efficace qu'une interrogation incessante ou le modem ne répondra présent qu'une fois sur plusieurs dizaines de milliers ! Deux conséquences à cette remarque : d'abord que si on a une machine très peu performante (un 8086, par exemple) et qu'on utilise une vitesse de transmission très élevée, le polling peut être plus rapide que les interruptions ! En effet, si le modem a quelque chose à transmettre lors d'une interrogation de polling une sur 2, et alors le surcoût d'une interruption n'aura pas à être payé. Cependant, il faut que le programme se contente de stocker les caractères en mémoire, sans réaliser d'autre traitement, sinon les caractères arriveront tellement vite que pendant le traitement supplémentaire, les caractères arrivant s'écraseront dans le tampon de réception de l'UART. Enfin, comme il est vrai que le surcoût d'une interruption est non négligeable (surtout dans les systèmes multitâches sécurisés, ou une commutation de contexte doit être réalisée à chaque fois), le tampon de réception des UART a été agrandi (à 16 et même jusqu'à 128 caractères !).

4.3 L'UART

  La liaison RS-232 est une liaison très répandue dans le monde informatique. La plupart des machines en possèdent une. L'UART d'Intel est l'une des implémentations d'un circuit périphérique de gestion de cette liaison. Étant présent dans les IBM PC et compatible, il a rapidement pris un poids important et toute une famille de circuits plus évolués mais compatibles avec lui ont vu le jour.

4.3.1 Architecture de l'UART 8250

  L'UART 8250 est le premier représentant d'une longue famille. Il est présenté sous un format DIP à 40 broches. Il possède une interface de bus de 8 bits. Tous les registres (à l'exception de deux qui seront détaillés plus loin) sont accessibles au travers du bus, certains en lecture seule, d'autres en lecture / écriture. L'UART est positionné à une adresse de base, qui est décodée par un circuit annexe, lui fournissant un signal de validation CS (Chip Select). L'UART ne décode que les 3 dernières lignes d'adresse (A0, A1 et A2), ce qui donne un total de 8 adresses réservées pour son compte.

Architecture du 8250
Figure 12 : Aperçu de l'architecture du 8250

  RSR (Receive Shift Register - registre à décalage en réception) : ce registre est un des rares à ne pas être directement accessible depuis le bus. En effet, sa largeur n'est pas de 8 bits, puisque tous les bits en provenance de la ligne RD pour transmettre un caractère y sont stockées à l'intérieur. Lorsque que le caractère est complet, des tests sont effectués sur ce RSR pour vérifier la validité des données, puis la partie « utile » du RSR est chargée dans le RHR - au risque d'écraser un caractère présent n'y ayant pas encore été lu.

  RHR (Receive Hold Register - registre tampon en réception ; Base + 0 lorsque DLAB=0 en lecture seule) : ce registre contient le dernier caractère reçu. Des informations de validité de ce caractère sont présentes dans le LSR. Si on lit plusieurs fois le RHR sans qu'un nouveau caractère soit arrivé, on lira toujours le même caractère… L'arrivée d'un caractère dans ce registre peut déclencher une interruption.

  TSR (Transmit Shift Register - registre à décalage en émission) : ce registre ne peut pas non plus être accédé depuis le bus, à l'exception d'une information : le fait qu'il soit vide, qui est accessible depuis le LSR. Lorsqu'il est vide, il est rempli automatiquement par tout nouveau caractère déposé dans le RHR. Des bits de start, de stop, de parité sont alors générés puis ces bits sont décalés vers la ligne TD. Le fait que l'on puisse savoir si le TSR est vide est importante. En effet, lors de l'émission d'un break, il faut s'assurer que tous les bits ont bien été transmis avant de faire forcer TD à la valeur 0.

  THR (Transmit Hold Register - registre tampon en émission ; Base + 0 lorsque DLAB=0 en écriture seule) : ce registre contient le prochain caractère à émettre. Lorsque son contenu est transféré au TSR, et donc qu'il peut à nouveau être chargé avec une nouvelle valeur à transmettre, un bit est modifié dans le LSR, et un interruption peut être déclenchée. Si on réécrit un nouveau caractère dans le THR avant que son contenu n'ait pu être transféré vers le TSR, l'ancienne donnée à transmettre est définitivement perdue.

  LSR (Line Status Register - registre d'état de ligne ; Base + 5 en lecture seule) : ce registre contient, bit par bit, un certain nombre d'informations :

  LCR (Line Control Register - registre de contrôle de la ligne ; Base + 3 en lecture/écriture) : ce registre permet de spécifier la configuration de la liaison RS-232. Il est en lecture/écriture pour pouvoir être lu, modifié, puis restauré dans son état initial.

  DL (Divisor Latch - Tampon de Diviseur ; Base+0 et Base+1 lorsque DLAB=1 en lecture/écriture) : ce registre est le seul registre 16 bits du 8250. Il détermine la vitesse suivant la formule suivante : vitesse = 115.200 / DL (en bits par seconde). Il ne peut cependant pas être accédé directement. Il faut pour cela que DLAB (bit 7 de LCR) soit positionné à 1 ; on accède ensuite à la partie basse de DL (DLL - DL Least) à l'adresse Base+0 et à la partie haute (DLM - DL Most) à l'adresse Base +1.

  MSR (Modem Status Register - registre d'état du modem ; Base+6) : ce registre indique l'état du modem, et surtout les modifications apportées à cet état depuis la dernière lecture du MSR. La signification des bits est la suivante :

MCR (Modem Control Register - registre de contrôle du modem ; Base+4 en lecture/écriture) : ce registre permet de positionner un certain nombre de lignes de la RS-232 :

IER (Interrupt Enable Register - registre d'autorisation de interruptions ; Base +1 en lecture/écriture lorsque DLAB=0) : ce registre permet d'autoriser et d'inhiber individuellement les différentes causes d'interruptions :

IIR (Interrupt Identification Register - registre d'identification des interruptions ; Base+2 en lecture seule) : Ce registre indique la cause actuellement la plus prioritaire d'interruption :

4.3.2 La famille des UART depuis le 8250

  Le 8250 n'est que le premier représentant d'une longue famille d'UART présent dans les PC. Celle-ci est trop nombreuse pour pouvoir être complètement citée ici ; cependant, un certain nombre de circuits ont produit des avancées technologiques notables :

Pour plus de détails sur les différents UART existant, allez donc voir les pages des constructeurs (entre autres, National Semiconductors®, Texas Instruments®, et Startech® - une filiale d'Exar®)

La liaison RS-232 Retour à l'index Le projet


Copyright (c) 1998 by Igx, the dreaming drummer…