Retrouvez cet article dans : Linux Magazine Hors série 23
Le port
Un port parallèle IEEE 1284 se compose de 17 lignes (broches) de signaux et de 8 lignes connectées à la masse pour former les 25 broches d’un connecteur DB25 femelle à l’arrière d’un PC. A chaque ligne correspond un bit dans un registre donné. Le premier registre est accessible à l’adresse d’entrée/sortie propre à chaque port parallèle. Un certain nombre d’adresses sont standardisées comme 0x378 pour le premier port, mais des cartes additionnelles peuvent utiliser des adresses totalement différentes. Le premier registre est celui contrôlant les lignes de donnée, le deuxième, 8 bits plus loin concerne les lignes d’état et enfin, le troisième, les lignes de contrôle. Il faut clairement distinguer les signaux des registres. C’est une source de confusion importante lorsqu’on travaille avec ce port. Certains signaux sont actifs au niveau haut, ils sont vrais lorsque le signal est au +5 V. D’autres sont actifs au niveau bas, vrais lorsqu’ils sont à la masse. De la même manière, les bits des registres peuvent être à 1 logique en présence de +5 V et d’autres à 1 logique si la ligne est à la masse.
Fig. 1 - Brochage de l’interface parallèle d’un PC (DB25 femelle)
Pour faire la distinction entre des signaux de l’un ou l’autre type, on utilise une barre placée au-dessus du non du signal ou un slash (barre de fraction). Ainsi, /ERROR est un signal actif au niveau bas et BUSY est actif au niveau haut. De manière identique, les registres peuvent être actifs au niveau haut comme S5 (registre d’état, bit 5) ou actif au niveau bas comme /S7 (si le bit est à 1, c’est que la ligne est à la masse). Là où cela devient épineux, c’est dans le fait que cette notion d’activation au niveau haut ou bas est relative à un état (vrai/faux) par rapport à une tension (+5 V/masse). Ainsi, si nous choisissons la ligne 15, le signal est /ERROR. Cela signifie qu’en présence de +5V il n’y a PAS d’erreur. Le bit correspondant (S3) dans le registre d’état (STATUS) est actif au niveau haut, un 1 signifie +5 V sur la broche 15. Cependant si ce bit est à 1, c’est qu’il n’y a PAS d’erreur. On n’écrit pas /S3 car le registre n’est pas actif au niveau bas, 1=+5 V. Le bit n’est pas actif par rapport à la véracité (l’état) du signal, mais par rapport l’état de la ligne (tension). Ajoutons une couche pour être sûr que tout cela soit assimilé. La ligne BUSY (11) est active au niveau haut. S’il y a présence de +5 V c’est que le périphérique est occupé. Le bit /S7 du registre d’état est actif au niveau bas, il sera à 1 si la ligne est à la masse. Il faut procéder par étape. En lecture, il faut lire le bit, en conclure l’état de la ligne (+5 V ou masse) puis en déduire la signification du signal. En écriture, il faut décider du signal, déduire l’état à appliquer à la ligne et choisir la valeur du bit dans le registre. Notre travail ici est simplifié puisque nous ne cherchons pas à développer un périphérique de type imprimante. La signification des signaux n’importe pas vraiment, nous voulons simplement utiliser les entrées et les sorties.
DATA
Il s’agit là des 8 lignes de données du port parallèle en bleu sur la figure 1. Normalement en sorties, ces lignes peuvent également être lues si le port est en mode bidirectionnel (voir section "Modes du port parallèle"). Dans tous les cas, il est possible de lire à l’adresse d’entrée/sortie du port (0x378 par défaut pour le premier). C’est la pertinence des informations qu’il faut prendre en considération. Avec un port non bidirectionnel, vous lirez la dernière valeur envoyée. Dans le cas contraire, les données lues peuvent être envoyées par le périphérique.STATUS
Accessibles à l’adresse du port plus 1, ces lignes sont en lecture seule et permettent d’obtenir des informations de la part du périphérique :- /ACK (bit 6 – broche 10) : le périphérique met cette ligne à l’état bas brièvement (environ 5 µs) pour indiquer à l’ordinateur qu’il a bien reçu le caractère transmis précédemment. C’est un signal d’accusé de réception.
- BUSY (bit 7 – broche 11) : actif au niveau haut cette ligne indique un état spécifique du périphérique, celui-ci ne peut plus recevoir de données et les traiter. L’ordinateur doit attendre que le périphérique soit à nouveau disponible.
- PE (bit 5 – broche 12) : " paper error ", " paper out " ou " paper empty " selon les documentations. Cette ligne indique que l’imprimante n’a plus de papier.
- ON LINE ou SELECT (bit 4 – broche 13) : cette ligne indique à l’ordinateur que le périphérique est en ligne (" on line ")
- /ERROR (bit 3 – broche 15) : indique à l’ordinateur que le périphérique est en erreur. Ce signal est actif au niveau bas et le registre au niveau haut. En clair, si à la lecture vous avez un 1 logique, c’est qu’il n’y a PAS d’erreur.
CONTROL
En vert sur le schéma en figure 1, les lignes de contrôle sont au nombre de 4 et permettent le pilotage de l’interface et la négociation avec l’imprimante. Il s’agit de sorties :- /STROBE : ce signal indique à l’imprimante que des données sont présentées sur les lignes de données et qu’elle doit les prendre en compte. Ce signal, comme les suivants, est actif au niveau bas (donc préfixé d’un slash). Ceci signifie que lorsqu’on veut signaler à l’imprimante la présence de données, on passe brièvement (moins de 0.5 µS) le signal à la masse avant de revenir au +5 V.
- /AUTOFEED : ce signal demande à l’imprimante de faire automatiquement un saut de ligne. A l’époque des imprimantes matricielles, certaines configurations d’imprimante ne faisaient pas de " retour, à la ligne " (CR/LF), mais un simple retour de la tête d’impression en début de ligne (CR). Il fallait donc logiciellement avancer le papier d’une ligne (LF) de manière automatique si les données ne contenaient qu’un retour chariot.
- /SELECT IN : ce signal permet une sélection d’imprimante. Tout comme avec certains composants que nous verrons plus loin dans ce hors-série, cette ligne active au niveau bas permet de signaler au périphérique qu’il est sélectionné et que les ordres émis le concernent.
- /INIT : via ce signal, l’ordinateur peut demander une réinitialisation de l’imprimante. Là encore le signal est actif au niveau bas, ce qui signifie qu’il faut mettre la ligne à la masse pour réinitialiser l’imprimante.
Modes du port parallèle
Pour l’heure, nous n’avons parlé que d’un seul mode du port parallèle : SPP pour Standard Parallel Port. Dans ce mode également appelé " Printer Mode ", les lignes de données du port ne peuvent être utilisées qu’en mode unidirectionnel. Le mode SPP peut également, selon l’interface, être utilisé de manière bidirectionnelle. On utilise le bit 5 du registre des lignes CONTROL pour inverser le mode de fonctionnement des huit lignes de données. En plaçant ce bit à 1, on peut lire les lignes DATA comme valeurs d’entrées et non plus comme dernières valeurs envoyées (latchs). Si le port n’est pas en mesure de travailler de manière bidirectionnelle, l’écriture du bit 5 n’aura aucun effet. SPP/EPP1.7/EPP1.9, parfois noté simplement EPP dans l’écran de configuration du BIOS est le mode le plus intéressant pour une machine moderne. EPP, Enhanced Parallel Port, est le résultat d’un rapprochement des sociétés Intel et Xircom & Zenith Data Systems. Le mode EPP présente l’intérêt de pouvoir continuer à travailler comme avec le mode SPP. Les registres SPP sont utilisables comme expliqué plus haut (base, base+1 et base+2) en tenant compte du fait que le bit 5 du registre CONTROLE permet d’inverser le sens écriture/lecture pour les lignes de données. Deux adresses supplémentaires, base+3 et base+4, donnent respectivement accès aux registres des ports d’adresses EPP et de données EPP. Un port parallèle en EPP peut donc être librement utilisé selon les besoins. La différence entre les versions 1.7 et 1.9 du mode EPP réside principalement dans l’absence du bit de timeout. Dans tous les cas, on préfèrera le standard le plus récent possible à moins d’avoir une bonne raison de choisir 1.7 (compatibilité avec un périphérique). Enfin, nous avons le mode ECP pour Extended Capabilities Port développé par Hewlett Packard et Microsoft. Ce mode est également compatible SPP et utilise des registres de configuration supplémentaires comme EPP : Base+0x400 pour les données en FIFO en mode FIFO ou configuration. A en mode configuration, Base+0x401 pour le registre de configuration B en mode configuration et Base+0x402 pour le registre ECR (Extended Control Register) dans tous les modes. Le mode ECP présente quelques caractéristiques majeures dont l’utilisation d’un canal DMA et un tampon FIFO pour les données. Cependant, ces éléments ne sont intéressants qu’en cas de débit important (périphérique bloc sur port parallèle) et sont largement compensés par une certaine difficulté d’utilisation. On notera que la grande majorité des BIOS permettent de configurer le port parallèle intégré à la carte mère en mode multiple. Ainsi, vous pouvez choisir ECP/EPP1.9 pour cumuler tous les avantages : port bidirectionnel SPP, registres du mode EPP base+3 et base+4, registre et mode de configuration ECP/ECR.Support Linux
Le noyau Linux prend en charge parfaitement les ports parallèles de tout type et dans tous les modes. Depuis la version 2.4 du noyau, le support de cette interface est devenu très hiérarchisé. Nous avons d’un coté le support spécifique à chaque plate-forme dont le plus utilisé estparport: PnPBIOS parport detected. parport0: PC-style at 0x378 (0x778), irq 7, dma 3 [PCSPP,TRISTATE,COMPAT,EPP,ECP,DMA]Le noyau 2.6 est quelque peu plus bavard que le 2.4, puisqu’il informe des différents modes supportés par l’interface, mais aussi des IRQ et DMA utilisés (selon le mode) et des adresses utiles. Vous retrouverez une partie de ces informations dans
Etat du port au démarrage de la machine
Aucune documentation officielle ni standard ne définit clairement l’état des lignes du port parallèle au démarrage d’un PC. Pire encore, durant le processus de démarrage entre l’initialisation par le BIOS, le chargement puis l’exécution du noyau et le lancement des différents services, les différentes lignes du port parallèle changent d’état. Pour cette raison, le périphérique doit réagir ou plutôt ne pas réagir en conséquence. Il était de coutume, fut un temps, de n’allumer l’imprimante qu’après le démarrage complet du système. On retrouve encore ce type de recommandation dans certaines documentations constructeur. J’ai cependant constaté sur bon nombre de machines que la ligne /STROBE restait, de la mise sous tension à l’utilisation par un outil logiciel, à l’état haut (+5 V). Ceci paraît parfaitement logique étant donné la fonction du signal. Toutefois, il ne s’agit là que d’une constatation empirique. Prenez garde, lors de la conception d’un nouveau montage connecté à ce port de ne pas le laisser agir/réagir avant une étape où vous avez entièrement le contrôle. Bien entendu, lorsqu’il s’agit du module LCD ou d’afficheurs lumineux, ceci n’est en rien critique. Il n’en va pas de même avec une carte à relais ou un triac pilotant des équipements importants (éclairage, moteur, etc.).Programmation : les mauvaises solutions
L’accès et la programmation de l’interface parallèle sous Linux est un vaste domaine qui pourrait couvrir la totalité de ce magazine. Nous ne traiterons ici que les cas les plus courants. Il existe plusieurs manières de piloter les lignes du port parallèle. Nous allons les voir de la plus mauvaise à la plus convenable.La méthode sauvage
Des lecteurs ayant déjà développé des applications sous MS/DOS sauront qu’il n’est pas difficile de piloter directement le port parallèle sans l’assistance du système. En mode SPP, les adresses du port sont connues. Habituellement 0x378 est l’adresse d’entrée/sortie de base du premier port parallèle (LPT1). Avec les anciennes versions du noyau Linux, accéder directement au port via cette adresse était la seule manière de le contrôler. Aujourd’hui, il s’agit tout simplement de la technique la plus " sale ". On utilisera les fonctions de bas niveau #include<unistd.h>
#include<stdio.h>
#include <asm/io.h>
#define BASEPORT 0x378
int main(int argc, char **argv)
{
if(ioperm(BASEPORT,3,1)) {
perror("ioperm");
exit(1);
}
outb(11,BASEPORT);
printf("lu : %X\n", inb(BASEPORT+1));
return(0);
}
Je vous ai prévenu, c’est moche. On utilise la fonction /dev/port
Sous GNU/Linux, il existe une méthode alternative permettant d’accéder aux ports d’entrée/sortie. Il suffit, en effet, d’utiliser#!/usr/bin/perl -w use Fcntl; $BASE=888; sysopen(PORT, “/dev/port”, O_WRONLY) or die “Impossible d’ouvrir le fichier : $!\n”; binmode(PORT); sysseek(PORT, $BASE,0) or die “Probleme seek : $!\n”; syswrite(PORT, chr(1) ) or die “Probleme syswrite : $!\n”; Close PORT or die “Probleme close : $!\n”;Comme précédemment, ces exemples ne sont qu’indicatifs. Il existe une méthode bien moins dangereuse et applicable aussi bien à du code C que Perl.
ppdev : programmation propre du port
Voici la méthode " normale " pour une application devant accéder aux lignes du port parallèle. L’accès depuis l’espace utilisateur se fait selon deux techniques en fonction des besoins. Si votre application doit envoyer des données à une imprimante, cela se fera via le protocole " imprimante " et#include <sys/ioctl.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/errno.h>
#include <linux/ppdev.h>
#include <linux/parport.h>
int errno, fd;
if ((fd = open("/dev/parport0", O_RDWR)) < 0) {
fprintf(stderr,"Open Error : %s (%d)\n",
strerror(errno),errno);
exit(EXIT_FAILURE);
}
Dès le descripteur de fichier obtenu, il est nécessaire de demander l’accès au port. Celui-ci peut être refusé par le système car une autre application ou un module noyau en a obtenu l’accès exclusif. On a généralement le problème lorsque if (ioctl(fd, PPCLAIM) < 0) {
fprintf(stderr,"PPCLAIM ioctl Error : %s (%d)\n",
strerror(errno),errno);
exit(EXIT_FAILURE);
}
Si cette commande réussit, on peut manipuler les lignes à loisir puis, au terme de la procédure, on rend la main et on referme de fichier :
if (ioctl(fd, PPRELEASE) < 0) {
fprintf(stderr,"PPRELEASE ioctl Error : %s (%d)\n",
strerror(errno),errno);
exit(EXIT_FAILURE);
}
if(close(fd) < 0) {
fprintf(stderr,"Close Error : %s (%d)\n",
strerror(errno),errno);
exit(EXIT_FAILURE);
}
La commande Écriture des données
Une fois l’accès au port obtenu, l’action la plus courante est d’écrire sur les lignes de données. On utilise la commandeunsigned char valout=0x01;
if (ioctl (fd, PPWDATA, &valout) < 0) {
fprintf(stderr,"PPWDATA ioctl Error : %s (%d)\n",
strerror(errno),errno);
exit(EXIT_FAILURE);
}
Le port parallèle n’est pas en mesure de fournir suffisamment de courant pour toutes les applications. Vous pouvez parfaitement connecter une LED sur chaque ligne de données via une résistance de 470 Ohms et contrôler leur allumage via ce type de code. Cela n’ira pas plus loin. Les lignes du port parallèle sont conçues pour véhiculer des signaux et vous pourrez y connecter toutes sortes de circuits logiques. Mais s’il vous faut piloter des composants nécessitant beaucoup de courant, l’utilisation de transistors en saturation ou d’optocoupleurs est indispensable.
Lecture des données
Cela a été dit plus haut, les lignes de données peuvent fonctionner de manière bidirectionnelle. Techniquement, c’est le bit 5 du registre des lignes CONTROL qui permet de passer les lignes de données en entrée. Avec
Fig. 2 - Exemple théorique du fonctionnement interne du mode bidirectionnel des lignes de données du port parallèle. Le bit 5 du registre CONTROL désactive le latch et permet au périphérique de contrôler les lignes dont nous lisons l’état dans le buffer. Si le périphérique impose un +5 V sur une ligne alors que le latch est activé un risque de court-circuit existe.
Il est important de négocier avec votre périphérique ou votre montage le moment où celui-ci pourra émettre des données et donc contrôler les lignes. Vous pouvez utiliser les lignes CONTROL et STATUS qui sont unidirectionnelles pour cette négociation. La quasi-totalité des ports parallèles disposent, en entrée sur les lignes de données, de résistances de pull-up (rappel au +5 V). Il s’agit de résistances qui ramènent la ligne au +5 V de manière à obtenir un 1 logique en l’absence de connexion. unsigned char valin;
int dirin=1;
int dirout=0;
if (ioctl (fd, PPDATADIR, &dirin) < 0) {
fprintf(stderr,"PPDATADIR ioctl Error : %s (%d)\n",
strerror(errno),errno);
exit(EXIT_FAILURE);
}
if (ioctl (fd, PPRDATA, &valin) < 0) {
fprintf(stderr,"PPRDATA ioctl Error : %s (%d)\n",
strerror(errno),errno);
exit(EXIT_FAILURE);
}
Si on applique un signal haut (+5 V), rien ne change et si on met la ligne à la masse, on obtient un 0 logique. Dans tous les cas, l’état d’une ligne n’est donc jamais indéfini. Toutes les documentations consultées sont d’accord sur un point : aucun fabricant ne semble suivre une ligne directrice unique et il devient nécessaire de tester avant toute connexion et configuration. Placez les lignes en entrée et lisez avec PPRDATA. Écrivez une valeur quelconque et relisez. La valeur lue ne doit pas être celle précédemment écrite si les lignes sont effectivement configurées en entrée.
A ce moment, vous pouvez partir du principe que le PC ne contrôle plus les lignes et vous pouvez relier l’une d’elle à la masse avant de lire à nouveau avec PPRDATA. Là, vous devez voir changer le bit correspondant dans le registre. Si votre groupe de ligne ne dispose pas en interne de résistances de pull-up, vous pouvez les ajouter à l’extérieur (voir la partie concernant les lignes STATUS ci-après).
Lecture de l’état
Pour lire le registre d’état et donc l’état des lignes 10, 11, 12, 13 et 15, il suffit d’utiliser la commandeunsigned char status;
if (ioctl (fd, PPRSTATUS, &status) < 0) {
fprintf(stderr,"PPRSTATUS ioctl Error : %s (%d)\n",
strerror(errno),errno);
exit(EXIT_FAILURE);
} else {
if (status & PARPORT_STATUS_ERROR) {
printf(“Pas d’erreur (1)\n”);
} else {
printf(“Erreur (0)\n”);
}
}
Normalement, tout comme avec les lignes de données, des résistances de pull-up internes au port permettent un rappel au +5 V. Cependant, comme il n’est pas garanti que ce fait soit établi sur toutes les machines, on utilisera un montage comme celui présenté en figure 3.

