Falsche Farben bei LVGL - Endianess

OP #7899313
Lesenswert?

Ich nutze die LVGL-library zur Grafikdarstellung auf einem 1.5" Oled-Display. Kurz zusammengefasst: Das Display mit SSD1351-Controller hat 128x128 Pixel, jedes Pixel belegt 2 Bytes im RGB565-Format. Es wird von einem ESP32 gesteuert, der das Display über SPI mit Daten füttert. Initialisierungs- und Flushroutine habe ich selbst geschrieben und funktionieren auch soweit.

Allerdings werden völlig falsche Farben dargestellt. Die Ursache ist, dass LVGL die 16-bit Pixelwerte im Little-Endian-Format mit low-Byte voran im Framebuffer ablegt, das Display sie aber als Big-Endian haben will, also high-Byte zuerst. Dies ist in der Doku von LVGL auch beschrieben:

"You may set LV_COLOR_16_SWAP in lv_conf.h to swap bytes of RGB565 colors. You may need this when sending 16-bit colors via a byte-oriented interface like SPI. As 16-bit numbers are stored in little-endian format (lower byte at the lower address), the interface will send the lower byte first. However, displays usually need the higher byte first. A mismatch in the byte order will result in highly distorted colors."

Leider gibt es LV_COLOR_16_SWAP als Konfigurationsoption anscheinend nicht mehr. Wie mache ich das Vertauschen der Bytes dann? In der flush-Routine ist das leider nicht möglich, da LVGL oft nur Teile des Framebuffers neu beschreibt und ich daher für jedes einzelne Pixel Buch führen müsste, ob es schon getauscht wurde oder nicht.

#7899321
Lesenswert?

Fritz G. schrieb:

Wie mache ich das Vertauschen der Bytes dann?

Vertausche deine Eingangsdaten (Bilder). Das löst aber nicht das Problem, wenn du einzelne Punkte, Linei etc. zeichnen willst.

In der flush-Routine ist das leider nicht möglich, da LVGL oft nur Teile des Framebuffers neu beschreibt und ich daher für jedes einzelne Pixel Buch führen müsste, ob es schon getauscht wurde oder nicht.

Du muss die Vertauschung beim Schreiben auf das Display machen, wenn die aten per SPI gesendet werden. Dann ist ALLES korrekt.

OP #7899328
Lesenswert?

Falk B. schrieb:

Vertausche deine Eingangsdaten (Bilder). Das löst aber nicht das Problem, wenn du einzelne Punkte, Linei etc. zeichnen willst.

Richtig, insbesondere bei Text sieht es blöd aus. R mit B zu vertauschen (das kann der Display-Controller) ist auch nicht zielführend, denn aus RRRRRGGG GGGBBBBB wird GGGBBBBB RRRRRGGG. Die Farben werden also nicht nur vertauscht, sondern auch gemischt.

Du muss die Vertauschung beim Schreiben auf das Display machen, wenn die aten per SPI gesendet werden. Dann ist ALLES korrekt.

Nach etwas Suchen habe ich die Funktion

1
 lv_draw_sw_rgb565_swap

gefunden, die alle Bytes im Framebuffer vertauscht. Damit funktioniert es. LVGL scheint beim Rendern immer den kompletten Frame neu zu schreiben. Ich hätte gedacht, dass z.B. bei der Änderung weniger Pixel nur Teile davon geändert werden.

#7899333
Lesenswert?

Was für eine Version hast du denn genau von LVGL. Teilweise schreiben sie das die Funktion wieder dazu kam und man nur das define setzen müsse: https://github.com/lvgl/lvgl/issues/6317

Bzw in der letzten Version (9.3) schreiben sie in der Doku man solle die Funktion lv_draw_sw_rgb565_swap(buf, buf_size_in_px) in seinem Flush Callback oder evtl Hardware nutzen um zu Swappen:

https://docs.lvgl.io/9.3/details/main-modules/display/color_format.html#swapping-endian-ness

Edit: zu spät 😄

OP #7899572
Lesenswert?

N. M. schrieb:

Was für eine Version hast du denn genau von LVGL. Teilweise schreiben sie das die Funktion wieder dazu kam und man nur das define setzen müsse: https://github.com/lvgl/lvgl/issues/6317

Ich habe die neueste Version 9.3. Warum sie die Option aus der Konfiguration geworfen haben, erschließt sich mir nicht. Es gibt doch viele Farbdisplays mit SPI oder I2C-Interface.

Bzw in der letzten Version (9.3) schreiben sie in der Doku man solle die Funktion lv_draw_sw_rgb565_swap(buf, buf_size_in_px) in seinem Flush Callback oder evtl Hardware nutzen um zu Swappen:

https://docs.lvgl.io/9.3/details/main-modules/display/color_format.html#swapping-endian-ness

Leider funktioniert das nur eingeschränkt. Setze ich z.B. einen neuen Text in ein Label, wird nur das vom Label belegte Rechteck neu gerendert und es zerschießt ie Grafik. Nur wenn der Framebuffer komplett neu gezeichnet wird, funktioniert es. Das geht natürlich auf die Performance. In meiner Anwendung mit 128x128 Pixeln und einer Handvoll Widgets ist das allerdings kein Problem.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren