J’avoue, l’I2C j’aime bien. Pourquoi ? Je n’en sais rien. Peut-être parce c’est ce qui m’a donné le moins de fil à retordre lors de mes expérimentations passées.
Toujours est-il qu’ayant un LCD I2C de chez Robot Electronics associé à un petit clavier (keypad) d’un côté, et une Raspberry Pi fraîchement déballée de l’autre, je me suis dit que c’était un bon exercice pratique.
Ah oui, dernier détail : Python, j’aime bien aussi. Je suis tombé dedans tout récemment, et je me suis laissé séduire. Encore une histoire de serpent, mais ce coup-ci avec une framboise et pas une pomme. Faut bien changer un peu de temps en temps.
On a donc résumé la mission du jour : Accéder au LCD I2C et à son keypad depuis la planète Rhas-Pih tu devras. Du Python, la Force t’y conduira.
Le support I2C pour commencer tu installeras
Afin de bien camper le décor, sachez que j’utilise la distribution Occidentalis 0.2 de chez Adafruit déjà présentée dans nos pages. Elle a l’avantage d’avoir déjà fait une partie du boulot en incluant le support de diverses interfaces hardware, dont l’I2C. Alors pourquoi se casser la tête, car pour avoir essayé de dépanner rapidement en réunion un POBOTien en perdition avec sa Raspbian, même si ce n’est pas la mer à boire, ça peut vite vous coûter quelques heures de recherche d’information et d’essais-erreurs.
Bon, ça c’est bien, mais ça ne fait pas tout. Il nous manque quelques outils et bibliothèques pour pouvoir l’utiliser.
Cet article de chez nous en parle déjà, mais je vais en extraire ici ce qui nous concerne directement, car il développe un cas de figure basé sur d’autres distribs. Le point important est la toolbox i2c-tools fournie par lm-sensors. En date de rédaction, il s’agit de la version 3.1.0.
Commencez par en récupérer l’archive :
$ wget http://dl.lm-sensors.org/i2c-tools/releases/i2c-tools-3.1.0.tar.bz2
Puis décompactez-là quelque part dans votre home dir sur la RasPi :
$ tar xf i2c-tools-3.1.0.tar.bz2
et propulsez-vous dans le répertoire ainsi créé :
$ cd i2c-tools-3.1.0
Lisez le README, et construisez les outils et la lib en utilisant la commande indiquée, à savoir :
$ make EXTRA="py-smbus"
En fait si vous omettez le EXTRA, eh bien ça ne nous servira pas à grand chose (en tout cas relativement à Python), puisque c’est précisément le binding Python qui nous intéresse ici.
Un sudo make install EXTRA="py-smbus" installera le tout là où il faut. A noter qu’il est possible de le faire directement sans passer par la case précédente, install déclenchant le build au préalable s’il n’est pas déjà disponible.
Vous disposer maintenant dans les libs Python d’un module dénommé smbus qui est votre clé vers le monde de l’I2C, qu’il vous suffira ensuite de charger via la classique instruction import.
A noter qu’il est question de SMBus et non pas d’I2C ici. De ce que j’en ai compris ça se vaut plus ou moins pour ce qui nous concerne. J’ai lu çà et là des discussions enflammées sur le fait que l’un est un "subset" de l’autre, et réciproquement, mais je n’en ai rien retenu de très constructif. Donc en première approximation et jusqu’à preuve du contraire, pour nous c’est bonnet blanc et blanc bonnet.
Tout ton bazar connecter tu devras
Je sens que les gouttes de sueur commencent à perler sur votre front, car vous n’avez pas manqué de lire de partout que les GPIO de la RasPi ne sont absolument pas protégées ni même 5V tolérantes. Or notre LCD fonctionne en 5V. Arghhh....
Avant de sortir un arsenal de level shifters, qui certes marcheront, penchons-nous un coup sur les signaux de l’I2C. Pour mémoire, il s’agit de deux lignes tirées à Vcc par des pull-ups. Lorsque quelqu’un veut produire un signal, il le fait en reliant la ligne à la masse via un driver qui n’est rien d’autre qu’un transistor en collecteur ouvert ou équivalent. Le reste du temps le driver est dit en haute impédance (Hi-Z), c’est à dire qu’il se comporte comme un interrupteur ouvert. C’est la solution utilisée pour permettre un fonctionnement en bus multi-drop, avec plusieurs devices dessus. Or la RasPi intègre deux pull-up de 1k8 sur les lignes SDA et SCL du GPIO, et donc c’est elle qui va maintenir le niveau haut avec une tension qui lui convient parfaitement. Le driver I2C du LCD ne va faire que relier ces lignes à la masse lorsqu’il voudra générer des signaux. Il ne les force jamais à son 5V à lui. Du coup, pas de prise de tête : il suffit de relier les signaux directement sur le GPIO.
D’ailleurs cela est confirmé sur le site même du fabricant, qui nous indique gentiment ici le câblage de quelques-uns de ses produits lorsqu’on veut les connecter sur la RasPi.
Attention : Ne me rendez pas responsable si vous avez grillé votre framboise en y connectant tout et n’importe quoi : ce qui est expliqué ici n’est valable que parce que notre LCD ne fonctionne qu’en tant que slave. Si vous connectez un équipement fonctionnant en master, il y a de fortes chances que ce soit lui qui drive les lignes à l’état haut. Et s’il est en logique 5V, adios amigos :(
Les bons droits d’accès avoir il te faudra
On peut lire çà et là des articles qui indiquent de lancer les applications en tant qur root (via sudo) faute de quoi ça ne marche pas. D’autres solutions utilisent des bibliothèques qui se chargent de fournir l’accès root à un programme lancé par un user standard. Je n’ai rien fait de tout cela (à ma connaissance en tout cas), et me suis contenté d’ajouter le user pi (qui est celui avec lequel je travaille sur la RasPi comme la plupart d’entre vous très certainement) dans le groupe i2c via la commande :
$ sudo adduser pi i2c
J’ai vérifié cela par la procédure suivante :
$ groups
pi adm dialout cdrom sudo audio video plugdev games users input
$ python
Python 2.7.3rc2 (default, May 6 2012, 20:02:25)
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from smbus import SMBus
>>> bus = SMBus()
>>> bus.open(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IOError: [Errno 13] Permission denied
>>> exit()
Le user pi n’appartient pas au groupe i2c, et toute tentative d’accès à un des bus détectés échoue. On l’ajoute donc au groupe :
$ sudo adduser pi i2c
Adding user <span class="base64" title="PGNvZGUgY2xhc3M9J3NwaXBfY29kZSBzcGlwX2NvZGVfaW5saW5lJyBkaXI9J2x0cic+cGknIHRvIGdyb3VwPC9jb2RlPg=="></span>i2c' ...
Adding user pi to group i2c
Done.
--- logout / login ---
$ groups
pi adm dialout cdrom sudo audio video plugdev games users i2c input
Et on refait le test maintenant que pi est bien dans le groupe i2c :
$ python
Python 2.7.3rc2 (default, May 6 2012, 20:02:25)
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from smbus import SMBus
>>> bus = SMBus()
>>> bus.open(1)
>>> bus.read_byte_data(0x63, 3)
6
>>>
Point d’erreur cette fois-ci et tout va bien, la lecture du registre 3 du LCD à l’adresse 0x63 retournant la version de son firmware, soit 6 ici, ce qu’on peut vérifier par le message qu’il affiche à la mise sous tension :
LCD03 REVISION6
I2CMODE @ 0xC6
On notera que l’adresse affichée ici est en mode 8 bits, c’est à dire bit de R/W inclus. On retrouve 0x63 tout simplement en divisant 0xC6 par 2, ce qui équivaut à un décalage d’un bit vers la droite.
Pour clôturer ce paragraphe sur les droits d’accès, la confirmation de l’approche est donnée tout simplement en observant les caractéristiques des pseudo-fichiers correspondant aux bus I2C :
$ ls -l /dev/i2c*
crw-rw---T 1 root i2c 89, 0 Dec 31 18:07 /dev/i2c-0
crw-rw---T 1 root i2c 89, 1 Dec 31 18:07 /dev/i2c-1
On y voit que le owner est root, qu’il appartiennent au groupe i2c pour lequel les droits d’accès en lecture/écriture sont octroyés, aucun droit n’étant octroyé aux autres utilisateurs. CQFD.
Petit rappel :
Je me permets de souligner ici un élément important, déjà annoncé en début d’article : cette facilité de mise en oeuvre est en grande partie le résultat de l’utilisation de la distribution Occidentalis au lieu de la Raspbian de base. Sur cette dernière il y un certain nombre de choses à faire en plus, et à moins d’y tenir vraiment, c’est plus chronophage que passionnant. Certes c’est peut-être formateur, mais mon objectif premier étant de tester la mise en oeuvre de l’I2C tout en conservant un minimum d’heure de sommeil par nuit, c’est tout vu. Maintenant, c’est vous qui voyez.
Et maintenant ?
Passés les premiers tests de bon fonctionnement en mode interactif, le plus propre est d’écrire un petit module qui va encapsuler cela bien proprement dans une classe baptisée LCD03. Je confesse avoir manqué d’imagination, mais pourquoi se torturer les méninges.
Ce module, qui intègre un petit programme de démo lorsqu’il est lancé en direct, vous est généreusement offert par votre serviteur. Il fait partie d’un package Python récemment démarré et qui a pour vocation de fournir une boite à outils simple pour interfacer ce qui nous passe entre les mains. Je sais qu’il y en a déjà des légions, mais comme cela vous aurez le choix.
Il est disponible sous GitHub via l’URL : git://github.com/Pobot/RasPy.git
Plutôt que d’en faire des tartines ici, le mieux est de lire le code : je l’ai abondamment commenté.
Et si vous vous demandez à quel anglophone j’ai piqué le source : à personne. Il se trouve que par déformation professionnelle, je rédige tout en anglais dès lors que j’écris du code, même si c’est pour moi. Et comme l’anglais est beaucoup plus concis que le français, ça évite des commentaires à rallonge pour dire la même chose.
Et ça donne quoi ?
J’ai failli oublier... Ci-dessous une petite photo de la manip :
On y voit la connexion avec le GPIO, le LCD avec son pote le keypad et un serpent qui surveille tout ce petit monde.
Je sais que le design du boîtier n’est pas au top, car j’avais packagé le LCD dans un modèle façon Traban de l’ancienne RDA. On fait avec ce qu’on a...
Have fun ;)
Vos commentaires
# Le 20 octobre 2014 à 23:03, par goliatt22 En réponse à : RasPi, I2C, Python et LCD
bonsoir
pour vous tenir au courant, votre solution est la bonne
j’ai juste du faire un reboot pour que ça prenne en compte les changements.
merci beaucoup.
sa me sort une belle épine du pied
réactivité efficacité merci
# Le 20 octobre 2014 à 23:10, par Eric P. En réponse à : RasPi, I2C, Python et LCD
Merci de nous avoir tenu informé.
En fait le reboot n’était peut-être pas nécessaire. Redémarrer le serveur aurait peut-être suffi, car pour un utilisateur normal, la prise en compte de ce type de modification se fait par un simple logout/login.
Mais c’est un point de détail, l’essentiel étant que votre problème soit résolu ;)
Cordialement
Eric
Répondre à ce message
# Le 20 octobre 2014 à 00:57, par goliatt22 En réponse à : RasPi, I2C, Python et LCD
bonjour
merci pour ce tuto très utiles
car ça fait une semaine que je bloque sur les permissions et droit pour i2c.
et la grâce à vous je viens d’avancer un peu.
mais j’ai une question (un probleme plus)
sur mon raspberry j’ai brancher une puce mcp23017
je la vois i2cdetect, j’arrive a m’en servir avec python sous inviter de commande.
mais impossible depuis un site héberger dans le raspberry.
j’appelle une commande python avec :
exec("python /var/www/bin/relais1/test.py") ;
ou
system("python /var/www/bin/relais1/test.py") ;
et rien pas de réaction alors que si je tapedans l’inviter de commande :
python /var/www/bin/relais1/test.py
sa fonctionne
merci si vous pouvez m’aider ça me ferais gagner des heures de sommeil
# Le 20 octobre 2014 à 09:26, par Eric P. En réponse à : RasPi, I2C, Python et LCD
Bonjour,
Il se peut que ce soit lié à un problème de droits d’accès.
Le user utilisé par le serveur Web ("www-data" assez souvent) ne doit en effet pas faire partie du groupe qui peut accéder aux ressources I2C. Il faut donc l’y ajouter, comme vous l’avez peut-être fait pour l’utilisateur "pi" si la distribution utilisée ne l’avais pas déjà configuré comme tel.
Cordialement
Eric
Répondre à ce message