Kampis Elektroecke

I2C

Raspberry Pi

Hier zeige ich, wie der I2C Bus des Raspberry Pi genutzt werden kann. Der Raspberry Pi nutzt 3,3 V Pegel und deswegen dürften NIEMALS 5 V Signalen auf das Board gegeben werden, da es ansonsten zu Schäden am Prozessor kommen kann.

I2C aktivieren:

Als aller erstes muss der I2C vom Raspberry Pi aktiviert werden. Dies geschieht durch folgende Zeilen:

$ sudo modprobe i2c-bcm2708 baudrate="WERT
$ sudo modprobe i2c-dev
$ sudo apt-get install i2c-tools

Die Zeilen

$ sudo modprobe i2c-bcm2708 baudrate="WERT
$ sudo modprobe i2c-dev

laden die für den I2C notwendigen Module und stellen den Takt vom I2C auf den Wert Wert ein (Default ist 100 kHz).

Die durchgeführten Befehle müssen bei jedem Neustart neu ausgeführt werden und deswegen ist es empfehlenswert diese Befehle in die Datei /etc/rc.local zu schreiben. Mit der Zeile

$ sudo apt-get install i2c-tools

werden die notwendigen Tools installiert um auf den I2C zugreifen zu können. Anschließend kann mittels

$ sudo i2cdetect -y 0

geprüft werden ob der I2C funktioniert. 

I2Cdetect

Dadurch zeigt euch das Raspberry Pi die Adressverteilung der Devices am Bus an. Bei mir ist z. B. ein Device mit der Adresse 0x20 angeschlossen (ein PCF8574).

I2C per Konsole verwenden:

Wenn ein Device am Bus erkannt wurde, kann mit den beiden Befehlen

$ sudo i2cget
$ sudo i2cset

per I2C Bus auf das Device zugreifen werden. Wenn von dem Device gelesen werden soll, muss der Befehl i2cget verwenden und falls geschrieben werden soll i2cset verwendet werden. Ein vollständiger Befehl zum Lesen sieht z. B. folgendermaßen aus:

$ sudo i2cget -y 0 0x20

Mittels i2cget -y soll von einem I2C Device gelesen werden, wobei die 0 der I2C Bus ist, der für den Zugriff verwendet werden soll (das Raspberry Pi hat auch noch einen anderen I2C Bus, aber der Bus der auf den 26-pol Connector rausgeführt ist ist der Bus 0). Der Wert 0x20 ist die Adresse von dem I2C-Device auf das Zugegriffen werden soll. Als Rückgabewert erhält man dann auf der Konsole das gesendete Byte vom I2C-Device.

Wenn nun in das Device geschrieben werden soll, so sieht der Befehl folgendermaßen aus:

$ sudo i2cset -y 0 0x20 0x00

Mit i2cset -y wird ein Schreibzyklus eingeleitet, wobei die 0 ist wieder der zu verwendende Bus ist und die 0x20 ist die Deviceadresse, gefolgt von einer 0x00, welche das zu sendende Datenbyte darstellt.

Auslesen eines EEPROMs:

Dieses Vorgehen soll Beispielhaft an einem EEPROM (24C128) gezeigt werden:

$ i2cset -y 0x50 0x00 0x00 0x10 i
$ i2cset -y 0x50 0x00 0x00
$ i2cget -y 0x50

Die erste Zeile spricht das EEPROM mit einem Schreibbefehl an und überträgt alle Adressen und Daten, die daraufhin in das EEPROM geschrieben werden. Dabei stellt der Wert 0x50 ist die Adresse des EEPROMs dar, die zwei 0x00 sind die beiden Datenbytes für den Adresspointer im EEPROM und die 0x10 sind die Daten die in das EEPROM geschrieben werden sollen.

Der Parameter i gibt an, dass es sich bei dem gesendeten Werten um Integer handelt, also die Adresse und die Daten aus je zwei Bytes bestehen.. Es muss bei Übertragungen von 4 Bytes oder mehr hinzugefügt werden. Da der Pointer im EEPROM nach jedem Schreibbefehl um eins inkrementiert wird, muss dieser jetzt erst wieder auf 0x00 gesetzt werden, bevor die Zelle gelesen werden kann.

