Peripheral API - LCD - PROBLEM!

Windorey
Posts: 3
Joined: Thu Mar 16, 2023 9:19 pm

Peripheral API - LCD - PROBLEM!

Postby Windorey » 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)
  1. /*
  2.  * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
  3.  *
  4.  * SPDX-License-Identifier: CC0-1.0
  5.  */
  6.  
  7. #include <stdio.h>
  8. #include "freertos/FreeRTOS.h"
  9. #include "freertos/task.h"
  10. #include "esp_timer.h"
  11. #include "esp_lcd_panel_io.h"
  12. #include "esp_lcd_panel_vendor.h"
  13. #include "esp_lcd_panel_ops.h"
  14. #include "driver/gpio.h"
  15. #include "driver/spi_master.h"
  16. #include "esp_err.h"
  17. #include "esp_log.h"
  18. #include "lvgl.h"
  19. #include "../demos/lv_demos.h"
  20.  
  21. #if CONFIG_EXAMPLE_LCD_CONTROLLER_ILI9341
  22. #include "esp_lcd_ili9341.h"
  23. #elif CONFIG_EXAMPLE_LCD_CONTROLLER_GC9A01
  24. #include "esp_lcd_gc9a01.h"
  25. #endif
  26.  
  27. #if CONFIG_EXAMPLE_LCD_TOUCH_CONTROLLER_STMPE610
  28. #include "esp_lcd_touch_stmpe610.h"
  29. #endif
  30.  
  31. static const char *TAG = "example";
  32.  
  33. // Using SPI2 in the example
  34. #define LCD_HOST  HSPI_HOST
  35.  
  36. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  37. //////////////////// Please update the following configuration according to your LCD spec //////////////////////////////
  38. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  39. #define EXAMPLE_LCD_PIXEL_CLOCK_HZ     (80 * 1000 * 1000)
  40. #define EXAMPLE_LCD_BK_LIGHT_ON_LEVEL  1
  41. #define EXAMPLE_LCD_BK_LIGHT_OFF_LEVEL !EXAMPLE_LCD_BK_LIGHT_ON_LEVEL
  42. #define EXAMPLE_PIN_NUM_SCLK           14
  43. #define EXAMPLE_PIN_NUM_MOSI           13
  44. #define EXAMPLE_PIN_NUM_MISO           12
  45. #define EXAMPLE_PIN_NUM_LCD_DC         15
  46. #define EXAMPLE_PIN_NUM_LCD_RST        25
  47. #define EXAMPLE_PIN_NUM_LCD_CS         26
  48. #define EXAMPLE_PIN_NUM_BK_LIGHT       27
  49. #define EXAMPLE_PIN_NUM_TOUCH_CS       15
  50.  
  51. #define CONFIG_EXAMPLE_LCD_CONTROLLER_ILI9341 1
  52.  
  53. // The pixel number in horizontal and vertical
  54. #if CONFIG_EXAMPLE_LCD_CONTROLLER_ILI9341
  55. #define EXAMPLE_LCD_H_RES              320
  56. #define EXAMPLE_LCD_V_RES              240
  57. #elif CONFIG_EXAMPLE_LCD_CONTROLLER_GC9A01
  58. #define EXAMPLE_LCD_H_RES              240
  59. #define EXAMPLE_LCD_V_RES              240
  60. #endif
  61. // Bit number used to represent command and parameter
  62. #define EXAMPLE_LCD_CMD_BITS           8
  63. #define EXAMPLE_LCD_PARAM_BITS         8
  64.  
  65. #define EXAMPLE_LVGL_TICK_PERIOD_MS    2
  66.  
  67.  
  68. #if CONFIG_EXAMPLE_LCD_TOUCH_ENABLED
  69. esp_lcd_touch_handle_t tp = NULL;
  70. #endif
  71.  
  72. extern void example_lvgl_demo_ui(lv_disp_t *disp);
  73.  
  74. 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)
  75. {
  76.     lv_disp_drv_t *disp_driver = (lv_disp_drv_t *)user_ctx;
  77.     lv_disp_flush_ready(disp_driver);
  78.     return false;
  79. }
  80.  
  81. static void example_lvgl_flush_cb(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_map)
  82. {
  83.     esp_lcd_panel_handle_t panel_handle = (esp_lcd_panel_handle_t) drv->user_data;
  84.     int offsetx1 = area->x1;
  85.     int offsetx2 = area->x2;
  86.     int offsety1 = area->y1;
  87.     int offsety2 = area->y2;
  88.     // copy a buffer's content to a specific area of the display
  89.     esp_lcd_panel_draw_bitmap(panel_handle, offsetx1, offsety1, offsetx2 + 1, offsety2 + 1, color_map);
  90. }
  91.  
  92. /* Rotate display and touch, when rotated screen in LVGL. Called when driver parameters are updated. */
  93. static void example_lvgl_port_update_callback(lv_disp_drv_t *drv)
  94. {
  95.     esp_lcd_panel_handle_t panel_handle = (esp_lcd_panel_handle_t) drv->user_data;
  96.  
  97.     switch (drv->rotated) {
  98.     case LV_DISP_ROT_NONE:
  99.         // Rotate LCD display
  100.         esp_lcd_panel_swap_xy(panel_handle, false);
  101.         esp_lcd_panel_mirror(panel_handle, true, false);
  102. #if CONFIG_EXAMPLE_LCD_TOUCH_ENABLED
  103.         // Rotate LCD touch
  104.         esp_lcd_touch_set_mirror_y(tp, false);
  105.         esp_lcd_touch_set_mirror_x(tp, false);
  106. #endif
  107.         break;
  108.     case LV_DISP_ROT_90:
  109.         // Rotate LCD display
  110.         esp_lcd_panel_swap_xy(panel_handle, true);
  111.         esp_lcd_panel_mirror(panel_handle, true, true);
  112. #if CONFIG_EXAMPLE_LCD_TOUCH_ENABLED
  113.         // Rotate LCD touch
  114.         esp_lcd_touch_set_mirror_y(tp, false);
  115.         esp_lcd_touch_set_mirror_x(tp, false);
  116. #endif
  117.         break;
  118.     case LV_DISP_ROT_180:
  119.         // Rotate LCD display
  120.         esp_lcd_panel_swap_xy(panel_handle, false);
  121.         esp_lcd_panel_mirror(panel_handle, false, true);
  122. #if CONFIG_EXAMPLE_LCD_TOUCH_ENABLED
  123.         // Rotate LCD touch
  124.         esp_lcd_touch_set_mirror_y(tp, false);
  125.         esp_lcd_touch_set_mirror_x(tp, false);
  126. #endif
  127.         break;
  128.     case LV_DISP_ROT_270:
  129.         // Rotate LCD display
  130.         esp_lcd_panel_swap_xy(panel_handle, true);
  131.         esp_lcd_panel_mirror(panel_handle, false, false);
  132. #if CONFIG_EXAMPLE_LCD_TOUCH_ENABLED
  133.         // Rotate LCD touch
  134.         esp_lcd_touch_set_mirror_y(tp, false);
  135.         esp_lcd_touch_set_mirror_x(tp, false);
  136. #endif
  137.         break;
  138.     }
  139. }
  140.  
  141. #if CONFIG_EXAMPLE_LCD_TOUCH_ENABLED
  142. static void example_lvgl_touch_cb(lv_indev_drv_t * drv, lv_indev_data_t * data)
  143. {
  144.     uint16_t touchpad_x[1] = {0};
  145.     uint16_t touchpad_y[1] = {0};
  146.     uint8_t touchpad_cnt = 0;
  147.  
  148.     /* Read touch controller data */
  149.     esp_lcd_touch_read_data(drv->user_data);
  150.  
  151.     /* Get coordinates */
  152.     bool touchpad_pressed = esp_lcd_touch_get_coordinates(drv->user_data, touchpad_x, touchpad_y, NULL, &touchpad_cnt, 1);
  153.  
  154.     if (touchpad_pressed && touchpad_cnt > 0) {
  155.         data->point.x = touchpad_x[0];
  156.         data->point.y = touchpad_y[0];
  157.         data->state = LV_INDEV_STATE_PRESSED;
  158.     } else {
  159.         data->state = LV_INDEV_STATE_RELEASED;
  160.     }
  161. }
  162. #endif
  163.  
  164. static void example_increase_lvgl_tick(void *arg)
  165. {
  166.     /* Tell LVGL how many milliseconds has elapsed */
  167.     lv_tick_inc(EXAMPLE_LVGL_TICK_PERIOD_MS);
  168. }
  169.  
  170. void app_main(void)
  171. {
  172.     static lv_disp_draw_buf_t disp_buf; // contains internal graphic buffer(s) called draw buffer(s)
  173.     static lv_disp_drv_t disp_drv;      // contains callback functions
  174.  
  175.     ESP_LOGI(TAG, "Turn off LCD backlight");
  176.     gpio_config_t bk_gpio_config = {
  177.         .mode = GPIO_MODE_OUTPUT,
  178.         .pin_bit_mask = 1ULL << EXAMPLE_PIN_NUM_BK_LIGHT
  179.     };
  180.     ESP_ERROR_CHECK(gpio_config(&bk_gpio_config));
  181.  
  182.     ESP_LOGI(TAG, "Initialize SPI bus");
  183.     spi_bus_config_t buscfg = {
  184.         .sclk_io_num = EXAMPLE_PIN_NUM_SCLK,
  185.         .mosi_io_num = EXAMPLE_PIN_NUM_MOSI,
  186.         .miso_io_num = EXAMPLE_PIN_NUM_MISO,
  187.         .quadwp_io_num = -1,
  188.         .quadhd_io_num = -1,
  189.         .max_transfer_sz = EXAMPLE_LCD_H_RES * 80 * sizeof(uint16_t),
  190.     };
  191.     ESP_ERROR_CHECK(spi_bus_initialize(LCD_HOST, &buscfg, SPI_DMA_CH_AUTO));
  192.  
  193.     ESP_LOGI(TAG, "Install panel IO");
  194.     esp_lcd_panel_io_handle_t io_handle = NULL;
  195.     esp_lcd_panel_io_spi_config_t io_config = {
  196.         .dc_gpio_num = EXAMPLE_PIN_NUM_LCD_DC,
  197.         .cs_gpio_num = EXAMPLE_PIN_NUM_LCD_CS,
  198.         .pclk_hz = EXAMPLE_LCD_PIXEL_CLOCK_HZ,
  199.         .lcd_cmd_bits = EXAMPLE_LCD_CMD_BITS,
  200.         .lcd_param_bits = EXAMPLE_LCD_PARAM_BITS,
  201.         .spi_mode = 0,
  202.         .trans_queue_depth = 10,
  203.         .on_color_trans_done = example_notify_lvgl_flush_ready,
  204.         .user_ctx = &disp_drv,
  205.     };
  206.     // Attach the LCD to the SPI bus
  207.     ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)LCD_HOST, &io_config, &io_handle));
  208.  
  209.     ESP_LOGI(TAG, "Install GC9A01 panel driver");
  210.     esp_lcd_panel_handle_t panel_handle = NULL;
  211.     esp_lcd_panel_dev_config_t panel_config = {
  212.         .reset_gpio_num = EXAMPLE_PIN_NUM_LCD_RST,
  213. #if CONFIG_EXAMPLE_LCD_CONTROLLER_ILI9341
  214.         .rgb_endian = LCD_RGB_ENDIAN_BGR,
  215. #elif CONFIG_EXAMPLE_LCD_CONTROLLER_GC9A01
  216.         .rgb_endian = LCD_RGB_ENDIAN_BGR,
  217. #endif
  218.         .bits_per_pixel = 16,
  219.     };
  220. #if CONFIG_EXAMPLE_LCD_CONTROLLER_ILI9341
  221.     ESP_ERROR_CHECK(esp_lcd_new_panel_ili9341(io_handle, &panel_config, &panel_handle));
  222. #elif CONFIG_EXAMPLE_LCD_CONTROLLER_GC9A01
  223.     ESP_ERROR_CHECK(esp_lcd_new_panel_gc9a01(io_handle, &panel_config, &panel_handle));
  224. #endif
  225.  
  226.     ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle));
  227.     ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle));
  228. #if CONFIG_EXAMPLE_LCD_CONTROLLER_GC9A01
  229.     ESP_ERROR_CHECK(esp_lcd_panel_invert_color(panel_handle, true));
  230. #endif
  231.     ESP_ERROR_CHECK(esp_lcd_panel_mirror(panel_handle, true, false));
  232.  
  233.     // user can flush pre-defined pattern to the screen before we turn on the screen or backlight
  234.     ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_handle, true));
  235.  
  236. #if CONFIG_EXAMPLE_LCD_TOUCH_ENABLED
  237.     esp_lcd_panel_io_handle_t tp_io_handle = NULL;
  238.     esp_lcd_panel_io_spi_config_t tp_io_config = ESP_LCD_TOUCH_IO_SPI_STMPE610_CONFIG(EXAMPLE_PIN_NUM_TOUCH_CS);
  239.     // Attach the TOUCH to the SPI bus
  240.     ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)LCD_HOST, &tp_io_config, &tp_io_handle));
  241.  
  242.     esp_lcd_touch_config_t tp_cfg = {
  243.         .x_max = EXAMPLE_LCD_H_RES,
  244.         .y_max = EXAMPLE_LCD_V_RES,
  245.         .rst_gpio_num = -1,
  246.         .int_gpio_num = -1,
  247.         .flags = {
  248.             .swap_xy = 0,
  249.             .mirror_x = 0,
  250.             .mirror_y = 0,
  251.         },
  252.     };
  253.  
  254. #if CONFIG_EXAMPLE_LCD_TOUCH_CONTROLLER_STMPE610
  255.     ESP_LOGI(TAG, "Initialize touch controller STMPE610");
  256.     ESP_ERROR_CHECK(esp_lcd_touch_new_spi_stmpe610(tp_io_handle, &tp_cfg, &tp));
  257. #endif // CONFIG_EXAMPLE_LCD_TOUCH_CONTROLLER_STMPE610
  258. #endif // CONFIG_EXAMPLE_LCD_TOUCH_ENABLED
  259.  
  260.     ESP_LOGI(TAG, "Turn on LCD backlight");
  261.     gpio_set_level(EXAMPLE_PIN_NUM_BK_LIGHT, EXAMPLE_LCD_BK_LIGHT_ON_LEVEL);
  262.  
  263.     ESP_LOGI(TAG, "Initialize LVGL library");
  264.     lv_init();
  265.     // alloc draw buffers used by LVGL
  266.     // it's recommended to choose the size of the draw buffer(s) to be at least 1/10 screen sized
  267.     lv_color_t *buf1 = heap_caps_malloc(EXAMPLE_LCD_H_RES * 40 * sizeof(lv_color_t), MALLOC_CAP_DMA);
  268.     assert(buf1);
  269.     lv_color_t *buf2 = heap_caps_malloc(EXAMPLE_LCD_H_RES * 40 * sizeof(lv_color_t), MALLOC_CAP_DMA);
  270.     assert(buf2);
  271.     // initialize LVGL draw buffers
  272.     lv_disp_draw_buf_init(&disp_buf, buf1, buf2, EXAMPLE_LCD_H_RES * 20);
  273.  
  274.     ESP_LOGI(TAG, "Register display driver to LVGL");
  275.     lv_disp_drv_init(&disp_drv);
  276.     disp_drv.hor_res = EXAMPLE_LCD_H_RES;
  277.     disp_drv.ver_res = EXAMPLE_LCD_V_RES;
  278.     disp_drv.flush_cb = example_lvgl_flush_cb;
  279.     disp_drv.drv_update_cb = example_lvgl_port_update_callback;
  280.     disp_drv.draw_buf = &disp_buf;
  281.     disp_drv.user_data = panel_handle;
  282.     lv_disp_t *disp = lv_disp_drv_register(&disp_drv);
  283.  
  284.     ESP_LOGI(TAG, "Install LVGL tick timer");
  285.     // Tick interface for LVGL (using esp_timer to generate 2ms periodic event)
  286.     const esp_timer_create_args_t lvgl_tick_timer_args = {
  287.         .callback = &example_increase_lvgl_tick,
  288.         .name = "lvgl_tick"
  289.     };
  290.     esp_timer_handle_t lvgl_tick_timer = NULL;
  291.     ESP_ERROR_CHECK(esp_timer_create(&lvgl_tick_timer_args, &lvgl_tick_timer));
  292.     ESP_ERROR_CHECK(esp_timer_start_periodic(lvgl_tick_timer, EXAMPLE_LVGL_TICK_PERIOD_MS * 1000));
  293.  
  294. #if CONFIG_EXAMPLE_LCD_TOUCH_ENABLED
  295.     static lv_indev_drv_t indev_drv;    // Input device driver (Touch)
  296.     lv_indev_drv_init(&indev_drv);
  297.     indev_drv.type = LV_INDEV_TYPE_POINTER;
  298.     indev_drv.disp = disp;
  299.     indev_drv.read_cb = example_lvgl_touch_cb;
  300.     indev_drv.user_data = tp;
  301.  
  302.     lv_indev_drv_register(&indev_drv);
  303. #endif
  304.  
  305.     ESP_LOGI(TAG, "Display LVGL Meter Widget");
  306.     /* example_lvgl_demo_ui(disp); */
  307.     lv_demo_music();
  308.  
  309.     esp_lcd_panel_swap_xy(panel_handle, true);
  310.         esp_lcd_panel_mirror(panel_handle, true, true);
  311.  
  312.     while (1) {
  313.         lv_timer_handler();
  314.     }
  315. }
