2.4" TFT 240x320 Vs CYD ESP32-2432S028

I have created a photo album using an ESP32 and a red 2.4" TFT 240x320 display. The images are crisp and look really good. The 2 libraries used are:

#include <TFT_eSPI.h>
// JPEG decoder library
#include <JPEGDecoder.h>

Now, I thought I’d try the same sketch on the CYD (Cheap Yellow Display (ESP32-2432S028)) or what ever you call it and the images look bad. I’ve adjusted the brightness using this:

void TFT_SET_BL(uint8_t Value) {
  if (Value < 0 || Value > 100) {
    printf("TFT_SET_BL Error \r\n");
  } else {
    analogWrite(TFT_BL, Value * 2.55);
  }
}

And this in the setup which didn’t solve the issue:

  //TFT_SET_BL(100);  // full brightness
  TFT_SET_BL(100);   // TFT_SET_BL(50) = 50% brightness
  //TFT_SET_BL(0);    // backlight off

The contrast on the CYD seems to be out and looks like the image is fading half way into a negative. I did initially think it was the TFT_INVERSION setting in the TFT_eSPI User_Setup.h file. I’ve tried both settings.

#define TFT_INVERSION_ON
//#define TFT_INVERSION_OFF

I thought with using the same libraries on the 2 screens the images would be identical but they aren’t. The cheaper red 2.4” TFT has a really great image displayed but the CYD is crap.

Any ideas?

Hi @lexter333 ,

Before I reply to this thread, I'd like to see if the next thread you asked about has been resolved.

I provided the code in the post #6, and also posted a link to my Github post with code using CYD and TFT_eSPI in post #3.

You're free to change the direction of your project, but I'm not going to waste my time on someone who doesn't care about the people who've spent their time on you.

1 Like

Yes that has been resolved (ish). I changed the file types to .jpg and used the JPEGDecoder.h instead and the result as above works fine. No matter what I tried with the png files it kept failing. I seen a post on another site and it worked great.

Okay, that's find. I'd appreciate it if you could post the solution you found so that others can benefit.

Regarding the color issue, there are two types of 2.8-inch CYDs, depending on the number of USB ports.

The "User_Setup.h" sample for each is below, so you may find it useful.

Regarding LCD brightness adjustment, the CYD's backlight pin appears to be a digital pin. This means PWM control is required, but the following code did not work.

#define TFT_BL_PWM_FREQUECCY 12000 // [Hz]
#define TFT_BL_PWM_RESOUTION 8 // [bit]

ledcAttach(TFT_BL, TFT_BL_PWM_FREQUECCY, TFT_BL_PWM_RESOUTION); // Configure the PWM pin with frequency resolution
ledcWrite(TFT_BL, 255); // duty: 0 to 255

It may need to send a command to the LCD driver.

If you want to control the LCD brightness, use LovyanGFX instead of TFT_eSPI. You can install it from the Library Manager.

LovyanGFX has an automatic CYD detection function, so complicated settings like "Uset_Setup.h" are unnecessary.

Instead of #include "TFT_eSPI.h", use the following.

#if   0

  #include <TFT_eSPI>
  TFT_eSPI tft = TFT_eSPI();

#else

  #define LGFX_AUTODETECT
  #include <LovyanGFX.h>
  LGFX tft;

#endif

With LovyanGFX, the brightness can be controlled using the following:

tft.setBrightness(255); // duty: 0 to 255

However, even if you specify the maximum duty, the brightness will not be brighter than the value set in TFT_eSPI as follows:

pinMode(TFT_BL, OUTPUT);
digitalWrite(TFT_BL, HIGH);

Here is sample code using LovyanGFX for the 2.8-inch CYD.

/*================================================================================
 * Loading PNG / JPEG files from SD card to LCD with LovyanGFX
 *================================================================================*/
#include <SD.h>

#define LGFX_AUTODETECT
#include <LovyanGFX.h>
static LGFX tft;

/*--------------------------------------------------------------------------------
 * SD chip select pin and SPI clock frequency
 *--------------------------------------------------------------------------------*/
