Introduction to ESP32 CYD Development
The ESP32 CYD (Cheap Yellow Display) represents a breakthrough in affordable embedded systems development, combining the powerful ESP32 microcontroller with an integrated 2.8-inch TFT touchscreen. This all-in-one solution eliminates the need for complex wiring between separate components, making it ideal for IoT dashboards, smart home controllers, wearable devices, and industrial HMIs. While many tutorials focus on the Arduino IDE for ESP32 CYD development, this comprehensive guide explores a more professional approach using Visual Studio Code with PlatformIO, offering superior code management, debugging capabilities, and library handling.
This tutorial not only covers basic setup but also dives deep into configuring the essential libraries—TFT_eSPI, XPT2046_Touchscreen, and LVGL—that transform this budget-friendly board into a capable interactive display platform. Whether you’re building a weather station interface, a retro gaming console, or a custom control panel, mastering VS Code with the ESP32 CYD will significantly accelerate your development workflow and project sophistication.

Prerequisites for ESP32 CYD Development
Before diving into the programming process, ensure you have the following components and knowledge:
Software Requirements:
-
Visual Studio Code (latest stable version)
-
PlatformIO IDE extension for VS Code
-
Basic familiarity with C/C++ programming
-
Git (for library management)
Hardware Requirements:
-
ESP32 CYD board (ESP32-2432S028R) or compatible variant
-
USB-C cable for programming and power
-
Computer with available USB port
Prior Experience:
-
Basic ESP32 programming concepts
-
Understanding of SPI communication protocol
-
Previous experience with Arduino IDE (helpful but not mandatory)
-
Familiarity with library management in embedded development
Note: This guide also applies if you’re using a standard ESP32 development board with a separate 2.8-inch ILI9341 240×320 TFT LCD touchscreen. The configuration steps remain largely identical, with only minor pin assignment differences.
Setting Up VS Code and PlatformIO
Installation Process
-
Download and Install VS Code: Visit the official Visual Studio Code website and download the appropriate version for your operating system (Windows, macOS, or Linux). Follow the standard installation procedure.
-
Install PlatformIO Extension:
-
Open VS Code and navigate to the Extensions view (Ctrl+Shift+X or Cmd+Shift+X on macOS)
-
Search for “PlatformIO IDE”
-
Click “Install” on the official PlatformIO extension by PlatformIO
-
Wait for the installation to complete (this may take several minutes as PlatformIO downloads necessary toolchains)
-
Initial PlatformIO Configuration:
-
After installation, you’ll see the PlatformIO icon (an alien head) in the VS Code activity bar
-
Click this icon to open the PlatformIO Home screen
-
PlatformIO will automatically set up the ESP32 toolchain on first launch
Creating Your First ESP32 CYD Project
-
From PlatformIO Home, select “New Project”
-
Name your project (e.g., “ESP32_CYD_Test”)
-
Select “Espressif ESP32” as the board
-
Choose “ESP32 Dev Module” as the specific board (the CYD uses a standard ESP32)
-
Select “Arduino” as the framework
-
Choose your project location and click “Finish”
PlatformIO will create a project structure with a src folder (for your code) and a critical platformio.ini file (for project configuration). This initialization process demonstrates the professional workflow advantage of PlatformIO over Arduino IDE, with proper project separation and dependency management.
Installing Essential Libraries for ESP32 CYD
Understanding Library Dependencies
The ESP32 CYD requires three core libraries for full functionality:
-
TFT_eSPI: Handles display graphics and text rendering
-
XPT2046_Touchscreen: Manages touch input from the resistive touch layer
-
LVGL (optional but recommended): Provides advanced graphical user interface elements
Installing XPT2046_Touchscreen Library
Unlike the Arduino IDE where libraries can be installed via the Library Manager, PlatformIO requires a different approach for the XPT2046_Touchscreen library due to known compatibility issues:
-
Open your project’s platformio.ini file
-
Add the following line under the [env:esp32dev] section (or your environment name):
lib_deps =
https://github.com/PaulStoffregen/XPT2046_Touchscreen.git
-
Save the file. PlatformIO will automatically download and install this library from GitHub on the next build.
Expert Tip: Adding libraries via GitHub URLs ensures you get the latest version directly from the source, which is particularly important for frequently updated libraries like XPT2046_Touchscreen. This method also provides better version control than the PlatformIO library registry for this specific library.
Installing TFT_eSPI Library
The TFT_eSPI library can be installed through PlatformIO’s Library Manager:
-
Click the PlatformIO icon in the activity bar
-
Select “Libraries” from the PlatformIO menu
-
Search for “TFT_eSPI” in the search bar
-
Find the library by Bodmer (the official version)
-
Click “Add to Project” and select your current ESP32 CYD project
Alternatively, you can add it directly to your platformio.ini file:
lib_deps =
https://github.com/PaulStoffregen/XPT2046_Touchscreen.git
bodmer/TFT_eSPI@^2.5.43
The version specification (@^2.5.43) ensures compatibility while allowing minor updates. After adding, your platformio.ini should also include these essential settings for proper serial monitoring:
monitor_speed = 115200
upload_speed = 921600
board_build.flash_mode = dio
Configuring the TFT_eSPI Library for ESP32 CYD
The Critical User_Setup.h File
The TFT_eSPI library requires specific configuration for each display type through a User_Setup.h file. Generic configurations available online often won’t work correctly with the ESP32 CYD, leading to display issues, incorrect colors, or touch calibration problems.
Step-by-Step Configuration Process
-
Locate the TFT_eSPI library in your project:
-
In VS Code’s Explorer panel, navigate to: .pio/libdeps/esp32dev/TFT_eSPI
-
The esp32dev portion may vary based on your board selection during project creation
-
Find and open User_Setup.h:
-
Within the TFT_eSPI folder, locate User_Setup.h
-
This file contains numerous configuration options for different displays
-
Replace with ESP32 CYD specific configuration:
-
Key Configuration Details:
The correct User_Setup.h for ESP32 CYD should include these essential definitions:
#define ILI9341_DRIVER
#define TFT_WIDTH 240
#define TFT_HEIGHT 320
#define TFT_MISO 39
#define TFT_MOSI 32
#define TFT_SCLK 25
#define TFT_CS 33
#define TFT_DC 15
#define TFT_RST 32
#define TOUCH_CS 33
#define LOAD_GLCD
#define LOAD_FONT2
#define SPI_FREQUENCY 40000000
#define SPI_TOUCH_FREQUENCY 2500000
Critical Note: Using an incorrect User_Setup.h file is the most common source of problems when working with TFT displays on ESP32. The configuration must match exactly the pin assignments and display driver of your specific hardware. Random Nerd Tutorials provides a tested configuration that accounts for the ESP32 CYD’s unique pin mapping and ILI9341 display controller characteristics.
Testing Display and Touchscreen Functionality
Complete Test Sketch
After installing and configuring the libraries, verify everything works correctly with this comprehensive test code:
#include <SPI.h>
#include <TFT_eSPI.h>
#include <XPT2046_Touchscreen.h>
TFT_eSPI tft = TFT_eSPI();
#define XPT2046_IRQ 36
#define XPT2046_MOSI 32
#define XPT2046_MISO 39
#define XPT2046_CLK 25
#define XPT2046_CS 33
SPIClass touchscreenSPI = SPIClass(VSPI);
XPT2046_Touchscreen touchscreen(XPT2046_CS, XPT2046_IRQ);
#define SCREEN_WIDTH 320
#define SCREEN_HEIGHT 240
#define FONT_SIZE 2
void setup() {
Serial.begin(115200);
touchscreenSPI.begin(XPT2046_CLK, XPT2046_MISO, XPT2046_MOSI, XPT2046_CS);
touchscreen.begin(touchscreenSPI);
touchscreen.setRotation(1);
tft.init();
tft.setRotation(1);
tft.fillScreen(TFT_BLACK);
tft.setTextColor(TFT_WHITE, TFT_BLACK);
tft.drawCentreString("ESP32 CYD Ready", SCREEN_WIDTH/2, 50, FONT_SIZE);
tft.drawCentreString("Touch to Test", SCREEN_WIDTH/2, 100, FONT_SIZE);
tft.drawCentreString("Check Serial Monitor", SCREEN_WIDTH/2, 150, FONT_SIZE);
Serial.println("ESP32 CYD Test Initialized");
}
void loop() {
if (touchscreen.tirqTouched() && touchscreen.touched()) {
TS_Point p = touchscreen.getPoint();
int x = map(p.x, 200, 3700, 1, SCREEN_WIDTH);
int y = map(p.y, 240, 3800, 1, SCREEN_HEIGHT);
int z = p.z;
tft.fillRect(0, 180, SCREEN_WIDTH, 60, TFT_BLACK);
tft.drawCentreString("X: " + String(x), SCREEN_WIDTH/2, 180, FONT_SIZE);
tft.drawCentreString("Y: " + String(y), SCREEN_WIDTH/2, 200, FONT_SIZE);
tft.drawCentreString("Pressure: " + String(z), SCREEN_WIDTH/2, 220, FONT_SIZE);
Serial.printf("Touch - X: %d, Y: %d, Pressure: %d\n", x, y, z);
delay(200);
}
}
Upload and Verification Process
-
Build the Project: Click the checkmark icon in the blue bottom status bar (or press Ctrl+Alt+B) to compile the code
-
Upload to ESP32 CYD: Click the right-arrow icon (or press Ctrl+Alt+U) to upload the compiled code
-
Open Serial Monitor: Click the plug icon (or press Ctrl+Alt+S) to open the serial monitor at 115200 baud
-
Expected Results:
-
The display should show a welcome message
-
Touching the screen should display coordinates on both the display and serial monitor
-
The touch pressure value should increase when pressing harder
Troubleshooting Common Issues
Installing and Configuring LVGL for Advanced GUIs
Why LVGL for ESP32 CYD?
LVGL (Light and Versatile Graphics Library) is a professional open-source embedded graphics library that enables sophisticated user interfaces on microcontrollers. While the TFT_eSPI library handles basic drawing functions, LVGL provides:
-
Advanced widgets (buttons, sliders, charts, lists)
-
Animations and transitions
-
Multi-language support
-
Memory-efficient rendering
-
Touch gesture recognition
For projects requiring more than basic text and shapes, LVGL transforms the ESP32 CYD into a capable platform for modern GUI applications.
Installation Process
-
Add LVGL to PlatformIO Project:
-
Open PlatformIO Libraries (PIO Home → Libraries)
-
Search for “lvgl”
-
Select version 9.x (latest stable)
-
Click “Add to Project” and select your ESP32 CYD project
-
Create lv_conf.h Configuration File:
-
In your project’s root directory, create a new file named lv_conf.h
-
Copy the LVGL configuration template specifically designed for ESP32 CYD:
#ifndef LV_CONF_H
#define LV_CONF_H
#define LV_MEM_SIZE (32 * 1024)
#define LV_HOR_RES_MAX 320
#define LV_VER_RES_MAX 240
#define LV_COLOR_DEPTH 16
#define LV_USE_GPU_STM32_DMA2D 0
#define LV_USE_LOG 1
#define LV_LOG_PRINTF 1
#define LV_USE_ASSERT_NULL 1
#define LV_USE_ASSERT_MEM 1
#define LV_USE_ASSERT_OBJ 1
#define LV_USE_USER_DATA 1
#define LV_USE_LABEL 1
#define LV_USE_BUTTON 1
#define LV_USE_BUTTONMATRIX 1
#define LV_USE_CHECKBOX 1
#define LV_USE_SLIDER 1
#define LV_USE_DROPDOWN 1
#endif
-
Update platformio.ini: Ensure your configuration includes sufficient memory allocation:
board_build.partitions = huge_app.csv
build_flags =
-DBOARD_HAS_PSRAM
-mfix-esp32-psram-cache-issue
lib_ldf_mode = deep+
LVGL Initialization Code
Integrate LVGL with your existing TFT_eSPI and touchscreen setup:
#include <lvgl.h>
#include <TFT_eSPI.h>
#include <XPT2046_Touchscreen.h>
TFT_eSPI tft = TFT_eSPI();
XPT2046_Touchscreen touchscreen(XPT2046_CS, XPT2046_IRQ);
static lv_disp_draw_buf_t draw_buf;
static lv_color_t buf[SCREEN_WIDTH * SCREEN_HEIGHT / 10];
void my_disp_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p) {
uint32_t w = (area->x2 - area->x1 + 1);
uint32_t h = (area->y2 - area->y1 + 1);
tft.startWrite();
tft.setAddrWindow(area->x1, area->y1, w, h);
tft.pushColors((uint16_t *)&color_p->full, w * h, true);
tft.endWrite();
lv_disp_flush_ready(disp);
}
void touchpad_read(lv_indev_drv_t *indev_driver, lv_indev_data_t *data) {
if (touchscreen.touched()) {
TS_Point p = touchscreen.getPoint();
data->point.x = map(p.x, 200, 3700, 0, SCREEN_WIDTH);
data->point.y = map(p.y, 240, 3800, 0, SCREEN_HEIGHT);
data->state = LV_INDEV_STATE_PR;
} else {
data->state = LV_INDEV_STATE_REL;
}
}
void setup() {
Serial.begin(115200);
tft.init();
tft.setRotation(1);
touchscreen.begin();
lv_init();
lv_disp_draw_buf_init(&draw_buf, buf, NULL, SCREEN_WIDTH * SCREEN_HEIGHT / 10);
static lv_disp_drv_t disp_drv;
lv_disp_drv_init(&disp_drv);
disp_drv.hor_res = SCREEN_WIDTH;
disp_drv.ver_res = SCREEN_HEIGHT;
disp_drv.flush_cb = my_disp_flush;
disp_drv.draw_buf = &draw_buf;
lv_disp_drv_register(&disp_drv);
static lv_indev_drv_t indev_drv;
lv_indev_drv_init(&indev_drv);
indev_drv.type = LV_INDEV_TYPE_POINTER;
indev_drv.read_cb = touchpad_read;
lv_indev_drv_register(&indev_drv);
lv_obj_t *btn = lv_btn_create(lv_scr_act());
lv_obj_set_size(btn, 100, 50);
lv_obj_center(btn);
lv_obj_t *label = lv_label_create(btn);
lv_label_set_text(label, "Click Me!");
lv_obj_center(label);
Serial.println("LVGL Initialized with ESP32 CYD");
}
void loop() {
lv_timer_handler();
delay(5);
}
Building a Complete ESP32 CYD Project
Sample Application: IoT Dashboard
Combine all learned elements into a practical IoT dashboard example:
#include <lvgl.h>
#include <TFT_eSPI.h>
#include <XPT2046_Touchscreen.h>
#include <WiFi.h>
#include <HTTPClient.h>
TFT_eSPI tft;
XPT2046_Touchscreen touchscreen(XPT2046_CS, XPT2046_IRQ);
lv_obj_t *temperatureLabel;
lv_obj_t *humidityLabel;
lv_obj_t *pressureLabel;
lv_obj_t *chart;
lv_chart_series_t *tempSeries;
const char* ssid = "YOUR_SSID";
const char* password = "YOUR_PASSWORD";
const String apiKey = "YOUR_API_KEY";
const String city = "London";
void updateWeatherData() {
if (WiFi.status() == WL_CONNECTED) {
HTTPClient http;
String url = "http://api.openweathermap.org/data/2.5/weather?q=" + city + "&appid=" + apiKey + "&units=metric";
http.begin(url);
int httpCode = http.GET();
if (httpCode == 200) {
String payload = http.getString();
float temperature = 22.5;
float humidity = 65;
float pressure = 1013;
lv_label_set_text_fmt(temperatureLabel, "Temp: %.1f°C", temperature);
lv_label_set_text_fmt(humidityLabel, "Humidity: %.0f%%", humidity);
lv_label_set_text_fmt(pressureLabel, "Pressure: %.0fhPa", pressure);
lv_chart_set_next_value(chart, tempSeries, temperature);
}
http.end();
}
}
void setup() {
Serial.begin(115200);
tft.init();
tft.setRotation(1);
touchscreen.begin();
lv_init();
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi...");
}
Serial.println("WiFi connected");
lv_obj_t *scr = lv_scr_act();
lv_obj_t *title = lv_label_create(scr);
lv_label_set_text(title, "ESP32 CYD Weather Dashboard");
lv_obj_align(title, LV_ALIGN_TOP_MID, 0, 10);
temperatureLabel = lv_label_create(scr);
lv_label_set_text(temperatureLabel, "Temp: -- °C");
lv_obj_align(temperatureLabel, LV_ALIGN_LEFT_MID, 20, -40);
humidityLabel = lv_label_create(scr);
lv_label_set_text(humidityLabel, "Humidity: --%");
lv_obj_align(humidityLabel, LV_ALIGN_LEFT_MID, 20, -10);
pressureLabel = lv_label_create(scr);
lv_label_set_text(pressureLabel, "Pressure: -- hPa");
lv_obj_align(pressureLabel, LV_ALIGN_LEFT_MID, 20, 20);
chart = lv_chart_create(scr);
lv_obj_set_size(chart, 150, 100);
lv_obj_align(chart, LV_ALIGN_RIGHT_MID, -20, 0);
lv_chart_set_range(chart, LV_CHART_AXIS_PRIMARY_Y, 0, 40);
lv_chart_set_point_count(chart, 20);
tempSeries = lv_chart_add_series(chart, lv_palette_main(LV_PALETTE_RED), LV_CHART_AXIS_PRIMARY_Y);
lv_obj_t *btn = lv_btn_create(scr);
lv_obj_set_size(btn, 100, 40);
lv_obj_align(btn, LV_ALIGN_BOTTOM_MID, 0, -20);
lv_obj_t *btnLabel = lv_label_create(btn);
lv_label_set_text(btnLabel, "Update");
lv_obj_center(btnLabel);
lv_obj_add_event_cb(btn, [](lv_event_t *e) {
updateWeatherData();
}, LV_EVENT_CLICKED, NULL);
updateWeatherData();
}
void loop() {
lv_timer_handler();
static unsigned long lastUpdate = 0;
if (millis() - lastUpdate > 30000) {
updateWeatherData();
lastUpdate = millis();
}
delay(5);
}
Advanced Tips and Best Practices
Optimizing Performance
-
Use PSRAM Effectively: The ESP32 CYD includes 8MB of PSRAM. Enable it in platformio.ini:
board_build.partitions = huge_app.csv
build_flags =
-DBOARD_HAS_PSRAM
-mfix-esp32-psram-cache-issue
-
LVGL Memory Optimization:
-
Adjust LV_MEM_SIZE in lv_conf.h based on your widget complexity
-
Use lv_disp_set_draw_buffers() for double buffering
-
Enable compression for images: #define LV_USE_IMG_COMPRESSED 1
-
Display Refresh Optimization:
-
Set appropriate SPI frequency (40MHz works well for ESP32 CYD)
-
Use tft.setSwapBytes(true) for correct color order
-
Implement partial updates where possible instead of full screen refreshes
Troubleshooting Advanced Issues
Version Management Best Practices
-
Library Version Pinning: Always specify library versions in platformio.ini to ensure consistent builds:
lib_deps =
bodmer/TFT_eSPI@2.5.43
https://github.com/PaulStoffregen/XPT2046_Touchscreen.git#v1.4.0
lvgl/lvgl@9.2.0
-
Configuration File Management: Store your User_Setup.h and lv_conf.h files in a version control system separate from the library installations.
-
Project Templates: Create a baseline ESP32 CYD project with all configurations pre-set, then duplicate it for new projects rather than reconfiguring each time.
Conclusion and Further Resources
The ESP32 CYD, when combined with VS Code and PlatformIO, becomes a powerful development platform for interactive display applications. By following this comprehensive guide, you’ve established a professional development environment, configured all necessary libraries, and learned to create both basic and advanced applications with LVGL.
Key Takeaways:
-
VS Code with PlatformIO offers superior project management compared to Arduino IDE
-
Proper library configuration is critical—especially the User_Setup.h file for TFT_eSPI
-
LVGL enables professional-grade user interfaces on the ESP32 CYD
-
Regular testing at each configuration step prevents compound issues
Next Steps to Expand Your ESP32 CYD Skills:
-
Explore LVGL Widgets: Experiment with advanced widgets like charts, meters, rollers, and text areas
-
Add External Sensors: Connect I2C or SPI sensors to create complete monitoring systems
-
Implement Power Saving: Use ESP32 deep sleep modes with display power management for battery-powered projects
-
Create Custom Themes: Design unique visual styles with LVGL’s theme system
-
Add Wireless Connectivity: Implement MQTT for IoT dashboards or Bluetooth for peripheral control
Additional Resources:
With this foundation, you’re equipped to tackle increasingly complex projects with the ESP32 CYD. The combination of low-cost hardware and professional development tools democratizes advanced embedded display applications, enabling everything from home automation interfaces to portable diagnostic tools. As you continue developing, remember to share your projects with the community—each project contributes to the collective knowledge base that makes platforms like the ESP32 CYD so valuable to makers and engineers worldwide.
Contact Us