Forum: Mikrocontroller und Digitale Elektronik Falsche Farben bei LVGL - Endianess


von Fritz G. (fritz65)


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.

: Bearbeitet durch User
von Joachim B. (jar)


Lesenswert?

Fritz G. schrieb:
> Little-Endian-Format

sicher? meine Falschfarben bei TFT kamen vom GRB statt RGB Format.

Fritz G. schrieb:
> ich daher für jedes einzelne Pixel Buch
> führen müsste

woran klemmts, am Speicher?

von Falk B. (falk)


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.

von Fritz G. (fritz65)


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.

: Bearbeitet durch User
von Joachim B. (jar)


Lesenswert?

Fritz G. schrieb:
> für jedes einzelne Pixel Buch
> führen müsste

sind doch nur 32768 Byte, mit aktuellen µC (z.B. ESP32) sollte das 
möglich sein

von Oliver S. (oliverso)


Lesenswert?

https://github.com/lvgl/lvgl/blob/1e2261683e23fcb7e472a4baef3c4ebb2225d794/src/core/lv_refr.c#L1404

Das sollte dein Problem erst einmal lösen, und auch einen Hinweis drauf 
geben, wie das eigentlich in der aktuellen Version gehandelt wird.

Oliver

: Bearbeitet durch User
von N. M. (mani)


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 😄

: Bearbeitet durch User
von Fritz G. (fritz65)


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.

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
Noch kein Account? Hier anmelden.