Bus filaire ; interfaces, débit, protocoles, timing

 


Transmission des données

On pourrait inventer un protocole de transmission, ou bien utiliser le protocole série standard. Ce dernier

permet en plus de disposer d'une interface quasi compatible sur chaque PC avec les ports COM.

On choisit donc de rester à une transmission série standards.

 

Standards EIA :

 

CARACTERISTIQUES

EMETTEUR

RECEPTEUR

CIRCUIT

RS232

Point à point

MAX232

RS422

1 vers 10, full duplex, différentiel, 1200m

Zout<100 Ω, Vdiff [2V,5V]

Zin>4 kΩ, Vcm [7V,7V], ∆Vin>200mV

LS31, LS32

RS485

32 vers 32, half duplex, différentiel, 1200m, 2 Mbps

Zout<20 Ω, If<100 A, Vdiff [1.5V,5V], Idrive<150mA

Zin>12 kΩ, Vcm [7V,12V], ∆Vin>200mV

75176, ADM485, LTC485, MAX485

 

C'est le RS485 qui permet le plus de chose, c'est le réseau le plus récent, il est compatible avec les autres.

 


Connexion au bus : ADM485, LTC485, MAX485, 75176

Le bus est interfacé avec des circuits standards : ADM485, LTC485, MAX485, 75176

Table I. Transmitting

Inputs

Outputs

/RE

DE

DI

B

A

X

1

1

0

1

X

1

0

1

0

X

0

X

Z

Z

Table II. Receiving

Inputs

Outputs

/RE

DE

A-B

RO

0

0

> +0.2V

1

0

0

<= -0.2V

0

0

0

Inputs open

1

1

0

X

Z


On peut relier ensemble /RE et DE ou bien de piloter que DE (prise de ligne) et laisser /RE à la masse pour recevoir toujours. Dans ce cas, le récepteur marche toujours, on peut mettre une LED pour montrer l'activité du réseau, et le micro-processeur gérera lui même la réception (bit REN du MCS51).


Normallement le bus domotique est en half duplex et les émetteurs/récepteurs RS485 sont conçus pour le half duplex.

 

Le câble et les connecteurs

On a 3 solutions simples, utilisant des connecteurs modular jack à très faible coût.

J'ai choisi d'utiliser des 4P4C, mais à l'usage, je me demande si des 6P4C n'auraient pas été mieux justement grace à l'abondance des cables et accessoires disponibles en grande surface.


Assignation des signaux sur le câble

Un câble plat 4 conducteurs destiné aux prises modular jack, peut être inséré dans la prise de 2 façons.

Cette ambiguïté peut causer des dégats.

4 cas de câblage sont possibles :

 

non symétrique : A et B ne sont pas symétriques dans le câble

symétrique : A et B sont symétriques dans le câble

jaune

noir

0 V

0 V

0 V

A

vert

rouge

V+

A

A

0 V

rouge

vert

A

V+

B

V+

noir

jaune

B

B

V+

B

Effet d'une inversion :

Puissance sur bus AB : létal pour un transceiver RS485, acceptable pour interphone

Bus inversé ; sans danger

Polarité puissance inversée sans danger si diode installée


Montage des prises RJ9


Par convention, on décide que le câble noir est à gauche de la prise 4P4C vue de face ou de dessus, ergot en dessous.

 


Débit et format de la liaison

D'abord on ne retient que les débits accessibles sur un port COM PC. Les débits 14400 et 28800 (modems), ou 31250 (bus MIDI) ne sont pas considérés.


300

600

1200

2400

4800

9600

19200

38400

57600

115200


La gamme de débit va de 1200 à 57600 bauds, pas la peine de perdre du temps sur des débits inférieurs. La valeur nominale est prise à 9600 bauds pour faciliter la topologie du réseau et l’extension via radio. Le débit pourrait être variable, mais comment le faire varier une fois le réseau installé ? Le central envoie un ordre à tous les terminaux (broadcast) ; ils enregistrent la nouvelle vitesse dans l'E2PROM locale, et change la vitesse ensembles.

Cas d'un 8031, famille MCS51

On peut utiliser l'UART MCS51 en mode 2 (9 bits), dans ce cas le débit vaut Fx/64 ou Fx/32 (173 kbps @11.0592 MHz). Ces débits risquent sont trop rapides pour une ligne standard sur cable téléphonique avec un réseau en étoile, ils ne sont pas non plus compatibles d'un pilotage/espionnage par un PC sur port série standard.

