Saturday, August 30, 2025

CYD: Cheap Yellow Display

 


The Cheap Yellow Display (CYD) is a 320x480 LCD display with resistive or capacitance touch capabilities, mounted on a PCB with its own ESP32, a TF-Card reader and many more features. 

This is another companion article for a much larger planned project.  I also cover a review of the CYD in this YouTube video which I recommend that you also watch as the information provided here is primarily in support of the video.

The CYD is, in essence, an ILI9341 or ST7796 display 'pre-mounted' on a PCB and connected to an ESP32.  I actually covered the ILI9341 in the following:


As you can see in those prior versions, using the ILI9241 display alone requires that you wire it to your own ESP32:




The CYD integrates the ESP32 onto the same PCB as the display and eliminates the need to make all these connections:


In addition, there are a number of GPIO pins from the ESP32 broken out to JST connectors and many other features.  I'll detail these shortly.

Parts List


This is a list of parts shown in this article or in the companion YouTube video.  Note that I will be testing and comparing two different 'variants' or clones of the CYD.  I'll try to always differentiate between the two versions when there are differences by using "Clone A" or "Clone B".  In addition, I am using the 3.5" display.  Other sizes are available, but should work in a similar manner.

Part/Item

Notes

CYD ESP32 - Resistive Touch

Clone “A” version

CYD ESP32 - Capacitance Touch

Clone “B” version

1.25 mm JST Connector Kit

 

 

 

Some of these links may be Amazon affiliate links.  Use of these links will not affect your pricing, but as an affiliate this blog may earn a small commission if you make a purchase.  

Clone "A" vs. Clone "B"


As I discovered with other components, like the APDS-9960, all clones are not created equal!  This might cause problems if trying to follow a tutorial, like this one from Random Nerd Tutorials that expect a very specific board type and may not work with yours.  For this reason, I'll be testing two different versions of the CYD from two different sellers.  I'll point out the major differences between these versions here, but more importantly I'll test both Arduino and ESPHome code on both versions to determine if they work as expected without modifying the library or configuration.

Click to enlarge

Just looking at the front side of the two different clones, there is already a difference.  Clone "B" has an RGB LED on the front and a light-dependent resistor (or photoresistor/light level sensor) on the front side.  While Clone A has the LED on the back (see below), it lacks the light level sensor.


There are many more differences on the back side, but the first thing to note is that the two boards appear to be using different ESP32 chips.



Clone "A" utilizes a standard ESP32 (commonly known as WROOM or DOWD) while Clone "B" uses an ESP32 from SparkleIoT, but at its root this is listed on the Amazon product page as an ESP32-S3.  This and difference in the onboard memory mean each clone appears to have some different specs:


Specs pulled from vendor's descriptions. Cost is amount paid at time of purchase (Amazon).

Clone "B" (or the supposed "S3" version) has slightly newer versions of the Xtensa processor and Bluetooth LE.  But the biggest difference is the amount of onboard flash.  While Clone "A" has 4 KB more RAM, the "S3" version has 32 MB of available flash vs. only 4 MB found on Clone "A".  The additional memory and touch type (see below) is probably what contributes to the higher price for the "S3" version.  But as you'll soon see, you can't necessary trust or believe the sales listing!

However there are other significant differences other than the processor and flash.  

Clone "A" (ESP32)


Click to enlarge

Clone "B" (ESP32-S3)

Click to enlarge


As you can see, there are numerous differences between the two boards.  First, the similarities:
  • Both boards have RESET and BOOT buttons
  • Both boards have a Speaker (I2S) interface
  • Both boards have a microSD card slot
  • Both boards have a 4-pin JST connection for serial/UART communication (VIN, GND, RX and TX)
But that's where the similarities end.

 

Clone “A”

Clone “B”

RGB LED

On back

On Front

Touch Type

Resistive

Capacitive

GPIO Breakouts*

8
(18,19,21,23,25,32,35,39)

3
(21,22,35)

Battery Interface

YES

No

Light Sensor

No

YES (on front)

USB Port

Type C

MicroUSB


* GPIOs broken out to JST headers. Not including RX/TX or GPIOs connected to other peripherals like the LED or MicroSD card reader.  Also does not include other GPIO pins that may be broken out to pads or other components on the board.

While both boards provide an RGB LED, Clone "A" has the LED on the back of the board while it is on the front edge of Clone "B".

Clone "A" uses resistive touch for the touch capabilities while Clone "B" uses capacitive touch.  I won't go into full details on the difference between the touch types here (look it up if you really want to know), but as a general rule capacitive touch is more accurate and also supports multiple touch (e.g. two-finger pinch to zoom) while resistive touch can be used with gloved fingers and other non-conductive items, such as a stylus.

As you can see, Clone "A" has significantly more GPIO pins broken out to JST headers.  Interestingly, it lists one JST connection as I2C and uses GPIO 25 and 32 (GPIO 21 and 22 are the general defaults for I2C on the ESP32... but of course other pins can be used).  It then has another header labeled SPI that provides access to GPIO 18, 19, 21 and 23... but again these can be repurposed if needed.

