GPIO

Raspberry Pi GPIOs mittels I2C Port Expander erweitern – Teil 1

Wer mehrere oder ein größeres Projekt hat, wird schnell feststellen, dass die GPIO Pins des Raspberry’s schnell zu wenig werden. Für all jene wird in diesem Tutorial gezeigt, wie man mittels eines I2C Port Expander sehr einfach die GPIO Pins um ein vielfaches erhöhen kann.



 

In manchen Situationen kann es vorkommen, dass man mehr GPIO Pins benötigt, als es Ausgänge hat und man an die physikalischen Grenzen stößt. Doch dafür gibt es die sehr nützlichen Port Expander. Auf die Benutzung einer dieser gehen wir in diesem Beitrag näher ein.

Ich benutze den MCP23017. Zu erst einmal der Aufbau der Mikrochips:

 

mcp23017_pinout-300x243

Wie man sieht sind die Unterschiede minimal, für dieses Tutorial ist es egal, welcher verwendet wird.

 

Vorbereitung

Eine kleine Erklärung der wichtigsten Pins:

  • GPA0-7 und GPB0-7 sind die GPIO Pins
  • A0, A1, A2 werden an + (3.3V) bzw. – (GND) angeschlossen und legen intern den Namen fest. Sind mehrere Port Expander angeschlossen, muss jeder dadurch eindeutig identifizierbar sein. Beim ersten I²C würde man alle an GND anschließen, beim nächsten A0 an 3.3V und die beiden anderen an GND. Beim dritten a! an 3.3V und die anderen zwei an GND usw. Es ist also mögich bis zu 2³ also 8 Port-Expander anzuschließen.
  • VDD (Pin 9) bekommt die Eingangsspannung (3.3V)
  • VSS (Pin 10) wird an GND angeschlossen
  • SCL (Pin 12) wird an den GPIO Pin 5 des Pi’s angeschlossen
  • SDA (Pin 13) wird  an den GPIO Pin 3 des Pi’s angeschlossen

Dementsprechend habe ich eine kleine Schaltung mit 3 LEDs gebaut (als Vorwiderstände 330Ω).

i2c_Steckplatine

(Den Taster benötigen wir erst in Teil 2 des Tutorials.)

Als erstes muss nun im Pi die Ntzung des I2C freigeschaltet werden.Am einfachsten geht dies mittels

sudo raspi-config

Unter „Advanced Options“ > „I2C“ wird es aktiviert.
Bei älteren Raspbian Versionen muss man zusätzlich eine Datei bearbeiten

sudo nano /etc/modules

und fügt an das Ende diese beiden Zeilen an:

i2c-bcm2708
i2c-dev

Mit STRG + O und STRG + X speichern und beenden.

 

Jetzt müssen die Module aus der Blacklist Datei genommen werden, da sie sonst nicht funktionieren.

sudo nano /etc/modprobe.d/raspi-blacklist.conf

und vor die beiden Einträge eine Raute # setzen.

#blacklist spi-bcm2708
#blacklist i2c-bcm2708

Erneut mit STRG + O und STRG + X speichern und beenden.

Damit wir den I2C nun auch ansprechen können, müssen wir noch ein paar Pakete installieren.

sudo apt-get install python-smbus i2c-tools

Anschließend den Pi noch herunterfahren, einige Sekunden warten und vom Strom trennen.

sudo shutdown now

Hardware testen

Nachdem alles angeschlossen ist und alle Verbindungen nochmals überprüft worden sind, starte den Pi und warte bis er hochgefahren ist.

Ich nutze einen Raspberry Pi Rev.2, daher teste ich es mit

sudo i2cdetect -y 1

Wer einen Pi Rev.1 hat, muss anstelle der 1 eine 0 eingeben.Die Ausgabe sieht folgendermaßen aus:

pi@raspberrypi ~ $ sudo 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: -- -- -- -- -- -- -- --

