Zero WT / OS "Buster" und zweiter I2C Bus

  • Moin,


    ich stehe vor einen riesigen Problem.
    Für eine Anwendung suche ich die Möglichkeit den I2C mit dem SPI Bus zu synchronisieren.

    Dazu hatte ich ein Codebeispiel aus den Anfangsjahren des PI von Erik Bartmann gefunden, wie man mit RPi.GPIO SPI Komponenten Ansprechen kann. Es ist zwar sehr viel Programmierarbeit, aber es funktioniert.

    Nun bin ich auf der Suche nach einem Beispiel-Code für den Portexpander PCF8574 von NXP, der ebenfalls mit oder über RPi.GPIO läuft.

    Jetzt habe ich schon fast überall herumgesucht, und habe einen Eintrag im englischen Raspberry Pi Forum gefunden. Dort ist beschrieben wie man mit einem Eintrag in der /boot/config.txt weitere GPIO-Pins zu einem I2C-Bus-Master machen kann. Das habe ich an meinen Anwendungsfall (GPIO Belegung) so angepaßt und wollte nun mit einem über GITHUB verfügbaren Steuercode, welcher jedoch smbus verwendet das Ganze ausprobieren.

    In der config.txt habe ich folgende Zeilen ergänzt.


    Bash
    dtoverlay=i2c-gpio,bus=1,i2c_gpio_sda=17,i2c_gpio_scl=27 


    Frage ich nun den über die GPIOs 17 und 27 angeschlossen PCF8574 mit i2cdetect -y 2 ab, erhalte ich die Meldung:


    Bash
    "Error: Could not open file `/dev/i2c-2' or `/dev/i2c/2': No such file or directory"

    Egal welche Zahl mit Ausnahme der 0 ich bei bus = eintrage, ich kann bei i2cdetect die letzte Stelle ändern wohin ich will, mit 1 werden immer die 3 angeschlossen Busadressen angezeigt. Nur jede andere Zahl 2 bis x führt immer wieder zu einer ähnlichen Meldung.

    Damit funktioniert auch der Pythoncode nicht.

    Python
    import smbus
    i2cbus = smbus.SMBus(2)

    Hier erhalte ich die Fehlermeldung:

    Bash
    Traceback (most recent call last):
    File "<pyshell>", line 1, in <module>
    FileNotFoundError: [Errno 2] No such file or directory

    Für meinen Anwendungsfall muß ich sicherstellen, daß der/die PCF8574 einen Eingang entsprechend geschaltet hat, bevor über den SPI-MOSI der nächste Befehl zur SPI Komponente gesendet wird.

    Ergänzen möchte ich noch, das ich am I2C Bus mit den PIns 3 (GPIO2) und 5 (GPIO3) schon ein RTC hängen habe, sowie ein TM1637 4x7Segmentanzeige und ein I2C-PCF8574-LCD Adapter für ein 20x4 LCD Display. Diese beiden Anzeigeeinheiten spreche ich über einen Thread in Python an und werden sekündlich aktualisiert. Soweit alles kein Problem.
    Bringe ich nun weitere PCF8574, jeweils mit einer anderen Bus-Adresse hinzu, und will die Ausführung zusammen mit der SPI Komponente betreiben, kommt es immer wieder zu einer Datenkollision, bzw. der Schaltvorgang wird nicht ausgeführt, was zur Folge hat, daß die SPI Komponente einen Schaden nimmt. Auf den Gedanken den I2C Portexpander durch einen SPI Portexpander zu ersetzen bin ich auch schon gekommen. Das geht leider auch nicht, denn dann müßte ich einen weiteren freien GPIO für die CE/CS Signalleitung zur Verfügung haben, denn ich benötigte in der Summe 3 dieser PCF8574.
    Somit bin ich nun auf der Suche nach einer Möglichkeit auf dem PI Zero den/die PCF8574 über zweit getrennte SDA / SCL Pins und RPi.GPIO anzusprechen.
    Mir geht es dabei nicht um die maximale Ausführungs- und Busgeschwindigkeit, sondern nur um die sichere Einhaltung der Befehlsfolgen:
    - Schalten eines Port-Pins am PCF8574
    - Abfrage zur Sicherheit im Portregister, ob dieser geschaltet hat
    - Befehlsübermittlung an die SPI Komponente.

    Danke

    Franky

  • Go to Best Answer
  • Moin Franky07,


    eine gute Quelle was alles mit overlays möglich ist, findest du in der /boot/overlays/README. Das aber nur am Rande.


    Wenn ich auf meinem Zero nur das Overlay I2C eingeschaltet habe, sehe ich folgendes:

    Code
    ls -l /dev/i2c*
    crw-rw---- 1 root i2c 89, 1 14. Mai 22:34 /dev/i2c-1
    crw-rw---- 1 root i2c 89, 2 14. Mai 22:34 /dev/i2c-2

    Trage ich nun dtoverlay=i2c-gpio,bus=3,i2c_gpio_sda=17,i2c_gpio_scl=27 in die /boot/config.txt ein, sehe ich nach einem Reboot folgendes:

    Code
    ls -l /dev/i2c*
    crw-rw---- 1 root i2c 89, 1 14. Mai 22:47 /dev/i2c-1
    crw-rw---- 1 root i2c 89, 2 14. Mai 22:47 /dev/i2c-2
    crw-rw---- 1 root i2c 89, 3 14. Mai 22:47 /dev/i2c-3

    Das ist es doch, was du suchst, oder?


    73 de Bernd

    Ich habe KEINE Ahnung und davon GANZ VIEL!!
    Bei einer Lösung freue ich mich über ein ":thumbup:"

    Vielleicht trifft man sich in der RPi-Plauderecke.

  • Hallo Franky,


    da Du an einem I2C-Bus rund 120 Devices (mit unterschiedlicher I2C-Adresse) anschließen kannst, ist es mir nun nicht nachvollziehbar, weshalb Du gleich einen weiteren I2C-Bus benötigst.


    WARUM also?


    Beste Grüße


    Andreas

    Ich bin wirklich nicht darauf aus, Microsoft zu zerstören. Das wird nur ein völlig unbeabsichtigter Nebeneffekt sein.
    Linus Torvalds - "Vater" von Linux

    • Icon-Tutorials (IDE: Geany) - GPIO-Library - µController-Programmierung in Icon! - ser. Devices - kein Support per PM / Konversation

    Linux is like a wigwam, no windows, no gates, but with an apache inside dancing samba, very hungry eating a yacc, a gnu and a bison.

  • Moin,


    Erik Barrtmann beschrieb in seinem von O'Reilly verlegten Buch "Die elektronische Welt mit Raspberry Pi entdecken" aus dem Jahre 2013 in dem Kapitel 14 die grundlegenden Methoden, wie man den SPI Bus ohne HW Aktivierung über die RASPI-CONFIG nur mit der Python Bibliothek "RPi.GPIO" mit frei wählbaren GPIO-PIns SPI Bausteine ansprechen kann. Also der gesamte Ablauf vom Setzen des CS Siganls auf LOW, der Takterzeugung bis hin zur Datenübertragung ( Senden über den MOSI Pin, und dem Empfangen über den MISO Pin) in Python sich umsetzen läßt. Die Methode ist zwar nicht die schnellste, aber so funktioniert das Python-Programm unabhängig der Grundkonfiguration des jeweiligen PIs auf welchem es ausgeführt wird. Damit hat man natürlich auch die volle Kontrolle über Abläufe die an eine gewisse Reihenfolge gebunden sind.
    RPi.GPIO steht mit GPIOZERO ( Standardmäßig enthalten) immer noch zur Verfügung.
    Auch wenn es für die meisten I2C und SPI Komponenten inzwischen schon fertige Bibliotheken gibt, oder z.T. auch schon in GPIOZERO enthalten sind, ist deren Ausführung nicht sonderlich schnell im Vergleich zur aufwendigeren Methode mit RPi.GPIO.
    Nun sind viele verfügbaren Bibliotheken schon auf oder mit SMBus geschrieben, oder nutzen WiringPI, was bei der gemischten Nutzung der Bibliotheken für einigen Ärger sorgt.

    Nun war mein Gedanke, daß man dieses Grundprinzip ( der freien PIN-Nutzung, und Konfigurationsunabhängig) auch auf den I2C Bus übertragen könne.

    @Bernd666:
    Ich hatte, wie schon gesagt, deiner Zeile ähnlich bei BUS die Zahl / Nummer 2 eingetragen.
    Damit erhalte ich nur einen Eintrag bei:

    Bash
    dtoverlay=i2c-gpio,bus=2,i2c_gpio_sda=17,i2c_gpio_scl=27
    
    ls -l /dev/i2c*
    crw-rw---- 1 root i2c 89, 1 Mai 15 05:22 /dev/i2c-1

    :-/ Erst wenn ich den Eintrag wie bei dir auf 3 ändere werden 2 Einträge angezeigt:

    Bash
    dtoverlay=i2c-gpio,bus=3,i2c_gpio_sda=17,i2c_gpio_scl=27
    
    ls -l /dev/i2c*
    crw-rw---- 1 root i2c 89, 1 Mai 15 05:28 /dev/i2c-1
    crw-rw---- 1 root i2c 89, 2 Mai 15 05:28 /dev/i2c-3

    führe ich nun i2cdetect -y 3 aus, erfolgt die Auflistung ( entschuldige das Wort ) kotzlangsam. :sleepy:

    Verwende ich nun die PCF8574 Bibliothek mit SMBus und trage dort statt der BUS-Nummer 1 hier nun die 3 ein, läuft zwar das Programm, aber die CPU Auslastung geht auf Anschlag 100% und es dauert ewig.

    Python
    from pcf8574 import PCF8574
    from time import time
    
    bus_num = 3
    pcf = PCF8574(bus_num, 0x20)
    T0 = time()
    for i in range(8):
        pcf.port[i] = True
    print(round(time() - T0,2), ' sec.')

    erhalte ich in der Ausgabe um nacheinander alle an den PCF angeschlossenen LEDs einzuschalten die Ausgabe 9.28 sec.. Ja, man kann in aller Ruhe zusehen, wie die LEDs nacheinander eingeschaltet werden. :wallbash:

    stecke ich nun den PCF an die anderen PINs (3,5) die für den BUS=1 vorgesehen sind, ändere im gleichen Programm nur die bus_num auf 1 erfolgt die Ausführung in 0.034 Sekunden und alle LEDs gehen optisch zeitgleich an.

    Das ist aber nicht das was ich mir vorstelle.
    Daher hatte ich die Frage gestellt, ob jemand noch ein älteres Programm für den PCF8574 beruhend auf RPi.GPIO hat, wo man ebenfalls die Pins für SCL und SDA frei auswählen kann, bzw das schon einmal mit RPi..GPIO umgesetzt hat.

    Franky

  • Moin Franky07,


    ja, mein Vorschlag ist zwar schnarch langsam, aber er geht. Du solltest nicht vergessen, das es eine Softwareemulierung eine I2C-Bus ist. Eventuell ist da ein Raspberry Zero W nicht schnell genug.

    Dazu hatte ich ein Codebeispiel aus den Anfangsjahren des PI von Erik Bartmann gefunden, wie man mit RPi.GPIO SPI Komponenten Ansprechen kann. Es ist zwar sehr viel Programmierarbeit, aber es funktioniert.

    Dann kannst du doch auf dieser Basis weitermachen. Die Funktionen eines PCF8574 sind ja nicht so umfangreich.


    Dann würde mich mal interessieren, warum du nicht auf die Frage vom Andreas eingehst?

    Warum passt der PCF8574 nicht mehr an den I2C-Bus?


    73 de Bernd

    Ich habe KEINE Ahnung und davon GANZ VIEL!!
    Bei einer Lösung freue ich mich über ein ":thumbup:"

    Vielleicht trifft man sich in der RPi-Plauderecke.

  • Moinsen,


    Warum ? Das ist ganz einfach, oder relativ logisch erklärt.

    Da ich, wie ich schon beschrieben hatte, am Hardware-I2C Bus schon 3 Komponenten dran habe, welches selber in einem festen Takt / Rhythmus aktualisiert werden, tritt ein unangenehmer Nebeneffekt auf. Warum das so ist, dafür habe ich keine Erklärung. :gk1:
    Wenn die beiden Anzeigeeinheiten sekündlich aktualisiert werden, erfolgt das hinter einander weg, und über einen Thread gesteuert. Das soll auch so sein.
    Komme ich nun dem System auch noch damit, das am HW unterstützten I2C drei weitere PCF8574 hänge, die sich auch darüber ansprechen lassen, kann ich das ganze Vorhaben beerdigen.
    Warum das Ergebnis noch Grotten langsamer wird, keine Ahnung.
    Sende ich in Python an alle 3 Zusatz-PCFs die gerade benötigte PIN-Auswahl geht das relativ schnell.
    Innerhalb der Abhängigkeitsroutine mit dem SW-SPI Bus prüfe ich vor der Sendung des SPI MOSI Befehls nochmal alle Portregister ab, ob der oder die Umschaltvorgänge auch stattgefunden haben.
    Das mache ich nun in einer while Schleife. Zudem habe ich in der dieser Schleife auch schon einen Counter eingebaut, damit diese Schleife sich nicht Endlos im Kreise dreht. Nach dem fünften Versuche wird noch einmal die gleiche Befehlsfolge an diese drei PCF gesendet, falls bis dahin nicht die gewünschten Port-Rückmeldungen kommen. Ob das mit dem Anzeige-Thread zusammen hängt, keine Ahnung - jedoch vermutlich. Je nach dem, und nicht wirklich reproduzierbar, dauert es zum Teil bis zu 20 Sekunden ausschließlich bei Nutzung des HW-I2C BUS bis dieser Programmteil fortgeführt wird. Manchmal geht es ganz fix, schon nach dem 1 oder 2 Durchlauf der Sicherheitsabfrage kann ich mit dem Programmteil fortfahren, der mit dem SW SPI Bus arbeitet, was vollkommen okay ist. Aber ich kann und will nicht eine halbe Minute warten müssen. Lasse ich den Anzeige-Thread weg, also starte ihn gar nicht erst, der die beiden Anzeigeneinheiten aktualisieren läßt, klappt es wunderbar. Ich nehme an, daß in diesem Zeitfenster zwischen den Displayaktualisierungen zu viel auf dem HW-I2C Bus los ist.

    Nachdem es mir ohne diese zusätzliche Port-Registerabfrage schon einiges von der Außenbeschaltung weggeräumt hat, bzw. in das Nirvana des Elektronik-Schrotts geschickt wurde, bin ich der Sache mal auf den Grund gegangen. Warum, obwohl das Programm weiter läuft, nicht immer alle Umschaltvorgänge zur Ausführung gekommen sind, kann ich nicht sagen. Deswegen habe ich diese zusätzliche Port-Registerabfrage eingefügt. Dann bliebt im Testlauf ab und zu einmal das Programm hängen. Hängen im Sinne davon, das zwar die Anzeigen noch aktualisiert worden, aber nach dem STRG-C stellte sich heraus, daß das Programm in dieser While Sicherheitsabfrage Schleife festhing. Also kam noch der Counter dazu, der nach 5 vergeblichen Abfragen, die Schaltbefehle an die 3 PCF wiederholt. Ich habe leider nicht das notwendige Hintergrundwissen, warum Python selber den Hintergrund-Threads zur Anzeigenaktualisierung die Priorität gewährt, aber die Hauptprogramm Routine hängen läßt, oder einzelne Befehle verschluckt.

    Der Thread zur Anzeigensteuerung ist relativ einfach gestrickt. In einer Endlosschleife wird der Wert aus einer global Variable ( Typ list ) genommen, aufgesplittet und mit den Displaybefehlen zu den Displays geschickt. Danach erfolgt ein sleep(0.92) damit dort einfach etwas Ruhe rein kommt, und der i2C Bus nicht ständig blockiert wird. Man kann zwar die Ausführung eines Threads vorübergehend unterbrechen, wenn wo anderes Dinge höherer Priorität angesagt sind, aber das setzt wiederum voraus, daß diese Kombi Routine I2c + SW-SPI ebenfalls in einem eigenen Thread laufen müßte. Von der Hauptprogrammroutine __main__ aus, kann ich nur den Thread komplett stoppen, oder killen, und müßte ihn dann neu starten. Das macht eine solche Routine natürlich sehr unflexibel, und setzt voraus das dieser Programmteil immer in einem eigenen Thread ausgeführt wird.

    Deswegen hatte ich nun die Idee, ohne das jedes PI, worauf dieser Programmteil mal laufen könnte, erst eine Anpassung in der /boot/config.txt vorgenommen werden müßte, daß ähnlich wie mit dem SW-SPI von Bartmann zu probieren. Dazu noch folgendes: Egal ob der SPI Bus in der Raspi-Config aktiv ist oder nicht, die Laufzeitunterschiede mit Bartmanns SPI Routine liegen nur im einstelligen Prozentbereich. Also im Bereich von unter einer Millisekunde.

    Das blinde Vertrauen, ich sende einen Befehl mit SMBus an einen PCF8574, wo im Hintergrund weitere I2C Komponenten angesprochen werden, haben mich schon über 100 € gekostet.


    Bernd666 deinem Verdacht, der ZERO könnte zu langsam sein, muß ich so widersprechen. Ich habe mal schnell auf eine 16er µSD ein frisches OS aufgezogen und in einen 3B+ geschoben. Bis auf den Unterschied das ich die Kernel-IR nicht aktiviert habe, was wiederum zur Folge hatte, das der Eintrag in der /boot/config.txt jetzt auch mit dem BUS=2 klappt ist kein wirklich eklatanter Unterschied festzustellen. Die Lösung alle 3 PCF8574 mit an den HW-I2c Bus Nr. 1 zu hängen bringt nicht wirklich etwas. Nur die Lösung mit dem zweiten I2C-Bus über die Config-Datei bereit gestellt läuft einiges schneller, aber nicht wirklich zügig.

    Daher, auch wenn es mich noch einige Zeit kostet, würde ich erst einmal bei dem Ansatz weiter verfolgen wollen, ob sich das Bit-Banging für den I2C auch mit RPi.GPIO umsetzen läßt - Genau dafür bin ich auf der Suche, nach einer alten Routine die man entsprechend anpassen könnte.

    Franky

    • New
    • Best Answer

    Hallo Franky,


    ich will jetzt gar nicht auf jeden Deiner Erklärungsversuche eingehen.


    Es hat schon seinen Grund, weshalb das Betriebssystem des Raspberry Pi gelegentlich revidiert wird. Es ist immer problematisch, wenn man irgendwelche "alten" oder "uralten" Vorgehensweisen zu reaktivieren versucht.


    Letztlich scheitert es auch an der Unterstützungsmöglichkeit, weil kaum jemand an den alten Zöpfen festhält.




    Daher, auch wenn es mich noch einige Zeit kostet, würde ich erst einmal bei dem Ansatz weiter verfolgen wollen, ob sich das Bit-Banging für den I2C auch mit RPi.GPIO umsetzen läßt - Genau dafür bin ich auf der Suche, nach einer alten Routine die man entsprechend anpassen könnte.

    Franky


    Ich hatte auch zu Wheezy-Zeiten (oder so) mal in der Programmiersprache Icon über Bit-Banging SPI nachgebildet. Einfach, um das mal auszuprobieren.


    Ja, es funktioniert.

    Was Du aber nicht außer Acht lassen darfst: Du musst jedes Timing, dass Dir das Datenblatt vorgibt, exakt nachbilden. Da stößt Du an Grenzen.


    1. Das von Dir eingesetzte Betriebssystem gehört nicht zu den Betriebssystemen, die für die Erfüllung der Eigenschaften für Echtzeit-Betriebssysteme bekannt sind.
    2. Python ist ebenfalls weit davon entfernt, echtzeitfähig zu sein. Ein delay(0,92) dauert theoretisch 920 ms. Das kann auch mal 1200 ms dauern - je nach dem, was da noch alles so läuft, und was gerade in dem Moment, in dem der Scheduler Deiner Anwendung wieder Aufmerksamkeit schenken möchte, gerade an wichtigeren Aktionen oder Reaktionen des Betriebssystems mit höherer Priorität eintrudelt.
    3. Auf Deinem Raspberry Zero buhlen alle Prozesse (alle des Betriebssystems in der Größenordnung von 60 bis 100), der Python-Interpreter, Deine Python-Anwendung UND alle Deine gestarteten Threads um den einen einzigen Prozessor. Das sorgt für ganz erhebliche Timing-Probleme - wenn Dein Bit-Banging im Bereich ms oder gar µs takten muss.

    Ich habe früher mal intensive Untersuchungen durchgeführt, wie reproduzierbar die Laufzeiten (einfachste Zyklen pro Zeiteinheit) sind. Das Ergebnis war genauso bemerkenswert wie schockierend (für RPis mit einem einzigen Prozessorkern).

    Bei einem RPi "1" B, RPi A und RPi Zero unterscheiden sich die Maximal- von den Minimalwerten wie 66 zu 100 zu oder 100 zu 150. Also ganz schlecht für Bit-Banging mit engeren Zeittoleranzen, als es diese Verhältniszahlen erlauben.


    Auf einem Standard-PC liegen die Verhältnisse schlechtestens bei 97 zu 100 - meistens bei 99,5 zu 100. Damit wäre Bit-Banging auch mit recht engen Toleranzen denkbar.

    Gleichzeitig setzt dies dann auch eine Grenze, die auf einem RPi nicht besser möglich sein wird.


    Auf einem RPi 3B (+) und RPi 4B sehen diesen Verhältnisse mit recht konstant 97 zu 100 brauchbar gut aus. Es gab aber auch Fälle, da muss wohl einiges Widrige zusammengekommen sein. Da gab es recht heftige Ausreißer - was dann zu erheblichen Störungen im Bit-Banging führen würde und somit zu Fehlinterpretationen von Bits und damit von Daten bzw. Kommandos.


    Die Versuche habe ich dann noch mit einem ASUS Tinkerboard und einem NVIDIA Jetson Nano wiederholt. Die Beobachtungen am Tinkerboard entsprechen denen des RPi 3B / 4B. Der Jetson Nano liefert ähnliche Beobachtungen wie der PC.


    Zusammenfassung:

    Für Dein Vorhaben nutzt Du eine ungeeignete Hardware, ein ungeeignetes Betriebssystem, eine ungeeignete Programmiersprache, ein ungeeignetes Threading auf einem einzigen Prozessor.

    Durch den quasi gleichzeitigen Ablauf von Betriebssystem, dessen zahlreichen Tasks und Services, Deiner Programmierumgebung, Deiner Anwendung und Deinen Threads gibt es zu viele Timing-Probleme, die ein Bit-Banging in einer Hochsprache verunmöglichen.


    Alternative Lösungsansätze hast Du erhalten. Nutze diese Vorschläge.



    Beste Grüße


    Andreas

    Ich bin wirklich nicht darauf aus, Microsoft zu zerstören. Das wird nur ein völlig unbeabsichtigter Nebeneffekt sein.
    Linus Torvalds - "Vater" von Linux

    • Icon-Tutorials (IDE: Geany) - GPIO-Library - µController-Programmierung in Icon! - ser. Devices - kein Support per PM / Konversation

    Linux is like a wigwam, no windows, no gates, but with an apache inside dancing samba, very hungry eating a yacc, a gnu and a bison.

    Edited 2 times, last by Andreas ().

  • Moin Franky07,


    Da ich, wie ich schon beschrieben hatte, am Hardware-I2C Bus schon 3 Komponenten dran habe, welches selber in einem festen Takt / Rhythmus aktualisiert werden, tritt ein unangenehmer Nebeneffekt auf. Warum das so ist, dafür habe ich keine Erklärung. :gk1:
    Wenn die beiden Anzeigeeinheiten sekündlich aktualisiert werden, erfolgt das hinter einander weg, und über einen Thread gesteuert. Das soll auch so sein.

    Das ist eine Aussage. Wie lange braucht dein Code um die 2 Anzeigen zu aktualisieren?

    Was macht der Code in der verbleibenden 700 mS ? Da kann man doch einen Befehl für einen PCF8574 schicken?!.

    Dann darf man aber auch nicht mit "delay" arbeiten. Dann steht der Code.

    Es gibt aber auch noch eine andere Lösung. Schau dir mal diesen Thread an : ESP8266 Nodemcu mit 4 I²C OLED 0,96" Displays (gleiche Adresse) und 2 DS18b20 (Wasserdicht mit Kabel 3m)


    Eventuell hilft es.

    Ansonsten kann ich dir nur viel Erfolg wünschen!!


    73 de Bernd

    Ich habe KEINE Ahnung und davon GANZ VIEL!!
    Bei einer Lösung freue ich mich über ein ":thumbup:"

    Vielleicht trifft man sich in der RPi-Plauderecke.

  • Moinsen Bernd666,

    Ich habe keine Ahnung, wie es um deine Python Kenntnisse bestellt ist, und ich will und möchte dir hierzu auch nichts unterstellen.
    Wenn ich in einem _Thread ein sleep() verwende, dann steht die Ausführung nur in dem Programmteil, der innerhalb dieses Thread-Aufrufes ausgeführt wird. Das ist am ehesten mit einem MULTITASKING zu vergleichen. Der Code im __MAIN__ läuft deswegen trotzdem weiter, auch in den darüber aufgerufenen DEF Routinen und Funktionen.
    Dieses delay() Regel gilt nur, wenn man, so mein Kenntnisstand, ein Interrupt Handling für einen AVR über die ARDUINO IDE in C++ proggt. Das trifft hier aber nicht zu ;)

    Bezogen auf die Antwort von Andreas ( Danke nochmals für die ausführliche Erläuterung :danke_ATDE: ) habe ich bis jetzt auch noch keine Laufzeitmessung des Threads gemacht, in dem diese Anzeigen aktualisiert werden.
    Zu einer Erkenntnis bin ich aber schon gekommen und meinem Ziel ein gute Stück näher gekommen.
    Wenn die Kernel IR Schnittstelle aktiv ist, wird die Software Emulation für den Eintrag:

    Bash
    # mit IR 
    
    dtoverlay=gpio-ir,gpio_pin=18
    dtoverlay=gpio-ir-tx,gpio_pin=4
    dtoverlay=i2c-gpio,bus=3,i2c_gpio_sda=17,i2c_gpio_scl=27
    
    # bzw. ohne IR
    
    dtoverlay=i2c-gpio,bus=2,i2c_gpio_sda=17,i2c_gpio_scl=27

    in der /boot/config.txt nochmals verzögert ausgeführt.
    Lasse ich diese Einstellung für die Nutzung einer IR Fernbedienung weg, und nutze den zweiten I2C Bus mit SMBus habe ich einen in der Ausführungszeit fast konstanten Programmlauf.
    Auf die Sicherheitsabfrage und den Counter habe ich erst einmal noch nicht verzichtet, aber diese KOMBI Routine läuft erst einmal sauber durch, auch ohne lange Wartezeiten. Die Counter Auswertung, auch wenn es eine Programmzeile zusätzlich ist, lasse ich in einer self.Counter Variablen Hochzählen. Jetzt bin ich bei ungefähr 2-3 Fehlversuchen, also dem Punkt, wo ich die PCF8574 Schaltbefehle nochmals senden muß bzw. wo die Portgerister nicht gleich den korrekten Schaltzustand zurückmelden auf 100 Schaltvorgängen.
    Das kann natürlich auch noch mit den Kabel zusammenhängen, was ich nicht ausschließen will, denn ich habe das Ganze noch verteilt über 4 Steckboards aufgebaut. Ich wollte erst einmal sicher gehen, bevor ich eine Leiterplatte anfertigen lasse, daß die gesamte Schaltung auch wirklich so funktioniert.
    Auf Grund der Erklärung von Andreas habe ich nun den Versuch aufgegeben, das BIT-Banging für I2C selber zu Programmieren.
    Mit der SW Emulation des zweiten I2C Busses funktioniert das ganze erste einmal zufriedenstellend, wenn auch nicht optimal, auch auf einem Zero. Ich habe weniger Konflikte im Vergleich zu der Herangehensweise, wenn ich dieses 3 PCF8574 mit an den ersten I2C HW Bus hänge. Damit habe ich wohl Leistungsfähigkeit und -Grenzen eines ZEROs ausgereizt. Die weiterhin bestehenden Konflikte, alles über den HW I2c Bus zu lösen konnte ich noch nicht aufklären. :gk1:

    Ich danke euch allen nochmals für diese sehr umfänglichen und sehr verständlichen Erläuterungen. :danke_ATDE:

    Franky