mardi 13 mai 2014

MCP23017 + Raspberry PI = Montage


Alors c'est parti pour apprendre à rajouter des sorties sur le Pi sans utiliser des GPIO (ou rajouter des entrées aussi, mais je les utilise uniquement en sorties, je garde les entrées sur le Pi directement)

Au niveau du Pi on va utiliser le bus I2C avec un MCP23017.
Le MCP23017 se présente de cette façon :


Il est séparé en 2 Banks de 8 GPIO (GPAx et GPBx) + alim (VDD, VSS) + adresse I2C (A2, A1,A0) + Bus I2C (SCL, SDA) + le RESET (à papa).

Alors, comme je vais utiliser les 16 sorties du MCP23017 pour piloter des relais, je vous fais la liste de course.
Il faut :
  • Un MCP23017 (au prix, en prendre plusieurs, on ne sait jamais...) ici 10€
Je conseille de le prendre avec DIP, ça permet de changer le MCP23017 si on le crame en 2s.
Total des courses : 64€50 pour le Pi complet et 17€50 les 16 relais soit un total de 82€ pour un serveur WEB avec 16 sorties relais, 8 entrées, sonde de température, etc... Imbattable !

Bon maintenant il s'agit de câbler le tout.
Voici le schéma logique de tout ça :

J'alimente en 5V le MCP23017 car je veux que ces sorties soit en 5V pour pouvoir piloter les relais.

ATTENTION : Des légendes urbaines précise que les broches SDA et SCL du MCP23017 vont amener du 5V aux broches I2 du Rasp (ce qui est vrai) mais les pin I2C ont 2 resistances pull-up qui va faire redescendre la tension à 3.3V, donc pas de panique.
Par contre il est précisé sur certains sites que si on branche plusieurs MCP23017, les resistances du Pi ne suffiront pas et il y a un risque. Perso j'utilise pour l'instant qu'un seul MCP23017, mais si je dois en mettre un deuxième, je mettrais un "level shifter" pour convertir le 5V des MCP23017 en 3.3V.

Voila donc au niveau câblage MCP23017 ça donne :
  • Pin 9 (VDD) est connecté au 5V
  • Pin 10 (VSS) est connecté à la Masse
  • Pin 12 (SCL) est connecté au Pin 5 du PI
  • Pin 13 (SDA) est connecté au Pin 3 du PI
  • Pin 18 (Reset) est mis au 5V (maintenu High) car sans cela, le MCP se met au tas de temps en temps.
  • Pins 15, 16 & 17 (A0-A2) est utilisé pour donné un adressage au MCP, si on en met plusieurs, il faut qu'il ai donc un adressage différent. C'est du binaire, donc ici 000, voir schéma ci dessous.
  • Les pins GPA0 à GPA7 sont connectés à la première carte de 8 relais
  • Les pins GPB0 à GPB7 sont connectés à la deuxième carte de 8 relais
Les différentes adresses possibles (marqué 3,3V mais 5V fonctionne aussi) :

