problem with ST7789V displays: green value 1 (and every other uneven) is gray!

This drives me crazy! >:(

I've got 3 displays from "Electronic Assembly" with an ST7789V controller. (datasheet)

Driving them over 4 line SPI in 16 Bit RGB565 color mode.

the problem:
Green value/bit 1 gives a gray instead of a dark green.
so, 1st byte: 0b00000000, 2nd byte: 0b00100000

these bars are:
red=0, blue=0, green value 0, 1, 2 and 3

As you can see, the gray from bit 1 makes every other uneven green value also grayish.

In 18 Bit mode, it is displayed as it should be:

Red and blue are also fine in 16 Bit mode:

I've tested it with the TFT_eSPI and the Adafruit library and also "manually" sending the init commands/data and display data.
I've checked the datasheet several times and tried different settings with the image enhancement modes, gamma correction and even a custom LUT table.
But whatever I try, the 1st green bit is always displayed as gray. :confused:

I've also checked the SPI data with my logic analyzer. It's what it should be.

I hope someone can help me, because I'm out of ideas. :frowning:

Please post a link to the actual display that you have bought. e.g. Electronic Arts sale page.

You had already said "ST7789V". So anyone can access the Sitronics datasheet.

It is the module pinout / pcb that we need to see.
I have a 666 library but life is simpler (and faster) with 565 pixels.

Think about it. You understand 18-bit pixels. The photos show 18-bit pixels.
However we can only guess whether you have a pcb or a bare panel.
And guess how many lines are on the panel ribbon.

David.

I'm no expert, never used these displays, but I have a hypothesis. Perhaps that lsb of green isn't really green at all. Perhaps there are 5 bits each of red, green and blue, and the extra bit adjusts the brightness of all 3 channels by 1 bit. Maybe this was done to ensure that the colour corresponding to all 15 bits set was white, as opposed to white with a green tinge?

david_prentice:
Please post a link to the actual display that you have bought. e.g. Electronic Arts sale page.
You had already said "ST7789V". So anyone can access the Sitronics datasheet.
It is the module pinout / pcb that we need to see.

Display 1:
https://shop.lcd-module.com/tft/2-0/2-tft-ips-for-spi-or-rgb.html

Display 2:
https://shop.lcd-module.com/tft/2-8/2-8-tft-ips-w-spi-or-rgb.html

david_prentice:
Think about it. You understand 18-bit pixels. The photos show 18-bit pixels.

What do you mean with "The photos show 18-bit pixels"?
There is 1 photo where I tested it in 18 bit mode. And it works.
But I have to use the 565 16 bit mode where it doesn't work.

PaulRB:
I'm no expert, never used these displays, but I have a hypothesis. Perhaps that lsb of green isn't really green at all. Perhaps there are 5 bits each of red, green and blue, and the extra bit adjusts the brightness of all 3 channels by 1 bit. Maybe this was done to ensure that the colour corresponding to all 15 bits set was white, as opposed to white with a green tinge?

No. As I've posted the screenshot from the datasheet.
It's 16 Bit. 5 bits red, 6 bits green, 5 bits blue.
RRRRRGGG|GGGBBBBB
In fact, I've never seen a 15 bit RGB555 display.
See attachment. LSB of green is G0

The controller features a look-up table for mapping <18 bit input to 18 bits what the display actually needs.
I've manually edited the two look-up tables for red and blue and it generally works. But still, with green=1, it adds red and blue, no matter what I do.

Ok, apologies for trying and failing to help. Good luck.

No apologies! As I'm completely stuck, I'm thankful for every input.

Thanks for the links. They show the pinout of the 39-way ribbon.

Which interface do you want to use ?
Personally, I would choose IM=0110 SPI with bidirectional SDA pin or IM=1110 SPI with separate SDI, SDO pins.

Bodmer's TFT_eSPI library should select 565-mode i.e. reg(0x3A)=0x55. I have used it with SPI ST7789 displays.
In fact everything should work straight out of the box.

You have an ESP8266, ESP32 or STM32 board (for TFT_eSPI library).
So you start off with the correct 3.3V GPIO levels.

Is your ribbon soldered to a pcb / adapter?
Or do you have a ZIF ribbon connector ?

David.

As mentioned, I’m using 4 line 8 Bit SPI.
I’m using an ESP32.
(also tested an UNO, as expected, doesn’t make a difference)

I connected the displays with the proper ZIF connectors.

Connection is okay. Otherwise there would be a lot more problems or no picture at all.

The logic analyzer shows, the transmitted (pixel-)data is what it should be:

I tested SPI frequency up to 80 MHz, but also 1 MHz.
Doesn’t make any difference regarding the “green/gray error”.

It looks like the display initialisation settings are wrong/messed up or gamma settings might be wrong for that display, the internal bias voltage settings are also critical and might vary between different supplier TFT pixel screens.

If in doubt, ask the supplier for the correct initialisation sequence.

This picture:

is the output from this sketch:

#include <SPI.h>
#include <TFT_eSPI.h>
TFT_eSPI tft;

void setup(void)
{
  tft.begin();
  tft.setRotation(1);
  tft.fillScreen(TFT_BLACK);
}

void loop(void)
{
 uint16_t g = 0;

 for (int y = 0; y < 160; y+=40) {
   for (int x = 0; x < 320; x+=20) {
     tft.fillRect(x,y,20,40, g<<5);
     g++;
   }
 }
 while(1) yield();
}

I tested with TFT_eSPI, ESP32 and “Setup23_TTGO_TM.h” setup file. As you can see there is black plus the 63 green levels (i.e. all 6 bits of colour for green) and they seem reasonable in terms of brightness gradient steps. Note that the “viewing angle” is quite narrow on some displays to get the right colour gradient. The best angle is usually with the screen ribbon cable at the bottom and slightly tilted back (as these screens are typically designed for phones).

The test was with a TTGO TM board which is fitted with an ST7789 display, not sure if it is the “V” version though.

Thanks for your test.

The datasheet of the display includes a complete initialisation sequence.
I tried it, but it didn't solve the "gray green bit error".

I also tried the TFT_eSPI init, Adafruit init, another lib's init I found on the net, my own init sequence, etc.
Also different gammas. (again: from datasheet, chip default, TFT_eSPI, Adafruit, my own, ...)

I went through nearly every single setting of the ST7789V datasheet, checked the current settings and tried others.
Every single command works as described and does what it should do.

That's what your test looks on my display
(ignore the white overexposed lower part. I had to manually adjust the camera settings to get the more interesting upper part captured as it's seen by the eyes)

It's a high quality IPS screen. And sure, I checked under the "right angle".
But it's like my photos show it. It's definitely a gray and not a green.
And it's clearly visible, that there is a pattern (every second/uneven value) that shouldn't be there.

Under the microscope you can also see, that the red and blue subpixel light up even if the shoulnd't and make the pixel gray which should be green.
What you see here is green level 2 on the left and green level 3 on the right.

You could try only configuring the minimal register set as sometimes the defaults are OK. Since some registers are not reset you will need to power off the system for 30s so that past configuration settings get removed.

I tried the minimal init sequence by commenting out sections of the init code in the TFT_eSPI driver and the display still works fine:

{
  writecommand(ST7789_SLPOUT);   // Sleep out
  delay(120);

  writecommand(ST7789_NORON);    // Normal display mode on

  //------------------------------display and color format setting--------------------------------//
  writecommand(ST7789_MADCTL);
  //writedata(0x00);
  writedata(TFT_MAD_COLOR_ORDER);
/*
  // JLX240 display datasheet
  writecommand(0xB6);
  writedata(0x0A);
  writedata(0x82);
*/
  writecommand(ST7789_COLMOD);
  writedata(0x55);
  delay(10);
//*/
/*
  //--------------------------------ST7789V Frame rate setting----------------------------------//
  writecommand(ST7789_PORCTRL);
  writedata(0x0c);
  writedata(0x0c);
  writedata(0x00);
  writedata(0x33);
  writedata(0x33);

  writecommand(ST7789_GCTRL);      // Voltages: VGH / VGL
  writedata(0x35);
//*/
  //---------------------------------ST7789V Power setting--------------------------------------//
  //writecommand(ST7789_VCOMS);
  //writedata(0x28); // JLX240 display datasheet

  //writecommand(ST7789_LCMCTRL);
  //writedata(0x0C);

  //writecommand(ST7789_VDVVRHEN);
  //writedata(0x01);
  //writedata(0xFF);

  //writecommand(ST7789_VRHS);       // voltage VRHS
  //writedata(0x10);

  //writecommand(ST7789_VDVSET);
  //writedata(0x20);

  //writecommand(ST7789_FRCTR2);
  //writedata(0x0f);

  //writecommand(ST7789_PWCTRL1);
  //writedata(0xa4);
  //writedata(0xa1);

  //--------------------------------ST7789V gamma setting---------------------------------------//
  /*
  writecommand(ST7789_PVGAMCTRL);
  writedata(0xd0);
  writedata(0x00);
  writedata(0x02);
  writedata(0x07);
  writedata(0x0a);
  writedata(0x28);
  writedata(0x32);
  writedata(0x44);
  writedata(0x42);
  writedata(0x06);
  writedata(0x0e);
  writedata(0x12);
  writedata(0x14);
  writedata(0x17);
*/
/*
  writecommand(ST7789_NVGAMCTRL);
  writedata(0xd0);
  writedata(0x00);
  writedata(0x02);
  writedata(0x07);
  writedata(0x0a);
  writedata(0x28);
  writedata(0x31);
  writedata(0x54);
  writedata(0x47);
  writedata(0x0e);
  writedata(0x1c);
  writedata(0x17);
  writedata(0x1b);
  writedata(0x1e);
*/
  writecommand(ST7789_INVON);

  writecommand(ST7789_CASET);    // Column address set
  writedata(0x00);
  writedata(0x00);
  writedata(0x00);
  writedata(0xE5);    // 239

  writecommand(ST7789_RASET);    // Row address set
  writedata(0x00);
  writedata(0x00);
  writedata(0x01);
  writedata(0x3F);    // 319

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

  end_tft_write();
  delay(120);
  begin_tft_write();

  writecommand(ST7789_DISPON);    //Display on
  delay(120);

#ifdef TFT_BL
  // Turn on the back-light LED
  digitalWrite(TFT_BL, HIGH);
  pinMode(TFT_BL, OUTPUT);
#endif
}

I tried sending the ILI9341 config data to the ST7789 display and get this image when using the same test sketch:

Although this image has issues with block placement (and fringing from camera<>display pixel aliasing) and poor colour gradient, there are clear indications that the LSB of green is invoking a greyness to blocks.

This again suggests problems with initialisation are likely to be the cause of your display problems. Perhaps it is best to use you display in 18 bit mode if that is all that works correctly but even then the brightness gradient does not look too good in those images either (but maybe this is the sketch used?)

I finally found the reason! :slight_smile:

RAM Control, RAMCTRL (B0h, see datasheet page 258) is missing in the init sequence.
Default value for the second parameter is F0, which means the bits for EPF[1:0] are 11, which causes exactly the behavior I noticed: the LSB of green is "copied" to the LSB of red and blue.

With the correct parameters in the init sequence:
writecommand(ST7789_RAMCTRL); // 0xB0
writedata(0x00);
writedata(0xC0); // 0xC0 instead of the default 0xF0

... it works now!

What I just don't understand is how it could then work for others.
The datasheet clearly states the default value which causes my problem.
I also checked the datasheets of other versions of this controller (7789V, VW, H2, ...).

Bluebrain:
the LSB of green is "copied" to the LSB of red and blue.

in other words

PaulRB:
the extra bit adjusts the brightness of all 3 channels by 1 bit.

In fact, you are right. :wink: But this would be an "abuse" of this 16>18 bit mapping function.

The controller has a separate, dedicated functions of controlling the brightness of the image, also a very nice "content adaptive" mode where the pixel brightness is raisen and the backlight power lowered to maintain the same visual appearance but with less power consumption.

Great to hear it is working now.

It is usually best to start with the init sequence provided by the supplier (page 31 here).

It appears that the EXTC pin on the display you have is wired high, this means that command table 2 registers are available. Indeed this is impled, as the supplier provides the correct init values for the command table 2 registers...

The ST7789_RAMCTRL command value has no effect on my ST7789 display so my EXTC must be wired low (command table 2 registers not accessible) and I am guessing the register defaults are then loaded automatically from the programmed settings in the displays NVM.

If you get slight green colour casting in white+greys then you might find EPF=10 (supplier recommended default) fixes this as it expands the 5 bit colour to the full 6 bits in the upper half of the brightness range. This MS to LS bit copy method has a more significant effect when converting 5 bit to higher bit count colours, ie 5 to 8 bit where the MS 3 bits of the 5 bit colour are also coppied to the LS 3 bits of the 8 bit colour.

Very interesting and now it suddenly makes sense.

For the next time, I'll remember to dig even deeper into the datasheet.
Until now, I didn't have such a problem with a display. Either it worked "out of the box", or the problem was mostly obviois or common, like inverted colors, rotation, width/height, wrong IM settings, and so on...

Following your investigation I have updated the TFT_eSPI init commands to include the RAMCTRL register as I found it did have an effect on a TTGO T Display which uses the ST7789V.

This is interesting because I had previously tried to use the endianess bit in the RAMCTRL register to swap bytes for SPI transfers and it did not work on the TTGO TM display. This endianess bit does indeed work on the TTGO T Display though. So this was a useful find that you made.

I alrady saw your comment to my edit on github.
Great to hear that this will finally also help the community.