- LE BUS I2C

Principe

Le bus est construit sur 2 fils, chaque terminal est connecté sur ces 2 équipotentielles au travers de circuits en collecteur ouvert, avec une résistance de charge. Ce n'est pas un bus différentiel, la charge capacité du bus influe directement sur les performances, ce n'est donc pas un bus destiné à courir sur des longueurs importantes.

 

Les drivers open drain sont donnés pour absorber 3mA max, à 0,4V, la valeur de la résistance de charge ne sera pas inférieure à Rp=5/3=1.66 kO.

 

Le temps de montée maximal dicte la valeur maximale de la résistance Rp. Le temps de montée 0%--70% est égal à 1,20*RC. Les graphiques ci dessous donnent les valeurs de Rp selon la capacité. Donc en final, utiliser des résistances Rp de 2,2 kO semble un bon choix

 

Valeur de Rp, selon la capacité du bus,pour le mode standard(Trise < 1µs)

Valeur de Rp, selon la capacité du bus,pour le mode rapide(Trise < 0.3µs)

 

Des résistances séries (330Ohms typique, <500Ohms) peuvent être montées sur les lignes afin de protéger les circuits des surtensions que les lignes peuvent capter, surtout dans un environnement propice comme une télévision à écran cathodique, ou lorsque que le bus est un peu long.


Protocole

 

Les changements d'état sur le bus de données SDA se font toujours lorsque le signal d'horloge SCL est au niveau bas SAUF pour marquer les conditions de START ou de STOP.
Les communications sont toujours à l'initiative d'un maître. Chaque échange débute par une condition START, et se termine par une condition STOP. Le premier octet transmis par le maître après le "start" est l'adresse du terminal esclave adressé. Si l'esclave se reconnaît, il accuse réception de son adresse, et dès lors, il est seul sur le bus avec le maître.

Il existe 3 types d'échange :

Extensions :

 


Timing

Il existe plusieurs vitesses du bus I2C :

Les circuits standards et fast mode, utilisent la même technologie de bus avec un pull up passif.
Le high speed demande des circuits spéciaux, avec un pull up actif, et ne sera certainement pas simulable avec un µcontrôleur.

 

 


IMPLENTATION LOGICIELLE (MAITRE)

Transmission d'un START, et en même temps, on vérifie que les lignes répondent bien

TxmtStart

SETB _SDA ; set SDA high

SETB _SCL ; clock is high

JNB _SDA,I2CERR1 ; SDA stuck @0 or bus not free

JNB _SCL,I2CERR2 ; SCL stuck @0 or bus not free

CALL Delay40uSec ; Tsu:sta>4,0µs entre SCL=1 et SDA=0

CLR _SDA ; give a falling edge on SDA while clock is high

CALL Delay47uSec ; Thd:sta>4,7µs entre SDA=0 et SCL=0

JB _SDA,I2CERR3 ; SDA stuck @1 or uC problem

CLR _SCL

JB _SCL,I2CERR4 ; SCL stuck @1 or uC problem

RETLW 0 ; retour sans erreur

 

Transmission d'un STOP, on suppose ici que SCL=0 en entrant dans la routine

TxmtStop

; CLR _SCL ; normallement SCL est déjà à 0 !!! sinon on fait un start ici

CLR _SDA ; set SDA low

CALL Delay47uSec ; tLOW>4,7µS

SETB _SCL ; Clock is pulled up

CALL Delay40uSec ; Tsu:sto>4,0µs entre SCL=1 et SDA=1

SETB _SDA ; give a rising edge on SDA while CLOCK is high

CALL Delay47uSec ; c'est pas dans la spec, par sécurité

RETLW 0 ; retour sans erreur

 

Ecriture d'un bit sur le bus

TxmtBit

MOV _SDA,C ; SDA=Carry

CALL Delay47uSec ; tLOW>4,7µS, Tsu:dat>0,25µS

SETB _SCL

; test sda=Carry, sinon ---> I2CERR6

JNB _SCL,I2CERR5 ; SCL stuck @0 or bus not free

CALL Delay40uSec ; tHIGH>4,0µS

CLR _SCL

RETLW 0 ; retour sans erreur

 

Lecture d'un bit sur le bus ; on fait un vote majoritaire pour éviter les parasites ; SDA est supposé à UN

RcvBit

CALL Delay47uSec ; tLOW>4,7µS

SETB _SCL ; SCL=1, data sent by slave

CALL Delay40uSec ; tHIGH>4,0µS

JNB _SCL,I2CERR7 ; SCL stuck @0 or bus not free

