top of page

LA LIAISON I2C

Le bus I2C (Inter Integrated Circuit Bus) a été développé par Philips dans les années 80, pour permettre de relier facilement à un microprocesseur divers circuits intégrés (spécialisés dans le stockage et l'affichage de données, dans l'exécution de fonction numériques ou analogiques diverses), en particulier dans un téléviseur.

Il existe d'innombrables périphériques exploitant ce bus, dans les appareils TV et vidéo (récepteur télécommande, réglages ampli BF, tuner, horloge …), mais aussi dans les systèmes audio et radio, postes téléphoniques, systèmes électroniques automobiles, PC, appareils électroménagers, etc.

De nombreux fabricants ayant adopté le système, la variété des circuits disponibles disposant d'un port I2C est énorme :

  • ports d'E/S bidirectionnels

  • convertisseurs A/N et N/A

  • mémoires (RAM, EPROM, EEPROM, etc)

  • circuits Audio (Egaliseur, Contrôle de volume, etc)

  • autres drivers (LED, Afficheurs LCD, etc)

Le bus I2C permet de faire communiquer, par une liaison série synchrone, entre eux des composants électroniques très divers grâce à seulement trois fils :        

  • un signal de donnée (SDA).

  • un signal d'horloge (SCL).

  • la masse (0V).

Une des particularités de la liaison I2C est que l'on peut faire communiquer le maître (en général le microprocesseur) avec plusieurs esclaves (les autres circuits) en les reliant tous au même bus. Il faut uniquement mettre deux résistances de tirage de 4.7 KΩ sur les lignes SDA et SCL.

La communication sur le bus est orchestrée de la manière suivante :

  • Le maître envoie sur le bus l'adresse du composant avec qui il souhaite communiquer ; chacun des esclaves ayant une adresse fixe codée sur 7 bits.

  • L'esclave qui reconnaît son adresse répond à son tour par un signal de confirmation, puis le maître continue la procédure de communication...(écriture/lecture).

Dans tous les cas, les transactions seront confirmées par un acquittement (ACK : acknowledge). ACK est actif à 0.

Prise de contrôle du bus :

  • Le bus doit être au repos avant la prise de contrôle : SDA=1 et SCL=1.

  • Pour transmettre des données, il faut surveiller :

    • La condition de départ : SDA passe à 0 et SCL reste à 1.

    • La condition d’arrêt : SDA passe à 1 et SCL reste à 1.

  • Après avoir vérifié que le bus est libre, puis pris le contrôle de celui-ci, le circuit en devient le maître ; c’est lui qui génère le signal d’horloge.

Transmission d'un octet :

  • Le maître transmet le bit de poids fort D7 sur SDA.

  • Il valide la donnée en appliquant un niveau 1 sur SCL.

  • Lorsque SCL retombe à 0, il poursuit avec D6, et ainsi de suite jusqu’à ce que l’octet soit transmis.

  • Il envoie le bit ACK à 1 en scrutant l’état de SDA.

  • L’esclave doit imposer un 0 pour indiquer que la transmission s’est effectuée correctement.

  • Le maître voit le 0 et peut passer à la suite.

Fonctionnement de l’acquittement :

  • Le maître libère la ligne SDA.

  • L’esclave force la ligne SDA à 0.

  • Le maître envoie une impulsion sur l’horloge SCL.

  • Lorsque l’impulsion retombe à 0, l’esclave libère SDA.

Transmission d'une adresse :

Chaque composant possède une adresse codée sur 7 bits et le maître indique s’il souhaite lire ou écrire dans ce composant grâce au bit R/W (0 en écriture et 1 en lecture).

Ecriture d'une donnée :

  • Le maître transmet l’adresse du composant avec R/W à 0.

  • Il envoie le bit ACK à 1 en scrutant l’état de SDA.

  • L’esclave doit imposer un 0 pour indiquer que la transmission s’est effectuée correctement.

  • Le maître transmet la donnée en commençant par D7.

  • Il envoie le bit ACK à 1 en scrutant l’état de SDA.

  • L’esclave doit imposer un 0 pour indiquer que la transmission s’est effectuée correctement.

  • Le maître voit le 0 et peut passer à la suite.