Donc on utilise l'UART en mode 1 ou 3 (8 ou 9 bits, variable) avec le timer 1 pour générer la cadence. Le mode du timer est 2 (reload sur TH1, SMOD=1), le quartz Fx est de 11.0592 MHz ou 22.1184 MHz pour avoir des débits normalisés compatibles d'un pilotage par port série d'un PC.


Débit (bps)

Durée bit (μs)

MCS51 @11.0592MHz

MCS51 @22.1184MHz

PIC @4MHz

Soft UART

Vitesses PC

 

300

3333

impossible

impossible

ok

ok

 

600

1667

-96, A0h

impossible

ok

ok

 

1200

833.3

-48, D0h

-96, A0h

ok

ok

ß possible

2400

416.7

-24, E8h

-48, D0h

ok

ok

ß possible

4800

208.3

-12, F4h

-24, E8h

ok

ok

ß possible

9600

104.2

-6, FAh

-12, F4h

ok

ok

ß nominal

19200

52.1

-3, FDh

-6, FAh

ok

ok

ß possible

38400

26.0

impossible

-3, FDh

impossible

ok

 

57600

17.4

-1, FFh

-2, FEh

impossible

ok

ß possible

115200

8.7

impossible avec timer 1, possible avec Timer2

-1, FFh

impossible

ok

 

Cas d'un PIC avec UART intégrée ; PIC16F628, PIC18F452…

Ces circuits récents disposent d'un générateur de bauds BRG, dont la valeur est Fosc/Bauds/16-1 pour les premiers circuits dotés d'un générateur de bauds sur 8 bits, et Fosc/Bauds/4-1 lorsqu'il est sur 16 bits (on suppose qu'on est toujours en BRGH=1 pour avoir accès aux débits les plus forts).


Format ; parité ou non ?

Si tous les messages sont encapsulés et munis d’une somme de contrôle, il n’est pas nécessaire d’utiliser un bit de parité. Cela facilite aussi l’utilisation d’un terminal ASCII standard.

D'un autre côté, il faut que le 9ème bit transmis soit à 1 pour faire un stop, contrainte issue de la gestion du half duplex.

On peut donc ne pas utiliser le bit parité. Le format de la liaison est donc 8-N-1.

 


Gestion du half duplex

Nous n'avons qu'un seul médium, et alternativement les connectés vont écouter puis parler : il faut gérer le "drive enable" de chaque côté : terminaux ou central.

L'émission vue d'un terminal

 

Prenons le timing du port série d’un µcontrôleur MCS51. Le signal DE sera mis à 1 par le µcontrôleur  dès qu’on rentre dans la routine d’envoi de caractères (SendK). A la fin de l’émission du 9ème bit, le signal TI monte, et une interruption est générée.

La routine d’interruption va remettre à zéro le signal DE, et donc la ligne va repasser en flottant au tout début du bit stop. Pour éviter cela il faudrait attendre une durée bit (104µs), mais à condition que TB8 soit mis à un pour faire le bit stop, on a un format 8-N-1, au moins et donc ce n'est pas gênant.

Il est donc impossible que ce bit soit utilisé pour une parité.

Par contre, il ne faut pas que le flottement du bus, juste après TB8 puisse être compris comme un zéro, donc comme un start. Il faut  polariser le bus, faiblement, mais suffisamment pour présenter un niveau 1, mais dans certains cas, cela ne suffit pas à recharger le bus si le caractère est nul.



Du vécu : artefacts à l'émission d'un terminal

Lorsqu'un terminal a un train d'octets à envoyer, ET que le temps de process interne au terminal est  supérieur au temps d'émission, alors le bus va être relaché à la fin de chaque caractère, et selon les conditions, il peut apparaitre un start parasite.

 

C'est ce qu'on observe ci-dessous (bus non polarisé)

M2(0000) : FA 1>vh

0000: ðFA àFA À31 ø31 ø0F àFF ðFF ðFF  €90 ð07 02 ð00 À01 ð00 àFF ðFF

0010: ø92 ü09 øE2 ø00 à01 ð00 àFF ðFF  ÀFF øFF øFF øFF ø11 øFF øFF øFF

0020: üFF øFF øFF øFF øFF øFF øFF øFF  ÀFF øFF øFF øFF øFF øFF øFF øFF

