Skip to content

3.5inch_Lesson03_Display_Touch_LVGL

1. Course Introduction

In this lesson, we use LovyanGFX within an ESP-IDF project to initialize the 3.5-inch LCD and the GT911 touch panel, then register the display refresh callback and the touch read callback with LVGL 9.1.0. After the program runs, the screen displays the lamp-control interface exported from SquareLine Studio; when the On / Off buttons are tapped, the output state of GPIO18 switches accordingly. For this lesson, the dimensions must be treated as 3.5 inches: the LVGL interface is in landscape orientation at 480 x 320.

Reference materials:

2. Learning Objectives

  • Be able to open and build the Lesson03_LVGL_35 ESP-IDF project.
  • Be able to use SquareLine Studio to create a 480 x 320 LVGL 9.1.0 project.
  • Be able to explain the relationship between LovyanGFX, the LVGL display callback, the touch callback, and the UI files.
  • Be able to describe how Lamp_on / Lamp_off correspond to GPIO18.
  • Be able to perform layered troubleshooting based on a black screen, garbled display, unresponsive touch, or a lamp that does not light up.

3. What You Need

  • Hardware: CrowPanel Advance 3.5-inch ESP32-S3 development board, with an LED or lamp-control load connected externally to GPIO18.
  • Software: VS Code, the ESP-IDF extension, and SquareLine Studio.
  • Project: Lesson03_LVGL_35
  • Key files: main/main.cpp, main/LovyanGFX_Driver.h, main/touch.h, main/ui*.c, main/ui*.h.
  • UI dimensions: 480 x 320, landscape orientation.

Code and Resource Download

Code download: - Lesson03_LVGL_35

Resource download: - table_lamp.png - table_lamp.png

4. ESP-IDF Software Operation Steps

  1. In VS Code, select File -> Open Folder... to open this lesson's project directory.
3.5_ESP_IDF/Lesson03_LVGL_35/

Select Open Folder

image-20260731093045924

  1. After opening the project, first run Build -> Delete to clear the build cache and path records generated by the old project. After switching computers, changing the ESP-IDF version, or copying the project, it is recommended to do this step first.

image-20260729191930020

  1. Confirm that VS Code has loaded ESP-IDF 5.5.4. If the version shown in the status bar or the ESP-IDF extension is incorrect, go back to the Lesson01 installation steps and reselect the 5.5.4 environment.

Confirm ESP-IDF Version

  1. Connect the external LED, and use a USB cable that supports data transfer to connect the development board to the computer.

IMG_8141

  1. Click the serial port location in the bottom status bar of VS Code, and select the actual COM port detected by the computer.

image-20260731093442160

  1. Click the target chip location in the status bar, or run the command ESP-IDF: Set Espressif Device Target, and select esp32s3 as the target chip. The reference image is only meant to show the entry point; the actual selection should follow this course's esp32s3.

image-20260729192318372

image-20260729192338956

  1. When selecting the debug configuration, choose the one that matches the ESP32-S3 development board, such as the ESP32-S3 built-in USB-JTAG or the corresponding ESP32-S3 OpenOCD configuration. Ordinary UART flashing mainly depends on the serial port and the target chip being set correctly.

image-20260729182506501

  1. Click the Build button in the status bar to start compiling, or run the following in the ESP-IDF terminal:
idf.py build

The first build needs to download and generate dependencies, so it will take longer; continue with flashing only after you see the build success message.

image-20260729192536042

image-20260731093558223

image-20260731093652009

  1. Confirm that the flashing method is set to UART, then click the lightning icon Flash, or run the following in the ESP-IDF terminal:
idf.py -p COMx flash

image-20260729192536042

image-20260731093741086

  1. After flashing is complete, click Monitor. Once the program starts, the screen will display the LVGL lamp-control interface, and touching the ON and OFF buttons controls the output state of GPIO18. Observe whether it outputs System starting..., the touch device registration information, and the initialization-complete log.

    image-20260729190836876

    image-20260731093815989

5. Hardware Operation Steps

  1. Use a USB data cable to connect the 3.5-inch development board.

  2. Connect the external LED or lamp-control module to the corresponding GPIO18 interface, and make sure GND is shared (common ground).

IMG_8141

  1. After flashing is complete, check whether the LCD backlight turns on and whether the interface displays completely.

Official website screenshot: UI interface displayed after flashing

  1. Tap the On and Off buttons on the screen and observe whether the lamp state switches.

Official website screenshot: Tapping On turns the lamp on

Official website screenshot: Tapping Off turns the lamp off

6. Key Code Explanation

