Kommunikation im Bus

Der praktischen  Verwendung im Nachbau des Projekts zur Anzeige von Text und Zeit auf dem LC-Display und dessen Einbindung mittels I²C-Schnittstellenmodul sowie der Einbindung des Uhrenmoduls auf den gleichen 2 Drähten (plus Spannung und Masse) schließt sich die Frage nach dem „Warum“, des „Wie“ und möglicher Probleme und Erweiterungen an.

Ganz hervorragend für Beginnende auf deutscher Sprache erklärt, findet man ein Video plus Texterklärungen auf dieser Webseite: http://fmh-studios.de/theorie/informationstechnik/i2c-bus/

https://www.youtube.com/watch?v=pSmLAPod5oY

Wie der eigenen praktischen Ansschauung zu entnehmen war, besitzt der I²C-Bus vier Leitungen, wobei zwei Leitungen für den Transport der Daten vorgesehen sind. Die beiden für die Datenkommunikation verantwortlichen Leitungen werden SDA (Serial Data Line) und SCL (Serial Clock Line) genannt. Während das Potenzial der Masseleitung (GND) eindeutig ist und in Bezug auf die teilnehmenden Systeme deren Null-Potenzial sein sollte, stellt sich die Sache bei Versorgungsspannung und Maximalspannung (Pegel) von SDA und SCL nicht so eindeutig dar. In der Arduino-Familie gibt es Mitglieder (Boards), die mit 5 V Versorgungsspannung laufen, während andere mit 3,3 V versorgt werden. Der ESP32 läuft auf 3,3 V während man es den Peripheriebauteilen (Display, Sensoren, Aktoren) oft nicht unmittelbar ansieht. Anforderungen an den I²C-Bus formuliert beispielsweise die folgende Webseite: https://de.i2c-bus.org/intro/anforderungen/ . Dort liest man, dass bei einer Versorgung mit 5 V ein Pegel von 1,1 V als LOW interpretiert wird. An einem Bus der mit 1,2 V betrieben wird, wäre der gleiche Pegel ein HIGH. Als HIGH werden Pegel erkannt die mindestens das 0,7fache der Versorgungsspannung betragen. Ein LOW-Pegel hat maximal das 0,3fache der Versorgungsspannung. Diese offene Konstruktion führt zu Schäden, wenn eine Partner mit einer höheren Spannung betrieben wird als die anderen. Sie lässt keine Kommunikation zu, wenn der steuernde Busteilnehmer mit wesentlich geringerer Spannung betrieben wird, als die von ihm zu steuernden Teilnehmenden. Zur Lösung des Problems werden an anderer Stelle Loogikpegel-Konverter vorgestellt.

Kommunikation ist eine Frage des Taktes

Als die Firma Philips den I²C-Bus zu Beginn der 80er des letzten Jahrhunderts entwickelte war das Ziel die Kommunikation zwischen ICs in der Unterhaltungselektronik. Der Bus arbeitete bidirektional mit einer Geschwindigkeit von 100kbit/s. In der Ausgangsversion verwendet er 8Bit-Adressen. In Schritten und neuen Versionen der Definitionen des I²C-Busses stieg die Geschwindigkeit über 400 kbit/s bis auf 3,4 Mbit/s. In der Version 1 des I²C-Bus sind 112 mögliche Teilnehmende vorgesehen (z. B. 1 Master und 111 Slaves, 16 Adressen sind fest reserviert). Aktuelle I²C-Implementierungen arbeiten 10 Bit. Zur Gewährleistung der Abwärtskompatibilität bleibt die Zahl möglicher Teilnehmender auf „nur“ 1136 begrenzt. Es ist der Master-Knoten, der den Takt und damit auch die Kommunikation vorgibt.

Kommunikation ist eine Frage der Distanz

