Suivez-nous sur X
|
|
|
0,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z,
ALL
|
|
0,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z
|
|
0,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z
|
|
A propos d'Obligement
|
|
David Brunet
|
|
|
|
Dossier : Les communications par prise série
(Article écrit par Philippe Rivaillon et extrait d'Amiga News Tech - août 1992)
|
|
Nous allons ici aborder les communications entre ordinateurs par prise la série. Sans aller jusqu'au modem,
on peut grâce à elle relier ensemble deux ordinateurs, même radicalement différents. Vive la circulation des données !
Nous allons commencer à étudier la prise elle-même, afin de ne pas faire le câble à l'aveuglette.
Il faut tout d'abord rappeler que sur l'Amiga, la prise série est du type RS-232 femelle (25 broches).
Il en est de même sur les Atari ST et les anciens PC XT, mais l'on trouve sur la plupart des compatibles
PC récents, notamment les PC AT, une prise de type RS-422 femelle (9 broches). Nous décrirons ici ces
deux types de prises, en précisant que des adaptateurs 9/25 broches existent sur le marché.
Broche RS-232 |
Broche RS-422 |
Nom |
Sens |
Description |
1 |
- |
BND |
- |
Masse de protection |
2 |
3 |
TXD |
> |
Donnée émise |
3 |
2 |
RXD |
< |
Donnée reçue |
4 |
7 |
RTS |
> |
Demande d'émission |
5 |
8 |
CTS |
< |
Prêt à émettre (réponse RTS) |
6 |
6 |
DSR |
< |
Donnée prête à envoyer |
7 |
5 |
GND |
- |
Masse de référence (0 Volt) |
8 |
1 |
CD |
< |
Porteuse modem détectée |
20 |
4 |
DTR |
> |
Terminal prêt à recevoir |
22 |
9 |
RI |
< |
Indicateur de sonnerie (modem) |
Le signe inférieur (<) indique un signal en entrée, le signe supérieur (>), un signal en sortie.
Quelques données supplémentaires pour l'Amiga uniquement :
Broche RS-232 |
Nom |
Description |
14 |
-5V |
Alimentation disponible en -5V, 50 mA |
15 |
AUDO |
Sortie audio de l'Amiga |
16 |
AUDI |
Entrée audio de l'Amiga |
17 |
EB |
Horloge d'entrée-sortie à 716 kHz |
18 |
INT2 |
Entrée d'interruption de niveau 2 (CIA-A) |
21 |
+5V |
Alimentation +5V, 100 mA |
23 |
+12V |
Alimentation +12V, 50 mA |
24 |
C2 |
Horloge de transmission à 3,58 MHz |
25 |
RESB |
Sortie RESET du 680x0 |
On voit à partir de tout cela que deux câbles de liaison peuvent être réalisés : un complet et un
simplifié. Dans ce dernier cas, les choses se résument à une transmission "bestiale" :
vous devrez veiller à ce que le périphérique de destination soit en lecture avant d'envoyer vos
données. Pour des transferts de données importants entre deux ordinateurs, il vaut mieux utiliser
le câble complet afin d'assurer une transmission parfaite. Maintenant, à vos fers à souder...
La transmission des données à travers le port sériel est géré par le circuit UART (Universal Asynchronous
Receiver/Transmitter). Celui-ci permet d'envoyer et de recevoir à une vitesse voulue, des données
vers ou en provenance d'un autre périphérique ou ordinateur.
Une transmission se décomposera en
"paquets" composés d'un bit de démarrage, de huit ou neuf bits de données et d'un ou deux bits d'arrêt
marquant la fin des données. L'envoyeur devra distribuer lui-même les fragments de données les uns
après les autres dans un registre de départ. A la réception, ils seront tour à tour placés dans un
registre où le destinataire pourra en disposer et les ranger. La circuiterie UART dispose d'une
structure particulière destinée à éviter toute perte de donnée due à des envois trop rapprochés,
mais il convient tout de même de ne pas trop tarder à ranger les données reçues.
Pour qu'une transmission soit possible, il faut que les vitesses d'envoi et de réception soient les
mêmes : les deux ordinateurs doivent se synchroniser. Cette vitesse s'exprime en bauds (nombre de
bits par seconde) et doit être fixée par chacun des deux utilisateurs. Il en est de même pour le
nombre de bits de données compris dans un envoi (soit 8, soit 9). Ces choix s'effectuent à l'aide
du registre suivant :
SERPER |
Nom |
Fonction |
15 |
LONG |
Nombre de bits de données (0=8 bits, 1=9 bits) |
14-0 |
RATE |
Vitesse de transmission |
Les bits 0 à 14 permettent de fixer la vitesse d'envoi et de réception. Ce n'est toutefois pas une
valeur en bauds qu'il faut mettre ici : avec une valeur quelconque N, il s'écoulera (N+I).279.4 ns
entre chaque envoi ou réception d'un bit. Pour convertir une vitesse exprimée en bauds en la valeur à
disposer dans le registre SERPER, on utilise la formule suivante :
SERPER = (1/(bauds 279,4E-9)) - 1
|
Les vitesses maximum et minimum suggérées par les préférences du Workbench sont de 31 250
bauds (SERPER=114) et 110 bauds (SERPER=32536). Tenter d'utiliser des valeurs supérieures ou
inférieures reviendrait à se heurter à des problèmes lors des transmissions. La bonne moyenne est
de 9600 bauds (SERPER=372) (NDLR : le Minitel navigue à 1200 bauds (SERPER=2981)).
Transmission de données
Pour effectuer un envoi par la prise sérielle, c'est très simple : une fois la vitesse de transmission
et le nombre de bits de données choisis, il ne reste qu'à écrire le bloc à envoyer dans le registre
SERDAT. Le processus commencera alors de lui-même.
Chaque paquet débute par un bit de démarrage (START) et finit par
un ou deux bits d'arrêt (STOP), au choix. Le bit de démarrage est émis automatiquement par l'UART, il n'aura donc pas
à figurer dans le mot à transférer. Par contre, le ou les bits d'arrêt doivent être placés manuellement
par le programmeur.
SERDAT $DFF030 Port Sériel : données envoyées
|
Bit |
Nom |
Fonction |
15-10 |
- |
Inutilisés |
9 |
STP2 |
Bit d'arrêt en mode 9 bits |
8 |
STP1 |
Bit d'arrêt en mode 8 bits |
7-0 |
DB7-0 |
8 bits inférieurs des données transmises |
Pour utiliser un deuxième bit d'arrêt, il n'y a aucune manipulation particulière à faire : il suffit de le
mettre. Notez que l'ajout d'un deuxième bit d'arrêt ne garantira pas une meilleure transmission. Une fois
que vous avez écrit dans ce registre, les données sont transférées dans un tampon mémoire
interne. Le registre SERDAT est alors prêt à recevoir une nouvelle donnée et une interruption de niveau 1
est générée (bit 0, TBE, de INTREQ fixé) pour prévenir l'utilisateur.
Pendant ce temps, le circuit UART ne chôme pas : il transmet le contenu de son tampon mémoire
à la vitesse voulue. Pour cela, il commence par envoyer un bit de démarrage, puis il effectue une rotation
vers la droite du contenu du tampon mémoire et en profite pour envoyer le bit 0 vers la prise sérielle.
Il réitère ensuite cette dernière opération (rotation/envoi) jusqu'à ce que le tampon mémoire
ne contienne plus que des 0.
Une fois le tampon mémoire vide, et si aucune donnée n'a été placée dans SERDAT, l'utilisateur est prévenu
que tous les registres d'envoi sont vides : le bit TSRE de SERDATR est mis à 1 (voir plus bas pour la
description de ce registre).
Réception de données
Pour le circuit UART, cette réception débute par la détection d'un bit de démarrage. Il stockera ensuite
tous les autres bits dans un registre interne servant de tampon. Une fois le bon nombre de bits reçu
(nombre choisi dans SERPER plus 1 bit d'arrêt), il transfert le contenu de son regsitre interne dans
SERDATR, et déclenche une interruption de niveau 5 (bit 11, RBF, de INTREQ fixé) indiquant que l'on peut
disposer de la donnée en question.
Le temps dont on disposer pour s'occuper d'une donnée avant qu'elle ne soit écrasée par une autre est
bien sûr fonction de la vitesse choisie : 2*(SERPER+1)*nb_bits cycles d'horloge, soit la valeur du
registre SERPER multipliée par le nombre de bits transmis (bits de démarrage et d'arrêt compris), le tout
multiplié par deux car l'horloge sérielle est deux fois plus lente que celle du 68000. Si ce délai est
dépassé, l'ordinateur indiquera qu'il y a eu une perte de donnée à l'aide d'un bit spécifique placé
dans SERDATR (bit OVRUN).
SERDATR $DFF018 Réception de données du port sériel
|
Bit |
Nom |
Fonction |
15 |
OVRUN |
Indicateur d'Over Run |
14 |
RBF |
Tampon mémoire de réception plein |
13 |
TBE |
Tampon mémoire de réception vide |
12 |
TSRE |
Registre de transmision vide |
11 |
RXD |
Ce bit est la copie des données reçues par la broche RXD (41) de Paula.
Cela permet une visualisation directe des données reçues par le circuit UART |
10 |
- |
Inutilisés |
9 |
STP |
Bit d'arrêt reçu (2e en mode 8 bits) |
8 |
STP |
Bit d'arrêt reçu en mode 8 bits, ou 9e bit de données en mode 9 bits |
7 |
DB7-0 |
8 bits inférieurs des données reçues |
Le bit OVRUN indique qu'une donnée nouvellement arrivée en a écrasé une ancienne. Ce bit est mis à 1 si
le bit RBF de INTREQ était déjà 1 quand la nouvelle donnée a été copiée dans SERDATR.
Le bit RBF est la copie du bit 11 du même nom de INTREQ. S'il est à 1, cela signifie qu'une donnée
vient d'être copiée dans SERDATR et doit être prise en charge par l'utilisateur.
Le bit TBE est la copie du bit 0 du même nom de INTREQ. S'il est à 1, cela signifie que le
tampon mémoire d'envoi est prêt à recevoir une nouvelle donnée de la part du 68000.
Le bit TSRE indique que toutes les données ont été envoyées (données contenues dans le
tampon mémoire d'envoi et dans SERDAT).
Laissons le code parler
Le principe a beau être très simple, quelques petits problèmes se posent lors de son application :
sachant que nous allons utiliser le câble simplifié, le premier problème est de commencer la transmission
quand le récepteur est prêt. Pour cela, le récepteur émet des données de façon continue. Quand le transmetteur
en a reçu une, il envoie une donnée pour prévenir le récepteur qu'il va émettre, et le transfert réel
peut alors commencer.
Je ne voulais pas utiliser d'interruptions pour que l'exemple soit clair pour tous. Quelle n'a pas été
ma surprise de constater qu'à 9600 bauds, environ 1 donnée sur 50 étaient perdue !
Après m'être arraché la moitié des cheveux en cherchant d'où venait l'erreur, j'ai trouvé : le problème
venait du fait que le système ralentissait le programme et que je n'avais alors plus assez de temps
pour cueillir les données au bon moment. D'où la solution bestiale : couper le multitâche.
Si vous voulez être rigoureux et totalement en harmonie avec le système, vous devrez faire un programme
à base d'interruptions (le programme ci-dessous ne sera pas bien difficile à transformer).
*******************************************
* Transmission et réception de données *
* par prise SERIE *
* *
* Par RIVAILLON Philippe sur SEKA V3.2 *
*******************************************
START:
move.w $DFF01C,SAUVE_INTENA
or.w #$C000,SAUVE_INTENA
move.l 4,A6
jsr -132(A6)
move.l #500,D0 ; Longueur en octets
move.l #DATA,A0 ; Adresse source
bsr TRANSMISSION
; ET à l'autre bout:
; move.l #500,D0 ; Longueur en octets
; move.l #BUFFER,A0 ; Adresse destination
; bsr RECEPTION
move.w #$7FFF,$DFF09A
move.w SAUVE_INTENA,$DFF09A
move.l 4,A6
jsr -138(A6)
rts
TRANSMISSION:
; D0: longueur en octets
; A0: adresse source
; Met tout en place.
move.w #372,$DFF032 ; 9600 bauds, 8 bits
move.w #$0801,$DFF09A ; N'autorise pas interruptions
; concernant le port série.
move.w #$0801,$DFF09C ; efface interruptions demandées
; On attend que la liaison soit établie
BOUCLE_LIAISON_TRANS:
move.w $DFF018,D1
btst #14,D1 ; Attend une donnée
beq.s BOUCLE_LIAISON_TRANS
move.w #$0800,$DFF09C ; INTREQ réinitialisé
; On émet une donnée de fin de demande de liaison
move.w #$1FF,$DFF030 ; donnée de fin émise
move.w #$0001,$DFF09C ; INTREQ réinitialisé
; Les ordinateurs sont en liaison
subq.l #1,D0
BOUCLE_TRANS:
move.w $DFF018,D1
btst #13,D1 ; Test si SERDAT vide
beq.s BOUCLE_TRANS
move.w #$0100,D1
move.b (A0)+,D1
move.w D1,$DFF030 ; Envoi donnée
move.w #$0001,$DFF09C ; INTREQ réinitialisé
dbra D0,boucle_trans
rts
RECEPTION:
; D0: longueur en octets
; A0: adresse destination
; Met tout en place.
move.w #372,$DFF032 ; 9600 bauds, 8 bits
move.w #$0801,$DFF09A ; N'autorise pas interruptions
; concernant le port série.
move.w #$0801,$DFF09C ; efface interruptions demandées
; Emet des données en attendant de recevoir
; la donnée de fin de demande de liaison.
move.w #$1FF,$DFF030
move.w #$0001,$DFF09C ; INTREQ réinitialisé
BOUCLE_LIAISON_REC:
move.w $DFF018,D1
btst #13,D1
beq.s SUITE_BLR
move.w #$1FF,$DFF030 ; émet que $1FF si TBE=1
move.w #$0001,$DFF09C ; INTREQ réinitialisé
SUITE_BLR:
btst #14,D1 ; Attend une réponse
beq.s BOUCLE_LIAISON_REC
move.w #$0800,$DFF09C ; INTREQ réinitialisé
; Les ordinateurs sont en liaison
subq.l #1,D0
BOUCLE_REC:
move.w $DFF018,D1
btst #14,D1 ; Test arrivée d'une donnée
beq.s BOUCLE_REC
move.b D1,(A0)+ ; Range donnée
move.w #$0800,$DFF09C ; INTREQ réinitialisé
dbra D0,BOUCLE_REC
rts
SAUVE_INTENA: dc.l 0
BUFFER: blk.b 500,0
DATA: blk.b 500,0
|
|