I2C-Scanner und Tester mit einer STM32 Bluepill
Die Grundlagen
Seit meinem ersten Kontakt mit dem I2C-Protokoll auf einem Raspberry Pi bin ich Fan davon.Eigentlich hat jeder Mikrocontroller heutzutage mindestens einen I2C-Bus. Außer mit Python auf dem Raspberry Pi kann man auf einen I2C-Bus auch auf dem Arduino, STM32, ESP8266, ESP32 und vielen anderen Mikrocontrollern zugreifen.
Auf dem Raspberry Pi gibt es noch die WiringPi-API für C und für die Arduino-kompatiblen Mikrocontrollern die Wire.h-Library, die einen bei der Programmierung des Zugriffs auf den Bus und die Geräte unterstützen. In den allermeisten Fällen gibt es sogar fertige Librarys für die einzelnen Geräte und man hat es noch einfacher bei der Programmierung.
Es ist so praktisch, mit nur zwei zusätzlichen Leitungen neben Masse und Spannungsversorgung die verschiedensten Geräte ansprechen zu können, die dann auch noch alle am selben Bus hängen dürfen und mit allen quasi gleichzeitig "sprechen" zu können.
Wenn mehrere Geräte an einer Leitung hängen, dann muss man sie irgendwie unterscheiden können. Dazu hat jedes I2C-Gerät eine feste (oder mit Jumpern änderbare) Adresse zwischen 8 und 127. Diese Adresse müssen wir kennen, um das Gerät ansprechen zu können. Dann schicken wir sozusagen ein Rundschreiben auf den I2C-Bus und das Gerät, dass sich unter der ausgerufenen Geräteadresse angesprochen fühlt, antwortet. Die anderen Geräten ignorieren die Meldungen, die nicht für sie bestimmt sind.
Nun stellt sich aber manchmal das Problem, dass man ein Modul oder Chip hat, dessen Adresse man nicht weiß. Vielleicht ist auch der Aufdruck auf dem Chip zu klein, um sicher erkennen zu können, um welches Modell es sich handelt.
Dann kann man den Trick anwenden, einfach alle Adresse auszurufen und zu schauen, ob jemand antwortet. Man muss dazu nur die Adressen bis 127 abklappern und bekommt so alle Adressen zurück, an denen funktionierende Geräte angeschlossen sind.
Auf dem Raspberry Pi gibt es dazu einen Satz Werkzeuge, die i2c-tools mit i2cdetect und i2cdump. Und eben i2cdetect macht genau dieses Scannen und gibt einem dann die angeschlossenen Geräteadressen zurück. Unter den entsprechenden Adressen kann man dann mittels i2cdump mit den jeweiligen Geräten kommunizieren.
Der Bedarf und die Idee
Unter Arduino und ESP8266 / ESP32 gibt es solche Tools nicht. Dies sind nämlich reine Mikrocontroller ohne Betriebssystem. Aber wir haben die Wire-Library, die uns die Programmierung erleichtert, so dass wir das I2C-Protokoll nicht selbst implementieren müssen. Und wir haben zwei hardwareseitig festgelegte Pins, die zusammen mit der Library für besonders schnellen Bustransfer bis zu 400 kHz sorgen. Oder wir benutzen eine "Softwire"-Library, die das I2C-Protokoll softwaremäßig abbildet und bei dem wir die Pins frei wählen können. Das ist dann in der Regel langsamer und rechenintensiver.Da wäre es doch schön, auch auf dem Arduino einen Scanner wie i2cdetect auf dem Raspberry Pi zu haben.
Mit dem könnte man dann unbekannte Bauteile identifizieren, indem man die I2C-Adresse notiert und zum Beispiel bei i2cdevices.org nachschlägt.
Und wäre es nicht fantastisch, wenn das zu entwickelnde Gerät - nennen wir es mal "I2C-Scanner und Tester" die gebräuchlichsten Komponenten selbst identifizieren würde? Und vielleicht sogar gleich testet?
Dann wäre das Durchtesten von neu gelieferten Komponenten beim Wareneingang, ob diese denn auch korrekt funktionieren, ein Kinderspiel. Kein Ärgern mehr darüber, dann das sich in der Schublade "gereifte" Bauteil beim ersten Einbau dann als defekt herausstellt, die Umtauschfrist aber schon lange abgelaufen ist.
Gedanken zur Umsetzung
Der richtige Mikrocontroller
Besonders praktisch wäre es natürlich, wenn man mit dem I2C-Scanner und Tester eine breite Palette von Komponenten testen könnte, egal, ob es sich dabei um 3.3 oder 5 Volt-Komponenten handelt.Da fällt mir dann auch gleich die STM32 Bluepill ein, die mit 3.3 läuft, aber 5V-tolerant ist. Wie das Pinout der STM32-Bluepill zeigt, gilt das auch für die I2C-Pins SCL1 an PB6 und SDA1 an PB7. Wenn wir also ein Gerät mit 5V auf dem I2C-Bus anschließen, nimmt unser STM32 keinen Schaden. Außerdem gibt es Pins mit 3.3 und 5V, die wir als Spannungsversorgung für die Komponenten weiterreichen können.
WLAN und Bluetooth brauchen wir eh nicht. Es soll ein kompaktes Gerät sein, dass einfach nur ein paar Dinge anzeigt, nämlich die gefundenen I2C-Adressen und das Testergebnis. Damit ist der STM32 vollkommen ausreichend. Auch verfügt die Bluepill über mehr als genügend Anschluss-Pins und genügend Speicher für ein größeres Programm, falls ein paar mehr Librarys für Komponenten eingebunden werden müssen.
Um mir die Arbeit bei der Entwicklung einfacher zu machen, verpasse ich der Bluepill den STM32dunio-Bootloader, damit ich über den USB-Anschluss serielle Debug-Mitteilungen lesen kann und das Hochladen von Code einfacher geht.
Das Display
Zur Anzeige soll uns ein einfaches 1602-Display reichen, dass ich direkt über vier Datenleitungen anschließen möchte, wie ich bereits einmal in diesem Artikel erklärt habe.Die I2C-Backbacks mit PCF8574 für LCDs sind zwar sehr praktisch, aber hier will ich darauf verzichten, damit ich nichts habe, was bereits eine I2C-Adresse belegt. Darum der direkte Anschluss des Displays.
Der Aufbau
Diesmal verzichte ich auf einen vorherigen Aufbau auf einem Breadboard, sondern benutze gleich Jumperkabel, um die Komponenten miteinander zu verbinden.Zu der Bluepill und dem Display gesellt sich noch ein Mini-Breadboard, auf dem dann die I2C-Module eingesteckt werden können, um sie zu testen. Dazu gibt es eine 3.3V und eine 5V Schiene. Außerdem gibt es einen Taster, der einen Reset ausführt, um Tests abzubrechen und neu zu starten.



Die Verkabelung stellt sich wie folgt dar:
STM32 1602 Display Mini-Breadboard Kabelfarbe
PA2 RS
PA3 EN
PA4 D4
PA5 D5
PA6 D6
PA7 D7
PB2 Reset-Taster weiß
PB6 (SCL) SCL grün
PB7 (SDA) SDA gelb
GND GND schwarz
GND K schwarz
GND -2KΩ- V0 schwarz
3V3 3.3V orange
5V -100Ω- A
5V 5V rot
Das Display lasse ich immer leuchten, sobald Strom fließt, habe es aber mit einem 100 Ohm-Widerstand zwischen der Kathode (K) und GND ein wenig gedimmt, damit es nicht ganz so hell ist und länger hält.
Software und Test
Die Software ist nicht sonderlich kompliziert und da sie sich fortlaufend ändern wird, wenn wieder ein neuer Test dazukommt, will ich hier nur auf die Grundlagen eingehen.Nach der Initialisierung des I2C-Buses mit Wire.begin() und ggf. setzen der Geschwindigkeit des Buses mit Wire.setClock(I2C_CLOCK_SPEED) wird in einer Schleife für die I2C-Adressen 8 bis 127 jeweils ein Wire.beginTransmission(deviceAddr) und ein ret = Wire.endTransmission(false) ausgesendet und geschaut, ob im Return-Wert eine Null zurückkommt, was auf eine fehlerfreie Ausführung hindeutet und das hier ein Gerät am I2C-Bus hängt. Das wird sogleich auf dem Display und über den Serial Monitor ausgegeben und für spätere Zwecke in einem Array gespeichert.
Nach der Schleife werden die gefundene Geräte anhand der im Array gespeicherte Geräteadressen identifiziert und das passende Testroutinen gestartet. Je nach Komponenten kann die ganz unterschiedlich aussehen.
Da ich möglichst viele Komponenten testbar machen möchte, habe ich versucht, möglichst auf fertige Libraries, die in Vielzahl doch recht viel Speicherplatz wegnehmen und irgendwann den Speicher sprengen würden, zu verzichten und nur ein paar Bytes für einen rudimentären Test, so dieser denn ausreichend ist, zu benutzen.
Komponenten, die erkannt und getestet werden können
Folgende Geräte kann mein I2C-Scanner und Tester zur Zeit identifizieren und testen:Unter Adresse 0x20 bis 0x26 (eigentlich 0x27) findet sich der PCF8574 IO-Expander, den ich in meinem Artikel OctoPrint-Raspi mit Status-LCD erweitern vorgestellt und erklärt habe.
Kurz gesagt ist ein IO-Expander ein Chip oder Modul, der die Anzahl der Ein- und Ausgänge eines Mikrocontrollers erweitert. Der PCF8574 stellt 8 digitale Ein/Ausgänge zur Verfügung, die man dann abfragen kann.
Viele PCF8574 Module haben DIP-Schalter, um die Adresse einzustellen. Die eingestellte Adresse wird bei der Suche zurückgegeben.
Der integrierte Test liest die IO-Port an P0 bis P7 aus und zeigt auf dem Display an, ob die Pins auf High oder Low sind. Mit einem Jumperkabel zwischen einem Pin und 3.3V oder GND kann man testen, ob sich Veränderungen in der Anzeige ergeben.
Da die Adresse 0x27 auch standardmäßig vom PCF8574 Chip auf einem I2C-1602-Backpack verwendet wird, wird dieser für den generellen PCF8574-Test ausgelassen und stößt den LCD-Display-Test 1602/2004 an.
Unter Adresse 0x27 antwortet der PCF8574 auf der Backpack-Platine, um 1602 und 2004 Displays über I2C ansrepchen zu können. Diese LCD-Displays habe ich im Artikel Ein Dot-Matrix-LCD (1602A und 2004A) mit dem Raspberry Pi ansteuern genauer erklärt.
Die Variante mit Huckepack-Modul wird in meinem Artikel OctoPrint-Raspi mit Status-LCD erweitern genauer erklärt.
Kurz gesagt, kann das 1602A 2 Zeilen zu jeweils 16 Zeichen und das 2004A 4 Zeilen zu 20 Zeichen darstellen. Die Displays sind gut ablesbar, können aber nur Buchstaben und Sonderzeichen, weil sie zeichen- und nicht grafikorientiert arbeiten.
Der integrierte Test schreibt Text in die zwei bzw. vier Zeilen des Displays und checkt so, ob die Darstellung gut ist und die Buchstaben richtig dargestellt werden.
Unter Adresse 0x29 wird der VL53L0X TOF Time of Flight Distanzsensor gefunden. Diesen habe ich in meinem Artikel Was ist besser zur Distanzmessung? Ultraschall-Modul HC-SR04 versus TOF-Modul VL53L0X genauer vorgestellt.
Kurz gesagt, wird hier ein Infrarot-Laser ausgesendet und wieder aufgefangen und die Zeit gemessen, die der Laser für diesen Weg gebraucht hat (eben "Time of flight"). Daraus wird die Entfernung berechnet.
Der integrierte Test zeigt die entsprechende Entfernung als Rohwert an. Mit der Hand über dem Sensor sollten sich die Werte ändern, wenn man die Hand hebt oder senkt.
Unter Adresse 0x35 lässt sich der ATECC608B Krypto-Chip finden, wie er zum Beispiel in der M5 ID-Unit verbaut ist. Auf diesen Chip bin ich näher in meinem Artikel Vorstellung der M5Stack ID-Unit: Krypto-Modul mit ATECC608B Krypto-Chip eingegangen. Dort kann man alles Wissenswerte dazu nachlesen.
Kurzgesagt kann man mit dem ATECC608B im der ID-Unit kryptografische Zertifikate und Zufallszahlen erzeugen. Mehr zum Thema Kryptografie allgemein unter Kryptografie.de.
Die ID Unit wird über ein Grove-Kabel angeschlossen. Die Grove-Kabel und Module hatte ich im Artikel Grove Shield zum schnellen Aufbau von Schaltungen und LCD mit RGB Backlight vorgestellt. Es handelt sich um 4-poligen, vertauschungssichere Kabel mit 2 mm Pinabstand, die unter anderen für den I2C-Bus benutzt werden.
Auf dem Breadboard kann ein Grove-Kabel eingesteckt werden, um Grove-Module wie die ID Unit einfach anschließen zu können. Allerdings schien es beim Aufbau Kommunikationsprobleme zu geben. Darum wird für die ID Unit der I2C-Bus auf 10 kHz heruntergetaktet, womit die Kommunikation dann besser klappt.
Der integrierte Test beschränkt sich auf die Abfrage der Version des Chips. Weiterführende kryptografische Funktionen sind komplexer und würden viel Speicher verbrauchen. Bei tiefergehendem Interesse einfach mal meinen obig verlinkten Artikel lesen.
Unter Adresse 0x39 lässt sich der ADPS-9960 Light/RGB Sensor finden, den ich in meinem Artikel Annäherungs-, Gesten- und Farberkennung mit dem ADPS-9960 Sensor näher behandele.
Der integrierte Test checkt die Proximity, also Annäherungsfunktion, die mit der Hand ein paar Zentimeter vor dem Sensor getestet werden kann. Direkt vor dem Sensor sollte der höchte Werte angezeigt werden.
Unter Adresse 0x3c findet sich dann das beliebte SS1306-OLED-Display mit 128x64 oder 128x128 Pixel in monochrom. Auf das Display gehe ich in meinen Artikeln OLED-Display (128x64 px, 0.96") an STM32 betreiben und Analog-Digital Wander ADS1115 als Voltmeter am ESP32 (ESP32 OLED) genauer ein.
Auf das winzige 0.96 Zoll große OLED-Display lassen sich auch monochrome Grafiken zaubern. Es ist sparsam im Verbrauch, hervorragend ablesbar und kostet nicht viel.
Der integrierte Test gibt Test und Grafik auf dem Display aus und schaltet auch alle Pixel auf an, um zu schauen, ob vielleicht ein Pixel nicht leuchtet.
Unter Adresse 0x48 werden der ADS1115 und der PCF8591 ADC gefunden. Beides sind Analog Digital Converter, messen also eine analoge Spannung an den Pins und geben den Wert digital zurück.
Den 16-bit-AD-Wandler ADS1115 stelle ich in meinem Artikel Analog-Digital Wander ADS1115 als Voltmeter am ESP32 (Lolin32) näher vor. Dem nur 8-bit-AD-Wandler ist der Artikel Über den I2C-Bus des Raspberry Pi einen Analog-Digital-Wandler (PCF8591) ansteuern gewidmet.
Da die I2C-Channel-Register für beide ADCs zufällig übereinstimmen, kann ich beide mit denselben Routinen behandeln. Der integrierte Test zeigt jeweils den Wert von AO bzw. AIN0 an. Hier kann eine schwache Spannungsquelle gemessen werden, indem man z. B. eine 1.5V-Batterie zwischen A0 und GND anschließt.
Unter Adresse 0x60 meldet sich der SI1145 UV Index Chip. Mit ihm kann man Umgebungslicht, Infrarotlicht messen und einen UV-Index berechnen lassen. Näheres zu dem Sensor in meinem Artikel Experimente mit dem SI1145 UV-Index / IR / sichtbares Licht-Sensor.
Bei dem integrierten Test wird die Part-ID des Chips auf dem Display wiedergegeben. So kann man schauen, ob die Kommunikation funktioniert. Auf tiefergehende Tests habe ich verzichtet, um Speicherplatz zu sparen.
Unter Adresse 0x68 melden sich zwei Chips: der MPU6050 und der DS1307. Der DS1307 meldet sich aber gleich unter zwei Adressen, wodurch man beide Chips unterscheiden kann.
Unter Adresse 0x68 (zusammen mit 0x50) meldet sich der DS1307 RTC. Die Dallas 1307 Real Time Clock ist eine Echtzeituhr, wie sie auf dem Tiny RTC Modul vorkommt. In meinem Artikel Echtzeituhr mit RTC auf 8fach-7Segment-Display anzeigen erkläre ich das Modul genau.
Zum Test wird das Datum und die Zeit der Entwicklung in die RTC geschrieben und danach die Uhr gestartet. Die fortschreitende Sekunden wird dann im Display angezeigt.
Unter Adresse 0x68 (allein) ist das MPU-6050 Gyro- und Accelerometer zu finden. Das ist ein Sensor, mit dem man Ausrichtung und Beschleunigung messen kann. Genauer erklärt ist er in meinem Artikel GY-521 Modul mit MPU-6050 Gyroskop/Beschleunigungssensor-Chip über I2C-Bus an Odroid Go ESP32 anschließen.
Für den internen Test werden die Rohwerte der beiden Sensoren jeweils für X, Y und Z auf dem Display ausgegeben.
Unter Adresse 0x76 findet sich der Bosch BMP280, ein Chip, mit dem man die genauere Temperatur und den Luftdruck messen kann. Den BMP280 habe ich in meinem Artikel Den Sensor BMP280 als Thermometer und Barometer nutzen und über den I2C-Bus auslesen genauer erklärt.
Beim integrierten Test wird die Temperatur auf dem Display ausgegeben.
Tests im Video
Natürlich habe ich die Tests der Komponenten bei der Entwicklung alle selbst durchgeführt. Dabei habe ich die Videokamera mitlaufen lassen, so dass das folgende Video einen guten Überblick über die testbaren Komponenten und die jeweiligen Anzeigen gibt:
Weitere Aussichten
Was dem I2C-Scanner und Tester jetzt noch fehlt, ist ein Gehäuse, damit der Kabelsalat verschwindet und das Ganze rüttel- und schüttelfest wird. Da werde ich sicher bald etwas aus meinem 3D-Drucker lassen.
Wenn es soweit ist, werde ich den Link hier posten.
Es ist soweit! Hier geht es zum Artikel, in dem ich das passende Gehäuse designe, drucke dem Scanner den letzten Schliff gebe.
Wenn es soweit ist, werde ich den Link hier posten.
Es ist soweit! Hier geht es zum Artikel, in dem ich das passende Gehäuse designe, drucke dem Scanner den letzten Schliff gebe.