I²C-Buskonstruktionen von mehr als 150 m Länge werden / wurden erfolgreich betrieben https://www.mikrocontroller.net/topic/63357 und https://www.mikrocontroller.net/topic/260958 . Gedacht war der Bus jedoch für die kurze Strecke. Probleme entstehen dabei nicht allein durch die Leitungswiderstände, das „Übersprechen“ der Leitungen ist ein ein Problem https://de.i2c-bus.org/intro/terminierung-und-kapazitaeten/. Leitungswiderstände (die Summe aller ohmschen Widerstände zwischen den Knotenpunkten) und die kapazitive Kopplung der Leitungen (dicht nebeneinander liegende Leitungen), die voneinander elektrisch isoliert sind und unterschiedliche Pozenziale besitzen bilden ein RC-Glied mit entsprechender Zeitkonstante. Dies schlägt sich deutlich auf den Signalverlauf nieder (siehe obiger Link). Die Anforderungen an den I²C-Bus sehen deshalb eine maximale Kapazität von 400 pF vor.

Kommunikation braucht eindeutiges Verstehen und den richtigen Abschluss

Durch die Belege der Leitungen mit Widerstand und Kapazität ist ein gewisser Potenzialverlust unvermeidlich, dem mit größeren Querschnitten der Leitungen begrenzt zu begegnen ist. Terminierung und Kapazitäten erläutert das Unvermeidliche, deshalb sind Leitungslängen auf das mögliche Minimum zu verkürzen. Andererseits kann eine Veringerung der Taktrate (Kommunikationsgeschwindigkeit) ebenfalls für eine Verbesserung der Situation sorgen, denn die Leitungen verhalten sich wie ein elektronischer Tiefpass.

Sowohl die Leitung SDA als auch die SCL -Leitung werden über einen Widerstand (oft 4,7 kOhm) mit der Versorgungsspannung verbunden (Pull-Up-Widerstände RP / I²C-Terminierung). Dadurch erreichen die genannten im Ruhezustand immer das Versorgungspannungspotenzial. Sie werden somit Übertragung eines LOW-Pegel aktiv auf das Null-Potenzial gezogen. Je kleiner der Widerstand zwischen SDA oder SCL und der Versorgungsspannungsleitung ist, desto stärker belastet dies den Ausgang der Pins für SDA und SCL am Master.

I2C.svg
Von <a href=“https://en.wikipedia.org/wiki/user:Cburnett“ class=“extiw“ title=“en:user:Cburnett“>en:user:Cburnett</a> – Own work made with Inkscape, CC BY-SA 3.0, Link

Die Abbildung zeigt die Masseleitung (GND) nicht. Die Höhe des erforderlichen Pull-Up-Widerstands richtet sich laut Spezifikationen des User-Manual UM10204 von NXP nach den koppelnden Kapazitäten der Leitungen sowie den Leitungswiderständen. Ein Problem kann dann entstehen, wenn einige Teilnehmer des Busses über jeweils eigene, festverbaute Pull-Up-Widerstände verfügen. Dann reduziert sich der Pull-Up-Widerstand im Bus durch die jeweils parallelen Widerständen. Der verbleibende Gesamtwiderstand sollte größer als 1,7 kOhm sein. Ist er geringen kann es zu Spannungsteilereffekten kommen und die verfügbaren Kommunikationsspannungen genügen den Spezifikationen des I²C-Bus nicht mehr.

I²C-Kommunikation mit der Arduino-IDE

Die zuvor beschriebenen Elemente der Hardwareseite und der elektronischen Seite der I²C-Kommunikation kapselt eine Softwarebibliothek in einer Weise, dass dem Designer / Nutzer der Bibliothek Fragen nach einer geeigneten Terminierungs / Pull-Up-Widerstände, nach Start- und Stop-Bedingungen usw. erst interessieren, wenn die Kommunikation nicht funktionieren will. Das ist zum Glück eher selten.

Die I²C-Bibliothek heißt „wire“-Library und ist immer in ein Programm einzubinden, wenn von der Komminikation über diesen Bus Gebrauch gemacht werden soll. Die Referenz zu dieser Bibliothek findet sich hier: https://www.arduino.cc/reference/en/libraries/i2commands/