Lecture d'une donnée :

  • Le maître transmet l’adresse du composant avec R/W à 1.

  • Il envoie le bit ACK à 1 en scrutant l’état de SDA.

  • L’esclave doit imposer un 0 pour indiquer que la transmission s’est effectuée correctement.

  • L’esclave transmet la donnée en commençant par D7.

  • Il envoie le bit ACK à 1 en scrutant l’état de SDA.

  • Le maître doit imposer un 0 pour indiquer que la transmission s’est effectuée correctement.

La mise en oeuvre d'un composant I2C nécessite une analyse poussée de sa documentation. Heureusement, de nombreux composants ou modules possèdent leur bibliothèque.

L'Arduino Uno possède une liaison I2C (SDA : broche analogique A4 et SCL : broche analogique A5) et une bibliothèque Wire() permet de gérer les échanges d'informations entre la carte Arduino et les circuits I2C connectés. Cette bibliothèque est installée de base dans l'IDE Arduino. Les principales fonctions de cette bibliothèque sont :

  • Wire.begin() : initialise la communication sur le bus.

  • Wire.beginTransmission(adresse) : le maître débute un échange d'informations avec l'esclave dont l'adresse est spécifiée.

  • Wire.endTransmission() : arrête l'échange d'informations entre le maître et l'esclave.

  • Wire.write(octet) : envoi d'un octet sur le bus.

  • Wire.requestFrom(adresse, nb_octets) : le maître  demande à l'esclave dont l'adresse est spécifiée de lui transmettre un nombre d'octets.

  • Wire.read() :le maître lit des données en provenance d'un esclave.

  • Wire.available() : renvoie le nombre d'octets présents sur le bus I2C.

Exemple :

Nous souhaitons afficher dans le moniteur série, l'angle et le module du champ magnétique terrestre. Nous utiliserons un module HMC5883L qui mesure les trois composantes X, Y et Z du champ magnétique et les transmet par une liaison I2C.

/* Boussole est un programme qui permet d'afficher le module et l'angle du champ magnétique terrestre dans le moniteur série */

#include <Wire.h>                                             // appel de la bibliothèque
#define HMC5803L_Addresse 0x1E                // adresse I2C du module

double composante_X;
double composante_Y;
double composante_Z;
double module;
double angle;

void setup()
{
  Serial.begin(9600);
  Wire.begin();                                                  // initialisation du bus I2C
  Init_HMC5803L();                                          // initialisation du module boussole
}

void loop()
{
  Wire.beginTransmission(HMC5803L_Addresse);         // lancement de la mesure
  Wire.write(0x02);
  Wire.write(0x01);
  Wire.endTransmission();
  delay(10);
  Wire.requestFrom(HMC5803L_Addresse, 6);                // récupération des composantes
  if(Wire.available() <=6)
  {    
    composante_X = Wire.read() << 8 | Wire.read();
    composante_Y = Wire.read() << 8 | Wire.read();
    composante_Z = Wire.read() << 8 | Wire.read();
  }
  Serial.print("X=");
  Serial.print (composante_X);
  Serial.print('\t');
  Serial.print("Y=");
  Serial.print (composante_Y);
  Serial.print('\t');
  Serial.print("Z=");
  Serial.print (composante_Z);
  Serial.print('\t');

  // Calcul du module
  module = sqrt(composante_X * composante_X + composante_Y * composante_Y + composante_Z * composante_Z);
  Serial.print("M=");
  Serial.print(module);
  Serial.print('\t');
 
  //Calcul de l'angle
  angle= atan2(composante_Y,composante_X) * (180 / 3.14159265);        // angle en degrés
  if (angle<0) {angle=angle+360;}
  Serial.print("Angle=");  
  Serial.println(angle);

 delay(1000);
}
 
// Initialisation du module HMC5803L
void Init_HMC5803L(void)
{
  Wire.beginTransmission(HMC5803L_Addresse);
  Wire.write(0x00);
  Wire.write(0x70);      
  Wire.write(0x01);
  Wire.write(0xA0);  
  Wire.endTransmission();

}

bottom of page