Inverted screen and colors

Hi, I’m new to lvgl and I’m recreating someone’s project displaying a custom UI on a colmi p8 smart watch: GitHub - atc1441/ATCwatch: Custom Arduino C++ firmware for the P8 and PineTime plus many more DaFit Smartwatches

I’m using the portable Arduino IDE version which uses lv_arduino version 2.1.5 library.

So here is the problem:

  • The UI display is flipped from left to right(around Y axis), but the touch functionalities are not flipped (to access an icon on the right side I must touch the left side of the screen.
  • Colors are inverted: white is supposed to be black and green is supposed to be red etc.

So I tried tweaking the display.cpp file a bit but couldn’t get any results. I was wondering if it was possible to completely change the direction of X axis for the display only and invert colors.

Here is a picture of what I see:

VS what I should see:

Thanks!

Hello, there’s a setting in the LVGL config lv_conf.h file:

/*Swap the 2 bytes of RGB565 color. Useful if the display has an 8-bit interface (e.g. SPI)*/
#define LV_COLOR_16_SWAP 0

which might do the trick?
Otherwise you may want to change the flushing function: as far as I know LVGL always stores the colors in RGB order with the given color depth (8, 16, 32-bit). So in the display flush function you may want to change the order in which the colors are written.

LV16SWAP isnt problem source here maybe colours , but primary need solve mirror.
Show your code for disp flush callback. Maybe too MADCTL in driver registers isnt correct.

Here are both display.h and display.cpp file of the project.

display.h:
#pragma once

#include “Arduino.h”
#include “pinout.h”

#define ST77XX_SLPIN 0x10
#define ST77XX_SLPOUT 0x11
#define ST77XX_DISPOFF 0x28
#define ST77XX_DISPON 0x29

void init_display();
void display_enable(bool state);
void inc_tick();

void setAddrWindowDisplay(uint32_t x, uint32_t y, uint32_t w, uint32_t h);
void initDisplay();
void spiCommand(uint8_t d);
void startWrite_display(void);
void endWrite_display(void);

display.cpp:
#include “display.h”

#include <lvgl.h>
#include “fast_spi.h”
#include “images.h”
#include “battery.h”
#include “touch.h”
#include “accl.h”
#include “menu.h”
#include “ble.h”
#include “heartrate.h”
#include “backlight.h”
#include “inputoutput.h”
#include “bootloader.h”
#include “time.h”
#include “push.h”

#define buffer_lcd_size LV_HOR_RES_MAX * 30
static lv_disp_buf_t disp_buf;
static lv_color_t buf[buffer_lcd_size];

void my_disp_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p)
{
uint32_t w = (area->x2 - area->x1 + 1);
uint32_t h = (area->y2 - area->y1 + 1);
startWrite_display();
setAddrWindowDisplay(area->x1, area->y1, w, h);
write_fast_spi(reinterpret_cast<const uint8_t *>(color_p), (w * h * 2));
endWrite_display();
lv_disp_flush_ready(disp);
}

bool my_touchpad_read(lv_indev_drv_t * indev_driver, lv_indev_data_t * data)
{
bool touched = false;
touch_data_struct touch_data;
if (swipe_enabled()) {
get_read_touch();
touch_data = get_touch();
touched = (touch_data.event == 2) ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL;
get_new_touch_interrupt();
} else {
if (get_new_touch_interrupt()) {
touch_data = get_touch();
touched = (touch_data.gesture == TOUCH_SINGLE_CLICK) ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL;
} else {
touched = LV_INDEV_STATE_REL;
}
}
data->state = touched;
data->point.x = touch_data.xpos;
data->point.y = touch_data.ypos;
return false;
}

void inc_tick() {
lv_tick_inc(40);
}

void init_display() {
initDisplay();
lv_init();
lv_disp_buf_init(&disp_buf, buf, NULL, buffer_lcd_size);

lv_disp_drv_t disp_drv;
lv_disp_drv_init(&disp_drv);
disp_drv.hor_res = 240;
disp_drv.ver_res = 240;
disp_drv.flush_cb = my_disp_flush;
disp_drv.buffer = &disp_buf;
lv_disp_drv_register(&disp_drv);

lv_indev_drv_t indev_drv;
lv_indev_drv_init(&indev_drv);
indev_drv.type = LV_INDEV_TYPE_POINTER;
indev_drv.read_cb = my_touchpad_read;

lv_indev_drv_register(&indev_drv);

lv_theme_t *th = lv_theme_night_init(10, NULL);
lv_theme_set_current(th);
}