Fig .3
Les résistances de 4.7 K Ohms forcent l’état haut en l’absence de pression sur les boutons poussoirs. Lorsqu’on établit la connexion, on force la ligne à la masse et la résistance limite le courant selon la formule U=R.I, soit 5=4700*I, soit 5/4700=1mA... négligeable. Bien entendu, des résistances plus importantes (10 K Ohms) feront également l’affaire. Le schéma présenté est complètement théorique. Il présente des boutons poussoirs ayant ce qu’il est courant d’appeler " la maladie des rebonds ". A l’échelle du PC, le contact du bouton n’est pas franc, mais entrecoupé à cause de raisons mécaniques évidentes. Un autre article présente une solution à ce type de problème. D’autre part, la liaison avec un circuit logique (TTL/CMOS) ne pose pas de problème et les résistances de pull-up deviennent inutiles.Écriture des lignes de contrôle
Si les huit lignes de sortie ne sont pas suffisantes pour votre application, vous pouvez également " piocher " dans les quatre lignes du groupe CONTROL. La commandestruct ppdev_frob_struct {
unsigned char mask;
unsigned char val;
}
Si nous souhaitons changer l’état de la ligne STROBE, il nous suffit alors de faire ceci :
Ici, nous passons la ligne STROBE à 1 logique (état bas sur la ligne)Conclusion
Nous venons de voir le principe de fonctionnement de base du port parallèle et la méthode d’usage pour l’accès depuis un code utilisateur sous GNU/Linux. Il reste un certain nombre de choses à explorer parmi lesquelles le développement d’un code noyau pilotant un montage sur ce port et la gestion des interruptions dans un code utilisateur. Ces deux sujets seront traités par ailleurs dans le présent hors-série dans le cadre d’une mise en pratique. Si vous voulez en apprendre davantage sur le port parallèle, son fonctionnement et sa programmation, référez-vous aux liens ci-dessous. Liens- Interfacing the Standard Parallel Port : http://www.beyondlogic.org/spp/parallel.htm
- The Linux 2.4 Parallel Port Subsystem : http://people.redhat.com/twaugh/parport/html/parportguide.html
- Parallel port interfacing made easy : http://www.epanorama.net/circuits/parallel_output.html
Retrouvez cet article dans : Linux Magazine Hors série 23