6.1 LVGL Resolution and Partial Refresh Buffer

#define HOR_RES 480
#define VER_RES 320

static uint16_t buf_1[HOR_RES * 20];
static uint16_t buf_2[HOR_RES * 20];

HOR_RES and VER_RES correspond to the 3.5-inch landscape interface. The buffers store only 20 lines of pixels rather than the entire screen, which reduces RAM usage. If the resolution is set to the 2.4-inch 320 x 240, the lower half of the UI will be lost or the coordinates will be misaligned.

6.2 Display Refresh Callback

void my_disp_flush(lv_display_t *disp, const lv_area_t *area, uint8_t *px_map) {
    uint32_t w = area->x2 - area->x1 + 1;
    uint32_t h = area->y2 - area->y1 + 1;

    gfx.startWrite();
    gfx.setAddrWindow(area->x1, area->y1, w, h);
    gfx.pushPixels(reinterpret_cast<uint16_t *>(px_map), w * h, true);
    gfx.endWrite();

    lv_display_flush_ready(disp);
}

LVGL is responsible for generating pixel data, and LovyanGFX is responsible for writing the pixels to the LCD. lv_display_flush_ready() must be called after the refresh is complete; otherwise LVGL will consider the screen still busy and the interface refresh may stall.

6.3 Touch Read Callback

void my_touchpad_read(lv_indev_t *indev, lv_indev_data_t *data) {
  data->state = LV_INDEV_STATE_REL;
  if ( gfx.getTouch( &touchX, &touchY ) ) {
    data->state = LV_INDEV_STATE_PR;
    data->point.x = touchX;
    data->point.y = touchY;
  }
}

gfx.getTouch() reads the coordinates from the touch chip and passes them to LVGL. When the interface displays but the buttons do not respond, focus on checking the GT911 I2C pins, the touch mapping, and whether this callback is registered.

6.4 Initialization Order

pinMode(38, OUTPUT);
digitalWrite(38, LOW);

gfx.begin();
gfx.setRotation(0);
gfx.setBrightness(128);
digitalWrite(38, HIGH);

lv_init();
lv_tick_set_cb(my_tick_get);

First initialize the LCD, then turn on the backlight, and then initialize LVGL. GPIO38 controls the screen backlight or enable state; when the screen is black, first distinguish whether the backlight is not turned on or whether LVGL is not refreshing the screen.

6.5 UI Initialization and Lamp-Control Events

ui_init();

ui_init() loads the interface exported from SquareLine Studio. The button events are located in ui_events.c:

void Lamp_on(lv_event_t * e)
{
    gpio_set_level(18, 1);
}

void Lamp_off(lv_event_t * e)
{
    gpio_set_level(18, 0);
}

If the touch logs are normal but the lamp does not light up, first check whether the buttons in SquareLine are bound to Lamp_on / Lamp_off, then check the GPIO18 wiring and the load power supply.

7. UI Creation Operation Steps

The UI in this section is created using SquareLine Studio. The official procedure is to first create a TFT_eSPI-compatible UI project, then add the light bulb image, the On button, and the Off button, bind the Lamp_on and Lamp_off callback functions to the two buttons respectively, and export the UI files for the ESP-IDF project.

For SquareLine Studio download and basic installation, refer to:

7.1 Create a SquareLine Project

  1. Open SquareLine Studio and click Create at the top. When creating a new project, you must select LVGL 9.1.0.

  2. In the board category, select the TFT_eSPI-compatible template category shown by SquareLine Studio.

  3. Select the TFT_eSPI project template.

image-20260730190107906

  1. Confirm the resolution based on the screen size. The 3.5-inch course project uses 480 x 320.

16

  1. In Project Settings on the right, set the project name and path, and confirm the key parameters:
Width: 480
Height: 320
Color depth: 16 bit
LVGL version: 9.1.0

image-20260730190141118

  1. After confirming the parameters, click CREATE to create the project.

WeChat Work screenshot_17852958807489

### 7.2 Import the Light Bulb Image Asset

  1. After entering the project editing interface, switch to the Assets area at the bottom.

  2. Click ADD FILE INTO ASSETS to import the light bulb image asset into the project resources.

  3. Of course, you can also choose other images you prefer to use.

  4. The image asset can be downloaded from the 3.5-inch repository asset path: table_lamp.png. Official website screenshot: Open Assets and add the image asset

  5. After importing, drag the light bulb image asset onto the Screen1 canvas. Adjust the position of the image on the canvas so that it is on the left side of the screen, leaving space for the button area on the right.

    Official website screenshot: Place the light bulb image onto the canvas

