le bus I2C (Inter-Integrated Circuit) est un mécanisme de communication série au niveau de la puce qui fonctionne sur seulement deux fils. Certains développeurs prononcent le nom du bus eye-two-see, d’autres eye-squared-see, mais les deux se réfèrent à la même chose. Conçu par Philips au début des années 1980, I2C a été créé pour standardiser les communications entre les puces de la société, mais il est depuis devenu une norme de facto prise en charge par de nombreux microcontrôleurs, des cartes Arduino au Raspberry Pi et, bien sûr, aux IMP.,
le Bus physique
I2C comprend lui-même deux fils. Une ligne I2C transmet des données, l’autre les signaux d’horloge qui synchronisent la conversation entre les appareils. La ligne de données est appelée ‘SDA’ , la ligne d’horloge ‘SCL’.
En règle générale, SDA et SCL sont tous deux connectés à une ligne électrique de 3,3 ou 5 V via une seule résistance « pull-up », une sur chaque ligne. Cela est nécessaire car les connexions SDA et SCL des appareils sont des lignes de « drain ouvert »: elles peuvent forcer la tension sur la ligne à 0V, ou « faible », mais ne peuvent pas l’élever à 3.3 V, ou « élevé »., Haut et bas sont les représentations électriques des 1 et 0 qui sont les composantes fondamentales de l’information numérique. L’ajout de ces deux résistances — et le bus n’en a besoin que de deux, quel que soit le nombre de périphériques connectés — garantit que la tension remonte à 3,3 V Sans court-circuit.
I2C insiste sur le fait que les appareils ont des conduites de vidange ouvertes pour s’assurer qu’aucun courant élevé nuisant aux composants ne peut circuler lorsque deux appareils essaient de signaler simultanément.
dans la plupart des cas, vous devrez ajouter ces résistances vous-même, mais certains appareils, généralement ceux qui fonctionnent à 3.,3V, incluez – les afin d’être compatible avec les appareils fournissant 5V. rappelez-vous, vous n’avez besoin que d’une paire de résistances pull-up par bus, il peut donc être nécessaire de retirer les résistances pull-up attachées à d’autres appareils sur le bus. Bien que l’imp ait ses propres résistances pull-up internes, celles-ci sont trop faibles pour être utiles pour I2C et sont donc automatiquement désactivées lorsque ses broches sont configurées pour gérer les signaux I2C.
les Contrôleurs Et Périphériques
Le bus I2C sépare de dispositifs dans « contrôleurs » et » périphériques’., Un seul périphérique peut envoyer des impulsions de synchronisation sur la ligne SCL à la fois, et c’est celui choisi pour être le contrôleur. Tous les autres synchronisent leurs timings avec le contrôleur, et sont donc considérés comme des périphériques. Le contrôleur — généralement l’imp-et ses périphériques peuvent tous transmettre et recevoir des données, mais seul le contrôleur peut indiquer à un périphérique quand transmettre des données.
adressage
Pour qu’un périphérique I2C communique avec un autre sur une base individuelle, les deux périphériques doivent être identifiables de manière unique. Cette identité est l’adresse I2C de l’appareil., Les adresses I2C sont généralement des numéros 7 bits, de sorte qu’un bus peut comprendre jusqu’à 127 périphériques en tout. Un octet comprend huit bits; le bit supplémentaire est utilisé pour indiquer si le signal est envoyé par le contrôleur au périphérique — une « écriture » — ou dans l’autre sens — une « lecture ». Ce huitième bit est en fait un bit zéro dans l’octet d’adresse envoyé sur le bus. L’adresse 7 bits est placée en bits un à sept de l’octet d’adresse.
conformément à ce format, l’API imp prend une adresse I2C comme valeur 8 bits., Les fournisseurs d’appareils donnent généralement les adresses de leurs produits sous forme de numéro 7 bits, il est donc nécessaire de convertir l’adresse de sept bits à huit. Ceci est réalisé avec L’opérateur <<
de Squirrel, qui déplace les valeurs de bits individuelles d’un nombre vers la gauche. Ce processus équivaut à multiplier par deux. Dans le code, ce processus ressemble à ceci:
local sevenBitAddress = 0x39;local eightBitAddress = sevenBitAddress << 1;
Squirrel définit automatiquement le bit zéro à la valeur correcte définie par I2C: 0 pour une opération d’écriture, 1 pour une lecture., Maintenant, vous êtes prêt à utiliser l’une des méthodes I2C de l’imp pour écrire des données sur le bus:
i2c.write(eightBitAddress, dataInStringForm);
l’adresse 7 bits du périphérique avec lequel vous souhaitez que votre imp communique sera fournie par le fabricant du composant et répertoriée sur la fiche technique de l’appareil. Il ne peut pas être fixé, mais sélectionné dans une plage d’adresses en fonction de la tension appliquée à une autre des broches des appareils., Par exemple, un capteur de lumière TAOS TSL2561 a trois adresses possibles: 0x29
, 0x49
ou 0x39
, selon que sa broche ADDR est fixée à 0V, 3.3 V ou « flottante » entre les deux. Nous disons que la valeur est flottante car elle n’a pas été activement sélectionnée pour fonctionner à une tension spécifique; elle pourrait aller de 0 à 3,3 V inclus.
signalisation
Le contrôleur de bus I2C utilise l’adresse 7 bits d’un périphérique pour identifier le composant avec lequel il veut parler., En fait, la signalisation est plus complexe que cela, mais heureusement tous les détails sont gérés par l’imp de sorte que vous n’avez besoin que de fournir l’adresse sous forme de valeur 8 bits.
Si vous écrivez sur le périphérique, vous devez également fournir les données à écrire, ce qui inclut souvent des valeurs de Registre qui indiquent au périphérique quoi faire avec les données. La documentation de l’API imp fait référence à ces registres en tant que »sous-adresses »:
i2c.write(eightBitAddress, dataString);
write() nécessite des données sous forme de chaîne. Par conséquent, vous devrez peut-être convertir la valeur stockée dans d’autres types de variable sous forme de chaîne.,
la lecture d’informations à partir d’un périphérique peut nécessiter une commande pour indiquer au périphérique les données à récupérer. Dire à l’imp de lire les données du bus I2C implique également de fournir un troisième paramètre, le nombre d’octets que vous attendez de recevoir:
i2c.read(eightBitAddress, controlDataString, numberOfBytesToRead);
derrière ces opérations se trouvent les signaux électriques de L’I2C, appliqués à la ligne SDA synchronisés avec les impulsions de synchronisation appliquées à la ligne SCL. L’écriture sur le bus implique un marqueur de démarrage: laisser tomber SDA à 0V alors que SCL est de 3,3 V. changer la tension SDA lorsque la tension du SCL est élevée définit les marqueurs de démarrage et d’arrêt., Si la tension SDA ne change pas alors que SCL est élevée, les périphériques I2C savent que des données, plutôt que des marqueurs, sont envoyées.
SDA va maintenant haut ou bas pour envoyer chaque bit de l’octet d’adresse: l’adresse du périphérique 7 bits suivie du bit de lecture / écriture. Les bits de l’octet sont envoyés en premier sur le bit le plus à gauche — le « bit le plus significatif » -, le SDA devenant élevé si la valeur du bit est 1 ou faible s’il est nul. Le périphérique cible va maintenant tirer SDA bas pour signaler l’accusé de réception des données, puis sort huit bits d’informations ou de données de contrôle, suivis de plus de données si nécessaire., Il y a une pause d’accusé de réception d’ACK de simple-impulsion sur SDA entre tous les huit bits envoyés, chronométrés à une neuvième impulsion de SCL. Si le périphérique n’accuse pas réception de cette façon, le contrôleur détectera que SDA est resté élevé et signalera une erreur.,
lorsque les données circulent du périphérique vers le contrôleur, ce dernier accuse également réception de huit bits en tirant SDA low sur la neuvième impulsion SCL, sauf s’il s’agit du dernier octet d’un lot, auquel cas le contrôleur ne tire pas SDA low — il émet un signal « nak », ou « no acknowledgement » — afin de faire savoir au périphérique qu’il a terminé.
lorsque nous avons terminé, SDA va haut comme un marqueur d’arrêt.,
le début de la transmission est indiqué par SDA passant de haute à basse tension (le rectangle de gauche),
s’arrête par l’inverse (le rectangle de droite). SCL doit être élevé lorsque cela a lieu
Timing
la vitesse d’horloge standard pour les communications I2C est de 100 kHz — 100 000 impulsions SCL par seconde. Il est possible d’aller plus vite, jusqu’à 400kHz. Certains appareils peuvent ne pas être en mesure de prendre en charge cette vitesse; vérifiez la fiche technique qui accompagne l’appareil que vous souhaitez connecter à votre imp., Cependant, de nombreux appareils lents utilisent une technique appelée « étirement d’horloge » pour forcer les appareils plus rapides à travailler à leur vitesse. L’imp prend en charge les appareils qui utilisent cette technique. Essentiellement, ils maintiennent SCL bas pendant qu’ils récupèrent les données que vous voulez qu’ils envoient à l’imp. L’imp détecte cela, libère la ligne SCL et attend que SCL redevienne élevé avant de continuer.
cependant, vous devrez peut-être abaisser vous-même la vitesse I2C si les caractéristiques électriques de votre installation ralentissent la vitesse de la transition entre 0V et 3.3 V, appelée « temps de montée »., Cela est souvent causé par de longs fils, qui augmentent la capacité du circuit. Pour que les périphériques détectent avec succès la transmission de chaque bit, le bus doit fonctionner plus lentement. La corruption des données ou des résultats inattendus sont les indices que vous devez rechercher. Réduisez la vitesse du bus I2C jusqu’à ce que les données soient lues avec succès.
l’API imp fournit actuellement quatre valeurs d’horloge prédéfinies: 10, 50 100 et 400KHZ., Ils sont sélectionnés en passant une constante à la méthode de configuration I2C en tant que paramètre:
i2c.configure(speedConstant);
où la valeur de speedConstant est l’une des
- CLOCK_SPEED_10_KHZ
- CLOCK_SPEED_50_KHz
- CLOCK_SPEED_100_KHZ
- clock_speed_400_khz
configuration d’un IMP pour I2C
l’objet I2C dans l’exemple de lignes de code donné ci-dessus n’est pas fourni directement par l’IMP, mais choisi par vous en fonction de laquelle des broches de votre IMP choisi vous utiliserez pour les communications I2C., Chaque type d’imp dispose de plusieurs bus I2C, tous mis à disposition au démarrage. Consultez le pin MUX pour le type d’imp que vous utilisez pour voir quels objets I2C sont disponibles pour vous. Ici, nous supposerons que vous utilisez un imp001. Les deux bus I2C de l’imp001 sont sur les broches 1 et 2, et les broches 8 et 9, respectivement instanciées en tant que propriétés i2c12 et i2c89 de l’objet matériel au démarrage de l’imp. Les broches 1 et 8 sont affectées à SCL, 2 et 9 à SDA.,
Il est courant de référencer votre choix avec une variable globale:
i2c <- hardware.i2c12;i2c.configure(CLOCK_SPEED_100_KHZ);
exemple de Code
le code suivant fonctionne avec le capteur de lumière visible et infrarouge TAOS TSL2561, un appareil 3.3 V qui utilise I2C pour communiquer avec son microcontrôleur hôte. La fiche technique de la puce peut être téléchargée sur le site Web D’Adafruit. Adafruit vend la puce sur une carte de dérivation à faible coût qui comprend des résistances pull-up appropriées sur la broche d’alimentation, VCC. Cela signifie qu’il est prêt à se connecter directement aux broches I2C d’un imp.,
carte de dérivation TSL2561 D’Adafruit
Remarque Après la rédaction de cet article, Adafruit a mis à jour sa carte de capteur TSL2561. La nouvelle version fonctionne avec le code actuel.
Voici le code, pour l’agent puis le périphérique:
Ce Que fait le Code
le code de l’agent répond à une requête HTTP entrante en notifiant au périphérique qu’il nécessite une lecture. Pour plus de simplicité, la lecture est simplement affichée dans le journal.
le code de l’appareil lit le capteur et calcule une valeur lux selon les calculs définis dans la fiche technique TSL2561., La première partie du programme met en place des constantes pour les registres de clés et les paramètres du TSL2561, y compris ses options d’adresse I2C. D’autres constantes sont utilisées dans le processus de conversion de luminosité.
câblage de l’imp
Au Point de début du programme, le code alias l’une des broches I2C de l’imp définie comme variable globale, configure la vitesse du bus à 100 kHz, puis décale L’adresse I2C du TSL2561 d’un bit vers la gauche afin qu’elle soit prête à être utilisée avec les fonctions I2C de l’imp. Il met ensuite en place le capteur., Juste pour vérifier que cela a fonctionné, nous lisons le registre de contrôle: la valeur de retour devrait être 3 si le TSL2561 vient de démarrer, ou 51 si l’appareil a déjà été allumé.
ensuite, le code définit la résolution ADC du capteur via le registre de synchronisation du TSL2561, puis définit le gain du signal sur high.
enfin, nous indiquons à l’imp comment répondre aux notifications"sense"
de l’agent. Cela appelle une fonction qui lit les deux capteurs de lumière du TSL2561, dont les valeurs numériques sont stockées dans les quatre registres ADC 8 bits de la puce., Les deux premiers donnent une lecture optique et infrarouge combinée de 16 bits, la deuxième paire une valeur IR uniquement de 16 bits. Les fonctions readSensorAdc0 () et readSensorAdc1 () convertissent les valeurs de registre individuelles en nombres de 16 bits en multipliant l’octet le plus significatif par 256 et en ajoutant la valeur de l’octet le moins significatif. La multiplication est effectuée en décalant les bits du nombre de huit bits à huit endroits avec L’opérateur << D’Écureuil.,
le code fournit ensuite ces deux lectures à une troisième fonction pour calculer une luminosité finale, valeur ‘lux’.
autres lectures
- erreurs I2C – comment déboguer les problèmes de lecture et d’écriture I2C