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 ![]()
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.