### 7.3 Add the On Button

  1. In the left Widgets > BASIC panel, select Button.
  2. Drag the Button onto the right side of the canvas to serve as the On button.

Official website screenshot: Add the Button widget

  1. Select the button and adjust its position and size in the Inspector on the right.

    Official website screenshot: Adjust the button size and position

  2. Expand STYLE (MAIN) > Background and set the button background color to orange-red; the official example color is FF5529.

Official website screenshot: Set the On button background color

  1. Add a Label from the left Widgets > BASIC panel and drag it into the button.

Official website screenshot: Add a Label to the button

  1. Select the Label and change the text to On in the text box on the right.

Official website screenshot: Set the Label text to On

  1. Adjust the Label style, set the text color to white, and choose an appropriate font size. Here we use montserrat 40.

Official website screenshot: Set the On text color and font size

  1. In the Hierarchy panel on the right, confirm that Label is a child control of Button.

Official website screenshot: Confirm that Label is under Button

### 7.4 Duplicate and Create the Off Button

  1. In the Hierarchy panel, select the completed Button1.
  2. Open the more menu and select Copy.

Official website screenshot: Duplicate the On button

  1. Paste it as a new button on the canvas or in the hierarchy. Use Paste as child to complete the duplication.

Official website screenshot: Paste the duplicated button

  1. Move the duplicated button below the On button.

Official website screenshot: Move the duplicated button

  1. Select the Label in the new button and change the text to Off.

Official website screenshot: Set the Label text to Off

  1. Adjust the position and background color of the two buttons as needed so that the On / Off buttons are arranged vertically on the right side.

Official website screenshot: Finish the On and Off button styles

3.5_ESP-IDF-03_37

### 7.5 Set Button Events

  1. Select the On button and scroll the Inspector on the right to the EVENTS area.
  2. Click ADD EVENT to add an event.

Official website screenshot: Adding an event for the On button

  1. Set Trigger to RELEASED.
  2. For Action, select CALL FUNCTION.
  3. For Function name, enter:
Lamp_on

Official website screenshot: On button bound to Lamp_on

  1. Select the Off button and add an event in the same way.

  2. Set Trigger to RELEASED, select CALL FUNCTION for Action, and enter the following for Function name:

    Note: The function name used in Call function must exactly match the function name defined in the exported UI project. In this lesson, the ON button uses Lamp_on and the Off button uses Lamp_off. Any error in capitalization will cause the button to fail to light up the LED.

Lamp_off

Official website screenshot: Off button bound to Lamp_off

  1. Click the play button in the upper-right corner to enter preview mode. After adding the events, run the program and verify that the On / Off buttons can be clicked normally.

Official website screenshot: Click the play button to enter preview

Official website screenshot: Play mode active

7.2 Set the Export Path

  1. Click File > Project Settings to open the project settings.

Official website screenshot: Open Project Settings

  1. Under FILE EXPORT, set the export path. In the example, Project Export Root points to the SquareLine project directory and UI Files Export Path points to the Output folder.

Official website screenshot: Set the UI file export path

  1. Set LVGL Include Path to:
lvgl.h
  1. Check Flat export (exports all files to one folder), then click APPLY CHANGES.

Official website screenshot: Set lvgl.h, Flat export, and apply

Note: It is recommended to check Flat export so that the exported UI files are consolidated into a single folder, making it less likely to miss any files when copying them into the ESP-IDF project later.

7.3 Export the UI Files and Copy Them to the IDF Project

  1. Click Export > Export UI Files from the top menu.

Official website screenshot: Export UI Files

  1. Open the exported Output folder and confirm that it contains the UI source files, event files, helper files, and image resource files. Common files include:
ui.c
ui.h
ui_events.c
ui_events.h
ui_helpers.c
ui_helpers.h
ui_Screen1.c
ui_comp_hook.c
ui_img_table_lamp_png.c

image-20260730190806324

  1. Copy the exported UI files into the Lesson03_LVGL_35 ESP-IDF project.

image-20260731095953815

8. Experimental Results

After the program starts, the serial port outputs System starting... along with the touch device registration information. The LCD backlight turns on and displays the LVGL lamp control interface. When the screen is touched, the serial port outputs the Data x and Data y coordinates; after clicking On / Off, the GPIO18 output changes and the external lamp turns on or off accordingly.

image-20260731093815989

Click the On and Off buttons on the screen and observe whether the lamp state toggles.

Official website screenshot: Click On to turn the lamp on

Official website screenshot: Click Off to turn the lamp off

9. Code Download

Code download link: Lesson03_LVGL_35

Lesson03 lamp image download link: table_lamp.png