#define SD_CS         SS        // defined in pins_arduino.h
#define SD_SPI_CLOCK  24000000  // 24 MHz for ESP32-2432S028
#define SD_CONFIG     SD_CS, SPI, SD_SPI_CLOCK

/*--------------------------------------------------------------------------------
 * TFT settings
 *--------------------------------------------------------------------------------*/
#define TFT_WIDTH   240
#define TFT_HEIGHT  320
#define TFT_ROTATION  0

/*--------------------------------------------------------------------------------
 * Global variables
 *--------------------------------------------------------------------------------*/

void setup(void) {
  tft.init();                             // Start the tft display
  tft.initDMA();                          // Enable DMA
  tft.setRotation(TFT_ROTATION);          // Set the TFT display rotation
  tft.fillScreen(TFT_WHITE);              // Clear the screen before writing to it
  tft.setTextColor(TFT_BLACK, TFT_WHITE); // Set text color black in white
  tft.setBrightness(255);                 // Duty: 0 to 255

  if (!SD.begin(SD_CONFIG)) {
    tft.print("SD Card initialization failed!");
    while (true);
  }
}

void loop(void) {
  File root = SD.open("/");
  while (true) {
    File myFile = root.openNextFile();
    if (!myFile) {
      root.rewindDirectory(); // No more files, rewind or break
      break;
    }

    if (myFile.isDirectory()) {
      myFile.close();
      continue;
    }

    const char *name = myFile.name();
    if (name[0] == '.') {
      myFile.close();
      continue;
    }

    std::string path = std::string("/") + name;

    if (strstr(name, ".png")) {
      tft.drawPngFile(SD, path.c_str(), 0, 0);
      delay(5000);
    }

    else if (strstr(name, ".jpg") || strstr(name, ".jpeg")) {
      tft.drawJpgFile(SD, path.c_str(), 0, 0);
      delay(5000);
    }

    myFile.close();
  }

  root.close();
}

No image decoding library is required.

The following functions can load and display an image file directly from the SD card.

tft.drawBmpFile(SD, "/sample.bmp");
tft.drawPngFile(SD, "/sample.png");
tft.drawJpgFile(SD, "/sample.jpg");
1 Like

Just tried this using about 40 .jpg files on the SD card

/*================================================================================
 * Loading PNG / JPEG files from SD card to LCD with LovyanGFX
 *================================================================================*/
#include <SD.h>

#define LGFX_AUTODETECT
#include <LovyanGFX.h>
static LGFX tft;

/*--------------------------------------------------------------------------------
 * SD chip select pin and SPI clock frequency
 *--------------------------------------------------------------------------------*/
#define SD_CS         SS        // defined in pins_arduino.h
#define SD_SPI_CLOCK  24000000  // 24 MHz for ESP32-2432S028
#define SD_CONFIG     SD_CS, SPI, SD_SPI_CLOCK

/*--------------------------------------------------------------------------------
 * TFT settings
 *--------------------------------------------------------------------------------*/
#define TFT_WIDTH   240
#define TFT_HEIGHT  320
#define TFT_ROTATION  0

/*--------------------------------------------------------------------------------
 * Global variables
 *--------------------------------------------------------------------------------*/

void setup(void) {
  tft.init();                             // Start the tft display
  tft.initDMA();                          // Enable DMA
  tft.setRotation(TFT_ROTATION);          // Set the TFT display rotation
  tft.fillScreen(TFT_WHITE);              // Clear the screen before writing to it
  tft.setTextColor(TFT_BLACK, TFT_WHITE); // Set text color black in white
  tft.setBrightness(255);                 // Duty: 0 to 255

  if (!SD.begin(SD_CONFIG)) {
    tft.print("SD Card initialization failed!");
    while (true);
  }
}