...

Chaque fois que le microC a un peu de boulot (ici aller chercher 8 octets en E2PROM pour en envoyer 1 seul) on voit apparaitre un caractère parasite reçu par le PC ; les caractères parasites sont 80, C0 (À), E0, F0 (ð), F8 (ø), FC (ü), FE,FF.

Ces caractères sont typiques d'un bit start parasite (le poids faible suit le bit start). Lorsque le terminal relache le bus RS485, il apparait une mise à 0 qui dure un peu (jusqu'à 8 bits @9600 bauds soit 800 micro-sec). Quand on règle la vitesse à 2400 bauds, il n'y a plus d'artéfact, mais à 4800 il y en a beaucoup plus.

Donc on modifie le code du moniteur pour aller un peu plus vite. Et çà marche, mais cela est ponctuel, et selon la durée de traitement le phénomène risque de se reproduire. On l'observe à nouveau par exemple sur une réponse avec un délai nécessaire pour faire une acquisition sur un ADC 12 bits.

On pourrait polariser faiblement le bus pour qu'on lise un état 1, lorsqu'aucun driver n'est connecté, mais cela ne suffit pas, il semble qu'on assiste à un phénomène capacitif si le dernier caractère transmis avant la libération du bus est nul.

Sur une acquisition ADC, le bus (faiblement polarisé) tombe et un caractere "1C" est vu, lorsque les niveaux précédemments envoyés sont nuls. On peut mettre en évidence le phénomène en forçant des niveaux forts en amont.

réponse reçue :    01 03 00 01 02 00 1C 60 6C E1

réponse attendue : 01 03 00 01 FF FF 00 62 89

La solution propre consiste à conserver la ligne tant que le terminal n'a pas terminé sa transmission complète, cette gestion est à traiter au niveau de la réponse datagramme.


L'émission vue du central

La gestion d'un bus half duplex à partir d'un port COM RS232 standard n'est pas immédiate. Il faut fabriquer un signal qui autorise l'émetteur RS485 (signal DE) lorsque le PC a quelque chose à envoyer.

