I2C (Inter-Integrated Circuit) est un bus de données qui permet de relier facilement un microprocesseur et différents circuits électroniques. Conçu par Philips en 1982 pour les applications de domotique et d’électronique domestique, il a permis d’interconnecter les composants d’une télévision moderne : récepteur de la télécommande, réglages des amplificateurs basses fréquences, tuner, horloge, gestion de la prise péritel, etc.
Il existe maintenant d’innombrables périphériques exploitant ce bus, dont beaucoup de microcontrôleurs. Le poids de l’industrie de l’électronique grand public a permis des prix très bas grâce à ces nombreux composants.
Remarque : Ce bus porte parfois le nom de TWI (Two Wire Interface) chez certains constructeurs.
I2C est un bus série synchrone bidirectionnel half-duplex.
Plusieurs équipements, soit maîtres, soit esclaves, peuvent être connectés au bus. Les échanges ont toujours lieu entre un seul maître et un (ou tous les) esclave(s), toujours à l’initiative du maître (jamais de maître à maître ou d’esclave à esclave). Cependant, rien n’empêche un composant de passer du statut de maître à esclave et réciproquement.
La connexion est réalisée par l’intermédiaire de deux lignes :
Remarque : Il ne faut également pas oublier la masse qui doit être commune aux équipements.
Le nombre maximal d’équipements est limité par le nombre d’adresses disponibles, 7 bits pour l’adresse et un bit pour définir si on écrit ou on lit (R/W), soit en théorie 128 périphériques. De nombreuses adresses sont déjà attribuées par les fabricants ce qui limite grandement le nombre d’équipements.
Le codage utilisé est de type NRZ (non retour à 0) :
Le niveau (« HIGH » ou « LOW ») de la ligne SDA doit être maintenu stable pendant le niveau « HIGH » sur la ligne SCL pour la lecture du bit.
Il existe cinq vitesses de transmission :
Le bus étant synchrone, c’est le maître qui impose l’horloge via la ligne SCL.
Lien : Spécifications Bus I2C
Le message peut être décomposé en deux parties :
La condition de START est une transgression de la règle de codage des bits qui est utilisée par le maître pour signifier le début d’une trame. Cette condition est caractérisée par le passage de la ligne SDA du niveau « HIGH » au niveau « LOW » pendant que la ligne « SCL » est maintenue au niveau « HIGH ».
La condition de STOP est une transgression de la règle de codage des bits qui est utilisée par le maître pour signifier la fin d’une trame. Cette condition est caractérisée par le passage de la ligne SDA du niveau « LOW » au niveau « HIGH » pendant que la ligne SCL est maintenue au niveau « HIGH ».
Le récepteur positionne le bit d’acquittement à :
L’octet d’adressage peut être scindé en deux parties :
On peut également considérer que l’adresse est codée sur les 8 bits, chaque esclave a alors deux adresses, l’adresse paire qui sert à lui envoyer des données, l’adresse impaire pour lui demander d’en envoyer.
Généralement, les fabricants des circuits I2C fixent une partie de l’adresse pour permettre d’identifier le type de circuit et laissent une partie libre permettant de relier plusieurs circuits du même type sur le bus.
Par exemple, le circuit I2C de 8 bits E/S (I/O) est déclinée en deux versions donnant deux adresses de base :
Le fabricant a laissé libre les 3 bits d’adresses de poids faible (A2 A1 A0) ce qui permettra de relier 2^3 = 8 circuits sur un même bus.
Si la version de votre noyau est >= 3.18 :
# uname -a
Linux raspberrypi 3.18.5+
Alors vous pouvez activer l’I2C en utilisant l’outil raspi-config :
# sudo raspi-config
Ou ajouter cette option à votre fichier /boot/config.txt
:
# I2C (or dtparam=i2c0=on on old models)
dtparam=i2c1=on
# sudo apt-get install i2c-tools
# sudo apt-get install libi2c-dev
# cat /usr/include/linux/i2c.h
# cat /usr/include/linux/i2c-dev.h
# sudo vim /etc/modprobe.d/raspi-blacklist.conf
#blacklist i2c-bcm2708
# sudo vim /etc/modules
i2c-dev
i2c-bcm2708
# sudo vim /lib/udev/rules.d/60-i2c-tools.rules
KERNEL=="i2c-0" , GROUP="i2c", MODE="0660"
KERNEL=="i2c-[1-9]*", GROUP="i2c", MODE="0666"
Brancher la carte de test I2C - E/S :
PCF8574 | Symbole | Couleur connecteur RJ |
---|---|---|
16 | VDD | Rouge |
15 | SCL | Jaune |
14 | SDA | Vert |
8 | VSS | Noir |
Sur le connecteur GPIO de la RaspberryPi :
# i2cdetect -y 1
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: 20 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
Remarque : l’adresse de base du PCF8574 est 0x40 et sur la Raspberry on obtient 0x20 donc (0x40 >> 1) car le bit R/W (poids faible) n’intervient pas dans l’adresse du circuit I2C.
L’accès au bus I2C peut être géré :
par les appels système (system calls) : open/ioctl/read/write/close (un exemple de classe BusI2C
basée sur ces appels est fourni dans ce document)
par la WiringPi : une bibliothèque C d’accès au GPIO utilisé sur la Raspberry Pi (BCM2835)
Installation de la librairie wiringPI :
$ scp wiringPi-02a3bd8.tar.gz pi@192.168.1.2:/home/pi
$ ls -l
-rw-r--r-- 1 pi pi 107676 juil. 1 20:33 wiringPi-02a3bd8.tar.gz
$ tar xfz wiringPi-02a3bd8.tar.gz
$ cd wiringPi-02a3bd8/
$ ./build
wiringPi Build script
=====================
WiringPi Library
[UnInstall]
[Compile] wiringPi.c
[Compile] wiringSerial.c
[Compile] wiringShift.c
[Compile] piHiPri.c
[Compile] piThread.c
[Compile] wiringPiSPI.c
[Compile] wiringPiI2C.c
[Compile] softPwm.c
[Compile] softTone.c
[Compile] mcp23008.c
[Compile] mcp23016.c
[Compile] mcp23017.c
[Compile] mcp23s08.c
[Compile] mcp23s17.c
[Compile] sr595.c
[Compile] pcf8574.c
[Compile] pcf8591.c
[Compile] mcp3002.c
[Compile] mcp3004.c
[Compile] mcp4802.c
[Compile] mcp3422.c
mcp3422.c: In function ‘myAnalogRead’:
mcp3422.c:47:37: warning: variable ‘b3’ set but not used [-Wunused-but-set-variable]
[Compile] max31855.c
[Compile] drc.c
[Link (Dynamic)]
[Install Headers]
[Install Dynamic Lib]
WiringPi Devices Library
[UnInstall]
[Compile] ds1302.c
[Compile] maxdetect.c
[Compile] piNes.c
[Compile] gertboard.c
[Compile] piFace.c
[Compile] lcd128x64.c
[Compile] lcd.c
[Link (Dynamic)]
[Install Headers]
[Install Dynamic Lib]
GPIO Utility
[Compile] gpio.c
[Compile] extensions.c
[Compile] readall.c
[Link]
[Install]
All Done.
NOTE: This is wiringPi v2, and if you need to use the lcd, Piface,
Gertboard, MaxDetext, etc. routines then you must change your
compile scripts to add -lwiringPiDev
On peut tester avec la carte PCF8591 CAN/CNA :
$ gpio -v
gpio version: 2.08
Copyright (c) 2012-2013 Gordon Henderson
This is free software with ABSOLUTELY NO WARRANTY.
For details type: gpio -warranty
This Raspberry Pi is a revision 2 board.
$ gpio readall
+-----+-------+------+----+-Rev2-----+----+------+-------+-----+
| wPi | Name | Mode | Val| Physical |Val | Mode | Name | wPi |
+-----+-------+------+----+----++----+----+------+-------+-----+
| | 3.3v | | | 1 || 2 | | | 5v | |
| 8 | SDA | IN | Lo | 3 || 4 | | | 5V | |
| 9 | SCL | IN | Lo | 5 || 6 | | | 0v | |
| 7 | GPIO7 | IN | Hi | 7 || 8 | Lo | ALT0 | TxD | 15 |
| | 0v | | | 9 || 10 | Lo | ALT0 | RxD | 16 |
| 0 | GPIO0 | IN | Hi | 11 || 12 | Hi | IN | GPIO1 | 1 |
| 2 | GPIO2 | IN | Hi | 13 || 14 | | | 0v | |
| 3 | GPIO3 | IN | Hi | 15 || 16 | Hi | IN | GPIO4 | 4 |
| | 3.3v | | | 17 || 18 | Hi | IN | GPIO5 | 5 |
| 12 | MOSI | IN | Hi | 19 || 20 | | | 0v | |
| 13 | MISO | IN | Hi | 21 || 22 | Hi | IN | GPIO6 | 6 |
| 14 | SCLK | IN | Hi | 23 || 24 | Hi | IN | CE1 | 10 |
| | 0v | | | 25 || 26 | Hi | IN | CE1 | 11 |
+-----+-------+------+----+----++----+----+------+-------+-----+
$ gpio i2cdetect
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- 08 -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- 48 -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- 6b -- -- -- --
70: -- -- -- -- -- -- -- --
Remarque : l’adresse de base du PCF8591 est 0x90 et sur la Raspberry cela donne 0x48 donc (0x90 >> 1) car le bit R/W (poids faible) n’intervient pas dans l’adresse du circuit I2C.
Pour fabriquer les programmes de test utilisant la bibliothèque WiringPi, il vous faudra utiliser ce fichier Makefile
:
INCLUDE = -I/usr/local/include
CFLAGS = -Wall $(INCLUDE)
LDFLAGS = -L/usr/local/lib
LDLIBS = -lwiringPi -lwiringPiDev -lpthread -lm
Pour un projet Qt, il faudra ajouter au fichier .pro
pour utiliser la wiringPi :
Il faut ajouter :
INCLUDEPATH += . /usr/local/include
LIBS += -lwiringPi -lwiringPiDev -lpthread -lm
Lire : PCF8574.pdf
Tester le programme suivant :
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "wiringPi.h"
#include "wiringPiI2C.h"
// Adressage I2C sur la raspberry
#define ADR_BASE_8574 (0x40 >> 1)
#define ADR_BASE_8574A (0x70 >> 1)
int main()
{
int fd;
int i2cAddress = ADR_BASE_8574;
if ((fd = wiringPiI2CSetup(i2cAddress)) < 0)
return fd ;
wiringPiI2CWrite(fd, 0x00); // état initial des 8 sorties
sleep(2);
wiringPiI2CWrite(fd, 0x55); // une sortie sur deux
sleep(2);
wiringPiI2CWrite(fd, 0xAA); // une sortie sur deux
sleep(2);
wiringPiI2CWrite(fd, 0x00); // retour à l'état initial
return 0;
}
Code source : test-mo-wiringpi-8574.zip
Aller plus loin : utiliser des masques pour pouvoir commander individuellement une (ou plusieurs) sortie(s).
Lire : PCF8591.pdf
Tester le programme suivant :
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "wiringPi.h"
#include "wiringPiI2C.h"
#define ADR_BASE_8591 (0x90 >> 1)
#define NB_CANAUX 4
int main()
{
int fd;
int i2cAddress = ADR_BASE_8591;
int x;
float tension;
const float VDD = 5.; // 5 Volts
const int NB_PAS = 256; // convertisseur 8 bits
int canal = 0; // entrée CAN n°0
int config;
if ((fd = wiringPiI2CSetup(i2cAddress)) < 0)
return fd ;
while(1)
{
// cf. doc PCF8591.pdf page 6
config = 0x00 | canal;
printf("# config : 0x%02X - canal : %d\n", (unsigned char)config, canal);
wiringPiI2CWrite(fd, config);
x = wiringPiI2CRead(fd); // à ignorer (conversion précédente)
x = wiringPiI2CRead(fd);
printf("# data CAN : 0x%02X\n", (unsigned char)x);
tension = (float)( (float)(x & 0x00FF) * (float)(VDD/NB_PAS) );
printf("# tension CAN = %2.2fV\n", tension);
printf("\n");
sleep(2);
}
return 0;
}
Code source : test-mo-wiringpi-8591.zip
Lire : DS1621.pdf
write 0xAC : access config (0x03 : output polarity active, single shot shot operation)
write 0xEE : start temperature conversation
write 0xAA : read temperature
do the read temperature
Code source : test-mo-wiringpi-ds1621.zip