void loop(void) {
  File root = SD.open("/");
  while (true) {
    File myFile = root.openNextFile();
    if (!myFile) {
      root.rewindDirectory(); // No more files, rewind or break
      break;
    }

    if (myFile.isDirectory()) {
      myFile.close();
      continue;
    }

    const char *name = myFile.name();
    if (name[0] == '.') {
      myFile.close();
      continue;
    }

    std::string path = std::string("/") + name;

    if (strstr(name, ".png")) {
      tft.drawPngFile(SD, path.c_str(), 0, 0);
      delay(5000);
    }

    else if (strstr(name, ".jpg") || strstr(name, ".jpeg")) {
      tft.drawJpgFile(SD, path.c_str(), 0, 0);
      delay(5000);
    }

    myFile.close();
  }

  root.close();
}

and all I get is a black screen. No errors in the serial monitor. If the above code works for you I’d like to get it up and running. Any advice?

After trying all the above the images are still poor quality.

The program I posted requires that all photos be saved in the root folder of the SD card.

If you want to display photos in a subfolder, modify the program by referring to listDir() in SD_Test.ino.

"poor quality" is a subjective matter, so it's hard to say.

In another thread you reported:

The technical answer to your representation is as follows:

There are two types of CYD LCD devices on the market: ILI9341 and ST7789. As long as the RGB order is configured correctly, color reproducibility will vary slightly depending on the device type.

If you refer to How do I know if a display is a CYD?, you can identify which device you have by looking at the following diagram.

I own one of each, and it's true that the color reproducibility of each is slightly different.

Both devices are limited to a 16-bit wide color (RGB565, i.e. 5 bits for R and B, 6 bits for G), so if you want better quality, you'll want to use a 24-bit wide (RGB888, i.e. everything is 8-bit) LCD.

Good luck.

I'm very sorry, but the code I posted was confirmed to work with the ILI9341, but when I checked it again with the ST7789 type, it seems that there are some models for which automatic detection does not work :sweat_smile:

This time I will share code that works on an ST7789 type board:

/*================================================================================
 * Loading PNG / JPEG files from SD card to LCD with LovyanGFX
 *================================================================================*/
#include <SD.h>

// Auto-detect and manual configuration settings
#define USE_AUTODETECT false

#if USE_AUTODETECT
// Some devices do not support auto-detect since the panel ID cannot be read.
#define LGFX_AUTODETECT
#include <LovyanGFX.h>
#else
// false: Panel driver: ILI9341 (micro-USB x 1 type)
// true : Panel driver: ST7789  (micro-USB x 1 + USB-C x 1 type)
#define DISPLAY_CYD_2USB  true
#include "LGFX_ESP32_2432S028R_CYD.hpp"
#endif // USE_AUTODETECT

static LGFX tft;

/*--------------------------------------------------------------------------------
 * SD chip select pin and SPI clock frequency
 *--------------------------------------------------------------------------------*/
#define SD_CS         SS        // defined in pins_arduino.h
#define SD_SPI_CLOCK  24000000  // 24 MHz for ESP32-2432S028
#define SD_CONFIG     SD_CS, SPI, SD_SPI_CLOCK

/*--------------------------------------------------------------------------------
 * TFT settings
 *--------------------------------------------------------------------------------*/
#define TFT_WIDTH   240
#define TFT_HEIGHT  320
#define TFT_ROTATION  0

/*--------------------------------------------------------------------------------
 * Global variables
 *--------------------------------------------------------------------------------*/

void setup(void) {
  tft.init();                             // Start the tft display
  tft.initDMA();                          // Enable DMA
  tft.setRotation(TFT_ROTATION);          // Set the TFT display rotation
  tft.fillScreen(TFT_WHITE);              // Clear the screen before writing to it
  tft.setTextColor(TFT_BLACK, TFT_WHITE); // Set text color black in white
  tft.setBrightness(255);                 // Duty: 0 to 255

  if (!SD.begin(SD_CONFIG)) {
    tft.print("SD Card initialization failed!");
    while (true);
  }
}