Bon une fois que c'est fait, on va préparer le Pi.
sudo vi /etc/modules
On rajoute ça (ou on enlève le # devant s'il y sont déja) :
i2c-bcm2708
i2c-dev
Ensuite :
sudo vi /etc/modprobe.d/raspi-blacklist.conf
On commente ces deux lignes (en rajoutant un # au début):
#blacklist spi-bcm2708
#blacklist i2c-bcm2708
On installe les tools I2C :
sudo apt-get install i2c-tools
Sur mon install j'ai des problème de droit (obligé de passer en root) même en mettant mon user dans le groupe I2C. Donc faire un chmod 4755 pour permettre l'exécution avec les variables root.

sudo chmod 4755 /usr/sbin/i2cdetect /usr/sbin/i2cset /usr/sbin/i2cget /usr/sbin/i2cdump
Une fois que tout ça est fait, on pourra appeler l'I2C de n'importe quel user (surtout www-data).
Pour savoir si le montage fonctionne, on va commencer par voir si le MCP23017 est reconnu.

Sur un Raspberry Pi première génération en 256Mo faire un
i2cdetect -y 0
Pour une deuxième génération en 512Mo (celui en lien sur amazon) :
i2cdetect -y 1
 En cas d'erreur, essayer en rajoutant un "sudo" devant mais normalement si vous avez lancé le chmod, il n'y a pas besoin.

Voici la sortie normale de la commande :
xxxxx@rasp-garage ~ $ 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: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
On voit le 20 en première colonne, 3ème ligne c'est l'adresse que l'on va donc utiliser (0x20 en fait car en Hexa).
Cette adresse est un résultat du câblage des pin A2, A1, A0.
Si A0 était branché au 5V au lieu de la masse, le MCP aurait 21 (0x21 en fait car en Hexa) comme adresse.

On va maintenant passer les 16 sorties du MCP en mode sorties (de base elles sont en entrées).

i2cset -y 1 0x20 0x00 0x00
i2cset -y 1 0x20 0x01 0x00
  • I2cset permet de faire des opérations sur le bus I2C.
  • -y est l'option de base qui permet de dire Yes pour éviter le mode interactif
  • 1 (i2cbus) pour désigner le bus I2C (lié à la version du Pi)
  • 0x20 (Chip Address) est l'adresse du MCP23017
  • 0x00 ou 0x01 (Data Address) désigne le bank de sortie du MCP (0x00 Bank A et 0x01 Bank B) Exactement IODIRA et IODIRB voir schéma plus bas.
  • 0x00 pour dire tout le monde est sortie.
Le 0x signifie qu'il faut parler Hexa, il y aura donc, à chaque fois, une gymnastique de l'esprit pour faire notre conversion binaire hexa (mais PHP le fera tout seul).

Pour info voici les ordres possibles au niveau Data Address :


Pour modifier l'état d'un PIN BANK A, on utilisera pour le champ Data address 0x12 ou 0x14 (même effet), pour la Bank B, ce sera 0x13 ou 0x15.

ATTENTION: Si vous avez acheté les mêmes cartes Relais que moi, les Pins sont INVERSÉS sur la carte relais pour éviter de la conso sur les sorties directement (la conso se fait sur la PIN VCC des cartes relais).
Si jamais c'est le cas, il faut agir inverser la commande.

Donc normalement quand on a les PIN en sorties, tous les relais sont sur OFF, mais avec notre carte relais il faut inverser, ce qui veux dire que de base quand on va mettre les PINs en sortie, les relais vont claquer de suite.
On va les remettre à zéro en faisant pour la bank A (GPA0-7) :
i2cset -y 1 0x20 0x14 0xFF
Pour des cartes relais normales, il faudra donc faire un
i2cset -y 1 0x20 0x14 0x00

Et pour la bank B (GPB0-7) :
i2cset -y 1 0x20 0x15 0xFF
Pour mettre à 1 la sortie GPB0, sur une carte relais normale, il faut faire
i2cset -y 1 0x20 0x15 0x01
Dans notre cas avec une carte relais inversé, il faudra faire
i2cset -y 1 0x20 0x15 0xFE
Le dernier élément de la ligne 0x01 (ou 0xFE en inversé) correspond au status des 8 relais de la Bank concerné.
A chaque ordre, nous renvoyons donc toute la Bank. Il faudra donc mettre en place une mémoire des états.

Si vous avez compris, tout se passe en binaire, on a 8 PINs, donc pour mettre à 1 le premier PIN (Pin 0), il faudra envoyer pour une carte relais normale

0000 0001 ce qui correspond à 0x01 en Hexa.

L'inverse pour une carte relais comme la notre est
1111 1110 ce qui correspond à 0xFE en Hexa.
Pour mettre à 1 les PINs 0, 3, et 7 sur une carte relais normale
1000 1001 ce qui correspond à 0x89 en Hexa.
Sur une carte relais inversé
0111 0110 ce qui correspond à 0x76 en Hexa.
Ici il faut juste comprendre que le Pin0 est le bit de poids faible et le Pin7 celui de poids fort. Un schéma est plus parlant...


Je ne vais pas faire une cours de conversion Binaire Hexa mais en gros voici la procédure :
Pour passer du binaire à l'Hexa, on passe par du décimal, qui lui utilise une table conversion pour aller à de l'Hexa.

Revenons à nos moutons, comme dit plus haut, au démarrage les PINs sont en entrée, on va donc créer un script de démarrage pour les passer en sortie au démarrage :
sudo vi ~/start.sh

Le fichier doit inclure 2 choses, passer en premier les ports à 0 puis les configurer en sortie, ainsi on évite le clac intempestif du démarrage des relais du à ma carte inversé. Copier tout dans le nouveau fichier :
#!/bin/bash
i2cset -y 1 0x20 0x14 0xFF
i2cset -y 1 0x20 0x15 0xFF
i2cset -y 1 0x20 0x00 0x00
i2cset -y 1 0x20 0x01 0x00
Pour une carte relais normale :
#!/bin/bash
i2cset -y 1 0x20 0x14 0x00
i2cset -y 1 0x20 0x15 0x00
i2cset -y 1 0x20 0x00 0x00
i2cset -y 1 0x20 0x01 0x00
Penser à le rendre Exécutable  :
sudo chmod 755 ~/start.sh
On va maintenant mettre ça dans un CRON qui se lance au démarrage :
crontab -e
Rajouter à la fin :
@reboot /bin/sh /home/nom-user/start.sh
Pensez à modifier le nom-user par le nom d'utilisateur avec lequel vous travaillez.
Le fichier CRONTAB se modifie avec nano, pas besoin de faire un "i" pour passer en édition, et pour sauvegarder, il faut faire un Ctrl+X puis Yes et entrée.
Pour que le crontab se modifie avec Vi, il faut modifier l'éditeur pas défaut (qui est nano), pour cela :
export EDITOR=vi
Voilà, normalement c'est fini pour la partie montage et paramétrage Rpi.
La suite : PHP pour contrôler tout ça.

4 commentaires:

  1. Merci beaucoup pour ce billet, il m'a permis de comprendre comment fonctionne ce module MCP23017 et grâce à toi, je me suis créé mon petit tableau CALC ou je renseigne mes valeurs souhaités en sortie et ça me génère le code à mettre dans mon Putty. Encore merci. Je ne doute pas un seul instant que ce bout de chemin me permettra d'ouvrir/fermer mes volets roulants.
    MERCI BEAUCOUP !

    RépondreSupprimer
  2. Avec plaisir, je devrais bientôt sortir du code qui va avec en PHP. Je finis quelque truc dessus, mais c'est déjà fonctionnel. Par contre ça ne prend en compte que des sorties, j'ai pas encore bossé sur les entrées avec un mcp23017.

    RépondreSupprimer
  3. Super article que je découvre là.
    Sans savoir que je prenais un risque, j'ai déjà fait un montage avec 4 MCP23017 sur le même port I²C et le raspberry n'a pas bronché. Je ne dis pas que c'est à faire mais je dis juste que ça a marché. :)
    Il y a 2 pins intéressantes mais que je n'ai pas encore exploité. Il s'agit des pins d'interruptions (INT A et INTB) en position 19 et 20.
    Il semblerait qu'une bascule d'état d'une entrée sur le côté A par ex fasse passer la PINA à l'état haut. Ce qui peut éviter par ex de faire du polling en permanence pour savoir si une fenêtre est ouverte (oui ok c'est ce que je fais ...).
    Les interruptions se gèrent très bien en python par ex sur les gpios du raspberry.

    RépondreSupprimer
  4. Salut !
    De mon coté j'ai déjà fait un montage avec 2, donc c'était vraiment à but informatif :)
    Alors pour INTA et INTB jamais utilisé, comme toi je fais le cochon en faisant une routine qui analyse les entrées, par contre en PHP :)
    et franchement ça pique 2% de cpu avec un refresh de 200ms, alors pourquoi se priver !
    Mais dès que j'utiliserais un peu plus entrées, je regarderai cette histoire de INTA et INTB merci !

    RépondreSupprimer