# ESP LCD GC9D01 [](https://components.espressif.com/components/hwzlovedz/esp_lcd_gc9d01) Implementation of the GC9D01 LCD controller with esp_lcd component. | LCD controller | Communication interface | Component name | Link to datasheet | | :------------: | :---------------------: | :------------: | :---------------: | | GC9D01 | SPI | esp_lcd_gc9d01 | [GALAXYCORE](https://files.waveshare.com/wiki/0.71inch-LCD-Module/GC9D01N_DataSheet_V1.1.pdf) | ## Add to project Packages from this repository are uploaded to [Espressif's component service](https://components.espressif.com/). You can add them to your project via `idf.py add-dependancy`, e.g. ``` idf.py add-dependency "hwzlovedz/esp_lcd_gc9d01^0.0.1" ``` Alternatively, you can create `idf_component.yml`. More is in [Espressif's documentation](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/tools/idf-component-manager.html). ## Example use ```c ESP_LOGI(TAG, "Initialize SPI bus"); const spi_bus_config_t bus_config = GC9D01_PANEL_BUS_SPI_CONFIG(EXAMPLE_PIN_NUM_LCD_PCLK, EXAMPLE_PIN_NUM_LCD_MOSI, EXAMPLE_LCD_H_RES * 80 * sizeof(uint16_t)); ESP_ERROR_CHECK(spi_bus_initialize(EXAMPLE_LCD_HOST, &bus_config, SPI_DMA_CH_AUTO)); ESP_LOGI(TAG, "Install panel IO"); esp_lcd_panel_io_handle_t io_handle = NULL; const esp_lcd_panel_io_spi_config_t io_config = GC9D01_PANEL_IO_SPI_CONFIG(EXAMPLE_PIN_NUM_LCD_CS, EXAMPLE_PIN_NUM_LCD_DC, example_callback, &example_callback_ctx); ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)EXAMPLE_LCD_HOST, &io_config, &io_handle)); /** * Uncomment these lines if use custom initialization commands. * The array should be declared as "static const" and positioned outside the function. */ // static const gc9d01_lcd_init_cmd_t lcd_init_cmds[] = { // // {cmd, { data }, data_size, delay_ms} // {0xfe, (uint8_t []){0x00}, 0, 0}, // {0xef, (uint8_t []){0x00}, 0, 0}, // {0xeb, (uint8_t []){0x14}, 1, 0}, // ... // }; ESP_LOGI(TAG, "Install GC9D01 panel driver"); esp_lcd_panel_handle_t panel_handle = NULL; // gc9d01_vendor_config_t vendor_config = { // Uncomment these lines if use custom initialization commands // .init_cmds = lcd_init_cmds, // .init_cmds_size = sizeof(lcd_init_cmds) / sizeof(gc9d01_lcd_init_cmd_t), // }; const esp_lcd_panel_dev_config_t panel_config = { .reset_gpio_num = EXAMPLE_PIN_NUM_LCD_RST, // Set to -1 if not use #if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) .color_space = ESP_LCD_COLOR_SPACE_RGB, #else .rgb_endian = LCD_RGB_ENDIAN_RGB, #endif .bits_per_pixel = 16, // Implemented by LCD command `3Ah` (16/18) // .vendor_config = &vendor_config, // Uncomment this line if use custom initialization commands }; ESP_ERROR_CHECK(esp_lcd_new_panel_gc9d01(io_handle, &panel_config, &panel_handle)); ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle)); ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle)); #if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) ESP_ERROR_CHECK(esp_lcd_panel_disp_off(panel_handle, false)); #else ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_handle, true)); #endif ``` There is an example in ESP-IDF with this LCD controller. Please follow this [link](https://github.com/espressif/esp-idf/tree/master/examples/peripherals/lcd/spi_lcd_touch). *** ## 推荐与 `esp_lvgl_port` 组件配合使用,点屏如呼吸 ```c /* * SPDX-License-Identifier: Apache-2.0 */ #include "esp_err.h" #include "esp_log.h" #include "esp_check.h" #include "driver/i2c.h" #include "driver/gpio.h" #include "driver/spi_master.h" #include "esp_lcd_panel_io.h" #include "esp_lcd_panel_vendor.h" #include "esp_lcd_panel_ops.h" #include "esp_lvgl_port.h" // #include "esp_lcd_gc9a01.h" #include "esp_lcd_gc9d01.h" #include "lv_examples.h" // #include "esp_lcd_touch_tt21100.h" /* LCD size */ #define EXAMPLE_LCD_H_RES (160) #define EXAMPLE_LCD_V_RES (160) /* LCD settings */ #define EXAMPLE_LCD_SPI_NUM (SPI2_HOST) #define EXAMPLE_LCD_PIXEL_CLK_HZ (SPI_MASTER_FREQ_80M) #define EXAMPLE_LCD_CMD_BITS (8) #define EXAMPLE_LCD_PARAM_BITS (8) #define EXAMPLE_LCD_COLOR_SPACE (ESP_LCD_COLOR_SPACE_BGR) #define EXAMPLE_LCD_BITS_PER_PIXEL (16) #define EXAMPLE_LCD_DRAW_BUFF_DOUBLE (1) #define EXAMPLE_LCD_DRAW_BUFF_HEIGHT (160) // 全刷缓冲区必须比分辨率高,局部刷新可以小于分辨率 // #define EXAMPLE_LCD_BL_ON_LEVEL (1) /* LCD pins */ #define EXAMPLE_LCD_GPIO_SCLK (GPIO_NUM_39) #define EXAMPLE_LCD_GPIO_MOSI (GPIO_NUM_38) #define EXAMPLE_LCD_GPIO_RST (GPIO_NUM_45) #define EXAMPLE_LCD_GPIO_DC (GPIO_NUM_40) #define EXAMPLE_LCD_GPIO_CS0 (GPIO_NUM_47) #define EXAMPLE_LCD_GPIO_CS1 (GPIO_NUM_48) // #define EXAMPLE_LCD_GPIO_BL (GPIO_NUM_NC) /* Touch settings */ // #define EXAMPLE_TOUCH_I2C_NUM (0) // #define EXAMPLE_TOUCH_I2C_CLK_HZ (400000) /* LCD touch pins */ // #define EXAMPLE_TOUCH_I2C_SCL (GPIO_NUM_18) // #define EXAMPLE_TOUCH_I2C_SDA (GPIO_NUM_8) // #define EXAMPLE_TOUCH_GPIO_INT (GPIO_NUM_3) static const char *TAG = "EXAMPLE"; // LVGL image declare // LV_IMG_DECLARE(esp_logo) /* LCD IO and panel */ static esp_lcd_panel_io_handle_t lcd_io = NULL; static esp_lcd_panel_handle_t lcd_panel = NULL; // static esp_lcd_touch_handle_t touch_handle = NULL; /* LVGL display and touch */ static lv_display_t *lvgl_disp = NULL; // static lv_indev_t *lvgl_touch_indev = NULL; static esp_err_t app_lcd_init(void) { esp_err_t ret = ESP_OK; /* LCD backlight */ // gpio_config_t bk_gpio_config = { // .mode = GPIO_MODE_OUTPUT, // .pin_bit_mask = 1ULL << EXAMPLE_LCD_GPIO_BL // }; // ESP_ERROR_CHECK(gpio_config(&bk_gpio_config)); /* LCD initialization */ ESP_LOGI(TAG, "Initialize SPI bus"); const spi_bus_config_t buscfg = { .sclk_io_num = EXAMPLE_LCD_GPIO_SCLK, .mosi_io_num = EXAMPLE_LCD_GPIO_MOSI, .miso_io_num = GPIO_NUM_NC, .quadwp_io_num = GPIO_NUM_NC, .quadhd_io_num = GPIO_NUM_NC, .max_transfer_sz = EXAMPLE_LCD_H_RES * EXAMPLE_LCD_DRAW_BUFF_HEIGHT * sizeof(uint16_t), }; ESP_RETURN_ON_ERROR(spi_bus_initialize(EXAMPLE_LCD_SPI_NUM, &buscfg, SPI_DMA_CH_AUTO), TAG, "SPI init failed"); ESP_LOGI(TAG, "Install panel IO"); const esp_lcd_panel_io_spi_config_t io_config = { .dc_gpio_num = EXAMPLE_LCD_GPIO_DC, .cs_gpio_num = EXAMPLE_LCD_GPIO_CS0, .pclk_hz = EXAMPLE_LCD_PIXEL_CLK_HZ, .lcd_cmd_bits = EXAMPLE_LCD_CMD_BITS, .lcd_param_bits = EXAMPLE_LCD_PARAM_BITS, .spi_mode = 0, .trans_queue_depth = 10, }; ESP_GOTO_ON_ERROR(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)EXAMPLE_LCD_SPI_NUM, &io_config, &lcd_io), err, TAG, "New panel IO failed"); ESP_LOGI(TAG, "Install LCD driver"); printf(" _______ ______ ______ ______ ______ ____ \r\n"); printf("/______/\\ /_____/\\ /_____/\\ /_____/\\ /_____/\\ /___/\\ \r\n"); printf("\\::::__\\/__ \\:::__\\/ \\:::_:\\ \\ \\:::_ \\ \\ \\:::_ \\ \\ \\_::\\ \\ \r\n"); printf(" \\:\\ /____/\\ \\:\\ \\ __ \\:\\_\\:\\ \\ \\:\\ \\ \\ \\ \\:\\ \\ \\ \\ \\::\\ \\ \r\n"); printf(" \\:\\\\_ _\\/ \\:\\ \\/_/\\ \\::__:\\ \\ \\:\\ \\ \\ \\ \\:\\ \\ \\ \\ _\\: \\ \\__ \r\n"); printf(" \\:\\_\\ \\ \\ \\:\\_\\ \\ \\ \\ \\ \\ \\:\\/.:| | \\:\\_\\ \\ \\ /__\\: \\__/\\ \r\n"); printf(" \\_____\\/ \\_____\\/ \\_\\/ \\____/_/ \\_____\\/ \\________\\/ \r\n"); printf(" \r\n"); const esp_lcd_panel_dev_config_t panel_config = { .reset_gpio_num = EXAMPLE_LCD_GPIO_RST, .color_space = EXAMPLE_LCD_COLOR_SPACE, .bits_per_pixel = EXAMPLE_LCD_BITS_PER_PIXEL, }; ESP_GOTO_ON_ERROR(esp_lcd_new_panel_gc9d01(lcd_io, &panel_config, &lcd_panel), err, TAG, "New panel failed"); esp_lcd_panel_reset(lcd_panel); esp_lcd_panel_init(lcd_panel); esp_lcd_panel_invert_color(lcd_panel, false); esp_lcd_panel_mirror(lcd_panel, true, true); esp_lcd_panel_disp_on_off(lcd_panel, true); /* LCD backlight on */ // ESP_ERROR_CHECK(gpio_set_level(EXAMPLE_LCD_GPIO_BL, EXAMPLE_LCD_BL_ON_LEVEL)); return ret; err: if (lcd_panel) { esp_lcd_panel_del(lcd_panel); } if (lcd_io) { esp_lcd_panel_io_del(lcd_io); } spi_bus_free(EXAMPLE_LCD_SPI_NUM); return ret; } // static esp_err_t app_touch_init(void) // { // /* Initilize I2C */ // const i2c_config_t i2c_conf = { // .mode = I2C_MODE_MASTER, // .sda_io_num = EXAMPLE_TOUCH_I2C_SDA, // .sda_pullup_en = GPIO_PULLUP_DISABLE, // .scl_io_num = EXAMPLE_TOUCH_I2C_SCL, // .scl_pullup_en = GPIO_PULLUP_DISABLE, // .master.clk_speed = EXAMPLE_TOUCH_I2C_CLK_HZ // }; // ESP_RETURN_ON_ERROR(i2c_param_config(EXAMPLE_TOUCH_I2C_NUM, &i2c_conf), TAG, "I2C configuration failed"); // ESP_RETURN_ON_ERROR(i2c_driver_install(EXAMPLE_TOUCH_I2C_NUM, i2c_conf.mode, 0, 0, 0), TAG, "I2C initialization failed"); // /* Initialize touch HW */ // const esp_lcd_touch_config_t tp_cfg = { // .x_max = EXAMPLE_LCD_H_RES, // .y_max = EXAMPLE_LCD_V_RES, // .rst_gpio_num = GPIO_NUM_NC, // Shared with LCD reset // .int_gpio_num = EXAMPLE_TOUCH_GPIO_INT, // .levels = { // .reset = 0, // .interrupt = 0, // }, // .flags = { // .swap_xy = 0, // .mirror_x = 1, // .mirror_y = 0, // }, // }; // esp_lcd_panel_io_handle_t tp_io_handle = NULL; // const esp_lcd_panel_io_i2c_config_t tp_io_config = ESP_LCD_TOUCH_IO_I2C_TT21100_CONFIG(); // ESP_RETURN_ON_ERROR(esp_lcd_new_panel_io_i2c((esp_lcd_i2c_bus_handle_t)EXAMPLE_TOUCH_I2C_NUM, &tp_io_config, &tp_io_handle), TAG, ""); // return esp_lcd_touch_new_i2c_tt21100(tp_io_handle, &tp_cfg, &touch_handle); // } static esp_err_t app_lvgl_init(void) { /* Initialize LVGL */ const lvgl_port_cfg_t lvgl_cfg = { .task_priority = 4, /* LVGL task priority */ .task_stack = 4096, /* LVGL task stack size */ .task_affinity = -1, /* LVGL task pinned to core (-1 is no affinity) */ .task_max_sleep_ms = 500, /* Maximum sleep in LVGL task */ .timer_period_ms = 5 /* LVGL timer tick period in ms */ }; ESP_RETURN_ON_ERROR(lvgl_port_init(&lvgl_cfg), TAG, "LVGL port initialization failed"); /* Add LCD screen */ ESP_LOGD(TAG, "Add LCD screen"); const lvgl_port_display_cfg_t disp_cfg = { .io_handle = lcd_io, .panel_handle = lcd_panel, .buffer_size = EXAMPLE_LCD_H_RES * EXAMPLE_LCD_DRAW_BUFF_HEIGHT, .double_buffer = EXAMPLE_LCD_DRAW_BUFF_DOUBLE, .hres = EXAMPLE_LCD_H_RES, .vres = EXAMPLE_LCD_V_RES, .monochrome = false, #if LVGL_VERSION_MAJOR >= 9 .color_format = LV_COLOR_FORMAT_RGB565, #endif .rotation = { .swap_xy = false, .mirror_x = false, .mirror_y = false, }, .flags = { .buff_dma = true, .buff_spiram = true, // 双缓冲+DMA使用外部PSRAM #if LVGL_VERSION_MAJOR >= 9 .swap_bytes = true, #endif .full_refresh = true, // 这个屌屏幕驱动局部刷新会有乱点 } }; lvgl_disp = lvgl_port_add_disp(&disp_cfg); // /* Add touch input (for selected screen) */ // const lvgl_port_touch_cfg_t touch_cfg = { // .disp = lvgl_disp, // .handle = touch_handle, // }; // lvgl_touch_indev = lvgl_port_add_touch(&touch_cfg); return ESP_OK; } static void app_main_display(void) { lv_obj_t *scr = lv_scr_act(); /* Task lock */ lvgl_port_lock(0); /* LCD HW rotation */ // lv_disp_set_rotation(lvgl_disp, LV_DISPLAY_ROTATION_0); /* Your LVGL objects code here .... */ lv_example_get_started_1(); /* Task unlock */ lvgl_port_unlock(); } void app_main(void) { /* LCD HW initialization */ ESP_ERROR_CHECK(app_lcd_init()); /* Touch initialization */ // ESP_ERROR_CHECK(app_touch_init()); /* LVGL initialization */ ESP_ERROR_CHECK(app_lvgl_init()); /* Show LVGL objects */ app_main_display(); } ``` ## 终端打印 ``` I (26) boot: ESP-IDF v5.4.1 2nd stage bootloader I (27) boot: compile time Jul 6 2025 00:09:55 I (27) boot: Multicore bootloader I (27) boot: chip revision: v0.2 I (30) boot: efuse block revision: v1.3 I (33) qio_mode: Enabling default flash chip QIO I (38) boot.esp32s3: Boot SPI Speed : 80MHz I (42) boot.esp32s3: SPI Mode : QIO I (45) boot.esp32s3: SPI Flash Size : 16MB I (49) boot: Enabling RNG early entropy source... I (54) boot: Partition Table: I (56) boot: ## Label Usage Type ST Offset Length I (63) boot: 0 nvs WiFi data 01 02 00009000 00006000 I (69) boot: 1 phy_init RF data 01 01 0000f000 00001000 I (76) boot: 2 factory factory app 00 00 00010000 00177000 I (82) boot: End of partition table I (85) esp_image: segment 0: paddr=00010020 vaddr=3c060020 size=133c0h ( 78784) map I (105) esp_image: segment 1: paddr=000233e8 vaddr=3fc96d00 size=03090h ( 12432) load I (107) esp_image: segment 2: paddr=00026480 vaddr=40374000 size=09b98h ( 39832) load I (116) esp_image: segment 3: paddr=00030020 vaddr=42000020 size=55600h (349696) map I (168) esp_image: segment 4: paddr=00085628 vaddr=4037db98 size=090c4h ( 37060) load I (176) esp_image: segment 5: paddr=0008e6f4 vaddr=600fe100 size=0001ch ( 28) load I (183) boot: Loaded app from partition at offset 0x10000 I (183) boot: Disabling RNG early entropy source... I (194) octal_psram: vendor id : 0x0d (AP) I (194) octal_psram: dev id : 0x02 (generation 3) I (194) octal_psram: density : 0x03 (64 Mbit) I (196) octal_psram: good-die : 0x01 (Pass) I (200) octal_psram: Latency : 0x01 (Fixed) I (205) octal_psram: VCC : 0x01 (3V) I (209) octal_psram: SRF : 0x01 (Fast Refresh) I (214) octal_psram: BurstType : 0x01 (Hybrid Wrap) I (219) octal_psram: BurstLen : 0x01 (32 Byte) I (223) octal_psram: Readlatency : 0x02 (10 cycles@Fixed) I (228) octal_psram: DriveStrength: 0x00 (1/1) I (233) MSPI Timing: PSRAM timing tuning index: 4 I (237) esp_psram: Found 8MB PSRAM device I (241) esp_psram: Speed: 80MHz I (244) cpu_start: Multicore app I (673) esp_psram: SPI SRAM memory test OK I (681) cpu_start: Pro cpu start user code I (681) cpu_start: cpu freq: 240000000 Hz I (681) app_init: Application information: I (682) app_init: Project name: LVGL9_LCD_TOUCH_TEST_0.71 I (687) app_init: App version: 1 I (690) app_init: Compile time: Jul 6 2025 00:09:01 I (695) app_init: ELF file SHA256: 2813ddf0b... I (700) app_init: ESP-IDF: v5.4.1 I (703) efuse_init: Min chip rev: v0.0 I (707) efuse_init: Max chip rev: v0.99 I (711) efuse_init: Chip rev: v0.2 I (715) heap_init: Initializing. RAM available for dynamic allocation: I (721) heap_init: At 3FCAAA68 len 0003ECA8 (251 KiB): RAM I (726) heap_init: At 3FCE9710 len 00005724 (21 KiB): RAM I (732) heap_init: At 3FCF0000 len 00008000 (32 KiB): DRAM I (737) heap_init: At 600FE11C len 00001ECC (7 KiB): RTCRAM I (742) esp_psram: Adding pool of 8192K of PSRAM memory to heap allocator I (749) spi_flash: detected chip: generic I (752) spi_flash: flash io: qio I (755) sleep_gpio: Configure to isolate all GPIO pins in sleep state I (762) sleep_gpio: Enable automatic switching of GPIO sleep configuration I (768) main_task: Started on CPU0 I (778) esp_psram: Reserving pool of 64K of internal memory for DMA/internal allocations I (778) main_task: Calling app_main() I (778) EXAMPLE: Initialize SPI bus I (788) EXAMPLE: Install panel IO I (788) gpio: GPIO[40]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 I (798) EXAMPLE: Install LCD driver _______ ______ ______ ______ ______ ____ /______/\ /_____/\ /_____/\ /_____/\ /_____/\ /___/\ \::::__\/__ \:::__\/ \:::_:\ \ \:::_ \ \ \:::_ \ \ \_::\ \ \:\ /____/\ \:\ \ __ \:\_\:\ \ \:\ \ \ \ \:\ \ \ \ \::\ \ \:\\_ _\/ \:\ \/_/\ \::__:\ \ \:\ \ \ \ \:\ \ \ \ _\: \ \__ \:\_\ \ \ \:\_\ \ \ \ \ \ \:\/.:| | \:\_\ \ \ /__\: \__/\ \_____\/ \_____\/ \_\/ \____/_/ \_____\/ \________\/ I (858) gpio: GPIO[45]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 I (868) gc9d01: LCD panel create success, version: 0.0.1 W (988) gc9d01: The 3Ah command has been used and will be overwritten by external initialization sequence W (988) gc9d01: The 36h command has been used and will be overwritten by external initialization sequence I (1188) LVGL: Starting LVGL task I (1198) main_task: Returned from app_main() ```
idf.py add-dependency "hwzlovedz/esp_lcd_gc9d01^0.0.3"