void loop(void) {
  File root = SD.open("/");
  while (true) {
    File myFile = root.openNextFile();
    if (!myFile) {
      root.rewindDirectory(); // No more files, rewind or break
      break;
    }

    if (myFile.isDirectory()) {
      myFile.close();
      continue;
    }

    const char *name = myFile.name();
    if (name[0] == '.') {
      myFile.close();
      continue;
    }

    std::string path = std::string("/") + name;

    if (strstr(name, ".png")) {
      tft.drawPngFile(SD, path.c_str(), 0, 0);
      delay(5000);
    }

    else if (strstr(name, ".jpg") || strstr(name, ".jpeg")) {
      tft.drawJpgFile(SD, path.c_str(), 0, 0);
      delay(5000);
    }

    else if (strstr(name, ".qoi")) {
      tft.drawQoiFile(SD, path.c_str(), 0, 0);
      delay(5000);
    }

    myFile.close();
  }

  root.close();
}

Save the following file as LGFX_ESP32_2432S028R_CYD.hpp in the same folder as the above sketch:

LGFX_ESP32_2432S028R_CYD.hpp
#pragma once

#include <LovyanGFX.hpp>

// Example of settings for LovyanGFX on ESP32
// https://github.com/espressif/arduino-esp32/blob/master/variants/jczn_2432s028r/pins_arduino.h

/*
Copy this file, give it a new name, and change the settings to suit your environment.
The created file can be used by including it in your user program.

The new file can also be placed in the "lgfx_user" folder of the library,
but please note that in this case it may be deleted when the library is updated.

To operate safely, make a backup or place it in the user project folder.
//*/

// false: Panel driver: ILI9341 (micro-USB x 1 type)
// true : Panel driver: ST7789  (micro-USB x 1 + USB-C x 1 type)
#ifndef DISPLAY_CYD_2USB
#error DISPLAY_CYD_2USB should be defined.
#endif

/// Create a class for your own settings by deriving from LGFX_Device.
class LGFX : public lgfx::LGFX_Device
{
/*
You can change the class name from "LGFX" to a different name.
When using with AUTODETECT, "LGFX" is used, so change it to a name other than LGFX.
Also, if you are using multiple panels at the same time, give each panel a different name.
If you change the class name, you must also change the constructor name to the same name.

You can name it whatever you like, but in case the number of settings increases,
for example, if you are setting up an SPI-connected ILI9341 with ESP32 DevKit-C, 
you can name it like LGFX_DevKitC_SPI_ILI9341 to match the file name and class name, 
which will make it less confusing when using it.
//*/

// Select an instance that matches the type of panel.
//lgfx::Panel_GC9A01      _panel_instance;
//lgfx::Panel_GDEW0154M09 _panel_instance;
//lgfx::Panel_HX8357B     _panel_instance;
//lgfx::Panel_HX8357D     _panel_instance;
//lgfx::Panel_ILI9163     _panel_instance;
//lgfx::Panel_ILI9341     _panel_instance;
//lgfx::Panel_ILI9342     _panel_instance;
//lgfx::Panel_ILI9481     _panel_instance;
//lgfx::Panel_ILI9486     _panel_instance;
//lgfx::Panel_ILI9488     _panel_instance;
//lgfx::Panel_IT8951      _panel_instance;
//lgfx::Panel_RA8875      _panel_instance;
//lgfx::Panel_SH110x      _panel_instance; // SH1106, SH1107
//lgfx::Panel_SSD1306     _panel_instance;
//lgfx::Panel_SSD1327     _panel_instance;
//lgfx::Panel_SSD1331     _panel_instance;
//lgfx::Panel_SSD1351     _panel_instance; // SSD1351, SSD1357
//lgfx::Panel_SSD1963     _panel_instance;
//lgfx::Panel_ST7735      _panel_instance;
//lgfx::Panel_ST7735S     _panel_instance;
//lgfx::Panel_ST7789      _panel_instance;
//lgfx::Panel_ST7796      _panel_instance;

#if DISPLAY_CYD_2USB
  lgfx::Panel_ST7789      _panel_instance;
#else
  lgfx::Panel_ILI9341     _panel_instance;
#endif

// Select an instance that matches the type of bus for your panel.
  lgfx::Bus_SPI       _bus_instance;   // SPI bus instance
//lgfx::Bus_I2C       _bus_instance;   // I2C bus instance (ESP32 only)
//lgfx::Bus_Parallel8 _bus_instance;   // 8-bit parallel bus instance (ESP32 only)

// If backlight control is possible, set an instance. (Delete if not needed)
  lgfx::Light_PWM     _light_instance;

// Select an instance that matches the touch screen type. (Delete if not needed)
//lgfx::Touch_CST816S          _touch_instance;
//lgfx::Touch_FT5x06           _touch_instance; // FT5206, FT5306, FT5406, FT6206, FT6236, FT6336, FT6436
//lgfx::Touch_GSL1680E_800x480 _touch_instance; // GSL_1680E, 1688E, 2681B, 2682B
//lgfx::Touch_GSL1680F_800x480 _touch_instance;
//lgfx::Touch_GSL1680F_480x272 _touch_instance;
//lgfx::Touch_GSLx680_320x320  _touch_instance;
//lgfx::Touch_GT911            _touch_instance;
//lgfx::Touch_STMPE610         _touch_instance;
//lgfx::Touch_TT21xxx          _touch_instance; // TT21100
  lgfx::Touch_XPT2046          _touch_instance;

public:

  // Create a constructor and set various settings here.
  // When you change the class name, specify the same name for the constructor.
  LGFX(void)
  {
    { //Sets the bus control.
      auto cfg = _bus_instance.config();    // Get the bus configuration structure.
//*
// SPI bus settings
      cfg.spi_host = HSPI_HOST;     // Select the SPI (ESP32-S2,C3: SPI2_HOST or SPI3_HOST / ESP32: VSPI_HOST or HSPI_HOST)
      // Due to the ESP-IDF version upgrade, the VSPI_HOST and HSPI_HOST are deprecated, so if an error occurs, use SPI2_HOST and SPI3_HOST instead.
      cfg.spi_mode = 0;             // SPI communication mode (0 to 3)
#if DISPLAY_CYD_2USB
      cfg.freq_write = 80000000;    // SPI clock for transmit (Maximum 80MHz, rounded to an integer value of 80MHz)
#else
      cfg.freq_write = 40000000;    // SPI clock for transmit (Maximum 80MHz, rounded to an integer value of 80MHz)
#endif
      cfg.freq_read  = 16000000;    // SPI clock for receive
      cfg.spi_3wire  = false;       // Set to true if receive on the MOSI pin
      cfg.use_lock   = true;        // Set to true if transaction lock is used
      cfg.dma_channel = SPI_DMA_CH_AUTO; // Set the DMA channel (0=DMA not used / 1=1ch / 2=2ch / SPI_DMA_CH_AUTO=automatic)
      // Due to the ESP-IDF version upgrade, SPI_DMA_CH_AUTO is recommended. Specifying 1ch or 2ch is no longer recommended.
      cfg.pin_sclk = 14;            // Set the SPI SCLK pin [CYD_TFT_SCK]
      cfg.pin_mosi = 13;            // Set the SPI MOSI pin [CYD_TFT_MOSI]
      cfg.pin_miso = 12;            // Set the SPI MISO pin (-1 = disable) [CYD_TFT_MISO]
      cfg.pin_dc   = 2;             // Set the SPI D/C  pin (-1 = disable) [CYD_TFT_DC]
     // When you use a common SPI bus with the SD card, be sure to set MISO and do not omit it.
//*/
/*
// I2C bus settings
      cfg.i2c_port    = 0;          // Select the I2C port to use (0 or 1)
      cfg.freq_write  = 400000;     // Clock for transmit
      cfg.freq_read   = 400000;     // Clock for receive
      cfg.pin_sda     = 21;         // SDA pin number
      cfg.pin_scl     = 22;         // SCL pin number
      cfg.i2c_addr    = 0x3C;       // I2C device address
//*/
/*
// 8-bit parallel bus settings
      cfg.i2s_port = I2S_NUM_0;     // Select the I2S port to use (I2S_NUM_0 or I2S_NUM_1) (Use the I2S LCD mode of ESP32)
      cfg.freq_write = 20000000;    // Clock for transmit (Maximum 20MHz, rounded to an integer division of 80MHz)
      cfg.pin_wr =  4;              // WR pin number
      cfg.pin_rd =  2;              // RD pin number
      cfg.pin_rs = 15;              // RS(D/C) pin number
      cfg.pin_d0 = 12;              // D0 pin number
      cfg.pin_d1 = 13;              // D1 pin number
      cfg.pin_d2 = 26;              // D2 pin number
      cfg.pin_d3 = 25;              // D3 pin number
      cfg.pin_d4 = 17;              // D4 pin number
      cfg.pin_d5 = 16;              // D5 pin number
      cfg.pin_d6 = 27;              // D6 pin number
      cfg.pin_d7 = 14;              // D7 pin number
//*/

      _bus_instance.config(cfg);    // Configure setting values in the bus.
      _panel_instance.setBus(&_bus_instance); // Set the bus on the panel.
    }

    { // Configure the display panel control settings.
      auto cfg = _panel_instance.config();    // Get the structure for display panel settings.

      cfg.pin_cs           = 15;          // CS   pin number (-1 = disable) CYD_TFT_CS
      cfg.pin_rst          = -1;          // RST  pin number (-1 = disable) CYD_TFT_RS = CYD_TFT_CS, RESET is connected to board RST
      cfg.pin_busy         = -1;          // BUSY pin number (-1 = disable)

      // The following are set to general values, so try commenting out if you are unsure of.

      cfg.panel_width      =   240;  // Panel width
      cfg.panel_height     =   320;  // Panel height
      cfg.offset_x         =     0;  // Panel offset in X direction
      cfg.offset_y         =     0;  // Panel offset in Y direction
#if DISPLAY_CYD_2USB
      cfg.offset_rotation  =     0;  // Rotation direction offset 0~7 (4~7 are upside down)
      cfg.dummy_read_pixel =    16;  // Number of dummy read bits before pixel read
#else
      cfg.offset_rotation  =     2;  // Rotation direction offset 0~7 (4~7 are upside down)
      cfg.dummy_read_pixel =     8;  // Number of dummy read bits before pixel read
#endif
      cfg.dummy_read_bits  =     1;  // Number of dummy read bits before reading non-pixel data
      cfg.readable         =  true;  // Set to true if data can be read
      cfg.invert           = false;  // Set to true if the panel is inverted
      cfg.rgb_order        = false;  // Set to true if the red and blue of the panel are swapped
      cfg.dlen_16bit       = false;  // Set to true if the panel transmit data in 16-bit via 16-bit parallel or SPI
      cfg.bus_shared       = false;  // Set to true if the bus is shared with the SD card (The bus is controlled for drawJpg etc.)

// Set the following only if your display is misaligned, such as ST7735 or ILI9163, which have variable pixel counts.
      cfg.memory_width     =   240;  // Maximum width  supported by driver IC
      cfg.memory_height    =   320;  // Maximum height supported by driver IC

      _panel_instance.config(cfg);
    }

//*
    { // Set the backlight control. (Delete if not required)
      auto cfg = _light_instance.config();    // Get the backlight setting structure

      cfg.pin_bl = 21;              // Backlight pin number [CYD_TFT_BL]
      cfg.invert = false;           // Set to true if the backlight brightness is inverted
      cfg.freq   = 12000;           // Backlight PWM frequency
      cfg.pwm_channel = 7;          // The PWM channel number

      _light_instance.config(cfg);
      _panel_instance.setLight(&_light_instance);  // Set the backlight on the panel.
    }
//*/

//
    { // Configure touch screen control (delete if not needed)
      auto cfg = _touch_instance.config();

      cfg.x_min =  240;         // Minimum X value (raw value) from touch screen
      cfg.x_max = 3800;         // Maximum X value (raw value) from touch screen
      cfg.y_min = 3700;         // Minimum Y value (raw value) from touch screen
      cfg.y_max =  200;         // Maximum Y value (raw value) from touch screen
      cfg.pin_int = 36;         // Interrupt pin number [CYD_TP_IRQ]
      cfg.bus_shared = false;   // Set to true if the bus shared with the screen
#if DISPLAY_CYD_2USB
      cfg.offset_rotation = 2;  // Adjust when display and touch orientation do not match (0~7)
#else
      cfg.offset_rotation = 0;  // Adjust when display and touch orientation do not match (0~7)
#endif

// For SPI connection
      cfg.spi_host = -1;            // Select the SPI (HSPI_HOST or VSPI_HOST) or only XPT2046 can be set to -1.
      cfg.freq = 1000000;           // Set the SPI clock
      cfg.pin_sclk = 25;            // SCLK pin number [CYD_TP_CLK]
      cfg.pin_mosi = 32;            // MOSI pin number [CYD_TP_MOSI]
      cfg.pin_miso = 39;            // MISO pin number [CYD_TP_MISO]
      cfg.pin_cs   = 33;            // CS   pin number [CYD_TP_CS]

// For I2C connection
      //cfg.i2c_port = 1;      // Select the I2C (0 or 1)
      //cfg.i2c_addr = 0x38;   // I2C device addres
      //cfg.pin_sda  = 23;     // SDA pin number
      //cfg.pin_scl  = 32;     // SCL pin number
      //cfg.freq = 400000;     // Set the I2C clock

      _touch_instance.config(cfg);
      _panel_instance.setTouch(&_touch_instance);  // Set the touch screen on the panel.
    }
//*/

    setPanel(&_panel_instance); // Set the panel to be used.
  }
};