While Clone "B" only has 3 GPIO pins broken out to JST connectors, the standard I2C pins, GPIO21 and 22, are actually broken out to two different headers... one with 3.3V and GND and the other with GPIO35 and GND.  I suspect this is so more than one I2C device can be connected.  The "B" board also provides a number of surface pads that aren't present on Clone "A".  These pads may also connect to GPIO pins, but I won't be using or going into detail on these.  You'd need to find the documentation on these pads (or trace them yourself). 

A few of the surface pads on Clone "B"

Clone "A" provides a battery interface for powering the system via battery, but Clone "B" provides the light level sensor (on the front edge like the LED).

Standard Component GPIO Pins


Of course other board components, such as the display, touch screen, SD card reader, RGB LED, etc. use GPIO pins.  While there may be variations from board to board and not every board will have all options, the following are the defaults for the generic Cheap Yellow Display. But check your particular version and if documentation is provided, you should that instead of the following.

Display Pins
The TFT display communicates using SPI (HSPI)

SPI Pin

GPIO

MISO (TFT_MISO)

12

MOSI (TFT_MOSI)

13

SCLK (TFT_SCLK)

14

CS (TFT_CS)

15

DC (TFT_DC)

2

RST (TFT_RST)

-1

Backlight

21



Touchscreen Pins
The touchscreen uses SPI.  Note that your pins may be different depending upon whether the touchscreen uses resistance or capacitance touch.

Resistive Touch:

SPI Pin

GPIO

IRQ (XPT2046_IRQ)

36

MOSI (XPT2046_MOSI)

32

MISO (XPT2046_MISO)

39

CLK (XPT2046_CLK)

25

CS (XPT2046_CS)

33


Capacitive Touch:

I2C Pin

GPIO

SLC

32

SDA

33

RESET

25

INTERRUPT

21



RGB LED

 

GPIO

Red LED

4

Green LED

16

Blue LED

17



MicroSD Card
The  microSD card uses SPI and the ESP32's default VSPI pins

SPI Pin

GPIO

MISO

19

MOSI

23

SCK

18

CS

5



LDR (Light Dependent Resistor) - Light Level
Some board may not include this sensor

LDR

GPIO 34



Speaker
Most boards do not have an internal speaker, but contain a small DAC for connecting an external speaker. But you may need to add your own DAC for better/louder sound.

Speaker

GPIO 26



BOOT Button
Used to restart the board and in some cases, held down at power up to put the board into flashing mode.

BOOT Button

GPIO 0



Other Breakouts

As covered above, different versions of the board may break out other GPIO pins to JST headers.  Also note that for some components, a GPIO pin may be used or provided in more than one location. Check the documentation (if provide) and assure that you are using the GPIO pins properly for your project.

This diagram, provided by Github user ardnew (full repository) provides a nice overview of all the GPIO pins.

Click to enlarge

Of course other boards may have different components or even use a different ESP32 chip.  Unfortunately, unless your board provides specific documentation, you sometimes have to do a little research or some trial-and-error testing.

For my larger project, I don't expect to need many GPIO pins from this board.  The light level sensor, LED on front and the much larger flash size is more attractive for my end project, so I'd prefer to use the Clone "B" board, but I'll have to see how they behave with the Arduino libraries and ESPHome first.

To do that, it's time to setup a few bench tests.

Initial Power Up


According to some of the research I read in prep for using this board, it appears most versions have some basic firmware already installed.  So the first step is to simply power on the boards via the USB connection and see what happens!


As you can see, both boards do appear to have some sort of sample or demo firmware pre-installed.  Clone "A" appears to be running firmware called ESP32 Marauder, which is described as 'A suite of WiFi/Bluetooth offensive and defensive tools for the ESP32'.

Clone "B" appears to just be running a demo from the Arduino Light and Versatile Graphics Library (LVGL).

Clone "A" (ESP32) Resistive vs. Clone "B" Capacitance Touch

I spent some time playing around with the touch capabilities of both boards and their respective demo firmware.  Clone "A", with resistive touch required the stylus to be able to select menu items consistently.  And even then, I had to touch a point significantly lower than the menu item itself to select it:

I had to touch a point significantly below a menu item to select it

Now, this could probably be fixed with different calibration settings.  But this particular menu system had the options way too close together to be able to reliable use a bare finger.

Clone "B" with the capacitance touch was a completely different story.


I was able to consistently use a bare finger to select different elements on the screen.  Scrolling was smooth and easy to execute as well. Again, this could be a function of the firmware itself, but I will definitely want to use the capacitance touch for my planned project... assuming I can get the proper firmware/libraries or ESPHome code to work with the cloned version.

While the sample firmware is fun to play with for a bit and also allows basic functionality to be tested, you most likely are going to want to install your own firmware that meets the needs of your project.

I'll start with Arduino and then take a look at ESPHome.

Arduino Code and Testing