La liaison RS232 a suffisamment de signaux de contrôles pour imaginer un contrôle direct. On peut faire passer RTS à 1 lorsque le PC veut parler et surtout (ce n'est pas le cas dans le protocole RS232) le remettre à 0 lorsque l'émission est terminée. C'est possible avec un soft dédié, impossible avec Hyperterminal ou Mttty, possible avec d'autres comme Terminal. Noter que les drivers Windows ne prennent pas en charge cette fonction, il faut le faire avec une fonction EscapeCommFunction comme le montre cet extrait de programme C

 

SetCommMask( hFile, EV_TXEMPTY ) ;

       ClearCommError( hFile, &dwErrorFlags, &ComStat ) ;

       EscapeCommFunction( hFile, CLRRTS ) ;

       fWriteStat = WriteFile( hFile, lpByte, dwBytesToWrite, &dwBytesWritten, NULL ) ;

       if (!fWriteStat) {

             dwLastError = GetLastError();

             ClearCommError( hFile, &dwErrorFlags, &ComStat ) ;

             wsprintf( szError, "Write error %d (Comm Err CE-0x%X)", dwLastError, dwErrorFlags ) ;

             Log( szError ) ;

       } else {

}

       EscapeCommFunction( hFile, SETRTS ) ;


Il est plus universel de recréer cette information, en hard, sur la seule indication de la ligne Tx, avec un monostable. Dès que le bit start est envoyé, l'interface force à 1 le signal DE de l'émetteur RS485. Cà c'est facile, mais pendant combien de temps faut-il tenir la ligne ?

En prenant le format le plus dimensionnant, 8-O-2 ou 8-E-2, un mot fait 12 bits au maximum


Débit (bps)

Durée bit (μs)

Durée octet (Start+8 bits+Parity+2 Stop) (μs)

1200

833.3

10000

2400

416.7

5000

4800

208.3

2500

9600

104.2

1250

19200

52.1

625

57600

17.4

208


Il suffit de prendre un monostable réarmable réglé sur la durée maximale (2.5 ms pour 4800 bauds). Le bus est déclaré occupé au tout début du bit start, en fait celui va même être un peu tronqué, mais de quelques dizaines de ns au plus.


 

 

La réception vue d'un terminal

A la fin d'une transmission d'un octet par le central, le bus reste occupé par le central pendant une durée de garde (2.5 ms @9600 bauds). Chaque terminal doit donc attendre ce temps avant de commencer à transmettre. Comme la transmission d'un terminal commence obligatoirement à la fin d'un message émis par le central, il suffit d'attendre un peu soit :

lorsqu'un message a été reçu :

Si le monostable au central est réglée précisément sur la durée bit, la durée à attendre par chaque terminal est égale = ( FFh - TH1 + 1 ) fois 192 cycles (12 bits * 16 cycles ; 1 cycle = Fx/12).


si message valide reçu :

    mov A,TH1  ; va chercher TH1 baud counter

    cpl A      ; complémente

    inc A      ; ici Acc est compris entre 1 (57600)et 48(1200)

loop:         call wait_192_cycles

    djnz Acc,loop



Si le monostable au central est réglée sur une durée fixe (par exemple 10 ms), il faut attendre cette durée évidemment.


si message valide reçu :

    mov A,#48  ; on force Acc au maximum (débit minimum = 1200 bauds)

loop:         call wait_192_cycles

    djnz Acc,loop



Noter qu'entre les deux solutions, on gagne qq msecondes, c'est tout. Il est peut-être plus simple de prendre une durée fixe.

lorsqu'on s'apprête à émettre en réponse :

On ré-arme un monostable re-déclenchable à chaque réception d'un caractère du central.

On règle cette durée à une durée supérieure au monostable de l'émission.

Si ce monostable tombe, le bus est libre, on peut émettre.

 


Vérification de l'écho ?

Dans le cas d’un bus half duplex, on pourrait bien recevoir en même temps qu’on émet. Que faire de cet écho naturel ? Rien dans le cas d’un protocole duplex avec accusé de réception, ce peut être nécessaire dans le cas d’un protocole simplex à répétition pour répéter encore le message, et absolument dans un cas de diagnostique de problème. Comment çà marche ?


Cas MCS51

Dans le cas d’un µcontrôleur compatible MCS51, dans le mode 3 (9 bits série, baud rate variable), le bit RI monte au milieu du bit RB8, donc du premier bit stop reçu, et le bit TI monte à la fin de TB8, donc du premier bit stop envoyé. Donc en half duplex, RI monte un peu avant TI



Comme il est hors de question d'attendre RI par polling, et donc de bloquer le µcontrôleur pendant les émissions, il faut inventer un contrôle de l’écho sous interruption.Le code typique est :

SendK:

           jb RS485send,$ ; attend que la précédente émission soit terminée

           jb RS485timer,$ ; attend que la tempo de non émission soit terminée

           setb RS485send ; prend la main

           setb TB8       ; force 9ème bit à 1

;;         clear REN      ; inhibe la réception

           mov SBUFF,A    ; envoie l'octet

           mov LastK,A    ; sauve l’octet envoyé

           ret

ITSerial:  jbc RI,ITRx1   ; réception d'un caractère --> clr RI

           jnb TI,ITTx1   ; est-ce que c’est une IT de fin d’émission ?

             clr TI       ; fin de transmission --> clr TI

             clr RS485send ; raz drapeau

;;           setb REN     ; autorise à nouveau les réception

ITTx1:     reti

ITRx1:     push Acc

           jnb RS485send,ITRx2 ; est-ce un écho ?

           mov A,SBUF     ; lire l’écho

           xor LastK,A    ; compare avec le caractère envoyé

           jz retour      ; si ok, on se tire

           setb errbus    ; met le flag erreur bus

           sjmp retour

ITRx2:     setb Skready   ; gestion du caractère reçu

           …


Cas d'un PIC


Dans le cas d’un µcontrôleur PIC avec USART intégrée, utilisée avec 9 bits série, baud rate variable. L'interruption RX arrive au milieu du bit stop, et les bits TRMT ou TXIF remontent au début du bit stop. Donc l'interruption réception arrive après la fin de transmission et çà devient délicat si on envoie une rafale d'octets, en interrogeant le signal TXIF ou TRMT. Autrement dit, si on recharge le registre de sortie avec une nouvelle valeur alors que le registre d'entrée n'a pas encore dit qu'il avait reçu un octet.


Si on ne fait pas attention, la routine interruption en réception peut comparer l'octet reçu avec l'avant dernier octet.  Il faudra donc inventer un dispositif à FIFO.

A l'émission on a

Si Fifo_index=0, SendBuff=K

Si Fifo_index=1, SendBuff+1=K

Si Fifo_index=2, SendBuff+2=K

Si Fifo_index=3, SendBuff+3=K

Increment Fifo_index

And Fifo_index,0x03     ; par sécurité

A la réception on a

LastK=SendBuff

SendBuff=SendBuff+1

SendBuff+1=SendBuff+2

SendBuff+2=SendBuff+1

SendBuff+3=0

Decrement Fifo_index

And Fifo_index,0x03     ; par sécurité

Normalement, on n'a besoin que de 3 positions dans la FIFO, l'index ne devrait jamais dépasser 2. Mais comme le code de réception est fait sous IT, il est possible d'envoyer des caractères sans avoir activé l'IT de réception, et ainsi, l'index ne sera jamais décrémenté. On le masque avec 0x0011 pour éviter les problèmes.



Définition des temps

Temps de relaxe RS485 : RS485tempo

C'est le temps que doit attendre un terminal après avoir reçu le dernier caractère d'un datagramme pour être sûr que le bus soit libre.

Si le bus est géré par la ligne RTS, ce temps peut être très faible, de l'ordre de la durée bit (100 µs à 9600 bauds).

Si le bus est géré par une temporisation, elle est au moins égale à la durée d'un octet : 13 temps bits / baudmin, (2.5 ms @4800 bauds). Le temps de relaxe attendu par le terminal doit être supérieur à cela, par exemple 277. ms (=10/3600).


Temps de cycle datagramme : DTGtempo

Il faut que chaque terminal puisse déterminer la position d'un octet dans un datagramme en réception. On utilise une temporisation.

Si un caractère est reçu avec cette temporisation non déclenchée, c'est le premier caractère du datagramme, sinon on est à l'intérieur d'un datagramme.

La temporisation est armée à chaque caractère reçu, hors écho.

Le terminal doit remettre à zéro le datagramme reçu (et donc la temporisation), et être prêt pour en recevoir un autre :

lorsque la temporisation se termine pour couvrir le cas d'un caractère parasite, la durée dans ce cas est donnée par le délai d'expédition du central. Comme on peut considérer que l'envoi sera toujours fait par un programme, et non à la main sur un clavier, cette durée est très faible, de l'ordre du temps de latence Windows, soit 5 à 20 ms.

si une erreur est détectée en cours de réception du header, le terminal ne va rien émettre, le central va partir en time out. La durée est très faible là aussi.

si une erreur est détectée sur le check sum, le terminal va émettre une réponse. Pas besoin de temporisation.

dès que le terminal a terminé la gestion d'un datagramme. Cette dernière durée peut être très longue (l'exécution d'un datagramme (16 ms forfaitaire) +PLUS+ les N tentatives de réponses autorisées (3*135 octets *13/ baudmin) cela représente 1100 ms @4800 bauds), et donc être très pénalisant car le central devra attendre ce temps avant d'envoyer un nouveau datagramme, même si celui ci n'a pas de réponse, ou que la réponse précédente est sans erreur. Donc on considère que le terminal remet à zéro la temporisation dès qu'il entame sa réponse, il devient prêt pour un nouveau datagramme alors qu'il n'a pas terminé l'ancien, mais le central le sait. Le central ne devra émettre un nouveau datagramme que lorsque la gestion de l'ancien est terminée.

Globalement, c'est le premier point qui est le plus dimensionnant, la durée de temporisation doit donc être supérieure à quelques ms (par exemple 17.77 = 64/3600ms).


Qu'a-t-on reçu ??

 

Un parasite

Le parasite est pris comme premier caractère d'un datagramme, la tempo est armée. A son extinction, reset, prêt pour le datagramme suivant

Un datagramme arrive

La tempo est réarmée sur chaque caractère reçu

en erreur

reset, prêt pour le datagramme suivant, pas de tempo

ok

 

incompréhensible

Seule l'application va pouvoir statuer là dessus.

compris

tout va bien

pas de réponse

reset, prêt pour le datagramme suivant, pas de tempo

1 réponse en erreur

 

3 réponses en erreur

reset, prêt pour le datagramme suivant, pas de tempo

réponse OK

reset, prêt pour le datagramme suivant, pas de tempo

Un echo

mise dans la pile de vérification

   

 


Echange typique