Bonjour. Cet article est génial : c’es juste ce que je cherche. Cependant j’ai une question à propos des adaptateurs usb/parallèle : sont-ils reconnu comme étant un port parallèle ou un port usb par le système linux?
Merci à tous ceux qui me répondrons.
Bonjour,
les ports parallèles sont de moins en moins présents sur nos PC (surtout sur les portables !). Précisons qu’il existe des convertisseurs USB-Parallèle qui permettent de résoudre le problème. Pour les plus curieux ces convertisseurs utilisent souvent un chipset Prolific PL 2305. http://www.prolific.com.tw/eng/Download-2.asp?ID=17
On peut trouver des vendeurs comme SparkFun http://www.sparkfun.com qui montent ce genre de chipsets (souvent des Composants Montés en Surface CMS) directement sur des circuits imprimés appelés « Breakout board »
D’autres références de chipsets permettant la convertion USB/Parallele peuvent être trouvés en regardant la liste des Vendor ID (VID) / Product ID (PID) de périphériques USB : http://www.linux-usb.org/usb.ids et en recherchant le mot « parallel ».
Vous pouvez aussi acheter directement une carte d’acquisition à faible coût (à base de microcontroleur) pour laquelle des drivers Linux existent. Cela vous permettra outre d’avoir des entrées/sorties numériques, de disposer pour un coût modeste également d’entrées/sorties analogiques : citons par exemple Labjack U12 http://www.labjack.com/labjack_u12.php ou en totalement libre Arduino http://www.arduino.cc
(la bande passante de tels dispositifs est loin d’être au top de la technologie mais pour du contrôle de procédés lents c’est souvent suffisant.
Cordialement