I’m totally new in ESP32 and CYD, as well I have basic knowledge of C++. I start with example project that I just doing LVGL demo widgets and start to adopt it for my needs. However, I realised that colors are inverted. It is pretty common problem. However, my code looks little bit different comparing to answers in other topics. So I confused.
None of them helps.
Next I found the remmendation to run tft.invertDisplay(1); after tft.init(); but my code looks like operate with highlevel wrapper, so I was not able to implement that.
Next, I have found the recommendation to run lv_draw_sw_rgb565_swap() it in the flush_cb. And implement it - no luck, however not sure if that was implemented correctly.
Code to reproduce
Here is some parts of my code. Setup of TFT.
#include <lvgl.h>
#include <lv_conf.h>
#include <TFT_eSPI.h>
#include <misc/lv_color.h>
#include <XPT2046_Touchscreen.h>
// Standard Libraries
// ----------------------------
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <ArduinoJson.h>
#include <StreamUtils.h>
#include <string>
#include <sstream>
#include <iomanip>
...
lv_indev_t * indev; //Touchscreen input device
uint8_t* draw_buf; //draw_buf is allocated on heap otherwise the static area is too big on ESP32 at compile
void setup()
{
//Some basic info on the Serial console
String LVGL_Arduino = "LVGL demo ";
LVGL_Arduino += String('V') + lv_version_major() + "." + lv_version_minor() + "." + lv_version_patch();
Serial.begin(115200);
Serial.println(LVGL_Arduino);
//Initialise the touchscreen
touchscreenSpi.begin(XPT2046_CLK, XPT2046_MISO, XPT2046_MOSI, XPT2046_CS); /* Start second SPI bus for touchscreen */
touchscreen.begin(touchscreenSpi); /* Touchscreen init */
touchscreen.setRotation(3); /* Inverted landscape orientation to match screen */
//Initialise LVGL
lv_init();
draw_buf = new uint8_t[DRAW_BUF_SIZE];
lv_display_t * disp;
disp = lv_tft_espi_create(TFT_HOR_RES, TFT_VER_RES, draw_buf, DRAW_BUF_SIZE);
//Initialize the XPT2046 input device driver
indev = lv_indev_create();
lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER);
lv_indev_set_read_cb(indev, my_touchpad_read);
//Done
Serial.println( "Setup done" );
}
void loop()
{
lv_tick_inc(millis() - lastTick); //Update the tick timer. Tick is new for LVGL 9
lastTick = millis();
lv_timer_handler(); //Update the UI
delay(5);
}
/* LVGL calls it when a rendered image needs to copied to the display*/
void my_disp_flush( lv_display_t *disp, const lv_area_t *area, uint8_t * px_map)
{
/*Call it to tell LVGL you are ready*/
Serial.println("Flush");
lv_draw_sw_rgb565_swap(draw_buf, DRAW_BUF_SIZE);
lv_disp_flush_ready(disp);
}
As far as I understand I should place lv_draw_sw_rgb565_swap in my_disp_flush function, which should automaticly called by LVGL as flush function (however, I do not see any binding of that function to LVGL code). But It does not helped. I put simple debug output in that function and there is no ouput as well. So looks like that function is not been called at all. So how could I invert colors in such code?
I’ve been struggling with this same problem on my CYD and tried all of the same settings with no success. I am very curious to see how you get it resolved.
I found a workaround hack to get my image to display properly. I opened my image in Photoshop and inverted the colors. Now when the CYD inverts them, it comes out proper. On Photoshop I used: Image>Adjustments>Invert. I believe GIMP has this feature as well as other image tools.
I ran into the same problem when I tried to get a demo program running on my CYD. For me, the solution was to uncomment the line “#define TFT_INVERSION_ON” in the User_Setup.h inside the display driver (TFT_eSPI) library directory.
The commented lines with the instructions and defines in that file to look for are:
// If colours are inverted (white shows as black) then uncomment one of the next
// 2 lines try both options, one of the options should correct the inversion.
// #define TFT_INVERSION_ON
// #define TFT_INVERSION_OFF
color inversion is a display setting on how the bits are stored in the GRAM of the display. if RGB values are 255, 0, 255 which is 11111111 00000000 11111111 in binary what it does is it stored that binary in the GRAM as 00000000 11111111 00000000 or 0, 255, 0. Some displays want the bits to be flip flopped, not sure why but that’s the way they are.
I ran into a case where the red and blue colors were swapped on a GC9307 display driver, while green was displayed correctly. The fix was simply to swap the red and blue channels. You can see my fix here:
If you encounter display color inversion, a good approach is to load a test image containing black, white, red, green, and blue. This makes it easier to identify which colors are inverted.
That does an in place modification of the buffer data…
If you need to perform a color order change from say RGB to BGR that would be done as a setting change on the display. You don’t have to do this in software. If you are using an RGB type connection to the display then you need to correct the connection from the display to the MCU. Most other displays whether it is an SPI or an I8080 display it will have a way to change the color byte order typically using the MADCTL register for the display.
The only time we usually see the need to perform a byte swap is ONLY when using RGB565 color depth and most of the time it typically needs to be done when using an SPI connection. This happens if the MCU handles the data in little endian and the display handles it in big endian or vice versa.
What your code looks to be doing is reversing an already byte swapped RGB565 buffer. It would be better to not have to iterate over the buffer to do that and to just display the byte swap in the first place.
I am not sure at what point in your code you are doing the reversal or what is doing the byte swap in the first place. If you are using an older version of LVGL < 9.0.* then you will want to set the LV_COLOR_16_SWAP macro to 0 and make sure that whatever driver library you are using is not swapping the bytes if it doesn’t need to be done.
It could be that you are having both LVGL and the display driver swapping the bytes which would cause the colors to appear incorrect so you stepping between them and flip flopping it makes it work correctly but is actually slowing things down a lot. The best way to correct the issue would be to disable the byte swapping in LVGL and remove your code and let the display driver handle it. You can also disable the display driver doing the swap and turn it on in LVGL and do a test to see if LVGL is faster and go with the driver if it is faster or go with LVGL if it is.
I just looked at your github repo and found the issue…
gfx->draw16bitBeRGBBitmap(x, y, data, w, h);
that call equates to this…
draw an RGB bitmap using 16bit color (rgb565) sending the data as Big endian (Be)
so changing that call to
gfx->draw16bitLeRGBBitmap(x, y, data, w, h);
and removing the order change you are doing should work. Doing that should turn off the byte swap that is happening in the display driver library you are using.