I have also attached a photo comparing the two. The left side is the ILI9341 type, and the right side is the ST7789 type.

ST7789 is slightly redder, and I agree with your subjective opinion.

EDIT: The original photo is here: Snow-capped mountain peak bathed in golden sunlight photo – Free Travel Image on Unsplash
In my opinion, the color reproducibility of the ST7789 is closer to the original.

You are an absolute star!!! That worked perfectly. I wouldn’t have been able to work that out myself. The JPG files are crisp, just like the red ILI9341. The images in the uploads a bit look poor but that is due to my phone. They are perfect. I cannot thank you enough.

I’m actually making a desktop photo album and digital radio for my wife’s work table. I’m using a ESP32-S3, a MAX98357A Audio Amplifier Module and a 3W / 8 ohm 2W Speaker.

I can only get the Audio.h to work with the S3 and I couldn’t get the red ILI9341 to work on that in conjunction with the Audio.h library. In fact I couldn’t get the ILI9341 to work on the S3 at all.

The Audio.h library will not work with the CYD but now I can use either Bluetooth, WiFi or a straight serial link to control the radio. I was actually impressed with the quality of the sound.

Once again thank you for your help with this and I hope other people get use from it.

I’m sure I will contact you again for help with other projects :slight_smile:

You're welcome!
I'm very glad to hear that :laughing:

