From ae69c02dad71c77b71072fd3484bb1c87fde02b5 Mon Sep 17 00:00:00 2001 From: marcus_xu Date: Fri, 17 Nov 2023 18:47:37 +0800 Subject: [PATCH 1/6] esp_lvgl_port: add sw_rotate and psram to sram. --- components/esp_lvgl_port/esp_lvgl_port.c | 97 +++++++++++++++++-- components/esp_lvgl_port/idf_component.yml | 2 +- .../esp_lvgl_port/include/esp_lvgl_port.h | 2 + 3 files changed, 92 insertions(+), 9 deletions(-) diff --git a/components/esp_lvgl_port/esp_lvgl_port.c b/components/esp_lvgl_port/esp_lvgl_port.c index 5c0fb5ff..95cb49e4 100644 --- a/components/esp_lvgl_port/esp_lvgl_port.c +++ b/components/esp_lvgl_port/esp_lvgl_port.c @@ -47,6 +47,9 @@ typedef struct { esp_lcd_panel_handle_t panel_handle; /* LCD panel handle */ lvgl_port_rotation_cfg_t rotation; /* Default values of the screen rotation */ lv_disp_drv_t disp_drv; /* LVGL display driver */ + lv_color_t *trans_buf; /* Buffer send to driver */ + uint32_t trans_size; /* Maximum size for one transport */ + SemaphoreHandle_t trans_sem; /* Idle transfer mutex */ } lvgl_port_display_ctx_t; #if __has_include ("esp_lcd_touch.h") @@ -207,6 +210,8 @@ lv_disp_t *lvgl_port_add_disp(const lvgl_port_display_cfg_t *disp_cfg) lv_disp_t *disp = NULL; lv_color_t *buf1 = NULL; lv_color_t *buf2 = NULL; + lv_color_t *buf3 = NULL; + SemaphoreHandle_t trans_sem = NULL; assert(disp_cfg != NULL); assert(disp_cfg->io_handle != NULL); assert(disp_cfg->panel_handle != NULL); @@ -222,9 +227,11 @@ lv_disp_t *lvgl_port_add_disp(const lvgl_port_display_cfg_t *disp_cfg) disp_ctx->rotation.swap_xy = disp_cfg->rotation.swap_xy; disp_ctx->rotation.mirror_x = disp_cfg->rotation.mirror_x; disp_ctx->rotation.mirror_y = disp_cfg->rotation.mirror_y; + disp_ctx->rotation.sw_rotate = disp_cfg->rotation.sw_rotate; + disp_ctx->trans_size = disp_cfg->trans_size; uint32_t buff_caps = MALLOC_CAP_DEFAULT; - if (disp_cfg->flags.buff_dma && disp_cfg->flags.buff_spiram) { + if (disp_cfg->flags.buff_dma && disp_cfg->flags.buff_spiram && (0 == disp_cfg->trans_size)) { ESP_GOTO_ON_FALSE(false, ESP_ERR_NOT_SUPPORTED, err, TAG, "Alloc DMA capable buffer in SPIRAM is not supported!"); } else if (disp_cfg->flags.buff_dma) { buff_caps = MALLOC_CAP_DMA; @@ -240,6 +247,17 @@ lv_disp_t *lvgl_port_add_disp(const lvgl_port_display_cfg_t *disp_cfg) buf2 = heap_caps_malloc(disp_cfg->buffer_size * sizeof(lv_color_t), buff_caps); ESP_GOTO_ON_FALSE(buf2, ESP_ERR_NO_MEM, err, TAG, "Not enough memory for LVGL buffer (buf2) allocation!"); } + + if (disp_cfg->trans_size) { + buf3 = heap_caps_malloc(disp_cfg->trans_size * sizeof(lv_color_t), MALLOC_CAP_DMA); + ESP_GOTO_ON_FALSE(buf3, ESP_ERR_NO_MEM, err, TAG, "Not enough memory for buffer(transport) allocation!"); + disp_ctx->trans_buf = buf3; + + trans_sem = xSemaphoreCreateCounting(1, 0); + ESP_GOTO_ON_FALSE(trans_sem, ESP_ERR_NO_MEM, err, TAG, "Failed to create transport counting Semaphore"); + disp_ctx->trans_sem = trans_sem; + } + lv_disp_draw_buf_t *disp_buf = malloc(sizeof(lv_disp_draw_buf_t)); ESP_GOTO_ON_FALSE(disp_buf, ESP_ERR_NO_MEM, err, TAG, "Not enough memory for LVGL display buffer allocation!"); @@ -251,7 +269,11 @@ lv_disp_t *lvgl_port_add_disp(const lvgl_port_display_cfg_t *disp_cfg) disp_ctx->disp_drv.hor_res = disp_cfg->hres; disp_ctx->disp_drv.ver_res = disp_cfg->vres; disp_ctx->disp_drv.flush_cb = lvgl_port_flush_callback; - disp_ctx->disp_drv.drv_update_cb = lvgl_port_update_callback; + disp_ctx->disp_drv.sw_rotate = disp_cfg->rotation.sw_rotate; + if (disp_cfg->rotation.sw_rotate == false) { + disp_ctx->disp_drv.drv_update_cb = lvgl_port_update_callback; + } + disp_ctx->disp_drv.draw_buf = disp_buf; disp_ctx->disp_drv.user_data = disp_ctx; @@ -282,6 +304,12 @@ lv_disp_t *lvgl_port_add_disp(const lvgl_port_display_cfg_t *disp_cfg) if (buf2) { free(buf2); } + if (buf3) { + free(buf3); + } + if (trans_sem) { + vSemaphoreDelete(trans_sem); + } if (disp_ctx) { free(disp_ctx); } @@ -588,9 +616,18 @@ static void lvgl_port_task_deinit(void) #if LVGL_PORT_HANDLE_FLUSH_READY static bool lvgl_port_flush_ready_callback(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *edata, void *user_ctx) { + BaseType_t taskAwake = pdFALSE; + lv_disp_drv_t *disp_drv = (lv_disp_drv_t *)user_ctx; assert(disp_drv != NULL); + lvgl_port_display_ctx_t *disp_ctx = disp_drv->user_data; + assert(disp_ctx != NULL); lv_disp_flush_ready(disp_drv); + + if (disp_ctx->trans_size && disp_ctx->trans_sem) { + xSemaphoreGiveFromISR(disp_ctx->trans_sem, &taskAwake); + } + return false; } #endif @@ -601,12 +638,56 @@ static void lvgl_port_flush_callback(lv_disp_drv_t *drv, const lv_area_t *area, lvgl_port_display_ctx_t *disp_ctx = (lvgl_port_display_ctx_t *)drv->user_data; assert(disp_ctx != NULL); - const int offsetx1 = area->x1; - const int offsetx2 = area->x2; - const int offsety1 = area->y1; - const int offsety2 = area->y2; - // copy a buffer's content to a specific area of the display - esp_lcd_panel_draw_bitmap(disp_ctx->panel_handle, offsetx1, offsety1, offsetx2 + 1, offsety2 + 1, color_map); + int x_draw_start; + int x_draw_end; + int y_draw_start; + int y_draw_end; + + int y_start_tmp; + int y_end_tmp; + + int trans_count; + int trans_line; + int max_line; + + const int x_start = area->x1; + const int x_end = area->x2; + const int y_start = area->y1; + const int y_end = area->y2; + const int width = x_end - x_start + 1; + const int height = y_end - y_start + 1; + + lv_color_t *from = color_map; + lv_color_t *to = NULL; + + if (0 == disp_ctx->trans_size) { + esp_lcd_panel_draw_bitmap(disp_ctx->panel_handle, x_start, y_start, x_end + 1, y_end + 1, color_map); + } else { + y_start_tmp = y_start; + max_line = ((disp_ctx->trans_size / width) > height) ? (height) : (disp_ctx->trans_size / width); + trans_count = height / max_line + (height % max_line ? (1) : (0)); + + for (int i = 0; i < trans_count; i++) { + trans_line = (y_end - y_start_tmp + 1) > max_line ? max_line : (y_end - y_start_tmp + 1); + y_end_tmp = (y_end - y_start_tmp + 1) > max_line ? (y_start_tmp + max_line - 1) : y_end; + + to = disp_ctx->trans_buf; + for (int y = 0; y < trans_line; y++) { + for (int x = 0; x < width; x++) { + *(to + y * (width) + x) = *(from + y * (width) + x); + } + } + x_draw_start = x_start; + x_draw_end = x_end; + y_draw_start = y_start_tmp; + y_draw_end = y_end_tmp; + esp_lcd_panel_draw_bitmap(disp_ctx->panel_handle, x_draw_start, y_draw_start, x_draw_end + 1, y_draw_end + 1, to); + + from += max_line * width; + y_start_tmp += max_line; + xSemaphoreTake(disp_ctx->trans_sem, portMAX_DELAY); + } + } } static void lvgl_port_update_callback(lv_disp_drv_t *drv) diff --git a/components/esp_lvgl_port/idf_component.yml b/components/esp_lvgl_port/idf_component.yml index 502deaea..c888f77a 100644 --- a/components/esp_lvgl_port/idf_component.yml +++ b/components/esp_lvgl_port/idf_component.yml @@ -1,4 +1,4 @@ -version: "1.3.0" +version: "1.4.0" description: ESP LVGL port url: https://github.com/espressif/esp-bsp/tree/master/components/esp_lvgl_port dependencies: diff --git a/components/esp_lvgl_port/include/esp_lvgl_port.h b/components/esp_lvgl_port/include/esp_lvgl_port.h index 4f30f253..b9afdec4 100644 --- a/components/esp_lvgl_port/include/esp_lvgl_port.h +++ b/components/esp_lvgl_port/include/esp_lvgl_port.h @@ -48,6 +48,7 @@ typedef struct { * @brief Rotation configuration */ typedef struct { + bool sw_rotate;/*!< Use software rotation (slower) */ bool swap_xy; /*!< LCD Screen swapped X and Y (in esp_lcd driver) */ bool mirror_x; /*!< LCD Screen mirrored X (in esp_lcd driver) */ bool mirror_y; /*!< LCD Screen mirrored Y (in esp_lcd driver) */ @@ -61,6 +62,7 @@ typedef struct { esp_lcd_panel_handle_t panel_handle; /*!< LCD panel handle */ uint32_t buffer_size; /*!< Size of the buffer for the screen in pixels */ bool double_buffer; /*!< True, if should be allocated two buffers */ + uint32_t trans_size; /*!< Allocated buffer will be in SRAM to move framebuf */ uint32_t hres; /*!< LCD display horizontal resolution */ uint32_t vres; /*!< LCD display vertical resolution */ bool monochrome; /*!< True, if display is monochrome and using 1bit for 1px */ From bb69579a80ad664805e0400f171d69291c0a84fc Mon Sep 17 00:00:00 2001 From: marcus_xu Date: Wed, 22 Nov 2023 11:16:10 +0800 Subject: [PATCH 2/6] esp_lvgl_port: update README for sw_rotate and PSRAM canvas. --- components/esp_lvgl_port/README.md | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/components/esp_lvgl_port/README.md b/components/esp_lvgl_port/README.md index 89d8541f..a583ed1c 100644 --- a/components/esp_lvgl_port/README.md +++ b/components/esp_lvgl_port/README.md @@ -182,11 +182,37 @@ Every LVGL calls must be protected with these lock/unlock commands: ``` ### Rotating screen +LVGL supports rotation of the display. You can select whether you'd like software rotation or hardware rotation. +Software rotation requires no additional logic in your `flush_cb` callback. + +Rotation mode can be selected in the `lvgl_port_display_cfg_t` structure. +``` c + const lvgl_port_display_cfg_t disp_cfg = { + ... + .rotation = { + .sw_rotate = true / false, // true: software; false: hardware + ... + } + } +``` +Display rotation can be changed at runtime. ``` c lv_disp_set_rotation(disp_handle, LV_DISP_ROT_90); ``` -**Note:** During the rotating, the component call [`esp_lcd`](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/lcd.html) API. +**Note:** During the hardware rotating, the component call [`esp_lcd`](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/lcd.html) API. when using software rotation, you cannot use neither `direct_mode` nor `full_refresh` in the driver. See [LVGL documentation](https://docs.lvgl.io/8.3/porting/display.html?highlight=sw_rotate) for more info. + +### Using PSRAM canvas + +If the SRAM is insufficient, you can use the PSRAM as a canvas and use a small trans_buffer to carry it, this makes drawing more efficient. +``` c + .buffer_size = DISP_WIDTH*DISP_HEIGHT, // in PSRAM, not DMA-capable + .trans_size = size, // in SRAM, DMA-capable + .flags = { + .buff_spiram = true, + .buff_dma = false, + } +``` ## Performance From 245c285280de4818b59b124993bec2359fb13034 Mon Sep 17 00:00:00 2001 From: espressif2022 <111102666+espressif2022@users.noreply.github.com> Date: Fri, 24 Nov 2023 13:44:53 +0800 Subject: [PATCH 3/6] Update components/esp_lvgl_port/README.md Co-authored-by: Vilem Zavodny <98878239+espzav@users.noreply.github.com> --- components/esp_lvgl_port/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_lvgl_port/README.md b/components/esp_lvgl_port/README.md index a583ed1c..f3e8b5e5 100644 --- a/components/esp_lvgl_port/README.md +++ b/components/esp_lvgl_port/README.md @@ -182,7 +182,7 @@ Every LVGL calls must be protected with these lock/unlock commands: ``` ### Rotating screen -LVGL supports rotation of the display. You can select whether you'd like software rotation or hardware rotation. +LVGL port supports rotation of the display. You can select whether you'd like software rotation or hardware rotation. Software rotation requires no additional logic in your `flush_cb` callback. Rotation mode can be selected in the `lvgl_port_display_cfg_t` structure. From ccd83e91a0ea37cc781de93dfeee4b56803d607c Mon Sep 17 00:00:00 2001 From: espressif2022 <111102666+espressif2022@users.noreply.github.com> Date: Fri, 24 Nov 2023 13:45:01 +0800 Subject: [PATCH 4/6] Update components/esp_lvgl_port/README.md Co-authored-by: Vilem Zavodny <98878239+espzav@users.noreply.github.com> --- components/esp_lvgl_port/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_lvgl_port/README.md b/components/esp_lvgl_port/README.md index f3e8b5e5..7204f485 100644 --- a/components/esp_lvgl_port/README.md +++ b/components/esp_lvgl_port/README.md @@ -200,7 +200,7 @@ Display rotation can be changed at runtime. lv_disp_set_rotation(disp_handle, LV_DISP_ROT_90); ``` -**Note:** During the hardware rotating, the component call [`esp_lcd`](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/lcd.html) API. when using software rotation, you cannot use neither `direct_mode` nor `full_refresh` in the driver. See [LVGL documentation](https://docs.lvgl.io/8.3/porting/display.html?highlight=sw_rotate) for more info. +**Note:** During the hardware rotating, the component call [`esp_lcd`](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/lcd.html) API. When using software rotation, you cannot use neither `direct_mode` nor `full_refresh` in the driver. See [LVGL documentation](https://docs.lvgl.io/8.3/porting/display.html?highlight=sw_rotate) for more info. ### Using PSRAM canvas From af2d950d48624f0689d5e7191776fff8e1daac6e Mon Sep 17 00:00:00 2001 From: marcus_xu Date: Mon, 4 Dec 2023 14:32:10 +0800 Subject: [PATCH 5/6] wsp_lvgl_port: update sw_rotate position --- components/esp_lvgl_port/README.md | 6 ++---- components/esp_lvgl_port/esp_lvgl_port.c | 5 ++--- components/esp_lvgl_port/include/esp_lvgl_port.h | 2 +- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/components/esp_lvgl_port/README.md b/components/esp_lvgl_port/README.md index 7204f485..f8eedca1 100644 --- a/components/esp_lvgl_port/README.md +++ b/components/esp_lvgl_port/README.md @@ -189,10 +189,8 @@ Rotation mode can be selected in the `lvgl_port_display_cfg_t` structure. ``` c const lvgl_port_display_cfg_t disp_cfg = { ... - .rotation = { - .sw_rotate = true / false, // true: software; false: hardware - ... - } + .sw_rotate = true / false, // true: software; false: hardware + ... } ``` Display rotation can be changed at runtime. diff --git a/components/esp_lvgl_port/esp_lvgl_port.c b/components/esp_lvgl_port/esp_lvgl_port.c index 95cb49e4..afeefbec 100644 --- a/components/esp_lvgl_port/esp_lvgl_port.c +++ b/components/esp_lvgl_port/esp_lvgl_port.c @@ -227,7 +227,6 @@ lv_disp_t *lvgl_port_add_disp(const lvgl_port_display_cfg_t *disp_cfg) disp_ctx->rotation.swap_xy = disp_cfg->rotation.swap_xy; disp_ctx->rotation.mirror_x = disp_cfg->rotation.mirror_x; disp_ctx->rotation.mirror_y = disp_cfg->rotation.mirror_y; - disp_ctx->rotation.sw_rotate = disp_cfg->rotation.sw_rotate; disp_ctx->trans_size = disp_cfg->trans_size; uint32_t buff_caps = MALLOC_CAP_DEFAULT; @@ -269,8 +268,8 @@ lv_disp_t *lvgl_port_add_disp(const lvgl_port_display_cfg_t *disp_cfg) disp_ctx->disp_drv.hor_res = disp_cfg->hres; disp_ctx->disp_drv.ver_res = disp_cfg->vres; disp_ctx->disp_drv.flush_cb = lvgl_port_flush_callback; - disp_ctx->disp_drv.sw_rotate = disp_cfg->rotation.sw_rotate; - if (disp_cfg->rotation.sw_rotate == false) { + disp_ctx->disp_drv.sw_rotate = disp_cfg->sw_rotate; + if (disp_ctx->disp_drv.sw_rotate == false) { disp_ctx->disp_drv.drv_update_cb = lvgl_port_update_callback; } diff --git a/components/esp_lvgl_port/include/esp_lvgl_port.h b/components/esp_lvgl_port/include/esp_lvgl_port.h index b9afdec4..52766625 100644 --- a/components/esp_lvgl_port/include/esp_lvgl_port.h +++ b/components/esp_lvgl_port/include/esp_lvgl_port.h @@ -48,7 +48,6 @@ typedef struct { * @brief Rotation configuration */ typedef struct { - bool sw_rotate;/*!< Use software rotation (slower) */ bool swap_xy; /*!< LCD Screen swapped X and Y (in esp_lcd driver) */ bool mirror_x; /*!< LCD Screen mirrored X (in esp_lcd driver) */ bool mirror_y; /*!< LCD Screen mirrored Y (in esp_lcd driver) */ @@ -66,6 +65,7 @@ typedef struct { uint32_t hres; /*!< LCD display horizontal resolution */ uint32_t vres; /*!< LCD display vertical resolution */ bool monochrome; /*!< True, if display is monochrome and using 1bit for 1px */ + bool sw_rotate; /*!< Use software rotation (slower) */ lvgl_port_rotation_cfg_t rotation; /*!< Default values of the screen rotation */ struct { From d63827134da2e5e7f3b683347581d3d6808008d6 Mon Sep 17 00:00:00 2001 From: marcus_xu Date: Wed, 6 Dec 2023 10:31:02 +0800 Subject: [PATCH 6/6] esp_lvgl_port: put sw_rotate in flags. --- components/esp_lvgl_port/README.md | 20 ++++++++++++------- components/esp_lvgl_port/esp_lvgl_port.c | 2 +- .../esp_lvgl_port/include/esp_lvgl_port.h | 2 +- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/components/esp_lvgl_port/README.md b/components/esp_lvgl_port/README.md index f8eedca1..49115922 100644 --- a/components/esp_lvgl_port/README.md +++ b/components/esp_lvgl_port/README.md @@ -189,8 +189,10 @@ Rotation mode can be selected in the `lvgl_port_display_cfg_t` structure. ``` c const lvgl_port_display_cfg_t disp_cfg = { ... - .sw_rotate = true / false, // true: software; false: hardware - ... + .flags = { + ... + .sw_rotate = true / false, // true: software; false: hardware + } } ``` Display rotation can be changed at runtime. @@ -204,11 +206,15 @@ Display rotation can be changed at runtime. If the SRAM is insufficient, you can use the PSRAM as a canvas and use a small trans_buffer to carry it, this makes drawing more efficient. ``` c - .buffer_size = DISP_WIDTH*DISP_HEIGHT, // in PSRAM, not DMA-capable - .trans_size = size, // in SRAM, DMA-capable - .flags = { - .buff_spiram = true, - .buff_dma = false, + const lvgl_port_display_cfg_t disp_cfg = { + ... + .buffer_size = DISP_WIDTH * DISP_HEIGHT, // in PSRAM, not DMA-capable + .trans_size = size, // in SRAM, DMA-capable + .flags = { + .buff_spiram = true, + .buff_dma = false, + ... + } } ``` diff --git a/components/esp_lvgl_port/esp_lvgl_port.c b/components/esp_lvgl_port/esp_lvgl_port.c index afeefbec..db3b040a 100644 --- a/components/esp_lvgl_port/esp_lvgl_port.c +++ b/components/esp_lvgl_port/esp_lvgl_port.c @@ -268,7 +268,7 @@ lv_disp_t *lvgl_port_add_disp(const lvgl_port_display_cfg_t *disp_cfg) disp_ctx->disp_drv.hor_res = disp_cfg->hres; disp_ctx->disp_drv.ver_res = disp_cfg->vres; disp_ctx->disp_drv.flush_cb = lvgl_port_flush_callback; - disp_ctx->disp_drv.sw_rotate = disp_cfg->sw_rotate; + disp_ctx->disp_drv.sw_rotate = disp_cfg->flags.sw_rotate; if (disp_ctx->disp_drv.sw_rotate == false) { disp_ctx->disp_drv.drv_update_cb = lvgl_port_update_callback; } diff --git a/components/esp_lvgl_port/include/esp_lvgl_port.h b/components/esp_lvgl_port/include/esp_lvgl_port.h index 52766625..4b05915f 100644 --- a/components/esp_lvgl_port/include/esp_lvgl_port.h +++ b/components/esp_lvgl_port/include/esp_lvgl_port.h @@ -65,12 +65,12 @@ typedef struct { uint32_t hres; /*!< LCD display horizontal resolution */ uint32_t vres; /*!< LCD display vertical resolution */ bool monochrome; /*!< True, if display is monochrome and using 1bit for 1px */ - bool sw_rotate; /*!< Use software rotation (slower) */ lvgl_port_rotation_cfg_t rotation; /*!< Default values of the screen rotation */ struct { unsigned int buff_dma: 1; /*!< Allocated LVGL buffer will be DMA capable */ unsigned int buff_spiram: 1; /*!< Allocated LVGL buffer will be in PSRAM */ + unsigned int sw_rotate: 1; /*!< Use software rotation (slower) */ } flags; } lvgl_port_display_cfg_t;