Before attempting to run any examples or writing your own code, there are a number of items that must first be determined.  The following assumes you have the Arduino IDE installed (v2.3.3 used for this article), along with the necessary boards for the ESP32.  If you have not used the Arduino IDE with ESP boards before, you  can review the following video for a setup and configuration how-to:

Click to launch video

Board Type (ESP32 Chip)

When creating an application (sketch) in Arduino, you must indicate the type of MCU or board that you are using.  To verify what was shown in the listing matches what is actually on the board, I connected each clone to ESPTool to read the chip.

On the Clone A chip, it shows ESP-32E and ESPTool returned the expected chip type:

This is just a standard ESP32, often found on development boards as ESP32-WROOM-32 and the actual chip is an ESP32-DOWD-V3. This matches what the Amazon listing stated.

Clone B however, which is advertised as having an ESP32-S3, returned the following via ESPTool:

Wait!  What's going on here?  ESPTool is reporting the same chip for Clone B as Clone A, yet Clone B is supposed to be an ESP32-S3.  Just to verify, I snagged a standard ESP32-S3 development board and ran ESPTool on that:


I was also skeptical of the advertised 32 MB of flash as the location where an external flash chip would be installed was empty in my Clone B version:


I was later able to confirm the flash size, both via the Arduino IDE and by attempting to upload a dummy .bin file using ESPHome Flasher:

Arduino IDE output


Both reported a flash size of 4 MB... but this is probably internal to the ESP32 chip. With no external flash (unless it is somewhere I'm not aware), then this board likely only has 4 MB of flash, like Clone "A"

So despite the product description on Amazon:

Clone "B" Amazon Listing

So despite what the Amazon listing states, the board I received is actually just a standard ESP32.  And it appears that there is only a total of 4 MB of flash and not the advertised 32 MB. It's possible that this board has been upgraded and I may have just received an older version that was still in stock.  But caveat emptor...

Side note: I posted my findings in an Amazon review.  Two days after I posted, the product description was updated and the "-S3" was removed from ESP32!  

Click to enlarge

On the plus side, this means both of my clones have the same ESP32 so I should also be able to use the same ESP board definition in Arduino:



Libraries and GPIO Pinouts

I listed standard GPIO pins for the CYD above.  But as I've shown, you can't always assume that a cloned board uses the same GPIO pinouts.  While the GPIO pins broken out to JST headers are generally labeled, the GPIO pins for other components, like the display, touch screen, LED, etc. also need to be known as most libraries will require that you configure these pins in the library header or your sketch.

At a minimum, a library will be needed for the display.  If you want to utilize touch, then you may need an additional library for that.  I also want to be able to use graphic controls, like buttons, sliders, etc., so I'll also want a graphics library.  So, for my planned project, I'll need at least:
      • Display Library (ST7796)
      • Touch Library (Resistive vs. Capacitance)
      • Graphics Library (LVGL)
Both of my clones specify that they use the ST7796 driver for the display, so any library selected must support this driver (in some cases, you may be able to also use a library for the ILI9341).

Since the touch technology uses are different for my two clones, I'll likely need different libraries for resistive vs. capacitive touch.

While most display libraries allow you to display graphics (static or moving) along with text, using a graphic library like the Light and Versatile Graphics Library (LVGL) will allow me to easily create controls like buttons, sliders, graphs and even an on-screen keyboard.


Of course, based on project needs, multiple other libraries may be needed, such as those for:
  • SD Card Reader
  • Audio/Speaker
  • Connected components (e.g. I2C, SPI)
  • WiFi, MQTT, etc.
This will likely require a lot of trial and error and in my case, a library that works with one clone might not work with the other, requiring a different library.  I'll save you all the testing I did and just list what I found that works (and what doesn't).

Display  (TFT_eSPI)

I initially tried a handful of libraries that were supposed made specifically for the Cheap Yellow Display, but I could not get any of them to work with my clones... most just resulted in a boot loop.  So I opted to use the TFT_eSPI library by Bodmer.  This has support for a large number of display and driver chips and also supports a wide range of ESP chips (and even some Raspberry Pi boards).  In fact, it includes configuration files for over 90 different types of displays.  It also has a large variety of examples and diagnostic tools as well.

Of course to support this wide variety of devices, different configuration files are needed.  And this could cause an issue if you want to use the library in more than one project that each use a different display/configuration.  To facilitate this situation, user configuration files can be created and used.  Despite quite a bit of documentation, this took me a bit to figure out.  To save you that effort, here's a overly simplified view of how it works:


You only need to include the main TFT_eSPI.h library in your main sketch.  The library, in turn, will look at the User_Setup_Select.h file in the main directory of the library (which can be found in the \libraries folder of the same location where your sketches are created... such as \My Documents\Arduino).

The User_Setup_Select.h file in turn simply includes a long list of board-specific configuration files, with the User_Setup.h being the enabled configuration by default.  Only one configuration file is 'enabled' in this list, with all others being remarked out.

The User_Setup.h file then has the specific configuration for the display, including things like the driver chip (e.g ILI9341, ST7796), which GPIO pins are used, the display resolution, rotation mode and a whole host of other settings.

