UART

COM1 : 0x3F8 COM2 : 0x2F8

Il y a plus de 8 registres différents et on ne dispose que de 3 bits d'adresse. La solution est d'utiliser un bit d'un registre spécial, DLAB. Suivant l'état du bit DLAB, on va sélectionner tel ou tel registres.

 

Adresse

Registre

 

A2

A1

A0

Si DLAB=0

0

0

0

RBR : Receiver Buffer (registre de réception) en lecture
THR : Transmitter Holding Register (registre d'émission) en écriture

Si DLAB=1

0

0

0

DLL : Divisor Latch LSB (poids faible diviseur horloge)

Si DLAB=1

0

0

1

DLM : Divisor Latch MSB (poids fort diviseur horloge)

Si DLAB=0

0

0

1

IER : Interrupt Enable Register
 

0

1

0

IIR : Interrupt Identification Register
 

0

1

1

LCR : Line Control Register
 

1

0

0

MCR : Modem Control Register
 

1

0

1

LSR : Line Status Register
 

1

1

0

MSR : Modem Status Register
 

1

1

1

Non utilisé

Exemple : si l'adresse de base de l'interface est par exemple 3F8H, l'adresse du registre RBR sera 3F8H + 000 = 3F8H et celle de IIR 3F8H + 010b = 3F8H + 2H = 3FAH.

On voit, comme nous l'avons dit plus haut, que les registres DLM et IER (par exemple) possèdent la même adresse (001b). Si le bit DLAB est 0, cette adresse permet d'accéder à DLM, et si DLAB=1 à IER.

Le bit DLAB est le bit de poids fort du registre LCR.

Choix de la rapidité de modulation = Débit

115200 / vitesse = 256 * DLM + DLL
( en C : division modulo 256 : % ).

Registre THR : ( ) Registre d'émission.

Registre RBR : ( ) Registre de réception.

Registre LCR (Line Control Register) : Registre de commande pour définir certains paramètres de la transmission.

B7

B6

B5

B4

B3

B2

B1

B0

DLAB

0

0

0 : parité impaire
1 : Parité paire

0: Sans parité
1: Avec parité

0 : 1 bit stop
1 : 2 bits stop

B1B0=00 : 5 bits de data
B1B0=01 : 6 bits de data
B1B0=10 : 7 bits de data
B1B0=11 : 8 bits de data

Registre IER : Utilisé pour les entrées/sorties par interruption.

Bit 0 : interruption lorsque donnée reçue dans RBR;
Bit 1 : interruption lorsque registre THR vide;
Bit 2 : interruption lorsque l'un des 4 bits de poids faible de LSR passe à 1;
Bit 3 : interruption sur état du modem.

Registre LSR : Registre d'état rendant compte du fonctionnement en réception (bits 0 à 4) et en émission (bits 5 et 6).

Bit 0

passe à 1 lorsqu'une donnée a été reçue et chargée dans RBR.

Bit 1 

signale erreur d'écrasement. 1 si donnée reçue et chargée dans RBR alors que la précédente n'avait pas été lue. Remis automatiquement à 0 par la lecture du registre LSR.

Bit 2

passe à 1 à la suite d'une erreur de parité. Remis à 0 par la lecture de LSR.

Bit 3

passe à 1 lorsque le niveau du bit STOP n'est pas valide (erreur de format). Remis à 0 par la lecture de LSR.

Bit 4

passe à 1 lorsque le niveau de la liaison est resté à 0 pendant la durée d'émission de la donnée (problème de l'emetteur). Remis à 0 par la lecture de LSR.

Bit 5

passe à 1 lorsqu'une donnée est transférée de THR vers le registre à décalage d'émission (THR est alors libre pour le caractère suivant).

Bit 6 

passe à 1 lorsque le registre à décalage d'émission est vide.

Bit 7 

Toujours à 0

Registre IIR :

IIR est utilisé pour les E/S par interruption. Son contenu permet d'identifier la cause de l'interruption émise par l'UART.

Registre MCR : MCR est le registre de commande du modem.

Bit 0 : commande le niveau de DTR qui informe le modem que le µP est prêt à communiquer;
Bit 1 : commande RTS qui demande au modem d'émettre.



Registre MSR : MSR est le registre d'état du fonctionnement du modem.

Bit 0 : Changement de CTS
Bit 1 : Changement de DSR
Bit 2 : Changement de RING

II) Programmation de l'interface en langage C

unsigned char inportb( int address ) lit un octet à l'adresse (de l'espace d'entrées/sorties) indiquée et le retourne.

void outportb( int address, unsigned char *data ) écrit l'octet (argument data) à l'adresse (E/S) indiquée.

#include <dos.h>

/* Constantes pour ameliorer la lisibilite: */
#define PORT (0x3F8) /* adresse de l'interface */
#define RBR PORT
#define THR PORT
#define LSR (PORT+5)
#define IIR (PORT+2)
#define LCR (PORT+3) /* DLAB ... */
#define DLL PORT /* DLAB = 1 */
#define DLM (PORT+1) /* DLAB = 1 */
#define IER (PORT+1)
#define MCR (PORT+4)
#define MSR (PORT+6)


Init :

DLAB à 1 : ouptortb(LCR,0x80)
DLL en adbase
DLM en adbase+1
Config en LCR


Lecture_bit_registre :

Lire val, Masque=1, masque=masque<<n°bit, val = val&masque ( & = ET binaire pas logique )
Si val nul alors return 0 sinon return 1


Set_bit_registre

Masque=1, masque=masque<<n°bit ( 0 à 7 ), lire val, val = val | masque


Reset_bit_registre

Masque=1, masque=masque<<n°bit, masque = ~masque, lire val, val = val & masque


Réception carac :

Tant que bit 0 de LSR = 0 : attendre
Lire la registre de données


Emission carac :

Ecrire le registre de données
Tant que bit 6 de LSR = 0 : attendre


Interruptions :

Il faut détourner les interruptions
( void interrupt (*ancien_sousprg ), void interrupt nouveau_sousprog(); ,
getvect , setvect avec 0x0C pour COM1, 0x0B pour COM2 )

Il faut autoriser les interruptions sur le PIC ( mettre à 0 le bit 4 pour COM1 ou 3 pour COM2 de 0x21 )

Remarques :
1) Sur certaines cartes, la sortie OUT2 de l’UART intervient dans le contrôle d’interruption.
Il est parfois nécessaire de la mettre à 1 ( bit 3 mis à 1 dans MCR )
2) Il faut acquitter les interruptions dans le sous prog : outportb(0x20,0x20)