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_35ESP-IDF project. - Be able to use SquareLine Studio to create a
480 x 320LVGL 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_offcorrespond 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¶
- In VS Code, select
File->Open Folder...to open this lesson's project directory.
- After opening the project, first run
Build->Deleteto 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.
- 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 the5.5.4environment.
- Connect the external LED, and use a USB cable that supports data transfer to connect the development board to the computer.
- Click the serial port location in the bottom status bar of VS Code, and select the actual
COMport detected by the computer.
- Click the target chip location in the status bar, or run the command
ESP-IDF: Set Espressif Device Target, and selectesp32s3as the target chip. The reference image is only meant to show the entry point; the actual selection should follow this course'sesp32s3.
- 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.
- Click the
Buildbutton in the status bar to start compiling, or run the following in the ESP-IDF terminal:
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.
- Confirm that the flashing method is set to
UART, then click the lightning iconFlash, or run the following in the ESP-IDF terminal:
-
After flashing is complete, click
Monitor. Once the program starts, the screen will display the LVGL lamp-control interface, and touching theONandOFFbuttons controls the output state of GPIO18. Observe whether it outputsSystem starting..., the touch device registration information, and the initialization-complete log.
5. Hardware Operation Steps¶
-
Use a USB data cable to connect the 3.5-inch development board.
-
Connect the external LED or lamp-control module to the corresponding GPIO18 interface, and make sure GND is shared (common ground).
- After flashing is complete, check whether the LCD backlight turns on and whether the interface displays completely.
- Tap the
OnandOffbuttons on the screen and observe whether the lamp state switches.
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() 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¶
-
Open SquareLine Studio and click Create at the top. When creating a new project, you must select LVGL
9.1.0. -
In the board category, select the TFT_eSPI-compatible template category shown by SquareLine Studio.
-
Select the TFT_eSPI project template.
- Confirm the resolution based on the screen size. The 3.5-inch course project uses
480 x 320.
- In Project Settings on the right, set the project name and path, and confirm the key parameters:
- After confirming the parameters, click CREATE to create the project.
### 7.2 Import the Light Bulb Image Asset
-
After entering the project editing interface, switch to the Assets area at the bottom.
-
Click ADD FILE INTO ASSETS to import the light bulb image asset into the project resources.
-
Of course, you can also choose other images you prefer to use.
-
The image asset can be downloaded from the 3.5-inch repository asset path: table_lamp.png.

-
After importing, drag the light bulb image asset onto the
Screen1canvas. 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.
### 7.3 Add the On Button
- In the left Widgets > BASIC panel, select Button.
- Drag the Button onto the right side of the canvas to serve as the
Onbutton.
-
Select the button and adjust its position and size in the Inspector on the right.
-
Expand STYLE (MAIN) > Background and set the button background color to orange-red; the official example color is
FF5529.
- Add a Label from the left Widgets > BASIC panel and drag it into the button.
- Select the Label and change the text to
Onin the text box on the right.
- Adjust the Label style, set the text color to white, and choose an appropriate font size. Here we use
montserrat 40.
- In the Hierarchy panel on the right, confirm that
Labelis a child control ofButton.
### 7.4 Duplicate and Create the Off Button
- In the Hierarchy panel, select the completed
Button1. - Open the more menu and select Copy.
- Paste it as a new button on the canvas or in the hierarchy. Use Paste as child to complete the duplication.
- Move the duplicated button below the
Onbutton.
- Select the Label in the new button and change the text to
Off.
- Adjust the position and background color of the two buttons as needed so that the
On/Offbuttons are arranged vertically on the right side.
### 7.5 Set Button Events
- Select the
Onbutton and scroll the Inspector on the right to the EVENTS area. - Click ADD EVENT to add an event.
- Set Trigger to
RELEASED. - For Action, select
CALL FUNCTION. - For Function name, enter:
-
Select the
Offbutton and add an event in the same way. -
Set Trigger to
RELEASED, selectCALL FUNCTIONfor 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
ONbutton usesLamp_onand theOffbutton usesLamp_off. Any error in capitalization will cause the button to fail to light up the LED.
- 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/Offbuttons can be clicked normally.
7.2 Set the Export Path¶
- Click File > Project Settings to open the project settings.
- Under FILE EXPORT, set the export path. In the example,
Project Export Rootpoints to the SquareLine project directory andUI Files Export Pathpoints to theOutputfolder.
- Set
LVGL Include Pathto:
- Check Flat export (exports all files to one folder), then click APPLY CHANGES.
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¶
- Click Export > Export UI Files from the top menu.
- Open the exported
Outputfolder 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
- Copy the exported UI files into the
Lesson03_LVGL_35ESP-IDF project.
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.
Click the On and Off buttons on the screen and observe whether the lamp state toggles.
9. Code Download¶
Code download link: Lesson03_LVGL_35
Lesson03 lamp image download link: table_lamp.png













































