ESP32 with TFT: Display Image using LVGL – 2.8 inch ILI9341 240×320 (Arduino)

In this guide, you’ll learn how to process and load an image to be displayed on a TFT 2.8 inch ILI9341 240×320 with the ESP32 board using LVGL (Light Versatile Graphics Library). The ESP32 will be programmed using Arduino IDE.

ESP32 with TFT Display Image using LVGL – 2.8 inch ILI9341 240×320 Arduino IDE

Are you using a CYD board? Read this guide: ESP32 CYD with LVGL: Display Image on the Screen

Project Overview

In this project, you’ll learn how to display images on the TFT screen using LVGL. We’ll create an example to display the image of a cat as shown in the picture below, but you can modify it to load any other image.

ESP32 TFT LCD with LVGL Display Image on the screen demonstration

Prerequisites

Before proceeding, make sure you follow the next prerequisites. You must follow all steps, otherwise, your project will not work.

1) Parts Required

For this project, you need the following parts:

2) Install ESP32 Boards in Arduino IDE

Arduino IDE 2 Logo

We’ll program the ESP32 using Arduino IDE. Make sure you have the ESP32 boards installed. Follow the next tutorial:

3) Get familiar with the ILI9341 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. 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, but we’ll use the one with 240 x 320 pixels).

ILI9341 TFT LCD Touchscreen Display

If this is your first time using this display, make sure to follow our getting started guide:

4) Wire the Display to the ESP32

Wire the TFT LCD and touchscreen pins to the ESP32 GPIOs according to the next table (you must use these exact pins, otherwise the project will not work).

Wiring TFT LCD Touchscreen display to ESP32
TFT LCD TouchscreenESP32
T_IRQGPIO 36
T_OUTGPIO 39
T_DINGPIO 32
T_CSGPIO 33
T_CLKGPIO 25
SDO(MISO)GPIO 12
LEDGPIO 21
SCKGPIO 14
SDI(MOSI)GPIO 13
D/CGPIO 2
RESETEN/RESET
CSGPIO 15
GNDGND
VCC5V (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
TFT LCD Touchscreen display J1 connection

5) Install TFT and LVGL Libraries

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).

LVGL new logo

Follow the next tutorial to install and configure the required libraries to use LVGL with the ESP32 using Arduino IDE and the TFT LCD touchscreen.

Preparing the Image File – image.h

To load a custom image using LVGL, you need to create and configure a file called image.h that must be placed inside the sketch folder. We already prepared that file for you. If you want to load a custom image, you just need to replace the image uint8_t map and the image size.

You can use our sample image or follow the next steps to prepare a custom image:

1. Go to the LVGL Image Converter Website: lvgl.io/tools/imageconverter

2. Select the following options highlighted in the image below:

  • Version: LVGL v9
  • Select an image from your computer
  • Color format: ARGB8888
  • Then, click the Convert button
LVGL Image Converter website LVGL.io v9 ARGB8888

3. It will download a file with the name of your picture but with the .c extension. Open that file and copy the code between brackets { } with many hexadecimal characters.

4. Create a new file called image.h.

5. Copy the code in this repository and paste it into the new image.h file that you’ve just created.