Unter der Adresse 0x20 (hexadezimal) befindet sich also der I2C. Wäre A2 z.B. an 3.3V angeschlossen (A1 und A0 an GND), so wäre er unter der Adresse 0x24 ansprechbar. Das ist, wie bereits erwähnt, wichtig, wenn man mehrere Port Expander angeschlossen hat, um sie eindeutig ansprechen zu können.

Um die LEDs anzusprechen, müssen die Ports entweder als Input oder Output deklariert werden (Rev1 Benutzer bitte wieder anpassen).

sudo i2cset -y 1 0x20 0x01 0x00

Ich gebe ein paar Beispiele, die erläutern, wie der Befehl funktioniert:

i2cset -y 1 0x20 0x01 0x00   #alle Pins von GPB sind Output
i2cset -y 1 0x20 0x01 0x04   #GPB2 ist Input, der Rest von GPB Output (da 0x04 in binär 00000100)
i2cset -y 1 0x20 0x00 0x80   #GPA7 ist Input, der Rest von GPA Output

Als erstes wird also die Adresse angesprochen, die man mittels i2cdetect herausgefunden hat. Der zweite Wert ist in dieser Tabelle (aus dem Datenblatt):

register

Nachdem wir also die Richtung (IODIRB) angegeben haben (0 = Output, 1 = Input), wollen wir die drei LEDs leuchten lassen (Binär 00000111 = 0x07):

sudo i2cset -y 1 0x20 0x15 0x07

Würden wir die GPA Pins benutzen, stände statt 0x15 eben 0x14.
Damit die LEDs aufhören zu leuchten, müssen wir den Pegel der Pins wieder auf 0 setzen:

sudo i2cset -y 1 0x20 0x15 0x00

Im nächsten Tutorial schreiben wir ein Skript, dass automatisch auf die Pins zugreift und lesen Input Werte ein.



, , , , , ,