$ i2cset -y 0x50 0x00 0x00

Auch hier ist die 0x50 wieder die Deviceadresse vom EEPROM und die zwei 0x00 sind die Adresse für den Pointer.
Anschließend kann die Zelle mit dem Befehl

$ i2cget -y 0x50

ausgelesen werden. Die Konsole gibt nun den Wert 0x10 aus.

Nachfolgend noch ein paar Beispielanwendungen mit dem I2C.

→ Eine DS1307 als Uhr verwenden
→ Externer ADC & CapSense
Servo ansteuern mittels PCA9685

Sämtliche Codebeispiele stehen in meinem Raspberry Pi Repository zum Download bereit.

44 Kommentare

  1. Hi,
    ne schöne Seite haste da gebastelt. Du schreibst, man soll nie mit 5V-Pegeln auf den Bus der Himbeere gehen, speziell der DS1307 arbeitet aber nur mit 5V Betriebsspannung. Wie hast Du die I2C-Pegel angepasst, um die Himbeere nicht in den Siliziumhimmel zu schicken?

    Gruß
    Kurt

    1. Hallo Kurt,

      I²C funktioniert mittels Open-Collector Eingänge. Sprich der Bus führt keine eigenen Pegel und deswegen werden die Pull-Ups benötigt.
      Die DS1307 wird mit einer Spannung von 5V betrieben aber der I²C vom Raspberry Pi wird mittels Pull-Ups, die sich auf dem Board befinden, auf 3,3V gezogen. Dadurch führt der Bus 3,3V Pegel. Die DS1307 kann diese Pegel lesen (glaube 2V ist Minimum bei der). Deswegen kann ich die RTC an den Pi anschließen. Ich missbrauche die Pull-Up Widerstände quasi als Pegelwandler.

      Gruß
      Daniel

  2. Ok, I2C läuft :). Allerdings ist bei den neuen Himbeeren mit 512MB der zweite I2C-Bus auf die Pin-Leiste verdrahtet.
    Die Ansteuerung ändert sich daher geringfügig, statt
    „i2cget -y 0 0x20“ muß man den Bus 1 wählen, also „i2cget -y 1 0x20“.

    In Programmen sollte man also irgendwie ermitteln, welcher Bus aktiv ist.

    Gruß
    Kurt

    1. Super das es funktioniert :)
      Wie man das ermittelt weiß ich leider nicht (ich wusste auch nicht mal das bei der 512 MB Variante ein anderer Bus verwendet wird :D)
      Aber in so einem Fall muss man einfach mal gucken welcher I²C verdrahtet worden ist.
      Danke auf jeden Fall für die Anmerkung!

    2. Hallo Kurt,

      ich habe nun auch eine 512MB Version vom Raspberry erhalten.
      Du kannst über /proc/cpuinfo die Daten zu dem Pi auslesen und alles was über Revision 2 ist, hat I2C-1.
      Für C-Programme o.ä. kannst du ja einfach testweise den Bus öffnen und gucken ob du ihn a) öffnen und b) auch was dadrüber verschicken kannst.
      Wenn es nicht geht probierst du einen anderen Bus aus.
      Alternativ kannst du auch den Ordner /dev durchsuchen, welcher I2C dort vorhanden ist.
      Es gibt einige Möglichkeiten es herauszufinden.
      Ist nur mit etwas Arbeit verbunden ;)

    3. Beim Rev.2-Board ist der „1er“-Bus auf dem (großen) P1-Stecker (26-polig) und laut http://elinux.org/RPi_Low-level_peripherals ist eine 2. I²C-Gruppe („0-er“-Bus) auf dem P5-Stecker.

      Dies wäre eine bessere Möglichkeit – somit lässt man eher P1 frei für andere Zwecke ohne die vielen durch den P1-Stecker verdeckt und ungenutzten GPIO’s.

      Ansonsten, vielen Dank, habe jetzt 2×16-Ports extra über MCP23017 für wenig Geld

      1. Hey,

        ja genau. Ich glaube im Artikel habe ich das nicht erwähnt, weil es sich in erster Linie nur um den 26-pol Stecker handelt.
        Aber dank dir für den Hinweis :)

        Gruß
        Daniel

  3. Hi Kami,

    super Tutorials haste hier zusammengestellt. Ich habe noch eine Verständnisfrage bzw. konnte dazu nichts im Netz bisher finden. Ist es möglich 1wire und I²C-Devices gleichzeitig mit dem Pi anzusprechen, bzw welche Pins sind hierfür bei der 256mb Version maßgeblich?

    Vielen Dank & Grüße
    Marc

    1. Hallo Marc,

      ich wüsste jetzt nicht warum das nicht gehen sollte. Für I²C werden die GPIO0 und 1 verwendet und für 1Wire sollte irgendein GPIO verwendet werden können (ist ja soweit ich weiß nur ein Übertragungsprotokoll).
      Oder was genau meinst du?

      Gruß
      Daniel

      1. Hi Daniel,
        danke für die rasche Antwort. Du hast recht die Schnittstelle für das 1wire-Protokoll ist so wie ich das verstanden habe frei wählbar, bei quellcodeanpassung standardmäßig auf gpio4.

        Gruß
        Marc

        1. Hey Marc,

          ich wollte jetzt mal selber bisl mit 1Wire experimentieren aber irgendwie läuft
          mein Pi nicht mehr…..keine Ahnung woran es liegt ^.^
          Aber wenn ich weiß wie das mit dem 1Wire funktioniert schreibe ich es dir und
          auf die HP :)

          Gruß
          Daniel

    1. Hey,

      ja es sollte prinzipiell möglich sein I²C über eine Website zu steuern.
      Ich würde aber eher ein Programm z.B. zum Auslesen eines EEPROMs schreiben und dieses Programm mittels Website aufrufen.
      Die Ausgabe kannst du dann in PHP anzeigen lassen.

      Gruß
      Daniel

    1. Hey,

      nein das geht nicht, weil du den Text und die Initialisierung seriell, sprich nacheinander schicken musst.
      D.h. du musst die Initialisierung händisch machen und anschließend händisch jeden Buchstaben senden und ob das geht weiß ich nicht.

      Gruß
      Daniel

      1. ich hab ein wenig rumgespielt aber viel mehr als die Hintergrundbeleuchtung ein und wieder auszuschalten hab ich nicht hinbekommen. Nun benutze ich LCDproc… das läuft richtig gut!!

        ! ! ! Vielen Dank für die Antwort ! ! !

  4. Ist es nicht auch möglich den I2C-Bus über eine website zu steuern?
    Hättest du da evl. Lösungsansätze??

    mfg Tobias
    Ps. Super tutorials haben mir echt geholfen^^

    1. Hey,

      theoretisch sollte es gehen.
      Gemacht habe ich es bisher noch nicht selber (mal schauen vielleicht kommt es mal :) ).
      Von daher habe ich noch keinen konkreten Ansatz.

      Gruß
      Daniel

  5. Falls es jemanden interessiert. Man kann mit modprobe i2c-bcm2708 Baudrate="WERT" z.B. 10000 den Standardwert von 100kHz überschreiben, um beispielsweise eine stabilere Übertragung bei einem längeren Bus zu erreichen.

    Gruß
    Daniel

  6. Hey

    erstmal echt tolle Seite.

    Ich habe nur leider ein Problem und zwar es klappt alles so weit nur ich habe Probleme die richtige Adressen zu finden. Ich bin zu blöd um die Erklärung aus dem Daten Blatt zu verstehen und den anderen Beiträgen im Internet. Könntest du mir vielleicht eine kleine list gegeben wo drine steht 0x43 Heist Ausgang 1 schreiben. Oder wenn das zu viel ist ich möchte erst mal zum testen 2 relais ansteuern die liegen an dem Pin 4, 5 laut Datenblatt Ausgang P0, P1 und habe an dem P2 (pin 6) einen Taster den ich gerne auslesen möchte. Wäre supa wenn mir da jemand helfen könnte.

    Danke

  7. Hi! Ich komm hier nicht weiter: ich habe zwei Sensoren auf 0x0e und 0x1d. Bei verwendung von i2cget -y 1 0x0e bzw. i2cget -y 1 0x1d bekomme ich in beiden fällen 0x00. Kann das stimmen? Ich befürchte, dass ich deshalb die Verbindung zu Matlab nicht herstellen kann. Der dritte Sensor gibt einen Zahlenwert aus und dort klappt die Verbindung. Welches Register wird ausgelesn wenn man keine weitere Adresse angibt?

    Vielen Dank!

    1. Hey,

      ich nehme an, dass du mittels i2cdetect schon überprüft hast ob die Verbindungen da sind.
      Du musst als erstes mit i2cset die Registeradresse schreiben:

      i2cset -y 1 Adresse Registeradresse

      Erst danach kannst du das Register auslesen.

      Gruß
      Daniel

    1. Hallo Peter,

      meinst du mit SD-Karte oder ohne?
      Im Grunde kannst du dir eine fertige SD-Karte kaufen. Das spart etwas Arbeit und eine SD-Karte brauchst du so oder so ;)

      Gruß
      Daniel

  8. Hallo Daniel,

    von der alten C-Control habe ich noch ein Touchdisplay eDIP240-7 übrig, und das wollte ich jetzt mit dem Raspi über I2C ansprechen. Es hat unter C-Control mit I2C-Anbindung funktioniert. Es gelingt mir allerdings nicht es zum laufen zu bringen. Lesen kann ich, aber nicht schreiben. Bekomme immer Input/output Error. Die Anleitungen in Deinem Buch bringen mich leider nicht weiter.

    Gruß Lush

  9. Hallo Daniel,

    weist du zufällig wie viele Portexpander man maximal an den Pi anschließen kann?
    Würde ca 132 Ports benötigen. Ist das mit diesen Chips rauszuholen?

    Gruß Gerald

    1. Hallo Gerald,

      der Portexpander hat drei Adresspins, d.h. du kannst 8 (2^3) verschiedene Portexpander an einem Bus anschließen.

      Gruß
      Daniel

      1. Hallo Daniel,

        und genau da liegt mein Problem wenn ich 8 Portexpander anschließen kann komme ich bei 16 Ports pro Chip auf 128 Ports. Mein Problem ist nur das ich 4 Ports mehr benötigen würde. Gib`s die evtl auch mit mehr Ports am Chip? Habe bisher leider noch keine mit mehr als 16 Ports gefunden.

        Gruß Gerald

  10. Hallo zusammen,
    habe da ein kleines „Verständigungsproblem“, wenn ich über sudo i2cdetect -y 1, zeigt es mir folgendes an:
    sudo i2cdetect -y 1
    0 1 2 3 4 5 6 7 8 9 a b c d e f
    00: — — — — — — — — — — — — —
    10: — — — — — — — — — — — — — — — —
    20: — — — — — — — — — — — — — — — —
    30: — — — — — — — — — — — — — — — —
    40: 40 — — — — — — — — — — — — — — —
    50: — — — — — — — — — — — — — — — —
    60: 60 — — — — — — — — — — — — — — —
    70: — — — — — — — —

    jedoch, wenn ich den Sensor ansprechen möchte:
    sudo i2cget -y 1 0x40

    Kommt mir nur dieser Error: Read failed.

    Meines Wissens, habe ich alles installiert was ich müsste, habt Ihr mir einen kleinen Typ.
    Merci schon mal, Gruss Urs

    1. Hallo Urs,

      um was für einen Sensor handelt es sich? Wird der Sensor vielleicht noch von was anderem (ein Programm etc.) ausgelesen?

      Gruß
      Daniel

Schreibe einen Kommentar

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