void display_enable(bool state) {
uint8_t temp[2];
startWrite_display();
if (state) {
spiCommand(ST77XX_DISPON);
spiCommand(ST77XX_SLPOUT);
} else {
spiCommand(ST77XX_SLPIN);
spiCommand(ST77XX_DISPOFF);
}
endWrite_display();
}

void setAddrWindowDisplay(uint32_t x, uint32_t y, uint32_t w, uint32_t h)
{
uint8_t temp[4];
//y += 180; // when rotated screen

spiCommand(0x2A);
temp[0] = (x >> 8);
temp[1] = x;
temp[2] = ((x + w - 1) >> 8);
temp[3] = (x + w - 1);
write_fast_spi(temp, 4);
spiCommand(0x2B);
temp[0] = (y >> 8 );
temp[1] = y;
temp[2] = ((y + h - 1) >> 8);
temp[3] = ((y + h - 1) & 0xFF);
write_fast_spi(temp, 4);
spiCommand(0x2C);
}

void initDisplay() {
uint8_t temp[25];
pinMode(LCD_CS, OUTPUT);
pinMode(LCD_RS, OUTPUT);
pinMode(LCD_RESET, OUTPUT);
pinMode(LCD_DET, OUTPUT);

digitalWrite(LCD_CS , HIGH);
digitalWrite(LCD_RS , HIGH);

digitalWrite(LCD_RESET, HIGH);
delay(20);
digitalWrite(LCD_RESET, LOW);
delay(100);
digitalWrite(LCD_RESET, HIGH);
delay(100);
startWrite_display();
spiCommand(54);
temp[0] = 0x00;//0xC0;// when rotated screen
write_fast_spi(temp, 1);
spiCommand(58);
temp[0] = 5;
write_fast_spi(temp, 1);
spiCommand(178);
temp[0] = 12;
temp[1] = 12;
temp[2] = 0;
temp[3] = 51;
temp[4] = 51;
write_fast_spi(temp, 5);
spiCommand(183);
temp[0] = 53;
write_fast_spi(temp, 1);
spiCommand(187);
temp[0] = 25;
write_fast_spi(temp, 1);
spiCommand(192);
temp[0] = 44;
write_fast_spi(temp, 1);
spiCommand(194);
temp[0] = 1;
write_fast_spi(temp, 1);
spiCommand(195);
temp[0] = 18;
write_fast_spi(temp, 1);
spiCommand(196);
temp[0] = 32;
write_fast_spi(temp, 1);
spiCommand(198);
temp[0] = 15;
write_fast_spi(temp, 1);
spiCommand(208);
temp[0] = 164;
temp[1] = 161;
write_fast_spi(temp, 2);
spiCommand(224);
temp[0] = 208;
temp[1] = 4;
temp[2] = 13;
temp[3] = 17;
temp[4] = 19;
temp[5] = 43;
temp[6] = 63;
temp[7] = 84;
temp[8] = 76;
temp[9] = 24;
temp[10] = 13;
temp[11] = 11;
temp[12] = 31;
temp[13] = 35;
write_fast_spi(temp, 14);
spiCommand(225);
temp[0] = 208;
temp[1] = 4;
temp[2] = 12;
temp[3] = 17;
temp[4] = 19;
temp[5] = 44;
temp[6] = 63;
temp[7] = 68;
temp[8] = 81;
temp[9] = 47;
temp[10] = 31;
temp[11] = 31;
temp[12] = 32;
temp[13] = 35;
write_fast_spi(temp, 14);
spiCommand(33);
spiCommand(17);
delay(120);
spiCommand(41);
spiCommand(0x11);
spiCommand(0x29);
endWrite_display();
}

void spiCommand(uint8_t d) {
digitalWrite(LCD_RS , LOW);
write_fast_spi(&d, 1);
digitalWrite(LCD_RS , HIGH);
}