34 Kommentare

  1. Rogon sagt:

    Guten Tach,
    sehr schönes Tutorial! Kompliment!
    Da ich leider nur sehr begrenzte Kenntnisse im Bereich Elektronik besitze, habe ich da eine Frage:

    sudo i2cset -y 1 (1) 0x20 (2) 0x15 (3)0x07

    (zur besseren Orientierung habe ich die Zahlen in den Klammern hinzugefügt)
    Also (1) gibt die Adresse des Slave an (zu finden mit „sudo i2cdetect -y 1“)
    (2) ist die „HEX“-Adresse der Zeile, die aussagt, was passieren soll (15=OLATB ==>Zustand der B-Pins soll verändert werden).
    (3) in welchem Zustand die Pins, nach dem Kommando sind ( 07 in HEX-Rechner => 111 = 00000111 => GPB 0 – GBP 2 auf High, GBP 3 – GBP 7 auf LOW)

    So, wie ich das gerade schreibe, und dabei nochmal dein Tutorial lesen, klingt das irgenwie logisch(für mich). Eventuell sitze ich auch einfach nur lange genug dran, um mir mein Geschreibsel schön zu reden 😉
    Kannst Du mir bitte sagen, ob ich richtig stehe und das Licht an geht, oder nicht?
    Vlt. könntest Du dem Tutorial noch ein paar mehr Beispiele hinzufügen, damit so Knalltüten wie ich, das noch besser verstehen?

    Danke, und schöne Grüße,
    Rogon….

    • Felix sagt:

      Hi Rogon,
      vielen Dank für das Lob 🙂
      ja deine Ausführung stimmt soweit. Was ist noch genau unklar? Waren die 3 Beispiele nicht hilfreich? Verbesserungsvorschläge sind immer willkommen.

      LG Felix

  2. Rogon sagt:

    Hallo Felix,
    zunächst einmal vielen Dank, für die schnelle Antwort.

    —!!!Heureka!!!—

    Unklar ist eigentlich nichts, ich habs dann ja doch verstanden.
    Bei der Elektrik ist bei mir so:
    Ich sitze in einem dunkeln Raum. Jemand gibt mir einen Würfel in die Hand, und erst wenn er das Licht anschaltet, glaube ich auch wirklich, dass es ein Würfel ist.
    Also Unsicherheit auf Grund völliger Unkenntnis.
    Deine Tutorials sind super! Kurz, knapp und knackig und am Ende funktioniert es sogar auch noch 😉
    Vergiss bitte die Bemerkung mit den zusätzlichen Beispielen…
    Zu leicht soll man es auch nicht machen, ein bisschen muss der Grips schon arbeiten.
    Werde, aus Freude, jetzt erstmal ne Runde mit den LED´s blinken 😉
    Nochmals vielen Dank für Deine Hilfe. Keep on running…
    LG Rogon…

    • Felix sagt:

      Hi Rogon,
      nochmal danke für das Lob! Freut mich, dass es dir gefällt.
      Sollte bei irgendeinem Tutorial etwas unklar sein, schreib es in die Kommentare oder mir per Mail. Ich versuche so schnell es geht zu antworten.

      LG Felix

  3. Erik sagt:

    Hallo,

    ich habe das Problem, dass der Chip im Pi nur ganz kurz sichtbar ist. Wenn ich versuche zu schreiben kommt nur Error: Write failed
    wenn ich im 0,5s Takt den Befehl sudo i2cdetect -y 1 ausführe wird nur in 10s einmal die 20 in der „Tabelle“ angezeigt, ansonsten wieder nur die — .
    Ich habe schon überprüft, ob nicht ein Kurzschluss oder manche Pins ausversehen verbunden werden, aber das ist nicht der Fall. Habe auch den Chip ausgewechselt, jedoch bleibt das Problem bestehen
    Was mache ich hier falsch? :/

    • Felix sagt:

      Wenn du den IC schon gewechselst hast, kann man einen Defekt davon ausschließen. Es muss also entweder an der Verkabelung oder am Pi.
      Du könntest z.B. nochmal ein sauberes Image probieren, vielleicht hast du etwas installiert, was Konflikte verursacht.

  4. bjarne sagt:

    hallo,
    bei mi funktioniert es nicht. Er zeigt mir keinen angeschlossen IC an in der Tabelle.
    habe alles genauso wie gesagt gemacht.
    bitte um Hilfe^^

  5. Holger sagt:

    Moin moin, also ich muss die ganzen Tutorials hier auch mal loben und den Verfasser. Ich vermute mal das Felix derjenige ist der hier immer schnellstmöglich alle Fragen beantwortet und die Tuts einstellt. Vielen Dank dafür.
    Ich hätte allerdings auch mal wieder eine Frage zu der Schaltung. Wie kann ich einen einzelnen PIN wieder auf 0 setzen? Mit 0x20 0x15 0x08 kann ich PIN 4 direkt auf 1 setzen, aber wie kann ich den jetzt wieder 0 setzen ohne die anderen PINs der Bank anzusprechen? Mit 0x20 0x15 0x00 werden ja alle pins auf 0 gesetzt.
    Gruß
    Holger

    • Felix sagt:

      Hallo Holger,
      vielen Dank für die lieben Worte 🙂
      Es gibt zwei Möglichkeiten: Entweder du schreibst eine Funktion, der du einen Pin und den Zustand angibst, allerdings diese deren Zustände vorher ausließt (falls Output) und entsprechend wieder setzt. Dann änderst du nur den Wert des Pins, der angegeben wurde und setzt die ganze Reihe.
      Der „einfachere“ Weg ist eine Bibliothek zu nehmen, wie z.B. diese hier: https://github.com/adafruit/Adafruit-MCP23017-Arduino-Library
      Ich vermute, dass die dortigen Funktionen ebenfalls alle Ports gleichzeitig ansprechen, aber eben die Werte vorher auslesen.

      mcp = Adafruit_MCP23017(busnum = 1, address = 0x20, num_gpios = 16)
      mcp.config(0, mcp.OUTPUT)
      mcp.config(1, mcp.OUTPUT)
      mcp.config(2, mcp.OUTPUT)
      mcp.output(0, 1)  # Pin 0 High
    • Holger sagt:

      Hi Felix, danke für den Tip. Ich denke ich werde es selbst auslesen und dann neu schreiben. Habe ich gerade schon einmal versucht und hatte die Befürchtung, dass es bei den Pins wo es keine Änderung gibt, eine kurze Unterbrechung gibt. Augenscheinlich ist dies aber nicht so. Gemessen habe ich es allerdings noch nicht 😀
      Gruß
      Holger

  6. Manuel sagt:

    Hallo,

    ich habe da auch ein Problem. Und zwar lief bis gestern noch alles reibungslos. Nun habe ich heute 2 weitere Boards angeschlossen und seit dem kann ich keinen i2c Port mehr schalten. Er lässt sich zwar über Putty schalten aber das Relay Board reagiert nicht. Hast du eine Idee woran es liegen könnte?

    Das ist der Code mit dem ich es vorhin nochmal versucht habe:
    i2cset -y 1 0x20 0x12 0xFF
    Er soll alle Port A Pins des ersten Boards einschalten.

    Hoffe du kannst mir helfen.
    Ansonsten ein sehr gutes Tutorial 😉 Alles sehr gut erklärt !!! TOP-Arbeit!
    Danke für deine Hilfe und das Tutorial.

  7. Sebastian sagt:

    HI! Danke für das Tutorial! Wenn ich das jetzt richtig verstehe müsste ich wenn ich diese Art von Pin Erweiterung benutze auf Dauer alles auf Platinen löten, richtig? Kennst du evtl. noch andere Möglichkeiten die vll. ähnlich klein sind aber ohne Löten auskommen?
    Viele Grüße, Sebastian

  8. swen sagt:

    hallo wenn ich das ganze probiere mit
    sudo i2cdetect -y 1
    bekomme ich eine fehlermeldung:
    Error: No i2c-bus specified!
    Usage: i2cdetect [-y] [-a] [-q|-r] I2CBUS [FIRST LAST]
    i2cdetect -F I2CBUS
    i2cdetect -l
    I2CBUS is an integer or an I2C bus name
    If provided, FIRST and LAST limit the probing range.

    was mache ich nur falsch? hbe alles schritt für schrit so gemacht 🙁

  9. Jonas sagt:

    Also bei mir scheint das i2cdetect nicht zu funktionieren. Die Ausgabe mit -y 1 bzw. 2,3 ist „error Could not open file. … no such file or directory „

    • Felix sagt:

      Welches Raspberry Pi Modell hast du und wofür soll 2,3 stehen? Klingt sehr danach, dass die Installation nicht (vollständig) geklappt hat.

  10. chris sagt:

    Ich habe auch diese meldung. habe den pi2

    habe aber eig alles befolgt was hier steht, wie kann ich den Fehler finden?

    Error: No i2c-bus specified!
    Usage: i2cdetect [-y] [-a] [-q|-r] I2CBUS [FIRST LAST]
    i2cdetect -F I2CBUS
    i2cdetect -l
    I2CBUS is an integer or an I2C bus name
    If provided, FIRST and LAST limit the probing range.

  11. chris sagt:

    ich habe „sudo i2cdetect -y0“ sowie mit „-y1“ getestet.
    meine blacklist ist komplett leer, keine einträge.
    i2c tools auf auf neuster version.
    python-smbus auf neuster version.
    die datei /etc/modules hat in den letzten beiden zeilen den diese befehle „i2c-bcm2708
    i2c-dev“

  12. chris sagt:

    unter lsmod
    ist i2c_dev sowie i2c_bcm2708 geladen.
    spi_bcm2708 ist nicht geladen, aner benötige ich auch nicht oder

  13. SgtIgram sagt:

    howdy-ho
    das tutorial ist jetzt zwar schon ein wenig älter.. aber obwohl ich es haarklein befolgt habe und sogar exakt den selben expander-chip verwende, habe ich nur probleme..

    auffällig hierbei ist folgendes:
    – beim i2cdetect tauchen „UU“s auf.. nach recherchen handelt es sich hier um reservierte adressbereiche die allerdings nicht mit dem 0x20 kollidiern..
    – durchschnittlich jedes dritte mal beim verwenden eines der i2c befehle, gibts probleme.. soll heißen.. beim i2c detect wird der 0x20’er nichtmehr gefunden.. oder beim setzen der pins, oder setzen als input/output wird nen error beim write rausgehaun

    – hin und wieder wirkt es auch so beim setzen der pins.. als wäre dort ein kurzer.. sowohl die powerLED am PI als auch eine kontroll LED die ich angebracht habe, ist für den bruchteil einer sekunde aus.. allerdings für so kurze zeit das das board normal weiterläuft und alles..

    – voller zuversicht hatte ich natürlich direkt 2 chips verkabelt.. die adresse war(wenn es mal angezeigt wurd) 0x22.. wenn ich raten müsste würde ich sagen das 0x21 der erste ist.. und 0x22 der zweite.. während 0x20 vlt. sogar beide gleichzeitig anspricht??

    da ich echt am verzweifeln bin(da es bei etlichen anderen leuten scheinbar problemlos funktioniert) und mir nicht ein chip nach dem andern(oder das PI selbst) zerschießen will.. brauch ich also echt unterstützung und wäre extrem dankbar..

    • Felix sagt:

      Hey,
      kannst du einen Wackelkontakt ausschließen? Das Problem sagt mir in der Form leider nichts, ich selbst hatte es noch nicht und bisher wohl auch keiner der das Tutorial befolgt hat.
      Die Adresse (0x20) gibst du – wie im Tutorial beschrieben – mit den drei A0-A2 Kontakten an. Möchtest du einen Chip mit der Adresse 0x22 ansprechen, so muss A0 und A2 an GND aber A1 an 3.3V.
      Ich würde dir wirklich gerne besser helfen, aber das klingt sehr merkwürdig. Klappen denn andere I2C Anwendungen bei dir (gibt einige Tutorials hier mit I2C)?

    • SgtIgram sagt:

      das mit der pin adressierung hab ich soweit schon verstanden.. und der 0x22 wurd ja auch angezeigt als ich , wie beschrieben , voller zuversicht direkt zwei chips angestöpselt habe..

      wackelkontakt kann ich ziemlich gut ausschließen.. zudem ich das problem(mit dem das er mal angezeigt wird und mal nicht) auch habe wenn ich definitiv außer reichweite bin um an dem raspi irgendwas zu bewegen..

      ich würde das ganze gerne mit fotos mit dir abgleichen.. in skype/steam heiß ich ebenfalls „sgtigram“.. ansonsten kannst du mich gern mal unter der hinterlegten email anschreiben

      grüße
      – sgtigram

  14. Tim sagt:

    Erstmal muss ich sagen dass das Tutorial großartig ist allerdings verstehe ich nicht wie ich 4 Expander anschließen kann. Könntest du oder wer anderes mir das nochmal erklären? Eventuell mit einem Bild der Schaltung?

    • Felix sagt:

      Du hast doch die Pins A0, A1 und A2. Jeder dieser Pins kann entweder Zustand AN oder Zustand AUS haben (=ein Bit). Wir haben also 2^3 = 8 Möglichkeiten eine Nummer zu vergeben, sprich du kannst bis zu 8 Expandern eine eindeutige Nummer zuweisen.
      Schau dir am besten mal das Binärsystem genauer an.

    • Tim sagt:

      Okay, das habe ich verstanden aber der Pi hat ja nur 2 I2C Anschlüsse, dann ist es doch nicht möglich 4 Expander anzuschließen. Sorry, wenn ich das nicht verstehe aber ich kenne mich damit nicht wirklich aus…

  15. Michael sagt:

    Der I2C ist ein Bussystem. Alle Expander hören also immer zu, reagieren aber nur auf ihre Adresse. D.h., dass alle Expander quasi parallel angeschlossen werden.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

Blog abonnieren

Abonniere Tutorials-RaspberryPi, um kein Tutorial mehr zu verpassen!