Just one more question though. With not using TFT_eSPI how do I get the touch screen working? I’ve Googled it and apparently the LovyanGFX can detect the touch screen, All I need is to get it to display the X, Y & Z to the serial monitor and I’ll take it from there.

Thanks in advance

Hi, @lexter333

LovyanGFX is my favorite because it draws faster than TFT_eSPI, but the downside is that there is little information available in English :wink:

Using touch is very simple, you can get the coordinates by:

uint16_t x, y;
if (tft.getTouch(&x, &y)) {
  do_something(x, y);
}

I think the default settings provide a decent level of touch coordinate accuracy.

However, a calibration method is prepared to improve pixel accuracy of touch coordinates, so I will post a sample code.

/*================================================================================
 * Touch screen test sketch for LovyanGFX
 *================================================================================*/

// Auto-detect and manual configuration settings
#define USE_AUTODETECT false

#if USE_AUTODETECT
// Some devices do not support auto-detect since the panel ID cannot be read.
#define LGFX_AUTODETECT
#include <LovyanGFX.h>
#else
// false: Panel driver: ILI9341 (micro-USB x 1 type)
// true : Panel driver: ST7789  (micro-USB x 1 + USB-C x 1 type)
#define DISPLAY_CYD_2USB  true
#include "LGFX_ESP32_2432S028R_CYD.hpp"
#endif // USE_AUTODETECT

static LGFX tft;

// Set to your screen resolution and rotation
#define TFT_WIDTH     240 // Panel width
#define TFT_HEIGHT    320 // Panel height
#define TFT_ROTATION  0   // 0, 2: Portrait / 1, 3: Landscape

