Peripheral API - LCD - PROBLEM!
Posted: Sat Mar 18, 2023 12:53 pm
Hello, I am a beginner with ESP-IDF, and I'm trying to use LVGL with the IDF-provided LCD drivers. I have both an ST7789V and an ILI9341 display, but using both with a provided example, I get very low performance. The performance is so low, that even an Arduino library beats it. Here is my code (edited version of the spi lcd touch example)
Here is the Arduino code
Here is a video showing the performance of both ESP_LCD (start of the video) and the Arduino TFT_eSPI library (45 second timestamp)
https://youtu.be/RMTQb6jxloo
- /*
- * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
- *
- * SPDX-License-Identifier: CC0-1.0
- */
- #include <stdio.h>
- #include "freertos/FreeRTOS.h"
- #include "freertos/task.h"
- #include "esp_timer.h"
- #include "esp_lcd_panel_io.h"
- #include "esp_lcd_panel_vendor.h"
- #include "esp_lcd_panel_ops.h"
- #include "driver/gpio.h"
- #include "driver/spi_master.h"
- #include "esp_err.h"
- #include "esp_log.h"
- #include "lvgl.h"
- #include "../demos/lv_demos.h"
- #if CONFIG_EXAMPLE_LCD_CONTROLLER_ILI9341
- #include "esp_lcd_ili9341.h"
- #elif CONFIG_EXAMPLE_LCD_CONTROLLER_GC9A01
- #include "esp_lcd_gc9a01.h"
- #endif
- #if CONFIG_EXAMPLE_LCD_TOUCH_CONTROLLER_STMPE610
- #include "esp_lcd_touch_stmpe610.h"
- #endif
- static const char *TAG = "example";
- // Using SPI2 in the example
- #define LCD_HOST HSPI_HOST
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- //////////////////// Please update the following configuration according to your LCD spec //////////////////////////////
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- #define EXAMPLE_LCD_PIXEL_CLOCK_HZ (80 * 1000 * 1000)
- #define EXAMPLE_LCD_BK_LIGHT_ON_LEVEL 1
- #define EXAMPLE_LCD_BK_LIGHT_OFF_LEVEL !EXAMPLE_LCD_BK_LIGHT_ON_LEVEL
- #define EXAMPLE_PIN_NUM_SCLK 14
- #define EXAMPLE_PIN_NUM_MOSI 13
- #define EXAMPLE_PIN_NUM_MISO 12
- #define EXAMPLE_PIN_NUM_LCD_DC 15
- #define EXAMPLE_PIN_NUM_LCD_RST 25
- #define EXAMPLE_PIN_NUM_LCD_CS 26
- #define EXAMPLE_PIN_NUM_BK_LIGHT 27
- #define EXAMPLE_PIN_NUM_TOUCH_CS 15
- #define CONFIG_EXAMPLE_LCD_CONTROLLER_ILI9341 1
- // The pixel number in horizontal and vertical
- #if CONFIG_EXAMPLE_LCD_CONTROLLER_ILI9341
- #define EXAMPLE_LCD_H_RES 320
- #define EXAMPLE_LCD_V_RES 240
- #elif CONFIG_EXAMPLE_LCD_CONTROLLER_GC9A01
- #define EXAMPLE_LCD_H_RES 240
- #define EXAMPLE_LCD_V_RES 240
- #endif
- // Bit number used to represent command and parameter
- #define EXAMPLE_LCD_CMD_BITS 8
- #define EXAMPLE_LCD_PARAM_BITS 8
- #define EXAMPLE_LVGL_TICK_PERIOD_MS 2
- #if CONFIG_EXAMPLE_LCD_TOUCH_ENABLED
- esp_lcd_touch_handle_t tp = NULL;
- #endif
- extern void example_lvgl_demo_ui(lv_disp_t *disp);
- static bool example_notify_lvgl_flush_ready(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *edata, void *user_ctx)
- {
- lv_disp_drv_t *disp_driver = (lv_disp_drv_t *)user_ctx;
- lv_disp_flush_ready(disp_driver);
- return false;
- }
- static void example_lvgl_flush_cb(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_map)
- {
- esp_lcd_panel_handle_t panel_handle = (esp_lcd_panel_handle_t) drv->user_data;
- int offsetx1 = area->x1;
- int offsetx2 = area->x2;
- int offsety1 = area->y1;
- int offsety2 = area->y2;
- // copy a buffer's content to a specific area of the display
- esp_lcd_panel_draw_bitmap(panel_handle, offsetx1, offsety1, offsetx2 + 1, offsety2 + 1, color_map);
- }
- /* Rotate display and touch, when rotated screen in LVGL. Called when driver parameters are updated. */
- static void example_lvgl_port_update_callback(lv_disp_drv_t *drv)
- {
- esp_lcd_panel_handle_t panel_handle = (esp_lcd_panel_handle_t) drv->user_data;
- switch (drv->rotated) {
- case LV_DISP_ROT_NONE:
- // Rotate LCD display
- esp_lcd_panel_swap_xy(panel_handle, false);
- esp_lcd_panel_mirror(panel_handle, true, false);
- #if CONFIG_EXAMPLE_LCD_TOUCH_ENABLED
- // Rotate LCD touch
- esp_lcd_touch_set_mirror_y(tp, false);
- esp_lcd_touch_set_mirror_x(tp, false);
- #endif
- break;
- case LV_DISP_ROT_90:
- // Rotate LCD display
- esp_lcd_panel_swap_xy(panel_handle, true);
- esp_lcd_panel_mirror(panel_handle, true, true);
- #if CONFIG_EXAMPLE_LCD_TOUCH_ENABLED
- // Rotate LCD touch
- esp_lcd_touch_set_mirror_y(tp, false);
- esp_lcd_touch_set_mirror_x(tp, false);
- #endif
- break;
- case LV_DISP_ROT_180:
- // Rotate LCD display
- esp_lcd_panel_swap_xy(panel_handle, false);
- esp_lcd_panel_mirror(panel_handle, false, true);
- #if CONFIG_EXAMPLE_LCD_TOUCH_ENABLED
- // Rotate LCD touch
- esp_lcd_touch_set_mirror_y(tp, false);
- esp_lcd_touch_set_mirror_x(tp, false);
- #endif
- break;
- case LV_DISP_ROT_270:
- // Rotate LCD display
- esp_lcd_panel_swap_xy(panel_handle, true);
- esp_lcd_panel_mirror(panel_handle, false, false);
- #if CONFIG_EXAMPLE_LCD_TOUCH_ENABLED
- // Rotate LCD touch
- esp_lcd_touch_set_mirror_y(tp, false);
- esp_lcd_touch_set_mirror_x(tp, false);
- #endif
- break;
- }
- }
- #if CONFIG_EXAMPLE_LCD_TOUCH_ENABLED
- static void example_lvgl_touch_cb(lv_indev_drv_t * drv, lv_indev_data_t * data)
- {
- uint16_t touchpad_x[1] = {0};
- uint16_t touchpad_y[1] = {0};
- uint8_t touchpad_cnt = 0;
- /* Read touch controller data */
- esp_lcd_touch_read_data(drv->user_data);
- /* Get coordinates */
- bool touchpad_pressed = esp_lcd_touch_get_coordinates(drv->user_data, touchpad_x, touchpad_y, NULL, &touchpad_cnt, 1);
- if (touchpad_pressed && touchpad_cnt > 0) {
- data->point.x = touchpad_x[0];
- data->point.y = touchpad_y[0];
- data->state = LV_INDEV_STATE_PRESSED;
- } else {
- data->state = LV_INDEV_STATE_RELEASED;
- }
- }
- #endif
- static void example_increase_lvgl_tick(void *arg)
- {
- /* Tell LVGL how many milliseconds has elapsed */
- lv_tick_inc(EXAMPLE_LVGL_TICK_PERIOD_MS);
- }
- void app_main(void)
- {
- static lv_disp_draw_buf_t disp_buf; // contains internal graphic buffer(s) called draw buffer(s)
- static lv_disp_drv_t disp_drv; // contains callback functions
- ESP_LOGI(TAG, "Turn off LCD backlight");
- gpio_config_t bk_gpio_config = {
- .mode = GPIO_MODE_OUTPUT,
- .pin_bit_mask = 1ULL << EXAMPLE_PIN_NUM_BK_LIGHT
- };
- ESP_ERROR_CHECK(gpio_config(&bk_gpio_config));
- ESP_LOGI(TAG, "Initialize SPI bus");
- spi_bus_config_t buscfg = {
- .sclk_io_num = EXAMPLE_PIN_NUM_SCLK,
- .mosi_io_num = EXAMPLE_PIN_NUM_MOSI,
- .miso_io_num = EXAMPLE_PIN_NUM_MISO,
- .quadwp_io_num = -1,
- .quadhd_io_num = -1,
- .max_transfer_sz = EXAMPLE_LCD_H_RES * 80 * sizeof(uint16_t),
- };
- ESP_ERROR_CHECK(spi_bus_initialize(LCD_HOST, &buscfg, SPI_DMA_CH_AUTO));
- ESP_LOGI(TAG, "Install panel IO");
- esp_lcd_panel_io_handle_t io_handle = NULL;
- esp_lcd_panel_io_spi_config_t io_config = {
- .dc_gpio_num = EXAMPLE_PIN_NUM_LCD_DC,
- .cs_gpio_num = EXAMPLE_PIN_NUM_LCD_CS,
- .pclk_hz = EXAMPLE_LCD_PIXEL_CLOCK_HZ,
- .lcd_cmd_bits = EXAMPLE_LCD_CMD_BITS,
- .lcd_param_bits = EXAMPLE_LCD_PARAM_BITS,
- .spi_mode = 0,
- .trans_queue_depth = 10,
- .on_color_trans_done = example_notify_lvgl_flush_ready,
- .user_ctx = &disp_drv,
- };
- // Attach the LCD to the SPI bus
- ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)LCD_HOST, &io_config, &io_handle));
- ESP_LOGI(TAG, "Install GC9A01 panel driver");
- esp_lcd_panel_handle_t panel_handle = NULL;
- esp_lcd_panel_dev_config_t panel_config = {
- .reset_gpio_num = EXAMPLE_PIN_NUM_LCD_RST,
- #if CONFIG_EXAMPLE_LCD_CONTROLLER_ILI9341
- .rgb_endian = LCD_RGB_ENDIAN_BGR,
- #elif CONFIG_EXAMPLE_LCD_CONTROLLER_GC9A01
- .rgb_endian = LCD_RGB_ENDIAN_BGR,
- #endif
- .bits_per_pixel = 16,
- };
- #if CONFIG_EXAMPLE_LCD_CONTROLLER_ILI9341
- ESP_ERROR_CHECK(esp_lcd_new_panel_ili9341(io_handle, &panel_config, &panel_handle));
- #elif CONFIG_EXAMPLE_LCD_CONTROLLER_GC9A01
- ESP_ERROR_CHECK(esp_lcd_new_panel_gc9a01(io_handle, &panel_config, &panel_handle));
- #endif
- ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle));
- ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle));
- #if CONFIG_EXAMPLE_LCD_CONTROLLER_GC9A01
- ESP_ERROR_CHECK(esp_lcd_panel_invert_color(panel_handle, true));
- #endif
- ESP_ERROR_CHECK(esp_lcd_panel_mirror(panel_handle, true, false));
- // user can flush pre-defined pattern to the screen before we turn on the screen or backlight
- ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_handle, true));
- #if CONFIG_EXAMPLE_LCD_TOUCH_ENABLED
- esp_lcd_panel_io_handle_t tp_io_handle = NULL;
- esp_lcd_panel_io_spi_config_t tp_io_config = ESP_LCD_TOUCH_IO_SPI_STMPE610_CONFIG(EXAMPLE_PIN_NUM_TOUCH_CS);
- // Attach the TOUCH to the SPI bus
- ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)LCD_HOST, &tp_io_config, &tp_io_handle));
- esp_lcd_touch_config_t tp_cfg = {
- .x_max = EXAMPLE_LCD_H_RES,
- .y_max = EXAMPLE_LCD_V_RES,
- .rst_gpio_num = -1,
- .int_gpio_num = -1,
- .flags = {
- .swap_xy = 0,
- .mirror_x = 0,
- .mirror_y = 0,
- },
- };
- #if CONFIG_EXAMPLE_LCD_TOUCH_CONTROLLER_STMPE610
- ESP_LOGI(TAG, "Initialize touch controller STMPE610");
- ESP_ERROR_CHECK(esp_lcd_touch_new_spi_stmpe610(tp_io_handle, &tp_cfg, &tp));
- #endif // CONFIG_EXAMPLE_LCD_TOUCH_CONTROLLER_STMPE610
- #endif // CONFIG_EXAMPLE_LCD_TOUCH_ENABLED
- ESP_LOGI(TAG, "Turn on LCD backlight");
- gpio_set_level(EXAMPLE_PIN_NUM_BK_LIGHT, EXAMPLE_LCD_BK_LIGHT_ON_LEVEL);
- ESP_LOGI(TAG, "Initialize LVGL library");
- lv_init();
- // alloc draw buffers used by LVGL
- // it's recommended to choose the size of the draw buffer(s) to be at least 1/10 screen sized
- lv_color_t *buf1 = heap_caps_malloc(EXAMPLE_LCD_H_RES * 40 * sizeof(lv_color_t), MALLOC_CAP_DMA);
- assert(buf1);
- lv_color_t *buf2 = heap_caps_malloc(EXAMPLE_LCD_H_RES * 40 * sizeof(lv_color_t), MALLOC_CAP_DMA);
- assert(buf2);
- // initialize LVGL draw buffers
- lv_disp_draw_buf_init(&disp_buf, buf1, buf2, EXAMPLE_LCD_H_RES * 20);
- ESP_LOGI(TAG, "Register display driver to LVGL");
- lv_disp_drv_init(&disp_drv);
- disp_drv.hor_res = EXAMPLE_LCD_H_RES;
- disp_drv.ver_res = EXAMPLE_LCD_V_RES;
- disp_drv.flush_cb = example_lvgl_flush_cb;
- disp_drv.drv_update_cb = example_lvgl_port_update_callback;
- disp_drv.draw_buf = &disp_buf;
- disp_drv.user_data = panel_handle;
- lv_disp_t *disp = lv_disp_drv_register(&disp_drv);
- ESP_LOGI(TAG, "Install LVGL tick timer");
- // Tick interface for LVGL (using esp_timer to generate 2ms periodic event)
- const esp_timer_create_args_t lvgl_tick_timer_args = {
- .callback = &example_increase_lvgl_tick,
- .name = "lvgl_tick"
- };
- esp_timer_handle_t lvgl_tick_timer = NULL;
- ESP_ERROR_CHECK(esp_timer_create(&lvgl_tick_timer_args, &lvgl_tick_timer));
- ESP_ERROR_CHECK(esp_timer_start_periodic(lvgl_tick_timer, EXAMPLE_LVGL_TICK_PERIOD_MS * 1000));
- #if CONFIG_EXAMPLE_LCD_TOUCH_ENABLED
- static lv_indev_drv_t indev_drv; // Input device driver (Touch)
- lv_indev_drv_init(&indev_drv);
- indev_drv.type = LV_INDEV_TYPE_POINTER;
- indev_drv.disp = disp;
- indev_drv.read_cb = example_lvgl_touch_cb;
- indev_drv.user_data = tp;
- lv_indev_drv_register(&indev_drv);
- #endif
- ESP_LOGI(TAG, "Display LVGL Meter Widget");
- /* example_lvgl_demo_ui(disp); */
- lv_demo_music();
- esp_lcd_panel_swap_xy(panel_handle, true);
- esp_lcd_panel_mirror(panel_handle, true, true);
- while (1) {
- lv_timer_handler();
- }
- }
- #include <lvgl.h>
- #include <TFT_eSPI.h>
- #include <demos/lv_demos.h>
- static const uint16_t screenWidth = 320;
- static const uint16_t screenHeight = 240;
- static lv_disp_draw_buf_t draw_buf;
- static lv_color_t buf1[screenWidth * screenHeight / 10];
- static lv_color_t buf2[screenWidth * screenHeight / 10];
- TFT_eSPI tft = TFT_eSPI();
- #if LV_USE_LOG != 0
- void my_print(const char *buf) {
- Serial.printf(buf);
- Serial.flush();
- }
- #endif
- /* Display flushing */
- void my_disp_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p) {
- uint32_t w = (area->x2 - area->x1 + 1);
- uint32_t h = (area->y2 - area->y1 + 1);
- tft.startWrite();
- tft.setAddrWindow(area->x1, area->y1, w, h);
- tft.pushPixelsDMA((uint16_t *)&color_p->full, w * h);
- lv_disp_flush_ready(disp);
- }
- void lv_timer_handler_thread(void *args) {
- while (1) {
- lv_timer_handler(); /* let the GUI do its work */
- /* vTaskDelay(10 / portTICK_PERIOD_MS); */
- }
- }
- void setup() {
- Serial.begin(115200); /* prepare for possible serial debug */
- tft.begin(); /* TFT init */
- tft.setRotation(3); /* Landscape orientation, flipped */
- tft.setSwapBytes(true);
- tft.initDMA();
- lv_init();
- #if LV_USE_LOG != 0
- lv_log_register_print_cb(my_print); /* register print function for debugging */
- #endif
- lv_disp_draw_buf_init(&draw_buf, buf1, buf2, screenWidth * screenHeight / 10);
- /*Initialize the display*/
- static lv_disp_drv_t disp_drv;
- lv_disp_drv_init(&disp_drv);
- disp_drv.hor_res = screenWidth;
- disp_drv.ver_res = screenHeight;
- disp_drv.flush_cb = my_disp_flush;
- disp_drv.draw_buf = &draw_buf;
- lv_disp_t *disp = lv_disp_drv_register(&disp_drv);
- disp->refr_timer->period = 40; // set refresh rate around 25FPS.
- Serial.println("Setup done");
- lv_demo_music();
- }
- void loop() {
- lv_timer_handler();
- }
https://youtu.be/RMTQb6jxloo