Lesson05_I2C_Touch_GT911: ESP32-P4 I2C Touch GT911¶
1. Course Introduction¶
This lesson uses ESP-IDF to initialize the GT911 capacitive touchscreen controller through the I2C master driver and reads touch coordinates via polling. After the program is flashed, the development board powers on and resets; the I2C bus (SDA=GPIO45, SCL=GPIO46) and the GT911 (RST=GPIO40, INT=GPIO42) complete initialization. When the learner touches the screen with a finger, the serial monitor prints the touch coordinates Touch at X=..., Y=... in real time, and stops printing when the finger leaves.
This lesson introduces the I2C bus and touch driver for the first time, and serves as the foundation for subsequent lessons on driving the display and LVGL interaction. Through this experiment, learners will complete end-to-end verification of the full chain: I2C bus creation, device registration, GT911 initialization, and coordinate reading.
2. Learning Objectives¶
- Be able to open the Lesson05 project in ESP-IDF and set the target chip to
esp32p4. - Be able to explain the call order and respective roles of
i2c_new_master_bus,esp_lcd_new_panel_io_i2c, andesp_lcd_touch_new_i2c_gt911. - Be able to explain the fallback mechanism for the GT911 primary and backup I2C addresses.
- Be able to complete compilation and flashing, and touch the screen to observe whether the serial port prints coordinates.
- Be able to determine whether the I2C and touch chain is functioning properly based on whether the coordinates change as the finger moves.
3. Prerequisites¶
- Hardware: one CrowPanel Advanced 7 / 9 / 10.1-inch ESP32-P4 HMI AI Display development board, and one USB Type-C data cable that supports data transfer.
- Compatibility note: The hardware and software code for the 7 / 9 / 10.1-inch development boards are fully interchangeable; only the board dimensions differ. Please select the appropriate model based on display size and use case.
- Software: VS Code, ESP-IDF Extension (ESP-IDF v5.4 or later).
- Project dependencies: retain the
main/main.c,peripheral/bsp_i2c, andperipheral/bsp_displaycomponents, as well as theesp_lcd_touch_gt911managed component. - Configuration: target chip
esp32p4; I2C port 0, SDA=GPIO45, SCL=GPIO46, 100 kHz; touch resolution 1024×600.
Code download link:
4. Software Operation Steps¶
-
In VS Code, open the ESP-IDF Extension panel, click Open ESP-IDF Project, and select the
Lesson05-Touchscreenfolder.
-
First select the code runtime environment ESP-IDF v5.4.2, set the flashing method to UART, and select the serial port that actually corresponds to your development board. Then click Set Espressif Device Target in the ESP-IDF Extension panel and select
esp32p4. Once configured, the status bar should display ESP-IDF v5.4.2, UART, the required COM port, and ESP32-P4.
-
Click SDK Configuration Editor in the VS Code bottom status bar or the ESP-IDF extension panel, and wait for the configuration page to fully load before modifying parameters. If the page is still loading, do not click Build immediately.

-
Enter
flashin the search box and ensure Flash SPI mode:QIO; Flash Sampling Mode:STR Mode; Flash SPI speed:80 MHz; Flash size:16 MB. These parameters should match the onboard Flash of the Advance-P4 board.
-
After verifying the configuration is correct, click Save in the top-right corner; confirm the changes have been saved, then run Build to compile.
-
Click Full Clean to clear the cache left over from the previous compilation. Performing this after the first build, when switching project configuration, or after modifying SDK parameters prevents stale configuration from affecting the new build result.

-
Click Build to compile the project. The first build will automatically download the
esp_lcd_touch_gt911component, and on success it outputsProject build complete.
-
Confirm the development board is connected to the computer via USB, then click Select Port to Use to choose the serial port.
-
Click Flash to flash the firmware. Upon completion, it displays
Hard resetting....
-
After flashing is complete, click Monitor to open the serial monitor at a baud rate of 115200. You should see the
Touch application started successfullylog. PressCtrl + ]to exit the monitor.
-
Finally, you can use the one-click operation button in the ESP-IDF status bar to sequentially execute compile, flash, and open serial monitor. Use this only after the project configuration, serial port, and code have all been confirmed correct; if you need to troubleshoot, you should still follow the steps above one by one.