Während die Funktionen der Library für alle von der Arduino-IDE gleich sind, verwenden die jeweiligen Boards oft unterschiedliche Pins an denen SDA und SCL herausgeführt werden. Bei Arduino UNO und Arduino NANO sind dies die Pins A4 für SDA und A5 für SCL. Beim ESP32 heißen die Pins GPIO22 für SCL und GPIO21 für SDA. So wie das LCD1602 mit I²C-Schnittstelle mit den Arduino UNO betrieben werden konnte, kann dies auch am ESP32 geschehen, wie diese Webseite zeigt.

I²C-Kommunikation zwischen 2 und mehr Arduinos

Unterschiedliche Beispiele zur Kommunikation von Arduinos untereinander bei Verwendung der I²C-Kommunikation. Details zur wire-Library, den Funktionen und deren Verwendung finden sich in der Detail-Referenz des Arduino-Playground: https://playground.arduino.cc/Main/WireLibraryDetailedReference/

A) http://www.sachsendreier.com/asw/projekteundexperimente/i2c/i2c.php

B) https://starthardware.org/mehrere-arduinos-verbinden-so-klappt-es/

C) https://www.instructables.com/Arduino-I2C-and-Multiple-Slaves/

D) https://www.electronicshub.org/arduino-i2c-tutorial/

Die Links A) und B) erläutern die Verwendung I²C-Kommunikation zwischen 2 Arduino UNO in deutscher Sprache sehr anschaulich. Warum kommen die Quellcodes in A) ohne Code in „loop()“ aus? Der Code des Slave in Beispiel B) benötigt ebenfalls keine Funktion in „loop()“.

Das Beispiel in Link B) verwendet Pull-Up-Widerstände, die in dieser Form praktisch nicht aufgebaut werden können.  Link C) zeigt, wie man über ein Steckbrett mehrere Arduino UNO verketten kann. Die Stromversorgung sollte dann ausschließlich vom Master aus erfolgen und die Höhe der angeschlossenen Gesamtlast muss begrenzt bleiben.

Link D) zeigt die bidirektionale Übertragung von Daten. Das Potenziometer ist ein Spannungsteiler, dessen Mittelabgriff ein Potenzial ergibt das auf Master und Slave jeweils mittels Analog-Eingang A0 gelesen und als Zahl übertragen wird. Die Darstellung der abgegriffenen Spannung erfolgt für das vom Slave gemessene Potenzial über die Helligkeit einer am PWM-Pin angeschlossenen LED auf dem Master. Umgekehrt zeigt die Helligkeit der LED auf dem Slave das im Mater gemessene Potenzial an. Daten können demnach in beide Richtungen übertragen werden.

Ergänzung

So schön und bequem sich ereignisorientierte Programmierung auch realisieren lässt, sie hat doch einige Haken und Ösen (Regeln), die zu beachten sind. Die mit onReceive() und onRequest() verbundenen Funktionen

  1. sind außerhalb von loop() zu formulieren.
  2. sollten möglichst kurz gehalten sein, keine lang andauernden Sequenzen enthalten
  3. auf delay() verzichten und am besten mit Flags arbeiten auf die innerhalb von loop() reagiert wird.
  4. Datenübertragungen jeweils < 32 Byte begrenzen

Mehrfach-Terminierungen von SDA und SCL durch möglicherweise in fertigen Baugruppen oder Bauteilen enthaltene Pullup-Widerstande sind so zu berücksichtigen, dass der Pullup-Widerstand in der Summe nicht durch Parallelschaltung der Widerstände zu gering wird (<1,7 kOhm). Ein hoher Pullup-Widerstand (>10kOhm) andererseits kann zu Problemen bei hohen Kommunikationsgeschwindigkeiten führen.

Unterschiedliche Arbeitsspannungen von Baugruppen (Mikrocontroller, Aktoren, Sensoren) sind unbedingt geeignet einzuplanen und ggf. mit Logikpegel-Konvertern hardwareseitig auszuräumen.

Erläuterungen gibt und weitere Probleme und deren Lösungen finden beschreibt die Webseite „Einführung in de I²C-Bus.“