I absolutely love this library and I also really like this display. Now I have come to a problem that cost me a lot of sleep last night. I followed through today and this is what I have found so far:
Symptom 1: When I save a portion of graphics, overwrite it and then restore it with: tft.readRect(x, y, 20, 20, img); and tft.pushRect(x, y, 20, 20, img); I have noticed slight distortions. If you do it often enough, the original img is destroyed. I don’t use this THAT much in the project and eventually the screen is refreshed anyway, so I ignored it.
Symptom 2: I wrote a routine to save images to 16/24bpp BMP files and noticed that when I view those images in Windows, the colors are wrong. For example, yellow and orange are visually exactly the same.
Upon investigating, I have found that even readPixel() doesn’t read what you think you wrote on this display. Here a short demonstration
#include <TFT_eSPI.h> // Graphics library for display
TFT_eSPI tft = TFT_eSPI(); // Invoke TFT_eSPI library with default width and height (SPI)
void setup(){
Serial.begin(115200);
while((!Serial) & millis() < 5000) delay(1);
delay(5000); // Anti-bricking delay! Prevent rogue Serial activity from blocking uploads!
Serial.printf("\r\n\nFirmware:%s %s\r\n\n", // Add some blank space and the firmware date/time in the Serial monitor
__DATE__, __TIME__);
tft.begin();
tft.fillScreen(TFT_BLACK);
Serial.printf("Name fill read Result\n");
test("TFT_BLACK", TFT_BLACK); // 0x0000
test("TFT_WHITE", TFT_WHITE); // 0xFFFF
test("TFT_NAVY", TFT_NAVY); // 0x000F
test("TFT_DARKGREEN", TFT_DARKGREEN); // 0x03E0
test("TFT_DARKCYAN", TFT_DARKCYAN); // 0x03EF
test("TFT_MAROON", TFT_MAROON); // 0x7800
test("TFT_PURPLE", TFT_PURPLE); // 0x780F
test("TFT_OLIVE", TFT_OLIVE); // 0x7BE0
test("TFT_LIGHTGREY", TFT_LIGHTGREY); // 0xD69A
test("TFT_DARKGREY", TFT_DARKGREY); // 0x7BEF
test("TFT_BLUE", TFT_BLUE); // 0x001F
test("TFT_GREEN", TFT_GREEN); // 0x07E0
test("TFT_CYAN", TFT_CYAN); // 0x07FF
test("TFT_RED", TFT_RED); // 0xF800
test("TFT_MAGENTA", TFT_MAGENTA); // 0xF81F
test("TFT_YELLOW", TFT_YELLOW); // 0xFFE0
test("TFT_ORANGE", TFT_ORANGE); // 0xFDA0
test("TFT_GREENYELLOW", TFT_GREENYELLOW); // 0xB7E0
test("TFT_PINK", TFT_PINK); // 0xFE19
test("TFT_BROWN", TFT_BROWN); // 0x9A60
test("TFT_GOLD", TFT_GOLD); // 0xFEA0
test("TFT_SILVER", TFT_SILVER); // 0xC618
test("TFT_SKYBLUE", TFT_SKYBLUE); // 0x867D
test("TFT_VIOLET", TFT_VIOLET); // 0x915C
}
void test(char *nam, uint16_t clr){
tft.fillRect(0,0,5,5,clr);
uint16_t readpixel = tft.readPixel(2, 2);
Serial.printf("%-*s %04x %04x",20,nam,clr,readpixel);
if(!(clr == readpixel)){
char binClr[20];
char binPix[20];
binary(binClr,clr);
binary(binPix,readpixel);
Serial.printf(" %s -> %s\n",binClr,binPix);
} else {
Serial.printf("\n");
}
}
void binary(char buffer[], uint16_t val){
uint16_t mask = 0x8000;
for(int i = 0; i < 16; i++){
buffer[i] = mask & val ? '1' : '0';
mask = mask >> 1;
}
buffer[16] = 0;
}
void loop(){}
Which gives the following output:
Name fill read Result
TFT_BLACK 0000 0000
TFT_WHITE ffff ffff
TFT_NAVY 000f 001f 0000000000001111 -> 0000000000011111
TFT_DARKGREEN 03e0 07e0 0000001111100000 -> 0000011111100000
TFT_DARKCYAN 03ef 07ff 0000001111101111 -> 0000011111111111
TFT_MAROON 7800 f800 0111100000000000 -> 1111100000000000
TFT_PURPLE 780f f81f 0111100000001111 -> 1111100000011111
TFT_OLIVE 7be0 ffe0 0111101111100000 -> 1111111111100000
TFT_LIGHTGREY d69a ffbf 1101011010011010 -> 1111111110111111
TFT_DARKGREY 7bef ffff 0111101111101111 -> 1111111111111111
TFT_BLUE 001f 003f 0000000000011111 -> 0000000000111111
TFT_GREEN 07e0 0fe0 0000011111100000 -> 0000111111100000
TFT_CYAN 07ff 0fff 0000011111111111 -> 0000111111111111
TFT_RED f800 f801 1111100000000000 -> 1111100000000001
TFT_MAGENTA f81f f83f 1111100000011111 -> 1111100000111111
TFT_YELLOW ffe0 ffe1 1111111111100000 -> 1111111111100001
TFT_ORANGE fda0 ffe1 1111110110100000 -> 1111111111100001
TFT_GREENYELLOW b7e0 ffe1 1011011111100000 -> 1111111111100001
TFT_PINK fe19 fe3b 1111111000011001 -> 1111111000111011
TFT_BROWN 9a60 bee1 1001101001100000 -> 1011111011100001
TFT_GOLD fea0 ffe1 1111111010100000 -> 1111111111100001
TFT_SILVER c618 ce39 1100011000011000 -> 1100111000111001
TFT_SKYBLUE 867d 8eff 1000011001111101 -> 1000111011111111
TFT_VIOLET 915c b3fd 1001000101011100 -> 1011001111111101
As you can see, when I fill an area with TFT_NAVY (0x000f), what readPixel() returns has an extra 1 (0x001f). The values appear to be shifted one bit. In some cases, the difference is radical. (TFT_GREENYELLOW, b7e0, ffe1)
I’ve poked in the library but haven’t found a bug yet. For the ST7796, it reads two bytes and returns that value. Can’t much go wrong there. Then it occurred to me that there may be something in the hardware that’s askew so I grabbed the datasheet and have come up with a suspicion:
The ST7796 supports multiple bit modes (page 153). Is it possible that this library THINKS it should be reading 16 bits but the hardware is actually in 18 or 24 bit mode - even though the 16bit writes produce the right colors?
I don’t think I can take this any further. Can anyone confirm the problem and maybe suggest how I can get it fixed?