5. Hardware Operation Steps¶
- Connect the ESP32-P4 development board to the computer using a USB data cable. Confirm that the touchscreen FFC cable is correctly inserted into the development board's FPC connector.

- After flashing is complete and the board resets, observe whether the serial port prints
I2C initializationandTouch application started successfully.
- Touch any position on the screen with a finger, and observe whether the serial port prints
Touch at X=..., Y=...; the coordinates should change as the finger moves.
- After the finger leaves the screen, observe whether the serial port stops printing coordinates, confirming that touch detection is working properly.

6. Key Code Explanation¶
i2c_master_bus_config_t conf = {
.i2c_port = I2C_MASTER_PORT,
.sda_io_num = I2C_GPIO_SDA,
.scl_io_num = I2C_GPIO_SCL,
.clk_source = I2C_CLK_SRC_DEFAULT,
.glitch_ignore_cnt = 7,
.flags.enable_internal_pullup = true,
};
err = i2c_new_master_bus(&conf, &i2c_bus_handle);
This creates the I2C master bus. sda_io_num/scl_io_num specify GPIO45/GPIO46; glitch_ignore_cnt=7 is the glitch filter length, used to filter out spike interference on the bus; enable_internal_pullup enables the internal pull-up. If the SDA/SCL pins are misconfigured or the pull-up is not enabled, I2C communication will fail and touch initialization will report an error. Note: for high-speed operation (400 kHz) or long traces, an external pull-up is recommended.
err = esp_lcd_touch_new_i2c_gt911(tp_io_handle, &tp_cfg, &tp);
if (err != ESP_OK) {
io_config.dev_addr = ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS_BACKUP;
...
}
The GT911 has two I2C addresses (primary and backup); the specific address depends on the level of the INT pin at power-up. The code first uses the primary address and automatically falls back to the backup address on failure. If the fallback logic is removed, initialization may fail under certain power-up sequences, manifesting as the serial port printing Touch initialization failed.
err = esp_lcd_touch_read_data(tp);
...
if (esp_lcd_touch_get_coordinates(tp, touch_x, touch_y, touch_strength, &touch_cnt, 1)) {
set_coor(touch_x[0], touch_y[0], true);
} else {
set_coor(0xffff, 0xffff, false);
}
esp_lcd_touch_read_data triggers a single register read; esp_lcd_touch_get_coordinates extracts the coordinates from the internal buffer. Returning true indicates a touch point is present, while returning false indicates no touch. When there is no touch, the coordinates are set to 0xffff as an "invalid" marker. If read_data is called without calling get_coordinates, the cached coordinates will not be updated and the serial port will keep printing stale values.
The task polls every 50 ms. Too long an interval (e.g., 500 ms) leads to sluggish touch response; too short an interval (e.g., 5 ms) wastes CPU and I2C bandwidth. 50 ms strikes a balance between responsiveness and resource consumption.
7. Experimental Phenomena¶
After the program is flashed and the board resets, the serial monitor outputs:
I (xxx) TOUCH_APP: Starting touch application
I (xxx) TOUCH_APP: Touch application started successfully
The task then enters polling. When the finger is not touching the screen, the serial port prints no coordinates; when the finger touches the screen, the serial port prints continuously.
The coordinates should change in real time as the finger moves, with the X range being 0–1023 and the Y range being 0–599. Printing stops after the finger leaves. If the serial port never outputs coordinates, priority should be given to checking whether the I2C pins and the GT911 reset/interrupt pins are correct; if the coordinates do not change as the finger moves, check whether x_max/y_max match the panel.