CLRF rcvSDA1 ; 3 échantillonages de _SDA, et on compte le nombre de UN

BTFSC _SDA

INCF rcvSDA1,F

BTFSC _SDA

INCF rcvSDA1,F

BTFSC _SDA

INCF rcvSDA1,F

CLR _SCL ; SCL=0

MOVLW 2

SUBWF rcvSDA1,W ; W=rcvSDA1-2, Cy=1 si rcvSDA1=2 ou 3, c'est le bit reçu

RETLW 0

 

Attention à la profondeur de la pile nécessaire à chaîner toutes les routines I2C. On arrive très rapidement à des niveaux de plus de 4 qui doivent être maîtrisés dans un environnement avec des interruptions.
Ici, nous avons une profondeur de 4, le dernier niveau étant traité par macro. Cela ne laisse que 4 niveaux pour l'appelant et les interruptions. Cette solution augmente la taille du code.

Séquence START-Add-NACK sur l'adresse D0h. Chaque bit dure 25µs.

Séquence START-Add-ACK sur l'adresse A0h

 

 

Interface logicielle

 

Tout échange I2C peut être résumé par une écriture suivie d'une lecture, avec un start répété.

START Send address+W Rec ack Send bytes (W) Rec ack  
START Send address+R Rec ack Receive bytes (R) Send ack/Nack STOP

Il suffit donc de créer une routine générale avec 5 parametres en entrée :

L'appel est des plus simple :

 

set R0,R1,R2,R3,R4

call I2CXCH

jnb I2COK,error

 

Cette routine s'appuie sur quelques routines de base : TxmitBit, TxmtStart, RcvBit...

Les délais sont traités par macro, au moment de l'assemblage, en donnant en parametre la fréquence quartz.

 

Gestion des erreurs

Les erreurs possibles pendant l'echange sont résumées dans ce tableau

START Send address+W Rec ack Send bytes (W) Rec ack  
01, 02, 03, 04 05, 06 07, 20 0D, 0E 0F, 40  
START Send address+R Rec ack Receive bytes (R) Send ack/Nack STOP
11, 12, 13, 14 15, 16 17, 60 1F pas d'erreur pas d'erreur

 

A la sortie de cette routine, on dispose d'un octet status qui donne l'erreur.

 

bits 7&6

bits 6&5

bits 4&3

bits 2&1&0

80h RESET-SDA line note released after 9 clocks

88h STOP-SDA line not released after recover

20h WRITE-no ack while addressing
40h WRITE-no ack while writing
60h READ-no ack while addressing

+00h WRITE-bus error while addressing
+08h WRITE-bus error while writing
+10h READ-bus error while addressing
+18h READ-bus error while writing

x1h START-SDA stuck @0 or bus not free

x2h* START-SCL stuck @0 or bus not free

x3h START-SDA stuck @1 or uC problem

x4h* START-SCL stuck @1 or uC problem

x5h* WRITE BIT/ACK-SCL not released after 3uS

x6h WRITE BIT/ACK-SDA line not correct

x7h* READ BIT/ACK-SCL not released after 3uS

(*) seulement si le test SCL est autorisé

 


IMPLENTATION LOGICIELLE (ESCLAVE)

Considérons que SCL est reçue par un entrée ordinaire, sans possibilité de sortie, et SDA est reçu sur une entrée avec un open drain associé (RA4 sur un PIC).
Pour gérer le protocole, il faut pouvoir renvoyer Ack sur un adresse reçue correcte, et appliquer le niveau ZERO sur SDA, en moins de Thigh+Tvd;dat soit 7,5µs après le front montant de SCL. En faisant cela en 15 à 20 instructions, il faut une horloge à plus de 10MHz.

Au démarrage SCL est en entrée, et SDA en sortie avec SDA=1.
Pour un esclave, on peut considérer qu'on a plusieurs états stables

Mode=1
Attente START

si START reçu,
· init USART, enable RX
· mode=2


Loop1 BTFSC _SDA ; Attente SDA & SCL = 1
Loop2 BTFSS _SCL
      GOTO Loop1
      BTFSC _SCL ; Attente Start SDA=0, SCL=1
      BTFSC _SDA
      GOTO Loop2
      ...

Mode=2
Attente réception adresse+RW

si RXIF,
· get RCREG --> I2Cadd
· si I2Cadd=LocalAdd
       SDA=0 (ack)
       si RW=0, mode=3
       si RW=1, mode=4
· sinon, mode=1

faudrait pouvoir détecter les stop ici
Mode=3
en write

·
 
Mode=3
en read

·
 

 

 

à continuer...

 

 


Liens & références