6. Replace the content of the my_image_map variable with the content you’ve just copied in step 3. (Don’t change the name of the my_image_map variable, only copy and replace what is between brackets.

#ifdef __has_include
    #if __has_include("lvgl.h")
        #ifndef LV_LVGL_H_INCLUDE_SIMPLE
            #define LV_LVGL_H_INCLUDE_SIMPLE
        #endif
    #endif
#endif

#if defined(LV_LVGL_H_INCLUDE_SIMPLE)
    #include "lvgl.h"
#else
    #include "lvgl/lvgl.h"
#endif

#define LV_BIG_ENDIAN_SYSTEM

#ifndef LV_ATTRIBUTE_MEM_ALIGN
#define LV_ATTRIBUTE_MEM_ALIGN
#endif

#ifndef LV_ATTRIBUTE_IMG_MY_IMAGE
#define LV_ATTRIBUTE_IMG_MY_IMAGE
#endif

const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_IMG_MY_IMAGE uint8_t my_image_map[] = {REPLACE_WITH_YOUR__IMAGE_ATTRIBUTE};

const lv_image_dsc_t my_image = {
    .header = {
        .magic = LV_IMAGE_HEADER_MAGIC,
        .cf = LV_COLOR_FORMAT_ARGB8888,
        .flags = 0,          
        .w = 128,
        .h = 128,
        //.stride = 120,
        .reserved_2 = 0
    },
    .data_size = sizeof(my_image_map),
    .data = my_image_map,
    .reserved = NULL
};

7. Scroll down on that file and change the following lines with your image width .w and height .h:

const lv_image_dsc_t my_image = {
    .header = {
        .magic = LV_IMAGE_HEADER_MAGIC,
        .cf = LV_COLOR_FORMAT_ARGB8888,
        .flags = 0,          
        .w = 128,
        .h = 128,
        //.stride = 120,
        .reserved_2 = 0
    },
    .data_size = sizeof(my_image_map),
    .data = my_image_map,
    .reserved = NULL
};

8. Finally, save your image.h file.

Important: the image.h file should be placed next to the .ino file in the sketch folder of your project.

LVGL Load Image Arduino Code example folder

Your Arduino IDE should have two tabs:

Arduino IDE tabs LVGL Load Image Arduino Code example folder

ESP32 with TFT LCD: Load and Display Image – Arduino Code

The following code will display an image on the screen. You must have prepared the image.h previously with the image of your choice. Alternatively, you can use our default image.h file. This file should be placed in the sketch folder next to the .ino file.

/*  Rui Santos & Sara Santos - Random Nerd Tutorials - https://RandomNerdTutorials.com/esp32-cyd-lvgl-display-image/
    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>

#include <image.h>

#define SCREEN_WIDTH 240
#define SCREEN_HEIGHT 320

#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();
}

void draw_image(void) {
  LV_IMAGE_DECLARE(my_image);
  lv_obj_t * img1 = lv_image_create(lv_screen_active());
  lv_image_set_src(img1, &my_image);
  lv_obj_align(img1, LV_ALIGN_CENTER, 0, 0);
}

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);

  // 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);
    
  // Function to draw the image
  draw_image();
}

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
}

View raw code

How Does the Code Work?

Let’s take a look at how to display an image on the TFT screen. Alternatively, you can skip to the Demonstration section.

Including Libraries

You need to include the lvgl.h and the TFT_eSPI.h libraries to communicate and display text on the screen.

#include <lvgl.h>
#include <TFT_eSPI.h>

Include the image.h file that contains all the information to draw the image.

#include <image.h>

setup()

In the setup(), include the following lines for debugging. These will print the version of LVGL that you’re using. You must be using version 9.

String LVGL_Arduino = String("LVGL Library Version: ") + lv_version_major() + "." + lv_version_minor() + "." + lv_version_patch();
Serial.begin(115200);
Serial.println(LVGL_Arduino);

Initialize the LVGL Library

Initialize the LVGL Library by calling the lv_init() function in the setup().

// Start LVGL
lv_init();

Register Debugging Function

Register your log_print() function declared previously as a function associated with debugging LVGL.

// Register print function for debugging
lv_log_register_print_cb(log_print);

Create a Display Object

To write to the display, you must create a display object first. You need to do this in all your LVGL sketches. The following lines will create an LVGL display object called disp with the screen width, screen height, and drawing buffer defined earlier.

// 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);

Drawing the image

The LVGL library works asynchronously. You must call the function draw_image() to draw on the display in the setup(). Then, everything works with events and callbacks. The code will always be listening for events in the background.

draw_image();

draw_image()

Create a function called draw_image() that will be called on the setup().

void draw_image(void) {
  LV_IMAGE_DECLARE(my_image);
  lv_obj_t * img1 = lv_image_create(lv_screen_active());
  lv_image_set_src(img1, &my_image);
  lv_obj_align(img1, LV_ALIGN_CENTER, 0, 0);
}

Start by declaring your image using the following line (my_image is declared on the image.h file).

LV_IMAGE_DECLARE(my_image);

Create an image LVGL object on the current screen called img1 using the lv_image_create() function.

lv_obj_t * img1 = lv_image_create(lv_screen_active());

Set the image source using the lv_image_set_src() function and pass as arguments the LVGL image object and image source.

lv_image_set_src(img1, &my_image);

Align the image at the center of the screen.

lv_obj_align(img1, LV_ALIGN_CENTER, 0, 0);

loop()

In the loop(), you can add any other tasks that you need your ESP32 to do like in any regular Arduino sketch. In our case, we won’t add any tasks to the loop().

void loop() {
  lv_task_handler();
  lv_tick_inc(5);
  delay(5);
}

Demonstration

Your image.h file should be next to your .ino file. The image.h file will automatically be uploaded to the board when you upload the code.

After having both files prepared, 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.

Arduino IDE 2 Upload Button

After a few seconds, the screen will display the image as shown in the picture below.

ESP32 with TFT Display Image using LVGL – 2.8 inch ILI9341 240×320 Arduino Code demonstration

Wrapping Up

In this tutorial, you learned how to display images on the TFT LCD Touchscreen with the ESP32 using the LVGL library.

We hope you found this tutorial useful. We’re preparing more guides about this board, so stay tuned. If you would like to learn more about creating graphical user interfaces using the LVGL library with the ESP32, check out our latest eBook:

Other guides you might like reading:

To learn more about the ESP32, make sure to take a look at our resources:



Learn how to build a home automation system and we’ll cover the following main subjects: Node-RED, Node-RED Dashboard, Raspberry Pi, ESP32, ESP8266, MQTT, and InfluxDB database DOWNLOAD »
Learn how to build a home automation system and we’ll cover the following main subjects: Node-RED, Node-RED Dashboard, Raspberry Pi, ESP32, ESP8266, MQTT, and InfluxDB database DOWNLOAD »

Enjoyed this project? Stay updated by subscribing our newsletter!

Leave a Comment

Download Our Free eBooks and Resources

Get instant access to our FREE eBooks, Resources, and Exclusive Electronics Projects by entering your email address below.