diff --git a/SquareLine/boards/esp32_s3_lcd_ev_board/main/idf_component.yml b/SquareLine/boards/esp32_s3_lcd_ev_board/main/idf_component.yml index 2fa3e5fe..b381e0bf 100644 --- a/SquareLine/boards/esp32_s3_lcd_ev_board/main/idf_component.yml +++ b/SquareLine/boards/esp32_s3_lcd_ev_board/main/idf_component.yml @@ -2,5 +2,4 @@ description: ESP-BSP SquareLine LVGL Example targets: - esp32s3 dependencies: - idf: ">=4.4" esp32_s3_lcd_ev_board: "*" diff --git a/SquareLine/boards/esp32_s3_lcd_ev_board/manifest.json b/SquareLine/boards/esp32_s3_lcd_ev_board/manifest.json index 80f8091e..b7ebb830 100644 --- a/SquareLine/boards/esp32_s3_lcd_ev_board/manifest.json +++ b/SquareLine/boards/esp32_s3_lcd_ev_board/manifest.json @@ -1,6 +1,6 @@ { "name":"ESP32-S3-LCD-EV-BOARD", - "version":"1.0.0", + "version":"2.0.0", "mcu":"ESP32S3", "screen_width":"800", @@ -8,7 +8,7 @@ "screen_color_swap":false, "short_description":"ESP32-S3-LCD-EV-BOARD is a development board for evaluating and verifying ESP32-S3 screen interactive applications. It has the functions of touch screen interaction and voice interaction.", - "long_description":"ESP32-S3-LCD-EV-BOARD has an ESP32-S3-WROOM-1 module with built-in 16 MB Flash and 8 MB PSRAM. It features onboard audio codec + audio amplifier and onboard dual microphone pickup. It uses USB type-C interface for download and debugging. ESP32-S3-LCD-EV-BOARD can be used with different screen sub boards with various screen sizes and resolutions, and supports RGB, 8080, SPI, I2C interface screens.", + "long_description":"ESP32-S3-LCD-EV-BOARD has an ESP32-S3-WROOM-1 module with built-in 16 MB Flash and 8/16 MB PSRAM. It features onboard audio codec + audio amplifier and onboard dual microphone pickup. It uses USB type-C interface for download and debugging. ESP32-S3-LCD-EV-BOARD can be used with different screen sub boards with various screen sizes and resolutions, and supports RGB, 8080, SPI, I2C interface screens.", "placeholders": { diff --git a/SquareLine/boards/esp32_s3_lcd_ev_board/sdkconfig.defaults b/SquareLine/boards/esp32_s3_lcd_ev_board/sdkconfig.defaults index d792ff0f..f38a1937 100644 --- a/SquareLine/boards/esp32_s3_lcd_ev_board/sdkconfig.defaults +++ b/SquareLine/boards/esp32_s3_lcd_ev_board/sdkconfig.defaults @@ -2,18 +2,23 @@ # Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration # CONFIG_IDF_TARGET="esp32s3" -CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_PERF=y CONFIG_ESPTOOLPY_FLASHMODE_QIO=y CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_COMPILER_OPTIMIZATION_PERF=y CONFIG_SPIRAM=y CONFIG_SPIRAM_MODE_OCT=y CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y CONFIG_SPIRAM_RODATA=y CONFIG_SPIRAM_SPEED_80M=y CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y -CONFIG_ESP32S3_DATA_CACHE_64KB=y +CONFIG_ESP32S3_DATA_CACHE_LINE_64B=y CONFIG_FREERTOS_HZ=1000 +CONFIG_BSP_LCD_RGB_BUFFER_NUMS=2 +CONFIG_BSP_LCD_RGB_BOUNCE_BUFFER_MODE=y +CONFIG_BSP_DISPLAY_LVGL_AVOID_TEAR=y +CONFIG_BSP_DISPLAY_LVGL_DIRECT_MODE=y CONFIG_LV_MEM_CUSTOM=y CONFIG_LV_MEMCPY_MEMSET_STD=y -CONFIG_LV_USE_PERF_MONITOR=y \ No newline at end of file +CONFIG_LV_USE_PERF_MONITOR=y +CONFIG_LV_ATTRIBUTE_FAST_MEM_USE_IRAM=y diff --git a/bsp/esp32_s3_lcd_ev_board/CHANGELOG.md b/bsp/esp32_s3_lcd_ev_board/CHANGELOG.md index 6a28ae8f..e97776e8 100644 --- a/bsp/esp32_s3_lcd_ev_board/CHANGELOG.md +++ b/bsp/esp32_s3_lcd_ev_board/CHANGELOG.md @@ -31,3 +31,24 @@ * Add new APIs for touch in `bsp/touch.h` * Add new APIs for spiffs, audio in `bsp/esp32_s3_lcd_ev_board.h` * Add new APIs for ADC in `bsp/esp32_s3_lcd_ev_board.h` + +## v3.0.0 - 2023-12-02 + +### Bugfix + +* Use `on_bounce_frame_finish` instead of `on_vsync` when enabling RGB bounce buffer mode. +* Fix some issues when enabling anti-tearing and rotation + +### Features + +* Configurations: + * Support to set the pinned core for LVGL task +* Implementations: + * Support ESP32-S3-WROOM-1-N16R16V module + * Add warning for compiling and running when using `ESP-IDF` version `<5.1.2` + +### Dependencies + +* Update the version of `ESP-IDF` to `>5.0.1` +* Use `esp_lcd_gc9503` version `^1` when using `ESP-IDF` version `<5.1.2` +* Use `esp_lcd_gc9503` version `^3` when using `ESP-IDF` version `>=5.1.2` diff --git a/bsp/esp32_s3_lcd_ev_board/CMakeLists.txt b/bsp/esp32_s3_lcd_ev_board/CMakeLists.txt index 2539aae6..08a7a3c5 100644 --- a/bsp/esp32_s3_lcd_ev_board/CMakeLists.txt +++ b/bsp/esp32_s3_lcd_ev_board/CMakeLists.txt @@ -5,5 +5,5 @@ idf_component_register( INCLUDE_DIRS "include" PRIV_INCLUDE_DIRS "priv_include" REQUIRES driver esp_lcd esp_adc - PRIV_REQUIRES esp_timer spiffs + PRIV_REQUIRES esp_timer spiffs esp_psram ) diff --git a/bsp/esp32_s3_lcd_ev_board/Kconfig b/bsp/esp32_s3_lcd_ev_board/Kconfig index 35fbddcf..e867d4a7 100644 --- a/bsp/esp32_s3_lcd_ev_board/Kconfig +++ b/bsp/esp32_s3_lcd_ev_board/Kconfig @@ -124,6 +124,13 @@ menu "Board Support Package" help The Board Support Package will create a task that will periodically handle LVGL operation in lv_timer_handler(). + config BSP_DISPLAY_LVGL_TASK_CORE_ID + int "LVGL task pinned core ID" + default -1 + range -1 1 + help + Core to pin LVGL task. -1 means no pinning. + config BSP_DISPLAY_LVGL_TASK_DELAY int "LVGL task minimum delay time (ms)" default 10 @@ -131,7 +138,7 @@ menu "Board Support Package" help Minimum delay time for LVGL task. It should be larger if the task watchdog is triggered frequently. - config BSP_DISPLAY_LVGL_TASK_STACK_SIZE + config BSP_DISPLAY_LVGL_TASK_STACK_SIZE_KB int "LVGL task stack size (KB)" default 4 help diff --git a/bsp/esp32_s3_lcd_ev_board/README.md b/bsp/esp32_s3_lcd_ev_board/README.md index bbb34404..f10d4323 100644 --- a/bsp/esp32_s3_lcd_ev_board/README.md +++ b/bsp/esp32_s3_lcd_ev_board/README.md @@ -10,7 +10,7 @@ ESP32-S3-LCD-EV-Board is a development board for evaluating and verifying ESP32-S3 screen interactive applications. It has the functions of touch screen interaction and voice interaction. The development board has the following characteristics: -* Onboard ESP32-S3-WROOM-1 module, with built-in 16 MB Flash + 8 MB PSRAM +* Onboard ESP32-S3-WROOM-1 module, with built-in 16 MB Flash + 8/16 MB PSRAM * Onboard audio codec + audio amplifier * Onboard dual microphone pickup * USB type-C interface download and debugging @@ -30,7 +30,7 @@ Here are some useful configurations in menuconfig that can be customed by user: * `BSP_LCD_RGB_REFRESH_MODE`: Choose the refresh mode for the RGB LCD. * `BSP_LCD_RGB_REFRESH_AUTO`: Use the most common method to refresh the LCD. * `BSP_LCD_RGB_REFRESH_MANUALLY`: Refresh the LCD within a dedicated task. This can help manage PSRAM bandwidth. - * `BSP_LCD_RGB_BOUNCE_BUFFER_MODE`: Enabling bounce buffer mode can lead to a higher PCLK frequency at the expense of increased CPU consumption. **This mode is particularly useful when dealing with screen drift, especially in scenarios involving Wi-Fi usage or writing to Flash memory. For more detailed information, refer to the documentation [here](https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/api-reference/peripherals/lcd.html#bounce-buffer-with-single-psram-frame-buffer).** This feature should be used in conjunction with `ESP32S3_DATA_CACHE_LINE_64B` configuration. + * `BSP_LCD_RGB_BOUNCE_BUFFER_MODE`: Enabling bounce buffer mode can lead to a higher PCLK frequency at the expense of increased CPU consumption. **This mode is particularly useful when dealing with [screen drift](https://docs.espressif.com/projects/esp-faq/en/latest/software-framework/peripherals/lcd.html#why-do-i-get-drift-overall-drift-of-the-display-when-esp32-s3-is-driving-an-rgb-lcd-screen), especially in scenarios involving Wi-Fi usage or writing to Flash memory.** This feature should be used in conjunction with `ESP32S3_DATA_CACHE_LINE_64B` configuration. For more detailed information, refer to the [documentation](https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/api-reference/peripherals/lcd.html#bounce-buffer-with-single-psram-frame-buffer). * `BSP_DISPLAY_LVGL_BUF_CAPS`: Select the memory type for the LVGL buffer. Internal memory offers better performance. * `BSP_DISPLAY_LVGL_BUF_HEIGHT`: Set the height of the LVGL buffer, with its width aligning with the LCD's width. The default value is 100, decreasing it can lower memory consumption. * `BSP_DISPLAY_LVGL_AVOID_TEAR`: Avoid tearing effect by using multiple buffers. This requires setting `BSP_LCD_RGB_BUFFER_NUMS` to a value greater than 1. @@ -42,3 +42,15 @@ Here are some useful configurations in menuconfig that can be customed by user: * `BSP_DISPLAY_LVGL_ROTATION_90`: 90-degree rotation. * `BSP_DISPLAY_LVGL_ROTATION_180`: 180-degree rotation. * `BSP_DISPLAY_LVGL_ROTATION_270`: 270-degree rotation. + +Based on the above configurations, there are three different anti-tearing modes can be used: + +* RGB double-buffer + LVGL full-refresh mode: + * Set `BSP_LCD_RGB_BUFFER_NUMS` to `2` + * Enable `BSP_DISPLAY_LVGL_AVOID_TEAR` and `BSP_DISPLAY_LVGL_FULL_REFRESH` +* RGB double-buffer + LVGL direct-mode: + * Set `BSP_LCD_RGB_BUFFER_NUMS` to `2` + * Enable `BSP_DISPLAY_LVGL_AVOID_TEAR` and `BSP_DISPLAY_LVGL_DIRECT_MODE` +* RGB triple-buffer + LVGL full-refresh mode: + * Set `BSP_LCD_RGB_BUFFER_NUMS` to `3` + * Enable `BSP_DISPLAY_LVGL_AVOID_TEAR` and `BSP_DISPLAY_LVGL_FULL_REFRESH` diff --git a/bsp/esp32_s3_lcd_ev_board/idf_component.yml b/bsp/esp32_s3_lcd_ev_board/idf_component.yml index f3f93bdc..02e1e8eb 100644 --- a/bsp/esp32_s3_lcd_ev_board/idf_component.yml +++ b/bsp/esp32_s3_lcd_ev_board/idf_component.yml @@ -1,4 +1,4 @@ -version: "2.0.0~2" +version: "2.1.0" description: Board Support Package for ESP32-S3-LCD-EV-Board url: https://github.com/espressif/esp-bsp/tree/master/bsp/esp32_s3_lcd_ev_board @@ -6,7 +6,7 @@ targets: - esp32s3 dependencies: - idf: ">=5.0" + idf: ">=5.0.1" esp_lcd_touch_gt1151: version: "^1" @@ -29,7 +29,11 @@ dependencies: public: true esp_lcd_gc9503: - version: "^1" + matches: + - if: "idf_version <5.1.2" + version: "^1" + - if: "idf_version >=5.1.2" + version: "^3" public: true esp_codec_dev: diff --git a/bsp/esp32_s3_lcd_ev_board/include/bsp/esp32_s3_lcd_ev_board.h b/bsp/esp32_s3_lcd_ev_board/include/bsp/esp32_s3_lcd_ev_board.h index bd6fe5ad..7bd5b8ba 100644 --- a/bsp/esp32_s3_lcd_ev_board/include/bsp/esp32_s3_lcd_ev_board.h +++ b/bsp/esp32_s3_lcd_ev_board/include/bsp/esp32_s3_lcd_ev_board.h @@ -31,6 +31,10 @@ #define BSP_I2C_SCL (GPIO_NUM_18) #define BSP_I2C_SDA (GPIO_NUM_8) +// Pins for board using ESP32-S3-WROOM-1-N16R16V +#define BSP_I2C_SCL_R16 (GPIO_NUM_48) +#define BSP_I2C_SDA_R16 (GPIO_NUM_47) + /* Audio */ #define BSP_I2S_SCLK (GPIO_NUM_16) #define BSP_I2S_MCLK (GPIO_NUM_5) @@ -62,6 +66,10 @@ #define BSP_LCD_SUB_BOARD_2_3_DATA14 (GPIO_NUM_2) #define BSP_LCD_SUB_BOARD_2_3_DATA15 (GPIO_NUM_1) +// Pins for board using ESP32-S3-WROOM-1-N16R16V +#define BSP_LCD_SUB_BOARD_2_3_DATA6_R16 (GPIO_NUM_8) +#define BSP_LCD_SUB_BOARD_2_3_DATA7_R16 (GPIO_NUM_18) + #define BSP_LCD_SUB_BOARD_2_SPI_CS (IO_EXPANDER_PIN_NUM_1) #define BSP_LCD_SUB_BOARD_2_SPI_SCK (IO_EXPANDER_PIN_NUM_2) #define BSP_LCD_SUB_BOARD_2_SPI_SDO (IO_EXPANDER_PIN_NUM_3) @@ -282,7 +290,8 @@ esp_err_t bsp_audio_poweramp_enable(bool enable); #define BSP_LCD_SUB_BOARD_2_H_RES (480) #define BSP_LCD_SUB_BOARD_2_V_RES (480) -#define SUB_BOARD2_800_480_PANEL_60HZ_RGB_TIMING() GC9503_480_480_PANEL_60HZ_RGB_TIMING() +#define SUB_BOARD2_480_480_PANEL_60HZ_RGB_TIMING() GC9503_480_480_PANEL_60HZ_RGB_TIMING() +#define SUB_BOARD2_480_480_PANEL_SCL_ACTIVE_EDGE (0) // Rising edge, 1: Falling edge #define BSP_LCD_SUB_BOARD_3_H_RES (800) #define BSP_LCD_SUB_BOARD_3_V_RES (480) diff --git a/bsp/esp32_s3_lcd_ev_board/priv_include/bsp_lvgl_port.h b/bsp/esp32_s3_lcd_ev_board/priv_include/bsp_lvgl_port.h index cc484502..34cc0f47 100644 --- a/bsp/esp32_s3_lcd_ev_board/priv_include/bsp_lvgl_port.h +++ b/bsp/esp32_s3_lcd_ev_board/priv_include/bsp_lvgl_port.h @@ -17,10 +17,36 @@ extern "C" { #endif +/** + * @brief Initialize LVGL port + * + * @param[in] lcd: LCD panel handle + * @param[in] tp: Touch handle + * @param[out] disp: LVGL display device + * @param[out] indev: LVGL input device + * + * @return + * - ESP_OK: Success + * - ESP_ERR_INVALID_ARG: Invalid argument + * - Others: Fail + */ esp_err_t bsp_lvgl_port_init(esp_lcd_panel_handle_t lcd, esp_lcd_touch_handle_t tp, lv_disp_t **disp, lv_indev_t **indev); +/** + * @brief Take LVGL mutex + * + * @param[in] timeout_ms: Timeout in [ms]. 0 will block indefinitely. + * + * @return + * - true: Mutex was taken + * - false: Mutex was NOT taken + */ bool bsp_lvgl_port_lock(uint32_t timeout_ms); +/** + * @brief Give LVGL mutex + * + */ void bsp_lvgl_port_unlock(void); #ifdef __cplusplus diff --git a/bsp/esp32_s3_lcd_ev_board/priv_include/bsp_probe.h b/bsp/esp32_s3_lcd_ev_board/priv_include/bsp_probe.h new file mode 100644 index 00000000..11b3b6bd --- /dev/null +++ b/bsp/esp32_s3_lcd_ev_board/priv_include/bsp_probe.h @@ -0,0 +1,46 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + MODULE_TYPE_UNKNOW = 0, + MODULE_TYPE_R8, /*!< ESP32-S3-WROOM-1-N16R8 */ + MODULE_TYPE_R16, /*!< ESP32-S3-WROOM-1-N16R16V */ +} bsp_module_type_t; + +typedef enum { + SUB_BOARD_TYPE_UNKNOW = 0, + SUB_BOARD_TYPE_2_480_480, /*!< Sub-board 2 with 480x480 LCD (GC9503), Touch (FT5x06) */ + SUB_BOARD_TYPE_3_800_480, /*!< Sub-board 3 with 800x480 LCD (ST7262), Touch (GT1151) */ +} bsp_sub_board_type_t; + +/** + * @brief Get module type + * + * @return + * - MODULE_TYPE_UNKNOW: Unknow module + * - MODULE_TYPE_R8: ESP32-S3-WROOM-1-N16R8 + * - MODULE_TYPE_R16: ESP32-S3-WROOM-1-N16R16V + */ +bsp_module_type_t bsp_probe_module_type(void); + +/** + * @brief Get sub-board type + * + * @return + * - SUB_BOARD_TYPE_UNKNOW: Unknow sub-board + * - SUB_BOARD_TYPE_2_480_480: Sub-board 2 with 480x480 LCD (GC9503), Touch (FT5x06) + * - SUB_BOARD_TYPE_3_800_480: Sub-board 3 with 800x480 LCD (ST7262), Touch (GT1151) + */ +bsp_sub_board_type_t bsp_probe_sub_board_type(void); + +#ifdef __cplusplus +} +#endif diff --git a/bsp/esp32_s3_lcd_ev_board/priv_include/bsp_sub_board.h b/bsp/esp32_s3_lcd_ev_board/priv_include/bsp_sub_board.h deleted file mode 100644 index b1e209ac..00000000 --- a/bsp/esp32_s3_lcd_ev_board/priv_include/bsp_sub_board.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ -#ifndef BSP_SUB_BOARD_H -#define BSP_SUB_BOARD_H - -#include "bsp/esp32_s3_lcd_ev_board.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum { - SUB_BOARD_TYPE_UNKNOW = 0, - SUB_BOARD_TYPE_2_480_480, - SUB_BOARD_TYPE_3_800_480, -} bsp_sub_board_type_t; - -/** - * @brief Get sub-board type - * - * @return - * - SUB_BOARD_TYPE_UNKNOW: Unknow sub-board - * - SUB_BOARD_TYPE_2_480_480: Sub-board 2 with 480x480 LCD (GC9503), Touch (FT5x06) - * - SUB_BOARD_TYPE_3_800_480: Sub-board 3 with 800x480 LCD (ST7262), Touch (GT1151) - */ -bsp_sub_board_type_t bsp_sub_board_get_type(void); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/bsp/esp32_s3_lcd_ev_board/src/bsp_lvgl_port.c b/bsp/esp32_s3_lcd_ev_board/src/bsp_lvgl_port.c index f481cae7..a62d67bc 100644 --- a/bsp/esp32_s3_lcd_ev_board/src/bsp_lvgl_port.c +++ b/bsp/esp32_s3_lcd_ev_board/src/bsp_lvgl_port.c @@ -14,7 +14,6 @@ #include "lvgl.h" #include "bsp_err_check.h" -#include "bsp_sub_board.h" #include "bsp/display.h" #include "bsp/esp32_s3_lcd_ev_board.h" @@ -46,14 +45,14 @@ IRAM_ATTR static void rotate_copy_pixel(const uint16_t *from, uint16_t *to, uint switch (rotate) { case LV_DISP_ROT_90: - to_index_const = (x_start + 1) * h - 1; + to_index_const = (w - x_start - 1) * h; for (int from_y = y_start; from_y < y_end + 1; from_y++) { from_index = from_y * w + x_start; - to_index = to_index_const - from_y; + to_index = to_index_const + from_y; for (int from_x = x_start; from_x < x_end + 1; from_x++) { *(to + to_index) = *(from + from_index); from_index += 1; - to_index += h; + to_index -= h; } } break; @@ -70,14 +69,14 @@ IRAM_ATTR static void rotate_copy_pixel(const uint16_t *from, uint16_t *to, uint } break; case LV_DISP_ROT_270: - to_index_const = (w - x_start - 1) * h; + to_index_const = (x_start + 1) * h - 1; for (int from_y = y_start; from_y < y_end + 1; from_y++) { from_index = from_y * w + x_start; - to_index = to_index_const + from_y; + to_index = to_index_const - from_y; for (int from_x = x_start; from_x < x_end + 1; from_x++) { *(to + to_index) = *(from + from_index); from_index += 1; - to_index -= h; + to_index += h; } } break; @@ -171,16 +170,14 @@ static inline void *flush_get_next_buf(void *panel_handle) */ static void flush_dirty_copy(void *dst, void *src, lv_port_dirty_area_t *dirty_area) { - lv_disp_t *disp_refr = _lv_refr_get_disp_refreshing(); - lv_coord_t x_start, x_end, y_start, y_end; - for (int i = 0; i < disp_refr->inv_p; i++) { + for (int i = 0; i < dirty_area->inv_p; i++) { /* Refresh the unjoined areas*/ - if (disp_refr->inv_area_joined[i] == 0) { - x_start = disp_refr->inv_areas[i].x1; - x_end = disp_refr->inv_areas[i].x2; - y_start = disp_refr->inv_areas[i].y1; - y_end = disp_refr->inv_areas[i].y2; + if (dirty_area->inv_area_joined[i] == 0) { + x_start = dirty_area->inv_areas[i].x1; + x_end = dirty_area->inv_areas[i].x2; + y_start = dirty_area->inv_areas[i].y1; + y_end = dirty_area->inv_areas[i].y2; rotate_copy_pixel(src, dst, x_start, y_start, x_end, y_end, LV_HOR_RES, LV_VER_RES, CONFIG_BSP_DISPLAY_LVGL_ROTATION_DEGREE); } @@ -194,39 +191,59 @@ static void flush_callback(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t const int offsetx2 = area->x2; const int offsety1 = area->y1; const int offsety2 = area->y2; + void *next_fb = NULL; + lv_port_flush_probe_t probe_result = FLUSH_PROBE_PART_COPY; - void *next_fb = flush_get_next_buf(panel_handle); - - lv_port_flush_probe_t probe_result; /* Action after last area refresh */ if (lv_disp_flush_is_last(drv)) { + /* Check if the `full_refresh` flag has been triggered */ if (drv->full_refresh) { + /* Reset flag */ drv->full_refresh = 0; - rotate_copy_pixel(color_map, next_fb, offsetx1, offsety1, offsetx2, offsety2, LV_HOR_RES, LV_VER_RES, CONFIG_BSP_DISPLAY_LVGL_ROTATION_DEGREE); - /* Due to direct-mode, here we just swtich driver's pointer of frame buffer rather than draw bitmap */ + + // Roate and copy data from the whole screen LVGL's buffer to the next frame buffer + next_fb = flush_get_next_buf(panel_handle); + rotate_copy_pixel((uint16_t *)color_map, next_fb, offsetx1, offsety1, offsetx2, offsety2, LV_HOR_RES, LV_VER_RES, CONFIG_BSP_DISPLAY_LVGL_ROTATION_DEGREE); + + /* Switch the current RGB frame buffer to `next_fb` */ esp_lcd_panel_draw_bitmap(panel_handle, offsetx1, offsety1, offsetx2 + 1, offsety2 + 1, next_fb); + /* Waiting for the current frame buffer to complete transmission */ ulTaskNotifyValueClear(NULL, ULONG_MAX); ulTaskNotifyTake(pdTRUE, portMAX_DELAY); + + /* Synchronously update the dirty area for another frame buffer */ flush_dirty_copy(flush_get_next_buf(panel_handle), color_map, &dirty_area); flush_get_next_buf(panel_handle); } else { - /* Probe and copy dirty area from the current LVGL's frame buffer to the next LVGL's frame buffer */ + /* Probe the copy method for the current dirty area */ probe_result = flush_copy_probe(drv); + if (probe_result == FLUSH_PROBE_FULL_COPY) { + /* Save current dirty area for next frame buffer */ flush_dirty_save(&dirty_area); - /* Set LVGL full-refresh flag and force to refresh whole screen */ + + /* Set LVGL full-refresh flag and set flush ready in advance */ drv->full_refresh = 1; lv_disp_flush_ready(drv); + + /* Force to refresh whole screen, and will invoke `flush_callback` recursively */ lv_refr_now(_lv_refr_get_disp_refreshing()); } else { - rotate_copy_pixel(color_map, next_fb, offsetx1, offsety1, offsetx2, offsety2, LV_HOR_RES, LV_VER_RES, CONFIG_BSP_DISPLAY_LVGL_ROTATION_DEGREE); - /* Due to full-refresh mode, here we just swtich pointer of frame buffer rather than draw bitmap */ + /* Update current dirty area for next frame buffer */ + next_fb = flush_get_next_buf(panel_handle); + flush_dirty_save(&dirty_area); + flush_dirty_copy(next_fb, color_map, &dirty_area); + + /* Switch the current RGB frame buffer to `next_fb` */ esp_lcd_panel_draw_bitmap(panel_handle, offsetx1, offsety1, offsetx2 + 1, offsety2 + 1, next_fb); + /* Waiting for the current frame buffer to complete transmission */ ulTaskNotifyValueClear(NULL, ULONG_MAX); ulTaskNotifyTake(pdTRUE, portMAX_DELAY); + if (probe_result == FLUSH_PROBE_PART_COPY) { + /* Synchronously update the dirty area for another frame buffer */ flush_dirty_save(&dirty_area); flush_dirty_copy(flush_get_next_buf(panel_handle), color_map, &dirty_area); flush_get_next_buf(panel_handle); @@ -253,20 +270,18 @@ static inline void *flush_get_next_buf(void *buf) */ static void flush_dirty_copy(void *dst, void *src, lv_port_dirty_area_t *dirty_area) { - lv_disp_t *disp_refr = _lv_refr_get_disp_refreshing(); - lv_coord_t x_start, x_end, y_start, y_end; uint32_t copy_bytes_per_line; - uint32_t h_res = disp_refr->driver->hor_res; + uint32_t h_res = LV_HOR_RES; uint32_t bytes_per_line = h_res * 2; uint8_t *from, *to; - for (int i = 0; i < disp_refr->inv_p; i++) { + for (int i = 0; i < dirty_area->inv_p; i++) { /* Refresh the unjoined areas*/ - if (disp_refr->inv_area_joined[i] == 0) { - x_start = disp_refr->inv_areas[i].x1; - x_end = disp_refr->inv_areas[i].x2 + 1; - y_start = disp_refr->inv_areas[i].y1; - y_end = disp_refr->inv_areas[i].y2 + 1; + if (dirty_area->inv_area_joined[i] == 0) { + x_start = dirty_area->inv_areas[i].x1; + x_end = dirty_area->inv_areas[i].x2 + 1; + y_start = dirty_area->inv_areas[i].y1; + y_end = dirty_area->inv_areas[i].y2 + 1; copy_bytes_per_line = (x_end - x_start) * 2; from = src + (y_start * h_res + x_start) * 2; @@ -291,31 +306,45 @@ static void flush_callback(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t lv_port_flush_probe_t probe_result; /* Action after last area refresh */ if (lv_disp_flush_is_last(drv)) { + /* Check if the `full_refresh` flag has been triggered */ if (drv->full_refresh) { + /* Reset flag */ drv->full_refresh = 0; - /* Due to direct-mode, here we just swtich driver's pointer of frame buffer rather than draw bitmap */ + + /* Switch the current RGB frame buffer to `color_map` */ esp_lcd_panel_draw_bitmap(panel_handle, offsetx1, offsety1, offsetx2 + 1, offsety2 + 1, color_map); - /* Waiting for the current frame buffer to complete transmission */ + + /* Waiting for the last frame buffer to complete transmission */ ulTaskNotifyValueClear(NULL, ULONG_MAX); ulTaskNotifyTake(pdTRUE, portMAX_DELAY); + + /* Synchronously update the dirty area for another frame buffer */ flush_dirty_copy(flush_get_next_buf(color_map), color_map, &dirty_area); drv->draw_buf->buf_act = (color_map == drv->draw_buf->buf1) ? drv->draw_buf->buf2 : drv->draw_buf->buf1; } else { - /* Probe and copy dirty area from the current LVGL's frame buffer to the next LVGL's frame buffer */ + /* Probe the copy method for the current dirty area */ probe_result = flush_copy_probe(drv); + if (probe_result == FLUSH_PROBE_FULL_COPY) { + /* Save current dirty area for next frame buffer */ flush_dirty_save(&dirty_area); - /* Set LVGL full-refresh flag and force to refresh whole screen */ + + /* Set LVGL full-refresh flag and set flush ready in advance */ drv->full_refresh = 1; lv_disp_flush_ready(drv); + + /* Force to refresh whole screen, and will invoke `flush_callback` recursively */ lv_refr_now(_lv_refr_get_disp_refreshing()); } else { - /* Due to direct-mode, here we just swtich driver's pointer of frame buffer rather than draw bitmap */ + /* Switch the current RGB frame buffer to `color_map` */ esp_lcd_panel_draw_bitmap(panel_handle, offsetx1, offsety1, offsetx2 + 1, offsety2 + 1, color_map); - /* Waiting for the current frame buffer to complete transmission */ + + /* Waiting for the last frame buffer to complete transmission */ ulTaskNotifyValueClear(NULL, ULONG_MAX); ulTaskNotifyTake(pdTRUE, portMAX_DELAY); + if (probe_result == FLUSH_PROBE_PART_COPY) { + /* Synchronously update the dirty area for another frame buffer */ flush_dirty_save(&dirty_area); flush_dirty_copy(flush_get_next_buf(color_map), color_map, &dirty_area); } @@ -337,9 +366,10 @@ static void flush_callback(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t const int offsety1 = area->y1; const int offsety2 = area->y2; - /* Due to full-refresh mode, here we just swtich pointer of frame buffer rather than draw bitmap */ + /* Switch the current RGB frame buffer to `color_map` */ esp_lcd_panel_draw_bitmap(panel_handle, offsetx1, offsety1, offsetx2 + 1, offsety2 + 1, color_map); - /* Waiting for the current frame buffer to complete transmission */ + + /* Waiting for the last frame buffer to complete transmission */ ulTaskNotifyValueClear(NULL, ULONG_MAX); ulTaskNotifyTake(pdTRUE, portMAX_DELAY); @@ -364,15 +394,20 @@ void flush_callback(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color #if CONFIG_BSP_DISPLAY_LVGL_ROTATION_DEGREE != 0 void *next_fb = get_next_frame_buffer(panel_handle); - rotate_copy_pixel(color_map, next_fb, offsetx1, offsety1, offsetx2, offsety2, LV_HOR_RES, LV_VER_RES, CONFIG_BSP_DISPLAY_LVGL_ROTATION_DEGREE); - /* Due to full-refresh mode, here we just swtich pointer of frame buffer rather than draw bitmap */ + + /* Rotate and copy dirty area from the current LVGL's buffer to the next RGB frame buffer */ + rotate_copy_pixel((uint16_t *)color_map, next_fb, offsetx1, offsety1, offsetx2, offsety2, LV_HOR_RES, LV_VER_RES, CONFIG_BSP_DISPLAY_LVGL_ROTATION_DEGREE); + + /* Switch the current RGB frame buffer to `next_fb` */ esp_lcd_panel_draw_bitmap(panel_handle, offsetx1, offsety1, offsetx2 + 1, offsety2 + 1, next_fb); #else drv->draw_buf->buf1 = color_map; drv->draw_buf->buf2 = lvgl_port_flush_next_buf; lvgl_port_flush_next_buf = color_map; - /* Due to full-refresh mode, here we just swtich pointer of frame buffer rather than draw bitmap */ + + /* Switch the current RGB frame buffer to `color_map` */ esp_lcd_panel_draw_bitmap(panel_handle, offsetx1, offsety1, offsetx2 + 1, offsety2 + 1, color_map); + lvgl_port_rgb_next_buf = color_map; #endif @@ -389,6 +424,7 @@ static bool lcd_trans_done(esp_lcd_panel_handle_t handle) lvgl_port_rgb_last_buf = lvgl_port_rgb_next_buf; } #else + // Notify that the current RGB frame buffer has been transmitted xTaskNotifyFromISR(lvgl_task_handle, ULONG_MAX, eNoAction, &need_yield); #endif return (need_yield == pdTRUE); @@ -404,6 +440,7 @@ void flush_callback(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color const int offsety1 = area->y1; const int offsety2 = area->y2; + /* Just copy data from the color map to the RGB frame buffer */ esp_lcd_panel_draw_bitmap(panel_handle, offsetx1, offsety1, offsetx2 + 1, offsety2 + 1, color_map); lv_disp_flush_ready(drv); @@ -449,14 +486,11 @@ static lv_disp_t *display_init(esp_lcd_panel_handle_t lcd) ESP_LOGD(TAG, "Malloc memory for LVGL buffer"); #ifndef CONFIG_BSP_DISPLAY_LVGL_AVOID_TEAR - bsp_sub_board_type_t type = bsp_sub_board_get_type(); - if ((type == SUB_BOARD_TYPE_2_480_480) || (type == SUB_BOARD_TYPE_3_800_480)) { - // Normmaly, for RGB LCD, we just use one buffer for LVGL rendering - buffer_size = BSP_LCD_H_RES * LVGL_BUFFER_HEIGHT; - buf1 = heap_caps_malloc(buffer_size * sizeof(lv_color_t), LVGL_BUFFER_MALLOC); - BSP_NULL_CHECK(buf1, NULL); - ESP_LOGI(TAG, "LVGL buffer size: %dKB", buffer_size * sizeof(lv_color_t) / 1024); - } + // Normmaly, for RGB LCD, we just use one buffer for LVGL rendering + buffer_size = BSP_LCD_H_RES * LVGL_BUFFER_HEIGHT; + buf1 = heap_caps_malloc(buffer_size * sizeof(lv_color_t), LVGL_BUFFER_MALLOC); + BSP_NULL_CHECK(buf1, NULL); + ESP_LOGI(TAG, "LVGL buffer size: %dKB", buffer_size * sizeof(lv_color_t) / 1024); #else // To avoid the tearing effect, we should use at least two frame buffers: one for LVGL rendering and another for RGB output buffer_size = BSP_LCD_H_RES * BSP_LCD_V_RES; @@ -585,21 +619,22 @@ esp_err_t bsp_lvgl_port_init(esp_lcd_panel_handle_t lcd, esp_lcd_touch_handle_t #if CONFIG_BSP_DISPLAY_LVGL_ROTATION_90 esp_lcd_touch_set_swap_xy(tp, true); - esp_lcd_touch_set_mirror_x(tp, true); + esp_lcd_touch_set_mirror_y(tp, true); #elif CONFIG_BSP_DISPLAY_LVGL_ROTATION_180 esp_lcd_touch_set_mirror_x(tp, true); esp_lcd_touch_set_mirror_y(tp, true); #elif CONFIG_BSP_DISPLAY_LVGL_ROTATION_270 esp_lcd_touch_set_swap_xy(tp, true); - esp_lcd_touch_set_mirror_y(tp, true); + esp_lcd_touch_set_mirror_x(tp, true); #endif lvgl_mux = xSemaphoreCreateRecursiveMutex(); BSP_NULL_CHECK(lvgl_mux, ESP_FAIL); ESP_LOGI(TAG, "Create LVGL task"); - BaseType_t ret = xTaskCreate( - lvgl_port_task, "LVGL", CONFIG_BSP_DISPLAY_LVGL_TASK_STACK_SIZE * 1024, NULL, - CONFIG_BSP_DISPLAY_LVGL_TASK_PRIORITY, &lvgl_task_handle + BaseType_t core_id = (CONFIG_BSP_DISPLAY_LVGL_TASK_CORE_ID < 0) ? tskNO_AFFINITY : CONFIG_BSP_DISPLAY_LVGL_TASK_CORE_ID; + BaseType_t ret = xTaskCreatePinnedToCore( + lvgl_port_task, "LVGL", CONFIG_BSP_DISPLAY_LVGL_TASK_STACK_SIZE_KB * 1024, NULL, + CONFIG_BSP_DISPLAY_LVGL_TASK_PRIORITY, &lvgl_task_handle, core_id ); if (ret != pdPASS) { ESP_LOGE(TAG, "Failed to create LVGL task"); diff --git a/bsp/esp32_s3_lcd_ev_board/src/bsp_probe.c b/bsp/esp32_s3_lcd_ev_board/src/bsp_probe.c new file mode 100644 index 00000000..f8a8c3e2 --- /dev/null +++ b/bsp/esp32_s3_lcd_ev_board/src/bsp_probe.c @@ -0,0 +1,85 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: CC0-1.0 + */ +#include "driver/i2c.h" +#include "esp_check.h" +#include "esp_psram.h" + +#include "esp_lcd_touch_ft5x06.h" +#include "esp_lcd_touch_gt1151.h" +#include "bsp_probe.h" +#include "bsp_err_check.h" +#include "bsp/esp32_s3_lcd_ev_board.h" + +#define MODULE_PSRAM_SIZE_R8 (8 * 1024 * 1024) + +static const char *TAG = "bsp_probe"; +static bsp_module_type_t module_type = MODULE_TYPE_UNKNOW; +static bsp_sub_board_type_t sub_board_type = SUB_BOARD_TYPE_UNKNOW; + +bsp_module_type_t bsp_probe_module_type(void) +{ + if (module_type != MODULE_TYPE_UNKNOW) { + return module_type; + } + + int psram_size = esp_psram_get_size(); + if (psram_size > MODULE_PSRAM_SIZE_R8) { + ESP_LOGI(TAG, "Detect module with 16MB PSRAM"); + module_type = MODULE_TYPE_R16; + } else { + ESP_LOGI(TAG, "Detect module with 8MB PSRAM"); + module_type = MODULE_TYPE_R8; + } + + return module_type; +} + +bsp_sub_board_type_t bsp_probe_sub_board_type(void) +{ + if (sub_board_type != SUB_BOARD_TYPE_UNKNOW) { + return sub_board_type; + } + + BSP_ERROR_CHECK_RETURN_ERR(bsp_i2c_init()); + + uint8_t tp_address[] = { + ESP_LCD_TOUCH_IO_I2C_FT5x06_ADDRESS, + ESP_LCD_TOUCH_IO_I2C_GT1151_ADDRESS, + }; + uint8_t i = 0; + i2c_cmd_handle_t cmd; + bsp_sub_board_type_t detect_type = SUB_BOARD_TYPE_UNKNOW; + while (i < sizeof(tp_address)) { + cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, (tp_address[i] << 1) | I2C_MASTER_WRITE, true); + i2c_master_stop(cmd); + if (i2c_master_cmd_begin(BSP_I2C_NUM, cmd, pdMS_TO_TICKS(20)) == ESP_OK) { + if (tp_address[i] == ESP_LCD_TOUCH_IO_I2C_FT5x06_ADDRESS) { + ESP_LOGI(TAG, "Detect sub_board2 with 480x480 LCD (GC9503), Touch (FT5x06)"); + detect_type = SUB_BOARD_TYPE_2_480_480; + } else if (tp_address[i] == ESP_LCD_TOUCH_IO_I2C_GT1151_ADDRESS) { + ESP_LOGI(TAG, "Detect sub_board3 with 800x480 LCD (ST7262), Touch (GT1151)"); + detect_type = SUB_BOARD_TYPE_3_800_480; + } + } + i2c_cmd_link_delete(cmd); + if (detect_type != SUB_BOARD_TYPE_UNKNOW) { + break; + } + i++; + } + + ESP_RETURN_ON_FALSE(detect_type != SUB_BOARD_TYPE_UNKNOW, ESP_ERR_INVALID_STATE, TAG, + "Failed to detect sub_board type, please check the hardware connection"); + if (CONFIG_BSP_LCD_SUB_BOARD_TYPE) { + ESP_RETURN_ON_FALSE(detect_type == CONFIG_BSP_LCD_SUB_BOARD_TYPE, ESP_ERR_INVALID_STATE, TAG, + "Sub_board type mismatch, please check the software configuration and hardware connection"); + } + sub_board_type = detect_type; + + return sub_board_type; +} diff --git a/bsp/esp32_s3_lcd_ev_board/src/bsp_sub_board.c b/bsp/esp32_s3_lcd_ev_board/src/bsp_sub_board.c index 1cf26cd1..164d6a6c 100644 --- a/bsp/esp32_s3_lcd_ev_board/src/bsp_sub_board.c +++ b/bsp/esp32_s3_lcd_ev_board/src/bsp_sub_board.c @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include "driver/i2c.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/semphr.h" @@ -22,20 +21,25 @@ #include "sdkconfig.h" #include "bsp_err_check.h" -#include "bsp_sub_board.h" +#include "bsp_probe.h" #include "bsp/display.h" #include "bsp/esp32_s3_lcd_ev_board.h" #include "bsp/touch.h" +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 1, 2) +#warning "Due to significant updates of the RGB LCD drivers, it's recommended to develop using ESP-IDF v5.1.2 or later" +#endif + +#if CONFIG_ESP32S3_DATA_CACHE_LINE_64B && !(CONFIG_SPIRAM_SPEED_120M || CONFIG_BSP_LCD_RGB_BOUNCE_BUFFER_MODE) +#warning "Enabling the `ESP32S3_DATA_CACHE_LINE_64B` configuration when the PSRAM speed is not set to 120MHz (`SPIRAM_SPEED_120M`) and the LCD is not in bounce buffer mode (`BSP_LCD_RGB_BOUNCE_BUFFER_MODE`) may result in screen drift, please enable `ESP32S3_DATA_CACHE_LINE_32B` instead" +#endif + static const char *TAG = "bsp_sub_board"; -static bsp_sub_board_type_t sub_board_type = SUB_BOARD_TYPE_UNKNOW; static bsp_display_trans_done_cb_t trans_done = NULL; #if CONFIG_BSP_LCD_RGB_REFRESH_MANUALLY static TaskHandle_t lcd_task_handle = NULL; #endif -static esp_err_t detect_sub_board_type(void); - /************************************************************************************************** * * Display Panel Function @@ -73,11 +77,31 @@ static void lcd_task(void *arg) esp_err_t bsp_display_new(const bsp_display_config_t *config, esp_lcd_panel_handle_t *ret_panel, esp_lcd_panel_io_handle_t *ret_io) { +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 1, 2) + ESP_LOGW(TAG, "Due to significant updates of the RGB LCD drivers, it's recommended to develop using ESP-IDF v5.1.2 or later"); +#endif + +#if CONFIG_ESP32S3_DATA_CACHE_LINE_64B && !(CONFIG_SPIRAM_SPEED_120M || CONFIG_BSP_LCD_RGB_BOUNCE_BUFFER_MODE) + ESP_LOGW(TAG, "Enabling the `ESP32S3_DATA_CACHE_LINE_64B` configuration when the PSRAM speed is not set to 120MHz \ +(`SPIRAM_SPEED_120M`) and the LCD is not in bounce buffer mode (`BSP_LCD_RGB_BOUNCE_BUFFER_MODE`) may result in screen \ +drift, please enable `ESP32S3_DATA_CACHE_LINE_32B` instead"); +#endif + esp_io_expander_handle_t expander = NULL; esp_lcd_panel_handle_t panel_handle = NULL; esp_lcd_panel_io_handle_t io_handle = NULL; - BSP_ERROR_CHECK_RETURN_ERR(detect_sub_board_type()); + bsp_module_type_t module_type = bsp_probe_module_type(); + if (module_type == MODULE_TYPE_UNKNOW) { + ESP_LOGE(TAG, "Unknow module type"); + return ESP_FAIL; + } + + bsp_sub_board_type_t sub_board_type = bsp_probe_sub_board_type(); + if (sub_board_type == SUB_BOARD_TYPE_UNKNOW) { + ESP_LOGE(TAG, "Unknow sub-board type"); + return ESP_FAIL; + } switch (sub_board_type) { case SUB_BOARD_TYPE_2_480_480: { @@ -102,11 +126,16 @@ esp_err_t bsp_display_new(const bsp_display_config_t *config, esp_lcd_panel_hand .sda_expander_pin = BSP_LCD_SUB_BOARD_2_SPI_SDO, .io_expander = expander, }; +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 1, 2) + esp_lcd_panel_io_3wire_spi_config_t io_config = GC9503_PANEL_IO_3WIRE_SPI_CONFIG( + line_config, SUB_BOARD2_480_480_PANEL_SCL_ACTIVE_EDGE); +#else esp_lcd_panel_io_3wire_spi_config_t io_config = GC9503_PANEL_IO_3WIRE_SPI_CONFIG(line_config); +#endif BSP_ERROR_CHECK_RETURN_ERR(esp_lcd_new_panel_io_3wire_spi(&io_config, &io_handle)); ESP_LOGI(TAG, "Initialize RGB panel"); - esp_lcd_rgb_panel_config_t panel_conf = { + esp_lcd_rgb_panel_config_t rgb_conf = { .clk_src = LCD_CLK_SRC_PLL160M, .psram_trans_align = 64, .data_width = 16, @@ -134,23 +163,45 @@ esp_err_t bsp_display_new(const bsp_display_config_t *config, esp_lcd_panel_hand BSP_LCD_SUB_BOARD_2_3_DATA14, BSP_LCD_SUB_BOARD_2_3_DATA15, }, - .timings = SUB_BOARD2_800_480_PANEL_60HZ_RGB_TIMING(), + .timings = SUB_BOARD2_480_480_PANEL_60HZ_RGB_TIMING(), .flags.fb_in_psram = 1, #if CONFIG_BSP_LCD_RGB_REFRESH_MANUALLY .flags.refresh_on_demand = 1, #endif -#if CONFIG_BSP_LCD_RGB_BUFFER_NUMS == 2 - .flags.double_fb = 1, -#elif CONFIG_BSP_LCD_RGB_BUFFER_NUMS == 3 - .num_fbs = 3, -#endif + .num_fbs = CONFIG_BSP_LCD_RGB_BUFFER_NUMS, #if CONFIG_BSP_LCD_RGB_BOUNCE_BUFFER_MODE .bounce_buffer_size_px = BSP_LCD_SUB_BOARD_2_H_RES * CONFIG_BSP_LCD_RGB_BOUNCE_BUFFER_HEIGHT, #endif }; + // To compatible with ESP32-S3-WROOM-N16R16V module + if (module_type == MODULE_TYPE_R16) { + rgb_conf.data_gpio_nums[6] = BSP_LCD_SUB_BOARD_2_3_DATA6_R16; + rgb_conf.data_gpio_nums[7] = BSP_LCD_SUB_BOARD_2_3_DATA7_R16; + } +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 1, 2) + gc9503_vendor_config_t vendor_config = { + .rgb_config = &rgb_conf, + .flags = { + .mirror_by_cmd = 0, + .auto_del_panel_io = 1, + }, + }; + const esp_lcd_panel_dev_config_t panel_conf = { + .reset_gpio_num = -1, + .rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB, + .bits_per_pixel = 18, + .vendor_config = &vendor_config, + }; BSP_ERROR_CHECK_RETURN_ERR(esp_lcd_new_panel_gc9503(io_handle, &panel_conf, &panel_handle)); +#else + BSP_ERROR_CHECK_RETURN_ERR(esp_lcd_new_panel_gc9503(io_handle, &rgb_conf, &panel_handle)); +#endif esp_lcd_rgb_panel_event_callbacks_t cbs = { +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 1, 2) && CONFIG_BSP_LCD_RGB_BOUNCE_BUFFER_MODE + .on_bounce_frame_finish = rgb_lcd_on_vsync_event, +#else .on_vsync = rgb_lcd_on_vsync_event, +#endif }; esp_lcd_rgb_panel_register_event_callbacks(panel_handle, &cbs, NULL); break; @@ -190,18 +241,23 @@ esp_err_t bsp_display_new(const bsp_display_config_t *config, esp_lcd_panel_hand #if CONFIG_BSP_LCD_RGB_REFRESH_MANUALLY .flags.refresh_on_demand = 1, #endif -#if CONFIG_BSP_LCD_RGB_BUFFER_NUMS == 2 - .flags.double_fb = 1, -#elif CONFIG_BSP_LCD_RGB_BUFFER_NUMS == 3 - .num_fbs = 3, -#endif + .num_fbs = CONFIG_BSP_LCD_RGB_BUFFER_NUMS, #if CONFIG_BSP_LCD_RGB_BOUNCE_BUFFER_MODE .bounce_buffer_size_px = BSP_LCD_SUB_BOARD_3_H_RES * CONFIG_BSP_LCD_RGB_BOUNCE_BUFFER_HEIGHT, #endif }; + // To compatible with ESP32-S3-WROOM-N16R16V module + if (module_type == MODULE_TYPE_R16) { + panel_conf.data_gpio_nums[6] = BSP_LCD_SUB_BOARD_2_3_DATA6_R16; + panel_conf.data_gpio_nums[7] = BSP_LCD_SUB_BOARD_2_3_DATA7_R16; + } BSP_ERROR_CHECK_RETURN_ERR(esp_lcd_new_rgb_panel(&panel_conf, &panel_handle)); esp_lcd_rgb_panel_event_callbacks_t cbs = { +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 1, 2) && CONFIG_BSP_LCD_RGB_BOUNCE_BUFFER_MODE + .on_bounce_frame_finish = rgb_lcd_on_vsync_event, +#else .on_vsync = rgb_lcd_on_vsync_event, +#endif }; esp_lcd_rgb_panel_register_event_callbacks(panel_handle, &cbs, NULL); break; @@ -252,7 +308,11 @@ esp_err_t bsp_touch_new(const bsp_touch_config_t *config, esp_lcd_touch_handle_t esp_lcd_panel_io_handle_t tp_io_handle = NULL; esp_lcd_touch_handle_t tp_handle = NULL; - BSP_ERROR_CHECK_RETURN_ERR(detect_sub_board_type()); + bsp_sub_board_type_t sub_board_type = bsp_probe_sub_board_type(); + if (sub_board_type == SUB_BOARD_TYPE_UNKNOW) { + ESP_LOGE(TAG, "Unknow sub-board type"); + return ESP_FAIL; + } switch (sub_board_type) { case SUB_BOARD_TYPE_2_480_480: { @@ -316,6 +376,12 @@ esp_err_t bsp_touch_new(const bsp_touch_config_t *config, esp_lcd_touch_handle_t **************************************************************************************************/ uint16_t bsp_display_get_h_res(void) { + bsp_sub_board_type_t sub_board_type = bsp_probe_sub_board_type(); + if (sub_board_type == SUB_BOARD_TYPE_UNKNOW) { + ESP_LOGE(TAG, "Unknow sub-board type"); + return ESP_FAIL; + } + switch (sub_board_type) { case SUB_BOARD_TYPE_2_480_480: return BSP_LCD_SUB_BOARD_2_H_RES; @@ -329,6 +395,12 @@ uint16_t bsp_display_get_h_res(void) uint16_t bsp_display_get_v_res(void) { + bsp_sub_board_type_t sub_board_type = bsp_probe_sub_board_type(); + if (sub_board_type == SUB_BOARD_TYPE_UNKNOW) { + ESP_LOGE(TAG, "Unknow sub-board type"); + return ESP_FAIL; + } + switch (sub_board_type) { case SUB_BOARD_TYPE_2_480_480: return BSP_LCD_SUB_BOARD_2_V_RES; @@ -339,55 +411,3 @@ uint16_t bsp_display_get_v_res(void) return 0; } } - -bsp_sub_board_type_t bsp_sub_board_get_type(void) -{ - return sub_board_type; -} - -static esp_err_t detect_sub_board_type(void) -{ - if (sub_board_type != SUB_BOARD_TYPE_UNKNOW) { - return ESP_OK; - } - - BSP_ERROR_CHECK_RETURN_ERR(bsp_i2c_init()); - - uint8_t tp_address[] = { - ESP_LCD_TOUCH_IO_I2C_FT5x06_ADDRESS, - ESP_LCD_TOUCH_IO_I2C_GT1151_ADDRESS, - }; - uint8_t i = 0; - i2c_cmd_handle_t cmd; - bsp_sub_board_type_t detect_type = SUB_BOARD_TYPE_UNKNOW; - while (i < sizeof(tp_address)) { - cmd = i2c_cmd_link_create(); - i2c_master_start(cmd); - i2c_master_write_byte(cmd, (tp_address[i] << 1) | I2C_MASTER_WRITE, true); - i2c_master_stop(cmd); - if (i2c_master_cmd_begin(BSP_I2C_NUM, cmd, pdMS_TO_TICKS(20)) == ESP_OK) { - if (tp_address[i] == ESP_LCD_TOUCH_IO_I2C_FT5x06_ADDRESS) { - ESP_LOGI(TAG, "Detect sub_board2 with 480x480 LCD (GC9503), Touch (FT5x06)"); - detect_type = SUB_BOARD_TYPE_2_480_480; - } else if (tp_address[i] == ESP_LCD_TOUCH_IO_I2C_GT1151_ADDRESS) { - ESP_LOGI(TAG, "Detect sub_board3 with 800x480 LCD (ST7262), Touch (GT1151)"); - detect_type = SUB_BOARD_TYPE_3_800_480; - } - } - i2c_cmd_link_delete(cmd); - if (detect_type != SUB_BOARD_TYPE_UNKNOW) { - break; - } - i++; - } - - ESP_RETURN_ON_FALSE(detect_type != SUB_BOARD_TYPE_UNKNOW, ESP_ERR_INVALID_STATE, TAG, - "Failed to detect sub_board type, please check the hardware connection"); - if (CONFIG_BSP_LCD_SUB_BOARD_TYPE) { - ESP_RETURN_ON_FALSE(detect_type == CONFIG_BSP_LCD_SUB_BOARD_TYPE, ESP_ERR_INVALID_STATE, TAG, - "Sub_board type mismatch, please check the software configuration and hardware connection"); - } - sub_board_type = detect_type; - - return ESP_OK; -} diff --git a/bsp/esp32_s3_lcd_ev_board/src/esp32_s3_lcd_ev_board.c b/bsp/esp32_s3_lcd_ev_board/src/esp32_s3_lcd_ev_board.c index c0312b72..a9569528 100644 --- a/bsp/esp32_s3_lcd_ev_board/src/esp32_s3_lcd_ev_board.c +++ b/bsp/esp32_s3_lcd_ev_board/src/esp32_s3_lcd_ev_board.c @@ -24,6 +24,7 @@ #include "bsp/touch.h" #include "bsp_err_check.h" #include "bsp_lvgl_port.h" +#include "bsp_probe.h" #define BSP_ES7210_CODEC_ADDR (0x82) @@ -79,7 +80,13 @@ esp_err_t bsp_i2c_init(void) return ESP_OK; } - const i2c_config_t i2c_conf = { + bsp_module_type_t module_type = bsp_probe_module_type(); + if (module_type == MODULE_TYPE_UNKNOW) { + ESP_LOGE(TAG, "Unknow module type"); + return ESP_FAIL; + } + + i2c_config_t i2c_conf = { .mode = I2C_MODE_MASTER, .sda_io_num = BSP_I2C_SDA, .sda_pullup_en = GPIO_PULLUP_DISABLE, @@ -87,6 +94,11 @@ esp_err_t bsp_i2c_init(void) .scl_pullup_en = GPIO_PULLUP_DISABLE, .master.clk_speed = CONFIG_BSP_I2C_CLK_SPEED_HZ }; + // To compatible with ESP32-S3-WROOM-N16R16V module + if (module_type == MODULE_TYPE_R16) { + i2c_conf.sda_io_num = BSP_I2C_SDA_R16; + i2c_conf.scl_io_num = BSP_I2C_SCL_R16; + } BSP_ERROR_CHECK_RETURN_ERR(i2c_param_config(BSP_I2C_NUM, &i2c_conf)); BSP_ERROR_CHECK_RETURN_ERR(i2c_driver_install(BSP_I2C_NUM, i2c_conf.mode, 0, 0, 0)); diff --git a/examples/display_lvgl_demos/README.md b/examples/display_lvgl_demos/README.md index df6d0445..c492fc01 100644 --- a/examples/display_lvgl_demos/README.md +++ b/examples/display_lvgl_demos/README.md @@ -2,32 +2,66 @@ This example shows LVGL internal demos with RGB LCD. -### Configurations - -To improve display performance (FPS), please set the following configurations: - -* System: - * `ESP_DEFAULT_CPU_FREQ_MHZ_240` - * `FREERTOS_HZ` = 1000 - * `COMPILER_OPTIMIZATION_PERF` -* Flash: - * `ESPTOOLPY_FLASHMODE_QIO` - * `ESPTOOLPY_FLASHFREQ_120M` -* PSRAM: - * `SPIRAM_MODE_OCT` - * `SPIRAM_SPEED_120M` (See [here](https://github.com/espressif/esp-dev-kits/tree/master/esp32-s3-lcd-ev-board#psram-120m-ddr) to enbale this feature of ESP-IDF) - * `SPIRAM_FETCH_INSTRUCTIONS` - * `SPIRAM_RODATA` -* Cache: - * `ESP32S3_DATA_CACHE_LINE_64B` (It can be enabled only when using bounce buffer or PSRAM with Octal 120M. Otherwise it will cause screen drift.) -* LVGL - * `LV_MEM_CUSTOM` - * `LV_MEMCPY_MEMSET_STD` - * `LV_ATTRIBUTE_FAST_MEM_USE_IRAM` +For common issues about RGB LCD, please refer to [LCD Development Guide](https://docs.espressif.com/projects/esp-iot-solution/en/latest/display/lcd/lcd_development_guide.html#common-problems). + +## How to use the example ### Hardware Required -ESP32-S3-LCD-EV-Board or ESP32-S3-LCD-EV-Board-2 +* ESP32-S3-LCD-EV-Board or ESP32-S3-LCD-EV-Board-2 +* USB-C Cable + +### Compile and flash + +``` +idf.py -p COMx build flash monitor +``` + +### Example outputs + +``` +... +I (0) cpu_start: App cpu up. +I (923) esp_psram: SPI SRAM memory test OK +I (932) cpu_start: Pro cpu start user code +I (932) cpu_start: cpu freq: 240000000 Hz +I (932) cpu_start: Application information: +I (935) cpu_start: Project name: display_lvgl_demos +I (941) cpu_start: App version: squareline-latest-29-geed37e1 +I (948) cpu_start: Compile time: Dec 2 2023 15:41:34 +I (954) cpu_start: ELF file SHA256: fb3ec2c6026f1bb4... +I (960) cpu_start: ESP-IDF: v5.1.2 +I (965) cpu_start: Min chip rev: v0.0 +I (969) cpu_start: Max chip rev: v0.99 +I (974) cpu_start: Chip rev: v0.2 +I (979) heap_init: Initializing. RAM available for dynamic allocation: +I (986) heap_init: At 3FC9BF28 len 0004D7E8 (309 KiB): DRAM +I (992) heap_init: At 3FCE9710 len 00005724 (21 KiB): STACK/DRAM +I (999) heap_init: At 3FCF0000 len 00008000 (32 KiB): DRAM +I (1005) heap_init: At 600FE010 len 00001FD8 (7 KiB): RTCRAM +I (1011) esp_psram: Adding pool of 15552K of PSRAM memory to heap allocator +I (1019) spi_flash: detected chip: gd +I (1023) spi_flash: flash io: qio +W (1027) spi_flash: Detected size(16384k) larger than the size in the binary image header(2048k). Using the size in the binary image header. +I (1041) sleep: Configure to isolate all GPIO pins in sleep state +I (1048) sleep: Enable automatic switching of GPIO sleep configuration +I (1055) app_start: Starting scheduler on CPU0 +I (1060) app_start: Starting scheduler on CPU1 +I (1060) main_task: Started on CPU0 +I (1070) esp_psram: Reserving pool of 32K of internal memory for DMA/internal allocations +I (1078) main_task: Calling app_main() +I (1083) bsp_probe: Detect module with 16MB PSRAM +I (1088) bsp_probe: Detect sub_board3 with 800x480 LCD (ST7262), Touch (GT1151) +I (1096) bsp_sub_board: Initialize RGB panel +I (1134) gt1151: IC version: GT1158_000101(Patch)_0102(Mask)_00(SensorID) +I (1136) bsp_lvgl_port: Create LVGL task +I (1136) bsp_lvgl_port: Starting LVGL task +I (1164) app_main: Avoid lcd tearing effect +I (1165) app_main: LVGL direct-mode +W (1165) S3-LCD-EV-BOARD: This board doesn't support to change brightness of LCD +I (1171) app_main: Display LVGL demo +I (1370) main_task: Returned from app_main() +``` Try it with ESP Launchpad diff --git a/examples/display_lvgl_demos/sdkconfig.bsp.esp32_s3_lcd_ev_board b/examples/display_lvgl_demos/sdkconfig.bsp.esp32_s3_lcd_ev_board index cffda712..91bd0147 100644 --- a/examples/display_lvgl_demos/sdkconfig.bsp.esp32_s3_lcd_ev_board +++ b/examples/display_lvgl_demos/sdkconfig.bsp.esp32_s3_lcd_ev_board @@ -10,7 +10,12 @@ CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y CONFIG_SPIRAM_RODATA=y CONFIG_SPIRAM_SPEED_80M=y CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y +CONFIG_ESP32S3_DATA_CACHE_LINE_64B=y CONFIG_FREERTOS_HZ=1000 +CONFIG_BSP_LCD_RGB_BUFFER_NUMS=2 +CONFIG_BSP_LCD_RGB_BOUNCE_BUFFER_MODE=y +CONFIG_BSP_DISPLAY_LVGL_AVOID_TEAR=y +CONFIG_BSP_DISPLAY_LVGL_DIRECT_MODE=y CONFIG_LV_MEM_CUSTOM=y CONFIG_LV_MEMCPY_MEMSET_STD=y CONFIG_LV_USE_PERF_MONITOR=y diff --git a/examples/display_lvgl_demos/sdkconfig.defaults b/examples/display_lvgl_demos/sdkconfig.defaults index cffda712..91bd0147 100644 --- a/examples/display_lvgl_demos/sdkconfig.defaults +++ b/examples/display_lvgl_demos/sdkconfig.defaults @@ -10,7 +10,12 @@ CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y CONFIG_SPIRAM_RODATA=y CONFIG_SPIRAM_SPEED_80M=y CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y +CONFIG_ESP32S3_DATA_CACHE_LINE_64B=y CONFIG_FREERTOS_HZ=1000 +CONFIG_BSP_LCD_RGB_BUFFER_NUMS=2 +CONFIG_BSP_LCD_RGB_BOUNCE_BUFFER_MODE=y +CONFIG_BSP_DISPLAY_LVGL_AVOID_TEAR=y +CONFIG_BSP_DISPLAY_LVGL_DIRECT_MODE=y CONFIG_LV_MEM_CUSTOM=y CONFIG_LV_MEMCPY_MEMSET_STD=y CONFIG_LV_USE_PERF_MONITOR=y