In this guide, you’ll get started with the LVGL (Light and Versatile Graphics Library) using a TFT LCD Touchscreen Display wired to an ESP32 board. The LVGL is a popular free and open-source embedded graphics library to create awesome UIs for many microcontrollers and displays.
We recommend an ESP32 board that has an on-board TFT display, read our Guide for LVGL with ESP32 Cheap Yellow Display Board (ESP32-2432S028R)
Introducing the TFT LCD Touchscreen Display
The display we’re using in this guide is the 2.8. inch TFT LCD that also comes with a touchscreen. The display communicates via SPI communication protocol and uses the ILI9341 driver. You can write text, draw shapes, and display images. The touchscreen also uses the SPI communication protocol.
The TFT LCD touchscreen also comes with an SD card interface if you need to load files for your specific project. This display is also available with different screen sizes.
Parts Required
For this project, you need to wire the TFT display and touchscreen pins to the ESP32. Here’s a list of parts you need:
- TFT LCD Touchscreen Display – 2.8 inch ILI9341 240×320
- ESP32 DOIT DEVKIT V1 Board – read ESP32 Development Boards Review and Comparison
- Breadboard
- Jumper wires
You can use the preceding links or go directly to MakerAdvisor.com/tools to find all the parts for your projects at the best price!
Wiring the TFT LCD Touchscreen Display to the ESP32 Board
Wire the TFT LCD and touchscreen pins to the following ESP32 GPIOs (you must use these exact pins, otherwise the project will not work).
TFT LCD Touchscreen | ESP32 |
T_IRQ | GPIO 36 |
T_OUT | GPIO 39 |
T_DIN | GPIO 32 |
T_CS | GPIO 33 |
T_CLK | GPIO 25 |
SDO(MISO) | GPIO 12 |
LED | GPIO 21 |
SCK | GPIO 14 |
SDI(MOSI) | GPIO 13 |
D/C | GPIO 2 |
RESET | EN/RESET |
CS | GPIO 15 |
GND | GND |
VCC | 5V (or 3.3V)* |
* In the VCC pin, you can either use 5V or 3.3V depending if your J1 connection is open or closed (by default it’s usually open as you can see in the figure below).
VCC = 5V | J1=OPEN
VCC = 3.3V | J1=CLOSE
Introducing LVGL (Light and Versatile Graphics Library)
LVGL (Light and Versatile Graphics Library) is a free and open-source graphics library that provides a wide range of easy-to-use graphical elements for your microcontroller projects that require a graphical user interface (GUI).
Here are some of its key features:
- Blocks: buttons, charts, lists, sliders, images, etc…
- Advanced graphics with animations, anti-aliasing, opacity, smooth scrolling;
- Various input devices such as touchpad, mouse, keyboard, encoder, etc…
- Multi-language support with UTF-8 encoding;
- Multi-display support, i.e. use multiple TFT, monochrome displays simultaneously;
- Fully customizable graphic elements with CSS-like styles;
- Hardware independent: use with any microcontroller or display;
- Scalable: able to operate with little memory (64 kB Flash, 16 kB RAM);
- Written in C for maximal compatibility (C++ compatible) and binding to MicroPython.
It also has a wide range of code examples in their documentation that you can use: text, buttons, sliders, input fields, keyboard, custom styling, images, arcs, lines, animations, menus, tabs, layouts, tables, and much more…
Installing Arduino Libraries
The ESP32 communicates with the TFT Display and Touchscreen using SPI communication protocol. We’ll be using the TFT_eSPI, XPT2046_Touchscreen, and LVGL 9 libraries.
Installing the TFT_eSPI Library
Open your Arduino IDE and go to Sketch > Include Library > Manage Libraries. The Library Manager should open. Search for TFT_eSPI. Select the TFT_eSPI library by Bodmer and install it.
Installing the XPT2046_Touchscreen Library
Open your Arduino IDE and go to Sketch > Include Library > Manage Libraries. The Library Manager should open. Search for XPT2046_Touchscreen. Select the XPT2046_Touchscreen library by Paul Stoffregen and install it.
Installing the LVGL 9 Library
Open your Arduino IDE and go to Sketch > Include Library > Manage Libraries. The Library Manager should open. Search for LVGL. Select the LVGL library by kiskegabor and install version 9.2.
Prepare Config Files for TFT_eSPI and LVGL Library
To properly use the TFT_eSPI library, you need a configuration file called User_Setup.h with the right definitions. You also need to prepare the lv_conf.h file for the LVGL library. We’ve already prepared these two files so that you don’t have any configuration issues following our examples. You just need to download them and move them to the correct folders. Follow the next instructions to learn how to do it.
a) Preparing the Config Files – Windows PC
b) Preparing the Config Files – Mac OS
a) Preparing the Config Files – Windows PC
Having all the libraries installed (TFT_eSPI, XPT2046_Touchscreen, and LVGL), start by downloading the User_Setup.h configuration file.
- Click here to download .zip folder with the User_Setup.h config file (view raw file)
In your Arduino IDE, go to File and open the Preferences menu.
Copy the Arduino IDE “Sketchbook location” path. In my case, it’s:
C:\Users\rui_s\Documents\Arduino
Then, in your Windows PC File Explorer tab enter the sketchbook location path to open the Arduino folder (it’s usually under the Documents folder).
Open the libraries folder:
You should see the TFT_eSPI library folder there. Open it.
You should be in a similar folder path as shown below:
C:\Users\rui_s\Documents\Arduino\libraries\TFT_eSPI
Copy the User_Setup.h file provided earlier and replace the existing file.
Then, download the lv_conf.h configuration file.
- Click here to download .zip folder with the lv_conf.h config file (view raw file)
Open a similar folder path in your computer as shown below:
C:\Users\rui_s\Documents\Arduino\libraries
Move the lv_conf.h to the libraries folder (do NOT move it inside the lvgl folder).
IMPORTANT: other User_Setup.h and lv_conf.h files available on the internet will probably NOT work with the examples available at Random Nerd Tutorials. You must use the exact files provided in this article.
Note: if you update your libraries, you’ll need to do this procedure again and place the right configuration files in the right places.
b) Preparing the Config Files – Mac OS
Having both libraries installed (TFT_eSPI and XPT2046_Touchscreen), download the User_Setup.h configuration file.
- Click here to download .zip folder with the User_Setup.h config file (view raw file)
In your Arduino IDE, open the Settings menu.
Copy the Arduino IDE “Sketchbook location” path. In my case, it’s:
/Users/rui/Documents/Arduino
In Finder, type /Users/rui/Documents/Arduino and open that directory.
Open the libraries folder.
You should see the TFT_eSPI library folder there. Open it.
You should be in a similar folder path as shown below:
/Users/rui/Documents/Arduino/libraries/TFT_eSPI
Copy the User_Setup.h file provided earlier and replace the existing file.
You should now have the User_Setup.h file provided on that path.
Then, download the lv_conf.h configuration file.
- Click here to download .zip folder with the lv_conf.h config file (view raw file)
Open a similar folder path for the libraries in your computer as shown below:
/Users/rui/Documents/Arduino/libraries
Move the lv_conf.h to the libraries folder (do NOT move it inside the lvgl folder).
IMPORTANT: other User_Setup.h and lv_conf.h files available on the internet will probably NOT work with the examples available at Random Nerd Tutorials. You must use the exact files provided in this article.
Note: if you update your libraries, you’ll need to do this procedure again and place the right configuration files in the right places.
Code – Display Text, Create Buttons and Slider
The following code displays a simple text in your TFT display and allows you to test the touchscreen using a button and slider. When you press the buttons or slider, it should trigger some events.
Copy the following code to the Arduino IDE and upload it to your board.
/* Rui Santos & Sara Santos - Random Nerd Tutorials
THIS EXAMPLE WAS TESTED WITH THE FOLLOWING HARDWARE:
1) ESP32-2432S028R 2.8 inch 240×320 also known as the Cheap Yellow Display (CYD): https://makeradvisor.com/tools/cyd-cheap-yellow-display-esp32-2432s028r/
SET UP INSTRUCTIONS: https://RandomNerdTutorials.com/cyd-lvgl/
2) REGULAR ESP32 Dev Board + 2.8 inch 240x320 TFT Display: https://makeradvisor.com/tools/2-8-inch-ili9341-tft-240x320/ and https://makeradvisor.com/tools/esp32-dev-board-wi-fi-bluetooth/
SET UP INSTRUCTIONS: https://RandomNerdTutorials.com/esp32-tft-lvgl/
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/
/* Install the "lvgl" library version 9.2 by kisvegabor to interface with the TFT Display - https://lvgl.io/
*** IMPORTANT: lv_conf.h available on the internet will probably NOT work with the examples available at Random Nerd Tutorials ***
*** YOU MUST USE THE lv_conf.h FILE PROVIDED IN THE LINK BELOW IN ORDER TO USE THE EXAMPLES FROM RANDOM NERD TUTORIALS ***
FULL INSTRUCTIONS AVAILABLE ON HOW CONFIGURE THE LIBRARY: https://RandomNerdTutorials.com/cyd-lvgl/ or https://RandomNerdTutorials.com/esp32-tft-lvgl/ */
#include <lvgl.h>
/* Install the "TFT_eSPI" library by Bodmer to interface with the TFT Display - https://github.com/Bodmer/TFT_eSPI
*** IMPORTANT: User_Setup.h available on the internet will probably NOT work with the examples available at Random Nerd Tutorials ***
*** YOU MUST USE THE User_Setup.h FILE PROVIDED IN THE LINK BELOW IN ORDER TO USE THE EXAMPLES FROM RANDOM NERD TUTORIALS ***
FULL INSTRUCTIONS AVAILABLE ON HOW CONFIGURE THE LIBRARY: https://RandomNerdTutorials.com/cyd-lvgl/ or https://RandomNerdTutorials.com/esp32-tft-lvgl/ */
#include <TFT_eSPI.h>
// Install the "XPT2046_Touchscreen" library by Paul Stoffregen to use the Touchscreen - https://github.com/PaulStoffregen/XPT2046_Touchscreen - Note: this library doesn't require further configuration
#include <XPT2046_Touchscreen.h>
// Touchscreen pins
#define XPT2046_IRQ 36 // T_IRQ
#define XPT2046_MOSI 32 // T_DIN
#define XPT2046_MISO 39 // T_OUT
#define XPT2046_CLK 25 // T_CLK
#define XPT2046_CS 33 // T_CS
SPIClass touchscreenSPI = SPIClass(VSPI);
XPT2046_Touchscreen touchscreen(XPT2046_CS, XPT2046_IRQ);
#define SCREEN_WIDTH 240
#define SCREEN_HEIGHT 320
// Touchscreen coordinates: (x, y) and pressure (z)
int x, y, z;
#define DRAW_BUF_SIZE (SCREEN_WIDTH * SCREEN_HEIGHT / 10 * (LV_COLOR_DEPTH / 8))
uint32_t draw_buf[DRAW_BUF_SIZE / 4];
// If logging is enabled, it will inform the user about what is happening in the library
void log_print(lv_log_level_t level, const char * buf) {
LV_UNUSED(level);
Serial.println(buf);
Serial.flush();
}
// Get the Touchscreen data
void touchscreen_read(lv_indev_t * indev, lv_indev_data_t * data) {
// Checks if Touchscreen was touched, and prints X, Y and Pressure (Z)
if(touchscreen.tirqTouched() && touchscreen.touched()) {
// Get Touchscreen points
TS_Point p = touchscreen.getPoint();
// Calibrate Touchscreen points with map function to the correct width and height
x = map(p.x, 200, 3700, 1, SCREEN_WIDTH);
y = map(p.y, 240, 3800, 1, SCREEN_HEIGHT);
z = p.z;
data->state = LV_INDEV_STATE_PRESSED;
// Set the coordinates
data->point.x = x;
data->point.y = y;
// Print Touchscreen info about X, Y and Pressure (Z) on the Serial Monitor
/* Serial.print("X = ");
Serial.print(x);
Serial.print(" | Y = ");
Serial.print(y);
Serial.print(" | Pressure = ");
Serial.print(z);
Serial.println();*/
}
else {
data->state = LV_INDEV_STATE_RELEASED;
}
}
int btn1_count = 0;
// Callback that is triggered when btn1 is clicked
static void event_handler_btn1(lv_event_t * e) {
lv_event_code_t code = lv_event_get_code(e);
if(code == LV_EVENT_CLICKED) {
btn1_count++;
LV_LOG_USER("Button clicked %d", (int)btn1_count);
}
}
// Callback that is triggered when btn2 is clicked/toggled
static void event_handler_btn2(lv_event_t * e) {
lv_event_code_t code = lv_event_get_code(e);
lv_obj_t * obj = (lv_obj_t*) lv_event_get_target(e);
if(code == LV_EVENT_VALUE_CHANGED) {
LV_UNUSED(obj);
LV_LOG_USER("Toggled %s", lv_obj_has_state(obj, LV_STATE_CHECKED) ? "on" : "off");
}
}
static lv_obj_t * slider_label;
// Callback that prints the current slider value on the TFT display and Serial Monitor for debugging purposes
static void slider_event_callback(lv_event_t * e) {
lv_obj_t * slider = (lv_obj_t*) lv_event_get_target(e);
char buf[8];
lv_snprintf(buf, sizeof(buf), "%d%%", (int)lv_slider_get_value(slider));
lv_label_set_text(slider_label, buf);
lv_obj_align_to(slider_label, slider, LV_ALIGN_OUT_BOTTOM_MID, 0, 10);
LV_LOG_USER("Slider changed to %d%%", (int)lv_slider_get_value(slider));
}
void lv_create_main_gui(void) {
// Create a text label aligned center on top ("Hello, world!")
lv_obj_t * text_label = lv_label_create(lv_screen_active());
lv_label_set_long_mode(text_label, LV_LABEL_LONG_WRAP); // Breaks the long lines
lv_label_set_text(text_label, "Hello, world!");
lv_obj_set_width(text_label, 150); // Set smaller width to make the lines wrap
lv_obj_set_style_text_align(text_label, LV_TEXT_ALIGN_CENTER, 0);
lv_obj_align(text_label, LV_ALIGN_CENTER, 0, -90);
lv_obj_t * btn_label;
// Create a Button (btn1)
lv_obj_t * btn1 = lv_button_create(lv_screen_active());
lv_obj_add_event_cb(btn1, event_handler_btn1, LV_EVENT_ALL, NULL);
lv_obj_align(btn1, LV_ALIGN_CENTER, 0, -50);
lv_obj_remove_flag(btn1, LV_OBJ_FLAG_PRESS_LOCK);
btn_label = lv_label_create(btn1);
lv_label_set_text(btn_label, "Button");
lv_obj_center(btn_label);
// Create a Toggle button (btn2)
lv_obj_t * btn2 = lv_button_create(lv_screen_active());
lv_obj_add_event_cb(btn2, event_handler_btn2, LV_EVENT_ALL, NULL);
lv_obj_align(btn2, LV_ALIGN_CENTER, 0, 10);
lv_obj_add_flag(btn2, LV_OBJ_FLAG_CHECKABLE);
lv_obj_set_height(btn2, LV_SIZE_CONTENT);
btn_label = lv_label_create(btn2);
lv_label_set_text(btn_label, "Toggle");
lv_obj_center(btn_label);
// Create a slider aligned in the center bottom of the TFT display
lv_obj_t * slider = lv_slider_create(lv_screen_active());
lv_obj_align(slider, LV_ALIGN_CENTER, 0, 60);
lv_obj_add_event_cb(slider, slider_event_callback, LV_EVENT_VALUE_CHANGED, NULL);
lv_slider_set_range(slider, 0, 100);
lv_obj_set_style_anim_duration(slider, 2000, 0);
// Create a label below the slider to display the current slider value
slider_label = lv_label_create(lv_screen_active());
lv_label_set_text(slider_label, "0%");
lv_obj_align_to(slider_label, slider, LV_ALIGN_OUT_BOTTOM_MID, 0, 10);
}
void setup() {
String LVGL_Arduino = String("LVGL Library Version: ") + lv_version_major() + "." + lv_version_minor() + "." + lv_version_patch();
Serial.begin(115200);
Serial.println(LVGL_Arduino);
// Start LVGL
lv_init();
// Register print function for debugging
lv_log_register_print_cb(log_print);
// Start the SPI for the touchscreen and init the touchscreen
touchscreenSPI.begin(XPT2046_CLK, XPT2046_MISO, XPT2046_MOSI, XPT2046_CS);
touchscreen.begin(touchscreenSPI);
// Set the Touchscreen rotation in landscape mode
// Note: in some displays, the touchscreen might be upside down, so you might need to set the rotation to 0: touchscreen.setRotation(0);
touchscreen.setRotation(2);
// Create a display object
lv_display_t * disp;
// Initialize the TFT display using the TFT_eSPI library
disp = lv_tft_espi_create(SCREEN_WIDTH, SCREEN_HEIGHT, draw_buf, sizeof(draw_buf));
lv_display_set_rotation(disp, LV_DISPLAY_ROTATION_270);
// Initialize an LVGL input device object (Touchscreen)
lv_indev_t * indev = lv_indev_create();
lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER);
// Set the callback function to read Touchscreen input
lv_indev_set_read_cb(indev, touchscreen_read);
// Function to draw the GUI (text, buttons and sliders)
lv_create_main_gui();
}
void loop() {
lv_task_handler(); // let the GUI do its work
lv_tick_inc(5); // tell LVGL how much time has passed
delay(5); // let this time pass
}
How the Code Works
Let’s take a quick look at the parts of the code that are relevant to this example.
Libraries
Include the lvgl, TFT_eSPI and XPT2046_Touchscreen libraries.
#include <lvgl.h>
#include <TFT_eSPI.h>
#include <XPT2046_Touchscreen.h>
Initialize Touchscreen
The following lines set the touchscreen pinout:
#define XPT2046_IRQ 36
#define XPT2046_MOSI 32
#define XPT2046_MISO 39
#define XPT2046_CLK 25
#define XPT2046_CS 33
Create a touchscreenSPI and touchscreen instances:
SPIClass touchscreenSPI = SPIClass(VSPI);
XPT2046_Touchscreen touchscreen(XPT2046_CS, XPT2046_IRQ);
Other Variables
Set the screen width and screen height:
#define SCREEN_WIDTH 240
#define SCREEN_HEIGHT 320
#define FONT_SIZE 2
Variables to store the coordinates: (x, y) and pressure (z).
int x, y, z;
setup()
Start a serial communication with the Serial Monitor at a baud rate of 115200 and print the LVGL library version that you are using:
String LVGL_Arduino = String("LVGL Library Version: ") + lv_version_major() + "." + lv_version_minor() + "." + lv_version_patch();
Serial.begin(115200);
Serial.println(LVGL_Arduino);
Start the LVGL and assign a callback function for debugging purposes.
lv_init();
lv_log_register_print_cb(log_print);
Start the SPI for the touchscreen and initialize the touchscreen.
touchscreenSPI.begin(XPT2046_CLK, XPT2046_MISO, XPT2046_MOSI, XPT2046_CS);
touchscreen.begin(touchscreenSPI);
touchscreen.setRotation(2);
Note: in some displays, the touchscreen might be upside down, so you might need to set the rotation to 0: touchscreen.setRotation(2);
Create the display object and initialize the TFT display using the TFT_eSPI library.
lv_display_t * disp;
disp = lv_tft_espi_create(SCREEN_WIDTH, SCREEN_HEIGHT, draw_buf, sizeof(draw_buf));
lv_display_set_rotation(disp, LV_DISPLAY_ROTATION_270);
Initialize an LVGL input device object (touchscreen) and set the callback function that will be triggered when you click the touchscreen.
lv_indev_t * indev = lv_indev_create();
lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER);
lv_indev_set_read_cb(indev, touchscreen_read);
Finally, call the lv_create_main_gui() function to draw the GUI for your touchscreen:
lv_create_main_gui();
loop()
When running an LVGL example, the loop() will usually look like this:
lv_task_handler(); // let the GUI do its work
lv_tick_inc(5); // tell LVGL how much time has passed
delay(5); // let this time pass
lv_create_main_gui()
The lv_create_main_gui() function draws the text label, buttons, and sliders. It’s also where you assign the event handler callback functions that will be triggered when you interact with your display.
void lv_create_main_gui(void) {
// Create a text label aligned center on top ("Hello, world!")
lv_obj_t * text_label = lv_label_create(lv_screen_active());
lv_label_set_long_mode(text_label, LV_LABEL_LONG_WRAP); // Breaks the long lines
lv_label_set_text(text_label, "Hello, world!");
lv_obj_set_width(text_label, 150); // Set smaller width to make the lines wrap
lv_obj_set_style_text_align(text_label, LV_TEXT_ALIGN_CENTER, 0);
lv_obj_align(text_label, LV_ALIGN_CENTER, 0, -90);
lv_obj_t * btn_label;
// Create a Button (btn1)
lv_obj_t * btn1 = lv_button_create(lv_screen_active());
lv_obj_add_event_cb(btn1, event_handler_btn1, LV_EVENT_ALL, NULL);
lv_obj_align(btn1, LV_ALIGN_CENTER, 0, -50);
lv_obj_remove_flag(btn1, LV_OBJ_FLAG_PRESS_LOCK);
btn_label = lv_label_create(btn1);
lv_label_set_text(btn_label, "Button");
lv_obj_center(btn_label);
// Create a Toggle button (btn2)
lv_obj_t * btn2 = lv_button_create(lv_screen_active());
lv_obj_add_event_cb(btn2, event_handler_btn2, LV_EVENT_ALL, NULL);
lv_obj_align(btn2, LV_ALIGN_CENTER, 0, 10);
lv_obj_add_flag(btn2, LV_OBJ_FLAG_CHECKABLE);
lv_obj_set_height(btn2, LV_SIZE_CONTENT);
btn_label = lv_label_create(btn2);
lv_label_set_text(btn_label, "Toggle");
lv_obj_center(btn_label);
// Create a slider aligned in the center bottom of the TFT display
lv_obj_t * slider = lv_slider_create(lv_screen_active());
lv_obj_align(slider, LV_ALIGN_CENTER, 0, 60);
lv_obj_add_event_cb(slider, slider_event_callback, LV_EVENT_VALUE_CHANGED, NULL);
lv_slider_set_range(slider, 0, 100);
lv_obj_set_style_anim_duration(slider, 2000, 0);
// Create a label below the slider to display the current slider value
slider_label = lv_label_create(lv_screen_active());
lv_label_set_text(slider_label, "0%");
lv_obj_align_to(slider_label, slider, LV_ALIGN_OUT_BOTTOM_MID, 0, 10);
}
event_handler_btn1()
The event_handler_btn1() function is triggered when you click the “Button” and it will also display in the Arduino IDE Serial Monitor the number of times the button has been clicked.
int btn1_count = 0;
// Callback that is triggered when btn1 is clicked
static void event_handler_btn1(lv_event_t * e) {
lv_event_code_t code = lv_event_get_code(e);
if(code == LV_EVENT_CLICKED) {
btn1_count++;
LV_LOG_USER("Button clicked %d%", (int)btn1_count);
}
}
event_handler_btn2()
The event_handler_btn2() is triggered when you click the “Toggle” button, it stores the current button state and prints a message with the current state in the Serial Monitor.
// Callback that is triggered when btn2 is clicked/toggled
static void event_handler_btn2(lv_event_t * e) {
lv_event_code_t code = lv_event_get_code(e);
lv_obj_t * obj = (lv_obj_t*) lv_event_get_target(e);
if(code == LV_EVENT_VALUE_CHANGED) {
LV_UNUSED(obj);
LV_LOG_USER("Toggled %s", lv_obj_has_state(obj, LV_STATE_CHECKED) ? "on" : "off");
}
}
slider_event_callback()
The slider_event_callback() function is called when you move the slider, it will also display both in the touchscreen and Serial Monitor the latest slider value on a scale from 0 to 100%.
static lv_obj_t * slider_label;
// Callback that prints the current slider value on the TFT display and Serial Monitor for debugging purposes
static void slider_event_callback(lv_event_t * e) {
lv_obj_t * slider = (lv_obj_t*) lv_event_get_target(e);
char buf[8];
lv_snprintf(buf, sizeof(buf), "%d%%", (int)lv_slider_get_value(slider));
lv_label_set_text(slider_label, buf);
lv_obj_align_to(slider_label, slider, LV_ALIGN_OUT_BOTTOM_MID, 0, 10);
LV_LOG_USER("Slider changed to %d%%", (int)lv_slider_get_value(slider));
}
Demonstration
Upload the code to your board. Go to Tools > Board and select ESP32 > ESP32 Dev Module. Then, select the right COM port in Tools > Port. Finally, click the upload button.
After uploading the code to your board, it should display the sample “Hello, world!” text centered at the top.
Press with your finger the first “Button”. In the Serial Monitor, it will print the coordinates of your button press, as well as a message with the number of times the button has been clicked: “Button clicked 1”, “Button clicked 2”, “Button clicked 3″…
Then, click the “Toggle” button, this could be used to control an LED or any other output. This button type has two states (color blue when off and color red when on).
Drag the slider with your finger, you’ll see the slider moving and the slider label changing when you move your finger.
All the events will be printed in your Arduino IDE Serial Monitor for debugging purposes:
Wrapping Up
In this tutorial, you learned to get started with the LVGL library with the TFT Touchscreen wired to an ESP32 board. In the next guides, we’ll explore other features and components of the LVGL library.
If you have an ESP32 Cheap Yellow Display board, you can follow this other guide to use the LVGL with the CYD board.
We hope you found this tutorial useful. We’re preparing more guides about the LVGL library, so stay tuned.
Other guides you might like reading:
- ESP32: TFT LCD Touchscreen Display – 2.8 inch ILI9341 240×320 (Arduino IDE)
- ESP32: TFT Touchscreen On/Off Button – 2.8 inch ILI9341 240×320 (Arduino IDE)
To learn more about the ESP32, make sure to take a look at our resources:
Nice example, but the ridiculous number of ads in the web page are very distracting.
Please limit or eliminate most of them.
There were error messages.
– E:\port apps\Arduino\arduino\libraries\TFT_eSPI/Processors/TFT_eSPI_ESP32.h:14:25: fatal error: hal/gpio_ll.h: No such file or directory
this helped: https://github.com/Bodmer/TFT_eSPI/discussions/3048
E:\port apps\Arduino\arduino\libraries\TFT_eSPI/Processors/TFT_eSPI_ESP32.h:138:18: fatal error: FS.h: No such file or directory
E:\port apps\Arduino\arduino\libraries\TFT_eSPI/Processors/TFT_eSPI_ESP32.h:139:36: fatal error: SPIFFS.h: No such file or directory
I fixed it, by searchig for SPIFFS.h
probably i’ve got the wrong one, because afterwards lots of error messages appeared
Can someone help me?
Hi.
Please double-check the instructions to install the libraries and preparing the configuration files.
Make sure you’re placing everything in the right places.
Regards,
Sara
Hello! As I understand, touch and LCD and SD card holder are SPI devices. Could it possible to connect them to same SPI pins, but using different CS pin for each device?
Hi.
Yes.
That is possible. Just make sure each SPI device has its own CS pin.
Regards,
Sara
Hello, I’m trying desperately to get your example to work but unfortunately the display on the screen doesn’t work unless I invert 240 x 320 but in that case the keys don’t work properly except for “toggle” because the screen isn’t facing the right way.
Can you please help me?
Hi.
Check this line of code:
// Note: in some displays, the touchscreen might be upside down, so you might need to set the rotation to 1: touchscreen.setRotation(1);
touchscreen.setRotation(3);
Set your rotation to 1.
touchscreen.setRotation(1);
Regards,
Sara
Hello, Sorry it doesn’t change anything, I can’t put the screen in “landscape” mode, but only in “portrait” mode by inverting #define SCREEN_WIDTH 240 #define SCREEN_HEIGHT 320 but in this case only “toggle” works normally even though the tests of the TFT-eSPI library are good I don’t know how to send you a photo, it would be easier thank you again.
LVGL – very cool library.
Сould you more explain about create different objects on LVGL?
Hi.
Yes. We’re currently creating a new eBook about that.
So, stay tuned.
Regards,
Sara
Hi!
It’s possible to change the TFT LED pin to another port on the ESP32? Because I need to use the I2C bus
Hi.
You can use I2C bus on pins 22 and 27.
Regards,
Sara
Thanks!
Regards.
Hi, I have already bought a couple of separate screens that are ILI9341 and 320 x 240 which look identical to those listed, including the touch screen, connectors and jumpers. However, they are clearly marked 3.2″ TFT SPI 240×320 V1.0 on the rear.
So far I have followed the instructions carefully and everything ( except needing to change the ‘Rotation’ from 3 to 1 ) is working perfectly.
Am I likely to run into problems later, or do you think these are just physically a little bigger than the recommended ones ?
Many thanks – Noel
Wow, really awesome this post! I really must read the posts which you guys posted after this one. I never used the ILI9341 with the ESP32, just with Arduino, but this LVGL library seens really awesome. Once again, congratulations, you guys rock Sara and Rui!
Thank you 😀
This project was working fine. Buttons, slider, touch screen. But now, after an upload completes, the TFT does not light up. However, in the ‘Serial Monitor’ I see this scrolling on forever:-
[Warn] (895.260, +0) indev_pointer_proc: Y is -15 which is smaller than zero lv_indev.c:654
[Warn] (895.290, +30) indev_pointer_proc: X is -17 which is smaller than zero lv_indev.c:648
[Warn] (895.290, +0) indev_pointer_proc: Y is -15 which is smaller than zero lv_indev.c:654
[Warn] (895.320, +30) indev_pointer_proc: X is -17 which is smaller than zero lv_indev.c:648
Any ideas ?
Nothing has changed except this is the next day !
Best regards – Noel
I think I just solved my own problem.
A couple of days ago, I was prompted to update one of my libraries, which is so common that I did not give it a second thought.
So I took a look at the manual changes detailed for the project. I used a File Comparison program, which showed me that the User_Setup.h had been changed. I replaced it with the required, correct version and all is now fine – phew !
Sorry for the panic, perhaps my mistake will help someone else….
Hi.
If you udpdate the library, you’ll need to place the right configuration file again in the right place.
REgards,
Rui
What change is required for ST7789?
i using tft shield parallel 2.8 cant use XPT2046_Touchscreen because i dont know pin
Hello Rui And Sara,
I have question, Is yesterday’s file User_setup.h in article https://randomnerdtutorials.com/esp32-tft-touchscreen-display-2-8-ili9341-arduino/ the same as this one?
Hi.
We recently changed a bit the User_setup file because there was a pin that was not being set correctly.
The User_setup file on the link already reflects those changes. Just make sure you follow the pinout on the table. There was a change in one of the pins.
Regards,
Sara
While this works fine with LVGL 9.1.0, the display is not drawn properly with LVGL 9.2.0
There were breaking changes on version 9.2.0.
Use previous version, or change WIDTH with HEIGHT and it will display correctly but in portrait mode.
I’m not sure why this broke with the update.
Regards,
sara
Greeting.
I have a question. Example from your guide ESP32: TFT Touchscreen On/Off Button – 2.8 inch ILI9341 240×320 (Arduino IDE) works fine for me, but example from LVGL Library : LVGL with ESP32 TFT LCD Touchscreen – 2.8 inch ILI9341 240× 320 (Arduino IDE) doesn’t work at all even though I tried to follow the instructions carefully.
The Arduino IDE gives me the following error:
c:\Users\Korisnik\Documents\Arduino\libraries\lvgl\src\examples\styles\lv_example_style_14.c:1:10: fatal error: ../../src/themes/lv_theme_private.h: No such file or directory
#include “../../src/themes/lv_theme_private.h”
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
exit status 1
Compilation error: exit status 1
Hi.
Check Rui’s answer here: https://rntlab.com/question/lvgl-book-1-3-compile-problem/
Regards,
Sara
Hi.
Thanks for the answer.
I applied Rui’s first tip and got the correct image on the display screen, however the screen (Toggle, Button and Slider) are not responding to touch.
You probably need to set a different rotation for the touchscreen
hi, how to make it working with ILI9488 4″ TFT please? do you have any example?
No, unfortunately at the moment we don’t have any instructions for that TFT.
Muchas gracias por compartir la información. Creo que he seguido todos los pasos, pero al compilar me da este error:
c:\Users\fremi\OneDrive – IES Juan de la Cierva\ESP32\TFT_eSPI_ILI9486\libraries\lvgl\src\examples\styles\lv_example_style_14.c:1:10: fatal error: ../../src/themes/lv_theme_private.h: No such file or directory
#include “../../src/themes/lv_theme_private.h”
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
exit status 1
Compilation error: exit status 1
Puede ayudarme alguien
Delete the LVGL library and re-install version 9.2 following these instructions: https://randomnerdtutorials.com/lvgl-esp32-tft-touchscreen-display-ili9341-arduino/
Do NOT move the demos or examples folders.
hi, I´m using a ESP32-2432S032 and i want to rotate the display from 270° to 90° with the lv_display_set_rotation(disp, LV_DISPLAY_ROTATION_90) function… but it doesn´t change anything… it just rotate the touchtscreen but not the display itself. With the itself TFT_eSPI lib it working. Does someone know how to change that for this code?
Hi Sara,
When I compile your program I get the following error msg:
:\User s\User\OneDrive\Documents\Arduino\libraries\TFT_eSPI\Extensions/Touch.cpp: In member function ‘void TFT_eSPI::begin_touch_read_write()’:
c:\Users\User\OneDrive\Documents\Arduino\libraries\TFT_eSPI\Processors/TFT_eSPI_ESP32.h:234:22: error: ‘GPIO’ was not declared in this scope
234 | #define CS_H GPIO.out_w1ts = (1 << TFT_CS)//;GPIO.out_w1ts = (1 << TFT_CS)
| ^~~~
c:\Users\User\OneDrive\Documents\Arduino\libraries\TFT_eSPI\Extensions/Touch.cpp:20:3: note: in expansion of macro ‘CS_H’
20 | CS_H; // Just in case it has been left low
| ^~~~
Means very little to me. Please help.
Thanks
Alan
Hi,by replacing User_Setup.h will it affect normal use of Arduino for other purposes?
Regards Torkel
No. It won’t.
Regards,
Sara
Good day. Such a problem. Nothing is displayed on the screen. The following is written in the port:
[Warn] (127.770, +0) indev_pointer_proc: Y is -26 which is smaller than zero lv_indev.c:695
[Warn] (127.770, +0) indev_pointer_proc: Y is -26 which is smaller than zero lv_indev.c:695
[Warn] (127.800, +30) indev_pointer_proc: X is -18 which is smaller than zero lv_indev.c:689
[Warn] (127.800, +30) indev_pointer_proc: X is -18 which is smaller than zero lv_indev.c:689
i am constantly getting this message i even tried older versions of the libraries but still this error remains constant
C:\Users\Dhruv Goel\AppData\Local\Temp.arduinoIDE-unsaved2024117-6388-skiaa5.sc6ef\sketch_dec7a\sketch_dec7a.ino: In function ‘void setup()’:
C:\Users\Dhruv Goel\AppData\Local\Temp.arduinoIDE-unsaved2024117-6388-skiaa5.sc6ef\sketch_dec7a\sketch_dec7a.ino:152:3: error: ‘lv_log_register_print_cb’ was not declared in this scope
152 | lv_log_register_print_cb(log_print);
| ^~~~~~~~~~~~~~~~~~~~~~~~
C:\Users\Dhruv Goel\AppData\Local\Temp.arduinoIDE-unsaved2024117-6388-skiaa5.sc6ef\sketch_dec7a\sketch_dec7a.ino:164:10: error: ‘lv_tft_espi_create’ was not declared in this scope; did you mean ‘lv_tlsf_create’?
164 | disp = lv_tft_espi_create(SCREEN_WIDTH, SCREEN_HEIGHT, draw_buf, sizeof(draw_buf));
| ^~~~~~~~~~~~~~~~~~
| lv_tlsf_create
exit status 1
Compilation error: ‘lv_log_register_print_cb’ was not declared in this scope
Which version of the LVGL library are you using?
Regards,
Sara
Hello,
I have a blank (white) screen only. Nothing is displayed. Any idea ?
Hi.
Do you get any information on the Serial Monitor?
Regards,
Sara
Hi,
Here is informations I have on Serial Monitor. Then, nothing else.
17:53:26.871 -> ets Jul 29 2019 12:21:46
17:53:26.871 ->
17:53:26.871 -> rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
17:53:26.871 -> configsip: 0, SPIWP:0xee
17:53:26.871 -> clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
17:53:26.871 -> mode:DIO, clock div:1
17:53:26.871 -> load:0x3fff0030,len:1344
17:53:26.871 -> load:0x40078000,len:13964
17:53:26.871 -> load:0x40080400,len:3600
17:53:26.871 -> entry 0x400805f0
17:53:27.059 -> LVGL Library Version: 9.2.0