[Retour à la page principale] |
---|
Signalons, en guise de préambule, que nous n'examinerons
pas ici toutes les subtilités du standard I2C, mais que
nous nous bornerons à évoquer les échanges
d'informations avec les mémoires EEPROMs 24C01 à 24C16.
Précisons tout de même que si vous avez bien assimilé
les infos présentées dans cette page, l'utilisation
d'autres périphériques I2C courants (avec un minimum de
documentation) ne devrait pas poser de problème insoluble.
Comme le montre la figure 1, outre la masse (qui sert
de référence de tension) le bus I2C n'est
constitué que de deux lignes de transmission :
- La ligne SDA (= Serial DAta), qui véhicule
toutes les informations (données, adresses, commandes).
- La ligne SCL (= Serial CLock), qui sert à transmettre
les impulsions d'horloge qui vont rythmer les échanges.
Ces deux lignes sont donc communes à tous les
périphériques qui partagent un même
bus I2C.
Etudions de plus prêt l'une de ces lignes (SDA
ou SCL, peu importe) ; comme l'indique la figure 2,
chaque entrée/sortie a une structure 'drain ouvert'
(c'est l'équivalent MOS d'un 'collecteur ouvert'),
celle-ci permet de relier ensemble plusieurs sorties
sans risquer de situation de conflit ; il faut alors
une résistance de tirage Rt pour fixer le potentiel
lorsque tous les transistors sont bloqués ; on peut
noter que l'ensemble réalise une fonction logique
'ET' câblée (il faut que toutes les sorties
reliées à la ligne soient à '1' pour
que la ligne soit à '1') ; on en déduit donc
que l'état de repos de la ligne est l'état
logique '1', chaque périphérique pouvant
'prendre la ligne' en la mettant à '0'.
Lors d'un dialogue entre deux périphériques I2C,
les rôles sont bien répartis :
- Le premier est le maître ; il initie le dialogue,
envoie les commandes, et génère le signal d'horloge
sur SCL.
- Le second est l'esclave : en fonction des
ordres et du signal d'horloge, il envoie ou reçoit
des données (octets).
Lorsque le bus est inactif, les lignes sont au niveau logique '1'.
Lorsque le bus est actif, l'état de repos de la ligne SCL
est l'état '0' ; chaque bit lu ou envoyé (sur SDA) est
validé par une impulsion positive sur SCL (soit un front
montant, suivi d'un front descendant, générés
par le 'maître'), comme l'illustre la figure 3 :
En principe, l'état de la ligne SDA ne doit pas changer
pendant que SCL est à '1'. Il y a néanmoins deux
exceptions, indiquées ci-dessus figure 4 ; les instructions
'START' et 'STOP' qui servent respectivement à initier et à
clore le dialogue, se différencient justement par le
fait qu'elles se produisent quand SCL est à '1' :
- par un front descendant sur SDA, suivi d'un front
descendant sur SCL, pour 'START'.
- par un front montant sur SCL, puis sur SDA, pour 'STOP'.
Les signaux 'START' et 'STOP' sont bien sûr
délivrés par le maître. En principe,
rien n'interdit qu'un périphérique soit
tantôt maître, tantôt esclave, par exemple
dans le cas où deux micro-contrôleurs partagent
un même bus I2C. Dans l'application présentée
plus loin, celle d'un micro-contrôleur pilotant
uniquement une EEPROM I2C, le micro sera toujours le
maître, et la mémoire l'esclave.
Dure loi que celle de la servitude ! mais ne confondons pas
mémoire et conscience...
Attention, pour que le 'maître' puisse recevoir des bits,
il faut que sa sortie ait été remise à '1'
au préalable, afin que la mémoire puisse mettre la
ligne SDA à '0' ou à '1' (structure à 'drain
ouvert' exposée précédemment).
Le protocole d'écriture d'un octet est exposé ci-dessous figure 5 ; analysons ensemble en détail les différentes étapes de l'opération :
Le principe décrit est valable pour une programmation
octet par octet ; pour gagner du temps, les mémoires
autorisent une écriture en mode 'Page', c'est-à-dire
de N octets à la fois ; le nombre N d'octets est donné
dans la documentation de la mémoire et doit être
respecté, mais surtout pas dépassé ;
il vaut par exemple 16 pour les 24C04, 24C08 et 24C16.
Chaque octet est suivi d'un ACK, jusqu'au STOP final, comme
le montre la figure 5 bis avec N = 4 (la réception d'un
octet incrémente automatiquement le compteur d'adresse de
la mémoire).
Attention, la durée nécessaire à la programmation
de la mémoire est contrôlée automatiquement par
celle-ci, mais cela veut dire que la mémoire sera indisponible
pendant quelques instants (de l'ordre de quelques millisecondes).
Il est sage de faire suivre la routine de programmation par une
boucle d'attente (Tempo) ou mieux, de surveiller la mémoire
jusqu'à ce qu'elle soit à nouveau disponible.
Pour cela, envoyez un START, puis le premier octet d'adressage,
puis tester l'ACK, puis un STOP. Si la mémoire a
répondu à l'ACK (en mettant SDA à '0'),
c'est qu'elle est enfin disponible, sinon, répétez
la séquence tant que ce sera nécessaire...
Comme le montre la figure 6 ci-dessus, la lecture d'un (ou
plusieurs) octet(s) s'effectue en deux étapes :
Voilà, l'opération est terminée ; contrairement à ce qui se passait lors de l'écriture de plusieurs octets, on peut lire autant d'octets qu'on le souhaite ; si l'on arrive à la fin de la mémoire, le compteur repasse à zéro et la lecture reprend simplement à partir du début.
Il y a bien évidemment des durées minimales à
respecter (temps d'accès) ; sans entrer dans trop de détails,
disons que les différents créneaux doivent avoir une
durée d'au moins 5 µs. Consultez la documentation des
constructeurs pour de plus amples infos.
Les indications données ci-dessus concernent l'accès
(écriture/lecture) aux mémoires I2C allant de la 24C01
à la 24C16 ; les mémoires 24C32 et au-delà
nécessitent plus que les 11 bits d'adresse disponibles ;
le protocole est presque le même, il utilise non pas deux, mais
trois octets d'adressage :
L'adaptation de l'algorithme n'est pas très compliquée ; n'hésitez surtout pas à consulter la documentation sous forme de fichiers PDF disponibles (en anglais) sur les sites indiqués sur la page principale.
à gauche : schéma électrique
à droite : implantation des composants
Le schéma présenté ci-dessus est assez élémentaire : une pile 9V associée à un régulateur 5V fournissent la tension d'alimentation, une diode protège l'ensemble contre toute erreur de polarité ; les parties 'oscillateur' (quartz 4 MHz + condensateurs céramique 22 pF) et 'Reset' (résistance, condensateur, bouton poussoir) n'appellent pas de commentaire particulier ; le bus I2C est câblé sur deux entrées/sorties du Port A ('drains ouverts'), avec ses deux résistances de tirage ; une led de contrôle est également montée sur une sortie du port A (et reliée au +5V, en raison de la structure 'drain ouvert') ; les entrées A0, A1 et A2 de l'EEPROM sont au niveau logique '0' (les adresses physiques partent donc de $000), ainsi que l'entrée WP (pour autoriser l'écriture dans la mémoire).
Le schéma d'implantation est donné à titre indicatif,
et l'ensemble pourra être réalisé sur une plaque
pastillée pré-perforée ; on utilisera des supports
'tulipe' pour les circuits intégrés.
Voici le fichier EEPROM05.ASM qui contient les routines d'accès (lecture et écriture) à la 24C16. Mais téléchargez plutôt le fichier EEPROM05.ZIP qui regroupe le fichier source ASM, ainsi que les fichiers LST et HEX fournis par l'assembleur.
Les commandes principales sont :
Ces deux fonctions ne font qu'appliquer les chronogrammes décrits figures 5 et 6 ; chaque étape revient à exécuter l'une des huit routines de base également présentes dans le fichier :
Ces routines sont accompagnées de commentaires détaillés ; prenez le temps d'étudier leur fonctionnement, avec le schéma et les chronogrammes sous les yeux...
Le programme principal n'est pas d'un grand intérêt du
point de vue technologique, il n'a pour but que d'illustrer l'utilisation
des fonctions Read24C16 et Write24C16 ; libre à vous
de le modifier pour lui faire exécuter des tâches plus utiles
; pour l'instant, il se contente d'initialiser tous les octets de la
mémoire en mode incrémental ($00, $01, $02, $03, ... $FE,
$FF et puis on recommence jusqu'à la fin de la mémoire) ;
seul le premier octet est épargné : sa valeur est
affichée sur le Port B (contrôlez les sorties au
voltmètre) ; à la fin du programme, qui dure environ
6 secondes avec une 24C16, la Led s'allume pour indiquer que
tout est terminé...
Pour vérifier cela, programmez une 24C16 (ou inférieure)
après avoir rempli le buffer de manière aléatoire,
et en ayant relevé la valeur du premier octet ; programmez ensuite
le PIC16F84, par exemple avec le programmateur décrit par
Patrice F5JTZ sur son site, puis
insérez les deux circuits dans leurs supports, appliquez le
courant et attendez quelques secondes l'allumage de la Led ; relevez
l'état des bits du Port B et comparez-le avec l'octet
n°1 ; relisez ensuite le contenu de l'EEPROM avec le
module décrit sur la page principale, en vérifiant que
ce contenu a été modifié comme convenu...
Attention, le courant doit être appliqué 'proprement' ;
si vous ne passez pas par un interrupteur, appuyez sur le bouton de remise
à zéro au moment où vous branchez la pile, puis
relâchez-le pour lancer le programme.
Voici une petite variante :
Elle intéressera les utilisateurs d'EEPROMs de capacités supérieures à la 24C16 ; ce type de mémoires nécessite un octet supplémentaire d'adressage, ce qui impose une petite modification des routines ; le fichier EEPext01.ZIP, 16862 octets, contient un programme qui réalise la même fonction que précédemment, mais avec une 24C64 (8192 octets) ; petite variante : la led clignote (16 fois) pour faire patienter l'utilisateur. Selon vos applications personnelles, il peut être intéressant d'utiliser le mode d'écriture 'par pages' pour gagner en vitesse, car le programme est actuellement assez lent. Les routines principales s'appellent maintenant 'Read24Cxxx' et 'Write24Cxxx', vous pouvez les utiliser directement, ou vous en inspirer pour implémenter le mode 'par pages'.
[Retour à la page principale] |
---|