Here is the Arduino code
  1. #include <lvgl.h>
  2. #include <TFT_eSPI.h>
  3. #include <demos/lv_demos.h>
  4.  
  5. static const uint16_t screenWidth = 320;
  6. static const uint16_t screenHeight = 240;
  7.  
  8. static lv_disp_draw_buf_t draw_buf;
  9. static lv_color_t buf1[screenWidth * screenHeight / 10];
  10. static lv_color_t buf2[screenWidth * screenHeight / 10];
  11.  
  12. TFT_eSPI tft = TFT_eSPI();
  13.  
  14.  
  15. #if LV_USE_LOG != 0
  16. void my_print(const char *buf) {
  17.   Serial.printf(buf);
  18.   Serial.flush();
  19. }
  20. #endif
  21.  
  22. /* Display flushing */
  23. void my_disp_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p) {
  24.   uint32_t w = (area->x2 - area->x1 + 1);
  25.   uint32_t h = (area->y2 - area->y1 + 1);
  26.  
  27.  tft.startWrite();
  28.   tft.setAddrWindow(area->x1, area->y1, w, h);
  29.   tft.pushPixelsDMA((uint16_t *)&color_p->full, w * h);
  30.   lv_disp_flush_ready(disp);
  31. }
  32.  
  33.  
  34. void lv_timer_handler_thread(void *args) {
  35.   while (1) {
  36.     lv_timer_handler(); /* let the GUI do its work */
  37.     /* vTaskDelay(10 / portTICK_PERIOD_MS); */
  38.   }
  39. }
  40.  
  41. void setup() {
  42.   Serial.begin(115200); /* prepare for possible serial debug */
  43.  
  44.   tft.begin();        /* TFT init */
  45.   tft.setRotation(3); /* Landscape orientation, flipped */
  46.   tft.setSwapBytes(true);
  47.   tft.initDMA();
  48.  
  49.   lv_init();
  50.  
  51. #if LV_USE_LOG != 0
  52.   lv_log_register_print_cb(my_print); /* register print function for debugging */
  53. #endif
  54.  
  55.  
  56.   lv_disp_draw_buf_init(&draw_buf, buf1, buf2, screenWidth * screenHeight / 10);
  57.  
  58.   /*Initialize the display*/
  59.   static lv_disp_drv_t disp_drv;
  60.   lv_disp_drv_init(&disp_drv);
  61.   disp_drv.hor_res = screenWidth;
  62.   disp_drv.ver_res = screenHeight;
  63.   disp_drv.flush_cb = my_disp_flush;
  64.   disp_drv.draw_buf = &draw_buf;
  65.   lv_disp_t *disp = lv_disp_drv_register(&disp_drv);
  66.   disp->refr_timer->period = 40;  // set refresh rate around 25FPS.
  67.  
  68.  
  69.  
  70.   Serial.println("Setup done");
  71.  
  72.   lv_demo_music();
  73.  
  74.  
  75.  
  76. }
  77.  
  78. void loop() {
  79.   lv_timer_handler();
  80. }
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

Who is online

Users browsing this forum: FrankJensen and 114 guests