//----------------------------------------------------------------------
// Perform the the touch panel calibration if it is set to true
//----------------------------------------------------------------------
#define EXEC_CALIBRATION false

#if EXEC_CALIBRATION
static void calibrate_touch(uint16_t cal[8]) {
  // Draw guide text on the screen.
  tft.setTextDatum(textdatum_t::middle_center);
  tft.drawString  ("Touch the arrow tips in order", tft.width() >> 1, tft.height() >> 1);
  tft.setTextDatum(textdatum_t::top_left);

  uint16_t fg = TFT_WHITE;
  uint16_t bg = TFT_BLACK;

  // Electronic Paper Display
  if (tft.isEPD()) {
    std::swap(fg, bg);
  }

  // You will need to calibrate by touching the four corners of the screen.
  tft.calibrateTouch(cal, fg, bg, std::max(tft.width(), tft.height()) >> 3);

  Serial.print("\nconst uint16_t cal[8] = { ");
  for (int i = 0; i < 8; i++) {
    Serial.printf("%d%s", cal[i], (i < 7 ? ", " : " };\n"));
  }
}
#endif // EXEC_CALIBRATION

static void tft_init(void) {
  tft.init();
  tft.initDMA();
  tft.setColorDepth(16);                  // Set to 16-bit (RGB565)
  tft.setRotation(TFT_ROTATION);          // Set panel rotation

  tft.clear(TFT_BLACK);                   // Clear screen with background color
  tft.setTextColor(TFT_WHITE, TFT_BLACK); // Set foreground color, background color
  tft.setFont(&fonts::Font2);             // https://lang-ship.com/blog/files/LovyanGFX/font/

  if (tft.touch()) {
#if EXEC_CALIBRATION
    uint16_t cal[8];
    calibrate_touch(cal);
#else
    // The following is equivalent to the `_touch_instance` setting in `LGFX_ESP32_2432S028R_CYD.hpp`.
    // The `cal[8]` can be replaced with the result displayed on the serial monitor after calibration.
    const uint16_t cal[8] = {
      240,   // x_min
      3700,  // y_min
      240,   // x_min
      200,   // y_max
      3800,  // x_max
      3700,  // y_min
      3800,  // x_max
      200    // y_max
    };
#endif
    tft.setTouchCalibrate((uint16_t*)cal);
  } else {
    Serial.println("Touch device not found.");
  }
}

void setup() {
  Serial.begin(115200);
  while (millis() < 1000);

  tft_init();
}

void loop() {
  uint16_t x, y;
  if (tft.getTouch(&x, &y)) {
    Serial.println("x: " + String(x) + ", y: " + String(y));

    // Draw a white spot at the detected coordinates
    tft.fillCircle(x, y, 2, TFT_WHITE);
  }
}

When you set the symbol EXEC_CALIBRATION to true, the following screen will be displayed to calibrate the touch panel. So touch the arrow tip in order.

Once you have finished touching the four arrows, the calibration results will be output to the serial monitor like the following:

const uint16_t cal[8] = { 252, 3700, 260, 187, 3762, 3726, 3796, 183 };

Replace this cal[8] setting with the following part of the code:

    // The following is equivalent to the `_touch_instance` setting in `LGFX_ESP32_2432S028R_CYD.hpp`.
    // The `cal[8]` can be replaced with the result displayed on the serial monitor after calibration.
    const uint16_t cal[8] = {
      240,   // x_min
      3700,  // y_min
      240,   // x_min
      200,   // y_max
      3800,  // x_max
      3700,  // y_min
      3800,  // x_max
      200    // y_max
    };

The sample sketch is a simple drawing program.


As a bonus, I'll share a cheat sheet for LovyanGFX.

Have fun!

Once again you have gone above and beyond with amazing detail :slightly_smiling_face: . I have only just got in from work at 2am so will be going to bed in a bit and then going hunting for a new car tomorrow so I’ll have a play either tomorrow evening or Thursday. I’ll let you know how I get on.

Thanks again for your help. It’s much appreciated.