Hallo, ich nutze auf meinem ESP8266 die Library U8G2, um mein OLED-Display (SSD1306) per I2C zu beschicken. Auf dem Bus sitzt zeitgleich noch ein Temperatursensor Aosong AM2320. Nun ist es so, dass ich auf dem Display eine extrem geringe Framerate bekomme. Beim Wechsel der Screens sieht man deutlich, wie das Bild von oben nach unten neu aufgebaut wird (Rolling-Shutter-Effekt). Ich schätze, dass die Framerate aufgrund der Refresh-Geschwindigkeit irgendwo bei maximal 10 FPS liegen dürfte. Ich habe über die Wire-Library bereits die Taktrate vor den Zeichenfunktionen auf 400k erhöht und anschließend wieder auf 100k gesenkt, da der Sensor laut Datenblatt nicht mehr kann. Ist das überhaupt sinnvoll, oder bremst der Sensor trotzdem? Oder liegt der Fehler wo ganz anderes? Beste Grüße André
André R. schrieb: > Oder liegt der Fehler wo ganz anderes? Zeile 42 in der Datei "unknown.ino". Jetzt wird meine Kristallkugel unklar: Du beschreibst das Display in einer Schleife und löscht es vor jedem Schreiben.
Das passt zu meiner Erfahrung (mit selbst geschriebenen Code ohne diese Library). Die Datenübertragung dauert einfach so lange. Schneller geht es mit SPI, aber auch dann nicht so schnell, dass es begeistern würde. Für bewegte Bilder taugen diese Display jedenfalls nicht.
Brummbär schrieb: > Du beschreibst das Display in einer Schleife und löscht es vor jedem > Schreiben. Genau so. Das Display wird über einen Hardware-Interrupt (Taster) aktiviert, zeigt dann via Timer nacheinander vier verschiedene Live-Status-Screens und schaltet anschließend wieder ab. Umgesetzt ist dieser Teil des Programms als Zustandsautomat. Da sich die Messwerte während der Anzeige ändern können, habe ich das Ganze einfach in der Schleife belassen und frische den Screen bei jedem Loop auf. Es ist auch nicht so, dass es flackern würde. Man erkennt allerdings beim Wechsel zwischen den vier verschiedenen Screens, wie das Bild von oben nach unten "umschaltet". Kann man denn mit der Wire-Library irgendwie auslesen, wie schnell der Bus gerade läuft? Stefan U. schrieb: > Die Datenübertragung dauert einfach so lange. Schneller geht > es mit SPI, aber auch dann nicht so schnell, dass es begeistern würde. Das wundert mich ja fast. Ich hätte erwartet, dass SPI bedeutend langsamer ist. > Für bewegte Bilder taugen diese Display jedenfalls nicht. Ist bei mir gar kein Use-Case. Ich sehe das auch eher als Schönheitsfehler an. Der Funktion tut es keinen Abbruch.
@André R. (andr_r619) >> Du beschreibst das Display in einer Schleife und löscht es vor jedem >> Schreiben. >Genau so. Das Display wird über einen Hardware-Interrupt (Taster) >aktiviert, zeigt dann via Timer nacheinander vier verschiedene >Live-Status-Screens und schaltet anschließend wieder ab. Das ist aber nicht die Antwort auf die Frage. Anscheinend löschst du das LCD NICHT vor jeder Anzeige. Das ist auch nicht nötig. >Schleife belassen und frische den Screen bei jedem Loop auf. Naja, du hast immerhin 10 Hz Refreshrate, das sollte reichen. >Es ist auch nicht so, dass es flackern würde. Man erkennt allerdings >beim Wechsel zwischen den vier verschiedenen Screens, wie das Bild von >oben nach unten "umschaltet". Das kann man nur verhindern, wenn man deutlich schneller die Daten in das LCD übertragen kann oder wenn das LCD 2 getrennte Speicher (Pages) hat. In die eine schreibt man beliebig langsam neue Daten, die andere wird angezeigt. Dann schaltet man im richtigen Moment um, wenn die Darstellung der neuen Daten beginnt. Sowas ist aber sehr selten. >Kann man denn mit der Wire-Library irgendwie auslesen, wie schnell der >Bus gerade läuft? Nein. >> Die Datenübertragung dauert einfach so lange. Schneller geht >> es mit SPI, aber auch dann nicht so schnell, dass es begeistern würde. >Das wundert mich ja fast. Ich hätte erwartet, dass SPI bedeutend >langsamer ist. Warum? I2C läuft mit 100 oder 400kHz, SPI kann je nach IC mehrere MHz bis weit in den 2-stelligen Bereich. >Ist bei mir gar kein Use-Case. Ich sehe das auch eher als >Schönheitsfehler an. Der Funktion tut es keinen Abbruch. Dann musst du den Refresh cleverer machen und nur den Bereich neu ausgeben, der sich wirklich ändert. Damit geht es schneller, weil weniger Daten übertragen werden müssen.
Wenn dein SSD1306 genug Ram (bzw. dein OLED wenig genug Pixel) hat: Bau den neuen Screen im Hintergrund auf, und schalte das Display um, sobald fertig. Befehl "Set Display Start Line"
> Bau den neuen Screen im Hintergrund auf, und schalte das Display um, > sobald fertig. Dafür hat das Display zu wenig Speicher. Das geht nur beim kleineren Display mit 32 Zeilen. > Dann musst du den Refresh cleverer machen und nur den Bereich neu > ausgeben, der sich wirklich ändert. Ja.
"It has 256-step brightness control. Data/Commands are sent from general MCU through the hardware selectable 6800/8000 series compatible Parallel Interface, I2C interface or Serial Peripheral Interface. " Beim Betrieb mit parallelem Interfache kann man laut Datenblatt 300ns Zykluszeit erreichen, das wären satte 3MB/s ;-) Bei SPI dürfen es immerhin noch 10MHz SPI-Takt sein, macht netto 1MB/s Bei I2C ist man auf max. 400kHz geschränkt, macht 50kB/s. Das LCD hat 128x64 Bit = 1kB Speicher, also sollte man es auch bei 400kHz ausreichend schnell beschreiben können, wenn der Rest paßt. Man müßte mal mit dem Oszi oder Logic Analyzer schauen, wie die Datenübertragung aussieht. Wahrscheinlich vergurkt die Lib da noch einiges.
> Bei I2C ist man auf max. 400kHz geschränkt, macht 50kB/s.
Du musst mindestens durch 11 teilen, nicht durch 8.
So einfach ist es aber nicht, denn ein paar der nötigen Kommandos
brauchen beträchtliche Zeit zur Ausführung. Es geht nicht nur um die
reine Datenübertragung.
@Stefan Us (stefanus) >Frames pro Sekunde. So einfach ist es aber nicht, denn ein paar der >nötigen Kommandos brauchen beträchtliche Zeit zur Ausführung. Ja welche denn? Und braucht man die, um neue Daten in den RAM zu schreiben?
Man muss angeben, ab welche Adresse man schreiben will. Dann kann man nicht das ganze RAM in einem Zug füllen, weil der auto-increment nur bis 256 zählen kann. Und außerdem konkurrieren Schreibzugriffe mit Lesezugriffen, was auch noch etwas zur Verlangsamung führt. Ein bisschen mehr als 10 Frames pro Sekunde gehen schon, aber höchstens doppelt so viele. Das wäre immer noch deutlich sichtbar.
> bremst der Sensor trotzdem
manche I²C Chips nutzen das Clock-Stretching, wenn sie mehr Zeit
brauchen. Manche Chips erlauben höhere Taktraten wenn sie gerade NICHT
angesprochen werden. Aber leider nicht alle.
Wenn das Datenblatt diese Details nicht erwähnt, musst du entweder mutig
ausprobieren oder den kleinsten gemeinsamen Nenner (also 100kHz) nehmen.
Hmm also schleifen sind schon mal ganz blöd. Deine Task darf keine ungebremste schleife haben. Wie ist denn der Display Buffer im U8G2 organisiert ? Man kann auch Zeilenweise schreiben und das mit der Eigenart vom ESP richtig blöd. Denn du füllst erstmal einen Buffer mit CMDs und nach dem Start schreibt die Hardware die Daten nach draußen. Ich könnte mir vorstellen wenn die Pakete recht klein sind das dieses verfahren recht langsam ist. Die i2c Funktion blockiert auch deine Task so lange wie Daten geschrieben werden. Ich würde eine extra Display Task machen und per event dort den Wert übergeben. Man kann auch gezielt nur den variablen Inhalt im Controller RAM überschreiben anstatt immer das ganze Display zu übertragen. Mit RTOS muss man etwas anders denken, also viel event basiert lösen.
:
Bearbeitet durch User
Falk B. schrieb: > Das ist aber nicht die Antwort auf die Frage. Anscheinend löschst du das > LCD NICHT vor jeder Anzeige. Das ist auch nicht nötig. Doch, derzeit habe ich immer einen Clear-Buffer-Befehl vor jedem Neuzeichnen. Am Ende des Zeichnens wird der komplette Buffer an den Screen geschickt (Full-Buffer-Mode). Falk B. schrieb: > Dann musst du den Refresh cleverer machen und nur den Bereich neu > ausgeben, der sich wirklich ändert. Damit geht es schneller, weil > weniger Daten übertragen werden müssen. Das dürfte die Lib nicht hergeben. Es gibt glaube ich so einen Modus, da kann man allerdings nicht mehr alle Zeichenfunktionen nutzen. Oder? Εrnst B. schrieb: > Wenn dein SSD1306 genug Ram (bzw. dein OLED wenig genug Pixel) hat: > > Bau den neuen Screen im Hintergrund auf, und schalte das Display um, > sobald fertig. Wie findet man das heraus? Das Display ist dieses hier: https://www.amazon.de/gp/product/B01N2K3BC9/ref=oh_aui_detailpage_o01_s00?ie=UTF8&psc=1 Falk B. schrieb: > Man müßte mal mit dem Oszi oder Logic Analyzer schauen, wie die > Datenübertragung aussieht. Wahrscheinlich vergurkt die Lib da noch > einiges. So gut ausgestattet bin ich leider nicht. Stefan U. schrieb: > Und außerdem konkurrieren Schreibzugriffe mit > Lesezugriffen, was auch noch etwas zur Verlangsamung führt. > > Ein bisschen mehr als 10 Frames pro Sekunde gehen schon, aber höchstens > doppelt so viele. Das wäre immer noch deutlich sichtbar. Ich dachte, I2C sei bei diesem Display/Controller nur unidirektional möglich … Stefan U. schrieb: > manche I²C Chips nutzen das Clock-Stretching, wenn sie mehr Zeit > brauchen. Manche Chips erlauben höhere Taktraten wenn sie gerade NICHT > angesprochen werden. Aber leider nicht alle. > > Wenn das Datenblatt diese Details nicht erwähnt, musst du entweder mutig > ausprobieren oder den kleinsten gemeinsamen Nenner (also 100kHz) nehmen. Ich hatte bei einem ursprünglichen Test ganz oben im Setup den Takt auf 400k gesetzt. Ich weiß allerdings nicht, ob das effektiv war. Funktioniert hat jedenfalls alles. Aber ich habe eben keine Ahnung, wie ich testen soll, wie schnell der Bus real tatsächlich arbeitet und ob meine Setting von 400k überhaupt angewendet oder von irgend einer Lib wieder überschrieben wird. Jedenfalls kam es mir nicht so vor, als würde es einen großen optischen Unterschied machen, ob ich mit 100k oder 400k schreibe. Marco H. schrieb: > Hmm also schleifen sind schon mal ganz blöd. Deine Task darf keine > ungebremste schleife haben. Wie ist denn der Display Buffer im U8G2 > organisiert ? Man kann auch Zeilenweise schreiben und das mit der > Eigenart vom ESP richtig blöd. Ich entwickle mit der Arduino-Library über Visual Micro im Visual Studio. Entsprechend nutze ich die Loop-Funktion. In diesem Loop kommt irgendwo ein If, welches fragt, ob mein Display-Mode-Enum > OFF (0) ist. Wenn ja, dann kommt darin zunächst ein Buffer-Clear und dann nach Art einer State-Machine ein Switch. Dieses zeichnet je nach aktuellem Modus den Frame in den Buffer. Nach dem Switch wird anschließend der Buffer auf den Screen geschrieben. Der Display-Mode wird alle 10 Sekunden durch einen Timer inkrementiert und springt nach dem vierten Modus wieder auf OFF. Dadurch wird das Display in den Energiesparmodus versetzt. Es gibt also keine wirkliche Schleife sondern nur den Loop vom Arduino. Es wird also pro Loop-Durchlauf nur einmal gezeichnet und anschließend kommen die anderen Dinge, die der Prozessor noch so erledigen muss. Marco H. schrieb: > Ich würde eine extra Display Task machen und per event dort den Wert > übergeben. Man kann auch gezielt nur den variablen Inhalt im Controller > RAM überschreiben anstatt immer das ganze Display zu übertragen. Auf dem ESP32 mit zwei Kernen würde ich das ja noch verstehen, aber welches Problem würde mir das auf dem ESP8266 lösen? Der Taster arbeitet über einen Hardware-Interrupt, wird also ohnehin nicht blockiert. Und gleichzeitig Sensor lesen und Display schreiben geht ohnehin nicht. Was sind denn die Vorteile eines Tasks, bzw. wie wird dieser auf dem ESP überhaupt deklariert? Der Grundaufbau des Programms ist, dass es zwei Timer gibt. Einer ist für das Display und wird erst gestartet, wenn der Interrupt kommt. Er wird wieder gelöscht, wenn der Display-Mode seinen letzten Zustand überschritten hat. Dieser Timer inkrementiert ausschließlich das Enum. Der andere Timer läuft alle fünf Sekunden und setzt eine Bool-Variable auf True, welche für die Sensor-Steuerung zuständig ist. In der Loop-Funktion werden das Enum und die Variable nacheinander geprüft und dann entsprechende Funktionen durchgeführt. Den Displayteil habe ich ja bereits beschrieben. Die Sensorfunktion schreibt die aktuellen Sensorwerte in einen Ringspeicher, sodass jederzeit die letzten 64 Sensorwerte als Historie zur Verfügung stehen. Läuft der Pointer auf meinen Ringspeicher über, so wird eine weitere Variable gesetzt, die im Loop weiter unten ebenfalls geprüft wird. Diese kümmert sich um das Übermitteln der aktuell gespeicherten 64 Datensätze als Paket an einen Server.
> Ich dachte, I2C sei bei diesem Display/Controller nur > unidirektional möglich … richtig. Ich meinte dass die Schreibzugriffe über I²C mit den internen Lesezugriffen der Displays selbst konkurrieren. Der ESP8266 hat soweit ich weiß keine echte I²C Schnittstelle (in Hardware). Da man ohnehin die beiden I/O Pins Bit-Bangen muss, sehe ich keinen wesentlichen Nachteil darin, dass blockierend zu tun.
Stefan U. schrieb: > Ein bisschen mehr als 10 Frames pro Sekunde gehen schon, aber höchstens > doppelt so viele. Das wäre immer noch deutlich sichtbar. 20fps deutlich sichtbar? Das kommt wohl SEHR auf die Inhalte der Frames an. Wenn es da z.B. ein graphisch aufgemotzen (aber konstanten) Hintergrund gibt, auf dem ein paar variable Ziffern im Vordergrund erscheinen, dann siehst du bei 20fps allenfalls mal gelegentlich einen kleinen "Ruckler" dort, wo sich gerade eine Ziffer ändert. Das gilt selbst dann, wenn (unnötigerweise) ein kompletter Refresh des Frameinhaltes durchgeführt wird. Wenn man hingegen komplett unterschiedliche Frames aufeinander folgen läßt, dann sieht das bei 20fps mit "rolling shutter" wirklich ziemlich Scheiße aus. Aber auch sowas läßt sich recht gut kaschieren. Man benutzt einfach einen Fade-Effekt, um den Übergang optisch weniger störend wirkend zu lassen. Blend z.B. oder fade to/from white/black. Schon recht wenige berechnete Zwischen-Frames lassen nicht nur den Effekt des "rolling shutter" dann optisch weitgehend verschwinden, nö, das Ergebnis sieht auch ingesamt sehr viel akttraktiver als das blödstumpfe Umschalten aus, so viel attraktiver, dass man solche Effekte sogar dann benutzt, wenn sie nicht wegen irgendwelcher Limitierungen der Display-Anbindung nötig werden würden, um das zu verdecken...
Stefan U. schrieb: > Für bewegte Bilder taugen diese Display jedenfalls nicht. :-) in C geschrieben ... https://www.youtube.com/watch?v=DVmTeQ6u3jQ
Nicht schlecht, ein beeindruckendes Video. Ich schätze dass dort nicht das ganze Bild neu gezeichnet wird, sondern nur wirklich geänderten Stellen. Aber egal, ist trotzdem beeindruckend.
Und es gibt immer noch kein Sourcecode ...
Stefan U. schrieb: > Ich schätze dass dort nicht das ganze Bild neu gezeichnet wird, sondern > nur wirklich geänderten Stellen. Nö, der Puffer (komplettes Bild) wird komplett übertragen. Es gibt auch Ansätze mit teilweise Übetragung, welche wohl (in manchen Fällen) schneller sind. Der Witz ist nur der Puffer, in welchem das Bild aufgebaut wird und dessen "optimaler" Übertragung. Die https://learn.adafruit.com/monochrome-oled-breakouts/arduino-library-and-examples können das gut :-)
Dieter F. schrieb: > :-) in C geschrieben ... Die Sprache spielt natürlich echt keine nennenswerte Rolle, wenn die IO-Anbindung des Displays mehr als eindeutig der limitierende Faktor ist...
c-hater schrieb: > Die Sprache spielt natürlich echt keine nennenswerte Rolle, Selbstverständlich ... :-)
Ich habe mit meinem eigenen Code nochmal ein bisschen herumgespielt, weil mich das Timing gerade interessiert und ich dies als gute Gelegenheit sehe, meinen neuen Logic Analyzer endlich mal zu benutzen. Bei 170kHz Taktfrequenz komme ich auf 56ms für einen kompletten Refresh. Bei 500kHz Taktfrequenz komme ich auf 19ms für einen kompletten Refresh. Dabei übertrage ich die Daten in 8 Blöcken (Pages) und rufe zwischen den Blöcken jeweils einmal yield() auf, damit der Watchdog nicht triggert. So oft ist das vermutlich nicht nötig, aber das hat ohnehin keinen großen Einfluss auf die Gesamt Performance. Meine vorherige Aussage, dass mehr als 20 Refreshes pro Sekunde nicht gehen muss ich somit revidieren.
Stefan U. schrieb: > richtig. Ich meinte dass die Schreibzugriffe über I²C mit den internen > Lesezugriffen der Displays selbst konkurrieren. Ach so; das habe ich natürlich nicht bedacht. Da müsste man zur genaueren Analyse wohl wirklich mal einen Logicanalyzer anschließen. Nur habe ich so ein Teil, wie geschrieben, nicht. Stefan U. schrieb: > Der ESP8266 hat soweit ich weiß keine echte I²C Schnittstelle (in > Hardware). Exakt richtig. c-hater schrieb: > Man benutzt > einfach einen Fade-Effekt, um den Übergang optisch weniger störend > wirkend zu lassen. Das wird auf einem Display mit 1 Bit Farbtiefe eher schwierig … Stefan U. schrieb: > Ich schätze dass dort nicht das ganze Bild neu gezeichnet wird, sondern > nur wirklich geänderten Stellen. Das vermute ich auch. Stefan U. schrieb: > Bei 170kHz Taktfrequenz komme ich auf 56ms für einen kompletten Refresh. > Bei 500kHz Taktfrequenz komme ich auf 19ms für einen kompletten Refresh. Dann stellt sich umso mehr die Frage, was bei mir schief läuft. Vielleicht sollte ich ja mal testweise das Display an einen zweiten Bus anschließen und somit vom Sensor entkoppeln. Denkt ihr, das könnte etwas bringen?
Stefan U. schrieb: > Man muss angeben, ab welche Adresse man schreiben will. Dann kann > man > nicht das ganze RAM in einem Zug füllen, weil der auto-increment nur bis > 256 zählen kann. Und außerdem konkurrieren Schreibzugriffe mit > Lesezugriffen, was auch noch etwas zur Verlangsamung führt. Ich hab jetzt nicht intensiv nachgesehen, ob die Ansteuerung des SSD1306 per I2C wirklich gegenüber SPI stark eingeschränkt ist, aber zumindest bei SPI gibt es keine Einschränkungen beim Autoinkrement. Den ganzen Speicher kann man in einem Rutsch schreiben. Das ist praktisch, weil das so schön per DMA geht, auch lässt sich der SSD meiner Erfahrung nach auch mit SPI-Frequenzen jenseits der 10MHz fehlerfrei betreiben. Effektiv sind nach Erst-Initialisierung nur die paar Befehle zum Anstossen des DMA nötig. Damit erreicht man Refresh-Raten jenseits von gut und böse.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.