So if you only have a single display and are only using this library for a single project, you could simply modify the User_Setup.h file for your board and be good to go.  But what if you have different displays used in different projects that both want to use this library?  Using just the User_Setup.h file, you'd have to modify the configuration and change all the settings each time you needed to recompile a project that uses a different board.  This is where the User_Setup_Select and the configurations found in the \User_Setups folder come in handy.

Partial Listing of the User_Setup_Select.h file

This file contains a long list of over 90 supported boards.  You simply select your board's configuration file and assure all other lines are commented out.  This means that switching from one board to another for different projects only means that you need to switch which configuration file is used here and you won't need to edit or change any actual configuration files.  In fact, if your board is one of the supported boards, you would only need to enable that board in this file (and disable all others) and you won't even need to set any GPIO pins or other configuration values!

For example, say I have a project that used an ESP8266 and an ILI9341.  The top of the User_Setup_Select.h would look like:

//#include <User_Setup.h> 
#include <User_Setups/Setup1_ILI9341.h> //ESP8266 & ILI9341
//#include <User_Setups/Setup2_ST7735.h>  //ESP8266 & ST7735
//#include <User_Setups/Setup3_ILI9163.h> //ESP8266 & ILI9163

But if I have another project that uses an ESP8266 and an ST7735, I don't need to edit any actual configuration files in terms of chips, GPIO pins, etc.  I just edit the User_Setup_Select.h file to enable a different configuration:

//#include <User_Setup.h> 
//#include <User_Setups/Setup1_ILI9341.h> //ESP8266 & ILI9341
#include <User_Setups/Setup2_ST7735.h>  //ESP8266 & ST7735
//#include <User_Setups/Setup3_ILI9163.h> //ESP8266 & ILI9163

By utilizing this method, instead of needing to modify multiple lines in the default user_setup.h file each time I switched displays/projects, I can just edit two lines in the select file, enabling the proper config and disabling any other config.

But what if your board, like my clones, isn't listed as one of the 'supported' boards?  Well, you can also create you own custom configuration files in the \User_Setups folder and add it to the User_Setup_Select.h file for easy selection.

Creating Custom Configs for Non-Listed Boards

To create a custom configuration, you can copy an existing file that is "close" to yours and modify it, or you can use the provided SetupX.h file as a template.  In most cases, you just go through the file, enabling options that apply and commenting out those that don't.  You will also set GPIO pins and things like the width and height of the display.  In my case, since I have two clones that may be different in terms of the configurations, I created two custom configuration files:

Setup501_CYD_A.h
Setup502_CYD_B.h
(I'll cover the configuration specifics for my clones in a minute)

Once you have created the configuration file(s), you just add them to the User_Setup_Select.h file:


I've added a line for each clone's configuration file.  Now when I want to work with Clone "A", I simply enable the 'CYD_A' configuration in the file.  When it's time to work with Clone "B", I comment out the 'CYD-A' line and enable the 'CYD-B' line:


I can now use this library with multiple projects and/or display types by simply making the one small change in the User_Setup_Select.h file and don't need to change any actual configuration files.

But what is in the configuration files for my two clones?

Clone 'A' & Clone 'B' Configuration

I started with the SetupX_Template.h file.  But the configuration files, which are generally over 500 lines long, mostly contains lists of options with many commented out and only one selected.  For example, all display drivers are listed but you only enable the one that matches your board.  For simplicity, here are the only lines that I enabled in the configuration file... and their corresponding values where appropriate:

//     USER DEFINED SETTINGS
// Set driver type, fonts to load, pins used, SPI control method etc.
//

#define USER_SETUP_ID 501  //Provide a unique ID

// ################################################################
// Section 1. Call up the right driver file and any options for it
// ################################################################

#define ST7796_DRIVER
#define TFT_RGB_ORDER TFT_BGR  // Colour order Blue-Green-Red
#define TFT_WIDTH  320 // Portrait mode
#define TFT_HEIGHT 480 // Portrait mode
#define TFT_INVERSION_OFF

// ##############################################################
// Section 2. Define the pins that are used for the display here
// #############################################################

#define TFT_BL   27            // LED back-light control pin
#define TFT_BACKLIGHT_ON HIGH  // Level to turn ON back-light

// ###### EDIT THE PIN NUMBERS IN THE LINES FOLLOWING TO SUIT YOUR ESP32 SETUP

#define TFT_MISO 12
#define TFT_MOSI 13
#define TFT_SCLK 14
#define TFT_CS   15  // Chip select control pin
#define TFT_DC    2  // Data Command control pin
#define TFT_RST  -1  // Set to -1 if RESET connected to ESP32 RST
#define TOUCH_CS 33  // Chip select pin (T_CS) of touch screen

// ####################################################
// Section 3. Define the fonts that are to be used here
// ####################################################

#define LOAD_GLCD   // Font 1. Original Adafruit 8 pixel font
#define LOAD_FONT2  // Font 2. Small 16 pixel high font
#define LOAD_FONT4  // Font 4. Medium 26 pixel high font
#define LOAD_FONT6  // Font 6. Large 48 pixel font
#define LOAD_FONT7  // Font 7. 7 segment 48 pixel font
#define LOAD_FONT8  // Font 8. Large 75 pixel font
#define LOAD_GFXFF  // FreeFonts

#define SMOOTH_FONT

// ############################
// Section 4. Other options
// ############################

#define SPI_FREQUENCY  27000000
#define SPI_READ_FREQUENCY  20000000
#define SPI_TOUCH_FREQUENCY  2500000

After saving this file, adding it to the User_Seltup_Select.h and enabling it, I was able to flash a simple example from the TFT_eSPI library:

TFT_Print_Test.ino

It did take some tweaking of the RGB_Order and TFT_Inversion to get the colors right (based on the sketch), but it is a promising start!

In fact, I decided to try flashing this to Clone 'B' using the same custom configuration file just to see what would happen:


(The background colors are different because the sketch selects a random background color every 10 seconds.  But all the text colors are correct for both).

Next I tried one of the image/graphic examples on both boards.

Animated Eyes Example Script

Obviously you can't see it from static photos, but the eyes would look around and occasionally blink.  Once again, the same sketch and configuration file worked for both clones.  This means, at a minimum, that both boards are using the same driver and GPIO pins for the TFT display.

Touch

While both boards work with the same configuration for general display purposes, and while the TFT_eSPI library supports touch, they will likely diverge when it comes to touch since Clone "A" is using resistive touch and Clone "B" is using capacitance.

But for the initial test, I have two lines enabled in my configuration above related to touch... touch_cs and spi_touch_frequency.  I then flashed the library example, Touch_calibrate.ino.  This library first runs through a calibration process, prompting you to touch the four corners of the screen.



For Clone 'A', this worked as expected.  Each time a corner was touched (using the stylus), the arrow advanced to the next corner.


When the calibration is complete, the values are sent to the serial monitor and you can use these to actually configure the touch parameters.


You can then test the screen by touching it and see a white dot appear.  If calibrations was complete, then the dot should appear right where you touch the screen (you can also try drawing).

Clone "A" Successful Touch Test

You can also just use your finger, but it is much less precise.. and does take a little bit of pressure.  For this type of screen (resistive), you are likely going to want to use the stylus for fine-grained control.  A finger might work OK with large buttons or other controls.  

Clone "B", not surprisingly, ran the firmware just fine.


But there was no response to touch of any kind... with a stylus or finger.  Not surprisingly, the TFT_eSPI library only supports resistive touch.  The author states this (more than once) in the library issues.


So it's back to the drawing board for touch capabilities on Clone "B".  Luckily, the touch controller chip on the back of the board is labeled:

Click to enlarge

The GT911 touch controller is an I2C device.  We can see this via the pinouts listed on the ribbon cable for the JST connector, where pins 1-6 are labeled as GND, SDA, SCL, RST, INT and VDD.  But this doesn't tell us which GPIO pins these are connected to on the ESP32.

Fortunately (for me and Clone "B"), the Amazon listing had an external link that included this diagram.

Click to enlarge

Looking a little closer at the pinouts for the ESP32:


Looking for pins that are labeled as capacitance touch (CTP), we see:
    • SCL:  GPIO32
    • SDA: GPIO33
    • RESET: GPIO25
    • INTERRUPT: GPIO21
We still don't know the I2C address, but since we know the GPIO pins, we can run a quick little utility to scan for I2C devices and return the address of any found.  You can find the full code for the scanner over at Random Nerd Tutorials, but I did have to add one line to specify the non-default I2C GPIO pins used.


I specified that I2C (Wire library) will use GPIO33 (SDA) and GPIO032 (SCL).  When I flashed this to the Clone "B" board and enabled the serial monitor in the Arduino IDE, it found the I2C display chip and returned the I2C address:


So I now know the GPIO pins and I2C address for the GT911 touch chip!  This should allow me to start investigating libraries to use for capacitive touch.

I reviewed a number of different potential libraries, but initially decided to try the initGT911 Touch Library


The library includes an example sketch where you can test the touch function and the touch coordinates will be output to the serial monitor.  I just needed to change a few things (shown in blue below), like GPIO pins, to use the sample code:


#include <Wire.h>
#include "initGT911.h"

// I2C pins and frequency
#define I2C_SDA 33
#define I2C_SCL 32
#define I2C_FREQ 400000

// GT911 I2C address
#define TOUCH_ADDR 0x5D // or GT911_I2C_ADDR_BA

// Reset and INT pins (set to -1 if unused)
#define RST_PIN  25
#define INT_PIN  -1  // not used in polling mode
...
  // Initialize GT911 in polling mode
  if (Touchscreen.begin(INT_PIN, RST_PIN, I2C_FREQ)) {
    Serial.println("GT911 initialized in polling mode");
    Touchscreen.setupDisplay(480, 320, initGT911::Rotate::_0); // example resolution
  } else {
    Serial.println("Failed to initialize GT911");
  }

The rest of the sample code was used 'as-is'.  When flashed to Clone 'B' and the serial monitor was enabled, each touch of the screen returned the X/Y coordinates for the point where the screen was touched:


I then combined this library with the TFT_eSPI display library to show a white dot on the screen where it was touched.  This is just like the Clone  "A" example, except the actual touch coordinates are coming from the GT911 library and then used by the TFT_eSPI library to render the white dot:

  uint8_t touchCount = Touchscreen.touched(GT911_MODE_POLLING);

  if (touchCount > 0) {
    for (uint8_t i = 0; i < touchCount; i++) {
      GTPoint p = Touchscreen.getPoint(i);
      Serial.printf("Touch %d: X=%d, Y=%d\n", i, p.x, p.y);
      tft.fillCircle((p.x)/1.5, (p.y)*1.5, 2, TFT_WHITE);
    }
  }


Just like the Clone "A" example, once I had the resolutions and coordinate configured between the two different libraries, the touch points seemed to be accurate across different areas of the board.

What's more, a capacitance screen has the advantage of being able to simultaneously detect more than one touch point.

Multiple simultaneous touch points detected

As you can see in the above, I'm simultaneously drawing on the screen with two fingers and all touch points are detected.  This would allow things like 'pinch-to-zoom' or other multi-touch operations to be implemented.

**A few additional notes on the above test:

For Clone "B", I did switch the configuration file for the TFT_eSPI library to my 'CYD-B' file.  This is actually the same a Clone "A" except the touch components aren't enabled since touch will use the initGT911 library for the touch coordinates.

I had to do a little scaling to align the display and touch libraries.  This is probably due to slight differences in how the displays are calibrated, but the touch library also seems to currently have issues with screen rotation (I've opened an issue in the repo).  Once I figured out the 'conversion' (used in the 'tft.fillCircle' statement), then the touch seemed to be highly accurate.


With this test, I now have both display and touch working on both clones... but it wasn't a quick 'plug-and-play' process!  And of course there are many other components, such as the SD card reader, LED, JST connections, etc. that I haven't even touched on here.

But the process for using these other components would be very similar to the process used for the display and touch... identify the GPIO pins and any other required information (e.g. I2C address, chip select, etc.) for the component.  Then find and implement an appropriate library for that feature.

For now, and due to the already long length of this article, I want to move on to ESPHome.  I will likely cover some of the other components and Arduino use in my upcoming larger project.

ESPHome Configuration and Testing



If you've jumped straight to this section because you want to use the CYD with ESPHome and have no plans to write your own firmware with Arduino, hold your horses!  Regardless of whether using Arduino or ESPHome, there are certain details that we need to know about the board.  This includes things like the type of ESP, GPIO pins used, display and touch drivers/controllers used, etc.  I cover how to find those items under the Arduino sections above.  But for reference, I'll cover the key parameters found for both my clones here:

 

Clone “A”

Clone “B”

ESP32 Type

ESP32-DOWD-V3

ESP32-DOWD-V3

Display Driver

ST7796

ST7796

    MISO

GPIO12

GPIO12

    MOSI

GPIO13

GPIO13

    SCLK

GPIO14

GPIO14

    CS

GPIO15

GPIO15

    DC

GPIO2

GPIO2

    BACKLIGHT

GPIO27

GPIO27

    RESET

-1 (not used)

-1 (not used)

    TOUCH_CS

GPIO33

n/a

    INVERSION

Off

Off

    RGB Order

BGR

BGR

    Dimensions

480 x 320

480 x 320

 

 

 

Touch Driver (type)

XPT2046 (resistive)

GT911 (capacitive)

    SCL

n/a

GPIO32

    SDA

n/a

GPIO33

    RESET

n/a

GPIO25

    INTERRUPT (INT)

n/a

-1 (polling mode)/GPIO25

    I2C Address

n/a

0x5D

 

 

 


I'm not going to cover creating a new ESPHome node that includes things like WiFi, the Home Assistant API, etc.  This initial framework can be automatically generated when you create a new node.


Just assure you are selecting the proper ESP type that matches your board.  In my case, both clones are using a standard ESP32.  If you want to know more about how to setup and flash ESPHome to one of your own boards, you can check out this video where I cover that process:

This process will get your component on WiFi, create the API interface to Home Assistant, etc.  For the remainder of this section, I'm only going to cover the parts of the ESPHome configuration that would be added to the starting framework for the display and touch features.

I created two new ESPHome nodes, one for each clone.


But now we need to add configurations to the nodes for display and touch.

Note: For the following examples to work properly, you must be running ESPHome 2025.8 or later.  This will use a new display component.  If you want to see the issues and difficulties trying to use this component with earlier versions of ESPHome, take a look at the video!

Display Component

To begin, I did a simple search for ST7796, since this is display driver used by both clones.

Most recent display component for SPI Displays

Using the documentation along with the GPIO pins discovered during Arduino testing, I added the following sections to my ESPHome configurations:

font:
  - file: "gfonts://Roboto"
    id: roboto_20
    size: 20
  - file: "gfonts://Comic Relief"
    id: comic_relief_30
    size: 20

spi:
  id: spi_bus1
  clk_pin: GPIO14
  mosi_pin: GPIO13
  miso_pin: GPIO12

display:
  - platform: mipi_spi
    id: main_display
    model: ST7796
    spi_id: spi_bus1
    dc_pin: GPIO2
    cs_pin: GPIO15
    invert_colors: False
    color_order: BGR
    color_depth: 8BIT
    dimensions:
      height: 320
      width: 480
    data_rate: 20000000.0
    rotation: 90
    lambda: |-
      auto yellow =  Color(255,255,0);
      auto black = Color(0,0,0);
      it.fill(COLOR_OFF);
      it.print(10,10, id(roboto_20), "Hello YouTube!");
      it.print(10, 60, id(comic_relief_30), "I'm running ESPHome!");
      it.filled_circle(it.get_width()/2, (it.get_height()/2)+50, 50, yellow);
      it.filled_circle((it.get_width()/2)-20, (it.get_height()/2)+30, 5, black);
      it.filled_circle((it.get_width()/2)+20, (it.get_height()/2)+30, 5, black);
      it.filled_gauge((it.get_width()/2), (it.get_height()/2)+80, 25, 20, 100, black);

light:
  - platform: monochromatic
    output: backlight_pwm
    restore_mode: ALWAYS_ON
    id: backlight

output: 
  - platform: ledc
    pin: GPIO27
    id: backlight_pwm

Fonts: I added a font section to import a couple of Google fonts that I can use to display text.  

SPI Bus: I define an SPI bus, give it a unique ID and then specify the SPI GPIO pins for the display.  Again, these were determined earlier in this article.

Display: I then defined the display component, using the new mipi_spi platform.  I also give this a unique ID (this will be used later for touch), specify the proper CS and DC pins and set other properties... based on what I used for Arduino.  For dimensions, these should be specified after any rotation is applied.  If I used a rotation of 0, then the width and height values would be reversed.

Finally, I'm just outputting some sample text and a couple geometric shapes.

Light & Output: These setup and define the backlight, which can be dimmed.


And as you can see, the same configuration worked for both boards, using the same configuration.  Why am I showing a "frowny" face instead of a "smiley" face?  When first trying to get the boards to work, I could not set the dimensions to use the full display:


This was resolved with ESPHome 2025.8... which came out just after I spent multiple hours trying to resolve the issue!  Again, you can watch the video to see my struggle.  Regardless, at this point, the display is working on both clones and you can do many of the same things as Arduino, including using the LGVL library for graphics.

Touch Components

That just leaves the touch component.  Unlike the display component, the two clones will definitely be different here as Clone 'A' uses resistive touch and Clone 'B' uses capacitive.  I'll start with Clone 'A' and resistive touch.

Resistive Touch

From the previous Arduino work, I know that touch controller is the XP2046.  So, I'll search for that on the ESPHome site:


Using the documentation provided, I added the following to the Clone 'A' configuration:

touchscreen:
  - platform: xpt2046
    id: xpt2046_touch
    display: main_display
    cs_pin: GPIO33
    calibration: 
      x_min: 340
      x_max: 3821
      y_min: 399
      y_max: 3747
    on_touch: 
      then:
        - lambda: |-
            ESP_LOGI("cal", "x=%d, y=%d, x_raw=%d, y_raw=%0d",
                touch.x,
                touch.y,
                touch.x_raw,
                touch.y_raw
                );

The display setting points at the ID that was used for the display configuration and tells the touch component which display screen is being used:

display:
  - platform: mipi_spi
    id: main_display

Calibration Values

The XPT2046 component requires the calibration key.  But where do these numbers come from, how do you get them and how do they translate to X,Y coordinates you would use in your code or automations?

For starters, I simply used the calibration numbers that I received when doing a calibration test with Arduino:


But these are just starting numbers.  For the initial testing and calibration, I'm outputting the raw X and Y values, along with the reported X,Y coordinates.  I can then flash this code to Clone 'A'.


After flashing, the display looks the same.  but if you display the ESPHome log for Clone 'A' and then touch each corner, four values will be presented for each touch:


Each touch logs x, y, raw_x and raw_y.  What's the difference between X, Y and raw_x and raw_y?  Well, touch controllers don't necessarily correspond to the same coordinates as the display.  In most cases, touch is a much broader range.

So, raw_x and raw_y are the touch coordinates and X and Y are how these coordinates get mapped to the display coordinates (0-480 for X and 0-320 for Y in landscape orientation).

From the four different corners, locate the maximum and mininum raw_x and raw_y values.  Mine initially looked like this:


I can easily pull the min/max values from the raw_x and raw_y values for the calibration numbers.  But there's another problem here.  The display coordinates appear to be reversed or transposed.  The 0,0 point is in corner "C" while it should be in corner 'A'.  It also appears that Y increases as you move horizontally instead of vertically.  But there's an easy fix for that:

touchscreen:
  - platform: xpt2046
    id: xpt2046_touch
    display: main_display
    cs_pin: GPIO33
    calibration: 
      x_min: 281
      x_max: 3839
      y_min: 269
      y_max: 3868
    transform: 
      swap_xy: True
      mirror_x: True
      mirror_y: True

By adding a transform section, we can swap or flip how the raw coordinates map to the display coordinates.  This will vary based on your display's orientation.  But for mine, after I uploaded the modified code and tested again, I got:


Now the touch coordinates align with the display coordinates.  I can draw a box on the screen, say from 10,10 to 80,80.  I can then setup a binary sensor that will return TRUE whenever a touch is detected in this range.  That binary sensor can then be used in local ESPHome automations or in Home Assistant.  There are plenty examples of this elsewhere, so I'll now move on to getting touch working on the capacitance-based Clone 'B'.

Capacitive Touch

From my earlier work, I know that Clone 'B' uses the GT911 touch controller.  So, just like with resistive touch, I'll first search the ESPHome site for 'GT911'.


Note that this is an I2C component, so we need to setup I2C in the ESPHome configuration in addition to the touch screen.  

This is actually a bit easier than the resistive XPT2046 configuration.  I added the following to the Clone 'B' configuration:

i2c:
  id: i2c_bus1
  sda: GPIO33
  scl: GPIO32
...

touchscreen:
  - platform: gt911
    address: 0x5D
    id: gt911_touch
    display: main_display
#    interrupt_pin: GPIO21  #COMMENTED OUT
    i2c_id: i2c_bus1
    transform: 
      swap_xy: True
      mirror_x: True
      mirror_y: False
    on_touch: 
      then:
        - lambda: |-
            ESP_LOGI("cal", "x=%d, y=%d, x_raw=%d, y_raw=%0d",
                touch.x,
                touch.y,
                touch.x_raw,
                touch.y_raw
                );

I2C: Since this board does not use the standard ESP32 I2C pins, I have to tell it which pins to use for SDA and SCL.  I also include an ID that will be used in the touchscreen setup.

Touchscreen: This is similar to the resistive touch setup, but with a few key differences.  Obviously the platform in this case is gt911.  I included the optional I2C address.  I only did this in case I add additional I2C components at a later time.  I ended up removing (commenting out) the optional interrupt pin.  The touch did not work when this was included.  In the Arduino testing, a polling method was used that did not use an interrupt pin.  So the interrupt pin might be misidentified or omitting the interrupt pin also uses polling in ESPHome.  You might need to try your clone with and without an interrupt and/or reset pin.

I once again transform the returned touch values so they match the orientation of the display.  The goal, just like with the Clone 'A' resistive touch is to have returned values close to the following:


Once the configuration was saved, validated and flashed to the board, I once again displayed the ESPHome log.


I then touched each of the four corners and noted the log output:


Note that we did not include any calibration numbers in the touchscreen setup.  In the case of the GT911 and this display, the raw numbers actually match the coordinates of the display.  The only difference between the 'raw' numbers and the general x,y coordinates is that the general coordinates have been "transformed" to match the orientation of the display.

So that is now display and touch are working on both clones in ESPHome!  Just like with Arduino, if you now want to add the SD card reader or other components to your configuration, you simply follow the same process... identify the type of component, GPIO  pins used and any other necessary information, such as I2C address if appropriate.

Oh...and ESPHome now supports LVGL, so you can also use LVGL features in ESPHome as well as Arduino.

Wrap Up and Conclusions


While I did eventually get display and touch working for both clones in Arduino and ESPHome, it took me WAY longer than it should have.  This isn't necessarily a fault of documentation with Arduino libraries or ESPHome (especially with the new site), but falls to the lack of documentation, or even incorrect documentation, that was provided by the sellers of the boards themselves.  Significant time was spent just trying to identify the types of components used, GPIO pins, etc.  If full (and correct) specifications had been provided, the entire testing process probably would have only taken a few hours at most.

But this is a common issue you will run into with mass produced and sold low-cost electronic components.  As shown here, you might buy what appears to be one particular component only to find that yours has significant differences from general online documentation and examples you might find.

So this particular article was about identifying components on cloned devices as much as it was about the CYD itself.  If you find yourself with some component that doesn't seem to work correctly with examples you might find online, you may have a clone with different parameters.  Hopefully some of the steps in this article can be used to help you out with your own cloned device!

You'll likely see a bit more about the CYD and how I use it when I get around to including it in my larger planned project.

Thanks for reading and let me know down in the comments if you have any questions or thoughts!

Links and Additional Info


ESPTool (identify chip)
TFT_eSPI library (Display & Resistance Touch)
initGT911 Library (Capacitance Touch)
ESPHome (new site!)


Supporting this blog and related YouTube channel


It takes significant time and effort (and often expense) to create these articles and videos.  If you'd like to support future content on this blog and the  related YouTube channel, or just say thanks for something that helped you out, you can consider buying me a one-off cup of coffee or two at:
  

No comments:

Post a Comment

To help eliminate spam and to keep all conversations civil, submitted comments are moderated. Therefore your post may not show up immediately. Please be patient as most reviews are completed within a few hours.