void startWrite_display(void) {
enable_spi(true);
digitalWrite(LCD_CS , LOW);
}

void endWrite_display(void) {
digitalWrite(LCD_CS , HIGH);
enable_spi(false);
}

This code is pretty unreadable without comments. Try read and inspire here TFT_eSPI/TFT_Drivers/ST7735_Init.h at master · Bodmer/TFT_eSPI · GitHub

And test and check if color format and MADCTL reg in your code 54 set right values.

#define TFT_MADCTL  0x36
#define TFT_MAD_MY  0x80
#define TFT_MAD_MX  0x40
#define TFT_MAD_MV  0x20
#define TFT_MAD_ML  0x10
#define TFT_MAD_BGR 0x08
#define TFT_MAD_MH  0x04
#define TFT_MAD_RGB 0x00

Sorry to annoy, but in which file do you find those registers?

Ended up finding out. It looks like it isn’t a register problem.

In Adafruit_ST7735.h I got:

#define ST7735_MADCTL 0x36

In Adafruit_ST7735.cpp I got:

#define MADCTL_MY  0x80
#define MADCTL_MX  0x40
#define MADCTL_MV  0x20
#define MADCTL_ML  0x10
#define MADCTL_RGB 0x08
#define MADCTL_MH  0x04

Yes and in your init you can use defines or numbers. 0x36 = 54
And test changing for example
temp[0] = MADCTL_MX | TFT_MAD_BGR;

We got some progress thanks!
So I changed this part of code for:

  spiCommand(0x36);
  temp[0] = 0x40|0x08;//0x00;//0xC0;// when rotated screen
  write_fast_spi(temp, 1);

and it fixed the mirroring problem. But the inverted colors remain, I tried changing

#define LV_COLOR_16_SWAP 

and it was just making some textures rainbow like in this picture:

Hello, I am just trying to understand your code here. I still think the flush function is the issue but I have never worked with SPI displays before so its hard to figure out whats wrong. I’ve copy-pasted your code and formatted it a bit.
I suspect the flush function because I once had this issue too, and it was simply because I wrote the colors to the screen in the wrong order. BGR instead of RGB and vice versa.

void my_disp_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p)
{
  uint32_t w = (area->x2 - area->x1 + 1); //Probably correct? Placement of pixels seems fine
  uint32_t h = (area->y2 - area->y1 + 1); //Probably correct? Placement of pixels seems fine

  startWrite_display(); //Understood.
  setAddrWindowDisplay(area->x1, area->y1, w, h); //what does this do?

  /*This line is probably the issue! */
  write_fast_spi(reinterpret_cast<const uint8_t *>(color_p), (w * h * 2));

  endWrite_display(); //Understood.
  lv_disp_flush_ready(disp); //Understood.
}

Am I correct in saying that this function sets the start x and y drawing positions in SPI?

void setAddrWindowDisplay(uint32_t x, uint32_t y, uint32_t w, uint32_t h)
{
  uint8_t temp[4];
  //y += 180; // when rotated screen
  
  spiCommand(0x2A);
  temp[0] = (x >> 8);
  temp[1] = x;
  temp[2] = ((x + w - 1) >> 8);
  temp[3] = (x + w - 1);
  write_fast_spi(temp, 4);
  spiCommand(0x2B);
  temp[0] = (y >> 8 );
  temp[1] = y;
  temp[2] = ((y + h - 1) >> 8);
  temp[3] = ((y + h - 1) & 0xFF);
  write_fast_spi(temp, 4);
  spiCommand(0x2C);
}

So, I figure this is the problem

  write_fast_spi(reinterpret_cast<const uint8_t *>(color_p), (w * h * 2));

Could you explain what this function does?

Try locate in initdisplay command for invert display . If exist remove it , if not add…
And try 0x40 alone too.

I locate it for you
spiCommand(33);
change to
spiCommand(32);

Thank you so much it works!
0x40 alone indeed gives the best results and I modified to spiCommand(40) by error and it fixed the color inversion just like spiCommand(32).

To be honest I don’t even know myself. As I said previously, this code is taken from someone else’s project (which you can find in my first message).

All right… Well, good to hear it works.