diff --git a/.build-rules.yml b/.build-rules.yml index bee2b420..065f5662 100644 --- a/.build-rules.yml +++ b/.build-rules.yml @@ -15,6 +15,10 @@ test_apps/lcd/qspi: disable: - if: SOC_GPSPI_SUPPORTED != 1 +test_apps/lcd/mipi_dsi: + disable: + - if: SOC_MIPI_DSI_SUPPORTED != 1 + test_apps/lcd/rgb: disable: - if: SOC_LCD_RGB_SUPPORTED != 1 diff --git a/.gitlab/ci/build.yml b/.gitlab/ci/build.yml index a429ab4f..00a6c606 100644 --- a/.gitlab/ci/build.yml +++ b/.gitlab/ci/build.yml @@ -49,6 +49,13 @@ - IMAGE: espressif/idf:release-v5.1 - IMAGE: espressif/idf:release-v5.2 - IMAGE: espressif/idf:release-v5.3 + - IMAGE: espressif/idf:release-v5.4 + +.build_esp32_p4_idf_release_version: + parallel: + matrix: + - IMAGE: espressif/idf:release-v5.3 + - IMAGE: espressif/idf:release-v5.4 # Test apps build_test_apps_lcd_3wire_spi_rgb: @@ -59,6 +66,14 @@ build_test_apps_lcd_3wire_spi_rgb: variables: EXAMPLE_DIR: test_apps/lcd/3wire_spi_rgb +build_test_apps_lcd_mipi_dsi: + extends: + - .build_examples_template + - .build_esp32_p4_idf_release_version + - .rules:build:test_apps_lcd_mipi_dsi + variables: + EXAMPLE_DIR: test_apps/lcd/mipi_dsi + build_test_apps_lcd_qspi: extends: - .build_examples_template diff --git a/.gitlab/ci/rules.yml b/.gitlab/ci/rules.yml index 50720242..7a558e75 100644 --- a/.gitlab/ci/rules.yml +++ b/.gitlab/ci/rules.yml @@ -26,6 +26,9 @@ .patterns-test_apps_lcd_3wire_spi_rgb: &patterns-test_apps_lcd_3wire_spi_rgb - "test_apps/lcd/3wire_spi_rgb/**/*" +.patterns-test_apps_lcd_mipi_dsi: &patterns-test_apps_lcd_mipi_dsi + - "test_apps/lcd/mipi_dsi/**/*" + .patterns-test_apps_lcd_qspi: &patterns-test_apps_lcd_qspi - "test_apps/lcd/qspi/**/*" @@ -103,6 +106,19 @@ - <<: *if-dev-push changes: *patterns-test_apps_lcd_3wire_spi_rgb +.rules:build:test_apps_lcd_mipi_dsi: + rules: + - <<: *if-protected + - <<: *if-label-build + - <<: *if-label-target_test + - <<: *if-trigger-job + - <<: *if-dev-push + changes: *patterns-build_system + - <<: *if-dev-push + changes: *patterns-component + - <<: *if-dev-push + changes: *patterns-test_apps_lcd_mipi_dsi + .rules:build:test_apps_lcd_qspi: rules: - <<: *if-protected diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f93459f..e404f1ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,21 +1,36 @@ # ChangeLog -## v0.1.9 - 2024-10-29 +## v0.2.0 - 2024-11-08 -* feat(board): add support for Waveshare ESP32-S3-Touch-LCD-2.1 +### Enhancements: -## v0.1.8 - 2024-10-25 +* feat(repo): support build on the esp-idf +* feat(bus & lcd): support MIPI-DSI LCD +* feat(lcd): add LCD controller EK79007 +* feat(lcd): add LCD controller ILI9881C +* feat(panel): add support for MIPI-DSI LCD +* feat(board): add support for Waveshare ESP32-S3-Touch-LCD-2.1 @martinroger (#117) +* feat(board): add support for Espressif ESP32-P4-Function-EV-Board +* feat(examples): add MIPI-DSI LCD +* feat(examples): optimize anti-tear rotation in lvgl_port_v8 +* feat(ci): update for MIPI-DSI LCD +* feat(test_apps): add MIPI-DSI LCD -* feat(board): add support for Waveshare ESP32-S3-Touch-LCD-1.85 +### Bugfixes: -### Enhancements: +* fix(touch): release ISR semaphore when delete -## v0.1.7 - 2024-08-22 +## v0.1.8 - 2024-10-25 ### Enhancements: +* feat(board): add support for Waveshare ESP32-S3-Touch-LCD-1.85 @martinroger (#115) * feat(docs): add additional information about screen drift issue +### Bugfixes: + +* fix(examples): correct readme broken links + ## v0.1.6 - 2024-07-30 ### Enhancements: diff --git a/ESP_Panel_Board_Custom.h b/ESP_Panel_Board_Custom.h index 3ae31b50..dfd5e727 100644 --- a/ESP_Panel_Board_Custom.h +++ b/ESP_Panel_Board_Custom.h @@ -110,8 +110,6 @@ // |--------------|---------------| #define ESP_PANEL_LCD_RGB_DATA_WIDTH (16) // | 8 | 16 | #define ESP_PANEL_LCD_RGB_PIXEL_BITS (16) // | 24 | 16 | - - #define ESP_PANEL_LCD_RGB_FRAME_BUF_NUM (1) // 1/2/3 #define ESP_PANEL_LCD_RGB_BOUNCE_BUF_SIZE (0) // Bounce buffer size in bytes. This function is used to avoid screen drift. // To enable the bounce buffer, set it to a non-zero value. Typically set to `ESP_PANEL_LCD_WIDTH * 10` // The size of the Bounce Buffer must satisfy `width_of_lcd * height_of_lcd = size_of_buffer * N`, @@ -121,7 +119,6 @@ #define ESP_PANEL_LCD_RGB_IO_DE (17) // -1 if not used #define ESP_PANEL_LCD_RGB_IO_PCLK (9) #define ESP_PANEL_LCD_RGB_IO_DISP (-1) // -1 if not used - // | RGB565 | RGB666 | RGB888 | // |--------|--------|--------| #define ESP_PANEL_LCD_RGB_IO_DATA0 (10) // | B0 | B0-1 | B0-3 | @@ -158,6 +155,22 @@ // The `mirror()` function will be implemented by LCD command if set to 1. #endif +#elif ESP_PANEL_LCD_BUS_TYPE == ESP_PANEL_BUS_TYPE_MIPI_DSI + + #define ESP_PANEL_LCD_MIPI_DSI_LANE_NUM (2) // ESP32-P4 supports 1 or 2 lanes + #define ESP_PANEL_LCD_MIPI_DSI_LANE_RATE_MBPS (1000) // Single lane bit rate, should consult the LCD supplier or check the + // LCD drive IC datasheet for the supported lane rate. + // ESP32-P4 supports max 1500Mbps + #define ESP_PANEL_LCD_MIPI_DSI_PHY_LDO_ID (3) // -1 if not used + #define ESP_PANEL_LCD_MIPI_DPI_CLK_MHZ (52) + #define ESP_PANEL_LCD_MIPI_DPI_PIXEL_BITS (ESP_PANEL_LCD_RGB565_COLOR_BITS_16) + #define ESP_PANEL_LCD_MIPI_DSI_HPW (10) + #define ESP_PANEL_LCD_MIPI_DSI_HBP (160) + #define ESP_PANEL_LCD_MIPI_DSI_HFP (160) + #define ESP_PANEL_LCD_MIPI_DSI_VPW (1) + #define ESP_PANEL_LCD_MIPI_DSI_VBP (23) + #define ESP_PANEL_LCD_MIPI_DSI_VFP (12) + #else #error "The function is not ready and will be implemented in the future." @@ -380,8 +393,8 @@ * */ #define ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_MAJOR 0 -#define ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_MINOR 2 -#define ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_PATCH 3 +#define ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_MINOR 3 +#define ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_PATCH 0 #endif /* ESP_PANEL_USE_CUSTOM_BOARD */ diff --git a/ESP_Panel_Board_Supported.h b/ESP_Panel_Board_Supported.h index 603e59bd..75d5c84a 100644 --- a/ESP_Panel_Board_Supported.h +++ b/ESP_Panel_Board_Supported.h @@ -31,6 +31,7 @@ * - BOARD_ESP32_S3_LCD_EV_BOARD_2 (ESP32-S3-LCD-EV-Board-2(v1.1-v1.4))): https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32s3/esp32-s3-lcd-ev-board/user_guide_v1.4.html * - BOARD_ESP32_S3_LCD_EV_BOARD_2_V1_5 (ESP32-S3-LCD-EV-Board-2(v1.5)): https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32s3/esp32-s3-lcd-ev-board/user_guide.html * - BOARD_ESP32_S3_USB_OTG (ESP32-S3-USB-OTG): https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32s3/esp32-s3-usb-otg/index.html + * - BOARD_ESP32_P4_FUNCTION_EV_BOARD (ESP32-P4-Function-EV-Board): https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32p4/esp32-p4-function-ev-board/index.html * */ // #define BOARD_ESP32_C3_LCDKIT @@ -45,6 +46,7 @@ // #define BOARD_ESP32_S3_LCD_EV_BOARD_2 // #define BOARD_ESP32_S3_LCD_EV_BOARD_2_V1_5 // #define BOARD_ESP32_S3_USB_OTG +// #define BOARD_ESP32_P4_FUNCTION_EV_BOARD /* * Elecrow (https://www.elecrow.com): @@ -101,7 +103,7 @@ * */ #define ESP_PANEL_BOARD_SUPPORTED_FILE_VERSION_MAJOR 0 -#define ESP_PANEL_BOARD_SUPPORTED_FILE_VERSION_MINOR 5 -#define ESP_PANEL_BOARD_SUPPORTED_FILE_VERSION_PATCH 1 +#define ESP_PANEL_BOARD_SUPPORTED_FILE_VERSION_MINOR 6 +#define ESP_PANEL_BOARD_SUPPORTED_FILE_VERSION_PATCH 0 #endif diff --git a/README.md b/README.md index 6cce25a8..51f7addd 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ Below is the list of [supported development boards](docs/Board_Instructions.md): | **Manufacturer** | **Board Model** | | ---------------- | --------------- | -| [Espressif](docs/Board_Instructions.md#espressif) | ESP32-C3-LCDkit, ESP32-S3-BOX, ESP32-S3-BOX-3, ESP32-S3-BOX-3B, ESP32-S3-BOX-3(beta), ESP32-S3-BOX-Lite, ESP32-S3-EYE, ESP32-S3-Korvo-2, ESP32-S3-LCD-EV-Board, ESP32-S3-LCD-EV-Board-2, ESP32-S3-USB-OTG | +| [Espressif](docs/Board_Instructions.md#espressif) | ESP32-C3-LCDkit, ESP32-S3-BOX, ESP32-S3-BOX-3, ESP32-S3-BOX-3B, ESP32-S3-BOX-3(beta), ESP32-S3-BOX-Lite, ESP32-S3-EYE, ESP32-S3-Korvo-2, ESP32-S3-LCD-EV-Board, ESP32-S3-LCD-EV-Board-2, ESP32-S3-USB-OTG, ESP32-P4-Function-EV-Board | | [Elecrow](docs/Board_Instructions.md#elecrow) | CrowPanel 7.0" | | [M5Stack](docs/Board_Instructions.md#m5stack) | M5STACK-M5CORE2, M5STACK-M5DIAL, M5STACK-M5CORES3 | | [Jingcai](docs/Board_Instructions.md#shenzhen-jingcai-intelligent) | ESP32-4848S040C_I_Y_3 | diff --git a/README_CN.md b/README_CN.md index 7e2a6e02..9cfd4395 100644 --- a/README_CN.md +++ b/README_CN.md @@ -36,7 +36,7 @@ ESP32_Display_Panel 的功能框图如下所示,主要包含以下特性: | **厂商** | **开发板型号** | | -------- | -------------- | -| [Espressif](docs/Board_Instructions.md#espressif) | ESP32-C3-LCDkit, ESP32-S3-BOX, ESP32-S3-BOX-3, ESP32-S3-BOX-3B, ESP32-S3-BOX-3(beta), ESP32-S3-BOX-Lite, ESP32-S3-EYE, ESP32-S3-Korvo-2, ESP32-S3-LCD-EV-Board, ESP32-S3-LCD-EV-Board-2, ESP32-S3-USB-OTG | +| [Espressif](docs/Board_Instructions.md#espressif) | ESP32-C3-LCDkit, ESP32-S3-BOX, ESP32-S3-BOX-3, ESP32-S3-BOX-3B, ESP32-S3-BOX-3(beta), ESP32-S3-BOX-Lite, ESP32-S3-EYE, ESP32-S3-Korvo-2, ESP32-S3-LCD-EV-Board, ESP32-S3-LCD-EV-Board-2, ESP32-S3-USB-OTG, ESP32-P4-Function-EV-Board | | [M5Stack](docs/Board_Instructions.md#m5stack) | M5STACK-M5CORE2, M5STACK-M5DIAL, M5STACK-M5CORES3 | | [Elecrow](docs/Board_Instructions.md#elecrow) | CrowPanel 7.0" | | [Jingcai](docs/Board_Instructions.md#shenzhen-jingcai-intelligent) | ESP32-4848S040C_I_Y_3 | diff --git a/docs/Board_Contribution_Guide.md b/docs/Board_Contribution_Guide.md index fdbe11bc..4334662c 100644 --- a/docs/Board_Contribution_Guide.md +++ b/docs/Board_Contribution_Guide.md @@ -1,5 +1,15 @@ # Board Contribution Guide +* [中文版本](./Board_Contribution_Guide_CN.md) + +## Table of Contents + +- [Board Contribution Guide](#board-contribution-guide) + - [Table of Contents](#table-of-contents) + - [Contribution Guidelines](#contribution-guidelines) + - [File Modifications](#file-modifications) + - [Adaptation Process](#adaptation-process) + ## Contribution Guidelines 1. The development board must at least ensure its hardware schematic is open-source, providing a link or file for reference. diff --git a/docs/Board_Contribution_Guide_CN.md b/docs/Board_Contribution_Guide_CN.md index 06941c74..5aaade42 100644 --- a/docs/Board_Contribution_Guide_CN.md +++ b/docs/Board_Contribution_Guide_CN.md @@ -1,5 +1,15 @@ # 开发板贡献指南 +* [English Version](./Board_Contribution_Guide.md) + +## 目录 + +- [开发板贡献指南](#开发板贡献指南) + - [目录](#目录) + - [贡献说明](#贡献说明) + - [文件修改](#文件修改) + - [适配流程](#适配流程) + ## 贡献说明 1. 开发板至少需要确保其硬件原理图开源,并提供链接或文件。 diff --git a/docs/Board_Instructions.md b/docs/Board_Instructions.md index 46014230..7650cb87 100644 --- a/docs/Board_Instructions.md +++ b/docs/Board_Instructions.md @@ -16,6 +16,7 @@ | | [ESP32-S3-LCD-EV-Board](https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32s3/esp32-s3-lcd-ev-board/index.html) | 3-wire SPI + RGB | GC9503 | 480x480 | I2C | FT5x06 | | | [ESP32-S3-LCD-EV-Board-2](https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32s3/esp32-s3-lcd-ev-board/index.html) | RGB | ST7262E43 | 800x480 | I2C | GT1151 | | | [ESP32-S3-USB-OTG](https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32s3/esp32-s3-usb-otg/index.html) | SPI | ST7789 | 240x240 | - | - | +| | [ESP32-P4-Function-EV-Board](https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32p4/esp32-p4-function-ev-board/index.html) | MIPI-DSI | EK79007 | 1024x600 | I2C | GT911 | ### [Elecrow](https://www.elecrow.com/) @@ -62,6 +63,7 @@ Below are recommended configurations for developing GUI applications on differen | ESP32-S3-LCD-EV-Board | ESP32S3 Dev Module | OPI | QIO 80MHz | 16MB | **See Note 1** | 16M Flash (3MB) | | ESP32-S3-LCD-EV-Board-2 | ESP32S3 Dev Module | OPI | QIO 80MHz | 16MB | **See Note 1** | 16M Flash (3MB) | | ESP32-S3-USB-OTG | ESP32-S3-USB-OTG | - | - | - | - | 8M with spiffs | +| ESP32-P4-Function-EV-Board | ESP32P4 Dev Module | Enabled | QIO | 16MB | Disabled | 16M Flash (3MB) | | M5STACK-M5CORE2 | M5Stack-Core2 | Enabled | - | - | - | Default | | M5STACK-M5DIAL | ESP32S3 Dev Module | OPI | QIO 80MHz | 8MB | Disabled | Default | | M5STACK-M5CORES3 | ESP32S3 Dev Module | OPI | QIO 80MHz | 16MB | Enabled | Default 4MB with spiffs | diff --git a/docs/FAQ.md b/docs/FAQ.md index 5c6d2f53..726f8507 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -1,5 +1,17 @@ # FAQ +* [中文版本](./FAQ_CN.md) + +## Table of Contents + +- [FAQ](#faq) + - [Table of Contents](#table-of-contents) + - [Where is the directory for Arduino libraries?](#where-is-the-directory-for-arduino-libraries) + - [How to Install ESP32\_Display\_Panel in Arduino IDE?](#how-to-install-esp32_display_panel-in-arduino-ide) + - [Where are the installation directory for arduino-esp32 and the SDK located?](#where-are-the-installation-directory-for-arduino-esp32-and-the-sdk-located) + - [How to fix screen drift issue when driving RGB LCD with ESP32-S3?](#how-to-fix-screen-drift-issue-when-driving-rgb-lcd-with-esp32-s3) + - [How to Use ESP32\_Display\_Panel on PlatformIO?](#how-to-use-esp32_display_panel-on-platformio) + ## Where is the directory for Arduino libraries? You can find and modify the directory path for Arduino libraries by selecting `File` > `Preferences` > `Settings` > `Sketchbook location` from the menu bar in the Arduino IDE. diff --git a/docs/FAQ_CN.md b/docs/FAQ_CN.md index cd2d5174..d0070f13 100644 --- a/docs/FAQ_CN.md +++ b/docs/FAQ_CN.md @@ -1,5 +1,17 @@ # 常见问题解答 +* [English Version](./FAQ.md) + +## 目录 + +- [常见问题解答](#常见问题解答) + - [目录](#目录) + - [Arduino 库的目录在哪儿?](#arduino-库的目录在哪儿) + - [如何在 Arduino IDE 中安装 ESP32\_Display\_Panel?](#如何在-arduino-ide-中安装-esp32_display_panel) + - [arduino-eps32 的安装目录以及 SDK 的目录在哪儿?](#arduino-eps32-的安装目录以及-sdk-的目录在哪儿) + - [使用 ESP32-S3 驱动 RGB LCD 时出现画面漂移问题的解决方案](#使用-esp32-s3-驱动-rgb-lcd-时出现画面漂移问题的解决方案) + - [如何在 PlatformIO 上使用 ESP32\_Display\_Panel?](#如何在-platformio-上使用-esp32_display_panel) + ## Arduino 库的目录在哪儿? 您可以在 Arduino IDE 的菜单栏中选择 `File` > `Preferences` > `Settings` > `Sketchbook location` 来查找和修改 Arduino 库的目录路径。 diff --git a/docs/_static/block_diagram.drawio b/docs/_static/block_diagram.drawio index 5bec07dd..e40ed152 100644 --- a/docs/_static/block_diagram.drawio +++ b/docs/_static/block_diagram.drawio @@ -1,112 +1,112 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/_static/block_diagram.png b/docs/_static/block_diagram.png index 845df05e..ee265909 100644 Binary files a/docs/_static/block_diagram.png and b/docs/_static/block_diagram.png differ diff --git a/examples/LCD/3wireSPI_RGB/3wireSPI_RGB.ino b/examples/LCD/3wireSPI_RGB/3wireSPI_RGB.ino index b8b4a8cf..61bd4c0e 100644 --- a/examples/LCD/3wireSPI_RGB/3wireSPI_RGB.ino +++ b/examples/LCD/3wireSPI_RGB/3wireSPI_RGB.ino @@ -11,9 +11,9 @@ * * ## How to use * - * 1. [Configure drivers](https://github.com/esp-arduino-libs/ESP32_Display_Panel/docs/How_To_Use.md#configuring-drivers) if needed. + * 1. [Configure drivers](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/How_To_Use.md#configuring-drivers) if needed. * 2. Modify the macros in the example to match the parameters according to your hardware. - * 3. Navigate to the `Tools` menu in the Arduino IDE to choose a ESP board and configure its parameters, please refter to [Configuring Supported Development Boards](https://github.com/esp-arduino-libs/ESP32_Display_Panel/docs/How_To_Use.md#configuring-supported-development-boards) + * 3. Navigate to the `Tools` menu in the Arduino IDE to choose a ESP board and configure its parameters, please refter to [Configuring Supported Development Boards](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/How_To_Use.md#configuring-supported-development-boards) * 4. Verify and upload the example to your ESP board. * * ## Serial Output @@ -36,13 +36,14 @@ * * ## Troubleshooting * - * Please check the [FAQ](https://github.com/esp-arduino-libs/ESP32_Display_Panel/docs/faq.md) first to see if the same question exists. If not, please create a [Github issue](https://github.com/esp-arduino-libs/ESP32_Display_Panel/issues). We will get back to you as soon as possible. + * Please check the [FAQ](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/FAQ.md) first to see if the same question exists. If not, please create a [Github issue](https://github.com/esp-arduino-libs/ESP32_Display_Panel/issues). We will get back to you as soon as possible. * */ #include #include +/* The following default configurations are for the board 'jingcai: ESP32_4848S040C_I_Y_3, ST7701' */ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// Please update the following configuration according to your LCD spec ////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -64,7 +65,8 @@ #define EXAMPLE_LCD_RGB_TIMING_VPW (10) #define EXAMPLE_LCD_RGB_TIMING_VBP (10) #define EXAMPLE_LCD_RGB_TIMING_VFP (10) -#define EXAMPLE_LCD_USE_EXTERNAL_CMD (0) +#define EXAMPLE_LCD_RGB_BOUNCE_BUFFER_SIZE (EXAMPLE_LCD_WIDTH * 10) +#define EXAMPLE_LCD_USE_EXTERNAL_CMD (1) #if EXAMPLE_LCD_USE_EXTERNAL_CMD /** * LCD initialization commands. @@ -86,10 +88,44 @@ const esp_lcd_panel_vendor_init_cmd_t lcd_init_cmd[] = { // {0xC1, (uint8_t []){0x0D, 0x02}, 2, 0}, // {0x29, (uint8_t []){0x00}, 0, 120}, // // or - // ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xFF, {0x77, 0x01, 0x00, 0x00, 0x10}), - // ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xC0, {0x3B, 0x00}), - // ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xC1, {0x0D, 0x02}), - // ESP_PANEL_LCD_CMD_WITH_NONE_PARAM(120, 0x29), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xFF, {0x77, 0x01, 0x00, 0x00, 0x10}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xC0, {0x3B, 0x00}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xC1, {0x0D, 0x02}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xC2, {0x31, 0x05}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xCD, {0x00}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xB0, {0x00, 0x11, 0x18, 0x0E, 0x11, 0x06, 0x07, 0x08, 0x07, 0x22, 0x04, 0x12, + 0x0F, 0xAA, 0x31, 0x18}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xB1, {0x00, 0x11, 0x19, 0x0E, 0x12, 0x07, 0x08, 0x08, 0x08, 0x22, 0x04, 0x11, + 0x11, 0xA9, 0x32, 0x18}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xFF, {0x77, 0x01, 0x00, 0x00, 0x11}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xB0, {0x60}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xB1, {0x32}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xB2, {0x07}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xB3, {0x80}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xB5, {0x49}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xB7, {0x85}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xB8, {0x21}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xC1, {0x78}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xC2, {0x78}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xE0, {0x00, 0x1B, 0x02}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xE1, {0x08, 0xA0, 0x00, 0x00, 0x07, 0xA0, 0x00, 0x00, 0x00, 0x44, 0x44}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xE2, {0x11, 0x11, 0x44, 0x44, 0xED, 0xA0, 0x00, 0x00, 0xEC, 0xA0, 0x00, 0x00}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xE3, {0x00, 0x00, 0x11, 0x11}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xE4, {0x44, 0x44}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xE5, {0x0A, 0xE9, 0xD8, 0xA0, 0x0C, 0xEB, 0xD8, 0xA0, 0x0E, 0xED, 0xD8, 0xA0, + 0x10, 0xEF, 0xD8, 0xA0}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xE6, {0x00, 0x00, 0x11, 0x11}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xE7, {0x44, 0x44}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xE8, {0x09, 0xE8, 0xD8, 0xA0, 0x0B, 0xEA, 0xD8, 0xA0, 0x0D, 0xEC, 0xD8, 0xA0, + 0x0F, 0xEE, 0xD8, 0xA0}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xEB, {0x02, 0x00, 0xE4, 0xE4, 0x88, 0x00, 0x40}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xEC, {0x3C, 0x00}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xED, {0xAB, 0x89, 0x76, 0x54, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x20, + 0x45, 0x67, 0x98, 0xBA}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xFF, {0x77, 0x01, 0x00, 0x00, 0x13}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xE5, {0xE4}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xFF, {0x77, 0x01, 0x00, 0x00, 0x00}), + ESP_PANEL_LCD_CMD_WITH_NONE_PARAM(120, 0x11), }; #endif @@ -169,43 +205,43 @@ void setup() #if EXAMPLE_LCD_PIN_NUM_BK_LIGHT >= 0 Serial.println("Initialize backlight and turn it off"); - ESP_PanelBacklight *backlight = new ESP_PanelBacklight(EXAMPLE_LCD_PIN_NUM_BK_LIGHT, EXAMPLE_LCD_BK_LIGHT_ON_LEVEL, true); + ESP_PanelBacklight *backlight = new ESP_PanelBacklight( + EXAMPLE_LCD_PIN_NUM_BK_LIGHT, EXAMPLE_LCD_BK_LIGHT_ON_LEVEL, true + ); backlight->begin(); backlight->off(); #endif Serial.println("Create 3-wire SPI + RGB LCD bus"); #if EXAMPLE_LCD_RGB_DATA_WIDTH == 8 - ESP_PanelBus_RGB *lcd_bus = new ESP_PanelBus_RGB(EXAMPLE_LCD_WIDTH, EXAMPLE_LCD_HEIGHT, - EXAMPLE_LCD_PIN_NUM_SPI_CS, EXAMPLE_LCD_PIN_NUM_SPI_SCK, - EXAMPLE_LCD_PIN_NUM_SPI_SDA, - EXAMPLE_LCD_PIN_NUM_RGB_DATA0, EXAMPLE_LCD_PIN_NUM_RGB_DATA1, - EXAMPLE_LCD_PIN_NUM_RGB_DATA2, EXAMPLE_LCD_PIN_NUM_RGB_DATA3, - EXAMPLE_LCD_PIN_NUM_RGB_DATA4, EXAMPLE_LCD_PIN_NUM_RGB_DATA5, - EXAMPLE_LCD_PIN_NUM_RGB_DATA6, EXAMPLE_LCD_PIN_NUM_RGB_DATA7, - EXAMPLE_LCD_PIN_NUM_RGB_HSYNC, EXAMPLE_LCD_PIN_NUM_RGB_VSYNC, - EXAMPLE_LCD_PIN_NUM_RGB_PCLK, EXAMPLE_LCD_PIN_NUM_RGB_DE, - EXAMPLE_LCD_PIN_NUM_RGB_DISP); + ESP_PanelBus_RGB *lcd_bus = new ESP_PanelBus_RGB( + EXAMPLE_LCD_WIDTH, EXAMPLE_LCD_HEIGHT, + EXAMPLE_LCD_PIN_NUM_SPI_CS, EXAMPLE_LCD_PIN_NUM_SPI_SCK, EXAMPLE_LCD_PIN_NUM_SPI_SDA, + EXAMPLE_LCD_PIN_NUM_RGB_DATA0, EXAMPLE_LCD_PIN_NUM_RGB_DATA1, EXAMPLE_LCD_PIN_NUM_RGB_DATA2, + EXAMPLE_LCD_PIN_NUM_RGB_DATA3, EXAMPLE_LCD_PIN_NUM_RGB_DATA4, EXAMPLE_LCD_PIN_NUM_RGB_DATA5, + EXAMPLE_LCD_PIN_NUM_RGB_DATA6, EXAMPLE_LCD_PIN_NUM_RGB_DATA7, EXAMPLE_LCD_PIN_NUM_RGB_HSYNC, + EXAMPLE_LCD_PIN_NUM_RGB_VSYNC, EXAMPLE_LCD_PIN_NUM_RGB_PCLK, EXAMPLE_LCD_PIN_NUM_RGB_DE, + EXAMPLE_LCD_PIN_NUM_RGB_DISP + ); #elif EXAMPLE_LCD_RGB_DATA_WIDTH == 16 - ESP_PanelBus_RGB *lcd_bus = new ESP_PanelBus_RGB(EXAMPLE_LCD_WIDTH, EXAMPLE_LCD_HEIGHT, - EXAMPLE_LCD_PIN_NUM_SPI_CS, EXAMPLE_LCD_PIN_NUM_SPI_SCK, - EXAMPLE_LCD_PIN_NUM_SPI_SDA, - EXAMPLE_LCD_PIN_NUM_RGB_DATA0, EXAMPLE_LCD_PIN_NUM_RGB_DATA1, - EXAMPLE_LCD_PIN_NUM_RGB_DATA2, EXAMPLE_LCD_PIN_NUM_RGB_DATA3, - EXAMPLE_LCD_PIN_NUM_RGB_DATA4, EXAMPLE_LCD_PIN_NUM_RGB_DATA5, - EXAMPLE_LCD_PIN_NUM_RGB_DATA6, EXAMPLE_LCD_PIN_NUM_RGB_DATA7, - EXAMPLE_LCD_PIN_NUM_RGB_DATA8, EXAMPLE_LCD_PIN_NUM_RGB_DATA9, - EXAMPLE_LCD_PIN_NUM_RGB_DATA10, EXAMPLE_LCD_PIN_NUM_RGB_DATA11, - EXAMPLE_LCD_PIN_NUM_RGB_DATA12, EXAMPLE_LCD_PIN_NUM_RGB_DATA13, - EXAMPLE_LCD_PIN_NUM_RGB_DATA14, EXAMPLE_LCD_PIN_NUM_RGB_DATA15, - EXAMPLE_LCD_PIN_NUM_RGB_HSYNC, EXAMPLE_LCD_PIN_NUM_RGB_VSYNC, - EXAMPLE_LCD_PIN_NUM_RGB_PCLK, EXAMPLE_LCD_PIN_NUM_RGB_DE, - EXAMPLE_LCD_PIN_NUM_RGB_DISP); + ESP_PanelBus_RGB *lcd_bus = new ESP_PanelBus_RGB( + EXAMPLE_LCD_WIDTH, EXAMPLE_LCD_HEIGHT, + EXAMPLE_LCD_PIN_NUM_SPI_CS, EXAMPLE_LCD_PIN_NUM_SPI_SCK, EXAMPLE_LCD_PIN_NUM_SPI_SDA, + EXAMPLE_LCD_PIN_NUM_RGB_DATA0, EXAMPLE_LCD_PIN_NUM_RGB_DATA1, EXAMPLE_LCD_PIN_NUM_RGB_DATA2, + EXAMPLE_LCD_PIN_NUM_RGB_DATA3, EXAMPLE_LCD_PIN_NUM_RGB_DATA4, EXAMPLE_LCD_PIN_NUM_RGB_DATA5, + EXAMPLE_LCD_PIN_NUM_RGB_DATA6, EXAMPLE_LCD_PIN_NUM_RGB_DATA7, EXAMPLE_LCD_PIN_NUM_RGB_DATA8, + EXAMPLE_LCD_PIN_NUM_RGB_DATA9, EXAMPLE_LCD_PIN_NUM_RGB_DATA10, EXAMPLE_LCD_PIN_NUM_RGB_DATA11, + EXAMPLE_LCD_PIN_NUM_RGB_DATA12, EXAMPLE_LCD_PIN_NUM_RGB_DATA13, EXAMPLE_LCD_PIN_NUM_RGB_DATA14, + EXAMPLE_LCD_PIN_NUM_RGB_DATA15, EXAMPLE_LCD_PIN_NUM_RGB_HSYNC, EXAMPLE_LCD_PIN_NUM_RGB_VSYNC, + EXAMPLE_LCD_PIN_NUM_RGB_PCLK, EXAMPLE_LCD_PIN_NUM_RGB_DE, EXAMPLE_LCD_PIN_NUM_RGB_DISP + ); #endif lcd_bus->configRgbTimingFreqHz(EXAMPLE_LCD_RGB_TIMING_FREQ_HZ); - lcd_bus->configRgbTimingPorch(EXAMPLE_LCD_RGB_TIMING_HPW, EXAMPLE_LCD_RGB_TIMING_HBP, EXAMPLE_LCD_RGB_TIMING_HFP, - EXAMPLE_LCD_RGB_TIMING_VPW, EXAMPLE_LCD_RGB_TIMING_VBP, EXAMPLE_LCD_RGB_TIMING_VFP); - // lcd_bus->configRgbBounceBufferSize(EXAMPLE_LCD_WIDTH * 10); // Set bounce buffer to avoid screen drift + lcd_bus->configRgbTimingPorch( + EXAMPLE_LCD_RGB_TIMING_HPW, EXAMPLE_LCD_RGB_TIMING_HBP, EXAMPLE_LCD_RGB_TIMING_HFP, + EXAMPLE_LCD_RGB_TIMING_VPW, EXAMPLE_LCD_RGB_TIMING_VBP, EXAMPLE_LCD_RGB_TIMING_VFP + ); + lcd_bus->configRgbBounceBufferSize(EXAMPLE_LCD_RGB_BOUNCE_BUFFER_SIZE); // Set bounce buffer to avoid screen drift lcd_bus->begin(); Serial.println("Create LCD device"); @@ -214,23 +250,23 @@ void setup() // Configure external initialization commands, should called before `init()` lcd->configVendorCommands(lcd_init_cmd, sizeof(lcd_init_cmd)/sizeof(lcd_init_cmd[0])); #endif - // lcd->configAutoReleaseBus(true); // If the "3-wire SPI" interface are sharing pins of the "RGB" interface to - // save GPIOs, please enable this function to release the bus object and pins - // (except CS signal). And then, the "3-wire SPI" interface cannot be used to - // transmit commands any more. - // lcd->configMirrorByCommand(true); // This function is conflict with `configAutoReleaseBus(true)`, please don't - // enable them at the same time + // lcd->configEnableIO_Multiplex(true); // If the "3-wire SPI" interface are sharing pins of the "RGB" interface to + // save GPIOs, please enable this function to release the bus object and pins + // (except CS signal). And then, the "3-wire SPI" interface cannot be used to + // transmit commands any more. + // lcd->configMirrorByCommand(true); // This function is conflict with `configAutoReleaseBus(true)`, please don't + // enable them at the same time lcd->init(); - lcd->reset(); // If the `configAutoReleaseBus(true)` is called, here should not call `reset()` - // to deinit the LCD device + lcd->reset(); lcd->begin(); - lcd->displayOn(); // This function is conflict with `configAutoReleaseBus(true)`, please don't - // enable them at the same time + lcd->displayOn(); #if EXAMPLE_ENABLE_PRINT_LCD_FPS + /* Attach a callback function which will be called when the Vsync signal is detected */ lcd->attachRefreshFinishCallback(onVsyncEndCallback, nullptr); #endif Serial.println("Draw color bar from top left to bottom right, the order is B - G - R"); + /* Users can refer to the implementation within `colorBardTest()` to draw patterns on the LCD */ lcd->colorBarTest(EXAMPLE_LCD_WIDTH, EXAMPLE_LCD_HEIGHT); #if EXAMPLE_LCD_PIN_NUM_BK_LIGHT >= 0 diff --git a/examples/LCD/MIPI_DSI/ESP_Panel_Conf.h b/examples/LCD/MIPI_DSI/ESP_Panel_Conf.h new file mode 100644 index 00000000..d860e8e1 --- /dev/null +++ b/examples/LCD/MIPI_DSI/ESP_Panel_Conf.h @@ -0,0 +1,77 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////// Debug Configurations ///////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/* Set to 1 if assert on error. Otherwise print error message */ +#define ESP_PANEL_CHECK_RESULT_ASSERT (0) // 0/1 + +/* Set to 1 if print log message for debug */ +#define ESP_PANEL_ENABLE_LOG (0) // 0/1 + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////// Touch Driver Configurations ////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/* Maximum point number */ +#define ESP_PANEL_TOUCH_MAX_POINTS (5) +/* Maximum button number */ +#define ESP_PANEL_TOUCH_MAX_BUTTONS (1) + +/** + * XPT2046 related + * + */ +#define ESP_PANEL_TOUCH_XPT2046_Z_THRESHOLD (400) // Minimum Z pressure threshold +/** + * Enable Interrupt (PENIRQ) output, also called Full Power Mode. + * Enable this to configure the XPT2046 to output low on the PENIRQ output if a touch is detected. + * This mode uses more power when enabled. Note that this signal goes low normally when a read is active. + */ +#define ESP_PANEL_TOUCH_XPT2046_INTERRUPT_MODE (0) // 0/1 +/** + * Keep internal Vref enabled. + * Enable this to keep the internal Vref enabled between conversions. This uses slightly more power, + * but requires fewer transactions when reading the battery voltage, aux voltage and temperature. + * + */ +#define ESP_PANEL_TOUCH_XPT2046_VREF_ON_MODE (0) // 0/1 +/** + * Convert touch coordinates to screen coordinates. + * When this option is enabled the raw ADC values will be converted from 0-4096 to 0-{screen width} or 0-{screen height}. + * When this option is disabled the process_coordinates method will need to be used to convert the raw ADC values into a + * screen coordinate. + * + */ +#define ESP_PANEL_TOUCH_XPT2046_CONVERT_ADC_TO_COORDS (1) // 0/1 +/** + * Enable data structure locking. + * By enabling this option the XPT2046 driver will lock the touch position data structures when reading values from the + * XPT2046 and when reading position data via API. + * WARNING: enabling this option may result in unintended crashes. + * + */ +#define ESP_PANEL_TOUCH_XPT2046_ENABLE_LOCKING (0) // 0/1 + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////// File Version /////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Do not change the following versions, they are used to check if the configurations in this file are compatible with + * the current version of `ESP_Panel_Conf.h` in the library. The detailed rules are as follows: + * + * 1. If the major version is not consistent, then the configurations in this file are incompatible with the library + * and must be replaced with the file from the library. + * 2. If the minor version is not consistent, this file might be missing some new configurations, which will be set to + * default values. It is recommended to replace it with the file from the library. + * 3. Even if the patch version is not consistent, it will not affect normal functionality. + * + */ +#define ESP_PANEL_CONF_FILE_VERSION_MAJOR 0 +#define ESP_PANEL_CONF_FILE_VERSION_MINOR 1 +#define ESP_PANEL_CONF_FILE_VERSION_PATCH 2 diff --git a/examples/LCD/MIPI_DSI/MIPI_DSI.ino b/examples/LCD/MIPI_DSI/MIPI_DSI.ino new file mode 100644 index 00000000..724b6444 --- /dev/null +++ b/examples/LCD/MIPI_DSI/MIPI_DSI.ino @@ -0,0 +1,248 @@ +/** + * | Supported ESP SoCs | ESP32-P4 | + * | ------------------ | -------- | + * + * | Supported LCD Controllers | EK79007 | ILI9881C | + * | ------------------------- | ------- | -------- | + * + * # MIPI-DSI LCD Example + * + * The example demonstrates how to develop different model LCDs with MIPI-DSI interface using standalone drivers and test them by displaying color bars. + * + * ## How to use + * + * 1. [Configure drivers](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/How_To_Use.md#configuring-drivers) if needed. + * 2. Modify the macros in the example to match the parameters according to your hardware. + * 3. Navigate to the `Tools` menu in the Arduino IDE to choose a ESP board and configure its parameters, please refter to [Configuring Supported Development Boards](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/How_To_Use.md#configuring-supported-development-boards) + * 4. Verify and upload the example to your ESP board. + * + * ## Serial Output + * + * ``` + * ... + * MIPI-DSI LCD example start + * Initialize backlight control pin and turn it on + * Create MIPI-DSI LCD bus + * Create LCD device + * Show MIPI-DSI patterns + * Draw color bar from top left to bottom right, the order is B - G - R + * Draw bitmap finish callback + * Draw bitmap finish callback + * Draw bitmap finish callback + * Draw bitmap finish callback + * Draw bitmap finish callback + * Draw bitmap finish callback + * Draw bitmap finish callback + * Draw bitmap finish callback + * Draw bitmap finish callback + * Draw bitmap finish callback + * Draw bitmap finish callback + * Draw bitmap finish callback + * Draw bitmap finish callback + * Draw bitmap finish callback + * Draw bitmap finish callback + * Draw bitmap finish callback + * Draw bitmap finish callback + * Draw bitmap finish callback + * Draw bitmap finish callback + * Draw bitmap finish callback + * Draw bitmap finish callback + * Draw bitmap finish callback + * Draw bitmap finish callback + * Draw bitmap finish callback + * MIPI-DSI LCD example end + * MIPI-DSI refresh rate: 0 + * MIPI-DSI refresh rate: 69 + * MIPI-DSI refresh rate: 69 + * MIPI-DSI refresh rate: 69 + * ... + * ``` + * + * ## Troubleshooting + * + * Please check the [FAQ](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/FAQ.md) first to see if the same question exists. If not, please create a [Github issue](https://github.com/esp-arduino-libs/ESP32_Display_Panel/issues). We will get back to you as soon as possible. + * + */ + +#include +#include + +/* The following default configurations are for the board 'Espressif: ESP32-P4-Function-EV-Board, EK79007' */ +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////// Please update the following configuration according to your LCD spec ////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Currently, the library supports the following MIPI-DSI LCDs: + * - EK79007, ILI9881C + */ +#define EXAMPLE_LCD_NAME EK79007 +#define EXAMPLE_LCD_WIDTH (1024) +#define EXAMPLE_LCD_HEIGHT (600) +#define EXAMPLE_LCD_COLOR_BITS (ESP_PANEL_LCD_RGB888_COLOR_BITS_24) +#define EXAMPLE_LCD_DSI_PHY_LDO_ID (3) // -1 if not used +#define EXAMPLE_LCD_DSI_LANE_NUM (2) // ESP32-P4 supports 1 or 2 lanes +#define EXAMPLE_LCD_DSI_LANE_RATE_MBPS (1000) /* Single lane bit rate, should consult the LCD supplier or check the + * LCD drive IC datasheet for the supported lane rate. + * ESP32-P4 supports max 1500Mbps + */ +#define EXAMPLE_LCD_DPI_CLK_MHZ (52) +#define EXAMPLE_LCD_DPI_COLOR_BITS (EXAMPLE_LCD_COLOR_BITS) +#define EXAMPLE_LCD_DPI_HPW (10) +#define EXAMPLE_LCD_DPI_HBP (160) +#define EXAMPLE_LCD_DPI_HFP (160) +#define EXAMPLE_LCD_DPI_VPW (1) +#define EXAMPLE_LCD_DPI_VBP (23) +#define EXAMPLE_LCD_DPI_VFP (12) +#define EXAMPLE_LCD_USE_EXTERNAL_CMD (0) +#if EXAMPLE_LCD_USE_EXTERNAL_CMD +/** + * LCD initialization commands. + * + * Vendor specific initialization can be different between manufacturers, should consult the LCD supplier for + * initialization sequence code. + * + * Please uncomment and change the following macro definitions, then use `configVendorCommands()` to pass them in the + * same format if needed. Otherwise, the LCD driver will use the default initialization sequence code. + * + * There are two formats for the sequence code: + * 1. Raw data: {command, (uint8_t []){ data0, data1, ... }, data_size, delay_ms} + * 2. Formatter: ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(delay_ms, command, { data0, data1, ... }) and + * ESP_PANEL_LCD_CMD_WITH_NONE_PARAM(delay_ms, command) + */ +const esp_lcd_panel_vendor_init_cmd_t lcd_init_cmd[] = { + // {0xFF, (uint8_t []){0x77, 0x01, 0x00, 0x00, 0x10}, 5, 0}, + // {0xC0, (uint8_t []){0x3B, 0x00}, 2, 0}, + // {0xC1, (uint8_t []){0x0D, 0x02}, 2, 0}, + // {0x29, (uint8_t []){0x00}, 0, 120}, + // // or + // ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xFF, {0x77, 0x01, 0x00, 0x00, 0x10}), + // ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xC0, {0x3B, 0x00}), + // ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xC1, {0x0D, 0x02}), + // ESP_PANEL_LCD_CMD_WITH_NONE_PARAM(120, 0x29), +}; +#endif + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////// Please update the following configuration according to your board spec //////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#define EXAMPLE_LCD_PIN_NUM_RST (27) // Set to -1 if not used +#define EXAMPLE_LCD_PIN_NUM_BK_LIGHT (26) // Set to -1 if not used +#define EXAMPLE_LCD_BK_LIGHT_ON_LEVEL (1) +#define EXAMPLE_LCD_BK_LIGHT_OFF_LEVEL !EXAMPLE_LCD_BK_LIGHT_ON_LEVEL + +/* Enable or disable pattern test */ +#define EXAMPLE_ENABLE_PATTERN_EXAMPLE (1) +/* Enable or disable the attachment of a callback function that is called after each bitmap drawing is completed */ +#define EXAMPLE_ENABLE_ATTACH_CALLBACK (1) +/* Enable or disable the attachment of a callback function that is called after each bitmap drawing is completed */ +#define EXAMPLE_ENABLE_PRINT_LCD_FPS (1) + +#define _EXAMPLE_LCD_CLASS(name, ...) ESP_PanelLcd_##name(__VA_ARGS__) +#define EXAMPLE_LCD_CLASS(name, ...) _EXAMPLE_LCD_CLASS(name, ##__VA_ARGS__) + +#if EXAMPLE_ENABLE_ATTACH_CALLBACK +IRAM_ATTR bool onDrawBitmapFinishCallback(void *user_data) +{ + esp_rom_printf("Draw bitmap finish callback\n"); + + return false; +} +#endif + +#if EXAMPLE_ENABLE_PRINT_LCD_FPS +#define EXAMPLE_LCD_FPS_COUNT_MAX (100) + +DRAM_ATTR int frame_count = 0; +DRAM_ATTR int fps = 0; +DRAM_ATTR long start_time = 0; + +IRAM_ATTR bool onVsyncEndCallback(void *user_data) +{ + long frame_start_time = *(long *)user_data; + if (frame_start_time == 0) { + (*(long *)user_data) = millis(); + + return false; + } + + frame_count++; + if (frame_count >= EXAMPLE_LCD_FPS_COUNT_MAX) { + fps = EXAMPLE_LCD_FPS_COUNT_MAX * 1000 / (millis() - frame_start_time); + frame_count = 0; + (*(long *)user_data) = millis(); + } + + return false; +} +#endif + +void setup() +{ + Serial.begin(115200); + Serial.println("MIPI-DSI LCD example start"); + +#if EXAMPLE_LCD_PIN_NUM_BK_LIGHT >= 0 + Serial.println("Initialize backlight control pin and turn it on"); + ESP_PanelBacklight *backlight = new ESP_PanelBacklight( + EXAMPLE_LCD_PIN_NUM_BK_LIGHT, EXAMPLE_LCD_BK_LIGHT_ON_LEVEL, true + ); + backlight->begin(); + backlight->on(); +#endif + + Serial.println("Create MIPI-DSI LCD bus"); + ESP_PanelBus_DSI *panel_bus = new ESP_PanelBus_DSI( + EXAMPLE_LCD_DSI_LANE_NUM, EXAMPLE_LCD_DSI_LANE_RATE_MBPS, + EXAMPLE_LCD_DPI_CLK_MHZ, EXAMPLE_LCD_DPI_COLOR_BITS, EXAMPLE_LCD_WIDTH, EXAMPLE_LCD_HEIGHT, + EXAMPLE_LCD_DPI_HPW, EXAMPLE_LCD_DPI_HBP, EXAMPLE_LCD_DPI_HFP, + EXAMPLE_LCD_DPI_VPW, EXAMPLE_LCD_DPI_VBP, EXAMPLE_LCD_DPI_VFP, + EXAMPLE_LCD_DSI_PHY_LDO_ID + ); + panel_bus->begin(); + + Serial.println("Create LCD device"); + ESP_PanelLcd *lcd = new EXAMPLE_LCD_CLASS(EXAMPLE_LCD_NAME, panel_bus, EXAMPLE_LCD_COLOR_BITS, EXAMPLE_LCD_PIN_NUM_RST); +#if EXAMPLE_LCD_USE_EXTERNAL_CMD + // Configure external initialization commands, should called before `init()` + lcd->configVendorCommands(lcd_init_cmd, sizeof(lcd_init_cmd)/sizeof(lcd_init_cmd[0])); +#endif + lcd->init(); + lcd->reset(); + lcd->begin(); + lcd->displayOn(); + +#if EXAMPLE_ENABLE_PATTERN_EXAMPLE + Serial.println("Show MIPI-DSI patterns"); + lcd->showDsiPattern(ESP_PanelLcd::DsiPatternType::BAR_HORIZONTAL); + delay(1000); + lcd->showDsiPattern(ESP_PanelLcd::DsiPatternType::BAR_VERTICAL); + delay(1000); + lcd->showDsiPattern(ESP_PanelLcd::DsiPatternType::BER_VERTICAL); + delay(1000); + lcd->showDsiPattern(ESP_PanelLcd::DsiPatternType::NONE); +#endif +#if EXAMPLE_ENABLE_ATTACH_CALLBACK + /* Attach a callback function which will be called when every bitmap drawing is completed */ + lcd->attachDrawBitmapFinishCallback(onDrawBitmapFinishCallback, NULL); +#endif +#if EXAMPLE_ENABLE_PRINT_LCD_FPS + /* Attach a callback function which will be called when the Vsync signal is detected */ + lcd->attachRefreshFinishCallback(onVsyncEndCallback, (void *)&start_time); +#endif + + Serial.println("Draw color bar from top left to bottom right, the order is B - G - R"); + /* Users can refer to the implementation within `colorBardTest()` to draw patterns on the LCD */ + lcd->colorBarTest(EXAMPLE_LCD_WIDTH, EXAMPLE_LCD_HEIGHT); + + Serial.println("MIPI-DSI LCD example end"); +} + +void loop() +{ + delay(1000); +#if EXAMPLE_ENABLE_PRINT_LCD_FPS + Serial.println("MIPI-DSI refresh rate: " + String(fps)); +#else + Serial.println("IDLE loop"); +#endif +} diff --git a/examples/LCD/MIPI_DSI/README.md b/examples/LCD/MIPI_DSI/README.md new file mode 100644 index 00000000..a8d2eb45 --- /dev/null +++ b/examples/LCD/MIPI_DSI/README.md @@ -0,0 +1,62 @@ +| Supported ESP SoCs | ESP32-P4 | +| ------------------ | -------- | + +| Supported LCD Controllers | EK79007 | ILI9881C | +| ------------------------- | ------- | -------- | + +# MIPI-DSI LCD Example + +The example demonstrates how to develop different model LCDs with MIPI-DSI interface using standalone drivers and test them by displaying color bars. + +## How to use + +1. [Configure drivers](../../../docs/How_To_Use.md#configuring-drivers) if needed. +2. Modify the macros in the example to match the parameters according to your hardware. +3. Navigate to the `Tools` menu in the Arduino IDE to choose a ESP board and configure its parameters, please refter to [Configuring Supported Development Boards](../../../docs/How_To_Use.md#configuring-supported-development-boards) +4. Verify and upload the example to your ESP board. + +## Serial Output + +``` +... +MIPI-DSI LCD example start +Initialize backlight control pin and turn it on +Create MIPI-DSI LCD bus +Create LCD device +Show MIPI-DSI patterns +Draw color bar from top left to bottom right, the order is B - G - R +Draw bitmap finish callback +Draw bitmap finish callback +Draw bitmap finish callback +Draw bitmap finish callback +Draw bitmap finish callback +Draw bitmap finish callback +Draw bitmap finish callback +Draw bitmap finish callback +Draw bitmap finish callback +Draw bitmap finish callback +Draw bitmap finish callback +Draw bitmap finish callback +Draw bitmap finish callback +Draw bitmap finish callback +Draw bitmap finish callback +Draw bitmap finish callback +Draw bitmap finish callback +Draw bitmap finish callback +Draw bitmap finish callback +Draw bitmap finish callback +Draw bitmap finish callback +Draw bitmap finish callback +Draw bitmap finish callback +Draw bitmap finish callback +MIPI-DSI LCD example end +MIPI-DSI refresh rate: 0 +MIPI-DSI refresh rate: 69 +MIPI-DSI refresh rate: 69 +MIPI-DSI refresh rate: 69 +... +``` + +## Troubleshooting + +Please check the [FAQ](../../../docs/FAQ.md) first to see if the same question exists. If not, please create a [Github issue](https://github.com/esp-arduino-libs/ESP32_Display_Panel/issues). We will get back to you as soon as possible. diff --git a/examples/LCD/QSPI/QSPI.ino b/examples/LCD/QSPI/QSPI.ino index 64ddc310..70ca52e7 100644 --- a/examples/LCD/QSPI/QSPI.ino +++ b/examples/LCD/QSPI/QSPI.ino @@ -11,9 +11,9 @@ * * ## How to use * - * 1. [Configure drivers](https://github.com/esp-arduino-libs/ESP32_Display_Panel/docs/How_To_Use.md#configuring-drivers) if needed. + * 1. [Configure drivers](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/How_To_Use.md#configuring-drivers) if needed. * 2. Modify the macros in the example to match the parameters according to your hardware. - * 3. Navigate to the `Tools` menu in the Arduino IDE to choose a ESP board and configure its parameters, please refter to [Configuring Supported Development Boards](https://github.com/esp-arduino-libs/ESP32_Display_Panel/docs/How_To_Use.md#configuring-supported-development-boards) + * 3. Navigate to the `Tools` menu in the Arduino IDE to choose a ESP board and configure its parameters, please refter to [Configuring Supported Development Boards](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/How_To_Use.md#configuring-supported-development-boards) * 4. Verify and upload the example to your ESP board. * * ## Serial Output @@ -49,18 +49,19 @@ * * ## Troubleshooting * - * Please check the [FAQ](https://github.com/esp-arduino-libs/ESP32_Display_Panel/docs/faq.md) first to see if the same question exists. If not, please create a [Github issue](https://github.com/esp-arduino-libs/ESP32_Display_Panel/issues). We will get back to you as soon as possible. + * Please check the [FAQ](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/FAQ.md) first to see if the same question exists. If not, please create a [Github issue](https://github.com/esp-arduino-libs/ESP32_Display_Panel/issues). We will get back to you as soon as possible. * */ #include #include +/* The following default configurations are for the board 'Espressif: Custom, ST77922' */ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// Please update the following configuration according to your LCD spec ////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** - * Currently, the library supports the following SPI LCDs: + * Currently, the library supports the following QSPI LCDs: * - GC9B71 * - SH8601 * - SPD2010 @@ -136,15 +137,18 @@ void setup() #if EXAMPLE_LCD_PIN_NUM_BK_LIGHT >= 0 Serial.println("Initialize backlight control pin and turn it off"); - ESP_PanelBacklight *backlight = new ESP_PanelBacklight(EXAMPLE_LCD_PIN_NUM_BK_LIGHT, EXAMPLE_LCD_BK_LIGHT_ON_LEVEL, true); + ESP_PanelBacklight *backlight = new ESP_PanelBacklight( + EXAMPLE_LCD_PIN_NUM_BK_LIGHT, EXAMPLE_LCD_BK_LIGHT_ON_LEVEL, true + ); backlight->begin(); backlight->off(); #endif Serial.println("Create QSPI LCD bus"); - ESP_PanelBus_QSPI *panel_bus = new ESP_PanelBus_QSPI(EXAMPLE_LCD_PIN_NUM_SPI_CS, EXAMPLE_LCD_PIN_NUM_SPI_SCK, - EXAMPLE_LCD_PIN_NUM_SPI_DATA0, EXAMPLE_LCD_PIN_NUM_SPI_DATA1, - EXAMPLE_LCD_PIN_NUM_SPI_DATA2, EXAMPLE_LCD_PIN_NUM_SPI_DATA3); + ESP_PanelBus_QSPI *panel_bus = new ESP_PanelBus_QSPI( + EXAMPLE_LCD_PIN_NUM_SPI_CS, EXAMPLE_LCD_PIN_NUM_SPI_SCK, EXAMPLE_LCD_PIN_NUM_SPI_DATA0, + EXAMPLE_LCD_PIN_NUM_SPI_DATA1, EXAMPLE_LCD_PIN_NUM_SPI_DATA2, EXAMPLE_LCD_PIN_NUM_SPI_DATA3 + ); panel_bus->configQspiFreqHz(EXAMPLE_LCD_SPI_FREQ_HZ); panel_bus->begin(); @@ -159,10 +163,12 @@ void setup() lcd->begin(); lcd->displayOn(); #if EXAMPLE_ENABLE_ATTACH_CALLBACK - lcd->attachRefreshFinishCallback(onDrawBitmapFinishCallback, NULL); + /* Attach a callback function which will be called when every bitmap drawing is completed */ + lcd->attachDrawBitmapFinishCallback(onDrawBitmapFinishCallback, NULL); #endif Serial.println("Draw color bar from top left to bottom right, the order is B - G - R"); + /* Users can refer to the implementation within `colorBardTest()` to draw patterns on the LCD */ lcd->colorBarTest(EXAMPLE_LCD_WIDTH, EXAMPLE_LCD_HEIGHT); #if EXAMPLE_LCD_PIN_NUM_BK_LIGHT >= 0 diff --git a/examples/LCD/RGB/RGB.ino b/examples/LCD/RGB/RGB.ino index c66fd7ed..6b481f42 100644 --- a/examples/LCD/RGB/RGB.ino +++ b/examples/LCD/RGB/RGB.ino @@ -11,9 +11,9 @@ * * ## How to use * - * 1. [Configure drivers](https://github.com/esp-arduino-libs/ESP32_Display_Panel/docs/How_To_Use.md#configuring-drivers) if needed. + * 1. [Configure drivers](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/How_To_Use.md#configuring-drivers) if needed. * 2. Modify the macros in the example to match the parameters according to your hardware. - * 3. Navigate to the `Tools` menu in the Arduino IDE to choose a ESP board and configure its parameters, please refter to [Configuring Supported Development Boards](https://github.com/esp-arduino-libs/ESP32_Display_Panel/docs/How_To_Use.md#configuring-supported-development-boards) + * 3. Navigate to the `Tools` menu in the Arduino IDE to choose a ESP board and configure its parameters, please refter to [Configuring Supported Development Boards](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/How_To_Use.md#configuring-supported-development-boards) * 4. Verify and upload the example to your ESP board. * * ## Serial Output @@ -34,13 +34,14 @@ * * ## Troubleshooting * - * Please check the [FAQ](https://github.com/esp-arduino-libs/ESP32_Display_Panel/docs/faq.md) first to see if the same question exists. If not, please create a [Github issue](https://github.com/esp-arduino-libs/ESP32_Display_Panel/issues). We will get back to you as soon as possible. + * Please check the [FAQ](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/FAQ.md) first to see if the same question exists. If not, please create a [Github issue](https://github.com/esp-arduino-libs/ESP32_Display_Panel/issues). We will get back to you as soon as possible. * */ #include #include +/* The following default configurations are for the board 'Espressif: ESP32_S3_LCD_EV_BOARD_2_V1_5, ST7262' */ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// Please update the following configuration according to your LCD spec ////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -53,7 +54,7 @@ #define EXAMPLE_LCD_WIDTH (800) #define EXAMPLE_LCD_HEIGHT (480) // | 8-bit RGB888 | 16-bit RGB565 | -#define EXAMPLE_LCD_COLOR_BITS (18) // | 24 | 16/18/24 | +#define EXAMPLE_LCD_COLOR_BITS (16) // | 24 | 16/18/24 | #define EXAMPLE_LCD_RGB_DATA_WIDTH (16) // | 8 | 16 | #define EXAMPLE_LCD_RGB_TIMING_FREQ_HZ (16 * 1000 * 1000) #define EXAMPLE_LCD_RGB_TIMING_HPW (40) @@ -62,6 +63,7 @@ #define EXAMPLE_LCD_RGB_TIMING_VPW (23) #define EXAMPLE_LCD_RGB_TIMING_VBP (32) #define EXAMPLE_LCD_RGB_TIMING_VFP (13) +#define EXAMPLE_LCD_RGB_BOUNCE_BUFFER_SIZE (EXAMPLE_LCD_WIDTH * 10) //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// Please update the following configuration according to your board spec //////////////////////////// @@ -79,8 +81,8 @@ #define EXAMPLE_LCD_PIN_NUM_RGB_DATA3 (13) // | B3 | B4 | B6 | #define EXAMPLE_LCD_PIN_NUM_RGB_DATA4 (14) // | B4 | B5 | B7 | #define EXAMPLE_LCD_PIN_NUM_RGB_DATA5 (21) // | G0 | G0 | G0-2 | -#define EXAMPLE_LCD_PIN_NUM_RGB_DATA6 (47) // | G1 | G1 | G3 | -#define EXAMPLE_LCD_PIN_NUM_RGB_DATA7 (48) // | G2 | G2 | G4 | +#define EXAMPLE_LCD_PIN_NUM_RGB_DATA6 (8) // | G1 | G1 | G3 | +#define EXAMPLE_LCD_PIN_NUM_RGB_DATA7 (18) // | G2 | G2 | G4 | #if EXAMPLE_LCD_RGB_DATA_WIDTH > 8 #define EXAMPLE_LCD_PIN_NUM_RGB_DATA8 (45) // | G3 | G3 | G5 | #define EXAMPLE_LCD_PIN_NUM_RGB_DATA9 (38) // | G4 | G4 | G6 | @@ -136,39 +138,39 @@ void setup() #if EXAMPLE_LCD_PIN_NUM_BK_LIGHT >= 0 Serial.println("Initialize backlight control pin and turn it off"); - ESP_PanelBacklight *backlight = new ESP_PanelBacklight(EXAMPLE_LCD_PIN_NUM_BK_LIGHT, EXAMPLE_LCD_BK_LIGHT_ON_LEVEL, true); + ESP_PanelBacklight *backlight = new ESP_PanelBacklight( + EXAMPLE_LCD_PIN_NUM_BK_LIGHT, EXAMPLE_LCD_BK_LIGHT_ON_LEVEL, true + ); backlight->begin(); backlight->off(); #endif Serial.println("Create RGB LCD bus"); + ESP_PanelBus_RGB *panel_bus = new ESP_PanelBus_RGB( #if EXAMPLE_LCD_RGB_DATA_WIDTH == 8 - ESP_PanelBus_RGB *panel_bus = new ESP_PanelBus_RGB(EXAMPLE_LCD_WIDTH, EXAMPLE_LCD_HEIGHT, - EXAMPLE_LCD_PIN_NUM_RGB_DATA0, EXAMPLE_LCD_PIN_NUM_RGB_DATA1, - EXAMPLE_LCD_PIN_NUM_RGB_DATA2, EXAMPLE_LCD_PIN_NUM_RGB_DATA3, - EXAMPLE_LCD_PIN_NUM_RGB_DATA4, EXAMPLE_LCD_PIN_NUM_RGB_DATA5, - EXAMPLE_LCD_PIN_NUM_RGB_DATA6, EXAMPLE_LCD_PIN_NUM_RGB_DATA7, - EXAMPLE_LCD_PIN_NUM_RGB_HSYNC, EXAMPLE_LCD_PIN_NUM_RGB_VSYNC, - EXAMPLE_LCD_PIN_NUM_RGB_PCLK, EXAMPLE_LCD_PIN_NUM_RGB_DE, - EXAMPLE_LCD_PIN_NUM_RGB_DISP); + EXAMPLE_LCD_WIDTH, EXAMPLE_LCD_HEIGHT, + EXAMPLE_LCD_PIN_NUM_RGB_DATA0, EXAMPLE_LCD_PIN_NUM_RGB_DATA1, EXAMPLE_LCD_PIN_NUM_RGB_DATA2, + EXAMPLE_LCD_PIN_NUM_RGB_DATA3, EXAMPLE_LCD_PIN_NUM_RGB_DATA4, EXAMPLE_LCD_PIN_NUM_RGB_DATA5, + EXAMPLE_LCD_PIN_NUM_RGB_DATA6, EXAMPLE_LCD_PIN_NUM_RGB_DATA7, EXAMPLE_LCD_PIN_NUM_RGB_HSYNC, + EXAMPLE_LCD_PIN_NUM_RGB_VSYNC, EXAMPLE_LCD_PIN_NUM_RGB_PCLK, EXAMPLE_LCD_PIN_NUM_RGB_DE, + EXAMPLE_LCD_PIN_NUM_RGB_DISP #elif EXAMPLE_LCD_RGB_DATA_WIDTH == 16 - ESP_PanelBus_RGB *panel_bus = new ESP_PanelBus_RGB(EXAMPLE_LCD_WIDTH, EXAMPLE_LCD_HEIGHT, - EXAMPLE_LCD_PIN_NUM_RGB_DATA0, EXAMPLE_LCD_PIN_NUM_RGB_DATA1, - EXAMPLE_LCD_PIN_NUM_RGB_DATA2, EXAMPLE_LCD_PIN_NUM_RGB_DATA3, - EXAMPLE_LCD_PIN_NUM_RGB_DATA4, EXAMPLE_LCD_PIN_NUM_RGB_DATA5, - EXAMPLE_LCD_PIN_NUM_RGB_DATA6, EXAMPLE_LCD_PIN_NUM_RGB_DATA7, - EXAMPLE_LCD_PIN_NUM_RGB_DATA8, EXAMPLE_LCD_PIN_NUM_RGB_DATA9, - EXAMPLE_LCD_PIN_NUM_RGB_DATA10, EXAMPLE_LCD_PIN_NUM_RGB_DATA11, - EXAMPLE_LCD_PIN_NUM_RGB_DATA12, EXAMPLE_LCD_PIN_NUM_RGB_DATA13, - EXAMPLE_LCD_PIN_NUM_RGB_DATA14, EXAMPLE_LCD_PIN_NUM_RGB_DATA15, - EXAMPLE_LCD_PIN_NUM_RGB_HSYNC, EXAMPLE_LCD_PIN_NUM_RGB_VSYNC, - EXAMPLE_LCD_PIN_NUM_RGB_PCLK, EXAMPLE_LCD_PIN_NUM_RGB_DE, - EXAMPLE_LCD_PIN_NUM_RGB_DISP); + EXAMPLE_LCD_WIDTH, EXAMPLE_LCD_HEIGHT, EXAMPLE_LCD_PIN_NUM_RGB_DATA0, EXAMPLE_LCD_PIN_NUM_RGB_DATA1, + EXAMPLE_LCD_PIN_NUM_RGB_DATA2, EXAMPLE_LCD_PIN_NUM_RGB_DATA3, EXAMPLE_LCD_PIN_NUM_RGB_DATA4, + EXAMPLE_LCD_PIN_NUM_RGB_DATA5, EXAMPLE_LCD_PIN_NUM_RGB_DATA6, EXAMPLE_LCD_PIN_NUM_RGB_DATA7, + EXAMPLE_LCD_PIN_NUM_RGB_DATA8, EXAMPLE_LCD_PIN_NUM_RGB_DATA9, EXAMPLE_LCD_PIN_NUM_RGB_DATA10, + EXAMPLE_LCD_PIN_NUM_RGB_DATA11, EXAMPLE_LCD_PIN_NUM_RGB_DATA12, EXAMPLE_LCD_PIN_NUM_RGB_DATA13, + EXAMPLE_LCD_PIN_NUM_RGB_DATA14, EXAMPLE_LCD_PIN_NUM_RGB_DATA15, EXAMPLE_LCD_PIN_NUM_RGB_HSYNC, + EXAMPLE_LCD_PIN_NUM_RGB_VSYNC, EXAMPLE_LCD_PIN_NUM_RGB_PCLK, EXAMPLE_LCD_PIN_NUM_RGB_DE, + EXAMPLE_LCD_PIN_NUM_RGB_DISP #endif + ); panel_bus->configRgbTimingFreqHz(EXAMPLE_LCD_RGB_TIMING_FREQ_HZ); - panel_bus->configRgbTimingPorch(EXAMPLE_LCD_RGB_TIMING_HPW, EXAMPLE_LCD_RGB_TIMING_HBP, EXAMPLE_LCD_RGB_TIMING_HFP, - EXAMPLE_LCD_RGB_TIMING_VPW, EXAMPLE_LCD_RGB_TIMING_VBP, EXAMPLE_LCD_RGB_TIMING_VFP); - // panel_bus->configRgbBounceBufferSize(EXAMPLE_LCD_WIDTH * 10); // Set bounce buffer to avoid screen drift + panel_bus->configRgbTimingPorch( + EXAMPLE_LCD_RGB_TIMING_HPW, EXAMPLE_LCD_RGB_TIMING_HBP, EXAMPLE_LCD_RGB_TIMING_HFP, + EXAMPLE_LCD_RGB_TIMING_VPW, EXAMPLE_LCD_RGB_TIMING_VBP, EXAMPLE_LCD_RGB_TIMING_VFP + ); + panel_bus->configRgbBounceBufferSize(EXAMPLE_LCD_RGB_BOUNCE_BUFFER_SIZE); // Set bounce buffer to avoid screen drift panel_bus->begin(); Serial.println("Create LCD device"); @@ -176,14 +178,14 @@ void setup() lcd->init(); lcd->reset(); lcd->begin(); -#if EXAMPLE_LCD_PIN_NUM_RGB_DISP >= 0 lcd->displayOn(); -#endif #if EXAMPLE_ENABLE_PRINT_LCD_FPS + /* Attach a callback function which will be called when the Vsync signal is detected */ lcd->attachRefreshFinishCallback(onVsyncEndCallback, (void *)&start_time); #endif Serial.println("Draw color bar from top left to bottom right, the order is B - G - R"); + /* Users can refer to the implementation within `colorBardTest()` to draw patterns on the LCD */ lcd->colorBarTest(EXAMPLE_LCD_WIDTH, EXAMPLE_LCD_HEIGHT); #if EXAMPLE_LCD_PIN_NUM_BK_LIGHT >= 0 diff --git a/examples/LCD/SPI/SPI.ino b/examples/LCD/SPI/SPI.ino index 64d7c9d9..e40ed878 100644 --- a/examples/LCD/SPI/SPI.ino +++ b/examples/LCD/SPI/SPI.ino @@ -11,9 +11,9 @@ * * ## How to use * - * 1. [Configure drivers](https://github.com/esp-arduino-libs/ESP32_Display_Panel/docs/How_To_Use.md#configuring-drivers) if needed. + * 1. [Configure drivers](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/How_To_Use.md#configuring-drivers) if needed. * 2. Modify the macros in the example to match the parameters according to your hardware. - * 3. Navigate to the `Tools` menu in the Arduino IDE to choose a ESP board and configure its parameters, please refter to [Configuring Supported Development Boards](https://github.com/esp-arduino-libs/ESP32_Display_Panel/docs/How_To_Use.md#configuring-supported-development-boards) + * 3. Navigate to the `Tools` menu in the Arduino IDE to choose a ESP board and configure its parameters, please refter to [Configuring Supported Development Boards](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/How_To_Use.md#configuring-supported-development-boards) * 4. Verify and upload the example to your ESP board. * * ## Serial Output @@ -49,7 +49,7 @@ * * ## Troubleshooting * - * Please check the [FAQ](https://github.com/esp-arduino-libs/ESP32_Display_Panel/docs/faq.md) first to see if the same question exists. If not, please create a [Github issue](https://github.com/esp-arduino-libs/ESP32_Display_Panel/issues). We will get back to you as soon as possible. + * Please check the [FAQ](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/FAQ.md) first to see if the same question exists. If not, please create a [Github issue](https://github.com/esp-arduino-libs/ESP32_Display_Panel/issues). We will get back to you as soon as possible. * */ @@ -73,7 +73,7 @@ #define EXAMPLE_LCD_HEIGHT (240) #define EXAMPLE_LCD_COLOR_BITS (16) #define EXAMPLE_LCD_SPI_FREQ_HZ (40 * 1000 * 1000) -#define EXAMPLE_LCD_USE_EXTERNAL_CMD (0) +#define EXAMPLE_LCD_USE_EXTERNAL_CMD (1) #if EXAMPLE_LCD_USE_EXTERNAL_CMD /** * LCD initialization commands. @@ -95,10 +95,22 @@ const esp_lcd_panel_vendor_init_cmd_t lcd_init_cmd[] = { // {0xC1, (uint8_t []){0x0D, 0x02}, 2, 0}, // {0x29, (uint8_t []){0x00}, 0, 120}, // // or - // ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xFF, {0x77, 0x01, 0x00, 0x00, 0x10}), - // ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xC0, {0x3B, 0x00}), - // ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xC1, {0x0D, 0x02}), - // ESP_PANEL_LCD_CMD_WITH_NONE_PARAM(120, 0x29), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xC8, {0xFF, 0x93, 0x42}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xC0, {0x0E, 0x0E}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xC5, {0xD0}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xC1, {0x02}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xB4, {0x02}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xE0, { + 0x00, 0x03, 0x08, 0x06, 0x13, 0x09, 0x39, 0x39, 0x48, 0x02, 0x0a, 0x08, + 0x17, 0x17, 0x0F + }), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xE1, { + 0x00, 0x28, 0x29, 0x01, 0x0d, 0x03, 0x3f, 0x33, 0x52, 0x04, 0x0f, 0x0e, + 0x37, 0x38, 0x0F + }), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xB1, {00, 0x1B}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xB7, {0x06}), + ESP_PANEL_LCD_CMD_WITH_NONE_PARAM(100, 0x11), }; #endif @@ -110,8 +122,8 @@ const esp_lcd_panel_vendor_init_cmd_t lcd_init_cmd[] = { #define EXAMPLE_LCD_PIN_NUM_SPI_SCK (7) #define EXAMPLE_LCD_PIN_NUM_SPI_SDA (6) #define EXAMPLE_LCD_PIN_NUM_SPI_SDO (-1) -#define EXAMPLE_LCD_PIN_NUM_RST (-1) // Set to -1 if not used -#define EXAMPLE_LCD_PIN_NUM_BK_LIGHT (45) // Set to -1 if not used +#define EXAMPLE_LCD_PIN_NUM_RST (48) // Set to -1 if not used +#define EXAMPLE_LCD_PIN_NUM_BK_LIGHT (47) // Set to -1 if not used #define EXAMPLE_LCD_BK_LIGHT_ON_LEVEL (1) #define EXAMPLE_LCD_BK_LIGHT_OFF_LEVEL !EXAMPLE_LCD_BK_LIGHT_ON_LEVEL @@ -155,11 +167,16 @@ void setup() // Configure external initialization commands, should called before `init()` lcd->configVendorCommands(lcd_init_cmd, sizeof(lcd_init_cmd)/sizeof(lcd_init_cmd[0])); #endif + // lcd->configColorRgbOrder(true); + // lcd->configResetActiveLevel(1); lcd->init(); lcd->reset(); lcd->begin(); + // lcd->mirrorX(true); + // lcd->mirrorY(true); lcd->displayOn(); #if EXAMPLE_ENABLE_ATTACH_CALLBACK + /* Attach a callback function which will be called when every bitmap drawing is completed */ lcd->attachRefreshFinishCallback(onDrawBitmapFinishCallback, NULL); #endif diff --git a/examples/LVGL/v8/Porting/ESP_Panel_Board_Custom.h b/examples/LVGL/v8/Porting/ESP_Panel_Board_Custom.h index 3ae31b50..dfd5e727 100644 --- a/examples/LVGL/v8/Porting/ESP_Panel_Board_Custom.h +++ b/examples/LVGL/v8/Porting/ESP_Panel_Board_Custom.h @@ -110,8 +110,6 @@ // |--------------|---------------| #define ESP_PANEL_LCD_RGB_DATA_WIDTH (16) // | 8 | 16 | #define ESP_PANEL_LCD_RGB_PIXEL_BITS (16) // | 24 | 16 | - - #define ESP_PANEL_LCD_RGB_FRAME_BUF_NUM (1) // 1/2/3 #define ESP_PANEL_LCD_RGB_BOUNCE_BUF_SIZE (0) // Bounce buffer size in bytes. This function is used to avoid screen drift. // To enable the bounce buffer, set it to a non-zero value. Typically set to `ESP_PANEL_LCD_WIDTH * 10` // The size of the Bounce Buffer must satisfy `width_of_lcd * height_of_lcd = size_of_buffer * N`, @@ -121,7 +119,6 @@ #define ESP_PANEL_LCD_RGB_IO_DE (17) // -1 if not used #define ESP_PANEL_LCD_RGB_IO_PCLK (9) #define ESP_PANEL_LCD_RGB_IO_DISP (-1) // -1 if not used - // | RGB565 | RGB666 | RGB888 | // |--------|--------|--------| #define ESP_PANEL_LCD_RGB_IO_DATA0 (10) // | B0 | B0-1 | B0-3 | @@ -158,6 +155,22 @@ // The `mirror()` function will be implemented by LCD command if set to 1. #endif +#elif ESP_PANEL_LCD_BUS_TYPE == ESP_PANEL_BUS_TYPE_MIPI_DSI + + #define ESP_PANEL_LCD_MIPI_DSI_LANE_NUM (2) // ESP32-P4 supports 1 or 2 lanes + #define ESP_PANEL_LCD_MIPI_DSI_LANE_RATE_MBPS (1000) // Single lane bit rate, should consult the LCD supplier or check the + // LCD drive IC datasheet for the supported lane rate. + // ESP32-P4 supports max 1500Mbps + #define ESP_PANEL_LCD_MIPI_DSI_PHY_LDO_ID (3) // -1 if not used + #define ESP_PANEL_LCD_MIPI_DPI_CLK_MHZ (52) + #define ESP_PANEL_LCD_MIPI_DPI_PIXEL_BITS (ESP_PANEL_LCD_RGB565_COLOR_BITS_16) + #define ESP_PANEL_LCD_MIPI_DSI_HPW (10) + #define ESP_PANEL_LCD_MIPI_DSI_HBP (160) + #define ESP_PANEL_LCD_MIPI_DSI_HFP (160) + #define ESP_PANEL_LCD_MIPI_DSI_VPW (1) + #define ESP_PANEL_LCD_MIPI_DSI_VBP (23) + #define ESP_PANEL_LCD_MIPI_DSI_VFP (12) + #else #error "The function is not ready and will be implemented in the future." @@ -380,8 +393,8 @@ * */ #define ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_MAJOR 0 -#define ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_MINOR 2 -#define ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_PATCH 3 +#define ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_MINOR 3 +#define ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_PATCH 0 #endif /* ESP_PANEL_USE_CUSTOM_BOARD */ diff --git a/examples/LVGL/v8/Porting/ESP_Panel_Board_Supported.h b/examples/LVGL/v8/Porting/ESP_Panel_Board_Supported.h index 603e59bd..75d5c84a 100644 --- a/examples/LVGL/v8/Porting/ESP_Panel_Board_Supported.h +++ b/examples/LVGL/v8/Porting/ESP_Panel_Board_Supported.h @@ -31,6 +31,7 @@ * - BOARD_ESP32_S3_LCD_EV_BOARD_2 (ESP32-S3-LCD-EV-Board-2(v1.1-v1.4))): https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32s3/esp32-s3-lcd-ev-board/user_guide_v1.4.html * - BOARD_ESP32_S3_LCD_EV_BOARD_2_V1_5 (ESP32-S3-LCD-EV-Board-2(v1.5)): https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32s3/esp32-s3-lcd-ev-board/user_guide.html * - BOARD_ESP32_S3_USB_OTG (ESP32-S3-USB-OTG): https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32s3/esp32-s3-usb-otg/index.html + * - BOARD_ESP32_P4_FUNCTION_EV_BOARD (ESP32-P4-Function-EV-Board): https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32p4/esp32-p4-function-ev-board/index.html * */ // #define BOARD_ESP32_C3_LCDKIT @@ -45,6 +46,7 @@ // #define BOARD_ESP32_S3_LCD_EV_BOARD_2 // #define BOARD_ESP32_S3_LCD_EV_BOARD_2_V1_5 // #define BOARD_ESP32_S3_USB_OTG +// #define BOARD_ESP32_P4_FUNCTION_EV_BOARD /* * Elecrow (https://www.elecrow.com): @@ -101,7 +103,7 @@ * */ #define ESP_PANEL_BOARD_SUPPORTED_FILE_VERSION_MAJOR 0 -#define ESP_PANEL_BOARD_SUPPORTED_FILE_VERSION_MINOR 5 -#define ESP_PANEL_BOARD_SUPPORTED_FILE_VERSION_PATCH 1 +#define ESP_PANEL_BOARD_SUPPORTED_FILE_VERSION_MINOR 6 +#define ESP_PANEL_BOARD_SUPPORTED_FILE_VERSION_PATCH 0 #endif diff --git a/examples/LVGL/v8/Porting/Porting.ino b/examples/LVGL/v8/Porting/Porting.ino index e7728911..0a1d9bb8 100644 --- a/examples/LVGL/v8/Porting/Porting.ino +++ b/examples/LVGL/v8/Porting/Porting.ino @@ -15,17 +15,17 @@ * * 1. For **ESP32_Display_Panel**: * - * - Follow the [steps](https://github.com/esp-arduino-libs/ESP32_Display_Panel/docs/How_To_Use.md#configuring-drivers) to configure drivers if needed. - * - If using a supported development board, follow the [steps](https://github.com/esp-arduino-libs/ESP32_Display_Panel/docs/How_To_Use.md#using-supported-development-boards) to configure it. - * - If using a custom board, follow the [steps](https://github.com/esp-arduino-libs/ESP32_Display_Panel/docs/How_To_Use.md#using-custom-development-boards) to configure it. + * - Follow the [steps](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/How_To_Use.md#configuring-drivers) to configure drivers if needed. + * - If using a supported development board, follow the [steps](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/How_To_Use.md#using-supported-development-boards) to configure it. + * - If using a custom board, follow the [steps](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/How_To_Use.md#using-custom-development-boards) to configure it. * * 2. For **lvgl**: * - * - Follow the [steps](https://github.com/esp-arduino-libs/ESP32_Display_Panel/docs/How_To_Use.md#configuring-lvgl) to add *lv_conf.h* file and change the configurations. + * - Follow the [steps](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/How_To_Use.md#configuring-lvgl) to add *lv_conf.h* file and change the configurations. * - Modify the macros in the [lvgl_port_v8.h](./lvgl_port_v8.h) file to configure the LVGL porting parameters. * * 3. Navigate to the `Tools` menu in the Arduino IDE to choose a ESP board and configure its parameters. For supported - * boards, please refter to [Configuring Supported Development Boards](https://github.com/esp-arduino-libs/ESP32_Display_Panel/docs/How_To_Use.md#configuring-supported-development-boards) + * boards, please refter to [Configuring Supported Development Boards](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/How_To_Use.md#configuring-supported-development-boards) * 4. Verify and upload the example to your ESP board. * * ## Serial Output @@ -44,7 +44,7 @@ * * ## Troubleshooting * - * Please check the [FAQ](https://github.com/esp-arduino-libs/ESP32_Display_Panel/docs/faq.md) first to see if the same question exists. If not, please create a [Github issue](https://github.com/esp-arduino-libs/ESP32_Display_Panel/issues). We will get back to you as soon as possible. + * Please check the [FAQ](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/FAQ.md) first to see if the same question exists. If not, please create a [Github issue](https://github.com/esp-arduino-libs/ESP32_Display_Panel/issues). We will get back to you as soon as possible. * */ @@ -71,10 +71,14 @@ void setup() ESP_Panel *panel = new ESP_Panel(); panel->init(); #if LVGL_PORT_AVOID_TEAR - // When avoid tearing function is enabled, configure the RGB bus according to the LVGL configuration - ESP_PanelBus_RGB *rgb_bus = static_cast(panel->getLcd()->getBus()); - rgb_bus->configRgbFrameBufferNumber(LVGL_PORT_DISP_BUFFER_NUM); - rgb_bus->configRgbBounceBufferSize(LVGL_PORT_RGB_BOUNCE_BUFFER_SIZE); + // When avoid tearing function is enabled, configure the bus according to the LVGL configuration + ESP_PanelBus *lcd_bus = panel->getLcd()->getBus(); +#if ESP_PANEL_LCD_BUS_TYPE == ESP_PANEL_BUS_TYPE_RGB + static_cast(lcd_bus)->configRgbBounceBufferSize(LVGL_PORT_RGB_BOUNCE_BUFFER_SIZE); + static_cast(lcd_bus)->configRgbFrameBufferNumber(LVGL_PORT_DISP_BUFFER_NUM); +#elif ESP_PANEL_LCD_BUS_TYPE == ESP_PANEL_BUS_TYPE_MIPI_DSI + static_cast(lcd_bus)->configDpiFrameBufferNumber(LVGL_PORT_DISP_BUFFER_NUM); +#endif #endif panel->begin(); @@ -85,7 +89,10 @@ void setup() /* Lock the mutex due to the LVGL APIs are not thread-safe */ lvgl_port_lock(-1); - /* Create a simple label */ + /** + * Create a simple label + * + */ lv_obj_t *label = lv_label_create(lv_scr_act()); lv_label_set_text(label, title.c_str()); lv_obj_align(label, LV_ALIGN_CENTER, 0, 0); diff --git a/examples/LVGL/v8/Porting/lvgl_port_v8.cpp b/examples/LVGL/v8/Porting/lvgl_port_v8.cpp index cfd9f29d..7173f33e 100644 --- a/examples/LVGL/v8/Porting/lvgl_port_v8.cpp +++ b/examples/LVGL/v8/Porting/lvgl_port_v8.cpp @@ -3,16 +3,17 @@ * * SPDX-License-Identifier: CC0-1.0 */ -#include -#include -#include +#include "esp_timer.h" #include "lvgl_port_v8.h" +#define LVGL_PORT_ENABLE_ROTATION_OPTIMIZED (1) #define LVGL_PORT_BUFFER_NUM_MAX (2) static const char *TAG = "lvgl_port"; static SemaphoreHandle_t lvgl_mux = nullptr; // LVGL mutex static TaskHandle_t lvgl_task_handle = nullptr; +static esp_timer_handle_t lvgl_tick_timer = NULL; +static void *lvgl_buf[LVGL_PORT_BUFFER_NUM_MAX] = {}; #if LVGL_PORT_ROTATION_DEGREE != 0 static void *get_next_frame_buffer(ESP_PanelLcd *lcd) @@ -21,8 +22,8 @@ static void *get_next_frame_buffer(ESP_PanelLcd *lcd) static void *fbs[2] = { NULL }; if (next_fb == NULL) { - fbs[0] = lcd->getRgbBufferByIndex(0); - fbs[1] = lcd->getRgbBufferByIndex(1); + fbs[0] = lcd->getFrameBufferByIndex(0); + fbs[1] = lcd->getFrameBufferByIndex(1); next_fb = fbs[1]; } else { next_fb = (next_fb == fbs[0]) ? fbs[1] : fbs[0]; @@ -31,53 +32,167 @@ static void *get_next_frame_buffer(ESP_PanelLcd *lcd) return next_fb; } -IRAM_ATTR static void rotate_copy_pixel(const lv_color_t *from, lv_color_t *to, uint16_t x_start, uint16_t y_start, - uint16_t x_end, uint16_t y_end, uint16_t w, uint16_t h, uint16_t rotate) +__attribute__((always_inline)) +static inline void copy_pixel_8bpp(uint8_t *to, const uint8_t *from) { + *to++ = *from++; +} + +__attribute__((always_inline)) +static inline void copy_pixel_16bpp(uint8_t *to, const uint8_t *from) +{ + *(uint16_t *)to++ = *(const uint16_t *)from++; +} + +__attribute__((always_inline)) +static inline void copy_pixel_24bpp(uint8_t *to, const uint8_t *from) +{ + *to++ = *from++; + *to++ = *from++; + *to++ = *from++; +} + +#define _COPY_PIXEL(_bpp, to, from) copy_pixel_##_bpp##bpp(to, from) +#define COPY_PIXEL(_bpp, to, from) _COPY_PIXEL(_bpp, to, from) + +#define ROTATE_90_ALL_BPP() \ + { \ + to_bytes_per_line = h * to_bytes_per_piexl; \ + to_index_const = (w - x_start - 1) * to_bytes_per_line; \ + for (int from_y = y_start; from_y < y_end + 1; from_y++) { \ + from_index = from_y * from_bytes_per_line + x_start * from_bytes_per_piexl; \ + to_index = to_index_const + from_y * to_bytes_per_piexl; \ + for (int from_x = x_start; from_x < x_end + 1; from_x++) { \ + COPY_PIXEL(LV_COLOR_DEPTH, to + to_index, from + from_index); \ + from_index += from_bytes_per_piexl; \ + to_index -= to_bytes_per_line; \ + } \ + } \ + } + +/** + * @brief Optimized transpose function for RGB565 format. + * + * @note ESP32-P4 1024x600 full-screen: 738ms -> 34ms + * @note ESP32-S3 480x480 full-screen: 380ms -> 37ms + * + */ +#define ROTATE_90_OPTIMIZED_16BPP(block_w, block_h) \ + { \ + for (int i = 0; i < h; i += block_h) { \ + max_height = (i + block_h > h) ? h : (i + block_h); \ + for (int j = 0; j < w; j += block_w) { \ + max_width = (j + block_w > w) ? w : (j + block_w); \ + start_y = w - 1 - j; \ + for (int x = i; x < max_height; x++) { \ + from_next = (uint16_t *)from + x * w; \ + for (int y = j, mirrored_y = start_y; y < max_width; y += 4, mirrored_y -= 4) { \ + ((uint16_t *)to)[(mirrored_y) * h + x] = *((uint32_t *)(from_next + y)) & 0xFFFF; \ + ((uint16_t *)to)[(mirrored_y - 1) * h + x] = (*((uint32_t *)(from_next + y)) >> 16) & 0xFFFF; \ + ((uint16_t *)to)[(mirrored_y - 2) * h + x] = *((uint32_t *)(from_next + y + 2)) & 0xFFFF; \ + ((uint16_t *)to)[(mirrored_y - 3) * h + x] = (*((uint32_t *)(from_next + y + 2)) >> 16) & 0xFFFF; \ + } \ + } \ + } \ + } \ + } + +#define ROTATE_180_ALL_BPP() \ + { \ + to_bytes_per_line = w * to_bytes_per_piexl; \ + to_index_const = (h - 1) * to_bytes_per_line + (w - x_start - 1) * to_bytes_per_piexl; \ + for (int from_y = y_start; from_y < y_end + 1; from_y++) { \ + from_index = from_y * from_bytes_per_line + x_start * from_bytes_per_piexl; \ + to_index = to_index_const - from_y * to_bytes_per_line; \ + for (int from_x = x_start; from_x < x_end + 1; from_x++) { \ + COPY_PIXEL(LV_COLOR_DEPTH, to + to_index, from + from_index); \ + from_index += from_bytes_per_piexl; \ + to_index -= to_bytes_per_piexl; \ + } \ + } \ + } + +#define ROTATE_270_OPTIMIZED_16BPP(block_w, block_h) \ + { \ + for (int i = 0; i < h; i += block_h) { \ + max_height = i + block_h > h ? h : i + block_h; \ + for (int j = 0; j < w; j += block_w) { \ + max_width = j + block_w > w ? w : j + block_w; \ + for (int x = i; x < max_height; x++) { \ + from_next = (uint16_t *)from + x * w; \ + for (int y = j; y < max_width; y += 4) { \ + ((uint16_t *)to)[y * h + (h - 1 - x)] = *((uint32_t *)(from_next + y)) & 0xFFFF; \ + ((uint16_t *)to)[(y + 1) * h + (h - 1 - x)] = (*((uint32_t *)(from_next + y)) >> 16) & 0xFFFF; \ + ((uint16_t *)to)[(y + 2) * h + (h - 1 - x)] = *((uint32_t *)(from_next + y + 2)) & 0xFFFF; \ + ((uint16_t *)to)[(y + 3) * h + (h - 1 - x)] = (*((uint32_t *)(from_next + y + 2)) >> 16) & 0xFFFF; \ + } \ + } \ + } \ + } \ + } + +#define ROTATE_270_ALL_BPP() \ + { \ + to_bytes_per_line = h * to_bytes_per_piexl; \ + from_index_const = x_start * from_bytes_per_piexl; \ + to_index_const = x_start * to_bytes_per_line + (h - 1) * to_bytes_per_piexl; \ + for (int from_y = y_start; from_y < y_end + 1; from_y++) { \ + from_index = from_y * from_bytes_per_line + from_index_const; \ + to_index = to_index_const - from_y * to_bytes_per_piexl; \ + for (int from_x = x_start; from_x < x_end + 1; from_x++) { \ + COPY_PIXEL(LV_COLOR_DEPTH, to + to_index, from + from_index); \ + from_index += from_bytes_per_piexl; \ + to_index += to_bytes_per_line; \ + } \ + } \ + } + +__attribute__((always_inline)) +IRAM_ATTR static inline void rotate_copy_pixel( + const uint8_t *from, uint8_t *to, uint16_t x_start, uint16_t y_start, uint16_t x_end, uint16_t y_end, uint16_t w, + uint16_t h, uint16_t rotate +) +{ + int from_bytes_per_piexl = sizeof(lv_color_t); + int from_bytes_per_line = w * from_bytes_per_piexl; int from_index = 0; + int from_index_const = 0; + + int to_bytes_per_piexl = LV_COLOR_DEPTH >> 3; + int to_bytes_per_line; int to_index = 0; int to_index_const = 0; +#if (LV_COLOR_DEPTH == 16) && LVGL_PORT_ENABLE_ROTATION_OPTIMIZED + int max_height = 0; + int max_width = 0; + int start_y = 0; + uint16_t *from_next = NULL; +#endif + + uint32_t time = esp_log_timestamp(); switch (rotate) { case 90: - 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; - 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; - } - } +#if (LV_COLOR_DEPTH == 16) && LVGL_PORT_ENABLE_ROTATION_OPTIMIZED + ROTATE_90_OPTIMIZED_16BPP(32, 256); +#else + ROTATE_90_ALL_BPP(); +#endif break; case 180: - to_index_const = h * w - x_start - 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 * w; - for (int from_x = x_start; from_x < x_end + 1; from_x++) { - *(to + to_index) = *(from + from_index); - from_index += 1; - to_index -= 1; - } - } + ROTATE_180_ALL_BPP(); break; case 270: - 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; - 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; - } - } +#if (LV_COLOR_DEPTH == 16) && LVGL_PORT_ENABLE_ROTATION_OPTIMIZED + ROTATE_270_OPTIMIZED_16BPP(32, 256); +#else + ROTATE_270_ALL_BPP(); +#endif break; default: break; } + ESP_LOGI(TAG, "rotate: end, time used:%d", (int)(esp_log_timestamp() - time)); } #endif /* LVGL_PORT_ROTATION_DEGREE */ @@ -174,8 +289,10 @@ static void flush_dirty_copy(void *dst, void *src, lv_port_dirty_area_t *dirty_a y_start = dirty_area->inv_areas[i].y1; y_end = dirty_area->inv_areas[i].y2; - rotate_copy_pixel((lv_color_t *)src, (lv_color_t *)dst, x_start, y_start, x_end, y_end, LV_HOR_RES, LV_VER_RES, - LVGL_PORT_ROTATION_DEGREE); + rotate_copy_pixel( + (uint8_t *)src, (uint8_t *)dst, x_start, y_start, x_end, y_end, LV_HOR_RES, LV_VER_RES, + LVGL_PORT_ROTATION_DEGREE + ); } } } @@ -200,10 +317,12 @@ static void flush_callback(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t // Rotate and copy data from the whole screen LVGL's buffer to the next frame buffer next_fb = flush_get_next_buf(lcd); - rotate_copy_pixel((lv_color_t *)color_map, (lv_color_t *)next_fb, offsetx1, offsety1, offsetx2, offsety2, - LV_HOR_RES, LV_VER_RES, LVGL_PORT_ROTATION_DEGREE); + rotate_copy_pixel( + (uint8_t *)color_map, (uint8_t *)next_fb, offsetx1, offsety1, offsetx2, offsety2, + LV_HOR_RES, LV_VER_RES, LVGL_PORT_ROTATION_DEGREE + ); - /* Switch the current RGB frame buffer to `next_fb` */ + /* Switch the current LCD frame buffer to `next_fb` */ lcd->drawBitmap(offsetx1, offsety1, offsetx2 - offsetx1 + 1, offsety2 - offsety1 + 1, (const uint8_t *)next_fb); /* Waiting for the current frame buffer to complete transmission */ @@ -234,7 +353,7 @@ static void flush_callback(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t flush_dirty_save(&dirty_area); flush_dirty_copy(next_fb, color_map, &dirty_area); - /* Switch the current RGB frame buffer to `next_fb` */ + /* Switch the current LCD frame buffer to `next_fb` */ lcd->drawBitmap(offsetx1, offsety1, offsetx2 - offsetx1 + 1, offsety2 - offsety1 + 1, (const uint8_t *)next_fb); /* Waiting for the current frame buffer to complete transmission */ @@ -266,7 +385,7 @@ static void flush_callback(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t /* Action after last area refresh */ if (lv_disp_flush_is_last(drv)) { - /* Switch the current RGB frame buffer to `color_map` */ + /* Switch the current LCD frame buffer to `color_map` */ lcd->drawBitmap(offsetx1, offsety1, offsetx2 - offsetx1 + 1, offsety2 - offsety1 + 1, (const uint8_t *)color_map); /* Waiting for the last frame buffer to complete transmission */ @@ -288,7 +407,7 @@ 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; - /* Switch the current RGB frame buffer to `color_map` */ + /* Switch the current LCD frame buffer to `color_map` */ lcd->drawBitmap(offsetx1, offsety1, offsetx2 - offsetx1 + 1, offsety2 - offsety1 + 1, (const uint8_t *)color_map); /* Waiting for the last frame buffer to complete transmission */ @@ -301,8 +420,8 @@ static void flush_callback(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t #elif LVGL_PORT_FULL_REFRESH && LVGL_PORT_DISP_BUFFER_NUM == 3 #if LVGL_PORT_ROTATION_DEGREE == 0 -static void *lvgl_port_rgb_last_buf = NULL; -static void *lvgl_port_rgb_next_buf = NULL; +static void *lvgl_port_lcd_last_buf = NULL; +static void *lvgl_port_lcd_next_buf = NULL; static void *lvgl_port_flush_next_buf = NULL; #endif @@ -317,38 +436,38 @@ void flush_callback(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color #if LVGL_PORT_ROTATION_DEGREE != 0 void *next_fb = get_next_frame_buffer(lcd); - /* Rotate and copy dirty area from the current LVGL's buffer to the next RGB frame buffer */ + /* Rotate and copy dirty area from the current LVGL's buffer to the next LCD frame buffer */ rotate_copy_pixel((lv_color_t *)color_map, (lv_color_t *)next_fb, offsetx1, offsety1, offsetx2, offsety2, LV_HOR_RES, LV_VER_RES, LVGL_PORT_ROTATION_DEGREE); - /* Switch the current RGB frame buffer to `next_fb` */ + /* Switch the current LCD frame buffer to `next_fb` */ lcd->drawBitmap(offsetx1, offsety1, offsetx2 - offsetx1 + 1, offsety2 - offsety1 + 1, (const uint8_t *)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; - /* Switch the current RGB frame buffer to `color_map` */ + /* Switch the current LCD frame buffer to `color_map` */ lcd->drawBitmap(offsetx1, offsety1, offsetx2 - offsetx1 + 1, offsety2 - offsety1 + 1, (const uint8_t *)color_map); - lvgl_port_rgb_next_buf = color_map; + lvgl_port_lcd_next_buf = color_map; #endif lv_disp_flush_ready(drv); } #endif -IRAM_ATTR bool onRgbVsyncCallback(void *user_data) +IRAM_ATTR bool onLcdVsyncCallback(void *user_data) { BaseType_t need_yield = pdFALSE; #if LVGL_PORT_FULL_REFRESH && (LVGL_PORT_DISP_BUFFER_NUM == 3) && (LVGL_PORT_ROTATION_DEGREE == 0) - if (lvgl_port_rgb_next_buf != lvgl_port_rgb_last_buf) { - lvgl_port_flush_next_buf = lvgl_port_rgb_last_buf; - lvgl_port_rgb_last_buf = lvgl_port_rgb_next_buf; + if (lvgl_port_lcd_next_buf != lvgl_port_lcd_last_buf) { + lvgl_port_flush_next_buf = lvgl_port_lcd_last_buf; + lvgl_port_lcd_last_buf = lvgl_port_lcd_next_buf; } #else TaskHandle_t task_handle = (TaskHandle_t)user_data; - // Notify that the current RGB frame buffer has been transmitted + // Notify that the current LCD frame buffer has been transmitted xTaskNotifyFromISR(task_handle, ULONG_MAX, eNoAction, &need_yield); #endif return (need_yield == pdTRUE); @@ -441,7 +560,6 @@ static lv_disp_t *display_init(ESP_PanelLcd *lcd) static lv_disp_drv_t disp_drv; // Alloc draw buffers used by LVGL - void *buf[LVGL_PORT_BUFFER_NUM_MAX] = { nullptr }; int buffer_size = 0; ESP_LOGD(TAG, "Malloc memory for LVGL buffer"); @@ -449,38 +567,38 @@ static lv_disp_t *display_init(ESP_PanelLcd *lcd) // Avoid tearing function is disabled buffer_size = LVGL_PORT_BUFFER_SIZE; for (int i = 0; (i < LVGL_PORT_BUFFER_NUM) && (i < LVGL_PORT_BUFFER_NUM_MAX); i++) { - buf[i] = heap_caps_malloc(buffer_size * sizeof(lv_color_t), LVGL_PORT_BUFFER_MALLOC_CAPS); - assert(buf[i]); - ESP_LOGD(TAG, "Buffer[%d] address: %p, size: %d", i, buf[i], buffer_size * sizeof(lv_color_t)); + lvgl_buf[i] = heap_caps_malloc(buffer_size * sizeof(lv_color_t), LVGL_PORT_BUFFER_MALLOC_CAPS); + assert(lvgl_buf[i]); + ESP_LOGD(TAG, "Buffer[%d] address: %p, size: %d", i, lvgl_buf[i], buffer_size * sizeof(lv_color_t)); } #else - // To avoid the tearing effect, we should use at least two frame buffers: one for LVGL rendering and another for RGB output + // To avoid the tearing effect, we should use at least two frame buffers: one for LVGL rendering and another for LCD refresh buffer_size = LVGL_PORT_DISP_WIDTH * LVGL_PORT_DISP_HEIGHT; #if (LVGL_PORT_DISP_BUFFER_NUM >= 3) && (LVGL_PORT_ROTATION_DEGREE == 0) && LVGL_PORT_FULL_REFRESH // With the usage of three buffers and full-refresh, we always have one buffer available for rendering, - // eliminating the need to wait for the RGB's sync signal - lvgl_port_rgb_last_buf = lcd->getRgbBufferByIndex(0); - buf[0] = lcd->getRgbBufferByIndex(1); - buf[1] = lcd->getRgbBufferByIndex(2); - lvgl_port_rgb_next_buf = lvgl_port_rgb_last_buf; - lvgl_port_flush_next_buf = buf[1]; + // eliminating the need to wait for the LCD's sync signal + lvgl_port_lcd_last_buf = lcd->getFrameBufferByIndex(0); + lvgl_buf[0] = lcd->getFrameBufferByIndex(1); + lvgl_buf[1] = lcd->getFrameBufferByIndex(2); + lvgl_port_lcd_next_buf = lvgl_port_lcd_last_buf; + lvgl_port_flush_next_buf = lvgl_buf[1]; #elif (LVGL_PORT_DISP_BUFFER_NUM >= 3) && (LVGL_PORT_ROTATION_DEGREE != 0) - buf[0] = lcd->getRgbBufferByIndex(2); + lvgl_buf[0] = lcd->getFrameBufferByIndex(2); #elif LVGL_PORT_DISP_BUFFER_NUM >= 2 for (int i = 0; (i < LVGL_PORT_DISP_BUFFER_NUM) && (i < LVGL_PORT_BUFFER_NUM_MAX); i++) { - buf[i] = lcd->getRgbBufferByIndex(i); + lvgl_buf[i] = lcd->getFrameBufferByIndex(i); } #endif #endif /* LVGL_PORT_AVOID_TEAR */ // initialize LVGL draw buffers - lv_disp_draw_buf_init(&disp_buf, buf[0], buf[1], buffer_size); + lv_disp_draw_buf_init(&disp_buf, lvgl_buf[0], lvgl_buf[1], buffer_size); ESP_LOGD(TAG, "Register display driver to LVGL"); lv_disp_drv_init(&disp_drv); @@ -550,16 +668,33 @@ static void tick_increment(void *arg) lv_tick_inc(LVGL_PORT_TICK_PERIOD_MS); } -static esp_err_t tick_init(void) +static bool tick_init(void) { // Tick interface for LVGL (using esp_timer to generate 2ms periodic event) const esp_timer_create_args_t lvgl_tick_timer_args = { .callback = &tick_increment, .name = "LVGL tick" }; - esp_timer_handle_t lvgl_tick_timer = NULL; - ESP_ERROR_CHECK(esp_timer_create(&lvgl_tick_timer_args, &lvgl_tick_timer)); - return esp_timer_start_periodic(lvgl_tick_timer, LVGL_PORT_TICK_PERIOD_MS * 1000); + ESP_PANEL_CHECK_ERR_RET( + esp_timer_create(&lvgl_tick_timer_args, &lvgl_tick_timer), false, "Create LVGL tick timer failed" + ); + ESP_PANEL_CHECK_ERR_RET( + esp_timer_start_periodic(lvgl_tick_timer, LVGL_PORT_TICK_PERIOD_MS * 1000), false, + "Start LVGL tick timer failed" + ); + + return true; +} + +static bool tick_deinit(void) +{ + ESP_PANEL_CHECK_ERR_RET( + esp_timer_stop(lvgl_tick_timer), false, "Stop LVGL tick timer failed" + ); + ESP_PANEL_CHECK_ERR_RET( + esp_timer_delete(lvgl_tick_timer), false, "Delete LVGL tick timer failed" + ); + return true; } #endif @@ -582,7 +717,7 @@ static void lvgl_port_task(void *arg) } } -IRAM_ATTR bool onRefreshFinishCallback(void *user_data) +IRAM_ATTR bool onDrawBitmapFinishCallback(void *user_data) { lv_disp_drv_t *drv = (lv_disp_drv_t *)user_data; @@ -594,9 +729,14 @@ IRAM_ATTR bool onRefreshFinishCallback(void *user_data) bool lvgl_port_init(ESP_PanelLcd *lcd, ESP_PanelTouch *tp) { ESP_PANEL_CHECK_FALSE_RET(lcd != nullptr, false, "Invalid LCD device"); + + auto bus_type = lcd->getBus()->getType(); #if LVGL_PORT_AVOID_TEAR - ESP_PANEL_CHECK_FALSE_RET(lcd->getBus()->getType() == ESP_PANEL_BUS_TYPE_RGB, false, "Avoid tearing function only works with RGB LCD now"); - ESP_LOGD(TAG, "Avoid tearing is enabled, mode: %d", LVGL_PORT_AVOID_TEARING_MODE); + ESP_PANEL_CHECK_FALSE_RET( + (bus_type == ESP_PANEL_BUS_TYPE_RGB) || (bus_type == ESP_PANEL_BUS_TYPE_MIPI_DSI), false, + "Avoid tearing function only works with RGB/MIPI-DSI LCD now" + ); + ESP_LOGI(TAG, "Avoid tearing is enabled, mode: %d", LVGL_PORT_AVOID_TEARING_MODE); #endif lv_disp_t *disp = nullptr; @@ -604,7 +744,7 @@ bool lvgl_port_init(ESP_PanelLcd *lcd, ESP_PanelTouch *tp) lv_init(); #if !LV_TICK_CUSTOM - ESP_PANEL_CHECK_ERR_RET(tick_init(), false, "Initialize LVGL tick failed"); + ESP_PANEL_CHECK_FALSE_RET(tick_init(), false, "Initialize LVGL tick failed"); #endif ESP_LOGD(TAG, "Initialize LVGL display driver"); @@ -614,9 +754,9 @@ bool lvgl_port_init(ESP_PanelLcd *lcd, ESP_PanelTouch *tp) lv_disp_set_rotation(disp, LV_DISP_ROT_NONE); // For non-RGB LCD, need to notify LVGL that the buffer is ready when the refresh is finished - if (lcd->getBus()->getType() != ESP_PANEL_BUS_TYPE_RGB) { + if (bus_type != ESP_PANEL_BUS_TYPE_RGB) { ESP_LOGD(TAG, "Attach refresh finish callback to LCD"); - lcd->attachRefreshFinishCallback(onRefreshFinishCallback, (void *)disp->driver); + lcd->attachDrawBitmapFinishCallback(onDrawBitmapFinishCallback, (void *)disp->driver); } if (tp != nullptr) { @@ -647,7 +787,7 @@ bool lvgl_port_init(ESP_PanelLcd *lcd, ESP_PanelTouch *tp) ESP_PANEL_CHECK_FALSE_RET(ret == pdPASS, false, "Create LVGL task failed"); #if LVGL_PORT_AVOID_TEAR - lcd->attachRefreshFinishCallback(onRgbVsyncCallback, (void *)lvgl_task_handle); + lcd->attachRefreshFinishCallback(onLcdVsyncCallback, (void *)lvgl_task_handle); #endif return true; @@ -669,3 +809,35 @@ bool lvgl_port_unlock(void) return true; } + +bool lvgl_port_deinit(void) +{ +#if !LV_TICK_CUSTOM + ESP_PANEL_CHECK_FALSE_RET(tick_deinit(), false, "Deinitialize LVGL tick failed"); +#endif + + ESP_PANEL_CHECK_FALSE_RET(lvgl_port_lock(-1), false, "Lock LVGL failed"); + if (lvgl_task_handle != nullptr) { + vTaskDelete(lvgl_task_handle); + lvgl_task_handle = nullptr; + } + ESP_PANEL_CHECK_FALSE_RET(lvgl_port_unlock(), false, "Unlock LVGL failed"); + +#if LV_ENABLE_GC || !LV_MEM_CUSTOM + lv_deinit(); +#endif +#if !LVGL_PORT_AVOID_TEAR + for (int i = 0; i < LVGL_PORT_BUFFER_NUM; i++) { + if (lvgl_buf[i] != nullptr) { + free(lvgl_buf[i]); + lvgl_buf[i] = nullptr; + } + } +#endif + if (lvgl_mux != nullptr) { + vSemaphoreDelete(lvgl_mux); + lvgl_mux = nullptr; + } + + return true; +} diff --git a/examples/LVGL/v8/Rotation/ESP_Panel_Board_Custom.h b/examples/LVGL/v8/Rotation/ESP_Panel_Board_Custom.h index 3ae31b50..dfd5e727 100644 --- a/examples/LVGL/v8/Rotation/ESP_Panel_Board_Custom.h +++ b/examples/LVGL/v8/Rotation/ESP_Panel_Board_Custom.h @@ -110,8 +110,6 @@ // |--------------|---------------| #define ESP_PANEL_LCD_RGB_DATA_WIDTH (16) // | 8 | 16 | #define ESP_PANEL_LCD_RGB_PIXEL_BITS (16) // | 24 | 16 | - - #define ESP_PANEL_LCD_RGB_FRAME_BUF_NUM (1) // 1/2/3 #define ESP_PANEL_LCD_RGB_BOUNCE_BUF_SIZE (0) // Bounce buffer size in bytes. This function is used to avoid screen drift. // To enable the bounce buffer, set it to a non-zero value. Typically set to `ESP_PANEL_LCD_WIDTH * 10` // The size of the Bounce Buffer must satisfy `width_of_lcd * height_of_lcd = size_of_buffer * N`, @@ -121,7 +119,6 @@ #define ESP_PANEL_LCD_RGB_IO_DE (17) // -1 if not used #define ESP_PANEL_LCD_RGB_IO_PCLK (9) #define ESP_PANEL_LCD_RGB_IO_DISP (-1) // -1 if not used - // | RGB565 | RGB666 | RGB888 | // |--------|--------|--------| #define ESP_PANEL_LCD_RGB_IO_DATA0 (10) // | B0 | B0-1 | B0-3 | @@ -158,6 +155,22 @@ // The `mirror()` function will be implemented by LCD command if set to 1. #endif +#elif ESP_PANEL_LCD_BUS_TYPE == ESP_PANEL_BUS_TYPE_MIPI_DSI + + #define ESP_PANEL_LCD_MIPI_DSI_LANE_NUM (2) // ESP32-P4 supports 1 or 2 lanes + #define ESP_PANEL_LCD_MIPI_DSI_LANE_RATE_MBPS (1000) // Single lane bit rate, should consult the LCD supplier or check the + // LCD drive IC datasheet for the supported lane rate. + // ESP32-P4 supports max 1500Mbps + #define ESP_PANEL_LCD_MIPI_DSI_PHY_LDO_ID (3) // -1 if not used + #define ESP_PANEL_LCD_MIPI_DPI_CLK_MHZ (52) + #define ESP_PANEL_LCD_MIPI_DPI_PIXEL_BITS (ESP_PANEL_LCD_RGB565_COLOR_BITS_16) + #define ESP_PANEL_LCD_MIPI_DSI_HPW (10) + #define ESP_PANEL_LCD_MIPI_DSI_HBP (160) + #define ESP_PANEL_LCD_MIPI_DSI_HFP (160) + #define ESP_PANEL_LCD_MIPI_DSI_VPW (1) + #define ESP_PANEL_LCD_MIPI_DSI_VBP (23) + #define ESP_PANEL_LCD_MIPI_DSI_VFP (12) + #else #error "The function is not ready and will be implemented in the future." @@ -380,8 +393,8 @@ * */ #define ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_MAJOR 0 -#define ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_MINOR 2 -#define ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_PATCH 3 +#define ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_MINOR 3 +#define ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_PATCH 0 #endif /* ESP_PANEL_USE_CUSTOM_BOARD */ diff --git a/examples/LVGL/v8/Rotation/ESP_Panel_Board_Supported.h b/examples/LVGL/v8/Rotation/ESP_Panel_Board_Supported.h index 603e59bd..75d5c84a 100644 --- a/examples/LVGL/v8/Rotation/ESP_Panel_Board_Supported.h +++ b/examples/LVGL/v8/Rotation/ESP_Panel_Board_Supported.h @@ -31,6 +31,7 @@ * - BOARD_ESP32_S3_LCD_EV_BOARD_2 (ESP32-S3-LCD-EV-Board-2(v1.1-v1.4))): https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32s3/esp32-s3-lcd-ev-board/user_guide_v1.4.html * - BOARD_ESP32_S3_LCD_EV_BOARD_2_V1_5 (ESP32-S3-LCD-EV-Board-2(v1.5)): https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32s3/esp32-s3-lcd-ev-board/user_guide.html * - BOARD_ESP32_S3_USB_OTG (ESP32-S3-USB-OTG): https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32s3/esp32-s3-usb-otg/index.html + * - BOARD_ESP32_P4_FUNCTION_EV_BOARD (ESP32-P4-Function-EV-Board): https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32p4/esp32-p4-function-ev-board/index.html * */ // #define BOARD_ESP32_C3_LCDKIT @@ -45,6 +46,7 @@ // #define BOARD_ESP32_S3_LCD_EV_BOARD_2 // #define BOARD_ESP32_S3_LCD_EV_BOARD_2_V1_5 // #define BOARD_ESP32_S3_USB_OTG +// #define BOARD_ESP32_P4_FUNCTION_EV_BOARD /* * Elecrow (https://www.elecrow.com): @@ -101,7 +103,7 @@ * */ #define ESP_PANEL_BOARD_SUPPORTED_FILE_VERSION_MAJOR 0 -#define ESP_PANEL_BOARD_SUPPORTED_FILE_VERSION_MINOR 5 -#define ESP_PANEL_BOARD_SUPPORTED_FILE_VERSION_PATCH 1 +#define ESP_PANEL_BOARD_SUPPORTED_FILE_VERSION_MINOR 6 +#define ESP_PANEL_BOARD_SUPPORTED_FILE_VERSION_PATCH 0 #endif diff --git a/examples/LVGL/v8/Rotation/Rotation.ino b/examples/LVGL/v8/Rotation/Rotation.ino index 7dee3f08..65669413 100644 --- a/examples/LVGL/v8/Rotation/Rotation.ino +++ b/examples/LVGL/v8/Rotation/Rotation.ino @@ -13,17 +13,17 @@ * * 1. For **ESP32_Display_Panel**: * - * - Follow the [steps](https://github.com/esp-arduino-libs/ESP32_Display_Panel/docs/How_To_Use.md#configuring-drivers) to configure drivers if needed. - * - If using a supported development board, follow the [steps](https://github.com/esp-arduino-libs/ESP32_Display_Panel/docs/How_To_Use.md#using-supported-development-boards) to configure it. - * - If using a custom board, follow the [steps](https://github.com/esp-arduino-libs/ESP32_Display_Panel/docs/How_To_Use.md#using-custom-development-boards) to configure it. + * - Follow the [steps](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/How_To_Use.md#configuring-drivers) to configure drivers if needed. + * - If using a supported development board, follow the [steps](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/How_To_Use.md#using-supported-development-boards) to configure it. + * - If using a custom board, follow the [steps](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/How_To_Use.md#using-custom-development-boards) to configure it. * * 2. For **lvgl**: * - * - Follow the [steps](https://github.com/esp-arduino-libs/ESP32_Display_Panel/docs/How_To_Use.md#configuring-lvgl) to add *lv_conf.h* file and change the configurations. + * - Follow the [steps](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/How_To_Use.md#configuring-lvgl) to add *lv_conf.h* file and change the configurations. * - Modify the macros in the [lvgl_port_v8.h](./lvgl_port_v8.h) file to configure the LVGL porting parameters. * * 3. Navigate to the `Tools` menu in the Arduino IDE to choose a ESP board and configure its parameters. For supported - * boards, please refter to [Configuring Supported Development Boards](https://github.com/esp-arduino-libs/ESP32_Display_Panel/docs/How_To_Use.md#configuring-supported-development-boards) + * boards, please refter to [Configuring Supported Development Boards](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/How_To_Use.md#configuring-supported-development-boards) * 4. Verify and upload the example to your ESP board. * * ## Serial Output @@ -42,7 +42,7 @@ * * ## Troubleshooting * - * Please check the [FAQ](https://github.com/esp-arduino-libs/ESP32_Display_Panel/docs/faq.md) first to see if the same question exists. If not, please create a [Github issue](https://github.com/esp-arduino-libs/ESP32_Display_Panel/issues). We will get back to you as soon as possible. + * Please check the [FAQ](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/FAQ.md) first to see if the same question exists. If not, please create a [Github issue](https://github.com/esp-arduino-libs/ESP32_Display_Panel/issues). We will get back to you as soon as possible. * */ diff --git a/examples/LVGL/v8/Rotation/lvgl_port_v8.cpp b/examples/LVGL/v8/Rotation/lvgl_port_v8.cpp index cfd9f29d..7173f33e 100644 --- a/examples/LVGL/v8/Rotation/lvgl_port_v8.cpp +++ b/examples/LVGL/v8/Rotation/lvgl_port_v8.cpp @@ -3,16 +3,17 @@ * * SPDX-License-Identifier: CC0-1.0 */ -#include -#include -#include +#include "esp_timer.h" #include "lvgl_port_v8.h" +#define LVGL_PORT_ENABLE_ROTATION_OPTIMIZED (1) #define LVGL_PORT_BUFFER_NUM_MAX (2) static const char *TAG = "lvgl_port"; static SemaphoreHandle_t lvgl_mux = nullptr; // LVGL mutex static TaskHandle_t lvgl_task_handle = nullptr; +static esp_timer_handle_t lvgl_tick_timer = NULL; +static void *lvgl_buf[LVGL_PORT_BUFFER_NUM_MAX] = {}; #if LVGL_PORT_ROTATION_DEGREE != 0 static void *get_next_frame_buffer(ESP_PanelLcd *lcd) @@ -21,8 +22,8 @@ static void *get_next_frame_buffer(ESP_PanelLcd *lcd) static void *fbs[2] = { NULL }; if (next_fb == NULL) { - fbs[0] = lcd->getRgbBufferByIndex(0); - fbs[1] = lcd->getRgbBufferByIndex(1); + fbs[0] = lcd->getFrameBufferByIndex(0); + fbs[1] = lcd->getFrameBufferByIndex(1); next_fb = fbs[1]; } else { next_fb = (next_fb == fbs[0]) ? fbs[1] : fbs[0]; @@ -31,53 +32,167 @@ static void *get_next_frame_buffer(ESP_PanelLcd *lcd) return next_fb; } -IRAM_ATTR static void rotate_copy_pixel(const lv_color_t *from, lv_color_t *to, uint16_t x_start, uint16_t y_start, - uint16_t x_end, uint16_t y_end, uint16_t w, uint16_t h, uint16_t rotate) +__attribute__((always_inline)) +static inline void copy_pixel_8bpp(uint8_t *to, const uint8_t *from) { + *to++ = *from++; +} + +__attribute__((always_inline)) +static inline void copy_pixel_16bpp(uint8_t *to, const uint8_t *from) +{ + *(uint16_t *)to++ = *(const uint16_t *)from++; +} + +__attribute__((always_inline)) +static inline void copy_pixel_24bpp(uint8_t *to, const uint8_t *from) +{ + *to++ = *from++; + *to++ = *from++; + *to++ = *from++; +} + +#define _COPY_PIXEL(_bpp, to, from) copy_pixel_##_bpp##bpp(to, from) +#define COPY_PIXEL(_bpp, to, from) _COPY_PIXEL(_bpp, to, from) + +#define ROTATE_90_ALL_BPP() \ + { \ + to_bytes_per_line = h * to_bytes_per_piexl; \ + to_index_const = (w - x_start - 1) * to_bytes_per_line; \ + for (int from_y = y_start; from_y < y_end + 1; from_y++) { \ + from_index = from_y * from_bytes_per_line + x_start * from_bytes_per_piexl; \ + to_index = to_index_const + from_y * to_bytes_per_piexl; \ + for (int from_x = x_start; from_x < x_end + 1; from_x++) { \ + COPY_PIXEL(LV_COLOR_DEPTH, to + to_index, from + from_index); \ + from_index += from_bytes_per_piexl; \ + to_index -= to_bytes_per_line; \ + } \ + } \ + } + +/** + * @brief Optimized transpose function for RGB565 format. + * + * @note ESP32-P4 1024x600 full-screen: 738ms -> 34ms + * @note ESP32-S3 480x480 full-screen: 380ms -> 37ms + * + */ +#define ROTATE_90_OPTIMIZED_16BPP(block_w, block_h) \ + { \ + for (int i = 0; i < h; i += block_h) { \ + max_height = (i + block_h > h) ? h : (i + block_h); \ + for (int j = 0; j < w; j += block_w) { \ + max_width = (j + block_w > w) ? w : (j + block_w); \ + start_y = w - 1 - j; \ + for (int x = i; x < max_height; x++) { \ + from_next = (uint16_t *)from + x * w; \ + for (int y = j, mirrored_y = start_y; y < max_width; y += 4, mirrored_y -= 4) { \ + ((uint16_t *)to)[(mirrored_y) * h + x] = *((uint32_t *)(from_next + y)) & 0xFFFF; \ + ((uint16_t *)to)[(mirrored_y - 1) * h + x] = (*((uint32_t *)(from_next + y)) >> 16) & 0xFFFF; \ + ((uint16_t *)to)[(mirrored_y - 2) * h + x] = *((uint32_t *)(from_next + y + 2)) & 0xFFFF; \ + ((uint16_t *)to)[(mirrored_y - 3) * h + x] = (*((uint32_t *)(from_next + y + 2)) >> 16) & 0xFFFF; \ + } \ + } \ + } \ + } \ + } + +#define ROTATE_180_ALL_BPP() \ + { \ + to_bytes_per_line = w * to_bytes_per_piexl; \ + to_index_const = (h - 1) * to_bytes_per_line + (w - x_start - 1) * to_bytes_per_piexl; \ + for (int from_y = y_start; from_y < y_end + 1; from_y++) { \ + from_index = from_y * from_bytes_per_line + x_start * from_bytes_per_piexl; \ + to_index = to_index_const - from_y * to_bytes_per_line; \ + for (int from_x = x_start; from_x < x_end + 1; from_x++) { \ + COPY_PIXEL(LV_COLOR_DEPTH, to + to_index, from + from_index); \ + from_index += from_bytes_per_piexl; \ + to_index -= to_bytes_per_piexl; \ + } \ + } \ + } + +#define ROTATE_270_OPTIMIZED_16BPP(block_w, block_h) \ + { \ + for (int i = 0; i < h; i += block_h) { \ + max_height = i + block_h > h ? h : i + block_h; \ + for (int j = 0; j < w; j += block_w) { \ + max_width = j + block_w > w ? w : j + block_w; \ + for (int x = i; x < max_height; x++) { \ + from_next = (uint16_t *)from + x * w; \ + for (int y = j; y < max_width; y += 4) { \ + ((uint16_t *)to)[y * h + (h - 1 - x)] = *((uint32_t *)(from_next + y)) & 0xFFFF; \ + ((uint16_t *)to)[(y + 1) * h + (h - 1 - x)] = (*((uint32_t *)(from_next + y)) >> 16) & 0xFFFF; \ + ((uint16_t *)to)[(y + 2) * h + (h - 1 - x)] = *((uint32_t *)(from_next + y + 2)) & 0xFFFF; \ + ((uint16_t *)to)[(y + 3) * h + (h - 1 - x)] = (*((uint32_t *)(from_next + y + 2)) >> 16) & 0xFFFF; \ + } \ + } \ + } \ + } \ + } + +#define ROTATE_270_ALL_BPP() \ + { \ + to_bytes_per_line = h * to_bytes_per_piexl; \ + from_index_const = x_start * from_bytes_per_piexl; \ + to_index_const = x_start * to_bytes_per_line + (h - 1) * to_bytes_per_piexl; \ + for (int from_y = y_start; from_y < y_end + 1; from_y++) { \ + from_index = from_y * from_bytes_per_line + from_index_const; \ + to_index = to_index_const - from_y * to_bytes_per_piexl; \ + for (int from_x = x_start; from_x < x_end + 1; from_x++) { \ + COPY_PIXEL(LV_COLOR_DEPTH, to + to_index, from + from_index); \ + from_index += from_bytes_per_piexl; \ + to_index += to_bytes_per_line; \ + } \ + } \ + } + +__attribute__((always_inline)) +IRAM_ATTR static inline void rotate_copy_pixel( + const uint8_t *from, uint8_t *to, uint16_t x_start, uint16_t y_start, uint16_t x_end, uint16_t y_end, uint16_t w, + uint16_t h, uint16_t rotate +) +{ + int from_bytes_per_piexl = sizeof(lv_color_t); + int from_bytes_per_line = w * from_bytes_per_piexl; int from_index = 0; + int from_index_const = 0; + + int to_bytes_per_piexl = LV_COLOR_DEPTH >> 3; + int to_bytes_per_line; int to_index = 0; int to_index_const = 0; +#if (LV_COLOR_DEPTH == 16) && LVGL_PORT_ENABLE_ROTATION_OPTIMIZED + int max_height = 0; + int max_width = 0; + int start_y = 0; + uint16_t *from_next = NULL; +#endif + + uint32_t time = esp_log_timestamp(); switch (rotate) { case 90: - 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; - 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; - } - } +#if (LV_COLOR_DEPTH == 16) && LVGL_PORT_ENABLE_ROTATION_OPTIMIZED + ROTATE_90_OPTIMIZED_16BPP(32, 256); +#else + ROTATE_90_ALL_BPP(); +#endif break; case 180: - to_index_const = h * w - x_start - 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 * w; - for (int from_x = x_start; from_x < x_end + 1; from_x++) { - *(to + to_index) = *(from + from_index); - from_index += 1; - to_index -= 1; - } - } + ROTATE_180_ALL_BPP(); break; case 270: - 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; - 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; - } - } +#if (LV_COLOR_DEPTH == 16) && LVGL_PORT_ENABLE_ROTATION_OPTIMIZED + ROTATE_270_OPTIMIZED_16BPP(32, 256); +#else + ROTATE_270_ALL_BPP(); +#endif break; default: break; } + ESP_LOGI(TAG, "rotate: end, time used:%d", (int)(esp_log_timestamp() - time)); } #endif /* LVGL_PORT_ROTATION_DEGREE */ @@ -174,8 +289,10 @@ static void flush_dirty_copy(void *dst, void *src, lv_port_dirty_area_t *dirty_a y_start = dirty_area->inv_areas[i].y1; y_end = dirty_area->inv_areas[i].y2; - rotate_copy_pixel((lv_color_t *)src, (lv_color_t *)dst, x_start, y_start, x_end, y_end, LV_HOR_RES, LV_VER_RES, - LVGL_PORT_ROTATION_DEGREE); + rotate_copy_pixel( + (uint8_t *)src, (uint8_t *)dst, x_start, y_start, x_end, y_end, LV_HOR_RES, LV_VER_RES, + LVGL_PORT_ROTATION_DEGREE + ); } } } @@ -200,10 +317,12 @@ static void flush_callback(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t // Rotate and copy data from the whole screen LVGL's buffer to the next frame buffer next_fb = flush_get_next_buf(lcd); - rotate_copy_pixel((lv_color_t *)color_map, (lv_color_t *)next_fb, offsetx1, offsety1, offsetx2, offsety2, - LV_HOR_RES, LV_VER_RES, LVGL_PORT_ROTATION_DEGREE); + rotate_copy_pixel( + (uint8_t *)color_map, (uint8_t *)next_fb, offsetx1, offsety1, offsetx2, offsety2, + LV_HOR_RES, LV_VER_RES, LVGL_PORT_ROTATION_DEGREE + ); - /* Switch the current RGB frame buffer to `next_fb` */ + /* Switch the current LCD frame buffer to `next_fb` */ lcd->drawBitmap(offsetx1, offsety1, offsetx2 - offsetx1 + 1, offsety2 - offsety1 + 1, (const uint8_t *)next_fb); /* Waiting for the current frame buffer to complete transmission */ @@ -234,7 +353,7 @@ static void flush_callback(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t flush_dirty_save(&dirty_area); flush_dirty_copy(next_fb, color_map, &dirty_area); - /* Switch the current RGB frame buffer to `next_fb` */ + /* Switch the current LCD frame buffer to `next_fb` */ lcd->drawBitmap(offsetx1, offsety1, offsetx2 - offsetx1 + 1, offsety2 - offsety1 + 1, (const uint8_t *)next_fb); /* Waiting for the current frame buffer to complete transmission */ @@ -266,7 +385,7 @@ static void flush_callback(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t /* Action after last area refresh */ if (lv_disp_flush_is_last(drv)) { - /* Switch the current RGB frame buffer to `color_map` */ + /* Switch the current LCD frame buffer to `color_map` */ lcd->drawBitmap(offsetx1, offsety1, offsetx2 - offsetx1 + 1, offsety2 - offsety1 + 1, (const uint8_t *)color_map); /* Waiting for the last frame buffer to complete transmission */ @@ -288,7 +407,7 @@ 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; - /* Switch the current RGB frame buffer to `color_map` */ + /* Switch the current LCD frame buffer to `color_map` */ lcd->drawBitmap(offsetx1, offsety1, offsetx2 - offsetx1 + 1, offsety2 - offsety1 + 1, (const uint8_t *)color_map); /* Waiting for the last frame buffer to complete transmission */ @@ -301,8 +420,8 @@ static void flush_callback(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t #elif LVGL_PORT_FULL_REFRESH && LVGL_PORT_DISP_BUFFER_NUM == 3 #if LVGL_PORT_ROTATION_DEGREE == 0 -static void *lvgl_port_rgb_last_buf = NULL; -static void *lvgl_port_rgb_next_buf = NULL; +static void *lvgl_port_lcd_last_buf = NULL; +static void *lvgl_port_lcd_next_buf = NULL; static void *lvgl_port_flush_next_buf = NULL; #endif @@ -317,38 +436,38 @@ void flush_callback(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color #if LVGL_PORT_ROTATION_DEGREE != 0 void *next_fb = get_next_frame_buffer(lcd); - /* Rotate and copy dirty area from the current LVGL's buffer to the next RGB frame buffer */ + /* Rotate and copy dirty area from the current LVGL's buffer to the next LCD frame buffer */ rotate_copy_pixel((lv_color_t *)color_map, (lv_color_t *)next_fb, offsetx1, offsety1, offsetx2, offsety2, LV_HOR_RES, LV_VER_RES, LVGL_PORT_ROTATION_DEGREE); - /* Switch the current RGB frame buffer to `next_fb` */ + /* Switch the current LCD frame buffer to `next_fb` */ lcd->drawBitmap(offsetx1, offsety1, offsetx2 - offsetx1 + 1, offsety2 - offsety1 + 1, (const uint8_t *)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; - /* Switch the current RGB frame buffer to `color_map` */ + /* Switch the current LCD frame buffer to `color_map` */ lcd->drawBitmap(offsetx1, offsety1, offsetx2 - offsetx1 + 1, offsety2 - offsety1 + 1, (const uint8_t *)color_map); - lvgl_port_rgb_next_buf = color_map; + lvgl_port_lcd_next_buf = color_map; #endif lv_disp_flush_ready(drv); } #endif -IRAM_ATTR bool onRgbVsyncCallback(void *user_data) +IRAM_ATTR bool onLcdVsyncCallback(void *user_data) { BaseType_t need_yield = pdFALSE; #if LVGL_PORT_FULL_REFRESH && (LVGL_PORT_DISP_BUFFER_NUM == 3) && (LVGL_PORT_ROTATION_DEGREE == 0) - if (lvgl_port_rgb_next_buf != lvgl_port_rgb_last_buf) { - lvgl_port_flush_next_buf = lvgl_port_rgb_last_buf; - lvgl_port_rgb_last_buf = lvgl_port_rgb_next_buf; + if (lvgl_port_lcd_next_buf != lvgl_port_lcd_last_buf) { + lvgl_port_flush_next_buf = lvgl_port_lcd_last_buf; + lvgl_port_lcd_last_buf = lvgl_port_lcd_next_buf; } #else TaskHandle_t task_handle = (TaskHandle_t)user_data; - // Notify that the current RGB frame buffer has been transmitted + // Notify that the current LCD frame buffer has been transmitted xTaskNotifyFromISR(task_handle, ULONG_MAX, eNoAction, &need_yield); #endif return (need_yield == pdTRUE); @@ -441,7 +560,6 @@ static lv_disp_t *display_init(ESP_PanelLcd *lcd) static lv_disp_drv_t disp_drv; // Alloc draw buffers used by LVGL - void *buf[LVGL_PORT_BUFFER_NUM_MAX] = { nullptr }; int buffer_size = 0; ESP_LOGD(TAG, "Malloc memory for LVGL buffer"); @@ -449,38 +567,38 @@ static lv_disp_t *display_init(ESP_PanelLcd *lcd) // Avoid tearing function is disabled buffer_size = LVGL_PORT_BUFFER_SIZE; for (int i = 0; (i < LVGL_PORT_BUFFER_NUM) && (i < LVGL_PORT_BUFFER_NUM_MAX); i++) { - buf[i] = heap_caps_malloc(buffer_size * sizeof(lv_color_t), LVGL_PORT_BUFFER_MALLOC_CAPS); - assert(buf[i]); - ESP_LOGD(TAG, "Buffer[%d] address: %p, size: %d", i, buf[i], buffer_size * sizeof(lv_color_t)); + lvgl_buf[i] = heap_caps_malloc(buffer_size * sizeof(lv_color_t), LVGL_PORT_BUFFER_MALLOC_CAPS); + assert(lvgl_buf[i]); + ESP_LOGD(TAG, "Buffer[%d] address: %p, size: %d", i, lvgl_buf[i], buffer_size * sizeof(lv_color_t)); } #else - // To avoid the tearing effect, we should use at least two frame buffers: one for LVGL rendering and another for RGB output + // To avoid the tearing effect, we should use at least two frame buffers: one for LVGL rendering and another for LCD refresh buffer_size = LVGL_PORT_DISP_WIDTH * LVGL_PORT_DISP_HEIGHT; #if (LVGL_PORT_DISP_BUFFER_NUM >= 3) && (LVGL_PORT_ROTATION_DEGREE == 0) && LVGL_PORT_FULL_REFRESH // With the usage of three buffers and full-refresh, we always have one buffer available for rendering, - // eliminating the need to wait for the RGB's sync signal - lvgl_port_rgb_last_buf = lcd->getRgbBufferByIndex(0); - buf[0] = lcd->getRgbBufferByIndex(1); - buf[1] = lcd->getRgbBufferByIndex(2); - lvgl_port_rgb_next_buf = lvgl_port_rgb_last_buf; - lvgl_port_flush_next_buf = buf[1]; + // eliminating the need to wait for the LCD's sync signal + lvgl_port_lcd_last_buf = lcd->getFrameBufferByIndex(0); + lvgl_buf[0] = lcd->getFrameBufferByIndex(1); + lvgl_buf[1] = lcd->getFrameBufferByIndex(2); + lvgl_port_lcd_next_buf = lvgl_port_lcd_last_buf; + lvgl_port_flush_next_buf = lvgl_buf[1]; #elif (LVGL_PORT_DISP_BUFFER_NUM >= 3) && (LVGL_PORT_ROTATION_DEGREE != 0) - buf[0] = lcd->getRgbBufferByIndex(2); + lvgl_buf[0] = lcd->getFrameBufferByIndex(2); #elif LVGL_PORT_DISP_BUFFER_NUM >= 2 for (int i = 0; (i < LVGL_PORT_DISP_BUFFER_NUM) && (i < LVGL_PORT_BUFFER_NUM_MAX); i++) { - buf[i] = lcd->getRgbBufferByIndex(i); + lvgl_buf[i] = lcd->getFrameBufferByIndex(i); } #endif #endif /* LVGL_PORT_AVOID_TEAR */ // initialize LVGL draw buffers - lv_disp_draw_buf_init(&disp_buf, buf[0], buf[1], buffer_size); + lv_disp_draw_buf_init(&disp_buf, lvgl_buf[0], lvgl_buf[1], buffer_size); ESP_LOGD(TAG, "Register display driver to LVGL"); lv_disp_drv_init(&disp_drv); @@ -550,16 +668,33 @@ static void tick_increment(void *arg) lv_tick_inc(LVGL_PORT_TICK_PERIOD_MS); } -static esp_err_t tick_init(void) +static bool tick_init(void) { // Tick interface for LVGL (using esp_timer to generate 2ms periodic event) const esp_timer_create_args_t lvgl_tick_timer_args = { .callback = &tick_increment, .name = "LVGL tick" }; - esp_timer_handle_t lvgl_tick_timer = NULL; - ESP_ERROR_CHECK(esp_timer_create(&lvgl_tick_timer_args, &lvgl_tick_timer)); - return esp_timer_start_periodic(lvgl_tick_timer, LVGL_PORT_TICK_PERIOD_MS * 1000); + ESP_PANEL_CHECK_ERR_RET( + esp_timer_create(&lvgl_tick_timer_args, &lvgl_tick_timer), false, "Create LVGL tick timer failed" + ); + ESP_PANEL_CHECK_ERR_RET( + esp_timer_start_periodic(lvgl_tick_timer, LVGL_PORT_TICK_PERIOD_MS * 1000), false, + "Start LVGL tick timer failed" + ); + + return true; +} + +static bool tick_deinit(void) +{ + ESP_PANEL_CHECK_ERR_RET( + esp_timer_stop(lvgl_tick_timer), false, "Stop LVGL tick timer failed" + ); + ESP_PANEL_CHECK_ERR_RET( + esp_timer_delete(lvgl_tick_timer), false, "Delete LVGL tick timer failed" + ); + return true; } #endif @@ -582,7 +717,7 @@ static void lvgl_port_task(void *arg) } } -IRAM_ATTR bool onRefreshFinishCallback(void *user_data) +IRAM_ATTR bool onDrawBitmapFinishCallback(void *user_data) { lv_disp_drv_t *drv = (lv_disp_drv_t *)user_data; @@ -594,9 +729,14 @@ IRAM_ATTR bool onRefreshFinishCallback(void *user_data) bool lvgl_port_init(ESP_PanelLcd *lcd, ESP_PanelTouch *tp) { ESP_PANEL_CHECK_FALSE_RET(lcd != nullptr, false, "Invalid LCD device"); + + auto bus_type = lcd->getBus()->getType(); #if LVGL_PORT_AVOID_TEAR - ESP_PANEL_CHECK_FALSE_RET(lcd->getBus()->getType() == ESP_PANEL_BUS_TYPE_RGB, false, "Avoid tearing function only works with RGB LCD now"); - ESP_LOGD(TAG, "Avoid tearing is enabled, mode: %d", LVGL_PORT_AVOID_TEARING_MODE); + ESP_PANEL_CHECK_FALSE_RET( + (bus_type == ESP_PANEL_BUS_TYPE_RGB) || (bus_type == ESP_PANEL_BUS_TYPE_MIPI_DSI), false, + "Avoid tearing function only works with RGB/MIPI-DSI LCD now" + ); + ESP_LOGI(TAG, "Avoid tearing is enabled, mode: %d", LVGL_PORT_AVOID_TEARING_MODE); #endif lv_disp_t *disp = nullptr; @@ -604,7 +744,7 @@ bool lvgl_port_init(ESP_PanelLcd *lcd, ESP_PanelTouch *tp) lv_init(); #if !LV_TICK_CUSTOM - ESP_PANEL_CHECK_ERR_RET(tick_init(), false, "Initialize LVGL tick failed"); + ESP_PANEL_CHECK_FALSE_RET(tick_init(), false, "Initialize LVGL tick failed"); #endif ESP_LOGD(TAG, "Initialize LVGL display driver"); @@ -614,9 +754,9 @@ bool lvgl_port_init(ESP_PanelLcd *lcd, ESP_PanelTouch *tp) lv_disp_set_rotation(disp, LV_DISP_ROT_NONE); // For non-RGB LCD, need to notify LVGL that the buffer is ready when the refresh is finished - if (lcd->getBus()->getType() != ESP_PANEL_BUS_TYPE_RGB) { + if (bus_type != ESP_PANEL_BUS_TYPE_RGB) { ESP_LOGD(TAG, "Attach refresh finish callback to LCD"); - lcd->attachRefreshFinishCallback(onRefreshFinishCallback, (void *)disp->driver); + lcd->attachDrawBitmapFinishCallback(onDrawBitmapFinishCallback, (void *)disp->driver); } if (tp != nullptr) { @@ -647,7 +787,7 @@ bool lvgl_port_init(ESP_PanelLcd *lcd, ESP_PanelTouch *tp) ESP_PANEL_CHECK_FALSE_RET(ret == pdPASS, false, "Create LVGL task failed"); #if LVGL_PORT_AVOID_TEAR - lcd->attachRefreshFinishCallback(onRgbVsyncCallback, (void *)lvgl_task_handle); + lcd->attachRefreshFinishCallback(onLcdVsyncCallback, (void *)lvgl_task_handle); #endif return true; @@ -669,3 +809,35 @@ bool lvgl_port_unlock(void) return true; } + +bool lvgl_port_deinit(void) +{ +#if !LV_TICK_CUSTOM + ESP_PANEL_CHECK_FALSE_RET(tick_deinit(), false, "Deinitialize LVGL tick failed"); +#endif + + ESP_PANEL_CHECK_FALSE_RET(lvgl_port_lock(-1), false, "Lock LVGL failed"); + if (lvgl_task_handle != nullptr) { + vTaskDelete(lvgl_task_handle); + lvgl_task_handle = nullptr; + } + ESP_PANEL_CHECK_FALSE_RET(lvgl_port_unlock(), false, "Unlock LVGL failed"); + +#if LV_ENABLE_GC || !LV_MEM_CUSTOM + lv_deinit(); +#endif +#if !LVGL_PORT_AVOID_TEAR + for (int i = 0; i < LVGL_PORT_BUFFER_NUM; i++) { + if (lvgl_buf[i] != nullptr) { + free(lvgl_buf[i]); + lvgl_buf[i] = nullptr; + } + } +#endif + if (lvgl_mux != nullptr) { + vSemaphoreDelete(lvgl_mux); + lvgl_mux = nullptr; + } + + return true; +} diff --git a/examples/Panel/PanelTest/ESP_Panel_Board_Custom.h b/examples/Panel/PanelTest/ESP_Panel_Board_Custom.h index 3ae31b50..dfd5e727 100644 --- a/examples/Panel/PanelTest/ESP_Panel_Board_Custom.h +++ b/examples/Panel/PanelTest/ESP_Panel_Board_Custom.h @@ -110,8 +110,6 @@ // |--------------|---------------| #define ESP_PANEL_LCD_RGB_DATA_WIDTH (16) // | 8 | 16 | #define ESP_PANEL_LCD_RGB_PIXEL_BITS (16) // | 24 | 16 | - - #define ESP_PANEL_LCD_RGB_FRAME_BUF_NUM (1) // 1/2/3 #define ESP_PANEL_LCD_RGB_BOUNCE_BUF_SIZE (0) // Bounce buffer size in bytes. This function is used to avoid screen drift. // To enable the bounce buffer, set it to a non-zero value. Typically set to `ESP_PANEL_LCD_WIDTH * 10` // The size of the Bounce Buffer must satisfy `width_of_lcd * height_of_lcd = size_of_buffer * N`, @@ -121,7 +119,6 @@ #define ESP_PANEL_LCD_RGB_IO_DE (17) // -1 if not used #define ESP_PANEL_LCD_RGB_IO_PCLK (9) #define ESP_PANEL_LCD_RGB_IO_DISP (-1) // -1 if not used - // | RGB565 | RGB666 | RGB888 | // |--------|--------|--------| #define ESP_PANEL_LCD_RGB_IO_DATA0 (10) // | B0 | B0-1 | B0-3 | @@ -158,6 +155,22 @@ // The `mirror()` function will be implemented by LCD command if set to 1. #endif +#elif ESP_PANEL_LCD_BUS_TYPE == ESP_PANEL_BUS_TYPE_MIPI_DSI + + #define ESP_PANEL_LCD_MIPI_DSI_LANE_NUM (2) // ESP32-P4 supports 1 or 2 lanes + #define ESP_PANEL_LCD_MIPI_DSI_LANE_RATE_MBPS (1000) // Single lane bit rate, should consult the LCD supplier or check the + // LCD drive IC datasheet for the supported lane rate. + // ESP32-P4 supports max 1500Mbps + #define ESP_PANEL_LCD_MIPI_DSI_PHY_LDO_ID (3) // -1 if not used + #define ESP_PANEL_LCD_MIPI_DPI_CLK_MHZ (52) + #define ESP_PANEL_LCD_MIPI_DPI_PIXEL_BITS (ESP_PANEL_LCD_RGB565_COLOR_BITS_16) + #define ESP_PANEL_LCD_MIPI_DSI_HPW (10) + #define ESP_PANEL_LCD_MIPI_DSI_HBP (160) + #define ESP_PANEL_LCD_MIPI_DSI_HFP (160) + #define ESP_PANEL_LCD_MIPI_DSI_VPW (1) + #define ESP_PANEL_LCD_MIPI_DSI_VBP (23) + #define ESP_PANEL_LCD_MIPI_DSI_VFP (12) + #else #error "The function is not ready and will be implemented in the future." @@ -380,8 +393,8 @@ * */ #define ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_MAJOR 0 -#define ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_MINOR 2 -#define ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_PATCH 3 +#define ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_MINOR 3 +#define ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_PATCH 0 #endif /* ESP_PANEL_USE_CUSTOM_BOARD */ diff --git a/examples/Panel/PanelTest/ESP_Panel_Board_Supported.h b/examples/Panel/PanelTest/ESP_Panel_Board_Supported.h index 603e59bd..75d5c84a 100644 --- a/examples/Panel/PanelTest/ESP_Panel_Board_Supported.h +++ b/examples/Panel/PanelTest/ESP_Panel_Board_Supported.h @@ -31,6 +31,7 @@ * - BOARD_ESP32_S3_LCD_EV_BOARD_2 (ESP32-S3-LCD-EV-Board-2(v1.1-v1.4))): https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32s3/esp32-s3-lcd-ev-board/user_guide_v1.4.html * - BOARD_ESP32_S3_LCD_EV_BOARD_2_V1_5 (ESP32-S3-LCD-EV-Board-2(v1.5)): https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32s3/esp32-s3-lcd-ev-board/user_guide.html * - BOARD_ESP32_S3_USB_OTG (ESP32-S3-USB-OTG): https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32s3/esp32-s3-usb-otg/index.html + * - BOARD_ESP32_P4_FUNCTION_EV_BOARD (ESP32-P4-Function-EV-Board): https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32p4/esp32-p4-function-ev-board/index.html * */ // #define BOARD_ESP32_C3_LCDKIT @@ -45,6 +46,7 @@ // #define BOARD_ESP32_S3_LCD_EV_BOARD_2 // #define BOARD_ESP32_S3_LCD_EV_BOARD_2_V1_5 // #define BOARD_ESP32_S3_USB_OTG +// #define BOARD_ESP32_P4_FUNCTION_EV_BOARD /* * Elecrow (https://www.elecrow.com): @@ -101,7 +103,7 @@ * */ #define ESP_PANEL_BOARD_SUPPORTED_FILE_VERSION_MAJOR 0 -#define ESP_PANEL_BOARD_SUPPORTED_FILE_VERSION_MINOR 5 -#define ESP_PANEL_BOARD_SUPPORTED_FILE_VERSION_PATCH 1 +#define ESP_PANEL_BOARD_SUPPORTED_FILE_VERSION_MINOR 6 +#define ESP_PANEL_BOARD_SUPPORTED_FILE_VERSION_PATCH 0 #endif diff --git a/examples/Panel/PanelTest/PanelTest.ino b/examples/Panel/PanelTest/PanelTest.ino index 30110db3..2f9b29bd 100644 --- a/examples/Panel/PanelTest/PanelTest.ino +++ b/examples/Panel/PanelTest/PanelTest.ino @@ -9,12 +9,12 @@ * * 1. For **ESP32_Display_Panel**: * - * - Follow the [steps](https://github.com/esp-arduino-libs/ESP32_Display_Panel/docs/How_To_Use.md#configuring-drivers) to configure drivers if needed. - * - If using a supported development board, follow the [steps](https://github.com/esp-arduino-libs/ESP32_Display_Panel/docs/How_To_Use.md#using-supported-development-boards) to configure it. - * - If using a custom board, follow the [steps](https://github.com/esp-arduino-libs/ESP32_Display_Panel/docs/How_To_Use.md#using-custom-development-boards) to configure it. + * - Follow the [steps](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/How_To_Use.md#configuring-drivers) to configure drivers if needed. + * - If using a supported development board, follow the [steps](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/How_To_Use.md#using-supported-development-boards) to configure it. + * - If using a custom board, follow the [steps](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/How_To_Use.md#using-custom-development-boards) to configure it. * * 2. Navigate to the `Tools` menu in the Arduino IDE to choose a ESP board and configure its parameters. For supported - * boards, please refter to [Configuring Supported Development Boards](https://github.com/esp-arduino-libs/ESP32_Display_Panel/docs/How_To_Use.md#configuring-supported-development-boards) + * boards, please refter to [Configuring Supported Development Boards](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/How_To_Use.md#configuring-supported-development-boards) * 3. Verify and upload the example to your ESP board. * * ## Serial Output @@ -36,7 +36,7 @@ * * ## Troubleshooting * - * Please check the [FAQ](https://github.com/esp-arduino-libs/ESP32_Display_Panel/docs/faq.md) first to see if the same question exists. If not, please create a [Github issue](https://github.com/esp-arduino-libs/ESP32_Display_Panel/issues). We will get back to you as soon as possible. + * Please check the [FAQ](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/FAQ.md) first to see if the same question exists. If not, please create a [Github issue](https://github.com/esp-arduino-libs/ESP32_Display_Panel/issues). We will get back to you as soon as possible. * */ diff --git a/examples/PlatformIO/src/ESP_Panel_Board_Custom.h b/examples/PlatformIO/src/ESP_Panel_Board_Custom.h index 3ae31b50..dfd5e727 100644 --- a/examples/PlatformIO/src/ESP_Panel_Board_Custom.h +++ b/examples/PlatformIO/src/ESP_Panel_Board_Custom.h @@ -110,8 +110,6 @@ // |--------------|---------------| #define ESP_PANEL_LCD_RGB_DATA_WIDTH (16) // | 8 | 16 | #define ESP_PANEL_LCD_RGB_PIXEL_BITS (16) // | 24 | 16 | - - #define ESP_PANEL_LCD_RGB_FRAME_BUF_NUM (1) // 1/2/3 #define ESP_PANEL_LCD_RGB_BOUNCE_BUF_SIZE (0) // Bounce buffer size in bytes. This function is used to avoid screen drift. // To enable the bounce buffer, set it to a non-zero value. Typically set to `ESP_PANEL_LCD_WIDTH * 10` // The size of the Bounce Buffer must satisfy `width_of_lcd * height_of_lcd = size_of_buffer * N`, @@ -121,7 +119,6 @@ #define ESP_PANEL_LCD_RGB_IO_DE (17) // -1 if not used #define ESP_PANEL_LCD_RGB_IO_PCLK (9) #define ESP_PANEL_LCD_RGB_IO_DISP (-1) // -1 if not used - // | RGB565 | RGB666 | RGB888 | // |--------|--------|--------| #define ESP_PANEL_LCD_RGB_IO_DATA0 (10) // | B0 | B0-1 | B0-3 | @@ -158,6 +155,22 @@ // The `mirror()` function will be implemented by LCD command if set to 1. #endif +#elif ESP_PANEL_LCD_BUS_TYPE == ESP_PANEL_BUS_TYPE_MIPI_DSI + + #define ESP_PANEL_LCD_MIPI_DSI_LANE_NUM (2) // ESP32-P4 supports 1 or 2 lanes + #define ESP_PANEL_LCD_MIPI_DSI_LANE_RATE_MBPS (1000) // Single lane bit rate, should consult the LCD supplier or check the + // LCD drive IC datasheet for the supported lane rate. + // ESP32-P4 supports max 1500Mbps + #define ESP_PANEL_LCD_MIPI_DSI_PHY_LDO_ID (3) // -1 if not used + #define ESP_PANEL_LCD_MIPI_DPI_CLK_MHZ (52) + #define ESP_PANEL_LCD_MIPI_DPI_PIXEL_BITS (ESP_PANEL_LCD_RGB565_COLOR_BITS_16) + #define ESP_PANEL_LCD_MIPI_DSI_HPW (10) + #define ESP_PANEL_LCD_MIPI_DSI_HBP (160) + #define ESP_PANEL_LCD_MIPI_DSI_HFP (160) + #define ESP_PANEL_LCD_MIPI_DSI_VPW (1) + #define ESP_PANEL_LCD_MIPI_DSI_VBP (23) + #define ESP_PANEL_LCD_MIPI_DSI_VFP (12) + #else #error "The function is not ready and will be implemented in the future." @@ -380,8 +393,8 @@ * */ #define ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_MAJOR 0 -#define ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_MINOR 2 -#define ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_PATCH 3 +#define ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_MINOR 3 +#define ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_PATCH 0 #endif /* ESP_PANEL_USE_CUSTOM_BOARD */ diff --git a/examples/PlatformIO/src/ESP_Panel_Board_Supported.h b/examples/PlatformIO/src/ESP_Panel_Board_Supported.h index 603e59bd..75d5c84a 100644 --- a/examples/PlatformIO/src/ESP_Panel_Board_Supported.h +++ b/examples/PlatformIO/src/ESP_Panel_Board_Supported.h @@ -31,6 +31,7 @@ * - BOARD_ESP32_S3_LCD_EV_BOARD_2 (ESP32-S3-LCD-EV-Board-2(v1.1-v1.4))): https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32s3/esp32-s3-lcd-ev-board/user_guide_v1.4.html * - BOARD_ESP32_S3_LCD_EV_BOARD_2_V1_5 (ESP32-S3-LCD-EV-Board-2(v1.5)): https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32s3/esp32-s3-lcd-ev-board/user_guide.html * - BOARD_ESP32_S3_USB_OTG (ESP32-S3-USB-OTG): https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32s3/esp32-s3-usb-otg/index.html + * - BOARD_ESP32_P4_FUNCTION_EV_BOARD (ESP32-P4-Function-EV-Board): https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32p4/esp32-p4-function-ev-board/index.html * */ // #define BOARD_ESP32_C3_LCDKIT @@ -45,6 +46,7 @@ // #define BOARD_ESP32_S3_LCD_EV_BOARD_2 // #define BOARD_ESP32_S3_LCD_EV_BOARD_2_V1_5 // #define BOARD_ESP32_S3_USB_OTG +// #define BOARD_ESP32_P4_FUNCTION_EV_BOARD /* * Elecrow (https://www.elecrow.com): @@ -101,7 +103,7 @@ * */ #define ESP_PANEL_BOARD_SUPPORTED_FILE_VERSION_MAJOR 0 -#define ESP_PANEL_BOARD_SUPPORTED_FILE_VERSION_MINOR 5 -#define ESP_PANEL_BOARD_SUPPORTED_FILE_VERSION_PATCH 1 +#define ESP_PANEL_BOARD_SUPPORTED_FILE_VERSION_MINOR 6 +#define ESP_PANEL_BOARD_SUPPORTED_FILE_VERSION_PATCH 0 #endif diff --git a/examples/PlatformIO/src/lvgl_port_v8.cpp b/examples/PlatformIO/src/lvgl_port_v8.cpp index cfd9f29d..7173f33e 100644 --- a/examples/PlatformIO/src/lvgl_port_v8.cpp +++ b/examples/PlatformIO/src/lvgl_port_v8.cpp @@ -3,16 +3,17 @@ * * SPDX-License-Identifier: CC0-1.0 */ -#include -#include -#include +#include "esp_timer.h" #include "lvgl_port_v8.h" +#define LVGL_PORT_ENABLE_ROTATION_OPTIMIZED (1) #define LVGL_PORT_BUFFER_NUM_MAX (2) static const char *TAG = "lvgl_port"; static SemaphoreHandle_t lvgl_mux = nullptr; // LVGL mutex static TaskHandle_t lvgl_task_handle = nullptr; +static esp_timer_handle_t lvgl_tick_timer = NULL; +static void *lvgl_buf[LVGL_PORT_BUFFER_NUM_MAX] = {}; #if LVGL_PORT_ROTATION_DEGREE != 0 static void *get_next_frame_buffer(ESP_PanelLcd *lcd) @@ -21,8 +22,8 @@ static void *get_next_frame_buffer(ESP_PanelLcd *lcd) static void *fbs[2] = { NULL }; if (next_fb == NULL) { - fbs[0] = lcd->getRgbBufferByIndex(0); - fbs[1] = lcd->getRgbBufferByIndex(1); + fbs[0] = lcd->getFrameBufferByIndex(0); + fbs[1] = lcd->getFrameBufferByIndex(1); next_fb = fbs[1]; } else { next_fb = (next_fb == fbs[0]) ? fbs[1] : fbs[0]; @@ -31,53 +32,167 @@ static void *get_next_frame_buffer(ESP_PanelLcd *lcd) return next_fb; } -IRAM_ATTR static void rotate_copy_pixel(const lv_color_t *from, lv_color_t *to, uint16_t x_start, uint16_t y_start, - uint16_t x_end, uint16_t y_end, uint16_t w, uint16_t h, uint16_t rotate) +__attribute__((always_inline)) +static inline void copy_pixel_8bpp(uint8_t *to, const uint8_t *from) { + *to++ = *from++; +} + +__attribute__((always_inline)) +static inline void copy_pixel_16bpp(uint8_t *to, const uint8_t *from) +{ + *(uint16_t *)to++ = *(const uint16_t *)from++; +} + +__attribute__((always_inline)) +static inline void copy_pixel_24bpp(uint8_t *to, const uint8_t *from) +{ + *to++ = *from++; + *to++ = *from++; + *to++ = *from++; +} + +#define _COPY_PIXEL(_bpp, to, from) copy_pixel_##_bpp##bpp(to, from) +#define COPY_PIXEL(_bpp, to, from) _COPY_PIXEL(_bpp, to, from) + +#define ROTATE_90_ALL_BPP() \ + { \ + to_bytes_per_line = h * to_bytes_per_piexl; \ + to_index_const = (w - x_start - 1) * to_bytes_per_line; \ + for (int from_y = y_start; from_y < y_end + 1; from_y++) { \ + from_index = from_y * from_bytes_per_line + x_start * from_bytes_per_piexl; \ + to_index = to_index_const + from_y * to_bytes_per_piexl; \ + for (int from_x = x_start; from_x < x_end + 1; from_x++) { \ + COPY_PIXEL(LV_COLOR_DEPTH, to + to_index, from + from_index); \ + from_index += from_bytes_per_piexl; \ + to_index -= to_bytes_per_line; \ + } \ + } \ + } + +/** + * @brief Optimized transpose function for RGB565 format. + * + * @note ESP32-P4 1024x600 full-screen: 738ms -> 34ms + * @note ESP32-S3 480x480 full-screen: 380ms -> 37ms + * + */ +#define ROTATE_90_OPTIMIZED_16BPP(block_w, block_h) \ + { \ + for (int i = 0; i < h; i += block_h) { \ + max_height = (i + block_h > h) ? h : (i + block_h); \ + for (int j = 0; j < w; j += block_w) { \ + max_width = (j + block_w > w) ? w : (j + block_w); \ + start_y = w - 1 - j; \ + for (int x = i; x < max_height; x++) { \ + from_next = (uint16_t *)from + x * w; \ + for (int y = j, mirrored_y = start_y; y < max_width; y += 4, mirrored_y -= 4) { \ + ((uint16_t *)to)[(mirrored_y) * h + x] = *((uint32_t *)(from_next + y)) & 0xFFFF; \ + ((uint16_t *)to)[(mirrored_y - 1) * h + x] = (*((uint32_t *)(from_next + y)) >> 16) & 0xFFFF; \ + ((uint16_t *)to)[(mirrored_y - 2) * h + x] = *((uint32_t *)(from_next + y + 2)) & 0xFFFF; \ + ((uint16_t *)to)[(mirrored_y - 3) * h + x] = (*((uint32_t *)(from_next + y + 2)) >> 16) & 0xFFFF; \ + } \ + } \ + } \ + } \ + } + +#define ROTATE_180_ALL_BPP() \ + { \ + to_bytes_per_line = w * to_bytes_per_piexl; \ + to_index_const = (h - 1) * to_bytes_per_line + (w - x_start - 1) * to_bytes_per_piexl; \ + for (int from_y = y_start; from_y < y_end + 1; from_y++) { \ + from_index = from_y * from_bytes_per_line + x_start * from_bytes_per_piexl; \ + to_index = to_index_const - from_y * to_bytes_per_line; \ + for (int from_x = x_start; from_x < x_end + 1; from_x++) { \ + COPY_PIXEL(LV_COLOR_DEPTH, to + to_index, from + from_index); \ + from_index += from_bytes_per_piexl; \ + to_index -= to_bytes_per_piexl; \ + } \ + } \ + } + +#define ROTATE_270_OPTIMIZED_16BPP(block_w, block_h) \ + { \ + for (int i = 0; i < h; i += block_h) { \ + max_height = i + block_h > h ? h : i + block_h; \ + for (int j = 0; j < w; j += block_w) { \ + max_width = j + block_w > w ? w : j + block_w; \ + for (int x = i; x < max_height; x++) { \ + from_next = (uint16_t *)from + x * w; \ + for (int y = j; y < max_width; y += 4) { \ + ((uint16_t *)to)[y * h + (h - 1 - x)] = *((uint32_t *)(from_next + y)) & 0xFFFF; \ + ((uint16_t *)to)[(y + 1) * h + (h - 1 - x)] = (*((uint32_t *)(from_next + y)) >> 16) & 0xFFFF; \ + ((uint16_t *)to)[(y + 2) * h + (h - 1 - x)] = *((uint32_t *)(from_next + y + 2)) & 0xFFFF; \ + ((uint16_t *)to)[(y + 3) * h + (h - 1 - x)] = (*((uint32_t *)(from_next + y + 2)) >> 16) & 0xFFFF; \ + } \ + } \ + } \ + } \ + } + +#define ROTATE_270_ALL_BPP() \ + { \ + to_bytes_per_line = h * to_bytes_per_piexl; \ + from_index_const = x_start * from_bytes_per_piexl; \ + to_index_const = x_start * to_bytes_per_line + (h - 1) * to_bytes_per_piexl; \ + for (int from_y = y_start; from_y < y_end + 1; from_y++) { \ + from_index = from_y * from_bytes_per_line + from_index_const; \ + to_index = to_index_const - from_y * to_bytes_per_piexl; \ + for (int from_x = x_start; from_x < x_end + 1; from_x++) { \ + COPY_PIXEL(LV_COLOR_DEPTH, to + to_index, from + from_index); \ + from_index += from_bytes_per_piexl; \ + to_index += to_bytes_per_line; \ + } \ + } \ + } + +__attribute__((always_inline)) +IRAM_ATTR static inline void rotate_copy_pixel( + const uint8_t *from, uint8_t *to, uint16_t x_start, uint16_t y_start, uint16_t x_end, uint16_t y_end, uint16_t w, + uint16_t h, uint16_t rotate +) +{ + int from_bytes_per_piexl = sizeof(lv_color_t); + int from_bytes_per_line = w * from_bytes_per_piexl; int from_index = 0; + int from_index_const = 0; + + int to_bytes_per_piexl = LV_COLOR_DEPTH >> 3; + int to_bytes_per_line; int to_index = 0; int to_index_const = 0; +#if (LV_COLOR_DEPTH == 16) && LVGL_PORT_ENABLE_ROTATION_OPTIMIZED + int max_height = 0; + int max_width = 0; + int start_y = 0; + uint16_t *from_next = NULL; +#endif + + uint32_t time = esp_log_timestamp(); switch (rotate) { case 90: - 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; - 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; - } - } +#if (LV_COLOR_DEPTH == 16) && LVGL_PORT_ENABLE_ROTATION_OPTIMIZED + ROTATE_90_OPTIMIZED_16BPP(32, 256); +#else + ROTATE_90_ALL_BPP(); +#endif break; case 180: - to_index_const = h * w - x_start - 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 * w; - for (int from_x = x_start; from_x < x_end + 1; from_x++) { - *(to + to_index) = *(from + from_index); - from_index += 1; - to_index -= 1; - } - } + ROTATE_180_ALL_BPP(); break; case 270: - 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; - 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; - } - } +#if (LV_COLOR_DEPTH == 16) && LVGL_PORT_ENABLE_ROTATION_OPTIMIZED + ROTATE_270_OPTIMIZED_16BPP(32, 256); +#else + ROTATE_270_ALL_BPP(); +#endif break; default: break; } + ESP_LOGI(TAG, "rotate: end, time used:%d", (int)(esp_log_timestamp() - time)); } #endif /* LVGL_PORT_ROTATION_DEGREE */ @@ -174,8 +289,10 @@ static void flush_dirty_copy(void *dst, void *src, lv_port_dirty_area_t *dirty_a y_start = dirty_area->inv_areas[i].y1; y_end = dirty_area->inv_areas[i].y2; - rotate_copy_pixel((lv_color_t *)src, (lv_color_t *)dst, x_start, y_start, x_end, y_end, LV_HOR_RES, LV_VER_RES, - LVGL_PORT_ROTATION_DEGREE); + rotate_copy_pixel( + (uint8_t *)src, (uint8_t *)dst, x_start, y_start, x_end, y_end, LV_HOR_RES, LV_VER_RES, + LVGL_PORT_ROTATION_DEGREE + ); } } } @@ -200,10 +317,12 @@ static void flush_callback(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t // Rotate and copy data from the whole screen LVGL's buffer to the next frame buffer next_fb = flush_get_next_buf(lcd); - rotate_copy_pixel((lv_color_t *)color_map, (lv_color_t *)next_fb, offsetx1, offsety1, offsetx2, offsety2, - LV_HOR_RES, LV_VER_RES, LVGL_PORT_ROTATION_DEGREE); + rotate_copy_pixel( + (uint8_t *)color_map, (uint8_t *)next_fb, offsetx1, offsety1, offsetx2, offsety2, + LV_HOR_RES, LV_VER_RES, LVGL_PORT_ROTATION_DEGREE + ); - /* Switch the current RGB frame buffer to `next_fb` */ + /* Switch the current LCD frame buffer to `next_fb` */ lcd->drawBitmap(offsetx1, offsety1, offsetx2 - offsetx1 + 1, offsety2 - offsety1 + 1, (const uint8_t *)next_fb); /* Waiting for the current frame buffer to complete transmission */ @@ -234,7 +353,7 @@ static void flush_callback(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t flush_dirty_save(&dirty_area); flush_dirty_copy(next_fb, color_map, &dirty_area); - /* Switch the current RGB frame buffer to `next_fb` */ + /* Switch the current LCD frame buffer to `next_fb` */ lcd->drawBitmap(offsetx1, offsety1, offsetx2 - offsetx1 + 1, offsety2 - offsety1 + 1, (const uint8_t *)next_fb); /* Waiting for the current frame buffer to complete transmission */ @@ -266,7 +385,7 @@ static void flush_callback(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t /* Action after last area refresh */ if (lv_disp_flush_is_last(drv)) { - /* Switch the current RGB frame buffer to `color_map` */ + /* Switch the current LCD frame buffer to `color_map` */ lcd->drawBitmap(offsetx1, offsety1, offsetx2 - offsetx1 + 1, offsety2 - offsety1 + 1, (const uint8_t *)color_map); /* Waiting for the last frame buffer to complete transmission */ @@ -288,7 +407,7 @@ 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; - /* Switch the current RGB frame buffer to `color_map` */ + /* Switch the current LCD frame buffer to `color_map` */ lcd->drawBitmap(offsetx1, offsety1, offsetx2 - offsetx1 + 1, offsety2 - offsety1 + 1, (const uint8_t *)color_map); /* Waiting for the last frame buffer to complete transmission */ @@ -301,8 +420,8 @@ static void flush_callback(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t #elif LVGL_PORT_FULL_REFRESH && LVGL_PORT_DISP_BUFFER_NUM == 3 #if LVGL_PORT_ROTATION_DEGREE == 0 -static void *lvgl_port_rgb_last_buf = NULL; -static void *lvgl_port_rgb_next_buf = NULL; +static void *lvgl_port_lcd_last_buf = NULL; +static void *lvgl_port_lcd_next_buf = NULL; static void *lvgl_port_flush_next_buf = NULL; #endif @@ -317,38 +436,38 @@ void flush_callback(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color #if LVGL_PORT_ROTATION_DEGREE != 0 void *next_fb = get_next_frame_buffer(lcd); - /* Rotate and copy dirty area from the current LVGL's buffer to the next RGB frame buffer */ + /* Rotate and copy dirty area from the current LVGL's buffer to the next LCD frame buffer */ rotate_copy_pixel((lv_color_t *)color_map, (lv_color_t *)next_fb, offsetx1, offsety1, offsetx2, offsety2, LV_HOR_RES, LV_VER_RES, LVGL_PORT_ROTATION_DEGREE); - /* Switch the current RGB frame buffer to `next_fb` */ + /* Switch the current LCD frame buffer to `next_fb` */ lcd->drawBitmap(offsetx1, offsety1, offsetx2 - offsetx1 + 1, offsety2 - offsety1 + 1, (const uint8_t *)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; - /* Switch the current RGB frame buffer to `color_map` */ + /* Switch the current LCD frame buffer to `color_map` */ lcd->drawBitmap(offsetx1, offsety1, offsetx2 - offsetx1 + 1, offsety2 - offsety1 + 1, (const uint8_t *)color_map); - lvgl_port_rgb_next_buf = color_map; + lvgl_port_lcd_next_buf = color_map; #endif lv_disp_flush_ready(drv); } #endif -IRAM_ATTR bool onRgbVsyncCallback(void *user_data) +IRAM_ATTR bool onLcdVsyncCallback(void *user_data) { BaseType_t need_yield = pdFALSE; #if LVGL_PORT_FULL_REFRESH && (LVGL_PORT_DISP_BUFFER_NUM == 3) && (LVGL_PORT_ROTATION_DEGREE == 0) - if (lvgl_port_rgb_next_buf != lvgl_port_rgb_last_buf) { - lvgl_port_flush_next_buf = lvgl_port_rgb_last_buf; - lvgl_port_rgb_last_buf = lvgl_port_rgb_next_buf; + if (lvgl_port_lcd_next_buf != lvgl_port_lcd_last_buf) { + lvgl_port_flush_next_buf = lvgl_port_lcd_last_buf; + lvgl_port_lcd_last_buf = lvgl_port_lcd_next_buf; } #else TaskHandle_t task_handle = (TaskHandle_t)user_data; - // Notify that the current RGB frame buffer has been transmitted + // Notify that the current LCD frame buffer has been transmitted xTaskNotifyFromISR(task_handle, ULONG_MAX, eNoAction, &need_yield); #endif return (need_yield == pdTRUE); @@ -441,7 +560,6 @@ static lv_disp_t *display_init(ESP_PanelLcd *lcd) static lv_disp_drv_t disp_drv; // Alloc draw buffers used by LVGL - void *buf[LVGL_PORT_BUFFER_NUM_MAX] = { nullptr }; int buffer_size = 0; ESP_LOGD(TAG, "Malloc memory for LVGL buffer"); @@ -449,38 +567,38 @@ static lv_disp_t *display_init(ESP_PanelLcd *lcd) // Avoid tearing function is disabled buffer_size = LVGL_PORT_BUFFER_SIZE; for (int i = 0; (i < LVGL_PORT_BUFFER_NUM) && (i < LVGL_PORT_BUFFER_NUM_MAX); i++) { - buf[i] = heap_caps_malloc(buffer_size * sizeof(lv_color_t), LVGL_PORT_BUFFER_MALLOC_CAPS); - assert(buf[i]); - ESP_LOGD(TAG, "Buffer[%d] address: %p, size: %d", i, buf[i], buffer_size * sizeof(lv_color_t)); + lvgl_buf[i] = heap_caps_malloc(buffer_size * sizeof(lv_color_t), LVGL_PORT_BUFFER_MALLOC_CAPS); + assert(lvgl_buf[i]); + ESP_LOGD(TAG, "Buffer[%d] address: %p, size: %d", i, lvgl_buf[i], buffer_size * sizeof(lv_color_t)); } #else - // To avoid the tearing effect, we should use at least two frame buffers: one for LVGL rendering and another for RGB output + // To avoid the tearing effect, we should use at least two frame buffers: one for LVGL rendering and another for LCD refresh buffer_size = LVGL_PORT_DISP_WIDTH * LVGL_PORT_DISP_HEIGHT; #if (LVGL_PORT_DISP_BUFFER_NUM >= 3) && (LVGL_PORT_ROTATION_DEGREE == 0) && LVGL_PORT_FULL_REFRESH // With the usage of three buffers and full-refresh, we always have one buffer available for rendering, - // eliminating the need to wait for the RGB's sync signal - lvgl_port_rgb_last_buf = lcd->getRgbBufferByIndex(0); - buf[0] = lcd->getRgbBufferByIndex(1); - buf[1] = lcd->getRgbBufferByIndex(2); - lvgl_port_rgb_next_buf = lvgl_port_rgb_last_buf; - lvgl_port_flush_next_buf = buf[1]; + // eliminating the need to wait for the LCD's sync signal + lvgl_port_lcd_last_buf = lcd->getFrameBufferByIndex(0); + lvgl_buf[0] = lcd->getFrameBufferByIndex(1); + lvgl_buf[1] = lcd->getFrameBufferByIndex(2); + lvgl_port_lcd_next_buf = lvgl_port_lcd_last_buf; + lvgl_port_flush_next_buf = lvgl_buf[1]; #elif (LVGL_PORT_DISP_BUFFER_NUM >= 3) && (LVGL_PORT_ROTATION_DEGREE != 0) - buf[0] = lcd->getRgbBufferByIndex(2); + lvgl_buf[0] = lcd->getFrameBufferByIndex(2); #elif LVGL_PORT_DISP_BUFFER_NUM >= 2 for (int i = 0; (i < LVGL_PORT_DISP_BUFFER_NUM) && (i < LVGL_PORT_BUFFER_NUM_MAX); i++) { - buf[i] = lcd->getRgbBufferByIndex(i); + lvgl_buf[i] = lcd->getFrameBufferByIndex(i); } #endif #endif /* LVGL_PORT_AVOID_TEAR */ // initialize LVGL draw buffers - lv_disp_draw_buf_init(&disp_buf, buf[0], buf[1], buffer_size); + lv_disp_draw_buf_init(&disp_buf, lvgl_buf[0], lvgl_buf[1], buffer_size); ESP_LOGD(TAG, "Register display driver to LVGL"); lv_disp_drv_init(&disp_drv); @@ -550,16 +668,33 @@ static void tick_increment(void *arg) lv_tick_inc(LVGL_PORT_TICK_PERIOD_MS); } -static esp_err_t tick_init(void) +static bool tick_init(void) { // Tick interface for LVGL (using esp_timer to generate 2ms periodic event) const esp_timer_create_args_t lvgl_tick_timer_args = { .callback = &tick_increment, .name = "LVGL tick" }; - esp_timer_handle_t lvgl_tick_timer = NULL; - ESP_ERROR_CHECK(esp_timer_create(&lvgl_tick_timer_args, &lvgl_tick_timer)); - return esp_timer_start_periodic(lvgl_tick_timer, LVGL_PORT_TICK_PERIOD_MS * 1000); + ESP_PANEL_CHECK_ERR_RET( + esp_timer_create(&lvgl_tick_timer_args, &lvgl_tick_timer), false, "Create LVGL tick timer failed" + ); + ESP_PANEL_CHECK_ERR_RET( + esp_timer_start_periodic(lvgl_tick_timer, LVGL_PORT_TICK_PERIOD_MS * 1000), false, + "Start LVGL tick timer failed" + ); + + return true; +} + +static bool tick_deinit(void) +{ + ESP_PANEL_CHECK_ERR_RET( + esp_timer_stop(lvgl_tick_timer), false, "Stop LVGL tick timer failed" + ); + ESP_PANEL_CHECK_ERR_RET( + esp_timer_delete(lvgl_tick_timer), false, "Delete LVGL tick timer failed" + ); + return true; } #endif @@ -582,7 +717,7 @@ static void lvgl_port_task(void *arg) } } -IRAM_ATTR bool onRefreshFinishCallback(void *user_data) +IRAM_ATTR bool onDrawBitmapFinishCallback(void *user_data) { lv_disp_drv_t *drv = (lv_disp_drv_t *)user_data; @@ -594,9 +729,14 @@ IRAM_ATTR bool onRefreshFinishCallback(void *user_data) bool lvgl_port_init(ESP_PanelLcd *lcd, ESP_PanelTouch *tp) { ESP_PANEL_CHECK_FALSE_RET(lcd != nullptr, false, "Invalid LCD device"); + + auto bus_type = lcd->getBus()->getType(); #if LVGL_PORT_AVOID_TEAR - ESP_PANEL_CHECK_FALSE_RET(lcd->getBus()->getType() == ESP_PANEL_BUS_TYPE_RGB, false, "Avoid tearing function only works with RGB LCD now"); - ESP_LOGD(TAG, "Avoid tearing is enabled, mode: %d", LVGL_PORT_AVOID_TEARING_MODE); + ESP_PANEL_CHECK_FALSE_RET( + (bus_type == ESP_PANEL_BUS_TYPE_RGB) || (bus_type == ESP_PANEL_BUS_TYPE_MIPI_DSI), false, + "Avoid tearing function only works with RGB/MIPI-DSI LCD now" + ); + ESP_LOGI(TAG, "Avoid tearing is enabled, mode: %d", LVGL_PORT_AVOID_TEARING_MODE); #endif lv_disp_t *disp = nullptr; @@ -604,7 +744,7 @@ bool lvgl_port_init(ESP_PanelLcd *lcd, ESP_PanelTouch *tp) lv_init(); #if !LV_TICK_CUSTOM - ESP_PANEL_CHECK_ERR_RET(tick_init(), false, "Initialize LVGL tick failed"); + ESP_PANEL_CHECK_FALSE_RET(tick_init(), false, "Initialize LVGL tick failed"); #endif ESP_LOGD(TAG, "Initialize LVGL display driver"); @@ -614,9 +754,9 @@ bool lvgl_port_init(ESP_PanelLcd *lcd, ESP_PanelTouch *tp) lv_disp_set_rotation(disp, LV_DISP_ROT_NONE); // For non-RGB LCD, need to notify LVGL that the buffer is ready when the refresh is finished - if (lcd->getBus()->getType() != ESP_PANEL_BUS_TYPE_RGB) { + if (bus_type != ESP_PANEL_BUS_TYPE_RGB) { ESP_LOGD(TAG, "Attach refresh finish callback to LCD"); - lcd->attachRefreshFinishCallback(onRefreshFinishCallback, (void *)disp->driver); + lcd->attachDrawBitmapFinishCallback(onDrawBitmapFinishCallback, (void *)disp->driver); } if (tp != nullptr) { @@ -647,7 +787,7 @@ bool lvgl_port_init(ESP_PanelLcd *lcd, ESP_PanelTouch *tp) ESP_PANEL_CHECK_FALSE_RET(ret == pdPASS, false, "Create LVGL task failed"); #if LVGL_PORT_AVOID_TEAR - lcd->attachRefreshFinishCallback(onRgbVsyncCallback, (void *)lvgl_task_handle); + lcd->attachRefreshFinishCallback(onLcdVsyncCallback, (void *)lvgl_task_handle); #endif return true; @@ -669,3 +809,35 @@ bool lvgl_port_unlock(void) return true; } + +bool lvgl_port_deinit(void) +{ +#if !LV_TICK_CUSTOM + ESP_PANEL_CHECK_FALSE_RET(tick_deinit(), false, "Deinitialize LVGL tick failed"); +#endif + + ESP_PANEL_CHECK_FALSE_RET(lvgl_port_lock(-1), false, "Lock LVGL failed"); + if (lvgl_task_handle != nullptr) { + vTaskDelete(lvgl_task_handle); + lvgl_task_handle = nullptr; + } + ESP_PANEL_CHECK_FALSE_RET(lvgl_port_unlock(), false, "Unlock LVGL failed"); + +#if LV_ENABLE_GC || !LV_MEM_CUSTOM + lv_deinit(); +#endif +#if !LVGL_PORT_AVOID_TEAR + for (int i = 0; i < LVGL_PORT_BUFFER_NUM; i++) { + if (lvgl_buf[i] != nullptr) { + free(lvgl_buf[i]); + lvgl_buf[i] = nullptr; + } + } +#endif + if (lvgl_mux != nullptr) { + vSemaphoreDelete(lvgl_mux); + lvgl_mux = nullptr; + } + + return true; +} diff --git a/examples/PlatformIO/src/lvgl_port_v8.h b/examples/PlatformIO/src/lvgl_port_v8.h index b0e25ee1..c7b7cdf2 100644 --- a/examples/PlatformIO/src/lvgl_port_v8.h +++ b/examples/PlatformIO/src/lvgl_port_v8.h @@ -5,6 +5,7 @@ */ #pragma once +#include #include #include @@ -36,7 +37,7 @@ * - The number of buffers should be 1 or 2. * */ -#define LVGL_PORT_BUFFER_MALLOC_CAPS (MALLOC_CAP_INTERNAL) // Allocate LVGL buffer in SRAM +#define LVGL_PORT_BUFFER_MALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT) // Allocate LVGL buffer in SRAM // #define LVGL_PORT_BUFFER_MALLOC_CAPS (MALLOC_CAP_SPIRAM) // Allocate LVGL buffer in PSRAM #define LVGL_PORT_BUFFER_SIZE (LVGL_PORT_DISP_WIDTH * 20) #define LVGL_PORT_BUFFER_NUM (2) @@ -49,7 +50,9 @@ #define LVGL_PORT_TASK_MIN_DELAY_MS (2) // The minimum delay of the LVGL timer task, in milliseconds #define LVGL_PORT_TASK_STACK_SIZE (6 * 1024) // The stack size of the LVGL timer task, in bytes #define LVGL_PORT_TASK_PRIORITY (2) // The priority of the LVGL timer task -#define LVGL_PORT_TASK_CORE (-1) // The core of the LVGL timer task, `-1` means the don't specify the core +#define LVGL_PORT_TASK_CORE (ARDUINO_RUNNING_CORE) + // The core of the LVGL timer task, `-1` means the don't specify the core + // Default is the same as the Arduino task // This can be set to `1` only if the SoCs support dual-core, // otherwise it should be set to `-1` or `0` diff --git a/examples/SquareLine/v8/Porting/ESP_Panel_Board_Custom.h b/examples/SquareLine/v8/Porting/ESP_Panel_Board_Custom.h index 3ae31b50..dfd5e727 100644 --- a/examples/SquareLine/v8/Porting/ESP_Panel_Board_Custom.h +++ b/examples/SquareLine/v8/Porting/ESP_Panel_Board_Custom.h @@ -110,8 +110,6 @@ // |--------------|---------------| #define ESP_PANEL_LCD_RGB_DATA_WIDTH (16) // | 8 | 16 | #define ESP_PANEL_LCD_RGB_PIXEL_BITS (16) // | 24 | 16 | - - #define ESP_PANEL_LCD_RGB_FRAME_BUF_NUM (1) // 1/2/3 #define ESP_PANEL_LCD_RGB_BOUNCE_BUF_SIZE (0) // Bounce buffer size in bytes. This function is used to avoid screen drift. // To enable the bounce buffer, set it to a non-zero value. Typically set to `ESP_PANEL_LCD_WIDTH * 10` // The size of the Bounce Buffer must satisfy `width_of_lcd * height_of_lcd = size_of_buffer * N`, @@ -121,7 +119,6 @@ #define ESP_PANEL_LCD_RGB_IO_DE (17) // -1 if not used #define ESP_PANEL_LCD_RGB_IO_PCLK (9) #define ESP_PANEL_LCD_RGB_IO_DISP (-1) // -1 if not used - // | RGB565 | RGB666 | RGB888 | // |--------|--------|--------| #define ESP_PANEL_LCD_RGB_IO_DATA0 (10) // | B0 | B0-1 | B0-3 | @@ -158,6 +155,22 @@ // The `mirror()` function will be implemented by LCD command if set to 1. #endif +#elif ESP_PANEL_LCD_BUS_TYPE == ESP_PANEL_BUS_TYPE_MIPI_DSI + + #define ESP_PANEL_LCD_MIPI_DSI_LANE_NUM (2) // ESP32-P4 supports 1 or 2 lanes + #define ESP_PANEL_LCD_MIPI_DSI_LANE_RATE_MBPS (1000) // Single lane bit rate, should consult the LCD supplier or check the + // LCD drive IC datasheet for the supported lane rate. + // ESP32-P4 supports max 1500Mbps + #define ESP_PANEL_LCD_MIPI_DSI_PHY_LDO_ID (3) // -1 if not used + #define ESP_PANEL_LCD_MIPI_DPI_CLK_MHZ (52) + #define ESP_PANEL_LCD_MIPI_DPI_PIXEL_BITS (ESP_PANEL_LCD_RGB565_COLOR_BITS_16) + #define ESP_PANEL_LCD_MIPI_DSI_HPW (10) + #define ESP_PANEL_LCD_MIPI_DSI_HBP (160) + #define ESP_PANEL_LCD_MIPI_DSI_HFP (160) + #define ESP_PANEL_LCD_MIPI_DSI_VPW (1) + #define ESP_PANEL_LCD_MIPI_DSI_VBP (23) + #define ESP_PANEL_LCD_MIPI_DSI_VFP (12) + #else #error "The function is not ready and will be implemented in the future." @@ -380,8 +393,8 @@ * */ #define ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_MAJOR 0 -#define ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_MINOR 2 -#define ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_PATCH 3 +#define ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_MINOR 3 +#define ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_PATCH 0 #endif /* ESP_PANEL_USE_CUSTOM_BOARD */ diff --git a/examples/SquareLine/v8/Porting/ESP_Panel_Board_Supported.h b/examples/SquareLine/v8/Porting/ESP_Panel_Board_Supported.h index 603e59bd..75d5c84a 100644 --- a/examples/SquareLine/v8/Porting/ESP_Panel_Board_Supported.h +++ b/examples/SquareLine/v8/Porting/ESP_Panel_Board_Supported.h @@ -31,6 +31,7 @@ * - BOARD_ESP32_S3_LCD_EV_BOARD_2 (ESP32-S3-LCD-EV-Board-2(v1.1-v1.4))): https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32s3/esp32-s3-lcd-ev-board/user_guide_v1.4.html * - BOARD_ESP32_S3_LCD_EV_BOARD_2_V1_5 (ESP32-S3-LCD-EV-Board-2(v1.5)): https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32s3/esp32-s3-lcd-ev-board/user_guide.html * - BOARD_ESP32_S3_USB_OTG (ESP32-S3-USB-OTG): https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32s3/esp32-s3-usb-otg/index.html + * - BOARD_ESP32_P4_FUNCTION_EV_BOARD (ESP32-P4-Function-EV-Board): https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32p4/esp32-p4-function-ev-board/index.html * */ // #define BOARD_ESP32_C3_LCDKIT @@ -45,6 +46,7 @@ // #define BOARD_ESP32_S3_LCD_EV_BOARD_2 // #define BOARD_ESP32_S3_LCD_EV_BOARD_2_V1_5 // #define BOARD_ESP32_S3_USB_OTG +// #define BOARD_ESP32_P4_FUNCTION_EV_BOARD /* * Elecrow (https://www.elecrow.com): @@ -101,7 +103,7 @@ * */ #define ESP_PANEL_BOARD_SUPPORTED_FILE_VERSION_MAJOR 0 -#define ESP_PANEL_BOARD_SUPPORTED_FILE_VERSION_MINOR 5 -#define ESP_PANEL_BOARD_SUPPORTED_FILE_VERSION_PATCH 1 +#define ESP_PANEL_BOARD_SUPPORTED_FILE_VERSION_MINOR 6 +#define ESP_PANEL_BOARD_SUPPORTED_FILE_VERSION_PATCH 0 #endif diff --git a/examples/SquareLine/v8/Porting/Porting.ino b/examples/SquareLine/v8/Porting/Porting.ino index 426a38c8..b72018fd 100644 --- a/examples/SquareLine/v8/Porting/Porting.ino +++ b/examples/SquareLine/v8/Porting/Porting.ino @@ -13,17 +13,17 @@ * * 1. For **ESP32_Display_Panel**: * - * - Follow the [steps](https://github.com/esp-arduino-libs/ESP32_Display_Panel/docs/How_To_Use.md#configuring-drivers) to configure drivers if needed. - * - If using a supported development board, follow the [steps](https://github.com/esp-arduino-libs/ESP32_Display_Panel/docs/How_To_Use.md#using-supported-development-boards) to configure it. - * - If using a custom board, follow the [steps](https://github.com/esp-arduino-libs/ESP32_Display_Panel/docs/How_To_Use.md#using-custom-development-boards) to configure it. + * - Follow the [steps](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/How_To_Use.md#configuring-drivers) to configure drivers if needed. + * - If using a supported development board, follow the [steps](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/How_To_Use.md#using-supported-development-boards) to configure it. + * - If using a custom board, follow the [steps](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/How_To_Use.md#using-custom-development-boards) to configure it. * * 2. For **lvgl**: * - * - Follow the [steps](https://github.com/esp-arduino-libs/ESP32_Display_Panel/docs/How_To_Use.md#configuring-lvgl) to add *lv_conf.h* file and change the configurations. + * - Follow the [steps](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/How_To_Use.md#configuring-lvgl) to add *lv_conf.h* file and change the configurations. * - Modify the macros in the [lvgl_port_v8.h](./lvgl_port_v8.h) file to configure the LVGL porting parameters. * * 3. Navigate to the `Tools` menu in the Arduino IDE to choose a ESP board and configure its parameters. For supported - * boards, please refter to [Configuring Supported Development Boards](https://github.com/esp-arduino-libs/ESP32_Display_Panel/docs/How_To_Use.md#configuring-supported-development-boards) + * boards, please refter to [Configuring Supported Development Boards](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/How_To_Use.md#configuring-supported-development-boards) * 4. Verify and upload the example to your ESP board. * * ## Serial Output @@ -43,7 +43,7 @@ * * ## Troubleshooting * - * Please first check [FAQ](https://github.com/esp-arduino-libs/ESP32_Display_Panel/docs/faq.md) for troubleshooting. If you still cannot solve the problem, please create a [Github issue](https://github.com/esp-arduino-libs/ESP32_Display_Panel/issues). We will get back to you as soon as possible. + * Please first check [FAQ](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/FAQ.md) for troubleshooting. If you still cannot solve the problem, please create a [Github issue](https://github.com/esp-arduino-libs/ESP32_Display_Panel/issues). We will get back to you as soon as possible. * */ diff --git a/examples/SquareLine/v8/Porting/lvgl_port_v8.cpp b/examples/SquareLine/v8/Porting/lvgl_port_v8.cpp index cfd9f29d..7173f33e 100644 --- a/examples/SquareLine/v8/Porting/lvgl_port_v8.cpp +++ b/examples/SquareLine/v8/Porting/lvgl_port_v8.cpp @@ -3,16 +3,17 @@ * * SPDX-License-Identifier: CC0-1.0 */ -#include -#include -#include +#include "esp_timer.h" #include "lvgl_port_v8.h" +#define LVGL_PORT_ENABLE_ROTATION_OPTIMIZED (1) #define LVGL_PORT_BUFFER_NUM_MAX (2) static const char *TAG = "lvgl_port"; static SemaphoreHandle_t lvgl_mux = nullptr; // LVGL mutex static TaskHandle_t lvgl_task_handle = nullptr; +static esp_timer_handle_t lvgl_tick_timer = NULL; +static void *lvgl_buf[LVGL_PORT_BUFFER_NUM_MAX] = {}; #if LVGL_PORT_ROTATION_DEGREE != 0 static void *get_next_frame_buffer(ESP_PanelLcd *lcd) @@ -21,8 +22,8 @@ static void *get_next_frame_buffer(ESP_PanelLcd *lcd) static void *fbs[2] = { NULL }; if (next_fb == NULL) { - fbs[0] = lcd->getRgbBufferByIndex(0); - fbs[1] = lcd->getRgbBufferByIndex(1); + fbs[0] = lcd->getFrameBufferByIndex(0); + fbs[1] = lcd->getFrameBufferByIndex(1); next_fb = fbs[1]; } else { next_fb = (next_fb == fbs[0]) ? fbs[1] : fbs[0]; @@ -31,53 +32,167 @@ static void *get_next_frame_buffer(ESP_PanelLcd *lcd) return next_fb; } -IRAM_ATTR static void rotate_copy_pixel(const lv_color_t *from, lv_color_t *to, uint16_t x_start, uint16_t y_start, - uint16_t x_end, uint16_t y_end, uint16_t w, uint16_t h, uint16_t rotate) +__attribute__((always_inline)) +static inline void copy_pixel_8bpp(uint8_t *to, const uint8_t *from) { + *to++ = *from++; +} + +__attribute__((always_inline)) +static inline void copy_pixel_16bpp(uint8_t *to, const uint8_t *from) +{ + *(uint16_t *)to++ = *(const uint16_t *)from++; +} + +__attribute__((always_inline)) +static inline void copy_pixel_24bpp(uint8_t *to, const uint8_t *from) +{ + *to++ = *from++; + *to++ = *from++; + *to++ = *from++; +} + +#define _COPY_PIXEL(_bpp, to, from) copy_pixel_##_bpp##bpp(to, from) +#define COPY_PIXEL(_bpp, to, from) _COPY_PIXEL(_bpp, to, from) + +#define ROTATE_90_ALL_BPP() \ + { \ + to_bytes_per_line = h * to_bytes_per_piexl; \ + to_index_const = (w - x_start - 1) * to_bytes_per_line; \ + for (int from_y = y_start; from_y < y_end + 1; from_y++) { \ + from_index = from_y * from_bytes_per_line + x_start * from_bytes_per_piexl; \ + to_index = to_index_const + from_y * to_bytes_per_piexl; \ + for (int from_x = x_start; from_x < x_end + 1; from_x++) { \ + COPY_PIXEL(LV_COLOR_DEPTH, to + to_index, from + from_index); \ + from_index += from_bytes_per_piexl; \ + to_index -= to_bytes_per_line; \ + } \ + } \ + } + +/** + * @brief Optimized transpose function for RGB565 format. + * + * @note ESP32-P4 1024x600 full-screen: 738ms -> 34ms + * @note ESP32-S3 480x480 full-screen: 380ms -> 37ms + * + */ +#define ROTATE_90_OPTIMIZED_16BPP(block_w, block_h) \ + { \ + for (int i = 0; i < h; i += block_h) { \ + max_height = (i + block_h > h) ? h : (i + block_h); \ + for (int j = 0; j < w; j += block_w) { \ + max_width = (j + block_w > w) ? w : (j + block_w); \ + start_y = w - 1 - j; \ + for (int x = i; x < max_height; x++) { \ + from_next = (uint16_t *)from + x * w; \ + for (int y = j, mirrored_y = start_y; y < max_width; y += 4, mirrored_y -= 4) { \ + ((uint16_t *)to)[(mirrored_y) * h + x] = *((uint32_t *)(from_next + y)) & 0xFFFF; \ + ((uint16_t *)to)[(mirrored_y - 1) * h + x] = (*((uint32_t *)(from_next + y)) >> 16) & 0xFFFF; \ + ((uint16_t *)to)[(mirrored_y - 2) * h + x] = *((uint32_t *)(from_next + y + 2)) & 0xFFFF; \ + ((uint16_t *)to)[(mirrored_y - 3) * h + x] = (*((uint32_t *)(from_next + y + 2)) >> 16) & 0xFFFF; \ + } \ + } \ + } \ + } \ + } + +#define ROTATE_180_ALL_BPP() \ + { \ + to_bytes_per_line = w * to_bytes_per_piexl; \ + to_index_const = (h - 1) * to_bytes_per_line + (w - x_start - 1) * to_bytes_per_piexl; \ + for (int from_y = y_start; from_y < y_end + 1; from_y++) { \ + from_index = from_y * from_bytes_per_line + x_start * from_bytes_per_piexl; \ + to_index = to_index_const - from_y * to_bytes_per_line; \ + for (int from_x = x_start; from_x < x_end + 1; from_x++) { \ + COPY_PIXEL(LV_COLOR_DEPTH, to + to_index, from + from_index); \ + from_index += from_bytes_per_piexl; \ + to_index -= to_bytes_per_piexl; \ + } \ + } \ + } + +#define ROTATE_270_OPTIMIZED_16BPP(block_w, block_h) \ + { \ + for (int i = 0; i < h; i += block_h) { \ + max_height = i + block_h > h ? h : i + block_h; \ + for (int j = 0; j < w; j += block_w) { \ + max_width = j + block_w > w ? w : j + block_w; \ + for (int x = i; x < max_height; x++) { \ + from_next = (uint16_t *)from + x * w; \ + for (int y = j; y < max_width; y += 4) { \ + ((uint16_t *)to)[y * h + (h - 1 - x)] = *((uint32_t *)(from_next + y)) & 0xFFFF; \ + ((uint16_t *)to)[(y + 1) * h + (h - 1 - x)] = (*((uint32_t *)(from_next + y)) >> 16) & 0xFFFF; \ + ((uint16_t *)to)[(y + 2) * h + (h - 1 - x)] = *((uint32_t *)(from_next + y + 2)) & 0xFFFF; \ + ((uint16_t *)to)[(y + 3) * h + (h - 1 - x)] = (*((uint32_t *)(from_next + y + 2)) >> 16) & 0xFFFF; \ + } \ + } \ + } \ + } \ + } + +#define ROTATE_270_ALL_BPP() \ + { \ + to_bytes_per_line = h * to_bytes_per_piexl; \ + from_index_const = x_start * from_bytes_per_piexl; \ + to_index_const = x_start * to_bytes_per_line + (h - 1) * to_bytes_per_piexl; \ + for (int from_y = y_start; from_y < y_end + 1; from_y++) { \ + from_index = from_y * from_bytes_per_line + from_index_const; \ + to_index = to_index_const - from_y * to_bytes_per_piexl; \ + for (int from_x = x_start; from_x < x_end + 1; from_x++) { \ + COPY_PIXEL(LV_COLOR_DEPTH, to + to_index, from + from_index); \ + from_index += from_bytes_per_piexl; \ + to_index += to_bytes_per_line; \ + } \ + } \ + } + +__attribute__((always_inline)) +IRAM_ATTR static inline void rotate_copy_pixel( + const uint8_t *from, uint8_t *to, uint16_t x_start, uint16_t y_start, uint16_t x_end, uint16_t y_end, uint16_t w, + uint16_t h, uint16_t rotate +) +{ + int from_bytes_per_piexl = sizeof(lv_color_t); + int from_bytes_per_line = w * from_bytes_per_piexl; int from_index = 0; + int from_index_const = 0; + + int to_bytes_per_piexl = LV_COLOR_DEPTH >> 3; + int to_bytes_per_line; int to_index = 0; int to_index_const = 0; +#if (LV_COLOR_DEPTH == 16) && LVGL_PORT_ENABLE_ROTATION_OPTIMIZED + int max_height = 0; + int max_width = 0; + int start_y = 0; + uint16_t *from_next = NULL; +#endif + + uint32_t time = esp_log_timestamp(); switch (rotate) { case 90: - 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; - 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; - } - } +#if (LV_COLOR_DEPTH == 16) && LVGL_PORT_ENABLE_ROTATION_OPTIMIZED + ROTATE_90_OPTIMIZED_16BPP(32, 256); +#else + ROTATE_90_ALL_BPP(); +#endif break; case 180: - to_index_const = h * w - x_start - 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 * w; - for (int from_x = x_start; from_x < x_end + 1; from_x++) { - *(to + to_index) = *(from + from_index); - from_index += 1; - to_index -= 1; - } - } + ROTATE_180_ALL_BPP(); break; case 270: - 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; - 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; - } - } +#if (LV_COLOR_DEPTH == 16) && LVGL_PORT_ENABLE_ROTATION_OPTIMIZED + ROTATE_270_OPTIMIZED_16BPP(32, 256); +#else + ROTATE_270_ALL_BPP(); +#endif break; default: break; } + ESP_LOGI(TAG, "rotate: end, time used:%d", (int)(esp_log_timestamp() - time)); } #endif /* LVGL_PORT_ROTATION_DEGREE */ @@ -174,8 +289,10 @@ static void flush_dirty_copy(void *dst, void *src, lv_port_dirty_area_t *dirty_a y_start = dirty_area->inv_areas[i].y1; y_end = dirty_area->inv_areas[i].y2; - rotate_copy_pixel((lv_color_t *)src, (lv_color_t *)dst, x_start, y_start, x_end, y_end, LV_HOR_RES, LV_VER_RES, - LVGL_PORT_ROTATION_DEGREE); + rotate_copy_pixel( + (uint8_t *)src, (uint8_t *)dst, x_start, y_start, x_end, y_end, LV_HOR_RES, LV_VER_RES, + LVGL_PORT_ROTATION_DEGREE + ); } } } @@ -200,10 +317,12 @@ static void flush_callback(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t // Rotate and copy data from the whole screen LVGL's buffer to the next frame buffer next_fb = flush_get_next_buf(lcd); - rotate_copy_pixel((lv_color_t *)color_map, (lv_color_t *)next_fb, offsetx1, offsety1, offsetx2, offsety2, - LV_HOR_RES, LV_VER_RES, LVGL_PORT_ROTATION_DEGREE); + rotate_copy_pixel( + (uint8_t *)color_map, (uint8_t *)next_fb, offsetx1, offsety1, offsetx2, offsety2, + LV_HOR_RES, LV_VER_RES, LVGL_PORT_ROTATION_DEGREE + ); - /* Switch the current RGB frame buffer to `next_fb` */ + /* Switch the current LCD frame buffer to `next_fb` */ lcd->drawBitmap(offsetx1, offsety1, offsetx2 - offsetx1 + 1, offsety2 - offsety1 + 1, (const uint8_t *)next_fb); /* Waiting for the current frame buffer to complete transmission */ @@ -234,7 +353,7 @@ static void flush_callback(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t flush_dirty_save(&dirty_area); flush_dirty_copy(next_fb, color_map, &dirty_area); - /* Switch the current RGB frame buffer to `next_fb` */ + /* Switch the current LCD frame buffer to `next_fb` */ lcd->drawBitmap(offsetx1, offsety1, offsetx2 - offsetx1 + 1, offsety2 - offsety1 + 1, (const uint8_t *)next_fb); /* Waiting for the current frame buffer to complete transmission */ @@ -266,7 +385,7 @@ static void flush_callback(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t /* Action after last area refresh */ if (lv_disp_flush_is_last(drv)) { - /* Switch the current RGB frame buffer to `color_map` */ + /* Switch the current LCD frame buffer to `color_map` */ lcd->drawBitmap(offsetx1, offsety1, offsetx2 - offsetx1 + 1, offsety2 - offsety1 + 1, (const uint8_t *)color_map); /* Waiting for the last frame buffer to complete transmission */ @@ -288,7 +407,7 @@ 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; - /* Switch the current RGB frame buffer to `color_map` */ + /* Switch the current LCD frame buffer to `color_map` */ lcd->drawBitmap(offsetx1, offsety1, offsetx2 - offsetx1 + 1, offsety2 - offsety1 + 1, (const uint8_t *)color_map); /* Waiting for the last frame buffer to complete transmission */ @@ -301,8 +420,8 @@ static void flush_callback(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t #elif LVGL_PORT_FULL_REFRESH && LVGL_PORT_DISP_BUFFER_NUM == 3 #if LVGL_PORT_ROTATION_DEGREE == 0 -static void *lvgl_port_rgb_last_buf = NULL; -static void *lvgl_port_rgb_next_buf = NULL; +static void *lvgl_port_lcd_last_buf = NULL; +static void *lvgl_port_lcd_next_buf = NULL; static void *lvgl_port_flush_next_buf = NULL; #endif @@ -317,38 +436,38 @@ void flush_callback(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color #if LVGL_PORT_ROTATION_DEGREE != 0 void *next_fb = get_next_frame_buffer(lcd); - /* Rotate and copy dirty area from the current LVGL's buffer to the next RGB frame buffer */ + /* Rotate and copy dirty area from the current LVGL's buffer to the next LCD frame buffer */ rotate_copy_pixel((lv_color_t *)color_map, (lv_color_t *)next_fb, offsetx1, offsety1, offsetx2, offsety2, LV_HOR_RES, LV_VER_RES, LVGL_PORT_ROTATION_DEGREE); - /* Switch the current RGB frame buffer to `next_fb` */ + /* Switch the current LCD frame buffer to `next_fb` */ lcd->drawBitmap(offsetx1, offsety1, offsetx2 - offsetx1 + 1, offsety2 - offsety1 + 1, (const uint8_t *)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; - /* Switch the current RGB frame buffer to `color_map` */ + /* Switch the current LCD frame buffer to `color_map` */ lcd->drawBitmap(offsetx1, offsety1, offsetx2 - offsetx1 + 1, offsety2 - offsety1 + 1, (const uint8_t *)color_map); - lvgl_port_rgb_next_buf = color_map; + lvgl_port_lcd_next_buf = color_map; #endif lv_disp_flush_ready(drv); } #endif -IRAM_ATTR bool onRgbVsyncCallback(void *user_data) +IRAM_ATTR bool onLcdVsyncCallback(void *user_data) { BaseType_t need_yield = pdFALSE; #if LVGL_PORT_FULL_REFRESH && (LVGL_PORT_DISP_BUFFER_NUM == 3) && (LVGL_PORT_ROTATION_DEGREE == 0) - if (lvgl_port_rgb_next_buf != lvgl_port_rgb_last_buf) { - lvgl_port_flush_next_buf = lvgl_port_rgb_last_buf; - lvgl_port_rgb_last_buf = lvgl_port_rgb_next_buf; + if (lvgl_port_lcd_next_buf != lvgl_port_lcd_last_buf) { + lvgl_port_flush_next_buf = lvgl_port_lcd_last_buf; + lvgl_port_lcd_last_buf = lvgl_port_lcd_next_buf; } #else TaskHandle_t task_handle = (TaskHandle_t)user_data; - // Notify that the current RGB frame buffer has been transmitted + // Notify that the current LCD frame buffer has been transmitted xTaskNotifyFromISR(task_handle, ULONG_MAX, eNoAction, &need_yield); #endif return (need_yield == pdTRUE); @@ -441,7 +560,6 @@ static lv_disp_t *display_init(ESP_PanelLcd *lcd) static lv_disp_drv_t disp_drv; // Alloc draw buffers used by LVGL - void *buf[LVGL_PORT_BUFFER_NUM_MAX] = { nullptr }; int buffer_size = 0; ESP_LOGD(TAG, "Malloc memory for LVGL buffer"); @@ -449,38 +567,38 @@ static lv_disp_t *display_init(ESP_PanelLcd *lcd) // Avoid tearing function is disabled buffer_size = LVGL_PORT_BUFFER_SIZE; for (int i = 0; (i < LVGL_PORT_BUFFER_NUM) && (i < LVGL_PORT_BUFFER_NUM_MAX); i++) { - buf[i] = heap_caps_malloc(buffer_size * sizeof(lv_color_t), LVGL_PORT_BUFFER_MALLOC_CAPS); - assert(buf[i]); - ESP_LOGD(TAG, "Buffer[%d] address: %p, size: %d", i, buf[i], buffer_size * sizeof(lv_color_t)); + lvgl_buf[i] = heap_caps_malloc(buffer_size * sizeof(lv_color_t), LVGL_PORT_BUFFER_MALLOC_CAPS); + assert(lvgl_buf[i]); + ESP_LOGD(TAG, "Buffer[%d] address: %p, size: %d", i, lvgl_buf[i], buffer_size * sizeof(lv_color_t)); } #else - // To avoid the tearing effect, we should use at least two frame buffers: one for LVGL rendering and another for RGB output + // To avoid the tearing effect, we should use at least two frame buffers: one for LVGL rendering and another for LCD refresh buffer_size = LVGL_PORT_DISP_WIDTH * LVGL_PORT_DISP_HEIGHT; #if (LVGL_PORT_DISP_BUFFER_NUM >= 3) && (LVGL_PORT_ROTATION_DEGREE == 0) && LVGL_PORT_FULL_REFRESH // With the usage of three buffers and full-refresh, we always have one buffer available for rendering, - // eliminating the need to wait for the RGB's sync signal - lvgl_port_rgb_last_buf = lcd->getRgbBufferByIndex(0); - buf[0] = lcd->getRgbBufferByIndex(1); - buf[1] = lcd->getRgbBufferByIndex(2); - lvgl_port_rgb_next_buf = lvgl_port_rgb_last_buf; - lvgl_port_flush_next_buf = buf[1]; + // eliminating the need to wait for the LCD's sync signal + lvgl_port_lcd_last_buf = lcd->getFrameBufferByIndex(0); + lvgl_buf[0] = lcd->getFrameBufferByIndex(1); + lvgl_buf[1] = lcd->getFrameBufferByIndex(2); + lvgl_port_lcd_next_buf = lvgl_port_lcd_last_buf; + lvgl_port_flush_next_buf = lvgl_buf[1]; #elif (LVGL_PORT_DISP_BUFFER_NUM >= 3) && (LVGL_PORT_ROTATION_DEGREE != 0) - buf[0] = lcd->getRgbBufferByIndex(2); + lvgl_buf[0] = lcd->getFrameBufferByIndex(2); #elif LVGL_PORT_DISP_BUFFER_NUM >= 2 for (int i = 0; (i < LVGL_PORT_DISP_BUFFER_NUM) && (i < LVGL_PORT_BUFFER_NUM_MAX); i++) { - buf[i] = lcd->getRgbBufferByIndex(i); + lvgl_buf[i] = lcd->getFrameBufferByIndex(i); } #endif #endif /* LVGL_PORT_AVOID_TEAR */ // initialize LVGL draw buffers - lv_disp_draw_buf_init(&disp_buf, buf[0], buf[1], buffer_size); + lv_disp_draw_buf_init(&disp_buf, lvgl_buf[0], lvgl_buf[1], buffer_size); ESP_LOGD(TAG, "Register display driver to LVGL"); lv_disp_drv_init(&disp_drv); @@ -550,16 +668,33 @@ static void tick_increment(void *arg) lv_tick_inc(LVGL_PORT_TICK_PERIOD_MS); } -static esp_err_t tick_init(void) +static bool tick_init(void) { // Tick interface for LVGL (using esp_timer to generate 2ms periodic event) const esp_timer_create_args_t lvgl_tick_timer_args = { .callback = &tick_increment, .name = "LVGL tick" }; - esp_timer_handle_t lvgl_tick_timer = NULL; - ESP_ERROR_CHECK(esp_timer_create(&lvgl_tick_timer_args, &lvgl_tick_timer)); - return esp_timer_start_periodic(lvgl_tick_timer, LVGL_PORT_TICK_PERIOD_MS * 1000); + ESP_PANEL_CHECK_ERR_RET( + esp_timer_create(&lvgl_tick_timer_args, &lvgl_tick_timer), false, "Create LVGL tick timer failed" + ); + ESP_PANEL_CHECK_ERR_RET( + esp_timer_start_periodic(lvgl_tick_timer, LVGL_PORT_TICK_PERIOD_MS * 1000), false, + "Start LVGL tick timer failed" + ); + + return true; +} + +static bool tick_deinit(void) +{ + ESP_PANEL_CHECK_ERR_RET( + esp_timer_stop(lvgl_tick_timer), false, "Stop LVGL tick timer failed" + ); + ESP_PANEL_CHECK_ERR_RET( + esp_timer_delete(lvgl_tick_timer), false, "Delete LVGL tick timer failed" + ); + return true; } #endif @@ -582,7 +717,7 @@ static void lvgl_port_task(void *arg) } } -IRAM_ATTR bool onRefreshFinishCallback(void *user_data) +IRAM_ATTR bool onDrawBitmapFinishCallback(void *user_data) { lv_disp_drv_t *drv = (lv_disp_drv_t *)user_data; @@ -594,9 +729,14 @@ IRAM_ATTR bool onRefreshFinishCallback(void *user_data) bool lvgl_port_init(ESP_PanelLcd *lcd, ESP_PanelTouch *tp) { ESP_PANEL_CHECK_FALSE_RET(lcd != nullptr, false, "Invalid LCD device"); + + auto bus_type = lcd->getBus()->getType(); #if LVGL_PORT_AVOID_TEAR - ESP_PANEL_CHECK_FALSE_RET(lcd->getBus()->getType() == ESP_PANEL_BUS_TYPE_RGB, false, "Avoid tearing function only works with RGB LCD now"); - ESP_LOGD(TAG, "Avoid tearing is enabled, mode: %d", LVGL_PORT_AVOID_TEARING_MODE); + ESP_PANEL_CHECK_FALSE_RET( + (bus_type == ESP_PANEL_BUS_TYPE_RGB) || (bus_type == ESP_PANEL_BUS_TYPE_MIPI_DSI), false, + "Avoid tearing function only works with RGB/MIPI-DSI LCD now" + ); + ESP_LOGI(TAG, "Avoid tearing is enabled, mode: %d", LVGL_PORT_AVOID_TEARING_MODE); #endif lv_disp_t *disp = nullptr; @@ -604,7 +744,7 @@ bool lvgl_port_init(ESP_PanelLcd *lcd, ESP_PanelTouch *tp) lv_init(); #if !LV_TICK_CUSTOM - ESP_PANEL_CHECK_ERR_RET(tick_init(), false, "Initialize LVGL tick failed"); + ESP_PANEL_CHECK_FALSE_RET(tick_init(), false, "Initialize LVGL tick failed"); #endif ESP_LOGD(TAG, "Initialize LVGL display driver"); @@ -614,9 +754,9 @@ bool lvgl_port_init(ESP_PanelLcd *lcd, ESP_PanelTouch *tp) lv_disp_set_rotation(disp, LV_DISP_ROT_NONE); // For non-RGB LCD, need to notify LVGL that the buffer is ready when the refresh is finished - if (lcd->getBus()->getType() != ESP_PANEL_BUS_TYPE_RGB) { + if (bus_type != ESP_PANEL_BUS_TYPE_RGB) { ESP_LOGD(TAG, "Attach refresh finish callback to LCD"); - lcd->attachRefreshFinishCallback(onRefreshFinishCallback, (void *)disp->driver); + lcd->attachDrawBitmapFinishCallback(onDrawBitmapFinishCallback, (void *)disp->driver); } if (tp != nullptr) { @@ -647,7 +787,7 @@ bool lvgl_port_init(ESP_PanelLcd *lcd, ESP_PanelTouch *tp) ESP_PANEL_CHECK_FALSE_RET(ret == pdPASS, false, "Create LVGL task failed"); #if LVGL_PORT_AVOID_TEAR - lcd->attachRefreshFinishCallback(onRgbVsyncCallback, (void *)lvgl_task_handle); + lcd->attachRefreshFinishCallback(onLcdVsyncCallback, (void *)lvgl_task_handle); #endif return true; @@ -669,3 +809,35 @@ bool lvgl_port_unlock(void) return true; } + +bool lvgl_port_deinit(void) +{ +#if !LV_TICK_CUSTOM + ESP_PANEL_CHECK_FALSE_RET(tick_deinit(), false, "Deinitialize LVGL tick failed"); +#endif + + ESP_PANEL_CHECK_FALSE_RET(lvgl_port_lock(-1), false, "Lock LVGL failed"); + if (lvgl_task_handle != nullptr) { + vTaskDelete(lvgl_task_handle); + lvgl_task_handle = nullptr; + } + ESP_PANEL_CHECK_FALSE_RET(lvgl_port_unlock(), false, "Unlock LVGL failed"); + +#if LV_ENABLE_GC || !LV_MEM_CUSTOM + lv_deinit(); +#endif +#if !LVGL_PORT_AVOID_TEAR + for (int i = 0; i < LVGL_PORT_BUFFER_NUM; i++) { + if (lvgl_buf[i] != nullptr) { + free(lvgl_buf[i]); + lvgl_buf[i] = nullptr; + } + } +#endif + if (lvgl_mux != nullptr) { + vSemaphoreDelete(lvgl_mux); + lvgl_mux = nullptr; + } + + return true; +} diff --git a/examples/SquareLine/v8/WiFiClock/ESP_Panel_Board_Custom.h b/examples/SquareLine/v8/WiFiClock/ESP_Panel_Board_Custom.h index 3ae31b50..dfd5e727 100644 --- a/examples/SquareLine/v8/WiFiClock/ESP_Panel_Board_Custom.h +++ b/examples/SquareLine/v8/WiFiClock/ESP_Panel_Board_Custom.h @@ -110,8 +110,6 @@ // |--------------|---------------| #define ESP_PANEL_LCD_RGB_DATA_WIDTH (16) // | 8 | 16 | #define ESP_PANEL_LCD_RGB_PIXEL_BITS (16) // | 24 | 16 | - - #define ESP_PANEL_LCD_RGB_FRAME_BUF_NUM (1) // 1/2/3 #define ESP_PANEL_LCD_RGB_BOUNCE_BUF_SIZE (0) // Bounce buffer size in bytes. This function is used to avoid screen drift. // To enable the bounce buffer, set it to a non-zero value. Typically set to `ESP_PANEL_LCD_WIDTH * 10` // The size of the Bounce Buffer must satisfy `width_of_lcd * height_of_lcd = size_of_buffer * N`, @@ -121,7 +119,6 @@ #define ESP_PANEL_LCD_RGB_IO_DE (17) // -1 if not used #define ESP_PANEL_LCD_RGB_IO_PCLK (9) #define ESP_PANEL_LCD_RGB_IO_DISP (-1) // -1 if not used - // | RGB565 | RGB666 | RGB888 | // |--------|--------|--------| #define ESP_PANEL_LCD_RGB_IO_DATA0 (10) // | B0 | B0-1 | B0-3 | @@ -158,6 +155,22 @@ // The `mirror()` function will be implemented by LCD command if set to 1. #endif +#elif ESP_PANEL_LCD_BUS_TYPE == ESP_PANEL_BUS_TYPE_MIPI_DSI + + #define ESP_PANEL_LCD_MIPI_DSI_LANE_NUM (2) // ESP32-P4 supports 1 or 2 lanes + #define ESP_PANEL_LCD_MIPI_DSI_LANE_RATE_MBPS (1000) // Single lane bit rate, should consult the LCD supplier or check the + // LCD drive IC datasheet for the supported lane rate. + // ESP32-P4 supports max 1500Mbps + #define ESP_PANEL_LCD_MIPI_DSI_PHY_LDO_ID (3) // -1 if not used + #define ESP_PANEL_LCD_MIPI_DPI_CLK_MHZ (52) + #define ESP_PANEL_LCD_MIPI_DPI_PIXEL_BITS (ESP_PANEL_LCD_RGB565_COLOR_BITS_16) + #define ESP_PANEL_LCD_MIPI_DSI_HPW (10) + #define ESP_PANEL_LCD_MIPI_DSI_HBP (160) + #define ESP_PANEL_LCD_MIPI_DSI_HFP (160) + #define ESP_PANEL_LCD_MIPI_DSI_VPW (1) + #define ESP_PANEL_LCD_MIPI_DSI_VBP (23) + #define ESP_PANEL_LCD_MIPI_DSI_VFP (12) + #else #error "The function is not ready and will be implemented in the future." @@ -380,8 +393,8 @@ * */ #define ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_MAJOR 0 -#define ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_MINOR 2 -#define ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_PATCH 3 +#define ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_MINOR 3 +#define ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_PATCH 0 #endif /* ESP_PANEL_USE_CUSTOM_BOARD */ diff --git a/examples/SquareLine/v8/WiFiClock/ESP_Panel_Board_Supported.h b/examples/SquareLine/v8/WiFiClock/ESP_Panel_Board_Supported.h index 603e59bd..75d5c84a 100644 --- a/examples/SquareLine/v8/WiFiClock/ESP_Panel_Board_Supported.h +++ b/examples/SquareLine/v8/WiFiClock/ESP_Panel_Board_Supported.h @@ -31,6 +31,7 @@ * - BOARD_ESP32_S3_LCD_EV_BOARD_2 (ESP32-S3-LCD-EV-Board-2(v1.1-v1.4))): https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32s3/esp32-s3-lcd-ev-board/user_guide_v1.4.html * - BOARD_ESP32_S3_LCD_EV_BOARD_2_V1_5 (ESP32-S3-LCD-EV-Board-2(v1.5)): https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32s3/esp32-s3-lcd-ev-board/user_guide.html * - BOARD_ESP32_S3_USB_OTG (ESP32-S3-USB-OTG): https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32s3/esp32-s3-usb-otg/index.html + * - BOARD_ESP32_P4_FUNCTION_EV_BOARD (ESP32-P4-Function-EV-Board): https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32p4/esp32-p4-function-ev-board/index.html * */ // #define BOARD_ESP32_C3_LCDKIT @@ -45,6 +46,7 @@ // #define BOARD_ESP32_S3_LCD_EV_BOARD_2 // #define BOARD_ESP32_S3_LCD_EV_BOARD_2_V1_5 // #define BOARD_ESP32_S3_USB_OTG +// #define BOARD_ESP32_P4_FUNCTION_EV_BOARD /* * Elecrow (https://www.elecrow.com): @@ -101,7 +103,7 @@ * */ #define ESP_PANEL_BOARD_SUPPORTED_FILE_VERSION_MAJOR 0 -#define ESP_PANEL_BOARD_SUPPORTED_FILE_VERSION_MINOR 5 -#define ESP_PANEL_BOARD_SUPPORTED_FILE_VERSION_PATCH 1 +#define ESP_PANEL_BOARD_SUPPORTED_FILE_VERSION_MINOR 6 +#define ESP_PANEL_BOARD_SUPPORTED_FILE_VERSION_PATCH 0 #endif diff --git a/examples/SquareLine/v8/WiFiClock/WiFiClock.ino b/examples/SquareLine/v8/WiFiClock/WiFiClock.ino index 6bf7af83..0d8b3321 100644 --- a/examples/SquareLine/v8/WiFiClock/WiFiClock.ino +++ b/examples/SquareLine/v8/WiFiClock/WiFiClock.ino @@ -17,15 +17,15 @@ * * 1. For **ESP32_Display_Panel**: * - * - [Configure drivers](https://github.com/esp-arduino-libs/ESP32_Display_Panel/docs/How_To_Use.md#configuring-drivers) if needed. - * - If using a supported development board, follow the [steps](https://github.com/esp-arduino-libs/ESP32_Display_Panel/docs/How_To_Use.md#using-supported-development-boards) to configure it. - * - If using a custom board, follow the [steps](https://github.com/esp-arduino-libs/ESP32_Display_Panel/docs/How_To_Use.md#using-custom-development-boards) to configure it. + * - [Configure drivers](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/How_To_Use.md#configuring-drivers) if needed. + * - If using a supported development board, follow the [steps](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/How_To_Use.md#using-supported-development-boards) to configure it. + * - If using a custom board, follow the [steps](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/How_To_Use.md#using-custom-development-boards) to configure it. * * 2. Copy the [ui](./libraries/ui/) folder from `libraries` to [Arduino Library directory](https://github.com/esp-arduino-libs/ESP32_Display_Panel#where-is-the-directory-for-arduino-libraries). * * 3. For **lvgl**: * - * - Follow the [steps](https://github.com/esp-arduino-libs/ESP32_Display_Panel/docs/How_To_Use.md#configuring-lvgl) to add *lv_conf.h* + * - Follow the [steps](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/How_To_Use.md#configuring-lvgl) to add *lv_conf.h* * file and change the configurations. Additionally, set the following configurations to `1`: * * - `LV_FONT_MONTSERRAT_12` @@ -45,7 +45,7 @@ * - Fill the name of the city for which need to obtain weather information (such as `Shanghai`) in the macro definition `WEATHER_CITY`. * * 6. To obtain and calibrate time information after connecting to Wi-Fi, Please correctly fill in your time zone within the macro `TIMEZONE_OFFSET` (such as `CST-8`). - * 7. Navigate to the `Tools` menu in the Arduino IDE to choose a ESP board and configure its parameters, please refter to [Configuring Supported Development Boards](https://github.com/esp-arduino-libs/ESP32_Display_Panel/docs/How_To_Use.md#configuring-supported-development-boards) + * 7. Navigate to the `Tools` menu in the Arduino IDE to choose a ESP board and configure its parameters, please refter to [Configuring Supported Development Boards](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/How_To_Use.md#configuring-supported-development-boards) * 8. Verify and upload the example to your ESP board. * * ## Serial Output @@ -67,7 +67,7 @@ * * ## Troubleshooting * - * Please check the [FAQ](https://github.com/esp-arduino-libs/ESP32_Display_Panel/docs/faq.md) first to see if the same question exists. If not, please create a [Github issue](https://github.com/esp-arduino-libs/ESP32_Display_Panel/issues). We will get back to you as soon as possible. + * Please check the [FAQ](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/FAQ.md) first to see if the same question exists. If not, please create a [Github issue](https://github.com/esp-arduino-libs/ESP32_Display_Panel/issues). We will get back to you as soon as possible. * */ diff --git a/examples/SquareLine/v8/WiFiClock/lvgl_port_v8.cpp b/examples/SquareLine/v8/WiFiClock/lvgl_port_v8.cpp index cfd9f29d..7173f33e 100644 --- a/examples/SquareLine/v8/WiFiClock/lvgl_port_v8.cpp +++ b/examples/SquareLine/v8/WiFiClock/lvgl_port_v8.cpp @@ -3,16 +3,17 @@ * * SPDX-License-Identifier: CC0-1.0 */ -#include -#include -#include +#include "esp_timer.h" #include "lvgl_port_v8.h" +#define LVGL_PORT_ENABLE_ROTATION_OPTIMIZED (1) #define LVGL_PORT_BUFFER_NUM_MAX (2) static const char *TAG = "lvgl_port"; static SemaphoreHandle_t lvgl_mux = nullptr; // LVGL mutex static TaskHandle_t lvgl_task_handle = nullptr; +static esp_timer_handle_t lvgl_tick_timer = NULL; +static void *lvgl_buf[LVGL_PORT_BUFFER_NUM_MAX] = {}; #if LVGL_PORT_ROTATION_DEGREE != 0 static void *get_next_frame_buffer(ESP_PanelLcd *lcd) @@ -21,8 +22,8 @@ static void *get_next_frame_buffer(ESP_PanelLcd *lcd) static void *fbs[2] = { NULL }; if (next_fb == NULL) { - fbs[0] = lcd->getRgbBufferByIndex(0); - fbs[1] = lcd->getRgbBufferByIndex(1); + fbs[0] = lcd->getFrameBufferByIndex(0); + fbs[1] = lcd->getFrameBufferByIndex(1); next_fb = fbs[1]; } else { next_fb = (next_fb == fbs[0]) ? fbs[1] : fbs[0]; @@ -31,53 +32,167 @@ static void *get_next_frame_buffer(ESP_PanelLcd *lcd) return next_fb; } -IRAM_ATTR static void rotate_copy_pixel(const lv_color_t *from, lv_color_t *to, uint16_t x_start, uint16_t y_start, - uint16_t x_end, uint16_t y_end, uint16_t w, uint16_t h, uint16_t rotate) +__attribute__((always_inline)) +static inline void copy_pixel_8bpp(uint8_t *to, const uint8_t *from) { + *to++ = *from++; +} + +__attribute__((always_inline)) +static inline void copy_pixel_16bpp(uint8_t *to, const uint8_t *from) +{ + *(uint16_t *)to++ = *(const uint16_t *)from++; +} + +__attribute__((always_inline)) +static inline void copy_pixel_24bpp(uint8_t *to, const uint8_t *from) +{ + *to++ = *from++; + *to++ = *from++; + *to++ = *from++; +} + +#define _COPY_PIXEL(_bpp, to, from) copy_pixel_##_bpp##bpp(to, from) +#define COPY_PIXEL(_bpp, to, from) _COPY_PIXEL(_bpp, to, from) + +#define ROTATE_90_ALL_BPP() \ + { \ + to_bytes_per_line = h * to_bytes_per_piexl; \ + to_index_const = (w - x_start - 1) * to_bytes_per_line; \ + for (int from_y = y_start; from_y < y_end + 1; from_y++) { \ + from_index = from_y * from_bytes_per_line + x_start * from_bytes_per_piexl; \ + to_index = to_index_const + from_y * to_bytes_per_piexl; \ + for (int from_x = x_start; from_x < x_end + 1; from_x++) { \ + COPY_PIXEL(LV_COLOR_DEPTH, to + to_index, from + from_index); \ + from_index += from_bytes_per_piexl; \ + to_index -= to_bytes_per_line; \ + } \ + } \ + } + +/** + * @brief Optimized transpose function for RGB565 format. + * + * @note ESP32-P4 1024x600 full-screen: 738ms -> 34ms + * @note ESP32-S3 480x480 full-screen: 380ms -> 37ms + * + */ +#define ROTATE_90_OPTIMIZED_16BPP(block_w, block_h) \ + { \ + for (int i = 0; i < h; i += block_h) { \ + max_height = (i + block_h > h) ? h : (i + block_h); \ + for (int j = 0; j < w; j += block_w) { \ + max_width = (j + block_w > w) ? w : (j + block_w); \ + start_y = w - 1 - j; \ + for (int x = i; x < max_height; x++) { \ + from_next = (uint16_t *)from + x * w; \ + for (int y = j, mirrored_y = start_y; y < max_width; y += 4, mirrored_y -= 4) { \ + ((uint16_t *)to)[(mirrored_y) * h + x] = *((uint32_t *)(from_next + y)) & 0xFFFF; \ + ((uint16_t *)to)[(mirrored_y - 1) * h + x] = (*((uint32_t *)(from_next + y)) >> 16) & 0xFFFF; \ + ((uint16_t *)to)[(mirrored_y - 2) * h + x] = *((uint32_t *)(from_next + y + 2)) & 0xFFFF; \ + ((uint16_t *)to)[(mirrored_y - 3) * h + x] = (*((uint32_t *)(from_next + y + 2)) >> 16) & 0xFFFF; \ + } \ + } \ + } \ + } \ + } + +#define ROTATE_180_ALL_BPP() \ + { \ + to_bytes_per_line = w * to_bytes_per_piexl; \ + to_index_const = (h - 1) * to_bytes_per_line + (w - x_start - 1) * to_bytes_per_piexl; \ + for (int from_y = y_start; from_y < y_end + 1; from_y++) { \ + from_index = from_y * from_bytes_per_line + x_start * from_bytes_per_piexl; \ + to_index = to_index_const - from_y * to_bytes_per_line; \ + for (int from_x = x_start; from_x < x_end + 1; from_x++) { \ + COPY_PIXEL(LV_COLOR_DEPTH, to + to_index, from + from_index); \ + from_index += from_bytes_per_piexl; \ + to_index -= to_bytes_per_piexl; \ + } \ + } \ + } + +#define ROTATE_270_OPTIMIZED_16BPP(block_w, block_h) \ + { \ + for (int i = 0; i < h; i += block_h) { \ + max_height = i + block_h > h ? h : i + block_h; \ + for (int j = 0; j < w; j += block_w) { \ + max_width = j + block_w > w ? w : j + block_w; \ + for (int x = i; x < max_height; x++) { \ + from_next = (uint16_t *)from + x * w; \ + for (int y = j; y < max_width; y += 4) { \ + ((uint16_t *)to)[y * h + (h - 1 - x)] = *((uint32_t *)(from_next + y)) & 0xFFFF; \ + ((uint16_t *)to)[(y + 1) * h + (h - 1 - x)] = (*((uint32_t *)(from_next + y)) >> 16) & 0xFFFF; \ + ((uint16_t *)to)[(y + 2) * h + (h - 1 - x)] = *((uint32_t *)(from_next + y + 2)) & 0xFFFF; \ + ((uint16_t *)to)[(y + 3) * h + (h - 1 - x)] = (*((uint32_t *)(from_next + y + 2)) >> 16) & 0xFFFF; \ + } \ + } \ + } \ + } \ + } + +#define ROTATE_270_ALL_BPP() \ + { \ + to_bytes_per_line = h * to_bytes_per_piexl; \ + from_index_const = x_start * from_bytes_per_piexl; \ + to_index_const = x_start * to_bytes_per_line + (h - 1) * to_bytes_per_piexl; \ + for (int from_y = y_start; from_y < y_end + 1; from_y++) { \ + from_index = from_y * from_bytes_per_line + from_index_const; \ + to_index = to_index_const - from_y * to_bytes_per_piexl; \ + for (int from_x = x_start; from_x < x_end + 1; from_x++) { \ + COPY_PIXEL(LV_COLOR_DEPTH, to + to_index, from + from_index); \ + from_index += from_bytes_per_piexl; \ + to_index += to_bytes_per_line; \ + } \ + } \ + } + +__attribute__((always_inline)) +IRAM_ATTR static inline void rotate_copy_pixel( + const uint8_t *from, uint8_t *to, uint16_t x_start, uint16_t y_start, uint16_t x_end, uint16_t y_end, uint16_t w, + uint16_t h, uint16_t rotate +) +{ + int from_bytes_per_piexl = sizeof(lv_color_t); + int from_bytes_per_line = w * from_bytes_per_piexl; int from_index = 0; + int from_index_const = 0; + + int to_bytes_per_piexl = LV_COLOR_DEPTH >> 3; + int to_bytes_per_line; int to_index = 0; int to_index_const = 0; +#if (LV_COLOR_DEPTH == 16) && LVGL_PORT_ENABLE_ROTATION_OPTIMIZED + int max_height = 0; + int max_width = 0; + int start_y = 0; + uint16_t *from_next = NULL; +#endif + + uint32_t time = esp_log_timestamp(); switch (rotate) { case 90: - 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; - 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; - } - } +#if (LV_COLOR_DEPTH == 16) && LVGL_PORT_ENABLE_ROTATION_OPTIMIZED + ROTATE_90_OPTIMIZED_16BPP(32, 256); +#else + ROTATE_90_ALL_BPP(); +#endif break; case 180: - to_index_const = h * w - x_start - 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 * w; - for (int from_x = x_start; from_x < x_end + 1; from_x++) { - *(to + to_index) = *(from + from_index); - from_index += 1; - to_index -= 1; - } - } + ROTATE_180_ALL_BPP(); break; case 270: - 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; - 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; - } - } +#if (LV_COLOR_DEPTH == 16) && LVGL_PORT_ENABLE_ROTATION_OPTIMIZED + ROTATE_270_OPTIMIZED_16BPP(32, 256); +#else + ROTATE_270_ALL_BPP(); +#endif break; default: break; } + ESP_LOGI(TAG, "rotate: end, time used:%d", (int)(esp_log_timestamp() - time)); } #endif /* LVGL_PORT_ROTATION_DEGREE */ @@ -174,8 +289,10 @@ static void flush_dirty_copy(void *dst, void *src, lv_port_dirty_area_t *dirty_a y_start = dirty_area->inv_areas[i].y1; y_end = dirty_area->inv_areas[i].y2; - rotate_copy_pixel((lv_color_t *)src, (lv_color_t *)dst, x_start, y_start, x_end, y_end, LV_HOR_RES, LV_VER_RES, - LVGL_PORT_ROTATION_DEGREE); + rotate_copy_pixel( + (uint8_t *)src, (uint8_t *)dst, x_start, y_start, x_end, y_end, LV_HOR_RES, LV_VER_RES, + LVGL_PORT_ROTATION_DEGREE + ); } } } @@ -200,10 +317,12 @@ static void flush_callback(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t // Rotate and copy data from the whole screen LVGL's buffer to the next frame buffer next_fb = flush_get_next_buf(lcd); - rotate_copy_pixel((lv_color_t *)color_map, (lv_color_t *)next_fb, offsetx1, offsety1, offsetx2, offsety2, - LV_HOR_RES, LV_VER_RES, LVGL_PORT_ROTATION_DEGREE); + rotate_copy_pixel( + (uint8_t *)color_map, (uint8_t *)next_fb, offsetx1, offsety1, offsetx2, offsety2, + LV_HOR_RES, LV_VER_RES, LVGL_PORT_ROTATION_DEGREE + ); - /* Switch the current RGB frame buffer to `next_fb` */ + /* Switch the current LCD frame buffer to `next_fb` */ lcd->drawBitmap(offsetx1, offsety1, offsetx2 - offsetx1 + 1, offsety2 - offsety1 + 1, (const uint8_t *)next_fb); /* Waiting for the current frame buffer to complete transmission */ @@ -234,7 +353,7 @@ static void flush_callback(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t flush_dirty_save(&dirty_area); flush_dirty_copy(next_fb, color_map, &dirty_area); - /* Switch the current RGB frame buffer to `next_fb` */ + /* Switch the current LCD frame buffer to `next_fb` */ lcd->drawBitmap(offsetx1, offsety1, offsetx2 - offsetx1 + 1, offsety2 - offsety1 + 1, (const uint8_t *)next_fb); /* Waiting for the current frame buffer to complete transmission */ @@ -266,7 +385,7 @@ static void flush_callback(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t /* Action after last area refresh */ if (lv_disp_flush_is_last(drv)) { - /* Switch the current RGB frame buffer to `color_map` */ + /* Switch the current LCD frame buffer to `color_map` */ lcd->drawBitmap(offsetx1, offsety1, offsetx2 - offsetx1 + 1, offsety2 - offsety1 + 1, (const uint8_t *)color_map); /* Waiting for the last frame buffer to complete transmission */ @@ -288,7 +407,7 @@ 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; - /* Switch the current RGB frame buffer to `color_map` */ + /* Switch the current LCD frame buffer to `color_map` */ lcd->drawBitmap(offsetx1, offsety1, offsetx2 - offsetx1 + 1, offsety2 - offsety1 + 1, (const uint8_t *)color_map); /* Waiting for the last frame buffer to complete transmission */ @@ -301,8 +420,8 @@ static void flush_callback(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t #elif LVGL_PORT_FULL_REFRESH && LVGL_PORT_DISP_BUFFER_NUM == 3 #if LVGL_PORT_ROTATION_DEGREE == 0 -static void *lvgl_port_rgb_last_buf = NULL; -static void *lvgl_port_rgb_next_buf = NULL; +static void *lvgl_port_lcd_last_buf = NULL; +static void *lvgl_port_lcd_next_buf = NULL; static void *lvgl_port_flush_next_buf = NULL; #endif @@ -317,38 +436,38 @@ void flush_callback(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color #if LVGL_PORT_ROTATION_DEGREE != 0 void *next_fb = get_next_frame_buffer(lcd); - /* Rotate and copy dirty area from the current LVGL's buffer to the next RGB frame buffer */ + /* Rotate and copy dirty area from the current LVGL's buffer to the next LCD frame buffer */ rotate_copy_pixel((lv_color_t *)color_map, (lv_color_t *)next_fb, offsetx1, offsety1, offsetx2, offsety2, LV_HOR_RES, LV_VER_RES, LVGL_PORT_ROTATION_DEGREE); - /* Switch the current RGB frame buffer to `next_fb` */ + /* Switch the current LCD frame buffer to `next_fb` */ lcd->drawBitmap(offsetx1, offsety1, offsetx2 - offsetx1 + 1, offsety2 - offsety1 + 1, (const uint8_t *)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; - /* Switch the current RGB frame buffer to `color_map` */ + /* Switch the current LCD frame buffer to `color_map` */ lcd->drawBitmap(offsetx1, offsety1, offsetx2 - offsetx1 + 1, offsety2 - offsety1 + 1, (const uint8_t *)color_map); - lvgl_port_rgb_next_buf = color_map; + lvgl_port_lcd_next_buf = color_map; #endif lv_disp_flush_ready(drv); } #endif -IRAM_ATTR bool onRgbVsyncCallback(void *user_data) +IRAM_ATTR bool onLcdVsyncCallback(void *user_data) { BaseType_t need_yield = pdFALSE; #if LVGL_PORT_FULL_REFRESH && (LVGL_PORT_DISP_BUFFER_NUM == 3) && (LVGL_PORT_ROTATION_DEGREE == 0) - if (lvgl_port_rgb_next_buf != lvgl_port_rgb_last_buf) { - lvgl_port_flush_next_buf = lvgl_port_rgb_last_buf; - lvgl_port_rgb_last_buf = lvgl_port_rgb_next_buf; + if (lvgl_port_lcd_next_buf != lvgl_port_lcd_last_buf) { + lvgl_port_flush_next_buf = lvgl_port_lcd_last_buf; + lvgl_port_lcd_last_buf = lvgl_port_lcd_next_buf; } #else TaskHandle_t task_handle = (TaskHandle_t)user_data; - // Notify that the current RGB frame buffer has been transmitted + // Notify that the current LCD frame buffer has been transmitted xTaskNotifyFromISR(task_handle, ULONG_MAX, eNoAction, &need_yield); #endif return (need_yield == pdTRUE); @@ -441,7 +560,6 @@ static lv_disp_t *display_init(ESP_PanelLcd *lcd) static lv_disp_drv_t disp_drv; // Alloc draw buffers used by LVGL - void *buf[LVGL_PORT_BUFFER_NUM_MAX] = { nullptr }; int buffer_size = 0; ESP_LOGD(TAG, "Malloc memory for LVGL buffer"); @@ -449,38 +567,38 @@ static lv_disp_t *display_init(ESP_PanelLcd *lcd) // Avoid tearing function is disabled buffer_size = LVGL_PORT_BUFFER_SIZE; for (int i = 0; (i < LVGL_PORT_BUFFER_NUM) && (i < LVGL_PORT_BUFFER_NUM_MAX); i++) { - buf[i] = heap_caps_malloc(buffer_size * sizeof(lv_color_t), LVGL_PORT_BUFFER_MALLOC_CAPS); - assert(buf[i]); - ESP_LOGD(TAG, "Buffer[%d] address: %p, size: %d", i, buf[i], buffer_size * sizeof(lv_color_t)); + lvgl_buf[i] = heap_caps_malloc(buffer_size * sizeof(lv_color_t), LVGL_PORT_BUFFER_MALLOC_CAPS); + assert(lvgl_buf[i]); + ESP_LOGD(TAG, "Buffer[%d] address: %p, size: %d", i, lvgl_buf[i], buffer_size * sizeof(lv_color_t)); } #else - // To avoid the tearing effect, we should use at least two frame buffers: one for LVGL rendering and another for RGB output + // To avoid the tearing effect, we should use at least two frame buffers: one for LVGL rendering and another for LCD refresh buffer_size = LVGL_PORT_DISP_WIDTH * LVGL_PORT_DISP_HEIGHT; #if (LVGL_PORT_DISP_BUFFER_NUM >= 3) && (LVGL_PORT_ROTATION_DEGREE == 0) && LVGL_PORT_FULL_REFRESH // With the usage of three buffers and full-refresh, we always have one buffer available for rendering, - // eliminating the need to wait for the RGB's sync signal - lvgl_port_rgb_last_buf = lcd->getRgbBufferByIndex(0); - buf[0] = lcd->getRgbBufferByIndex(1); - buf[1] = lcd->getRgbBufferByIndex(2); - lvgl_port_rgb_next_buf = lvgl_port_rgb_last_buf; - lvgl_port_flush_next_buf = buf[1]; + // eliminating the need to wait for the LCD's sync signal + lvgl_port_lcd_last_buf = lcd->getFrameBufferByIndex(0); + lvgl_buf[0] = lcd->getFrameBufferByIndex(1); + lvgl_buf[1] = lcd->getFrameBufferByIndex(2); + lvgl_port_lcd_next_buf = lvgl_port_lcd_last_buf; + lvgl_port_flush_next_buf = lvgl_buf[1]; #elif (LVGL_PORT_DISP_BUFFER_NUM >= 3) && (LVGL_PORT_ROTATION_DEGREE != 0) - buf[0] = lcd->getRgbBufferByIndex(2); + lvgl_buf[0] = lcd->getFrameBufferByIndex(2); #elif LVGL_PORT_DISP_BUFFER_NUM >= 2 for (int i = 0; (i < LVGL_PORT_DISP_BUFFER_NUM) && (i < LVGL_PORT_BUFFER_NUM_MAX); i++) { - buf[i] = lcd->getRgbBufferByIndex(i); + lvgl_buf[i] = lcd->getFrameBufferByIndex(i); } #endif #endif /* LVGL_PORT_AVOID_TEAR */ // initialize LVGL draw buffers - lv_disp_draw_buf_init(&disp_buf, buf[0], buf[1], buffer_size); + lv_disp_draw_buf_init(&disp_buf, lvgl_buf[0], lvgl_buf[1], buffer_size); ESP_LOGD(TAG, "Register display driver to LVGL"); lv_disp_drv_init(&disp_drv); @@ -550,16 +668,33 @@ static void tick_increment(void *arg) lv_tick_inc(LVGL_PORT_TICK_PERIOD_MS); } -static esp_err_t tick_init(void) +static bool tick_init(void) { // Tick interface for LVGL (using esp_timer to generate 2ms periodic event) const esp_timer_create_args_t lvgl_tick_timer_args = { .callback = &tick_increment, .name = "LVGL tick" }; - esp_timer_handle_t lvgl_tick_timer = NULL; - ESP_ERROR_CHECK(esp_timer_create(&lvgl_tick_timer_args, &lvgl_tick_timer)); - return esp_timer_start_periodic(lvgl_tick_timer, LVGL_PORT_TICK_PERIOD_MS * 1000); + ESP_PANEL_CHECK_ERR_RET( + esp_timer_create(&lvgl_tick_timer_args, &lvgl_tick_timer), false, "Create LVGL tick timer failed" + ); + ESP_PANEL_CHECK_ERR_RET( + esp_timer_start_periodic(lvgl_tick_timer, LVGL_PORT_TICK_PERIOD_MS * 1000), false, + "Start LVGL tick timer failed" + ); + + return true; +} + +static bool tick_deinit(void) +{ + ESP_PANEL_CHECK_ERR_RET( + esp_timer_stop(lvgl_tick_timer), false, "Stop LVGL tick timer failed" + ); + ESP_PANEL_CHECK_ERR_RET( + esp_timer_delete(lvgl_tick_timer), false, "Delete LVGL tick timer failed" + ); + return true; } #endif @@ -582,7 +717,7 @@ static void lvgl_port_task(void *arg) } } -IRAM_ATTR bool onRefreshFinishCallback(void *user_data) +IRAM_ATTR bool onDrawBitmapFinishCallback(void *user_data) { lv_disp_drv_t *drv = (lv_disp_drv_t *)user_data; @@ -594,9 +729,14 @@ IRAM_ATTR bool onRefreshFinishCallback(void *user_data) bool lvgl_port_init(ESP_PanelLcd *lcd, ESP_PanelTouch *tp) { ESP_PANEL_CHECK_FALSE_RET(lcd != nullptr, false, "Invalid LCD device"); + + auto bus_type = lcd->getBus()->getType(); #if LVGL_PORT_AVOID_TEAR - ESP_PANEL_CHECK_FALSE_RET(lcd->getBus()->getType() == ESP_PANEL_BUS_TYPE_RGB, false, "Avoid tearing function only works with RGB LCD now"); - ESP_LOGD(TAG, "Avoid tearing is enabled, mode: %d", LVGL_PORT_AVOID_TEARING_MODE); + ESP_PANEL_CHECK_FALSE_RET( + (bus_type == ESP_PANEL_BUS_TYPE_RGB) || (bus_type == ESP_PANEL_BUS_TYPE_MIPI_DSI), false, + "Avoid tearing function only works with RGB/MIPI-DSI LCD now" + ); + ESP_LOGI(TAG, "Avoid tearing is enabled, mode: %d", LVGL_PORT_AVOID_TEARING_MODE); #endif lv_disp_t *disp = nullptr; @@ -604,7 +744,7 @@ bool lvgl_port_init(ESP_PanelLcd *lcd, ESP_PanelTouch *tp) lv_init(); #if !LV_TICK_CUSTOM - ESP_PANEL_CHECK_ERR_RET(tick_init(), false, "Initialize LVGL tick failed"); + ESP_PANEL_CHECK_FALSE_RET(tick_init(), false, "Initialize LVGL tick failed"); #endif ESP_LOGD(TAG, "Initialize LVGL display driver"); @@ -614,9 +754,9 @@ bool lvgl_port_init(ESP_PanelLcd *lcd, ESP_PanelTouch *tp) lv_disp_set_rotation(disp, LV_DISP_ROT_NONE); // For non-RGB LCD, need to notify LVGL that the buffer is ready when the refresh is finished - if (lcd->getBus()->getType() != ESP_PANEL_BUS_TYPE_RGB) { + if (bus_type != ESP_PANEL_BUS_TYPE_RGB) { ESP_LOGD(TAG, "Attach refresh finish callback to LCD"); - lcd->attachRefreshFinishCallback(onRefreshFinishCallback, (void *)disp->driver); + lcd->attachDrawBitmapFinishCallback(onDrawBitmapFinishCallback, (void *)disp->driver); } if (tp != nullptr) { @@ -647,7 +787,7 @@ bool lvgl_port_init(ESP_PanelLcd *lcd, ESP_PanelTouch *tp) ESP_PANEL_CHECK_FALSE_RET(ret == pdPASS, false, "Create LVGL task failed"); #if LVGL_PORT_AVOID_TEAR - lcd->attachRefreshFinishCallback(onRgbVsyncCallback, (void *)lvgl_task_handle); + lcd->attachRefreshFinishCallback(onLcdVsyncCallback, (void *)lvgl_task_handle); #endif return true; @@ -669,3 +809,35 @@ bool lvgl_port_unlock(void) return true; } + +bool lvgl_port_deinit(void) +{ +#if !LV_TICK_CUSTOM + ESP_PANEL_CHECK_FALSE_RET(tick_deinit(), false, "Deinitialize LVGL tick failed"); +#endif + + ESP_PANEL_CHECK_FALSE_RET(lvgl_port_lock(-1), false, "Lock LVGL failed"); + if (lvgl_task_handle != nullptr) { + vTaskDelete(lvgl_task_handle); + lvgl_task_handle = nullptr; + } + ESP_PANEL_CHECK_FALSE_RET(lvgl_port_unlock(), false, "Unlock LVGL failed"); + +#if LV_ENABLE_GC || !LV_MEM_CUSTOM + lv_deinit(); +#endif +#if !LVGL_PORT_AVOID_TEAR + for (int i = 0; i < LVGL_PORT_BUFFER_NUM; i++) { + if (lvgl_buf[i] != nullptr) { + free(lvgl_buf[i]); + lvgl_buf[i] = nullptr; + } + } +#endif + if (lvgl_mux != nullptr) { + vSemaphoreDelete(lvgl_mux); + lvgl_mux = nullptr; + } + + return true; +} diff --git a/examples/Touch/I2C/I2C.ino b/examples/Touch/I2C/I2C.ino index fdf95e1e..bf0de087 100644 --- a/examples/Touch/I2C/I2C.ino +++ b/examples/Touch/I2C/I2C.ino @@ -11,9 +11,9 @@ * * ## How to use * - * 1. [Configure drivers](https://github.com/esp-arduino-libs/ESP32_Display_Panel/docs/How_To_Use.md#configuring-drivers) if needed. + * 1. [Configure drivers](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/How_To_Use.md#configuring-drivers) if needed. * 2. Modify the macros in the example to match the parameters according to your hardware. - * 3. Navigate to the `Tools` menu in the Arduino IDE to choose a ESP board and configure its parameters, please refter to [Configuring Supported Development Boards](https://github.com/esp-arduino-libs/ESP32_Display_Panel/docs/How_To_Use.md#configuring-supported-development-boards) + * 3. Navigate to the `Tools` menu in the Arduino IDE to choose a ESP board and configure its parameters, please refter to [Configuring Supported Development Boards](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/How_To_Use.md#configuring-supported-development-boards) * 4. Verify and upload the example to your ESP board. * * ## Serial Output @@ -34,7 +34,7 @@ * * ## Troubleshooting * - * Please check the [FAQ](https://github.com/esp-arduino-libs/ESP32_Display_Panel/docs/faq.md) first to see if the same question exists. If not, please create a [Github issue](https://github.com/esp-arduino-libs/ESP32_Display_Panel/issues). We will get back to you as soon as possible. + * Please check the [FAQ](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/FAQ.md) first to see if the same question exists. If not, please create a [Github issue](https://github.com/esp-arduino-libs/ESP32_Display_Panel/issues). We will get back to you as soon as possible. * */ diff --git a/examples/Touch/SPI/SPI.ino b/examples/Touch/SPI/SPI.ino index 7e204c42..5cab2dbc 100644 --- a/examples/Touch/SPI/SPI.ino +++ b/examples/Touch/SPI/SPI.ino @@ -11,9 +11,9 @@ * * ## How to use * - * 1. [Configure drivers](https://github.com/esp-arduino-libs/ESP32_Display_Panel/docs/How_To_Use.md#configuring-drivers) if needed. + * 1. [Configure drivers](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/How_To_Use.md#configuring-drivers) if needed. * 2. Modify the macros in the example to match the parameters according to your hardware. - * 3. Navigate to the `Tools` menu in the Arduino IDE to choose a ESP board and configure its parameters, please refter to [Configuring Supported Development Boards](https://github.com/esp-arduino-libs/ESP32_Display_Panel/docs/How_To_Use.md#configuring-supported-development-boards) + * 3. Navigate to the `Tools` menu in the Arduino IDE to choose a ESP board and configure its parameters, please refter to [Configuring Supported Development Boards](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/How_To_Use.md#configuring-supported-development-boards) * 4. Verify and upload the example to your ESP board. * * ## Serial Output @@ -34,7 +34,7 @@ * * ## Troubleshooting * - * Please check the [FAQ](https://github.com/esp-arduino-libs/ESP32_Display_Panel/docs/faq.md) first to see if the same question exists. If not, please create a [Github issue](https://github.com/esp-arduino-libs/ESP32_Display_Panel/issues). We will get back to you as soon as possible. + * Please check the [FAQ](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/FAQ.md) first to see if the same question exists. If not, please create a [Github issue](https://github.com/esp-arduino-libs/ESP32_Display_Panel/issues). We will get back to you as soon as possible. * */ diff --git a/library.properties b/library.properties index 97ee5217..c8b92e57 100644 --- a/library.properties +++ b/library.properties @@ -3,7 +3,7 @@ version=0.2.0 author=espressif maintainer=espressif sentence=ESP32_Display_Panel is an library designed for ESP SoCs to drive display panels and facilitate rapid GUI development. -paragraph=Currently supported boards:ESP32-C3-LCDkit,ESP32-S3-BOX,ESP32-S3-BOX-3,ESP32-S3-BOX-3B,ESP32-S3-BOX-3(beta),ESP32-S3-BOX-Lite,ESP32-S3-EYE,ESP32-S3-Korvo-2,ESP32-S3-LCD-EV-Board,ESP32-S3-LCD-EV-Board-2,ESP32-S3-USB-OTG,M5STACK-M5CORE2,M5STACK-M5DIAL,M5STACK-M5CORES3,ESP32-4848S040C_I_Y_3,ESP32-S3-Touch-LCD-4.3,ESP32-S3-Touch-LCD-1.85,ESP32-S3-Touch-LCD-2.1. Currently supported devices: Bus,LCD,Touch,Backlight,IO expander. Currently supported Bus: I2C,SPI,QSPI,3-wire SPI + RGB. Currently supported LCD controllers: EK9716B,GC9A01,GC9B71,GC9503,ILI9341,NV3022B,ST7262,ST7701,ST7789,ST7796,ST77916,ST77922. Currently supported Touch controllers: CST816S,FT5x06,GT1151,GT911,ST7123,TT21100,XPT2046. +paragraph=Currently supported boards:ESP32-C3-LCDkit,ESP32-S3-BOX,ESP32-S3-BOX-3,ESP32-S3-BOX-3B,ESP32-S3-BOX-3(beta),ESP32-S3-BOX-Lite,ESP32-S3-EYE,ESP32-S3-Korvo-2,ESP32-S3-LCD-EV-Board,ESP32-S3-LCD-EV-Board-2,ESP32-S3-USB-OTG,ESP32-P4-Function-EV-Board,M5STACK-M5CORE2,M5STACK-M5DIAL,M5STACK-M5CORES3,ESP32-4848S040C_I_Y_3,ESP32-S3-Touch-LCD-4.3,ESP32-S3-Touch-LCD-1.85,ESP32-S3-Touch-LCD-2.1. Currently supported devices: Bus,LCD,Touch,Backlight,IO expander. Currently supported Bus: I2C,SPI,QSPI,3-wire SPI + RGB. Currently supported LCD controllers: EK9716B,GC9A01,GC9B71,GC9503,ILI9341,NV3022B,ST7262,ST7701,ST7789,ST7796,ST77916,ST77922. Currently supported Touch controllers: CST816S,FT5x06,GT1151,GT911,ST7123,TT21100,XPT2046. category=Other architectures=esp32 url=https://github.com/esp-arduino-libs/ESP32_Display_Panel diff --git a/src/ESP_Panel.cpp b/src/ESP_Panel.cpp index b4eaaf35..4b02877c 100644 --- a/src/ESP_Panel.cpp +++ b/src/ESP_Panel.cpp @@ -229,7 +229,7 @@ bool ESP_Panel::init(void) }, .data_width = ESP_PANEL_LCD_RGB_DATA_WIDTH, .bits_per_pixel = ESP_PANEL_LCD_RGB_PIXEL_BITS, - .num_fbs = ESP_PANEL_LCD_RGB_FRAME_BUF_NUM, + .num_fbs = 1, .bounce_buffer_size_px = ESP_PANEL_LCD_RGB_BOUNCE_BUF_SIZE, .sram_trans_align = 4, .psram_trans_align = 64, @@ -261,6 +261,21 @@ bool ESP_Panel::init(void) }, }; +#elif ESP_PANEL_LCD_BUS_TYPE == ESP_PANEL_BUS_TYPE_MIPI_DSI + + ESP_LOGD(TAG, "Use MIPI-DSI bus"); + // MIPI-DSI bus + esp_lcd_dsi_bus_config_t dsi_bus_config = ESP_PANEL_HOST_DSI_CONFIG_DEFAULT( + ESP_PANEL_LCD_MIPI_DSI_LANE_NUM, ESP_PANEL_LCD_MIPI_DSI_LANE_RATE_MBPS + ); + // MIPI-DPI panel + esp_lcd_dpi_panel_config_t dpi_panel_config = ESP_PANEL_DPI_CONFIG_DEFAULT( + ESP_PANEL_LCD_MIPI_DPI_CLK_MHZ, ESP_PANEL_LCD_MIPI_DPI_PIXEL_BITS, + ESP_PANEL_LCD_WIDTH, ESP_PANEL_LCD_HEIGHT, + ESP_PANEL_LCD_MIPI_DSI_HPW, ESP_PANEL_LCD_MIPI_DSI_HBP, ESP_PANEL_LCD_MIPI_DSI_HFP, + ESP_PANEL_LCD_MIPI_DSI_VPW, ESP_PANEL_LCD_MIPI_DSI_VBP, ESP_PANEL_LCD_MIPI_DSI_VFP + ); + #else #error "This function is not ready and will be implemented in the future." @@ -273,19 +288,12 @@ bool ESP_Panel::init(void) .init_cmds = lcd_init_cmds, .init_cmds_size = sizeof(lcd_init_cmds) / sizeof(lcd_init_cmds[0]), #endif -#if ESP_PANEL_LCD_BUS_TYPE == ESP_PANEL_BUS_TYPE_RGB - .rgb_config = &rgb_panel_config, .flags = { -#if !ESP_PANEL_LCD_BUS_SKIP_INIT_HOST +#if (ESP_PANEL_LCD_BUS_TYPE == ESP_PANEL_BUS_TYPE_RGB) && !ESP_PANEL_LCD_BUS_SKIP_INIT_HOST .mirror_by_cmd = ESP_PANEL_LCD_FLAGS_MIRROR_BY_CMD, .auto_del_panel_io = ESP_PANEL_LCD_FLAGS_AUTO_DEL_PANEL_IO, #endif }, -#elif ESP_PANEL_LCD_BUS_TYPE == ESP_PANEL_BUS_TYPE_QSPI - .flags = { - .use_qspi_interface = true, - }, -#endif }; // LCD device configuration @@ -308,14 +316,18 @@ bool ESP_Panel::init(void) #else lcd_bus_ptr = CREATE_BUS_SKIP_HOST(ESP_PANEL_LCD_BUS_NAME, rgb_panel_config, ESP_PANEL_LCD_BUS_HOST); #endif +#elif ESP_PANEL_LCD_BUS_TYPE == ESP_PANEL_BUS_TYPE_MIPI_DSI + lcd_bus_ptr = CREATE_BUS_INIT_HOST( + ESP_PANEL_LCD_BUS_NAME, dsi_bus_config, dpi_panel_config, ESP_PANEL_LCD_MIPI_DSI_PHY_LDO_ID + ); #else - /* For non-RGB LCD, should use `ADD_HOST()` to init host when `ESP_PANEL_LCD_BUS_SKIP_INIT_HOST` enabled */ + /* For other LCDs, should use `ADD_HOST()` to init host when `ESP_PANEL_LCD_BUS_SKIP_INIT_HOST` enabled */ #if !ESP_PANEL_LCD_BUS_SKIP_INIT_HOST ESP_PANEL_CHECK_FALSE_RET(ADD_HOST(ESP_PANEL_LCD_BUS_NAME, host_ptr, lcd_bus_host_config, ESP_PANEL_LCD_BUS_HOST), false, "Add host failed"); #endif lcd_bus_ptr = CREATE_BUS_SKIP_HOST(ESP_PANEL_LCD_BUS_NAME, lcd_panel_io_config, ESP_PANEL_LCD_BUS_HOST); -#endif +#endif /* ESP_PANEL_LCD_BUS_TYPE */ ESP_PANEL_CHECK_NULL_RET(lcd_bus_ptr, false, "Create LCD bus failed"); @@ -498,17 +510,18 @@ bool ESP_Panel::begin(void) ESP_LOGD(TAG, "Begin LCD"); #if ESP_PANEL_USE_EXPANDER && ((ESP_PANEL_LCD_3WIRE_SPI_CS_USE_EXPNADER) || (ESP_PANEL_LCD_3WIRE_SPI_SCL_USE_EXPNADER) || \ (ESP_PANEL_LCD_3WIRE_SPI_SDA_USE_EXPNADER)) - shared_ptr lcd_bus_ptr = static_pointer_cast(_lcd_bus_ptr); - lcd_bus_ptr->configSpiLine(ESP_PANEL_LCD_3WIRE_SPI_CS_USE_EXPNADER, ESP_PANEL_LCD_3WIRE_SPI_SCL_USE_EXPNADER, - ESP_PANEL_LCD_3WIRE_SPI_SDA_USE_EXPNADER, _expander_ptr.get()); + if (_lcd_bus_ptr->getType() == ESP_PANEL_BUS_TYPE_RGB) { + shared_ptr lcd_bus_ptr = static_pointer_cast(_lcd_bus_ptr); + lcd_bus_ptr->configSpiLine( + ESP_PANEL_LCD_3WIRE_SPI_CS_USE_EXPNADER, ESP_PANEL_LCD_3WIRE_SPI_SCL_USE_EXPNADER, + ESP_PANEL_LCD_3WIRE_SPI_SDA_USE_EXPNADER, _expander_ptr.get() + ); + } #endif ESP_PANEL_CHECK_FALSE_RET(_lcd_bus_ptr->begin(), false, "Begin LCD bus failed"); ESP_PANEL_CHECK_FALSE_RET(_lcd_ptr->init(), false, "Initialize LCD failed"); - // Operate LCD device according to the optional configurations -#if (ESP_PANEL_LCD_BUS_TYPE != ESP_PANEL_BUS_TYPE_RGB) || !ESP_PANEL_LCD_FLAGS_AUTO_DEL_PANEL_IO - // We can't reset the LCD if the bus is RGB bus and the `ESP_PANEL_LCD_FLAGS_AUTO_DEL_PANEL_IO` is enabled ESP_PANEL_CHECK_FALSE_RET(_lcd_ptr->reset(), false, "Reset LCD failed"); -#endif + // Operate LCD device according to the optional configurations #ifdef ESP_PANEL_LCD_SWAP_XY ESP_PANEL_CHECK_FALSE_RET(_lcd_ptr->swapXY(ESP_PANEL_LCD_SWAP_XY), false, "Swap XY failed"); #endif @@ -522,18 +535,7 @@ bool ESP_Panel::begin(void) ESP_PANEL_CHECK_FALSE_RET(_lcd_ptr->invertColor(ESP_PANEL_LCD_INEVRT_COLOR), false, "Invert color failed"); #endif ESP_PANEL_CHECK_FALSE_RET(_lcd_ptr->begin(), false, "Begin LCD failed"); - /** - * Turn on display only when meets one of the following conditions: - * - The LCD bus is not RGB bus - * - The LCD bus is "3wire-SPI + RGB" bus and the `ESP_PANEL_LCD_FLAGS_AUTO_DEL_PANEL_IO` is disabled - * - The LCD bus is RGB (with or without 3-wire SPI) bus and the `ESP_PANEL_LCD_RGB_IO_DISP` pin is used - * - */ -#if (ESP_PANEL_LCD_BUS_TYPE != ESP_PANEL_BUS_TYPE_RGB) || \ - (defined(ESP_PANEL_LCD_RGB_IO_DISP) && (ESP_PANEL_LCD_RGB_IO_DISP != -1)) || \ - (defined(ESP_PANEL_LCD_FLAGS_AUTO_DEL_PANEL_IO) && !ESP_PANEL_LCD_FLAGS_AUTO_DEL_PANEL_IO) ESP_PANEL_CHECK_FALSE_RET(_lcd_ptr->displayOn(), false, "Display on failed"); -#endif // Run additional code after the LCD is started if needed #ifdef ESP_PANEL_BEGIN_LCD_END_FUNCTION ESP_PANEL_BEGIN_LCD_END_FUNCTION(this); @@ -640,37 +642,21 @@ bool ESP_Panel::del(void) ESP_PanelLcd *ESP_Panel::getLcd(void) { - if (_lcd_ptr == nullptr) { - ESP_LOGD(TAG, "Get invalid LCD pointer"); - } - return _lcd_ptr.get(); } ESP_PanelTouch *ESP_Panel::getTouch(void) { - if (_touch_ptr == nullptr) { - ESP_LOGD(TAG, "Get invalid touch pointer"); - } - return _touch_ptr.get(); } ESP_PanelBacklight *ESP_Panel::getBacklight(void) { - if (_backlight_ptr == nullptr) { - ESP_LOGD(TAG, "Get invalid backlight pointer"); - } - return _backlight_ptr.get(); } ESP_IOExpander *ESP_Panel::getExpander(void) { - if (_expander_ptr == nullptr) { - ESP_LOGD(TAG, "Get invalid expander pointer"); - } - return _expander_ptr.get(); } diff --git a/src/ESP_PanelLog.h b/src/ESP_PanelLog.h index 9d1387d1..7498cc34 100644 --- a/src/ESP_PanelLog.h +++ b/src/ESP_PanelLog.h @@ -30,15 +30,15 @@ #define ESP_PANEL_CHECK_NULL_RET(x, ...) assert((x) != NULL) #define ESP_PANEL_CHECK_FALSE_RET(x, ...) assert((x) != false) #else -#if ESP_PANEL_ENABLE_LOG +// #if ESP_PANEL_ENABLE_LOG #define ESP_PANEL_ERROR_CHECK_LOG_FORMAT(err, format) "[%s] %s(%u): " format, esp_err_to_name(err), __FUNCTION__, __LINE__ #define ESP_PANEL_ERROR_CHECK_LOGE(tag, err, format, ...) ESP_LOGE(tag, ESP_PANEL_ERROR_CHECK_LOG_FORMAT(err, format), ##__VA_ARGS__) #define ESP_PANEL_OTHER_CHECK_LOG_FORMAT(format) "%s(%u): " format, __FUNCTION__, __LINE__ #define ESP_PANEL_OTHER_CHECK_LOGE(tag, format, ...) ESP_LOGE(tag, ESP_PANEL_OTHER_CHECK_LOG_FORMAT(format), ##__VA_ARGS__) -#else -#define ESP_PANEL_ERROR_CHECK_LOGE(tag, err, format, ...) do {} while(0) -#define ESP_PANEL_OTHER_CHECK_LOGE(tag, format, ...) do {} while(0) -#endif +// #else +// #define ESP_PANEL_ERROR_CHECK_LOGE(tag, err, format, ...) do {} while(0) +// #define ESP_PANEL_OTHER_CHECK_LOGE(tag, format, ...) do {} while(0) +// #endif #define ESP_PANEL_CHECK_ERR_RET(x, ret, fmt, ...) do { \ esp_err_t err_rc_ = (x); \ diff --git a/src/ESP_PanelTypes.h b/src/ESP_PanelTypes.h index c6532daf..9d24f070 100644 --- a/src/ESP_PanelTypes.h +++ b/src/ESP_PanelTypes.h @@ -10,7 +10,7 @@ #include "sdkconfig.h" /** - * @brief Panel bus type macros + * @brief Macros for bus type * */ #define ESP_PANEL_BUS_TYPE_UNKNOWN (0) @@ -19,7 +19,16 @@ #define ESP_PANEL_BUS_TYPE_RGB (3) #define ESP_PANEL_BUS_TYPE_I2C (4) #define ESP_PANEL_BUS_TYPE_I80 (5) -#define ESP_PANEL_BUS_TYPE_MAX (6) +#define ESP_PANEL_BUS_TYPE_MIPI_DSI (6) +#define ESP_PANEL_BUS_TYPE_MAX (7) + +/** + * @brief Macros for LCD color format bits + * + */ +#define ESP_PANEL_LCD_RGB565_COLOR_BITS_16 (16) +#define ESP_PANEL_LCD_RGB666_COLOR_BITS_18 (18) +#define ESP_PANEL_LCD_RGB888_COLOR_BITS_24 (24) /** * @brief This macro is used to generate the I2C panel IO configuration according to the touch panel name. diff --git a/src/ESP_PanelVersions.h b/src/ESP_PanelVersions.h index f8338218..db246b84 100644 --- a/src/ESP_PanelVersions.h +++ b/src/ESP_PanelVersions.h @@ -20,19 +20,22 @@ /* File `ESP_Panel_Board_Custom.h` */ #define ESP_PANEL_BOARD_CUSTOM_VERSION_MAJOR 0 -#define ESP_PANEL_BOARD_CUSTOM_VERSION_MINOR 2 -#define ESP_PANEL_BOARD_CUSTOM_VERSION_PATCH 3 +#define ESP_PANEL_BOARD_CUSTOM_VERSION_MINOR 3 +#define ESP_PANEL_BOARD_CUSTOM_VERSION_PATCH 0 /* File `ESP_Panel_Board_Supported.h` */ #define ESP_PANEL_BOARD_SUPPORTED_VERSION_MAJOR 0 -#define ESP_PANEL_BOARD_SUPPORTED_VERSION_MINOR 5 -#define ESP_PANEL_BOARD_SUPPORTED_VERSION_PATCH 1 +#define ESP_PANEL_BOARD_SUPPORTED_VERSION_MINOR 6 +#define ESP_PANEL_BOARD_SUPPORTED_VERSION_PATCH 0 // *INDENT-OFF* +/** + * Check if the current configuration file version is compatible with the library version + * + */ +/* File `ESP_Panel_Conf.h` */ #ifndef ESP_PANEL_CONF_FILE_SKIP - /* Check if the current configuration file version is compatible with the library version */ - // File `ESP_Panel_Conf.h` // If the version is not defined, set it to `0.1.0` #if !defined(ESP_PANEL_CONF_FILE_VERSION_MAJOR) && \ !defined(ESP_PANEL_CONF_FILE_VERSION_MINOR) && \ @@ -51,46 +54,51 @@ #endif /* ESP_PANEL_CONF_INCLUDE_INSIDE */ #endif /* ESP_PANEL_CONF_FILE_SKIP */ -#ifndef ESP_PANEL_BOARD_FILE_SKIP - // File `ESP_Panel_Board_Custom.h` & `ESP_Panel_Board_Supported.h` - #ifdef ESP_PANEL_USE_BOARD - /* For using a supported board */ - #if ESP_PANEL_USE_SUPPORTED_BOARD - // If the version is not defined, set it to `0.1.0` - #if !defined(ESP_PANEL_BOARD_SUPPORTED_FILE_VERSION_MAJOR) && \ - !defined(ESP_PANEL_BOARD_SUPPORTED_FILE_VERSION_MINOR) && \ - !defined(ESP_PANEL_BOARD_SUPPORTED_FILE_VERSION_PATCH) - #define ESP_PANEL_BOARD_SUPPORTED_FILE_VERSION_MAJOR 0 - #define ESP_PANEL_BOARD_SUPPORTED_FILE_VERSION_MINOR 1 - #define ESP_PANEL_BOARD_SUPPORTED_FILE_VERSION_PATCH 0 - #endif - // Check if the current configuration file version is compatible with the library version - #if ESP_PANEL_BOARD_SUPPORTED_FILE_VERSION_MAJOR != ESP_PANEL_BOARD_SUPPORTED_VERSION_MAJOR - #error "The file `ESP_Panel_Board_Supported.h` version is not compatible. Please update it with the file from the library" - #elif ESP_PANEL_BOARD_SUPPORTED_FILE_VERSION_MINOR < ESP_PANEL_BOARD_SUPPORTED_VERSION_MINOR - #warning "The file `ESP_Panel_Board_Supported.h` version is outdated. Some new configurations are missing" - #elif ESP_PANEL_BOARD_SUPPORTED_FILE_VERSION_MINOR > ESP_PANEL_BOARD_SUPPORTED_VERSION_MINOR - #warning "The file `ESP_Panel_Board_Supported.h` version is newer than the library. Some new configurations are not supported" - #endif - #else /* For using a custom board */ - // If the version is not defined, set it to `0.1.0` - #if !defined(ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_MAJOR) && \ - !defined(ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_MINOR) && \ - !defined(ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_PATCH) - #define ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_MAJOR 0 - #define ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_MINOR 1 - #define ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_PATCH 0 - #endif - // Check if the current configuration file version is compatible with the library version - #if ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_MAJOR != ESP_PANEL_BOARD_CUSTOM_VERSION_MAJOR - #error "The file `ESP_Panel_Board_Custom.h` version is not compatible. Please update it with the file from the library" - #elif ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_MINOR < ESP_PANEL_BOARD_CUSTOM_VERSION_MINOR - #warning "The file `ESP_Panel_Board_Custom.h` version is outdated. Some new configurations are missing" - #elif ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_MINOR > ESP_PANEL_BOARD_CUSTOM_VERSION_PATCH - #warning "The file `ESP_Panel_Board_Custom.h` version is newer than the library. Some new configurations are not supported" - #endif - #endif /* CONFIG_ESP_PANEL_USE_SUPPORTED_BOARD || ESP_PANEL_USE_SUPPORTED_BOARD */ - #endif /* ESP_PANEL_USE_BOARD */ -#endif /* ESP_PANEL_BOARD_FILE_SKIP */ +/* File `ESP_Panel_Board_Custom.h` & `ESP_Panel_Board_Supported.h` */ +#ifdef ESP_PANEL_USE_BOARD + /* File `ESP_Panel_Board_Supported.h` */ + // Only check this file versions if use a supported board and not skip the file + #if ESP_PANEL_USE_SUPPORTED_BOARD && !defined(ESP_PANEL_BOARD_FILE_SKIP) + // If the version is not defined, set it to `0.1.0` + #if !defined(ESP_PANEL_BOARD_SUPPORTED_FILE_VERSION_MAJOR) && \ + !defined(ESP_PANEL_BOARD_SUPPORTED_FILE_VERSION_MINOR) && \ + !defined(ESP_PANEL_BOARD_SUPPORTED_FILE_VERSION_PATCH) + #define ESP_PANEL_BOARD_SUPPORTED_FILE_VERSION_MAJOR 0 + #define ESP_PANEL_BOARD_SUPPORTED_FILE_VERSION_MINOR 1 + #define ESP_PANEL_BOARD_SUPPORTED_FILE_VERSION_PATCH 0 + #endif + // Check if the current configuration file version is compatible with the library version + #if ESP_PANEL_BOARD_SUPPORTED_FILE_VERSION_MAJOR != ESP_PANEL_BOARD_SUPPORTED_VERSION_MAJOR + #error "The file `ESP_Panel_Board_Supported.h` version is not compatible. Please update it with the file from the library" + #elif ESP_PANEL_BOARD_SUPPORTED_FILE_VERSION_MINOR < ESP_PANEL_BOARD_SUPPORTED_VERSION_MINOR + #warning "The file `ESP_Panel_Board_Supported.h` version is outdated. Some new configurations are missing" + #elif ESP_PANEL_BOARD_SUPPORTED_FILE_VERSION_MINOR > ESP_PANEL_BOARD_SUPPORTED_VERSION_MINOR + #warning "The file `ESP_Panel_Board_Supported.h` version is newer than the library. Some new configurations are not supported" + #endif + #endif + + /* File `ESP_Panel_Board_Custom.h` */ + // If the version is not defined, set it to `0.1.0` + #if !defined(ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_MAJOR) && \ + !defined(ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_MINOR) && \ + !defined(ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_PATCH) + #define ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_MAJOR 0 + #define ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_MINOR 1 + #define ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_PATCH 0 + #endif + // Check if the current configuration file version is compatible with the library version + // Must check the major version + #if ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_MAJOR != ESP_PANEL_BOARD_CUSTOM_VERSION_MAJOR + #error "The file `ESP_Panel_Board_Custom.h` version is not compatible. Please update it with the file from the library" + #endif + // Only check the other versions if not skip the file + #if !defined(ESP_PANEL_BOARD_FILE_SKIP) + #if ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_MINOR < ESP_PANEL_BOARD_CUSTOM_VERSION_MINOR + #warning "The file `ESP_Panel_Board_Custom.h` version is outdated. Some new configurations are missing" + #elif ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_MINOR > ESP_PANEL_BOARD_CUSTOM_VERSION_PATCH + #warning "The file `ESP_Panel_Board_Custom.h` version is newer than the library. Some new configurations are not supported" + #endif + #endif +#endif /* ESP_PANEL_USE_BOARD */ // *INDENT-OFF* diff --git a/src/ESP_Panel_Board_Internal.h b/src/ESP_Panel_Board_Internal.h index 91527867..d221135e 100644 --- a/src/ESP_Panel_Board_Internal.h +++ b/src/ESP_Panel_Board_Internal.h @@ -119,12 +119,20 @@ #elif ESP_PANEL_LCD_BUS_TYPE == ESP_PANEL_BUS_TYPE_RGB - #ifndef SOC_LCD_RGB_SUPPORTED + #if !SOC_LCD_RGB_SUPPORTED #error "RGB is not supported for current SoC, please select the correct board." #endif #define ESP_PANEL_LCD_BUS_NAME RGB #define ESP_PANEL_LCD_BUS_HOST (-1) + #elif ESP_PANEL_LCD_BUS_TYPE == ESP_PANEL_BUS_TYPE_MIPI_DSI + + #if !SOC_MIPI_DSI_SUPPORTED + #error "MIPI-DSI is not supported for current SoC, please select the correct board." + #endif + #define ESP_PANEL_LCD_BUS_NAME DSI + #define ESP_PANEL_LCD_BUS_HOST (-1) + #else #error "Unknown LCD panel bus type selected, please refer to the README for supported bus types" diff --git a/src/ESP_Panel_Board_Kconfig.h b/src/ESP_Panel_Board_Kconfig.h index 34054e9d..ebe9fb6e 100644 --- a/src/ESP_Panel_Board_Kconfig.h +++ b/src/ESP_Panel_Board_Kconfig.h @@ -91,6 +91,16 @@ #define BOARD_ESP32_S3_USB_OTG CONFIG_BOARD_ESP32_S3_USB_OTG #endif #endif + #ifndef BOARD_ESP32_P4_FUNCTION_EV_BOARD + #ifdef CONFIG_BOARD_ESP32_P4_FUNCTION_EV_BOARD + #define BOARD_ESP32_P4_FUNCTION_EV_BOARD CONFIG_BOARD_ESP32_P4_FUNCTION_EV_BOARD + #endif + #endif + #ifndef BOARD_ESP32_P4_FUNCTION_EV_BOARD_800_1280 + #ifdef CONFIG_BOARD_ESP32_P4_FUNCTION_EV_BOARD_800_1280 + #define BOARD_ESP32_P4_FUNCTION_EV_BOARD_800_1280 CONFIG_BOARD_ESP32_P4_FUNCTION_EV_BOARD_800_1280 + #endif + #endif // Elecrow #ifndef BOARD_ELECROW_CROWPANEL_7_0 #ifdef CONFIG_BOARD_ELECROW_CROWPANEL_7_0 diff --git a/src/ESP_Panel_Library.h b/src/ESP_Panel_Library.h index 23d72bd0..870a0620 100644 --- a/src/ESP_Panel_Library.h +++ b/src/ESP_Panel_Library.h @@ -21,14 +21,17 @@ #include "bus/SPI.h" #include "bus/RGB.h" #include "bus/QSPI.h" +#include "bus/DSI.h" /* LCD */ #include "lcd/ESP_PanelLcd.h" +#include "lcd/EK79007.h" #include "lcd/EK9716B.h" #include "lcd/GC9503.h" #include "lcd/GC9A01.h" #include "lcd/GC9B71.h" #include "lcd/ILI9341.h" +#include "lcd/ILI9881C.h" #include "lcd/NV3022B.h" #include "lcd/SH8601.h" #include "lcd/SPD2010.h" diff --git a/src/board/ESP_PanelBoard.h b/src/board/ESP_PanelBoard.h index 92d083bf..50816c8e 100644 --- a/src/board/ESP_PanelBoard.h +++ b/src/board/ESP_PanelBoard.h @@ -9,63 +9,84 @@ // *INDENT-OFF* // Check if multiple boards are enabled -#if defined(BOARD_ESP32_C3_LCDKIT) + defined(BOARD_ESP32_S3_BOX) + defined(BOARD_ESP32_S3_BOX_3) + \ - defined(BOARD_ESP32_S3_BOX_3_BETA) + defined(BOARD_ESP32_S3_BOX_LITE) + defined(BOARD_ESP32_S3_EYE) + \ - defined(BOARD_ESP32_S3_KORVO_2) + defined(BOARD_ESP32_S3_LCD_EV_BOARD) + \ - defined(BOARD_ESP32_S3_LCD_EV_BOARD_V1_5) + defined(BOARD_ESP32_S3_LCD_EV_BOARD_2) + \ - defined(BOARD_ESP32_S3_LCD_EV_BOARD_2_V1_5) + defined(BOARD_ESP32_S3_USB_OTG) + defined(BOARD_ELECROW_CROWPANEL_7_0) + \ - defined(BOARD_M5STACK_M5CORE2) + defined(BOARD_M5STACK_M5DIAL) + defined(BOARD_M5STACK_M5CORES3) + \ - defined(BOARD_ESP32_4848S040C_I_Y_3) + defined(BOARD_WAVESHARE_ESP32_S3_Touch_LCD_4_3) + defined(BOARD_WAVESHARE_ESP32_S3_Touch_LCD_1_85) + \ - defined(BOARD_WAVESHARE_ESP32_S3_Touch_LCD_2_1) \ +#if \ + /* Espressif */ \ + defined(BOARD_ESP32_C3_LCDKIT) \ + + defined(BOARD_ESP32_S3_BOX) \ + + defined(BOARD_ESP32_S3_BOX_3) \ + + defined(BOARD_ESP32_S3_BOX_3_BETA) \ + + defined(BOARD_ESP32_S3_BOX_LITE) \ + + defined(BOARD_ESP32_S3_EYE) \ + + defined(BOARD_ESP32_S3_KORVO_2) \ + + defined(BOARD_ESP32_S3_LCD_EV_BOARD) \ + + defined(BOARD_ESP32_S3_LCD_EV_BOARD_V1_5) \ + + defined(BOARD_ESP32_S3_LCD_EV_BOARD_2) \ + + defined(BOARD_ESP32_S3_LCD_EV_BOARD_2_V1_5) \ + + defined(BOARD_ESP32_S3_USB_OTG) \ + + defined(BOARD_ESP32_P4_FUNCTION_EV_BOARD) \ + /* Elecrow */ \ + + defined(BOARD_ELECROW_CROWPANEL_7_0) \ + /* M5Stack */ \ + + defined(BOARD_M5STACK_M5CORE2) \ + + defined(BOARD_M5STACK_M5DIAL) \ + + defined(BOARD_M5STACK_M5CORES3) \ + /* JingCai */ \ + + defined(BOARD_ESP32_4848S040C_I_Y_3) \ + /* Waveshare */ \ + + defined(BOARD_WAVESHARE_ESP32_S3_Touch_LCD_4_3) \ + + defined(BOARD_WAVESHARE_ESP32_S3_Touch_LCD_1_85) \ + + defined(BOARD_WAVESHARE_ESP32_S3_Touch_LCD_2_1) \ > 1 #error "Multiple boards enabled! Please check file `ESP_Panel_Board_Supported.h` and make sure only one board is enabled." #endif // Include board specific header file /* Espressif */ -#if defined(BOARD_ESP32_C3_LCDKIT) || CONFIG_BOARD_ESP32_C3_LCDKIT +#if defined(BOARD_ESP32_C3_LCDKIT) #include "board/espressif/ESP32_C3_LCDKIT.h" -#elif defined(BOARD_ESP32_S3_BOX) || CONFIG_BOARD_ESP32_S3_BOX +#elif defined(BOARD_ESP32_S3_BOX) #include "board/espressif/ESP32_S3_BOX.h" -#elif defined(BOARD_ESP32_S3_BOX_3) || CONFIG_BOARD_ESP32_S3_BOX_3 +#elif defined(BOARD_ESP32_S3_BOX_3) #include "board/espressif/ESP32_S3_BOX_3.h" -#elif defined(BOARD_ESP32_S3_BOX_3_BETA) || CONFIG_BOARD_ESP32_S3_BOX_3_BETA +#elif defined(BOARD_ESP32_S3_BOX_3_BETA) #include "board/espressif/ESP32_S3_BOX_3_BETA.h" -#elif defined(BOARD_ESP32_S3_BOX_LITE) || CONFIG_BOARD_ESP32_S3_BOX_LITE +#elif defined(BOARD_ESP32_S3_BOX_LITE) #include "board/espressif/ESP32_S3_BOX_LITE.h" -#elif defined(BOARD_ESP32_S3_EYE) || CONFIG_BOARD_ESP32_S3_EYE +#elif defined(BOARD_ESP32_S3_EYE) #include "board/espressif/ESP32_S3_EYE.h" -#elif defined(BOARD_ESP32_S3_KORVO_2) || CONFIG_BOARD_ESP32_S3_KORVO_2 +#elif defined(BOARD_ESP32_S3_KORVO_2) #include "board/espressif/ESP32_S3_KORVO_2.h" -#elif defined(BOARD_ESP32_S3_LCD_EV_BOARD) || CONFIG_BOARD_ESP32_S3_LCD_EV_BOARD +#elif defined(BOARD_ESP32_S3_LCD_EV_BOARD) #include "board/espressif/ESP32_S3_LCD_EV_BOARD.h" -#elif defined(BOARD_ESP32_S3_LCD_EV_BOARD_V1_5) || CONFIG_BOARD_ESP32_S3_LCD_EV_BOARD_V1_5 +#elif defined(BOARD_ESP32_S3_LCD_EV_BOARD_V1_5) #include "board/espressif/ESP32_S3_LCD_EV_BOARD_V1_5.h" -#elif defined(BOARD_ESP32_S3_LCD_EV_BOARD_2) || CONFIG_BOARD_ESP32_S3_LCD_EV_BOARD_2 +#elif defined(BOARD_ESP32_S3_LCD_EV_BOARD_2) #include "board/espressif/ESP32_S3_LCD_EV_BOARD_2.h" -#elif defined(BOARD_ESP32_S3_LCD_EV_BOARD_2_V1_5) || CONFIG_BOARD_ESP32_S3_LCD_EV_BOARD_2_V1_5 +#elif defined(BOARD_ESP32_S3_LCD_EV_BOARD_2_V1_5) #include "board/espressif/ESP32_S3_LCD_EV_BOARD_2_V1_5.h" -#elif defined(BOARD_ESP32_S3_USB_OTG) || CONFIG_BOARD_ESP32_S3_USB_OTG +#elif defined(BOARD_ESP32_S3_USB_OTG) #include "board/espressif/ESP32_S3_USB_OTG.h" +#elif defined(BOARD_ESP32_P4_FUNCTION_EV_BOARD) + #include "board/espressif/ESP32_P4_FUNCTION_EV_BOARD.h" /* Elecrow */ -#elif defined(BOARD_ELECROW_CROWPANEL_7_0) || CONFIG_BOARD_ELECROW_CROWPANEL_7_0 +#elif defined(BOARD_ELECROW_CROWPANEL_7_0) #include "board/elecrow/CROWPANEL_7_0.h" /* M5Stack */ -#elif defined(BOARD_M5STACK_M5CORE2) || CONFIG_BOARD_M5STACK_M5CORE2 +#elif defined(BOARD_M5STACK_M5CORE2) #include "board/m5stack/M5CORE2.h" -#elif defined(BOARD_M5STACK_M5DIAL) || CONFIG_BOARD_M5STACK_M5DIAL +#elif defined(BOARD_M5STACK_M5DIAL) #include "board/m5stack/M5DIAL.h" -#elif defined(BOARD_M5STACK_M5CORES3) || CONFIG_BOARD_M5STACK_M5CORES3 +#elif defined(BOARD_M5STACK_M5CORES3) #include "board/m5stack/M5CORES3.h" /* Jingcai */ -#elif defined(BOARD_ESP32_4848S040C_I_Y_3) || CONFIG_BOARD_ESP32_4848S040C_I_Y_3 +#elif defined(BOARD_ESP32_4848S040C_I_Y_3) #include "board/jingcai/ESP32_4848S040C_I_Y_3.h" /* Waveshare */ -#elif defined(BOARD_WAVESHARE_ESP32_S3_Touch_LCD_4_3) || CONFIG_BOARD_WAVESHARE_ESP32_S3_Touch_LCD_4_3 +#elif defined(BOARD_WAVESHARE_ESP32_S3_Touch_LCD_4_3) #include "board/waveshare/ESP32_S3_Touch_LCD_4_3.h" -#elif defined(BOARD_WAVESHARE_ESP32_S3_Touch_LCD_1_85) || CONFIG_BOARD_WAVESHARE_ESP32_S3_Touch_LCD_1_85 +#elif defined(BOARD_WAVESHARE_ESP32_S3_Touch_LCD_1_85) #include "board/waveshare/ESP32_S3_Touch_LCD_1_85.h" -#elif defined(BOARD_WAVESHARE_ESP32_S3_Touch_LCD_2_1) || CONFIG_BOARD_WAVESHARE_ESP32_S3_Touch_LCD_2_1 +#elif defined(BOARD_WAVESHARE_ESP32_S3_Touch_LCD_2_1) #include "board/waveshare/ESP32_S3_Touch_LCD_2_1.h" #else #error "Unknown board selected! Please check file `ESP_Panel_Board_Supported.h` and make sure only one board is enabled." diff --git a/src/board/elecrow/CROWPANEL_7_0.h b/src/board/elecrow/CROWPANEL_7_0.h index 46ba70a0..bb9a7890 100644 --- a/src/board/elecrow/CROWPANEL_7_0.h +++ b/src/board/elecrow/CROWPANEL_7_0.h @@ -53,7 +53,7 @@ #define ESP_PANEL_LCD_RGB_PCLK_ACTIVE_NEG (1) // 0: rising edge, 1: falling edge #define ESP_PANEL_LCD_RGB_DATA_WIDTH (16) // 8 | 16 #define ESP_PANEL_LCD_RGB_PIXEL_BITS (16) // 24 | 16 - #define ESP_PANEL_LCD_RGB_FRAME_BUF_NUM (1) // 1/2/3 + #define ESP_PANEL_LCD_RGB_BOUNCE_BUF_SIZE (ESP_PANEL_LCD_WIDTH * 10) // Bounce buffer size in bytes. This function is used to avoid screen drift. // To enable the bounce buffer, set it to a non-zero value. diff --git a/src/board/espressif/ESP32_P4_FUNCTION_EV_BOARD.h b/src/board/espressif/ESP32_P4_FUNCTION_EV_BOARD.h new file mode 100644 index 00000000..ca731432 --- /dev/null +++ b/src/board/espressif/ESP32_P4_FUNCTION_EV_BOARD.h @@ -0,0 +1,225 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +// *INDENT-OFF* + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////// Please update the following macros to configure the LCD panel ///////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/* Set to 1 when using an LCD panel */ +#define ESP_PANEL_USE_LCD (1) // 0/1 + +#if ESP_PANEL_USE_LCD +/** + * LCD Controller Name. + */ +#define ESP_PANEL_LCD_NAME EK79007 + +/* LCD resolution in pixels */ +#define ESP_PANEL_LCD_WIDTH (1024) +#define ESP_PANEL_LCD_HEIGHT (600) + +/* LCD Bus Settings */ +/** + * If set to 1, the bus will skip to initialize the corresponding host. Users need to initialize the host in advance. + * It is useful if other devices use the same host. Please ensure that the host is initialized only once. + * + * Note: This macro is not useful for the MIPI-DSI bus. + * + */ +#define ESP_PANEL_LCD_BUS_SKIP_INIT_HOST (0) // 0/1 +/** + * LCD Bus Type. + */ +#define ESP_PANEL_LCD_BUS_TYPE (ESP_PANEL_BUS_TYPE_MIPI_DSI) +/** + * LCD Bus Parameters. + * + * Please refer to https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/api-reference/peripherals/lcd.html and + * https://docs.espressif.com/projects/esp-iot-solution/en/latest/display/lcd/index.html for more details. + * + */ +#if ESP_PANEL_LCD_BUS_TYPE == ESP_PANEL_BUS_TYPE_MIPI_DSI + + #define ESP_PANEL_LCD_MIPI_DSI_LANE_NUM (2) // ESP32-P4 supports 1 or 2 lanes + #define ESP_PANEL_LCD_MIPI_DSI_LANE_RATE_MBPS (1000) // Single lane bit rate, should consult the LCD supplier or check the + // LCD drive IC datasheet for the supported lane rate. + // ESP32-P4 supports max 1500Mbps + #define ESP_PANEL_LCD_MIPI_DSI_PHY_LDO_ID (3) // -1 if not used + #define ESP_PANEL_LCD_MIPI_DPI_CLK_MHZ (52) + #define ESP_PANEL_LCD_MIPI_DPI_PIXEL_BITS (ESP_PANEL_LCD_RGB565_COLOR_BITS_16) + #define ESP_PANEL_LCD_MIPI_DSI_HPW (10) + #define ESP_PANEL_LCD_MIPI_DSI_HBP (160) + #define ESP_PANEL_LCD_MIPI_DSI_HFP (160) + #define ESP_PANEL_LCD_MIPI_DSI_VPW (1) + #define ESP_PANEL_LCD_MIPI_DSI_VBP (23) + #define ESP_PANEL_LCD_MIPI_DSI_VFP (12) + +#endif /* ESP_PANEL_LCD_BUS_TYPE */ + +/** + * LCD Vendor Initialization Commands. + * + * Vendor specific initialization can be different between manufacturers, should consult the LCD supplier for + * initialization sequence code. Please uncomment and change the following macro definitions. Otherwise, the LCD driver + * will use the default initialization sequence code. + * + * There are two formats for the sequence code: + * 1. Raw data: {command, (uint8_t []){ data0, data1, ... }, data_size, delay_ms} + * 2. Formatter: ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(delay_ms, command, { data0, data1, ... }) and + * ESP_PANEL_LCD_CMD_WITH_NONE_PARAM(delay_ms, command) + */ +/* +#define ESP_PANEL_LCD_VENDOR_INIT_CMD() \ + { \ + {0xFF, (uint8_t []){0x77, 0x01, 0x00, 0x00, 0x10}, 5, 0}, \ + {0xC0, (uint8_t []){0x3B, 0x00}, 2, 0}, \ + {0xC1, (uint8_t []){0x0D, 0x02}, 2, 0}, \ + {0x29, (uint8_t []){0x00}, 0, 120}, \ + or \ + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xFF, {0x77, 0x01, 0x00, 0x00, 0x10}), \ + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xC0, {0x3B, 0x00}), \ + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xC1, {0x0D, 0x02}), \ + ESP_PANEL_LCD_CMD_WITH_NONE_PARAM(120, 0x29), \ + } +*/ + +/* LCD Color Settings */ +/* LCD color depth in bits */ +#define ESP_PANEL_LCD_COLOR_BITS (ESP_PANEL_LCD_MIPI_DPI_PIXEL_BITS) // 8/16/18/24, typically same as the pixel bits +/* + * LCD RGB Element Order. Choose one of the following: + * - 0: RGB + * - 1: BGR + */ +#define ESP_PANEL_LCD_BGR_ORDER (0) // 0/1 +#define ESP_PANEL_LCD_INEVRT_COLOR (0) // 0/1 + +/* LCD Transformation Flags */ +// #define ESP_PANEL_LCD_SWAP_XY (0) // 0/1 +// #define ESP_PANEL_LCD_MIRROR_X (0) // 0/1 +// #define ESP_PANEL_LCD_MIRROR_Y (0) // 0/1 + +/* LCD Other Settings */ +/* IO num of RESET pin, set to -1 if not use */ +#define ESP_PANEL_LCD_IO_RST (27) +#define ESP_PANEL_LCD_RST_LEVEL (0) // 0: low level, 1: high level + +#endif /* ESP_PANEL_USE_LCD */ + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////// Please update the following macros to configure the touch panel /////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/* Set to 1 when using an touch panel */ +#define ESP_PANEL_USE_TOUCH (1) // 0/1 +#if ESP_PANEL_USE_TOUCH +/** + * Touch controller name. + */ +#define ESP_PANEL_TOUCH_NAME GT911 + +/* Touch resolution in pixels */ +#define ESP_PANEL_TOUCH_H_RES (ESP_PANEL_LCD_WIDTH) // Typically set to the same value as the width of LCD +#define ESP_PANEL_TOUCH_V_RES (ESP_PANEL_LCD_HEIGHT) // Typically set to the same value as the height of LCD + +/* Touch Panel Bus Settings */ +/** + * If set to 1, the bus will skip to initialize the corresponding host. Users need to initialize the host in advance. + * It is useful if other devices use the same host. Please ensure that the host is initialized only once. + */ +#define ESP_PANEL_TOUCH_BUS_SKIP_INIT_HOST (0) // 0/1 +/** + * Touch panel bus type. + */ +#define ESP_PANEL_TOUCH_BUS_TYPE (ESP_PANEL_BUS_TYPE_I2C) +/* Touch panel bus parameters */ +#if ESP_PANEL_TOUCH_BUS_TYPE == ESP_PANEL_BUS_TYPE_I2C + + #define ESP_PANEL_TOUCH_BUS_HOST_ID (0) // Typically set to 0 + #define ESP_PANEL_TOUCH_I2C_ADDRESS (0) // Typically set to 0 to use default address +#if !ESP_PANEL_TOUCH_BUS_SKIP_INIT_HOST + #define ESP_PANEL_TOUCH_I2C_CLK_HZ (400 * 1000) + // Typically set to 400K + #define ESP_PANEL_TOUCH_I2C_SCL_PULLUP (0) // 0/1 + #define ESP_PANEL_TOUCH_I2C_SDA_PULLUP (0) // 0/1 + #define ESP_PANEL_TOUCH_I2C_IO_SCL (8) + #define ESP_PANEL_TOUCH_I2C_IO_SDA (7) +#endif + +#endif + +/* Touch Transformation Flags */ +#define ESP_PANEL_TOUCH_SWAP_XY (0) // 0/1 +#define ESP_PANEL_TOUCH_MIRROR_X (1) // 0/1 +#define ESP_PANEL_TOUCH_MIRROR_Y (1) // 0/1 + +/* Touch Other Settings */ +/* IO num of RESET pin, set to -1 if not use */ +#define ESP_PANEL_TOUCH_IO_RST (-1) +#define ESP_PANEL_TOUCH_RST_LEVEL (0) // 0: low level, 1: high level +/* IO num of INT pin, set to -1 if not use */ +#define ESP_PANEL_TOUCH_IO_INT (-1) +#define ESP_PANEL_TOUCH_INT_LEVEL (0) // 0: low level, 1: high level + +#endif /* ESP_PANEL_USE_TOUCH */ + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////// Please update the following macros to configure the backlight //////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#define ESP_PANEL_USE_BACKLIGHT (1) // 0/1 +#if ESP_PANEL_USE_BACKLIGHT +/* Backlight pin */ +#define ESP_PANEL_BACKLIGHT_IO (26) // IO num of backlight pin +#define ESP_PANEL_BACKLIGHT_ON_LEVEL (1) // 0: low level, 1: high level + +/* Set to 1 if you want to turn off the backlight after initializing the panel; otherwise, set it to turn on */ +#define ESP_PANEL_BACKLIGHT_IDLE_OFF (0) // 0: on, 1: off + +/* Set to 1 if use PWM for brightness control */ +#define ESP_PANEL_LCD_BL_USE_PWM (1) // 0/1 +#endif /* ESP_PANEL_USE_BACKLIGHT */ + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////// Please update the following macros to configure the IO expander ////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/* Set to 0 if not using IO Expander */ +#define ESP_PANEL_USE_EXPANDER (0) // 0/1 + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////// Please utilize the following macros to execute any additional code if required. ////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// #define ESP_PANEL_BEGIN_START_FUNCTION( panel ) +// #define ESP_PANEL_BEGIN_EXPANDER_START_FUNCTION( panel ) +// #define ESP_PANEL_BEGIN_EXPANDER_END_FUNCTION( panel ) +// #define ESP_PANEL_BEGIN_LCD_START_FUNCTION( panel ) +// #define ESP_PANEL_BEGIN_LCD_END_FUNCTION( panel ) +// #define ESP_PANEL_BEGIN_TOUCH_START_FUNCTION( panel ) +// #define ESP_PANEL_BEGIN_TOUCH_END_FUNCTION( panel ) +// #define ESP_PANEL_BEGIN_BACKLIGHT_START_FUNCTION( panel ) +// #define ESP_PANEL_BEGIN_BACKLIGHT_END_FUNCTION( panel ) +// #define ESP_PANEL_BEGIN_END_FUNCTION( panel ) + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////// File Version /////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Do not change the following versions, they are used to check if the configurations in this file are compatible with + * the current version of `ESP_Panel_Board_Custom.h` in the library. The detailed rules are as follows: + * + * 1. If the major version is not consistent, then the configurations in this file are incompatible with the library + * and must be replaced with the file from the library. + * 2. If the minor version is not consistent, this file might be missing some new configurations, which will be set to + * default values. It is recommended to replace it with the file from the library. + * 3. Even if the patch version is not consistent, it will not affect normal functionality. + * + */ +#define ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_MAJOR 0 +#define ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_MINOR 3 +#define ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_PATCH 0 + +// *INDENT-OFF* diff --git a/src/board/espressif/ESP32_S3_LCD_EV_BOARD.h b/src/board/espressif/ESP32_S3_LCD_EV_BOARD.h index 7fd47cc4..b50b5065 100644 --- a/src/board/espressif/ESP32_S3_LCD_EV_BOARD.h +++ b/src/board/espressif/ESP32_S3_LCD_EV_BOARD.h @@ -53,7 +53,7 @@ #define ESP_PANEL_LCD_RGB_PCLK_ACTIVE_NEG (0) // 0: rising edge, 1: falling edge #define ESP_PANEL_LCD_RGB_DATA_WIDTH (16) // 8 | 16 #define ESP_PANEL_LCD_RGB_PIXEL_BITS (16) // 24 | 16 - #define ESP_PANEL_LCD_RGB_FRAME_BUF_NUM (1) // 1/2/3 + #define ESP_PANEL_LCD_RGB_BOUNCE_BUF_SIZE (ESP_PANEL_LCD_WIDTH * 10) // Bounce buffer size in bytes. This function is used to avoid screen drift. // To enable the bounce buffer, set it to a non-zero value. diff --git a/src/board/espressif/ESP32_S3_LCD_EV_BOARD_2.h b/src/board/espressif/ESP32_S3_LCD_EV_BOARD_2.h index e909972c..813a4104 100644 --- a/src/board/espressif/ESP32_S3_LCD_EV_BOARD_2.h +++ b/src/board/espressif/ESP32_S3_LCD_EV_BOARD_2.h @@ -53,7 +53,7 @@ #define ESP_PANEL_LCD_RGB_PCLK_ACTIVE_NEG (1) // 0: rising edge, 1: falling edge #define ESP_PANEL_LCD_RGB_DATA_WIDTH (16) // 8 | 16 #define ESP_PANEL_LCD_RGB_PIXEL_BITS (16) // 24 | 16 - #define ESP_PANEL_LCD_RGB_FRAME_BUF_NUM (1) // 1/2/3 + #define ESP_PANEL_LCD_RGB_BOUNCE_BUF_SIZE (ESP_PANEL_LCD_WIDTH * 10) // Bounce buffer size in bytes. This function is used to avoid screen drift. // To enable the bounce buffer, set it to a non-zero value. diff --git a/src/board/espressif/ESP32_S3_LCD_EV_BOARD_2_V1_5.h b/src/board/espressif/ESP32_S3_LCD_EV_BOARD_2_V1_5.h index cefbcb55..6b50bf81 100644 --- a/src/board/espressif/ESP32_S3_LCD_EV_BOARD_2_V1_5.h +++ b/src/board/espressif/ESP32_S3_LCD_EV_BOARD_2_V1_5.h @@ -53,7 +53,7 @@ #define ESP_PANEL_LCD_RGB_PCLK_ACTIVE_NEG (1) // 0: rising edge, 1: falling edge #define ESP_PANEL_LCD_RGB_DATA_WIDTH (16) // 8 | 16 #define ESP_PANEL_LCD_RGB_PIXEL_BITS (16) // 24 | 16 - #define ESP_PANEL_LCD_RGB_FRAME_BUF_NUM (1) // 1/2/3 + #define ESP_PANEL_LCD_RGB_BOUNCE_BUF_SIZE (ESP_PANEL_LCD_WIDTH * 10) // Bounce buffer size in bytes. This function is used to avoid screen drift. // To enable the bounce buffer, set it to a non-zero value. diff --git a/src/board/espressif/ESP32_S3_LCD_EV_BOARD_V1_5.h b/src/board/espressif/ESP32_S3_LCD_EV_BOARD_V1_5.h index a4626e5d..f09a51f2 100644 --- a/src/board/espressif/ESP32_S3_LCD_EV_BOARD_V1_5.h +++ b/src/board/espressif/ESP32_S3_LCD_EV_BOARD_V1_5.h @@ -53,7 +53,7 @@ #define ESP_PANEL_LCD_RGB_PCLK_ACTIVE_NEG (0) // 0: rising edge, 1: falling edge #define ESP_PANEL_LCD_RGB_DATA_WIDTH (16) // 8 | 16 #define ESP_PANEL_LCD_RGB_PIXEL_BITS (16) // 24 | 16 - #define ESP_PANEL_LCD_RGB_FRAME_BUF_NUM (1) // 1/2/3 + #define ESP_PANEL_LCD_RGB_BOUNCE_BUF_SIZE (ESP_PANEL_LCD_WIDTH * 10) // Bounce buffer size in bytes. This function is used to avoid screen drift. // To enable the bounce buffer, set it to a non-zero value. diff --git a/src/board/espressif/Kconfig.espressif b/src/board/espressif/Kconfig.espressif index 57d934ef..1aff0a17 100644 --- a/src/board/espressif/Kconfig.espressif +++ b/src/board/espressif/Kconfig.espressif @@ -57,3 +57,8 @@ config BOARD_ESP32_S3_USB_OTG bool "ESP32-S3-USB-OTG" help https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32s3/esp32-s3-usb-otg/index.html + +config BOARD_ESP32_P4_FUNCTION_EV_BOARD + bool "ESP32-P4-Function-EV-Board (with 7-inch 1024x600 LCD)" + help + https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32p4/esp32-p4-function-ev-board/index.html diff --git a/src/board/jingcai/ESP32_4848S040C_I_Y_3.h b/src/board/jingcai/ESP32_4848S040C_I_Y_3.h index 3c23176c..2a696f51 100644 --- a/src/board/jingcai/ESP32_4848S040C_I_Y_3.h +++ b/src/board/jingcai/ESP32_4848S040C_I_Y_3.h @@ -53,7 +53,7 @@ #define ESP_PANEL_LCD_RGB_PCLK_ACTIVE_NEG (0) // 0: rising edge, 1: falling edge #define ESP_PANEL_LCD_RGB_DATA_WIDTH (16) // 8 | 16 #define ESP_PANEL_LCD_RGB_PIXEL_BITS (16) // 24 | 16 - #define ESP_PANEL_LCD_RGB_FRAME_BUF_NUM (1) // 1/2/3 + #define ESP_PANEL_LCD_RGB_BOUNCE_BUF_SIZE (ESP_PANEL_LCD_WIDTH * 10) // Bounce buffer size in bytes. This function is used to avoid screen drift. // To enable the bounce buffer, set it to a non-zero value. diff --git a/src/board/m5stack/M5DIAL.h b/src/board/m5stack/M5DIAL.h index 58afaa2e..dc5e5acb 100644 --- a/src/board/m5stack/M5DIAL.h +++ b/src/board/m5stack/M5DIAL.h @@ -101,7 +101,7 @@ #define ESP_PANEL_LCD_RGB_PCLK_ACTIVE_NEG (0) // 0: rising edge, 1: falling edge #define ESP_PANEL_LCD_RGB_DATA_WIDTH (16) // 8 | 16 #define ESP_PANEL_LCD_RGB_PIXEL_BITS (16) // 24 | 16 - #define ESP_PANEL_LCD_RGB_FRAME_BUF_NUM (1) // 1/2/3 + #define ESP_PANEL_LCD_RGB_BOUNCE_BUF_SIZE (0) // Bounce buffer size in bytes. This function is used to avoid screen drift. // To enable the bounce buffer, set it to a non-zero value. Typically set to `ESP_PANEL_LCD_WIDTH * 10` // The size of the Bounce Buffer must satisfy `width_of_lcd * height_of_lcd = size_of_buffer * N`, diff --git a/src/board/waveshare/ESP32_S3_Touch_LCD_4_3.h b/src/board/waveshare/ESP32_S3_Touch_LCD_4_3.h index 1155896d..ecea5576 100644 --- a/src/board/waveshare/ESP32_S3_Touch_LCD_4_3.h +++ b/src/board/waveshare/ESP32_S3_Touch_LCD_4_3.h @@ -56,7 +56,7 @@ // |--------------|---------------| #define ESP_PANEL_LCD_RGB_DATA_WIDTH (16) // | 8 | 16 | #define ESP_PANEL_LCD_RGB_PIXEL_BITS (16) // | 24 | 16 | - #define ESP_PANEL_LCD_RGB_FRAME_BUF_NUM (1) // 1/2/3 + #define ESP_PANEL_LCD_RGB_BOUNCE_BUF_SIZE (ESP_PANEL_LCD_WIDTH * 10) // Bounce buffer size in bytes. This function is used to avoid screen drift. // To enable the bounce buffer, set it to a non-zero value. Typically set to `ESP_PANEL_LCD_WIDTH * 10` // The size of the Bounce Buffer must satisfy `width_of_lcd * height_of_lcd = size_of_buffer * N`, diff --git a/src/bus/DSI.cpp b/src/bus/DSI.cpp new file mode 100644 index 00000000..a20b0db2 --- /dev/null +++ b/src/bus/DSI.cpp @@ -0,0 +1,131 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "soc/soc_caps.h" + +#if SOC_MIPI_DSI_SUPPORTED +#include +#include +#include "ESP_PanelLog.h" +#include "DSI.h" + +#define MIPI_DSI_PHY_PWR_LDO_VOLTAGE_MV (2500) + +static const char *TAG = "ESP_PanelBus_DSI"; + +ESP_PanelBus_DSI::ESP_PanelBus_DSI( + uint8_t dsi_lane_num, uint32_t dsi_lane_rate_mbps, + uint32_t dpi_clk_mhz, uint32_t dpi_bits_per_pixel, uint16_t dpi_w, uint16_t dpi_h, + uint16_t dpi_hpw, uint16_t dpi_hbp, uint16_t dpi_hfp, uint16_t dpi_vpw, uint16_t dpi_vbp, uint16_t dpi_vfp, + int phy_ldo_id +): + ESP_PanelBus(ESP_PANEL_HOST_DSI_ID_DEFAULT, ESP_PANEL_BUS_TYPE_MIPI_DSI, true), + _phy_ldo_id(phy_ldo_id), + _dsi_config((esp_lcd_dsi_bus_config_t)ESP_PANEL_HOST_DSI_CONFIG_DEFAULT(dsi_lane_num, dsi_lane_rate_mbps)), + _dbi_config((esp_lcd_dbi_io_config_t)ESP_PANEL_IO_DBI_CONFIG_DEFAULT()), + _dpi_config( + (esp_lcd_dpi_panel_config_t)ESP_PANEL_DPI_CONFIG_DEFAULT( + dpi_clk_mhz, dpi_bits_per_pixel, dpi_w, dpi_h, dpi_hpw, dpi_hbp, dpi_hfp, dpi_vpw, dpi_vbp, dpi_vfp + ) + ), + _phy_ldo_handle(NULL), + _dsi_handle(NULL) +{ +} + +ESP_PanelBus_DSI::ESP_PanelBus_DSI( + uint8_t dsi_lane_num, uint32_t dsi_lane_rate_mbps, const esp_lcd_dpi_panel_config_t &dpi_config, int phy_ldo_id +): + ESP_PanelBus(ESP_PANEL_HOST_DSI_ID_DEFAULT, ESP_PANEL_BUS_TYPE_MIPI_DSI, true), + _phy_ldo_id(phy_ldo_id), + _dsi_config((esp_lcd_dsi_bus_config_t)ESP_PANEL_HOST_DSI_CONFIG_DEFAULT(dsi_lane_num, dsi_lane_rate_mbps)), + _dbi_config((esp_lcd_dbi_io_config_t)ESP_PANEL_IO_DBI_CONFIG_DEFAULT()), + _dpi_config(dpi_config), + _phy_ldo_handle(NULL), + _dsi_handle(NULL) +{ +} + +ESP_PanelBus_DSI::ESP_PanelBus_DSI( + const esp_lcd_dsi_bus_config_t &dsi_config, const esp_lcd_dpi_panel_config_t &dpi_config, int phy_ldo_id +): + ESP_PanelBus(ESP_PANEL_HOST_DSI_ID_DEFAULT, ESP_PANEL_BUS_TYPE_MIPI_DSI, true), + _phy_ldo_id(phy_ldo_id), + _dsi_config(dsi_config), + _dbi_config((esp_lcd_dbi_io_config_t)ESP_PANEL_IO_DBI_CONFIG_DEFAULT()), + _dpi_config(dpi_config), + _phy_ldo_handle(NULL), + _dsi_handle(NULL) +{ +} + +ESP_PanelBus_DSI::~ESP_PanelBus_DSI() +{ + if (handle == NULL) { + goto end; + } + + if (!del()) { + ESP_LOGE(TAG, "Delete panel io failed"); + } + +end: + ESP_LOGD(TAG, "Destroyed"); +} + +bool ESP_PanelBus_DSI::del(void) +{ + ESP_PANEL_ENABLE_TAG_DEBUG_LOG(); + + ESP_PANEL_CHECK_FALSE_RET(ESP_PanelBus::del(), false, "Delete base panel failed"); + if (_dsi_handle != NULL) { + if (esp_lcd_del_dsi_bus(_dsi_handle) != ESP_OK) { + ESP_LOGE(TAG, "Delete _dsi_handle[%d] driver failed", host_id); + } else { + ESP_LOGD(TAG, "Delete _dsi_handle[%d] driver", host_id); + } + _dsi_handle = NULL; + } + if (_phy_ldo_handle != NULL) { + if (esp_ldo_release_channel(_phy_ldo_handle) != ESP_OK) { + ESP_LOGE(TAG, "Release LDO channel[%d] failed", _phy_ldo_id); + } else { + ESP_LOGD(TAG, "MIPI DSI PHY (LDO %d) Powered off", _phy_ldo_id); + } + _phy_ldo_handle = NULL; + } + + return true; +} + +void ESP_PanelBus_DSI::configDpiFrameBufferNumber(uint8_t num) +{ + _dpi_config.num_fbs = num; +} + +bool ESP_PanelBus_DSI::begin(void) +{ + ESP_PANEL_ENABLE_TAG_DEBUG_LOG(); + + if (_phy_ldo_id >= 0) { + // Turn on the power for MIPI DSI PHY, so it can go from "No Power" state to "Shutdown" state + esp_ldo_channel_config_t ldo_config = { + .chan_id = _phy_ldo_id, + .voltage_mv = MIPI_DSI_PHY_PWR_LDO_VOLTAGE_MV, + }; + ESP_PANEL_CHECK_ERR_RET(esp_ldo_acquire_channel(&ldo_config, &_phy_ldo_handle), false, "Acquire LDO channel failed"); + ESP_LOGD(TAG, "MIPI DSI PHY (LDO %d) Powered on", _phy_ldo_id); + } + if (flags.host_need_init) { + ESP_PANEL_CHECK_ERR_RET(esp_lcd_new_dsi_bus(&_dsi_config, &_dsi_handle), false, "Initialize Host[%d] failed", host_id); + ESP_LOGD(TAG, "Init MIPI DSI _dsi_handle[%d]", host_id); + } + ESP_PANEL_CHECK_ERR_RET(esp_lcd_new_panel_io_dbi(_dsi_handle, &_dbi_config, &handle), false, "Create panel io failed"); + ESP_LOGD(TAG, "Create panel io @%p", handle); + + return true; +} +#endif /* SOC_MIPI_DSI_SUPPORTED */ diff --git a/src/bus/DSI.h b/src/bus/DSI.h new file mode 100644 index 00000000..bd9ee416 --- /dev/null +++ b/src/bus/DSI.h @@ -0,0 +1,169 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include "soc/soc_caps.h" + +#if SOC_MIPI_DSI_SUPPORTED +#include "esp_ldo_regulator.h" +#include "esp_lcd_mipi_dsi.h" +#include "esp_lcd_panel_io.h" +#include "ESP_PanelBus.h" + +/** + * @brief Macro for MIPI DSI bus configuration + * + */ +#define ESP_PANEL_HOST_DSI_ID_DEFAULT (0) +#define ESP_PANEL_HOST_DSI_CONFIG_DEFAULT(lane_num, lane_rate_mbps) \ + { \ + .bus_id = ESP_PANEL_HOST_DSI_ID_DEFAULT, \ + .num_data_lanes = lane_num, \ + .phy_clk_src = MIPI_DSI_PHY_CLK_SRC_DEFAULT, \ + .lane_bit_rate_mbps = lane_rate_mbps, \ + } + +/** + * @brief Macro for MIPI DBI panel IO configuration + * + */ +#define ESP_PANEL_IO_DBI_CONFIG_DEFAULT() \ + { \ + .virtual_channel = 0, \ + .lcd_cmd_bits = 8, \ + .lcd_param_bits = 8, \ + } + +/** + * @brief Macro for MIPI DPI panel configuration + * + */ +#define ESP_PANEL_DPI_CONFIG_DEFAULT(clk_mhz, bits_per_pixel, w, h, hpw, hbp, hfp, vpw, vbp, vfp) \ + { \ + .virtual_channel = 0, \ + .dpi_clk_src = MIPI_DSI_DPI_CLK_SRC_DEFAULT, \ + .dpi_clock_freq_mhz = clk_mhz, \ + .pixel_format = (bits_per_pixel == 16) ? LCD_COLOR_PIXEL_FORMAT_RGB565 : \ + ((bits_per_pixel == 18) ? LCD_COLOR_PIXEL_FORMAT_RGB666 : LCD_COLOR_PIXEL_FORMAT_RGB888), \ + .num_fbs = 1, \ + .video_timing = { \ + .h_size = w, \ + .v_size = h, \ + .hsync_pulse_width = hpw, \ + .hsync_back_porch = hbp, \ + .hsync_front_porch = hfp, \ + .vsync_pulse_width = vpw, \ + .vsync_back_porch = vbp, \ + .vsync_front_porch = vfp, \ + }, \ + .flags = { \ + .use_dma2d = true, \ + }, \ + } + +/** + * @brief MIPI-DSI bus object class + * + * @note This class is a derived class of `ESP_PanelBus`, user can use it directly + */ +class ESP_PanelBus_DSI: public ESP_PanelBus { +public: + /** + * @brief Construct a MIPI-DSI bus object in a common way, the host_handle will be initialized by the driver + * + * @note This function uses some default values (ESP_PANEL_HOST_DSI_CONFIG_DEFAULT && ESP_PANEL_IO_DBI_CONFIG_DEFAULT) + * to config the bus object, use `config*()` functions to change them + * @note The `init()` function should be called after this function + * + * @param ldo_chan_id MIPI-DSI CS pin + */ + ESP_PanelBus_DSI( + uint8_t dsi_lane_num, uint32_t dsi_lane_rate_mbps, + uint32_t dpi_clk_mhz, uint32_t dpi_bits_per_pixel, uint16_t dpi_w, uint16_t dpi_h, + uint16_t dpi_hpw, uint16_t dpi_hbp, uint16_t dpi_hfp, uint16_t dpi_vpw, uint16_t dpi_vbp, uint16_t dpi_vfp, + int phy_ldo_id = -1 + ); + + /** + * @brief Construct a MIPI-DSI bus object in a common way, the host_handle will be initialized by the driver + * + * @note This function uses some default values (ESP_PANEL_HOST_DSI_CONFIG_DEFAULT) to config the bus object, + * use `config*()` functions to change them + * @note The `init()` function should be called after this function + * + * @param sck_io MIPI-DSI SCK pin + * @param mosi_io MIPI-DSI MOSI pin + * @param miso_io MIPI-DSI MISO pin + * @param io_config MIPI-DSI panel IO configuration + */ + ESP_PanelBus_DSI( + uint8_t dsi_lane_num, uint32_t dsi_lane_rate_mbps, const esp_lcd_dpi_panel_config_t &dpi_config, + int phy_ldo_id = -1 + ); + + /** + * @brief Construct a MIPI-DSI bus object in a complex way, the host_handle will be initialized by the driver + * + * @note The `init()` function should be called after this function + * + * @param host_config MIPI-DSI host_handle configuration + * @param io_config MIPI-DSI panel IO configuration + * @param host_id MIPI-DSI host_handle ID, default is `ESP_PANEL_HOST_DSI_ID_DEFAULT` + */ + ESP_PanelBus_DSI( + const esp_lcd_dsi_bus_config_t &dsi_config, const esp_lcd_dpi_panel_config_t &dpi_config, int phy_ldo_id = -1 + ); + + /** + * @brief Destroy the MIPI-DSI bus object + * + */ + ~ESP_PanelBus_DSI() override; + + /** + * @brief Delete the bus object, release the resources + * + * @return true if success, otherwise false + */ + bool del(void) override; + + /** + * @brief Here are some functions to configure the MIPI-DSI bus object. These functions should be called before `begin()` + * + */ + void configDpiFrameBufferNumber(uint8_t num); + + /** + * @brief Startup the bus + * + * @return true if success, otherwise false + */ + bool begin(void) override; + + esp_lcd_dsi_bus_handle_t getBusHandle(void) + { + return _dsi_handle; + } + + const esp_lcd_dsi_bus_config_t *getDsiConfig(void) + { + return &_dsi_config; + } + + const esp_lcd_dpi_panel_config_t *getDpiConfig(void) + { + return &_dpi_config; + } + +private: + int _phy_ldo_id; + esp_lcd_dsi_bus_config_t _dsi_config; + esp_lcd_dbi_io_config_t _dbi_config; + esp_lcd_dpi_panel_config_t _dpi_config; + esp_ldo_channel_handle_t _phy_ldo_handle; + esp_lcd_dsi_bus_handle_t _dsi_handle; +}; +#endif /* SOC_MIPI_DSI_SUPPORTED */ diff --git a/src/bus/ESP_PanelBus.cpp b/src/bus/ESP_PanelBus.cpp index 3f818f7d..901eb715 100644 --- a/src/bus/ESP_PanelBus.cpp +++ b/src/bus/ESP_PanelBus.cpp @@ -9,11 +9,17 @@ #include "esp_lcd_panel_io.h" #include "ESP_PanelBus.h" +#define FLAGS_DEFAULT(host_init) \ + { \ + .host_need_init = host_init, \ + .del_skip_panel_io = 0, \ + } + static const char *TAG = "ESP_PanelBus"; ESP_PanelBus::ESP_PanelBus(int host_id, uint8_t bus_type, bool host_need_init): + flags(FLAGS_DEFAULT(host_need_init)), host_id(host_id), - host_need_init(host_need_init), bus_type(bus_type), handle(NULL) { @@ -47,35 +53,21 @@ bool ESP_PanelBus::del(void) { ESP_PANEL_ENABLE_TAG_DEBUG_LOG(); - // RGB bus which needs to initialize the host inside can be deleted - if ((bus_type == ESP_PANEL_BUS_TYPE_RGB) && !host_need_init) { - ESP_LOGD(TAG, "Use RGB bus without host init, skip delete panel IO"); - return true; + // RGB bus which needs to initialize the host inside and not skip panel IO can be deleted + if ((bus_type == ESP_PANEL_BUS_TYPE_RGB) && (!flags.host_need_init || flags.del_skip_panel_io)) { + ESP_LOGD(TAG, "Use RGB bus without host init or enable skip panel IO, skip delete panel IO"); + goto end; } ESP_PANEL_CHECK_ERR_RET(esp_lcd_panel_io_del(handle), false, "Delete panel IO failed"); - ESP_LOGD(TAG, "Delete panel IO @%p", handle); + +end: handle = NULL; return true; } -void ESP_PanelBus::configHostId(int id) -{ - host_id = id; -} - -esp_lcd_panel_io_handle_t ESP_PanelBus::getHandle(void) -{ - if (handle == NULL) { - ESP_PANEL_ENABLE_TAG_DEBUG_LOG(); - ESP_LOGD(TAG, "Get invalid handle"); - } - - return handle; -} - uint8_t ESP_PanelBus::getType(void) { if ((bus_type == ESP_PANEL_BUS_TYPE_UNKNOWN) || (bus_type >= ESP_PANEL_BUS_TYPE_MAX)) { diff --git a/src/bus/ESP_PanelBus.h b/src/bus/ESP_PanelBus.h index 169ec47d..dacaaf6a 100644 --- a/src/bus/ESP_PanelBus.h +++ b/src/bus/ESP_PanelBus.h @@ -25,7 +25,7 @@ class ESP_PanelBus { * - ESP_PANEL_BUS_TYPE_SPI: SPI bus * - ESP_PANEL_BUS_TYPE_RGB: RGB bus * - ESP_PANEL_BUS_TYPE_QSPI: QSPI bus - * @param host_need_init Whether the host should be initialized inside. + * @param flags.host_need_init Whether the host should be initialized inside. * - true: the host needs to be initialized inside * - false: the host should been initialized by users */ @@ -41,7 +41,10 @@ class ESP_PanelBus { * @brief Here are some functions to configure the bus object. These functions should be called before `begin()` * */ - void configHostId(int id); + void configHostId(int id) + { + host_id = id; + } /** * @brief Startup the bus @@ -57,6 +60,12 @@ class ESP_PanelBus { */ virtual bool del(void); + bool delSkipPanelIO(void) + { + flags.del_skip_panel_io = 1; + return del(); + } + /** * @brief Read the register data * @@ -104,17 +113,36 @@ class ESP_PanelBus { uint8_t getType(void); /** - * @brief Get the IO handle of bus + * @brief Get the panel IO handle + * + * @return + * - NULL: if fail + * - Others: the handle of bus + */ + [[deprecated("This API is deprecated. Please use `getPanelIO_Handle()` instead.")]] + esp_lcd_panel_io_handle_t getHandle(void) + { + return getPanelIO_Handle(); + } + + /** + * @brief Get the panel IO handle * * @return * - NULL: if fail * - Others: the handle of bus */ - esp_lcd_panel_io_handle_t getHandle(void); + esp_lcd_panel_io_handle_t getPanelIO_Handle(void) + { + return handle; + } protected: + struct { + uint8_t host_need_init: 1; + uint8_t del_skip_panel_io: 1; + } flags; int host_id; - bool host_need_init; uint8_t bus_type; esp_lcd_panel_io_handle_t handle; }; diff --git a/src/bus/I2C.cpp b/src/bus/I2C.cpp index 61a44bb3..d1626aa0 100644 --- a/src/bus/I2C.cpp +++ b/src/bus/I2C.cpp @@ -17,8 +17,9 @@ ESP_PanelBus_I2C::ESP_PanelBus_I2C(int scl_io, int sda_io, const esp_lcd_panel_i { } -ESP_PanelBus_I2C::ESP_PanelBus_I2C(const i2c_config_t &host_config, const esp_lcd_panel_io_i2c_config_t &io_config, - i2c_port_t host_id): +ESP_PanelBus_I2C::ESP_PanelBus_I2C( + const i2c_config_t &host_config, const esp_lcd_panel_io_i2c_config_t &io_config, i2c_port_t host_id +): ESP_PanelBus((int)host_id, ESP_PANEL_BUS_TYPE_I2C, true), host_config(host_config), io_config(io_config) @@ -43,7 +44,7 @@ ESP_PanelBus_I2C::~ESP_PanelBus_I2C() ESP_LOGE(TAG, "Delete panel io failed"); } - if (host_need_init) { + if (flags.host_need_init) { if (i2c_driver_delete((i2c_port_t)host_id) != ESP_OK) { ESP_LOGE(TAG, "Delete host[%d] driver failed", host_id); } else { @@ -106,7 +107,7 @@ bool ESP_PanelBus_I2C::begin(void) { ESP_PANEL_ENABLE_TAG_DEBUG_LOG(); - if (host_need_init) { + if (flags.host_need_init) { ESP_PANEL_CHECK_ERR_RET(i2c_param_config((i2c_port_t)host_id, &host_config), false, "Configure host[%d] failed", host_id); ESP_PANEL_CHECK_ERR_RET(i2c_driver_install((i2c_port_t)host_id, host_config.mode, 0, 0, 0), false, "Install host[%d] failed", host_id); diff --git a/src/bus/QSPI.cpp b/src/bus/QSPI.cpp index fbdf139d..556584d4 100644 --- a/src/bus/QSPI.cpp +++ b/src/bus/QSPI.cpp @@ -51,7 +51,7 @@ ESP_PanelBus_QSPI::~ESP_PanelBus_QSPI() ESP_LOGE(TAG, "Delete panel io failed"); } - if (host_need_init) { + if (flags.host_need_init) { if (spi_bus_free((spi_host_device_t)host_id) != ESP_OK) { ESP_LOGE(TAG, "Delete host[%d] driver failed", host_id); } else { @@ -82,7 +82,7 @@ bool ESP_PanelBus_QSPI::begin(void) { ESP_PANEL_ENABLE_TAG_DEBUG_LOG(); - if (host_need_init) { + if (flags.host_need_init) { ESP_PANEL_CHECK_ERR_RET(spi_bus_initialize((spi_host_device_t)host_id, &host_config, SPI_DMA_CH_AUTO), false, "Initializeost Host[%d] failed", host_id); ESP_LOGD(TAG, "Init host[%d]", host_id); diff --git a/src/bus/QSPI.h b/src/bus/QSPI.h index f5a8f664..f04b2eea 100644 --- a/src/bus/QSPI.h +++ b/src/bus/QSPI.h @@ -11,11 +11,6 @@ #include "host/ESP_PanelHost.h" #include "ESP_PanelBus.h" -/** - * @brief Macro for QSPI bus default host ID - * - */ - /** * @brief Macro for QSPI panel IO configuration * diff --git a/src/bus/RGB.cpp b/src/bus/RGB.cpp index 7c42671f..c60dc081 100644 --- a/src/bus/RGB.cpp +++ b/src/bus/RGB.cpp @@ -89,17 +89,10 @@ ESP_PanelBus_RGB::~ESP_PanelBus_RGB() { ESP_PANEL_ENABLE_TAG_DEBUG_LOG(); - if (host_need_init) { - if (handle == NULL) { - goto end; - } - - if (!del()) { - ESP_LOGE(TAG, "Delete panel io failed"); - } + if (flags.host_need_init && (handle != NULL) && !del()) { + ESP_LOGE(TAG, "Delete panel io failed"); } -end: ESP_LOGD(TAG, "Destroyed"); } @@ -168,7 +161,7 @@ bool ESP_PanelBus_RGB::begin(void) { ESP_PANEL_ENABLE_TAG_DEBUG_LOG(); - if (host_need_init) { + if (flags.host_need_init) { ESP_PANEL_CHECK_ERR_RET(esp_lcd_new_panel_io_3wire_spi(&spi_config, &handle), false, "Create panel io failed"); ESP_LOGD(TAG, "Create panel io @%p", handle); } @@ -176,9 +169,4 @@ bool ESP_PanelBus_RGB::begin(void) return true; } -const esp_lcd_rgb_panel_config_t *ESP_PanelBus_RGB::getRgbConfig() -{ - return &rgb_config; -} - #endif /* SOC_LCD_RGB_SUPPORTED */ diff --git a/src/bus/RGB.h b/src/bus/RGB.h index 662a02e3..c7c4ac80 100644 --- a/src/bus/RGB.h +++ b/src/bus/RGB.h @@ -318,7 +318,10 @@ class ESP_PanelBus_RGB: public ESP_PanelBus { */ bool begin(void) override; - const esp_lcd_rgb_panel_config_t *getRgbConfig(); + const esp_lcd_rgb_panel_config_t *getRgbConfig() + { + return &rgb_config; + } private: esp_lcd_rgb_panel_config_t rgb_config; diff --git a/src/bus/SPI.cpp b/src/bus/SPI.cpp index 22ee6963..d6fb83dd 100644 --- a/src/bus/SPI.cpp +++ b/src/bus/SPI.cpp @@ -66,7 +66,7 @@ bool ESP_PanelBus_SPI::del(void) ESP_PANEL_ENABLE_TAG_DEBUG_LOG(); ESP_PANEL_CHECK_FALSE_RET(ESP_PanelBus::del(), false, "Delete base panel failed"); - if (host_need_init) { + if (flags.host_need_init) { if (spi_bus_free((spi_host_device_t)host_id) != ESP_OK) { ESP_LOGE(TAG, "Delete host[%d] driver failed", host_id); } else { @@ -106,7 +106,7 @@ bool ESP_PanelBus_SPI::begin(void) { ESP_PANEL_ENABLE_TAG_DEBUG_LOG(); - if (host_need_init) { + if (flags.host_need_init) { ESP_PANEL_CHECK_ERR_RET(spi_bus_initialize((spi_host_device_t)host_id, &host_config, SPI_DMA_CH_AUTO), false, "Initializeost Host[%d] failed", host_id); ESP_LOGD(TAG, "Init host[%d]", host_id); diff --git a/src/lcd/EK79007.cpp b/src/lcd/EK79007.cpp new file mode 100644 index 00000000..30cab660 --- /dev/null +++ b/src/lcd/EK79007.cpp @@ -0,0 +1,62 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "soc/soc_caps.h" + +#if SOC_MIPI_DSI_SUPPORTED +#include "ESP_PanelLog.h" +#include "EK79007.h" + +static const char *TAG = "EK79007_CPP"; + +ESP_PanelLcd_EK79007::ESP_PanelLcd_EK79007(ESP_PanelBus *bus, uint8_t color_bits, int rst_io): + ESP_PanelLcd(bus, color_bits, rst_io) +{ + disabled_functions.display_on_off = 1; + disabled_functions.set_gap = 1; + disabled_functions.swap_xy = 1; +} + +ESP_PanelLcd_EK79007::ESP_PanelLcd_EK79007(ESP_PanelBus *bus, const esp_lcd_panel_dev_config_t &panel_config): + ESP_PanelLcd(bus, panel_config) +{ + disabled_functions.display_on_off = 1; + disabled_functions.set_gap = 1; + disabled_functions.swap_xy = 1; +} + +ESP_PanelLcd_EK79007::~ESP_PanelLcd_EK79007() +{ + ESP_PANEL_ENABLE_TAG_DEBUG_LOG(); + + if (handle == NULL) { + goto end; + } + + if (!del()) { + ESP_LOGE(TAG, "Delete device failed"); + } + +end: + ESP_LOGD(TAG, "Destroyed"); +} + +bool ESP_PanelLcd_EK79007::init(void) +{ + ESP_PANEL_CHECK_NULL_RET(bus, false, "Invalid bus"); + + /* Load MIPI-DSI configurations from bus to vendor configurations */ + ESP_PANEL_CHECK_FALSE_RET(loadVendorConfigFromBus(), false, "Load vendor config from bus failed"); + + /* Create panel handle */ + ESP_PANEL_CHECK_ERR_RET( + esp_lcd_new_panel_ek79007(bus->getPanelIO_Handle(), &panel_config, &handle), false, "Create panel failed" + ); + + return true; +} + +#endif diff --git a/src/lcd/EK79007.h b/src/lcd/EK79007.h new file mode 100644 index 00000000..6a126465 --- /dev/null +++ b/src/lcd/EK79007.h @@ -0,0 +1,59 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include "soc/soc_caps.h" + +#if SOC_MIPI_DSI_SUPPORTED +#include "ESP_PanelLcd.h" +#include "base/esp_lcd_vendor_types.h" +#include "base/esp_lcd_ek79007.h" + +/** + * @brief EK79007 LCD device object class + * + * @note This class is a derived class of `ESP_PanelLcd`, user can use it directly + */ +class ESP_PanelLcd_EK79007: public ESP_PanelLcd { +public: + /** + * @brief Construct a new LCD device in a simple way, the `init()` function should be called after this function + * + * @note This function uses some default values to config the LCD device, please use `config*()` functions to + * change them + * @note Vendor specific initialization can be different between manufacturers, should consult the LCD supplier + * for initialization sequence code, and use `configVendorCommands()` to configure + * + * @param bus Pointer of panel bus + * @param color_bits Bits per pixel (16/18/24) + * @param rst_io Reset pin, set to -1 if no use + */ + ESP_PanelLcd_EK79007(ESP_PanelBus *bus, uint8_t color_bits, int rst_io = -1); + + /** + * @brief Construct a new LCD in a complex way, the `init()` function should be called after this function + * + * @param bus Pointer of panel bus + * @param panel_config LCD device configuration + */ + ESP_PanelLcd_EK79007(ESP_PanelBus *bus, const esp_lcd_panel_dev_config_t &panel_config); + + /** + * @brief Destroy the LCD device + * + */ + ~ESP_PanelLcd_EK79007() override; + + /** + * @brief Initialize the LCD device, the `begin()` function should be called after this function + * + * @note This function typically calls `esp_lcd_new_panel_*()` to create the LCD panel handle + * + * @return true if success, otherwise false + */ + bool init(void) override; +}; +#endif diff --git a/src/lcd/EK9716B.cpp b/src/lcd/EK9716B.cpp index 0495c7b3..727c7852 100644 --- a/src/lcd/EK9716B.cpp +++ b/src/lcd/EK9716B.cpp @@ -52,6 +52,7 @@ bool ESP_PanelLcd_EK9716B::init(void) { ESP_PANEL_ENABLE_TAG_DEBUG_LOG(); + /* Initialize RST pin */ if (panel_config.reset_gpio_num >= 0) { gpio_config_t gpio_conf = { .pin_bit_mask = BIT64(panel_config.reset_gpio_num), @@ -62,6 +63,11 @@ bool ESP_PanelLcd_EK9716B::init(void) }; ESP_PANEL_CHECK_ERR_RET(gpio_config(&gpio_conf), false, "`Config RST gpio failed"); } + + /* Load RGB configurations from bus to vendor configurations */ + ESP_PANEL_CHECK_FALSE_RET(loadVendorConfigFromBus(), false, "Load vendor config from bus failed"); + + /* Create panel handle */ ESP_PANEL_CHECK_ERR_RET(esp_lcd_new_rgb_panel(vendor_config.rgb_config, &handle), false, "Create panel failed"); ESP_LOGD(TAG, "LCD panel @%p created", handle); diff --git a/src/lcd/ESP_PanelLcd.cpp b/src/lcd/ESP_PanelLcd.cpp index 28e96038..4976e5c5 100644 --- a/src/lcd/ESP_PanelLcd.cpp +++ b/src/lcd/ESP_PanelLcd.cpp @@ -7,20 +7,16 @@ #include #include "cstring" #include "ESP_PanelLog.h" -#include "soc/soc_caps.h" +#include "sdkconfig.h" #include "esp_heap_caps.h" #include "esp_lcd_panel_ops.h" #include "esp_lcd_panel_io.h" -#if SOC_LCD_RGB_SUPPORTED -#include "esp_lcd_panel_rgb.h" -#endif #include "esp_memory_utils.h" #include "freertos/FreeRTOS.h" #include "freertos/semphr.h" #include "driver/spi_master.h" -#include "soc/soc_caps.h" -#include "sdkconfig.h" #include "bus/RGB.h" +#include "bus/DSI.h" #include "bus/ESP_PanelBus.h" #include "ESP_PanelLcd.h" @@ -31,7 +27,10 @@ .flags = { \ .mirror_by_cmd = 1, \ .auto_del_panel_io = 0, \ + .use_spi_interface = 0, \ .use_qspi_interface = 0, \ + .use_rgb_interface = 0, \ + .use_mipi_interface = 0, \ } \ } #define CALLBACK_DATA_DEFAULT() \ @@ -45,69 +44,49 @@ static const char *TAG = "ESP_PanelLcd"; using namespace std; ESP_PanelLcd::ESP_PanelLcd(ESP_PanelBus *bus, uint8_t color_bits, int rst_io): + disabled_functions{}, x_coord_align(0), y_coord_align(0), bus(bus), panel_config(ESP_PANEL_LCD_DEVICE_CONFIG_DEFAULT(rst_io, color_bits, &vendor_config)), - vendor_config(VENDOR_CONFIG_DEFAULT()), + vendor_config((esp_lcd_panel_vendor_config_t)VENDOR_CONFIG_DEFAULT()), handle(NULL), - _swap_xy(false), - _mirror_x(false), - _mirror_y(false), + _flags{}, _gap_x(0), _gap_y(0), + onDrawBitmapFinishCallback(NULL), onRefreshFinishCallback(NULL), - _refresh_finish_sem(NULL), - callback_data(CALLBACK_DATA_DEFAULT()) + _draw_bitmap_finish_sem(NULL), + _callback_data(CALLBACK_DATA_DEFAULT()) { - switch (bus->getType()) { - case ESP_PANEL_BUS_TYPE_QSPI: - vendor_config.flags.use_qspi_interface = 1; - break; -#if SOC_LCD_RGB_SUPPORTED - /* Retrieve RGB configuration from the bus and register it into the vendor configuration */ - case ESP_PANEL_BUS_TYPE_RGB: - vendor_config.rgb_config = static_cast(bus)->getRgbConfig(); - break; -#endif - default: - break; - } } ESP_PanelLcd::ESP_PanelLcd(ESP_PanelBus *bus, const esp_lcd_panel_dev_config_t &panel_config): + disabled_functions{}, x_coord_align(0), y_coord_align(0), bus(bus), panel_config(panel_config), vendor_config(VENDOR_CONFIG_DEFAULT()), handle(NULL), - _swap_xy(false), - _mirror_x(false), - _mirror_y(false), + _flags{}, _gap_x(0), _gap_y(0), + onDrawBitmapFinishCallback(NULL), onRefreshFinishCallback(NULL), - _refresh_finish_sem(NULL), - callback_data(CALLBACK_DATA_DEFAULT()) + _draw_bitmap_finish_sem(NULL), + _callback_data(CALLBACK_DATA_DEFAULT()) { /* Save vendor configuration to local and register the local one into panel configuration */ if (panel_config.vendor_config != NULL) { vendor_config = *(esp_lcd_panel_vendor_config_t *)panel_config.vendor_config; } this->panel_config.vendor_config = &vendor_config; - -#if SOC_LCD_RGB_SUPPORTED - /* Retrieve RGB configuration from the bus and register it into the vendor configuration */ - if (bus->getType() == ESP_PANEL_BUS_TYPE_RGB) { - const esp_lcd_rgb_panel_config_t *rgb_config = static_cast(bus)->getRgbConfig(); - vendor_config.rgb_config = rgb_config; - } -#endif } bool ESP_PanelLcd::configVendorCommands(const esp_lcd_panel_vendor_init_cmd_t init_cmd[], uint32_t init_cmd_size) { + ESP_PANEL_CHECK_FALSE_RET(!checkIsInit(), false, "This function should be called before `init()`"); ESP_PANEL_CHECK_FALSE_RET((init_cmd == NULL) || (init_cmd_size > 0), false, "Size of init commands is invalid"); vendor_config.init_cmds = init_cmd; @@ -116,29 +95,54 @@ bool ESP_PanelLcd::configVendorCommands(const esp_lcd_panel_vendor_init_cmd_t in return true; } -void ESP_PanelLcd::configColorRgbOrder(bool BGR_order) +bool ESP_PanelLcd::configColorRgbOrder(bool BGR_order) { + ESP_PANEL_CHECK_FALSE_RET(!checkIsInit(), false, "This function should be called before `init()`"); + if (BGR_order) { panel_config.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_BGR; } else { panel_config.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB; } + + return true; +} + +bool ESP_PanelLcd::configResetActiveLevel(int level) +{ + ESP_PANEL_CHECK_FALSE_RET(!checkIsInit(), false, "This function should be called before `init()`"); + + panel_config.flags.reset_active_high = level; + + return true; } -void ESP_PanelLcd::configMirrorByCommand(bool en) +bool ESP_PanelLcd::configMirrorByCommand(bool en) { + ESP_PANEL_CHECK_FALSE_RET(!checkIsInit(), false, "This function should be called before `init()`"); + ESP_PANEL_CHECK_NULL_RET(bus, false, "Invalid bus"); + ESP_PANEL_CHECK_FALSE_RET(bus->getType() == ESP_PANEL_BUS_TYPE_RGB, false, "This function is only for RGB interface"); + vendor_config.flags.mirror_by_cmd = en; + + return true; } -void ESP_PanelLcd::configAutoReleaseBus(bool en) +bool ESP_PanelLcd::configEnableIO_Multiplex(bool en) { - vendor_config.flags.auto_del_panel_io = en; + ESP_PANEL_CHECK_FALSE_RET(!checkIsInit(), false, "This function should be called before `init()`"); + ESP_PANEL_CHECK_NULL_RET(bus, false, "Invalid bus"); + ESP_PANEL_CHECK_FALSE_RET(bus->getType() == ESP_PANEL_BUS_TYPE_RGB, false, "This function is only for RGB interface"); + + vendor_config.flags.enable_io_multiplex = en; + + return true; } bool ESP_PanelLcd::begin(void) { - ESP_PANEL_CHECK_NULL_RET(handle, false, "Invalid handle"); - ESP_PANEL_CHECK_NULL_RET(bus, false, "Invalid bus"); + ESP_PANEL_CHECK_FALSE_RET(checkIsInit(), false, "Not initialized"); + ESP_PANEL_CHECK_FALSE_RET(!checkIsBegun() || _flags.is_reset, false, "Already begun and not reset"); ESP_PANEL_ENABLE_TAG_DEBUG_LOG(); @@ -147,22 +151,21 @@ bool ESP_PanelLcd::begin(void) /* Initialize LCD panel */ ESP_PANEL_CHECK_ERR_RET(esp_lcd_panel_init(handle), false, "Init panel failed"); - /* For non-RGB interface, create Semaphore for using API `drawBitmapWaitUntilFinish()` */ - if (bus->getType() != ESP_PANEL_BUS_TYPE_RGB) { - _refresh_finish_sem = xSemaphoreCreateBinary(); - ESP_PANEL_CHECK_NULL_RET(_refresh_finish_sem, false, "Create semaphore failed"); + /* If the panel is reset, goto end directly */ + if (checkIsBegun() && _flags.is_reset) { + goto end; } - /* Register transimit done callback for non-RGB interface and RGB interface */ - if (bus->getType() != ESP_PANEL_BUS_TYPE_RGB) { - esp_lcd_panel_io_callbacks_t io_cb = { - .on_color_trans_done = (esp_lcd_panel_io_color_trans_done_cb_t)onRefreshFinish, - }; - ESP_PANEL_CHECK_ERR_RET(esp_lcd_panel_io_register_event_callbacks(bus->getHandle(), &io_cb, &callback_data), false, - "Register IO callback failed"); + /* For non-RGB interface, create Semaphore for using API `drawBitmapWaitUntilFinish()` */ + if ((bus->getType() != ESP_PANEL_BUS_TYPE_RGB) && (_draw_bitmap_finish_sem == NULL)) { + _draw_bitmap_finish_sem = xSemaphoreCreateBinary(); + ESP_PANEL_CHECK_NULL_RET(_draw_bitmap_finish_sem, false, "Create draw bitmap finish semaphore failed"); } + + /* Register transimit done callback for different interface */ + switch (bus->getType()) { #if SOC_LCD_RGB_SUPPORTED - else { + case ESP_PANEL_BUS_TYPE_RGB: { const esp_lcd_rgb_panel_config_t *rgb_config = static_cast(bus)->getRgbConfig(); esp_lcd_rgb_panel_event_callbacks_t rgb_event_cb = { NULL }; if (rgb_config->bounce_buffer_size_px == 0) { @@ -172,66 +175,113 @@ bool ESP_PanelLcd::begin(void) // When bounce buffer is enabled, use `on_bounce_frame_finish` callback to notify draw bitmap finish rgb_event_cb.on_bounce_frame_finish = (esp_lcd_rgb_panel_bounce_buf_finish_cb_t)onRefreshFinish; } - ESP_PANEL_CHECK_ERR_RET(esp_lcd_rgb_panel_register_event_callbacks(handle, &rgb_event_cb, &callback_data), - false, "Register RGB callback failed"); + ESP_PANEL_CHECK_ERR_RET( + esp_lcd_rgb_panel_register_event_callbacks(handle, &rgb_event_cb, &_callback_data), false, + "Register RGB callback failed" + ); + break; } #endif +#if SOC_MIPI_DSI_SUPPORTED + case ESP_PANEL_BUS_TYPE_MIPI_DSI: { + esp_lcd_dpi_panel_event_callbacks_t dpi_event_cb = { + .on_color_trans_done = (esp_lcd_dpi_panel_color_trans_done_cb_t)onDrawBitmapFinish, + .on_refresh_done = (esp_lcd_dpi_panel_refresh_done_cb_t)onRefreshFinish, + }; + ESP_PANEL_CHECK_ERR_RET( + esp_lcd_dpi_panel_register_event_callbacks(handle, &dpi_event_cb, &_callback_data), false, + "Register MIPI-DSI callback failed" + ); + break; + } +#endif + default: + esp_lcd_panel_io_callbacks_t io_cb = { + .on_color_trans_done = (esp_lcd_panel_io_color_trans_done_cb_t)onDrawBitmapFinish, + }; + ESP_PANEL_CHECK_ERR_RET( + esp_lcd_panel_io_register_event_callbacks(bus->getPanelIO_Handle(), &io_cb, &_callback_data), false, + "Register panel IO callback failed" + ); + break; + } +end: ESP_LOGD(TAG, "Begin end"); + _flags.is_begun = true; + _flags.is_reset = false; return true; } bool ESP_PanelLcd::reset(void) { + ESP_PANEL_CHECK_FALSE_RET(checkIsInit(), false, "Not initialized"); + +#if SOC_LCD_RGB_SUPPORTED + if ((bus->getType() == ESP_PANEL_BUS_TYPE_RGB) && !checkIsBegun() && vendor_config.flags.auto_del_panel_io) { + ESP_LOGD(TAG, "Ignore reset panel before begun for RGB LCD with auto release bus"); + goto end; + } +#endif + ESP_PANEL_CHECK_ERR_RET(esp_lcd_panel_reset(handle), false, "Reset panel failed"); +#if SOC_LCD_RGB_SUPPORTED +end: +#endif + _flags.is_reset = true; + _flags.is_begun = false; + return true; } bool ESP_PanelLcd::del(void) { + ESP_PANEL_CHECK_FALSE_RET(checkIsInit(), false, "Not initialized"); + ESP_PANEL_CHECK_ERR_RET(esp_lcd_panel_del(handle), false, "Delete panel failed"); - if (_refresh_finish_sem) { - vSemaphoreDelete(_refresh_finish_sem); - _refresh_finish_sem = NULL; + if (_draw_bitmap_finish_sem) { + vSemaphoreDelete(_draw_bitmap_finish_sem); + _draw_bitmap_finish_sem = NULL; } ESP_LOGD(TAG, "LCD panel @%p deleted", handle); handle = NULL; + _flags = {}; return true; } bool ESP_PanelLcd::drawBitmap(uint16_t x_start, uint16_t y_start, uint16_t width, uint16_t height, const uint8_t *color_data) { - ESP_PANEL_CHECK_ERR_RET(esp_lcd_panel_draw_bitmap(handle, x_start, y_start, x_start + width, y_start + height, color_data), - false, "Draw bitmap failed"); + ESP_PANEL_CHECK_FALSE_RET(checkIsBegun(), false, "Not begun"); + + ESP_PANEL_CHECK_ERR_RET( + esp_lcd_panel_draw_bitmap(handle, x_start, y_start, x_start + width, y_start + height, color_data), + false, "Draw bitmap failed" + ); return true; } -bool ESP_PanelLcd::drawBitmapWaitUntilFinish(uint16_t x_start, uint16_t y_start, uint16_t width, uint16_t height, - const uint8_t *color_data, int timeout_ms) +bool ESP_PanelLcd::drawBitmapWaitUntilFinish( + uint16_t x_start, uint16_t y_start, uint16_t width, uint16_t height, const uint8_t *color_data, int timeout_ms +) { - ESP_PANEL_CHECK_NULL_RET(bus, false, "Invalid bus"); + ESP_PANEL_CHECK_FALSE_RET(checkIsBegun(), false, "Not begun"); /* For RGB LCD, since `drawBitmap()` uses `memcpy()` instead of DMA operation, doesn't need to wait */ - if (bus->getType() == ESP_PANEL_BUS_TYPE_RGB) { - ESP_PANEL_CHECK_FALSE_RET(drawBitmap(x_start, y_start, width, height, color_data), false, "Draw bitmap failed"); - return true; - } - - /* For other LCDs, since `drawBitmap()` use DMA operation, need to use semaphore to wait */ - ESP_PANEL_CHECK_NULL_RET(_refresh_finish_sem, false, "Semaphore is not created"); - ESP_PANEL_CHECK_FALSE_RET(drawBitmap(x_start, y_start, width, height, color_data), false, "Draw bitmap failed"); - /* Wait for the semaphore to be given by the callback function */ - BaseType_t timeout_tick = (timeout_ms < 0) ? portMAX_DELAY : pdMS_TO_TICKS(timeout_ms); - if (xSemaphoreTake(_refresh_finish_sem, timeout_tick) != pdTRUE) { - ESP_LOGD(TAG, "Draw bitmap wait for finish timeout"); - return false; + /* For other interfaces which uses DMA operation, wait for the drawing to finish */ + if (bus->getType() != ESP_PANEL_BUS_TYPE_RGB) { + /* Wait for the semaphore to be given by the callback function */ + BaseType_t timeout_tick = (timeout_ms < 0) ? portMAX_DELAY : pdMS_TO_TICKS(timeout_ms); + ESP_PANEL_CHECK_FALSE_RET( + xSemaphoreTake(_draw_bitmap_finish_sem, timeout_tick) == pdTRUE, false, + "Draw bitmap wait for finish timeout" + ); } return true; @@ -239,30 +289,58 @@ bool ESP_PanelLcd::drawBitmapWaitUntilFinish(uint16_t x_start, uint16_t y_start, bool ESP_PanelLcd::mirrorX(bool en) { - ESP_PANEL_CHECK_ERR_RET(esp_lcd_panel_mirror(handle, en, _mirror_y), false, "Mirror X failed"); - _mirror_x = en; + ESP_PANEL_CHECK_FALSE_RET(checkIsInit(), false, "Not initialized"); + + if (disabled_functions.mirror) { + ESP_LOGW(TAG, "Mirror function is disabled"); + return true; + } + + ESP_PANEL_CHECK_ERR_RET(esp_lcd_panel_mirror(handle, en, _flags.mirror_y), false, "Mirror X failed"); + _flags.mirror_x = en; return true; } bool ESP_PanelLcd::mirrorY(bool en) { - ESP_PANEL_CHECK_ERR_RET(esp_lcd_panel_mirror(handle, _mirror_x, en), false, "Mirror X failed"); - _mirror_y = en; + ESP_PANEL_CHECK_FALSE_RET(checkIsInit(), false, "Not initialized"); + + if (disabled_functions.mirror) { + ESP_LOGW(TAG, "Mirror function is disabled"); + return true; + } + + ESP_PANEL_CHECK_ERR_RET(esp_lcd_panel_mirror(handle, _flags.mirror_x, en), false, "Mirror X failed"); + _flags.mirror_y = en; return true; } bool ESP_PanelLcd::swapXY(bool en) { + ESP_PANEL_CHECK_FALSE_RET(checkIsInit(), false, "Not initialized"); + + if (disabled_functions.swap_xy) { + ESP_LOGW(TAG, "Swap XY function is disabled"); + return true; + } + ESP_PANEL_CHECK_ERR_RET(esp_lcd_panel_swap_xy(handle, en), false, "Swap XY failed"); - _swap_xy = en; + _flags.swap_xy = en; return true; } bool ESP_PanelLcd::setGapX(uint16_t gap) { + ESP_PANEL_CHECK_FALSE_RET(checkIsInit(), false, "Not initialized"); + + if (disabled_functions.set_gap) { + ESP_LOGW(TAG, "Set gap function is disabled"); + return true; + } + ESP_PANEL_CHECK_ERR_RET(esp_lcd_panel_set_gap(handle, gap, _gap_y), false, "Set X gap failed"); _gap_x = gap; @@ -271,6 +349,13 @@ bool ESP_PanelLcd::setGapX(uint16_t gap) bool ESP_PanelLcd::setGapY(uint16_t gap) { + ESP_PANEL_CHECK_FALSE_RET(checkIsInit(), false, "Not initialized"); + + if (disabled_functions.set_gap) { + ESP_LOGW(TAG, "Set gap function is disabled"); + return true; + } + ESP_PANEL_CHECK_ERR_RET(esp_lcd_panel_set_gap(handle, _gap_x, gap), false, "Set Y gap failed"); _gap_y = gap; @@ -279,6 +364,8 @@ bool ESP_PanelLcd::setGapY(uint16_t gap) bool ESP_PanelLcd::invertColor(bool en) { + ESP_PANEL_CHECK_FALSE_RET(checkIsInit(), false, "Not initialized"); + ESP_PANEL_CHECK_ERR_RET(esp_lcd_panel_invert_color(handle, en), false, "Invert color failed"); return true; @@ -286,6 +373,28 @@ bool ESP_PanelLcd::invertColor(bool en) bool ESP_PanelLcd::displayOn(void) { + ESP_PANEL_CHECK_FALSE_RET(checkIsInit(), false, "Not initialized"); + + bool is_disable = disabled_functions.display_on_off; + if (is_disable) { + goto end; + } + +#if SOC_LCD_RGB_SUPPORTED + if (bus->getType() == ESP_PANEL_BUS_TYPE_RGB) { + is_disable = (bus->getPanelIO_Handle() == NULL) && (vendor_config.rgb_config->disp_gpio_num == -1); + if (is_disable) { + goto end; + } + } +#endif + +end: + if (is_disable) { + ESP_LOGW(TAG, "Display on/off function is disabled"); + return true; + } + ESP_PANEL_CHECK_ERR_RET(esp_lcd_panel_disp_on_off(handle, true), false, "Display on failed"); return true; @@ -293,18 +402,50 @@ bool ESP_PanelLcd::displayOn(void) bool ESP_PanelLcd::displayOff(void) { + ESP_PANEL_CHECK_FALSE_RET(checkIsInit(), false, "Not initialized"); + + if (disabled_functions.display_on_off) { + ESP_LOGW(TAG, "Display on/off function is disabled"); + return true; + } + ESP_PANEL_CHECK_ERR_RET(esp_lcd_panel_disp_on_off(handle, false), false, "Display off failed"); return true; } +bool ESP_PanelLcd::attachDrawBitmapFinishCallback(std::function callback, void *user_data) +{ + ESP_PANEL_CHECK_FALSE_RET(checkIsInit(), false, "Not initialized"); + ESP_PANEL_CHECK_FALSE_RET( + bus->getType() != ESP_PANEL_BUS_TYPE_RGB, false, "RGB interface doesn't support this callback" + ); + +// *INDENT-OFF* + if ((_callback_data.user_data != NULL) && (_callback_data.user_data != user_data)) { + ESP_LOGW(TAG, "Callback data is not NULL, will overwrite the previous one"); + } + _callback_data.user_data = user_data; + onDrawBitmapFinishCallback = callback; +// *INDENT-OFF* + + return true; +} + bool ESP_PanelLcd::attachRefreshFinishCallback(std::function callback, void *user_data) { + ESP_PANEL_CHECK_FALSE_RET(checkIsInit(), false, "Not initialized"); + ESP_PANEL_CHECK_FALSE_RET( + (bus->getType() != ESP_PANEL_BUS_TYPE_SPI) && (bus->getType() != ESP_PANEL_BUS_TYPE_QSPI), false, + "SPI and QSPI interfaces don't support this callback" + ); + + /* Check the callback function and user data placement */ // For RGB LCD, if the "XIP on PSRAM" function is not enabled, the callback function and user data should be // placed in SRAM -#if SOC_LCD_RGB_SUPPORTED && CONFIG_LCD_RGB_ISR_IRAM_SAFE && \ - !(CONFIG_SPIRAM_RODATA && CONFIG_SPIRAM_FETCH_INSTRUCTIONS) - if (bus->getType() == ESP_PANEL_BUS_TYPE_RGB) { +#if (SOC_MIPI_DSI_SUPPORTED && CONFIG_LCD_DSI_ISR_IRAM_SAFE) || \ + (SOC_LCD_RGB_SUPPORTED && CONFIG_LCD_RGB_ISR_IRAM_SAFE && !(CONFIG_SPIRAM_RODATA && CONFIG_SPIRAM_FETCH_INSTRUCTIONS)) + if (bus->getType() == ESP_PANEL_BUS_TYPE_RGB || bus->getType() == ESP_PANEL_BUS_TYPE_MIPI_DSI) { ESP_PANEL_CHECK_FALSE_RET( esp_ptr_in_iram(callback), false, "Callback function should be placed in IRAM, add `IRAM_ATTR` before the function" @@ -314,7 +455,10 @@ bool ESP_PanelLcd::attachRefreshFinishCallback(std::function call #endif // *INDENT-OFF* - callback_data.user_data = user_data; + if ((_callback_data.user_data != NULL) && (_callback_data.user_data != user_data)) { + ESP_LOGW(TAG, "Callback data is not NULL, will overwrite the previous one"); + } + _callback_data.user_data = user_data; onRefreshFinishCallback = callback; // *INDENT-OFF* @@ -323,23 +467,25 @@ bool ESP_PanelLcd::attachRefreshFinishCallback(std::function call bool ESP_PanelLcd::colorBarTest(uint16_t width, uint16_t height) { - ESP_PANEL_CHECK_NULL_RET(bus, false, "Invalid bus"); + ESP_PANEL_CHECK_FALSE_RET(checkIsBegun(), false, "Not begun"); int bits_per_piexl = getColorBits(); ESP_PANEL_CHECK_FALSE_RET(bits_per_piexl > 0, false, "Invalid color bits"); + ESP_LOGD(TAG, "Color bar test, width: %d, height: %d, bits per pixel: %d", width, height, bits_per_piexl); + int bytes_per_piexl = bits_per_piexl / 8; - int line_per_bar = height / bits_per_piexl; + int row_per_bar = height / bits_per_piexl; int line_count = 0; int res_line_count = 0; /* Malloc memory for a single color bar */ - shared_ptr single_bar_buf(new uint8_t[line_per_bar * width * bytes_per_piexl]); + shared_ptr single_bar_buf(new uint8_t[row_per_bar * width * bytes_per_piexl]); ESP_PANEL_CHECK_FALSE_RET(single_bar_buf != nullptr, false, "Malloc color buffer failed"); /* Draw color bar from top left to bottom right, the order is B - G - R */ for (int j = 0; j < bits_per_piexl; j++) { - for (int i = 0; i < line_per_bar * width; i++) { + for (int i = 0; i < row_per_bar * width; i++) { for (int k = 0; k < bytes_per_piexl; k++) { if ((bus->getType() == ESP_PANEL_BUS_TYPE_SPI) || (bus->getType() == ESP_PANEL_BUS_TYPE_QSPI)) { // For SPI interface, the data bytes should be swapped since the data is sent by LSB first @@ -349,9 +495,9 @@ bool ESP_PanelLcd::colorBarTest(uint16_t width, uint16_t height) } } } - line_count += line_per_bar; + line_count += row_per_bar; ESP_PANEL_CHECK_FALSE_RET( - drawBitmapWaitUntilFinish(0, j * line_per_bar, width, line_per_bar, single_bar_buf.get()), false, + drawBitmapWaitUntilFinish(0, j * row_per_bar, width, row_per_bar, single_bar_buf.get()), false, "Draw bitmap failed" ); } @@ -371,77 +517,157 @@ bool ESP_PanelLcd::colorBarTest(uint16_t width, uint16_t height) return true; } -int ESP_PanelLcd::getColorBits(void) +#if SOC_MIPI_DSI_SUPPORTED +bool ESP_PanelLcd::showDsiPattern(DsiPatternType type) { -#if SOC_LCD_RGB_SUPPORTED - ESP_PANEL_CHECK_NULL_RET(bus, -1, "Invalid bus"); - if (bus->getType() == ESP_PANEL_BUS_TYPE_RGB) { - const esp_lcd_rgb_panel_config_t *rgb_config = static_cast(bus)->getRgbConfig(); - ESP_PANEL_CHECK_NULL_RET(rgb_config, -1, "Invalid RGB config"); + ESP_PANEL_CHECK_FALSE_RET(checkIsBegun(), false, "Not begun"); + ESP_PANEL_CHECK_FALSE_RET( + bus->getType() == ESP_PANEL_BUS_TYPE_MIPI_DSI, false, "Invalid bus type(%d)", bus->getType() + ); - return rgb_config->bits_per_pixel; - } -#endif + ESP_PANEL_CHECK_ERR_RET( + esp_lcd_dpi_panel_set_pattern(handle, static_cast(type)), false, + "Set DPI pattern failed" + ); - return panel_config.bits_per_pixel; + return true; } +#endif /* SOC_MIPI_DSI_SUPPORTED */ -bool ESP_PanelLcd::getSwapXYFlag(void) +int ESP_PanelLcd::getColorBits(void) { - return _swap_xy; -} + ESP_PANEL_CHECK_NULL_RET(bus, -1, "Invalid bus"); -bool ESP_PanelLcd::getMirrorXFlag(void) -{ - return _mirror_x; -} + int bits_per_pixel = panel_config.bits_per_pixel; + switch (bus->getType()) { +#if SOC_LCD_RGB_SUPPORTED + case ESP_PANEL_BUS_TYPE_RGB: { + const esp_lcd_rgb_panel_config_t *rgb_config = static_cast(bus)->getRgbConfig(); + ESP_PANEL_CHECK_NULL_RET(rgb_config, -1, "Invalid RGB config"); + bits_per_pixel = rgb_config->bits_per_pixel; + break; + } +#endif /* SOC_LCD_RGB_SUPPORTED */ +#if SOC_MIPI_DSI_SUPPORTED + case ESP_PANEL_BUS_TYPE_MIPI_DSI: { + const esp_lcd_dpi_panel_config_t *dpi_config = static_cast(bus)->getDpiConfig(); + ESP_PANEL_CHECK_NULL_RET(dpi_config, -1, "Invalid MIPI DPI config"); + switch (dpi_config->pixel_format) { + case LCD_COLOR_PIXEL_FORMAT_RGB565: + bits_per_pixel = 16; + break; + case LCD_COLOR_PIXEL_FORMAT_RGB666: + bits_per_pixel = 18; + break; + case LCD_COLOR_PIXEL_FORMAT_RGB888: + bits_per_pixel = 24; + break; + default: + break; + } + break; + } +#endif /* SOC_MIPI_DSI_SUPPORTED */ + default: + break; + } -bool ESP_PanelLcd::getMirrorYFlag(void) -{ - return _mirror_y; + return bits_per_pixel; } -#if SOC_LCD_RGB_SUPPORTED -void *ESP_PanelLcd::getRgbBufferByIndex(uint8_t index) +void *ESP_PanelLcd::getFrameBufferByIndex(uint8_t index) { - ESP_PANEL_CHECK_NULL_RET(handle, NULL, "Invalid handle"); + ESP_PANEL_CHECK_FALSE_RET(checkIsBegun(), NULL, "Not begun"); + ESP_PANEL_CHECK_FALSE_RET( + index < ESP_PANEL_LCD_FRAME_BUFFER_MAX_NUM, NULL, "Index(%d) out of range(0-%d)", index, + ESP_PANEL_LCD_FRAME_BUFFER_MAX_NUM - 1 + ); - void *buffer[3] = { NULL }; - ESP_PANEL_CHECK_ERR_RET(esp_lcd_rgb_panel_get_frame_buffer(handle, index + 1, &buffer[0], &buffer[1], &buffer[2]), - NULL, "Get RGB buffer failed"); + void *buffer[ESP_PANEL_LCD_FRAME_BUFFER_MAX_NUM] = {}; + switch (bus->getType()) { +#if SOC_LCD_RGB_SUPPORTED + case ESP_PANEL_BUS_TYPE_RGB: + ESP_PANEL_CHECK_ERR_RET( + esp_lcd_rgb_panel_get_frame_buffer(handle, index + 1, &buffer[0], &buffer[1], &buffer[2]), NULL, + "Get RGB buffer failed" + ); + break; +#endif +#if SOC_MIPI_DSI_SUPPORTED + case ESP_PANEL_BUS_TYPE_MIPI_DSI: + ESP_PANEL_CHECK_ERR_RET( + esp_lcd_dpi_panel_get_frame_buffer(handle, index + 1, &buffer[0], &buffer[1], &buffer[2]), NULL, + "Get MIPI DPI buffer failed" + ); + break; +#endif + default: + ESP_PANEL_CHECK_FALSE_RET(false, NULL, "Invalid bus type(%d)", bus->getType()); + break; + } return buffer[index]; } -#endif -uint8_t ESP_PanelLcd::getXCoordAlign(void) +bool ESP_PanelLcd::loadVendorConfigFromBus(void) { - return x_coord_align; -} + ESP_PANEL_CHECK_FALSE_RET(!checkIsInit(), false, "This function should be called before `init()`"); + ESP_PANEL_CHECK_NULL_RET(bus, false, "Invalid bus"); -uint8_t ESP_PanelLcd::getYCoordAlign(void) -{ - return y_coord_align; + switch (bus->getType()) { + case ESP_PANEL_BUS_TYPE_SPI: + vendor_config.flags.use_spi_interface = 1; + break; + case ESP_PANEL_BUS_TYPE_QSPI: + vendor_config.flags.use_qspi_interface = 1; + break; +#if SOC_LCD_RGB_SUPPORTED + /* Retrieve RGB configuration from the bus and register it into the vendor configuration */ + case ESP_PANEL_BUS_TYPE_RGB: + vendor_config.flags.use_rgb_interface = 1; + vendor_config.rgb_config = static_cast(bus)->getRgbConfig(); + break; +#endif +#if SOC_MIPI_DSI_SUPPORTED + /* Retrieve MIPI DPI configuration from the bus and register it into the vendor configuration */ + case ESP_PANEL_BUS_TYPE_MIPI_DSI: + vendor_config.flags.use_mipi_interface = 1; + vendor_config.mipi_config = { + .lane_num = static_cast(bus)->getDsiConfig()->num_data_lanes, + .dsi_bus = static_cast(bus)->getBusHandle(), + .dpi_config = static_cast(bus)->getDpiConfig(), + }; + break; +#endif + default: + ESP_LOGE(TAG, "Unsupported bus type"); + break; + } + + return true; } -esp_lcd_panel_handle_t ESP_PanelLcd::getHandle(void) +IRAM_ATTR bool ESP_PanelLcd::onDrawBitmapFinish(void *panel_io, void *edata, void *user_ctx) { - if (handle == NULL) { - ESP_PANEL_ENABLE_TAG_DEBUG_LOG(); - ESP_LOGD(TAG, "Get invalid handle"); + ESP_PanelLcdCallbackData_t *callback_data = (ESP_PanelLcdCallbackData_t *)user_ctx; + if (callback_data == NULL) { + return false; } - return handle; -} + ESP_PanelLcd *lcd_ptr = (ESP_PanelLcd *)callback_data->lcd_ptr; + if (lcd_ptr == NULL) { + return false; + } -ESP_PanelBus *ESP_PanelLcd::getBus(void) -{ - if (bus == NULL) { - ESP_PANEL_ENABLE_TAG_DEBUG_LOG(); - ESP_LOGD(TAG, "Get invalid bus"); + BaseType_t need_yield = pdFALSE; + if (lcd_ptr->onDrawBitmapFinishCallback != NULL) { + need_yield = lcd_ptr->onDrawBitmapFinishCallback(callback_data->user_data) ? pdTRUE : need_yield; + } + if (lcd_ptr->_draw_bitmap_finish_sem != NULL) { + xSemaphoreGiveFromISR(lcd_ptr->_draw_bitmap_finish_sem, &need_yield); } - return bus; + return (need_yield == pdTRUE); } IRAM_ATTR bool ESP_PanelLcd::onRefreshFinish(void *panel_io, void *edata, void *user_ctx) @@ -460,9 +686,6 @@ IRAM_ATTR bool ESP_PanelLcd::onRefreshFinish(void *panel_io, void *edata, void * if (lcd_ptr->onRefreshFinishCallback != NULL) { need_yield = lcd_ptr->onRefreshFinishCallback(callback_data->user_data) ? pdTRUE : need_yield; } - if (lcd_ptr->_refresh_finish_sem != NULL) { - xSemaphoreGiveFromISR(lcd_ptr->_refresh_finish_sem, &need_yield); - } return (need_yield == pdTRUE); } diff --git a/src/lcd/ESP_PanelLcd.h b/src/lcd/ESP_PanelLcd.h index c8fb4293..e4da6a85 100644 --- a/src/lcd/ESP_PanelLcd.h +++ b/src/lcd/ESP_PanelLcd.h @@ -11,15 +11,13 @@ #include "soc/soc_caps.h" #include "esp_lcd_panel_ops.h" #include "esp_lcd_panel_vendor.h" -#if SOC_LCD_RGB_SUPPORTED -#include "esp_lcd_panel_rgb.h" -#endif #include "freertos/FreeRTOS.h" #include "freertos/semphr.h" -#include "soc/soc_caps.h" -#include "base/esp_lcd_custom_types.h" +#include "base/esp_lcd_vendor_types.h" #include "bus/ESP_PanelBus.h" +#define ESP_PANEL_LCD_FRAME_BUFFER_MAX_NUM (3) + /** * @brief LCD device default configuration macro * @@ -43,6 +41,15 @@ */ class ESP_PanelLcd { public: +#if SOC_MIPI_DSI_SUPPORTED + enum class DsiPatternType { + NONE = MIPI_DSI_PATTERN_NONE, + BAR_HORIZONTAL = MIPI_DSI_PATTERN_BAR_HORIZONTAL, + BAR_VERTICAL = MIPI_DSI_PATTERN_BAR_VERTICAL, + BER_VERTICAL = MIPI_DSI_PATTERN_BER_VERTICAL, + }; +#endif + /** * @brief Construct a new LCD device in a simple way, the `init()` function should be called after this function * @@ -91,13 +98,20 @@ class ESP_PanelLcd { * @param bgr_order true: BGR order, false: RGB order * */ - void configColorRgbOrder(bool BGR_order); + bool configColorRgbOrder(bool BGR_order); + + /** + * @brief Configure the reset active level of LCD, default is RGB. This function should be called before `init()` + * + * @param level 0: low level, 1: high level + * + */ + bool configResetActiveLevel(int level); /** * @brief Configure driver to mirror by command, default is false (by software). This function should be called before - * `init()` + * `init()`. Only valid for RGB interface. * - * @note This function is only useful for some LCDs without GRAM, like RGB LCD. * @note After using this function, the `mirror()` function will be implemented by LCD command. Otherwise, the * `mirror()`function will be implemented by software * @note This function is conflict with `configAutoReleaseBus()`, please don't use them at the same time @@ -105,13 +119,12 @@ class ESP_PanelLcd { * @param en true: enable, false: disable * */ - void configMirrorByCommand(bool en); + bool configMirrorByCommand(bool en); /** * @brief Configure driver to release bus automatically, default is false. This function should be called before - * `init()` + * `init()`. Only valid for RGB interface. * - * @note This function is only useful for some LCDs without GRAM, like RGB LCD. * @note If the "3-wire SPI" interface are sharing pins of the "RGB" interface to save GPIOs, please call * this function to release the bus object and pins (except CS signal). And then, the "3-wire SPI" interface * cannot be used to transmit commands any more. @@ -119,8 +132,29 @@ class ESP_PanelLcd { * * @param en true: enable, false: disable * + * @return true if success, otherwise false */ - void configAutoReleaseBus(bool en); + [[deprecated("This function is deprecated, please use `configEnableIO_Multiplex()` instead")]] + bool configAutoReleaseBus(bool en) + { + return configEnableIO_Multiplex(en); + } + + /** + * @brief Configure driver to enable IO multiplex function, default is false. This function should be called before + * `init()` and the panel IO will be deleted automatically after calling `init()` function. Only valid for + * RGB interface. + * + * @note If the "3-wire SPI" interface are sharing pins of the "RGB" interface to save GPIOs, please call + * this function to release the bus object and pins (except CS signal). And then, the "3-wire SPI" interface + * cannot be used to transmit commands any more. + * @note This function is conflict with `configMirrorByCommand()`, please don't use them at the same time + * + * @param en true: enable, false: disable + * + * @return true if success, otherwise false + */ + bool configEnableIO_Multiplex(bool en); /** * @brief Initialize the LCD device, the `begin()` function should be called after this function @@ -305,6 +339,19 @@ class ESP_PanelLcd { * by this function * @param user_data The user data which will be passed to the callback function */ + bool attachDrawBitmapFinishCallback(std::function callback, void *user_data = NULL); + + /** + * @brief Attach a callback function, which will be called when the frame buffer refreshing is finished + * + * @note For RGB LCD, the function will be called when VSYNC end signal is detected, which means + * the whole frame refreshing is finished + * @note For other LCDs, the function will be called when every single drawing is finished + * + * @param callback The callback function. Its return value decides whether a high priority task has been waken up + * by this function + * @param user_data The user data which will be passed to the callback function + */ bool attachRefreshFinishCallback(std::function callback, void *user_data = NULL); /** @@ -320,6 +367,10 @@ class ESP_PanelLcd { */ bool colorBarTest(uint16_t width, uint16_t height); +#if SOC_MIPI_DSI_SUPPORTED + bool showDsiPattern(DsiPatternType type); +#endif /* SOC_MIPI_DSI_SUPPORTED */ + /** * @brief Get the bits of pixel color * @@ -334,25 +385,35 @@ class ESP_PanelLcd { * * @return true if swap, otherwise not swap */ - bool getSwapXYFlag(void); + bool getSwapXYFlag(void) + { + return _flags.swap_xy; + } /** * @brief Get the flag of the X axis mirror * * @return true if mirror, otherwise not mirror */ - bool getMirrorXFlag(void); + bool getMirrorXFlag(void) + { + return _flags.mirror_x; + } /** * @brief Get the flag of the Y axis mirror * * @return true if mirror, otherwise not mirror */ - bool getMirrorYFlag(void); + bool getMirrorYFlag(void) + { + return _flags.mirror_y; + } #if SOC_LCD_RGB_SUPPORTED /** - * @brief Get the RGB buffer by index (default is 0), only valid for RGB LCD + * @brief Get the RGB buffer by index (default is 0), only valid for RGB LCD. + * Deprecated function, please use `getFrameBufferByIndex()` instead * * @note This function should be called after `begin()` * @@ -362,38 +423,85 @@ class ESP_PanelLcd { * - NULL: if fail * - others: the pointer of the RGB buffer */ - void *getRgbBufferByIndex(uint8_t index = 0); + [[deprecated("This API is deprecated. Please use `getFrameBufferByIndex()` instead.")]] + void *getRgbBufferByIndex(uint8_t index = 0) + { + return getFrameBufferByIndex(index); + } #endif + /** + * @brief Get the frame buffer by index (default is 0), currently only valid for RGB/MIPI-DSI LCD + * + * @note This function should be called after `begin()` + * + * @param index + * + * @return + * - NULL: if fail + * - others: the pointer of the frame buffer + */ + void *getFrameBufferByIndex(uint8_t index = 0); + /** * @brief Get the X coordinate align * * @return The X coordinate align */ - uint8_t getXCoordAlign(void); + uint8_t getXCoordAlign(void) + { + return x_coord_align; + } /** * @brief Get the Y coordinate align * * @return The Y coordinate align */ - uint8_t getYCoordAlign(void); + uint8_t getYCoordAlign(void) + { + return y_coord_align; + } /** * @brief Get the panel handle * * @return The handle of the LCD panel, or NULL if fail */ - esp_lcd_panel_handle_t getHandle(void); + esp_lcd_panel_handle_t getHandle(void) + { + return handle; + } /** * @brief Get the panel bus * * @return The pointer of the LCD Bus, or NULL if fail */ - ESP_PanelBus *getBus(void); + ESP_PanelBus *getBus(void) + { + return bus; + } protected: + bool loadVendorConfigFromBus(void); + + bool checkIsInit(void) + { + return (handle != NULL) && (bus != NULL); + } + + bool checkIsBegun(void) + { + return _flags.is_begun; + } + + struct { + uint8_t mirror: 1; + uint8_t swap_xy: 1; + uint8_t set_gap: 1; + uint8_t display_on_off: 1; + } disabled_functions; uint8_t x_coord_align; uint8_t y_coord_align; ESP_PanelBus *bus; @@ -402,19 +510,25 @@ class ESP_PanelLcd { esp_lcd_panel_handle_t handle; private: - static bool onRefreshFinish(void *panel_io, void *edata, void *user_ctx); - - bool _swap_xy; - bool _mirror_x; - bool _mirror_y; + IRAM_ATTR static bool onDrawBitmapFinish(void *panel_io, void *edata, void *user_ctx); + IRAM_ATTR static bool onRefreshFinish(void *panel_io, void *edata, void *user_ctx); + + struct { + uint8_t is_begun: 1; + uint8_t is_reset: 1; + uint8_t swap_xy: 1; + uint8_t mirror_x: 1; + uint8_t mirror_y: 1; + } _flags; uint16_t _gap_x; uint16_t _gap_y; + std::function onDrawBitmapFinishCallback; std::function onRefreshFinishCallback; - SemaphoreHandle_t _refresh_finish_sem; + SemaphoreHandle_t _draw_bitmap_finish_sem; typedef struct { void *lcd_ptr; void *user_data; } ESP_PanelLcdCallbackData_t; - ESP_PanelLcdCallbackData_t callback_data; + ESP_PanelLcdCallbackData_t _callback_data; }; diff --git a/src/lcd/GC9503.cpp b/src/lcd/GC9503.cpp index 22141908..8c96b8fe 100644 --- a/src/lcd/GC9503.cpp +++ b/src/lcd/GC9503.cpp @@ -42,7 +42,18 @@ bool ESP_PanelLcd_GC9503::init(void) { ESP_PANEL_CHECK_NULL_RET(bus, false, "Invalid bus"); - ESP_PANEL_CHECK_ERR_RET(esp_lcd_new_panel_gc9503(bus->getHandle(), &panel_config, &handle), false, "Create panel failed"); + /* Load RGB configurations from bus to vendor configurations */ + ESP_PANEL_CHECK_FALSE_RET(loadVendorConfigFromBus(), false, "Load vendor config from bus failed"); + + /* Create panel handle */ + ESP_PANEL_CHECK_ERR_RET( + esp_lcd_new_panel_gc9503(bus->getPanelIO_Handle(), &panel_config, &handle), false, "Create panel failed" + ); + + // Delete panel io if enable `auto_del_panel_io` or `enable_io_multiplex` flag + if (((esp_lcd_panel_vendor_config_t *)panel_config.vendor_config)->flags.auto_del_panel_io) { + ESP_PANEL_CHECK_FALSE_RET(bus->delSkipPanelIO(), false, "Delete panel io failed"); + } return true; } diff --git a/src/lcd/GC9503.h b/src/lcd/GC9503.h index a37b5f01..f1f9f49a 100644 --- a/src/lcd/GC9503.h +++ b/src/lcd/GC9503.h @@ -10,7 +10,7 @@ #if SOC_LCD_RGB_SUPPORTED #include "ESP_PanelLcd.h" -#include "base/esp_lcd_custom_types.h" +#include "base/esp_lcd_vendor_types.h" #include "base/esp_lcd_gc9503.h" /** diff --git a/src/lcd/GC9A01.cpp b/src/lcd/GC9A01.cpp index 34c938b3..775e46ea 100644 --- a/src/lcd/GC9A01.cpp +++ b/src/lcd/GC9A01.cpp @@ -39,7 +39,7 @@ bool ESP_PanelLcd_GC9A01::init(void) { ESP_PANEL_CHECK_NULL_RET(bus, false, "Invalid bus"); - ESP_PANEL_CHECK_ERR_RET(esp_lcd_new_panel_gc9a01(bus->getHandle(), &panel_config, &handle), false, "Create panel failed"); + ESP_PANEL_CHECK_ERR_RET(esp_lcd_new_panel_gc9a01(bus->getPanelIO_Handle(), &panel_config, &handle), false, "Create panel failed"); return true; } diff --git a/src/lcd/GC9A01.h b/src/lcd/GC9A01.h index e3dab146..6701706b 100644 --- a/src/lcd/GC9A01.h +++ b/src/lcd/GC9A01.h @@ -7,7 +7,7 @@ #pragma once #include "ESP_PanelLcd.h" -#include "base/esp_lcd_custom_types.h" +#include "base/esp_lcd_vendor_types.h" #include "base/esp_lcd_gc9a01.h" /** diff --git a/src/lcd/GC9B71.cpp b/src/lcd/GC9B71.cpp index 1cdfdf63..61d5bab5 100644 --- a/src/lcd/GC9B71.cpp +++ b/src/lcd/GC9B71.cpp @@ -43,7 +43,7 @@ bool ESP_PanelLcd_GC9B71::init(void) { ESP_PANEL_CHECK_NULL_RET(bus, false, "Invalid bus"); - ESP_PANEL_CHECK_ERR_RET(esp_lcd_new_panel_gc9b71(bus->getHandle(), &panel_config, &handle), false, "Create panel failed"); + ESP_PANEL_CHECK_ERR_RET(esp_lcd_new_panel_gc9b71(bus->getPanelIO_Handle(), &panel_config, &handle), false, "Create panel failed"); return true; } diff --git a/src/lcd/GC9B71.h b/src/lcd/GC9B71.h index af2ac1db..12fd9767 100644 --- a/src/lcd/GC9B71.h +++ b/src/lcd/GC9B71.h @@ -7,7 +7,7 @@ #pragma once #include "ESP_PanelLcd.h" -#include "base/esp_lcd_custom_types.h" +#include "base/esp_lcd_vendor_types.h" #include "base/esp_lcd_gc9b71.h" /** diff --git a/src/lcd/ILI9341.cpp b/src/lcd/ILI9341.cpp index c144581a..6a0294ef 100644 --- a/src/lcd/ILI9341.cpp +++ b/src/lcd/ILI9341.cpp @@ -39,7 +39,7 @@ bool ESP_PanelLcd_ILI9341::init(void) { ESP_PANEL_CHECK_NULL_RET(bus, false, "Invalid bus"); - ESP_PANEL_CHECK_ERR_RET(esp_lcd_new_panel_ili9341(bus->getHandle(), &panel_config, &handle), false, "Create panel failed"); + ESP_PANEL_CHECK_ERR_RET(esp_lcd_new_panel_ili9341(bus->getPanelIO_Handle(), &panel_config, &handle), false, "Create panel failed"); return true; } diff --git a/src/lcd/ILI9341.h b/src/lcd/ILI9341.h index 4dee383c..97557f35 100644 --- a/src/lcd/ILI9341.h +++ b/src/lcd/ILI9341.h @@ -7,7 +7,7 @@ #pragma once #include "ESP_PanelLcd.h" -#include "base/esp_lcd_custom_types.h" +#include "base/esp_lcd_vendor_types.h" #include "base/esp_lcd_ili9341.h" /** diff --git a/src/lcd/ILI9881C.cpp b/src/lcd/ILI9881C.cpp new file mode 100644 index 00000000..1a3a498c --- /dev/null +++ b/src/lcd/ILI9881C.cpp @@ -0,0 +1,60 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "soc/soc_caps.h" + +#if SOC_MIPI_DSI_SUPPORTED +#include "ESP_PanelLog.h" +#include "ILI9881C.h" + +static const char *TAG = "ILI9881C_CPP"; + +ESP_PanelLcd_ILI9881C::ESP_PanelLcd_ILI9881C(ESP_PanelBus *bus, uint8_t color_bits, int rst_io): + ESP_PanelLcd(bus, color_bits, rst_io) +{ + disabled_functions.set_gap = 1; + disabled_functions.swap_xy = 1; +} + +ESP_PanelLcd_ILI9881C::ESP_PanelLcd_ILI9881C(ESP_PanelBus *bus, const esp_lcd_panel_dev_config_t &panel_config): + ESP_PanelLcd(bus, panel_config) +{ + disabled_functions.set_gap = 1; + disabled_functions.swap_xy = 1; +} + +ESP_PanelLcd_ILI9881C::~ESP_PanelLcd_ILI9881C() +{ + ESP_PANEL_ENABLE_TAG_DEBUG_LOG(); + + if (handle == NULL) { + goto end; + } + + if (!del()) { + ESP_LOGE(TAG, "Delete device failed"); + } + +end: + ESP_LOGD(TAG, "Destroyed"); +} + +bool ESP_PanelLcd_ILI9881C::init(void) +{ + ESP_PANEL_CHECK_NULL_RET(bus, false, "Invalid bus"); + + /* Load MIPI-DSI configurations from bus to vendor configurations */ + ESP_PANEL_CHECK_FALSE_RET(loadVendorConfigFromBus(), false, "Load vendor config from bus failed"); + + /* Create panel handle */ + ESP_PANEL_CHECK_ERR_RET( + esp_lcd_new_panel_ili9881c(bus->getPanelIO_Handle(), &panel_config, &handle), false, "Create panel failed" + ); + + return true; +} + +#endif diff --git a/src/lcd/ILI9881C.h b/src/lcd/ILI9881C.h new file mode 100644 index 00000000..50457853 --- /dev/null +++ b/src/lcd/ILI9881C.h @@ -0,0 +1,59 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include "soc/soc_caps.h" + +#if SOC_MIPI_DSI_SUPPORTED +#include "ESP_PanelLcd.h" +#include "base/esp_lcd_vendor_types.h" +#include "base/esp_lcd_ili9881c.h" + +/** + * @brief ILI9881C LCD device object class + * + * @note This class is a derived class of `ESP_PanelLcd`, user can use it directly + */ +class ESP_PanelLcd_ILI9881C: public ESP_PanelLcd { +public: + /** + * @brief Construct a new LCD device in a simple way, the `init()` function should be called after this function + * + * @note This function uses some default values to config the LCD device, please use `config*()` functions to + * change them + * @note Vendor specific initialization can be different between manufacturers, should consult the LCD supplier + * for initialization sequence code, and use `configVendorCommands()` to configure + * + * @param bus Pointer of panel bus + * @param color_bits Bits per pixel (16/18/24) + * @param rst_io Reset pin, set to -1 if no use + */ + ESP_PanelLcd_ILI9881C(ESP_PanelBus *bus, uint8_t color_bits, int rst_io = -1); + + /** + * @brief Construct a new LCD in a complex way, the `init()` function should be called after this function + * + * @param bus Pointer of panel bus + * @param panel_config LCD device configuration + */ + ESP_PanelLcd_ILI9881C(ESP_PanelBus *bus, const esp_lcd_panel_dev_config_t &panel_config); + + /** + * @brief Destroy the LCD device + * + */ + ~ESP_PanelLcd_ILI9881C() override; + + /** + * @brief Initialize the LCD device, the `begin()` function should be called after this function + * + * @note This function typically calls `esp_lcd_new_panel_*()` to create the LCD panel handle + * + * @return true if success, otherwise false + */ + bool init(void) override; +}; +#endif diff --git a/src/lcd/NV3022B.cpp b/src/lcd/NV3022B.cpp index aa1d9741..54a95202 100644 --- a/src/lcd/NV3022B.cpp +++ b/src/lcd/NV3022B.cpp @@ -39,7 +39,7 @@ bool ESP_PanelLcd_NV3022B::init(void) { ESP_PANEL_CHECK_NULL_RET(bus, false, "Invalid bus"); - ESP_PANEL_CHECK_ERR_RET(esp_lcd_new_panel_nv3022b(bus->getHandle(), &panel_config, &handle), false, "Create panel failed"); + ESP_PANEL_CHECK_ERR_RET(esp_lcd_new_panel_nv3022b(bus->getPanelIO_Handle(), &panel_config, &handle), false, "Create panel failed"); return true; } diff --git a/src/lcd/NV3022B.h b/src/lcd/NV3022B.h index aa4f0a72..39dd3957 100644 --- a/src/lcd/NV3022B.h +++ b/src/lcd/NV3022B.h @@ -7,7 +7,7 @@ #pragma once #include "ESP_PanelLcd.h" -#include "base/esp_lcd_custom_types.h" +#include "base/esp_lcd_vendor_types.h" #include "base/esp_lcd_nv3022b.h" /** diff --git a/src/lcd/SH8601.cpp b/src/lcd/SH8601.cpp index 7329fc1a..2c2f31c3 100644 --- a/src/lcd/SH8601.cpp +++ b/src/lcd/SH8601.cpp @@ -43,7 +43,7 @@ bool ESP_PanelLcd_SH8601::init(void) { ESP_PANEL_CHECK_NULL_RET(bus, false, "Invalid bus"); - ESP_PANEL_CHECK_ERR_RET(esp_lcd_new_panel_sh8601(bus->getHandle(), &panel_config, &handle), false, "Create panel failed"); + ESP_PANEL_CHECK_ERR_RET(esp_lcd_new_panel_sh8601(bus->getPanelIO_Handle(), &panel_config, &handle), false, "Create panel failed"); return true; } diff --git a/src/lcd/SH8601.h b/src/lcd/SH8601.h index 6d1c0a30..91090d7d 100644 --- a/src/lcd/SH8601.h +++ b/src/lcd/SH8601.h @@ -7,7 +7,7 @@ #pragma once #include "ESP_PanelLcd.h" -#include "base/esp_lcd_custom_types.h" +#include "base/esp_lcd_vendor_types.h" #include "base/esp_lcd_sh8601.h" /** diff --git a/src/lcd/SPD2010.cpp b/src/lcd/SPD2010.cpp index 288dd006..133d3ddb 100644 --- a/src/lcd/SPD2010.cpp +++ b/src/lcd/SPD2010.cpp @@ -41,7 +41,7 @@ bool ESP_PanelLcd_SPD2010::init(void) { ESP_PANEL_CHECK_NULL_RET(bus, false, "Invalid bus"); - ESP_PANEL_CHECK_ERR_RET(esp_lcd_new_panel_spd2010(bus->getHandle(), &panel_config, &handle), false, "Create panel failed"); + ESP_PANEL_CHECK_ERR_RET(esp_lcd_new_panel_spd2010(bus->getPanelIO_Handle(), &panel_config, &handle), false, "Create panel failed"); return true; } diff --git a/src/lcd/SPD2010.h b/src/lcd/SPD2010.h index 9f1c6f72..94dd54a4 100644 --- a/src/lcd/SPD2010.h +++ b/src/lcd/SPD2010.h @@ -7,7 +7,7 @@ #pragma once #include "ESP_PanelLcd.h" -#include "base/esp_lcd_custom_types.h" +#include "base/esp_lcd_vendor_types.h" #include "base/esp_lcd_spd2010.h" /** diff --git a/src/lcd/ST7262.cpp b/src/lcd/ST7262.cpp index c0b7e071..766a32d0 100644 --- a/src/lcd/ST7262.cpp +++ b/src/lcd/ST7262.cpp @@ -52,6 +52,7 @@ bool ESP_PanelLcd_ST7262::init(void) { ESP_PANEL_ENABLE_TAG_DEBUG_LOG(); + /* Initialize RST pin */ if (panel_config.reset_gpio_num >= 0) { gpio_config_t gpio_conf = { .pin_bit_mask = BIT64(panel_config.reset_gpio_num), @@ -62,6 +63,11 @@ bool ESP_PanelLcd_ST7262::init(void) }; ESP_PANEL_CHECK_ERR_RET(gpio_config(&gpio_conf), false, "`Config RST gpio failed"); } + + /* Load RGB configurations from bus to vendor configurations */ + ESP_PANEL_CHECK_FALSE_RET(loadVendorConfigFromBus(), false, "Load vendor config from bus failed"); + + /* Create panel handle */ ESP_PANEL_CHECK_ERR_RET(esp_lcd_new_rgb_panel(vendor_config.rgb_config, &handle), false, "Create panel failed"); ESP_LOGD(TAG, "LCD panel @%p created", handle); diff --git a/src/lcd/ST7701.cpp b/src/lcd/ST7701.cpp index c01e43c1..a75d4adc 100644 --- a/src/lcd/ST7701.cpp +++ b/src/lcd/ST7701.cpp @@ -42,7 +42,16 @@ bool ESP_PanelLcd_ST7701::init(void) { ESP_PANEL_CHECK_NULL_RET(bus, false, "Invalid bus"); - ESP_PANEL_CHECK_ERR_RET(esp_lcd_new_panel_st7701(bus->getHandle(), &panel_config, &handle), false, "Create panel failed"); + /* Load RGB configurations from bus to vendor configurations */ + ESP_PANEL_CHECK_FALSE_RET(loadVendorConfigFromBus(), false, "Load vendor config from bus failed"); + + /* Create panel handle */ + ESP_PANEL_CHECK_ERR_RET(esp_lcd_new_panel_st7701(bus->getPanelIO_Handle(), &panel_config, &handle), false, "Create panel failed"); + + // Delete panel io if enable `auto_del_panel_io` or `enable_io_multiplex` flag + if (((esp_lcd_panel_vendor_config_t *)panel_config.vendor_config)->flags.auto_del_panel_io) { + ESP_PANEL_CHECK_FALSE_RET(bus->delSkipPanelIO(), false, "Delete panel io failed"); + } return true; } diff --git a/src/lcd/ST7701.h b/src/lcd/ST7701.h index 526c567c..b51fb025 100644 --- a/src/lcd/ST7701.h +++ b/src/lcd/ST7701.h @@ -9,7 +9,7 @@ #if SOC_LCD_RGB_SUPPORTED #include "ESP_PanelLcd.h" -#include "base/esp_lcd_custom_types.h" +#include "base/esp_lcd_vendor_types.h" #include "base/esp_lcd_st7701.h" /** diff --git a/src/lcd/ST7789.cpp b/src/lcd/ST7789.cpp index a28afecb..fd4980e1 100644 --- a/src/lcd/ST7789.cpp +++ b/src/lcd/ST7789.cpp @@ -39,7 +39,7 @@ bool ESP_PanelLcd_ST7789::init(void) { ESP_PANEL_CHECK_NULL_RET(bus, false, "Invalid bus"); - ESP_PANEL_CHECK_ERR_RET(esp_lcd_new_panel_st7789(bus->getHandle(), &panel_config, &handle), false, "Create panel failed"); + ESP_PANEL_CHECK_ERR_RET(esp_lcd_new_panel_st7789(bus->getPanelIO_Handle(), &panel_config, &handle), false, "Create panel failed"); return true; } diff --git a/src/lcd/ST7789.h b/src/lcd/ST7789.h index 78aadebd..7ca987ec 100644 --- a/src/lcd/ST7789.h +++ b/src/lcd/ST7789.h @@ -7,7 +7,7 @@ #pragma once #include "ESP_PanelLcd.h" -#include "base/esp_lcd_custom_types.h" +#include "base/esp_lcd_vendor_types.h" #include "base/esp_lcd_st7789.h" /** diff --git a/src/lcd/ST77916.cpp b/src/lcd/ST77916.cpp index b2b88f72..7cfd2936 100644 --- a/src/lcd/ST77916.cpp +++ b/src/lcd/ST77916.cpp @@ -39,7 +39,7 @@ bool ESP_PanelLcd_ST77916::init(void) { ESP_PANEL_CHECK_NULL_RET(bus, false, "Invalid bus"); - ESP_PANEL_CHECK_ERR_RET(esp_lcd_new_panel_st77916(bus->getHandle(), &panel_config, &handle), false, "Create panel failed"); + ESP_PANEL_CHECK_ERR_RET(esp_lcd_new_panel_st77916(bus->getPanelIO_Handle(), &panel_config, &handle), false, "Create panel failed"); return true; } diff --git a/src/lcd/ST77916.h b/src/lcd/ST77916.h index 2149192b..906f1f09 100644 --- a/src/lcd/ST77916.h +++ b/src/lcd/ST77916.h @@ -7,7 +7,7 @@ #pragma once #include "ESP_PanelLcd.h" -#include "base/esp_lcd_custom_types.h" +#include "base/esp_lcd_vendor_types.h" #include "base/esp_lcd_st77916.h" /** diff --git a/src/lcd/ST77922.cpp b/src/lcd/ST77922.cpp index e775ac62..a99a1140 100644 --- a/src/lcd/ST77922.cpp +++ b/src/lcd/ST77922.cpp @@ -41,7 +41,7 @@ bool ESP_PanelLcd_ST77922::init(void) { ESP_PANEL_CHECK_NULL_RET(bus, false, "Invalid bus"); - ESP_PANEL_CHECK_ERR_RET(esp_lcd_new_panel_st77922(bus->getHandle(), &panel_config, &handle), false, "Create panel failed"); + ESP_PANEL_CHECK_ERR_RET(esp_lcd_new_panel_st77922(bus->getPanelIO_Handle(), &panel_config, &handle), false, "Create panel failed"); return true; } diff --git a/src/lcd/ST77922.h b/src/lcd/ST77922.h index 893806bf..b839abec 100644 --- a/src/lcd/ST77922.h +++ b/src/lcd/ST77922.h @@ -7,7 +7,7 @@ #pragma once #include "ESP_PanelLcd.h" -#include "base/esp_lcd_custom_types.h" +#include "base/esp_lcd_vendor_types.h" #include "base/esp_lcd_st77922.h" /** diff --git a/src/lcd/ST7796.cpp b/src/lcd/ST7796.cpp index abff96f6..67805379 100644 --- a/src/lcd/ST7796.cpp +++ b/src/lcd/ST7796.cpp @@ -39,7 +39,7 @@ bool ESP_PanelLcd_ST7796::init(void) { ESP_PANEL_CHECK_NULL_RET(bus, false, "Invalid bus"); - ESP_PANEL_CHECK_ERR_RET(esp_lcd_new_panel_st7796(bus->getHandle(), &panel_config, &handle), false, "Create panel failed"); + ESP_PANEL_CHECK_ERR_RET(esp_lcd_new_panel_st7796(bus->getPanelIO_Handle(), &panel_config, &handle), false, "Create panel failed"); return true; } diff --git a/src/lcd/ST7796.h b/src/lcd/ST7796.h index d4341cb2..c6b54735 100644 --- a/src/lcd/ST7796.h +++ b/src/lcd/ST7796.h @@ -8,7 +8,7 @@ #include "ESP_PanelLcd.h" #include "base/esp_lcd_st7796.h" -#include "base/esp_lcd_custom_types.h" +#include "base/esp_lcd_vendor_types.h" /** * @brief ST7796 LCD device object class diff --git a/src/lcd/base/esp_lcd_ek79007.c b/src/lcd/base/esp_lcd_ek79007.c new file mode 100644 index 00000000..be96d391 --- /dev/null +++ b/src/lcd/base/esp_lcd_ek79007.c @@ -0,0 +1,284 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "soc/soc_caps.h" + +#if SOC_MIPI_DSI_SUPPORTED +#include "ESP_PanelLog.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "driver/gpio.h" +#include "esp_check.h" +#include "esp_lcd_panel_commands.h" +#include "esp_lcd_panel_interface.h" +#include "esp_lcd_panel_io.h" +#include "esp_lcd_mipi_dsi.h" +#include "esp_lcd_panel_vendor.h" +#include "esp_log.h" +#include "esp_lcd_ek79007.h" + +#include "esp_lcd_vendor_types.h" + +#define EK79007_PAD_CONTROL (0xB2) +#define EK79007_DSI_2_LANE (0x10) +#define EK79007_DSI_4_LANE (0x00) + +#define EK79007_CMD_SHLR_BIT (1ULL << 0) +#define EK79007_CMD_UPDN_BIT (1ULL << 1) +#define EK79007_MDCTL_VALUE_DEFAULT (0x01) + +typedef struct { + esp_lcd_panel_io_handle_t io; + int reset_gpio_num; + uint8_t madctl_val; // save current value of LCD_CMD_MADCTL register + const esp_lcd_panel_vendor_init_cmd_t *init_cmds; + uint16_t init_cmds_size; + uint8_t lane_num; + struct { + unsigned int reset_level: 1; + } flags; + // To save the original functions of MIPI DPI panel + esp_err_t (*del)(esp_lcd_panel_t *panel); + esp_err_t (*init)(esp_lcd_panel_t *panel); +} ek79007_panel_t; + +static const char *TAG = "ek79007"; + +static esp_err_t panel_ek79007_send_init_cmds(ek79007_panel_t *ek79007); + +static esp_err_t panel_ek79007_del(esp_lcd_panel_t *panel); +static esp_err_t panel_ek79007_init(esp_lcd_panel_t *panel); +static esp_err_t panel_ek79007_reset(esp_lcd_panel_t *panel); +static esp_err_t panel_ek79007_mirror(esp_lcd_panel_t *panel, bool mirror_x, bool mirror_y); +static esp_err_t panel_ek79007_invert_color(esp_lcd_panel_t *panel, bool invert_color_data); + +esp_err_t esp_lcd_new_panel_ek79007(const esp_lcd_panel_io_handle_t io, const esp_lcd_panel_dev_config_t *panel_dev_config, + esp_lcd_panel_handle_t *ret_panel) +{ + ESP_PANEL_ENABLE_TAG_DEBUG_LOG(); + + ESP_LOGI(TAG, "version: %d.%d.%d", ESP_LCD_EK79007_VER_MAJOR, ESP_LCD_EK79007_VER_MINOR, + ESP_LCD_EK79007_VER_PATCH); + ESP_RETURN_ON_FALSE(io && panel_dev_config && ret_panel, ESP_ERR_INVALID_ARG, TAG, "invalid arguments"); + esp_lcd_panel_vendor_config_t *vendor_config = (esp_lcd_panel_vendor_config_t *)panel_dev_config->vendor_config; + ESP_RETURN_ON_FALSE(vendor_config && vendor_config->mipi_config.dpi_config && vendor_config->mipi_config.dsi_bus, ESP_ERR_INVALID_ARG, TAG, + "invalid vendor config"); + + esp_err_t ret = ESP_OK; + ek79007_panel_t *ek79007 = (ek79007_panel_t *)calloc(1, sizeof(ek79007_panel_t)); + ESP_RETURN_ON_FALSE(ek79007, ESP_ERR_NO_MEM, TAG, "no mem for ek79007 panel"); + + if (panel_dev_config->reset_gpio_num >= 0) { + gpio_config_t io_conf = { + .mode = GPIO_MODE_OUTPUT, + .pin_bit_mask = 1ULL << panel_dev_config->reset_gpio_num, + }; + ESP_GOTO_ON_ERROR(gpio_config(&io_conf), err, TAG, "configure GPIO for RST line failed"); + } + + ek79007->io = io; + ek79007->init_cmds = vendor_config->init_cmds; + ek79007->init_cmds_size = vendor_config->init_cmds_size; + ek79007->lane_num = vendor_config->mipi_config.lane_num; + ek79007->reset_gpio_num = panel_dev_config->reset_gpio_num; + ek79007->flags.reset_level = panel_dev_config->flags.reset_active_high; + ek79007->madctl_val = EK79007_MDCTL_VALUE_DEFAULT; + + // Create MIPI DPI panel + ESP_GOTO_ON_ERROR(esp_lcd_new_panel_dpi(vendor_config->mipi_config.dsi_bus, vendor_config->mipi_config.dpi_config, ret_panel), err, TAG, + "create MIPI DPI panel failed"); + ESP_LOGD(TAG, "new MIPI DPI panel @%p", *ret_panel); + + // Save the original functions of MIPI DPI panel + ek79007->del = (*ret_panel)->del; + ek79007->init = (*ret_panel)->init; + // Overwrite the functions of MIPI DPI panel + (*ret_panel)->del = panel_ek79007_del; + (*ret_panel)->init = panel_ek79007_init; + (*ret_panel)->reset = panel_ek79007_reset; + (*ret_panel)->mirror = panel_ek79007_mirror; + (*ret_panel)->invert_color = panel_ek79007_invert_color; + (*ret_panel)->user_data = ek79007; + ESP_LOGD(TAG, "new ek79007 panel @%p", ek79007); + + return ESP_OK; + +err: + if (ek79007) { + if (panel_dev_config->reset_gpio_num >= 0) { + gpio_reset_pin(panel_dev_config->reset_gpio_num); + } + free(ek79007); + } + return ret; +} + +static const esp_lcd_panel_vendor_init_cmd_t vendor_specific_init_default[] = { +// {cmd, { data }, data_size, delay_ms} + {0x80, (uint8_t []){0x8B}, 1, 0}, + {0x81, (uint8_t []){0x78}, 1, 0}, + {0x82, (uint8_t []){0x84}, 1, 0}, + {0x83, (uint8_t []){0x88}, 1, 0}, + {0x84, (uint8_t []){0xA8}, 1, 0}, + {0x85, (uint8_t []){0xE3}, 1, 0}, + {0x86, (uint8_t []){0x88}, 1, 0}, + {0x11, (uint8_t []){0x00}, 0, 120}, +}; + +static esp_err_t panel_ek79007_send_init_cmds(ek79007_panel_t *ek79007) +{ + esp_lcd_panel_io_handle_t io = ek79007->io; + const esp_lcd_panel_vendor_init_cmd_t *init_cmds = NULL; + uint16_t init_cmds_size = 0; + uint8_t lane_command = EK79007_DSI_2_LANE; + bool is_cmd_overwritten = false; + + switch (ek79007->lane_num) { + case 0: + case 2: + lane_command = EK79007_DSI_2_LANE; + break; + case 4: + lane_command = EK79007_DSI_4_LANE; + break; + default: + ESP_LOGE(TAG, "Invalid lane number %d", ek79007->lane_num); + return ESP_ERR_INVALID_ARG; + } + ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, EK79007_PAD_CONTROL, (uint8_t[]) { + lane_command, + }, 1), TAG, "send command failed"); + + // vendor specific initialization, it can be different between manufacturers + // should consult the LCD supplier for initialization sequence code + if (ek79007->init_cmds) { + init_cmds = ek79007->init_cmds; + init_cmds_size = ek79007->init_cmds_size; + } else { + init_cmds = vendor_specific_init_default; + init_cmds_size = sizeof(vendor_specific_init_default) / sizeof(esp_lcd_panel_vendor_init_cmd_t); + } + + for (int i = 0; i < init_cmds_size; i++) { + // Check if the command has been used or conflicts with the internal + if (init_cmds[i].data_bytes > 0) { + switch (init_cmds[i].cmd) { + case LCD_CMD_MADCTL: + is_cmd_overwritten = true; + ek79007->madctl_val = ((uint8_t *)init_cmds[i].data)[0]; + break; + default: + is_cmd_overwritten = false; + break; + } + + if (is_cmd_overwritten) { + is_cmd_overwritten = false; + ESP_LOGW(TAG, "The %02Xh command has been used and will be overwritten by external initialization sequence", + init_cmds[i].cmd); + } + } + + // Send command + ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, init_cmds[i].cmd, init_cmds[i].data, init_cmds[i].data_bytes), TAG, "send command failed"); + vTaskDelay(pdMS_TO_TICKS(init_cmds[i].delay_ms)); + } + + ESP_LOGD(TAG, "send init commands success"); + + return ESP_OK; +} + +static esp_err_t panel_ek79007_del(esp_lcd_panel_t *panel) +{ + ek79007_panel_t *ek79007 = (ek79007_panel_t *)panel->user_data; + + if (ek79007->reset_gpio_num >= 0) { + gpio_reset_pin(ek79007->reset_gpio_num); + } + // Delete MIPI DPI panel + ek79007->del(panel); + ESP_LOGD(TAG, "del ek79007 panel @%p", ek79007); + free(ek79007); + + return ESP_OK; +} + +static esp_err_t panel_ek79007_init(esp_lcd_panel_t *panel) +{ + ek79007_panel_t *ek79007 = (ek79007_panel_t *)panel->user_data; + + ESP_RETURN_ON_ERROR(panel_ek79007_send_init_cmds(ek79007), TAG, "send init commands failed"); + ESP_RETURN_ON_ERROR(ek79007->init(panel), TAG, "init MIPI DPI panel failed"); + + return ESP_OK; +} + +static esp_err_t panel_ek79007_reset(esp_lcd_panel_t *panel) +{ + ek79007_panel_t *ek79007 = (ek79007_panel_t *)panel->user_data; + esp_lcd_panel_io_handle_t io = ek79007->io; + + // Perform hardware reset + if (ek79007->reset_gpio_num >= 0) { + gpio_set_level(ek79007->reset_gpio_num, ek79007->flags.reset_level); + vTaskDelay(pdMS_TO_TICKS(10)); + gpio_set_level(ek79007->reset_gpio_num, !ek79007->flags.reset_level); + vTaskDelay(pdMS_TO_TICKS(20)); + } else if (io) { // Perform software reset + ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, LCD_CMD_SWRESET, NULL, 0), TAG, "send command failed"); + vTaskDelay(pdMS_TO_TICKS(20)); + } + + return ESP_OK; +} + +static esp_err_t panel_ek79007_mirror(esp_lcd_panel_t *panel, bool mirror_x, bool mirror_y) +{ + ek79007_panel_t *ek79007 = (ek79007_panel_t *)panel->user_data; + esp_lcd_panel_io_handle_t io = ek79007->io; + uint8_t madctl_val = ek79007->madctl_val; + + ESP_RETURN_ON_FALSE(io, ESP_ERR_INVALID_STATE, TAG, "invalid panel IO"); + + // Control mirror through LCD command + if (mirror_x) { + madctl_val |= EK79007_CMD_SHLR_BIT; + } else { + madctl_val &= ~EK79007_CMD_SHLR_BIT; + } + if (mirror_y) { + madctl_val |= EK79007_CMD_UPDN_BIT; + } else { + madctl_val &= ~EK79007_CMD_UPDN_BIT; + } + + ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, LCD_CMD_MADCTL, (uint8_t []) { + madctl_val + }, 1), TAG, "send command failed"); + ek79007->madctl_val = madctl_val; + + return ESP_OK; +} + +static esp_err_t panel_ek79007_invert_color(esp_lcd_panel_t *panel, bool invert_color_data) +{ + ek79007_panel_t *ek79007 = (ek79007_panel_t *)panel->user_data; + esp_lcd_panel_io_handle_t io = ek79007->io; + uint8_t command = 0; + + ESP_RETURN_ON_FALSE(io, ESP_ERR_INVALID_STATE, TAG, "invalid panel IO"); + + if (invert_color_data) { + command = LCD_CMD_INVON; + } else { + command = LCD_CMD_INVOFF; + } + ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, command, NULL, 0), TAG, "send command failed"); + + return ESP_OK; +} +#endif /* SOC_MIPI_DSI_SUPPORTED */ diff --git a/src/lcd/base/esp_lcd_ek79007.h b/src/lcd/base/esp_lcd_ek79007.h new file mode 100644 index 00000000..b367b991 --- /dev/null +++ b/src/lcd/base/esp_lcd_ek79007.h @@ -0,0 +1,93 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "soc/soc_caps.h" + +#if SOC_MIPI_DSI_SUPPORTED +#include +#include "esp_lcd_panel_vendor.h" +#include "esp_lcd_mipi_dsi.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ESP_LCD_EK79007_VER_MAJOR (1) +#define ESP_LCD_EK79007_VER_MINOR (0) +#define ESP_LCD_EK79007_VER_PATCH (0) + +/** + * @brief Create LCD panel for model EK79007 + * + * @note Vendor specific initialization can be different between manufacturers, should consult the LCD supplier for initialization sequence code. + * + * @param[in] io LCD panel IO handle + * @param[in] panel_dev_config General panel device configuration + * @param[out] ret_panel Returned LCD panel handle + * @return + * - ESP_ERR_INVALID_ARG if parameter is invalid + * - ESP_OK on success + * - Otherwise on fail + */ +esp_err_t esp_lcd_new_panel_ek79007(const esp_lcd_panel_io_handle_t io, const esp_lcd_panel_dev_config_t *panel_dev_config, + esp_lcd_panel_handle_t *ret_panel); + +/** + * @brief MIPI DSI bus configuration structure + * + */ +#define EK79007_PANEL_BUS_DSI_2CH_CONFIG() \ + { \ + .bus_id = 0, \ + .num_data_lanes = 2, \ + .phy_clk_src = MIPI_DSI_PHY_CLK_SRC_DEFAULT, \ + .lane_bit_rate_mbps = 1000, \ + } + +/** + * @brief MIPI DBI panel IO configuration structure + * + */ +#define EK79007_PANEL_IO_DBI_CONFIG() \ + { \ + .virtual_channel = 0, \ + .lcd_cmd_bits = 8, \ + .lcd_param_bits = 8, \ + } + +/** + * @brief MIPI DPI configuration structure + * + * @note refresh_rate = (dpi_clock_freq_mhz * 1000000) / (h_res + hsync_pulse_width + hsync_back_porch + hsync_front_porch) + * / (v_res + vsync_pulse_width + vsync_back_porch + vsync_front_porch) + * + */ +#define EK79007_1024_600_PANEL_60HZ_CONFIG(px_format) \ + { \ + .dpi_clk_src = MIPI_DSI_DPI_CLK_SRC_DEFAULT, \ + .dpi_clock_freq_mhz = 52, \ + .virtual_channel = 0, \ + .pixel_format = px_format, \ + .num_fbs = 1, \ + .video_timing = { \ + .h_size = 1024, \ + .v_size = 600, \ + .hsync_back_porch = 160, \ + .hsync_pulse_width = 10, \ + .hsync_front_porch = 160, \ + .vsync_back_porch = 23, \ + .vsync_pulse_width = 1, \ + .vsync_front_porch = 12, \ + }, \ + .flags.use_dma2d = true, \ + } +#endif /* SOC_MIPI_DSI_SUPPORTED */ + +#ifdef __cplusplus +} +#endif diff --git a/src/lcd/base/esp_lcd_gc9503.c b/src/lcd/base/esp_lcd_gc9503.c index ad2c23ae..25046ce4 100644 --- a/src/lcd/base/esp_lcd_gc9503.c +++ b/src/lcd/base/esp_lcd_gc9503.c @@ -19,7 +19,7 @@ #include "esp_lcd_panel_vendor.h" #include "esp_log.h" -#include "esp_lcd_custom_types.h" +#include "esp_lcd_vendor_types.h" #include "esp_lcd_gc9503.h" #define GC9503_CMD_MADCTL (0xB1) // Memory data access control diff --git a/src/lcd/base/esp_lcd_gc9a01.c b/src/lcd/base/esp_lcd_gc9a01.c index 2d71b6f1..650985da 100644 --- a/src/lcd/base/esp_lcd_gc9a01.c +++ b/src/lcd/base/esp_lcd_gc9a01.c @@ -5,7 +5,7 @@ */ #include "ESP_PanelLog.h" -#include "esp_lcd_custom_types.h" +#include "esp_lcd_vendor_types.h" #include #include diff --git a/src/lcd/base/esp_lcd_gc9b71.c b/src/lcd/base/esp_lcd_gc9b71.c index 4d2e8388..c7dcde4c 100644 --- a/src/lcd/base/esp_lcd_gc9b71.c +++ b/src/lcd/base/esp_lcd_gc9b71.c @@ -19,7 +19,7 @@ #include "esp_lcd_panel_commands.h" #include "esp_log.h" -#include "esp_lcd_custom_types.h" +#include "esp_lcd_vendor_types.h" #include "esp_lcd_gc9b71.h" #define LCD_OPCODE_WRITE_CMD (0x02ULL) diff --git a/src/lcd/base/esp_lcd_ili9341.c b/src/lcd/base/esp_lcd_ili9341.c index 05e63c39..e7ff1cd1 100644 --- a/src/lcd/base/esp_lcd_ili9341.c +++ b/src/lcd/base/esp_lcd_ili9341.c @@ -18,7 +18,7 @@ #include "esp_log.h" #include "esp_check.h" -#include "esp_lcd_custom_types.h" +#include "esp_lcd_vendor_types.h" #include "esp_lcd_ili9341.h" static const char *TAG = "ili9341"; diff --git a/src/lcd/base/esp_lcd_ili9881c.c b/src/lcd/base/esp_lcd_ili9881c.c new file mode 100644 index 00000000..bbcffb51 --- /dev/null +++ b/src/lcd/base/esp_lcd_ili9881c.c @@ -0,0 +1,583 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "soc/soc_caps.h" + +#if SOC_MIPI_DSI_SUPPORTED +#include "ESP_PanelLog.h" +#include "esp_check.h" +#include "esp_log.h" +#include "esp_lcd_panel_commands.h" +#include "esp_lcd_panel_interface.h" +#include "esp_lcd_panel_io.h" +#include "esp_lcd_mipi_dsi.h" +#include "esp_lcd_panel_vendor.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "driver/gpio.h" +#include "esp_lcd_ili9881c.h" + +#include "esp_lcd_vendor_types.h" + +#define ILI9881C_CMD_CNDBKxSEL (0xFF) +#define ILI9881C_CMD_BKxSEL_BYTE0 (0x98) +#define ILI9881C_CMD_BKxSEL_BYTE1 (0x81) +#define ILI9881C_CMD_BKxSEL_BYTE2_PAGE0 (0x00) +#define ILI9881C_CMD_BKxSEL_BYTE2_PAGE1 (0x01) +#define ILI9881C_CMD_BKxSEL_BYTE2_PAGE2 (0x02) +#define ILI9881C_CMD_BKxSEL_BYTE2_PAGE3 (0x03) +#define ILI9881C_CMD_BKxSEL_BYTE2_PAGE4 (0x04) + +#define ILI9881C_PAD_CONTROL (0xB7) +#define ILI9881C_DSI_2_LANE (0x03) +#define ILI9881C_DSI_3_4_LANE (0x02) + +#define ILI9881C_CMD_GS_BIT (1 << 0) +#define ILI9881C_CMD_SS_BIT (1 << 1) + +typedef struct { + esp_lcd_panel_io_handle_t io; + int reset_gpio_num; + uint8_t madctl_val; // save current value of LCD_CMD_MADCTL register + uint8_t colmod_val; // save surrent value of LCD_CMD_COLMOD register + const esp_lcd_panel_vendor_init_cmd_t *init_cmds; + uint16_t init_cmds_size; + uint8_t lane_num; + struct { + unsigned int reset_level: 1; + } flags; + // To save the original functions of MIPI DPI panel + esp_err_t (*del)(esp_lcd_panel_t *panel); + esp_err_t (*init)(esp_lcd_panel_t *panel); +} ili9881c_panel_t; + +static const char *TAG = "ili9881c"; + +static esp_err_t panel_ili9881c_del(esp_lcd_panel_t *panel); +static esp_err_t panel_ili9881c_init(esp_lcd_panel_t *panel); +static esp_err_t panel_ili9881c_reset(esp_lcd_panel_t *panel); +static esp_err_t panel_ili9881c_invert_color(esp_lcd_panel_t *panel, bool invert_color_data); +static esp_err_t panel_ili9881c_mirror(esp_lcd_panel_t *panel, bool mirror_x, bool mirror_y); +static esp_err_t panel_ili9881c_disp_on_off(esp_lcd_panel_t *panel, bool on_off); +static esp_err_t panel_ili9881c_sleep(esp_lcd_panel_t *panel, bool sleep); + +esp_err_t esp_lcd_new_panel_ili9881c(const esp_lcd_panel_io_handle_t io, const esp_lcd_panel_dev_config_t *panel_dev_config, + esp_lcd_panel_handle_t *ret_panel) +{ + ESP_PANEL_ENABLE_TAG_DEBUG_LOG(); + + ESP_LOGI( + TAG, "version: %d.%d.%d", ESP_LCD_ILI9881C_VER_MAJOR, ESP_LCD_ILI9881C_VER_MINOR, ESP_LCD_ILI9881C_VER_PATCH + ); + ESP_RETURN_ON_FALSE(io && panel_dev_config && ret_panel, ESP_ERR_INVALID_ARG, TAG, "invalid arguments"); + esp_lcd_panel_vendor_config_t *vendor_config = (esp_lcd_panel_vendor_config_t *)panel_dev_config->vendor_config; + ESP_RETURN_ON_FALSE( + vendor_config && vendor_config->mipi_config.dpi_config && vendor_config->mipi_config.dsi_bus, + ESP_ERR_INVALID_ARG, TAG, "invalid vendor config" + ); + + esp_err_t ret = ESP_OK; + ili9881c_panel_t *ili9881c = (ili9881c_panel_t *)calloc(1, sizeof(ili9881c_panel_t)); + ESP_RETURN_ON_FALSE(ili9881c, ESP_ERR_NO_MEM, TAG, "no mem for ili9881c panel"); + + if (panel_dev_config->reset_gpio_num >= 0) { + gpio_config_t io_conf = { + .mode = GPIO_MODE_OUTPUT, + .pin_bit_mask = 1ULL << panel_dev_config->reset_gpio_num, + }; + ESP_GOTO_ON_ERROR(gpio_config(&io_conf), err, TAG, "configure GPIO for RST line failed"); + } + + switch (panel_dev_config->rgb_ele_order) { + case LCD_RGB_ELEMENT_ORDER_RGB: + ili9881c->madctl_val = 0; + break; + case LCD_RGB_ELEMENT_ORDER_BGR: + ili9881c->madctl_val |= LCD_CMD_BGR_BIT; + break; + default: + ESP_GOTO_ON_FALSE(false, ESP_ERR_NOT_SUPPORTED, err, TAG, "unsupported color space"); + break; + } + + switch (panel_dev_config->bits_per_pixel) { + case 16: // RGB565 + ili9881c->colmod_val = 0x55; + break; + case 18: // RGB666 + ili9881c->colmod_val = 0x66; + break; + case 24: // RGB888 + ili9881c->colmod_val = 0x77; + break; + default: + ESP_GOTO_ON_FALSE(false, ESP_ERR_NOT_SUPPORTED, err, TAG, "unsupported pixel width"); + break; + } + + // The ID register is on the CMD_Page 1 + uint8_t ID1, ID2, ID3; + esp_lcd_panel_io_tx_param(io, ILI9881C_CMD_CNDBKxSEL, (uint8_t[]) { + ILI9881C_CMD_BKxSEL_BYTE0, ILI9881C_CMD_BKxSEL_BYTE1, ILI9881C_CMD_BKxSEL_BYTE2_PAGE1 + }, 3); + esp_lcd_panel_io_rx_param(io, 0x00, &ID1, 1); + esp_lcd_panel_io_rx_param(io, 0x01, &ID2, 1); + esp_lcd_panel_io_rx_param(io, 0x02, &ID3, 1); + ESP_LOGI(TAG, "ID1: 0x%x, ID2: 0x%x, ID3: 0x%x", ID1, ID2, ID3); + + ili9881c->io = io; + ili9881c->init_cmds = vendor_config->init_cmds; + ili9881c->init_cmds_size = vendor_config->init_cmds_size; + ili9881c->lane_num = vendor_config->mipi_config.lane_num; + ili9881c->reset_gpio_num = panel_dev_config->reset_gpio_num; + ili9881c->flags.reset_level = panel_dev_config->flags.reset_active_high; + + // Create MIPI DPI panel + ESP_GOTO_ON_ERROR( + esp_lcd_new_panel_dpi(vendor_config->mipi_config.dsi_bus, vendor_config->mipi_config.dpi_config, ret_panel), + err, TAG, "create MIPI DPI panel failed" + ); + ESP_LOGD(TAG, "new MIPI DPI panel @%p", *ret_panel); + + // Save the original functions of MIPI DPI panel + ili9881c->del = (*ret_panel)->del; + ili9881c->init = (*ret_panel)->init; + // Overwrite the functions of MIPI DPI panel + (*ret_panel)->del = panel_ili9881c_del; + (*ret_panel)->init = panel_ili9881c_init; + (*ret_panel)->reset = panel_ili9881c_reset; + (*ret_panel)->mirror = panel_ili9881c_mirror; + (*ret_panel)->invert_color = panel_ili9881c_invert_color; + (*ret_panel)->disp_on_off = panel_ili9881c_disp_on_off; + (*ret_panel)->disp_sleep = panel_ili9881c_sleep; + (*ret_panel)->user_data = ili9881c; + ESP_LOGD(TAG, "new ili9881c panel @%p", ili9881c); + + return ESP_OK; + +err: + if (ili9881c) { + if (panel_dev_config->reset_gpio_num >= 0) { + gpio_reset_pin(panel_dev_config->reset_gpio_num); + } + free(ili9881c); + } + return ret; +} + +static const esp_lcd_panel_vendor_init_cmd_t vendor_specific_init_default[] = { + // {cmd, { data }, data_size, delay_ms} + /**** CMD_Page 3 ****/ + {ILI9881C_CMD_CNDBKxSEL, (uint8_t []){ILI9881C_CMD_BKxSEL_BYTE0, ILI9881C_CMD_BKxSEL_BYTE1, ILI9881C_CMD_BKxSEL_BYTE2_PAGE3}, 3, 0}, + {0x01, (uint8_t []){0x00}, 1, 0}, + {0x02, (uint8_t []){0x00}, 1, 0}, + {0x03, (uint8_t []){0x53}, 1, 0}, + {0x04, (uint8_t []){0x53}, 1, 0}, + {0x05, (uint8_t []){0x13}, 1, 0}, + {0x06, (uint8_t []){0x04}, 1, 0}, + {0x07, (uint8_t []){0x02}, 1, 0}, + {0x08, (uint8_t []){0x02}, 1, 0}, + {0x09, (uint8_t []){0x00}, 1, 0}, + {0x0a, (uint8_t []){0x00}, 1, 0}, + {0x0b, (uint8_t []){0x00}, 1, 0}, + {0x0c, (uint8_t []){0x00}, 1, 0}, + {0x0d, (uint8_t []){0x00}, 1, 0}, + {0x0e, (uint8_t []){0x00}, 1, 0}, + {0x0f, (uint8_t []){0x00}, 1, 0}, + {0x10, (uint8_t []){0x00}, 1, 0}, + {0x11, (uint8_t []){0x00}, 1, 0}, + {0x12, (uint8_t []){0x00}, 1, 0}, + {0x13, (uint8_t []){0x00}, 1, 0}, + {0x14, (uint8_t []){0x00}, 1, 0}, + {0x15, (uint8_t []){0x00}, 1, 0}, + {0x16, (uint8_t []){0x00}, 1, 0}, + {0x17, (uint8_t []){0x00}, 1, 0}, + {0x18, (uint8_t []){0x00}, 1, 0}, + {0x19, (uint8_t []){0x00}, 1, 0}, + {0x1a, (uint8_t []){0x00}, 1, 0}, + {0x1b, (uint8_t []){0x00}, 1, 0}, + {0x1c, (uint8_t []){0x00}, 1, 0}, + {0x1d, (uint8_t []){0x00}, 1, 0}, + {0x1e, (uint8_t []){0xc0}, 1, 0}, + {0x1f, (uint8_t []){0x80}, 1, 0}, + {0x20, (uint8_t []){0x02}, 1, 0}, + {0x21, (uint8_t []){0x09}, 1, 0}, + {0x22, (uint8_t []){0x00}, 1, 0}, + {0x23, (uint8_t []){0x00}, 1, 0}, + {0x24, (uint8_t []){0x00}, 1, 0}, + {0x25, (uint8_t []){0x00}, 1, 0}, + {0x26, (uint8_t []){0x00}, 1, 0}, + {0x27, (uint8_t []){0x00}, 1, 0}, + {0x28, (uint8_t []){0x55}, 1, 0}, + {0x29, (uint8_t []){0x03}, 1, 0}, + {0x2a, (uint8_t []){0x00}, 1, 0}, + {0x2b, (uint8_t []){0x00}, 1, 0}, + {0x2c, (uint8_t []){0x00}, 1, 0}, + {0x2d, (uint8_t []){0x00}, 1, 0}, + {0x2e, (uint8_t []){0x00}, 1, 0}, + {0x2f, (uint8_t []){0x00}, 1, 0}, + {0x30, (uint8_t []){0x00}, 1, 0}, + {0x31, (uint8_t []){0x00}, 1, 0}, + {0x32, (uint8_t []){0x00}, 1, 0}, + {0x33, (uint8_t []){0x00}, 1, 0}, + {0x34, (uint8_t []){0x00}, 1, 0}, + {0x35, (uint8_t []){0x00}, 1, 0}, + {0x36, (uint8_t []){0x00}, 1, 0}, + {0x37, (uint8_t []){0x00}, 1, 0}, + {0x38, (uint8_t []){0x3C}, 1, 0}, + {0x39, (uint8_t []){0x00}, 1, 0}, + {0x3a, (uint8_t []){0x00}, 1, 0}, + {0x3b, (uint8_t []){0x00}, 1, 0}, + {0x3c, (uint8_t []){0x00}, 1, 0}, + {0x3d, (uint8_t []){0x00}, 1, 0}, + {0x3e, (uint8_t []){0x00}, 1, 0}, + {0x3f, (uint8_t []){0x00}, 1, 0}, + {0x40, (uint8_t []){0x00}, 1, 0}, + {0x41, (uint8_t []){0x00}, 1, 0}, + {0x42, (uint8_t []){0x00}, 1, 0}, + {0x43, (uint8_t []){0x00}, 1, 0}, + {0x44, (uint8_t []){0x00}, 1, 0}, + {0x50, (uint8_t []){0x01}, 1, 0}, + {0x51, (uint8_t []){0x23}, 1, 0}, + {0x52, (uint8_t []){0x45}, 1, 0}, + {0x53, (uint8_t []){0x67}, 1, 0}, + {0x54, (uint8_t []){0x89}, 1, 0}, + {0x55, (uint8_t []){0xab}, 1, 0}, + {0x56, (uint8_t []){0x01}, 1, 0}, + {0x57, (uint8_t []){0x23}, 1, 0}, + {0x58, (uint8_t []){0x45}, 1, 0}, + {0x59, (uint8_t []){0x67}, 1, 0}, + {0x5a, (uint8_t []){0x89}, 1, 0}, + {0x5b, (uint8_t []){0xab}, 1, 0}, + {0x5c, (uint8_t []){0xcd}, 1, 0}, + {0x5d, (uint8_t []){0xef}, 1, 0}, + {0x5e, (uint8_t []){0x01}, 1, 0}, + {0x5f, (uint8_t []){0x08}, 1, 0}, + {0x60, (uint8_t []){0x02}, 1, 0}, + {0x61, (uint8_t []){0x02}, 1, 0}, + {0x62, (uint8_t []){0x0A}, 1, 0}, + {0x63, (uint8_t []){0x15}, 1, 0}, + {0x64, (uint8_t []){0x14}, 1, 0}, + {0x65, (uint8_t []){0x02}, 1, 0}, + {0x66, (uint8_t []){0x11}, 1, 0}, + {0x67, (uint8_t []){0x10}, 1, 0}, + {0x68, (uint8_t []){0x02}, 1, 0}, + {0x69, (uint8_t []){0x0F}, 1, 0}, + {0x6a, (uint8_t []){0x0E}, 1, 0}, + {0x6b, (uint8_t []){0x02}, 1, 0}, + {0x6c, (uint8_t []){0x0D}, 1, 0}, + {0x6d, (uint8_t []){0x0C}, 1, 0}, + {0x6e, (uint8_t []){0x06}, 1, 0}, + {0x6f, (uint8_t []){0x02}, 1, 0}, + {0x70, (uint8_t []){0x02}, 1, 0}, + {0x71, (uint8_t []){0x02}, 1, 0}, + {0x72, (uint8_t []){0x02}, 1, 0}, + {0x73, (uint8_t []){0x02}, 1, 0}, + {0x74, (uint8_t []){0x02}, 1, 0}, + {0x75, (uint8_t []){0x06}, 1, 0}, + {0x76, (uint8_t []){0x02}, 1, 0}, + {0x77, (uint8_t []){0x02}, 1, 0}, + {0x78, (uint8_t []){0x0A}, 1, 0}, + {0x79, (uint8_t []){0x15}, 1, 0}, + {0x7a, (uint8_t []){0x14}, 1, 0}, + {0x7b, (uint8_t []){0x02}, 1, 0}, + {0x7c, (uint8_t []){0x10}, 1, 0}, + {0x7d, (uint8_t []){0x11}, 1, 0}, + {0x7e, (uint8_t []){0x02}, 1, 0}, + {0x7f, (uint8_t []){0x0C}, 1, 0}, + {0x80, (uint8_t []){0x0D}, 1, 0}, + {0x81, (uint8_t []){0x02}, 1, 0}, + {0x82, (uint8_t []){0x0E}, 1, 0}, + {0x83, (uint8_t []){0x0F}, 1, 0}, + {0x84, (uint8_t []){0x08}, 1, 0}, + {0x85, (uint8_t []){0x02}, 1, 0}, + {0x86, (uint8_t []){0x02}, 1, 0}, + {0x87, (uint8_t []){0x02}, 1, 0}, + {0x88, (uint8_t []){0x02}, 1, 0}, + {0x89, (uint8_t []){0x02}, 1, 0}, + {0x8A, (uint8_t []){0x02}, 1, 0}, + {ILI9881C_CMD_CNDBKxSEL, (uint8_t []){ILI9881C_CMD_BKxSEL_BYTE0, ILI9881C_CMD_BKxSEL_BYTE1, ILI9881C_CMD_BKxSEL_BYTE2_PAGE4}, 3, 0}, + {0x6C, (uint8_t []){0x15}, 1, 0}, + {0x6E, (uint8_t []){0x30}, 1, 0}, + {0x6F, (uint8_t []){0x33}, 1, 0}, + {0x8D, (uint8_t []){0x1F}, 1, 0}, + {0x87, (uint8_t []){0xBA}, 1, 0}, + {0x26, (uint8_t []){0x76}, 1, 0}, + {0xB2, (uint8_t []){0xD1}, 1, 0}, + {0x35, (uint8_t []){0x1F}, 1, 0}, + {0x33, (uint8_t []){0x14}, 1, 0}, + {0x3A, (uint8_t []){0xA9}, 1, 0}, + {0x3B, (uint8_t []){0x3D}, 1, 0}, + {0x38, (uint8_t []){0x01}, 1, 0}, + {0x39, (uint8_t []){0x00}, 1, 0}, + {ILI9881C_CMD_CNDBKxSEL, (uint8_t []){ILI9881C_CMD_BKxSEL_BYTE0, ILI9881C_CMD_BKxSEL_BYTE1, ILI9881C_CMD_BKxSEL_BYTE2_PAGE1}, 3, 0}, + {0x22, (uint8_t []){0x09}, 1, 0}, + {0x31, (uint8_t []){0x00}, 1, 0}, + {0x40, (uint8_t []){0x53}, 1, 0}, + {0x50, (uint8_t []){0xC0}, 1, 0}, + {0x51, (uint8_t []){0xC0}, 1, 0}, + {0x53, (uint8_t []){0x47}, 1, 0}, + {0x55, (uint8_t []){0x46}, 1, 0}, + {0x60, (uint8_t []){0x28}, 1, 0}, + {0x2E, (uint8_t []){0xC8}, 1, 0}, + {0xA0, (uint8_t []){0x01}, 1, 0}, + {0xA1, (uint8_t []){0x10}, 1, 0}, + {0xA2, (uint8_t []){0x1B}, 1, 0}, + {0xA3, (uint8_t []){0x0C}, 1, 0}, + {0xA4, (uint8_t []){0x14}, 1, 0}, + {0xA5, (uint8_t []){0x25}, 1, 0}, + {0xA6, (uint8_t []){0x1A}, 1, 0}, + {0xA7, (uint8_t []){0x1D}, 1, 0}, + {0xA8, (uint8_t []){0x68}, 1, 0}, + {0xA9, (uint8_t []){0x1B}, 1, 0}, + {0xAA, (uint8_t []){0x26}, 1, 0}, + {0xAB, (uint8_t []){0x5B}, 1, 0}, + {0xAC, (uint8_t []){0x1B}, 1, 0}, + {0xAD, (uint8_t []){0x17}, 1, 0}, + {0xAE, (uint8_t []){0x4F}, 1, 0}, + {0xAF, (uint8_t []){0x24}, 1, 0}, + {0xB0, (uint8_t []){0x2A}, 1, 0}, + {0xB1, (uint8_t []){0x4E}, 1, 0}, + {0xB2, (uint8_t []){0x5F}, 1, 0}, + {0xB3, (uint8_t []){0x39}, 1, 0}, + {0xC0, (uint8_t []){0x0F}, 1, 0}, + {0xC1, (uint8_t []){0x1B}, 1, 0}, + {0xC2, (uint8_t []){0x27}, 1, 0}, + {0xC3, (uint8_t []){0x16}, 1, 0}, + {0xC4, (uint8_t []){0x14}, 1, 0}, + {0xC5, (uint8_t []){0x28}, 1, 0}, + {0xC6, (uint8_t []){0x1D}, 1, 0}, + {0xC7, (uint8_t []){0x21}, 1, 0}, + {0xC8, (uint8_t []){0x6C}, 1, 0}, + {0xC9, (uint8_t []){0x1B}, 1, 0}, + {0xCA, (uint8_t []){0x26}, 1, 0}, + {0xCB, (uint8_t []){0x5B}, 1, 0}, + {0xCC, (uint8_t []){0x1B}, 1, 0}, + {0xCD, (uint8_t []){0x1B}, 1, 0}, + {0xCE, (uint8_t []){0x4F}, 1, 0}, + {0xCF, (uint8_t []){0x24}, 1, 0}, + {0xD0, (uint8_t []){0x2A}, 1, 0}, + {0xD1, (uint8_t []){0x4E}, 1, 0}, + {0xD2, (uint8_t []){0x5F}, 1, 0}, + {0xD3, (uint8_t []){0x39}, 1, 0}, + {ILI9881C_CMD_CNDBKxSEL, (uint8_t []){ILI9881C_CMD_BKxSEL_BYTE0, ILI9881C_CMD_BKxSEL_BYTE1, ILI9881C_CMD_BKxSEL_BYTE2_PAGE0}, 3, 0}, + {0x35, (uint8_t []){0x00}, 1, 0}, + {0x29, (uint8_t []){0x00}, 0, 0}, + + //============ Gamma END=========== +}; + +static esp_err_t panel_ili9881c_del(esp_lcd_panel_t *panel) +{ + ili9881c_panel_t *ili9881c = (ili9881c_panel_t *)panel->user_data; + + if (ili9881c->reset_gpio_num >= 0) { + gpio_reset_pin(ili9881c->reset_gpio_num); + } + // Delete MIPI DPI panel + ili9881c->del(panel); + free(ili9881c); + ESP_LOGD(TAG, "del ili9881c panel @%p", ili9881c); + + return ESP_OK; +} + +static esp_err_t panel_ili9881c_init(esp_lcd_panel_t *panel) +{ + ili9881c_panel_t *ili9881c = (ili9881c_panel_t *)panel->user_data; + esp_lcd_panel_io_handle_t io = ili9881c->io; + const esp_lcd_panel_vendor_init_cmd_t *init_cmds = NULL; + uint16_t init_cmds_size = 0; + uint8_t lane_command = ILI9881C_DSI_2_LANE; + bool is_command0_enable = false; + bool is_cmd_overwritten = false; + + switch (ili9881c->lane_num) { + case 0: + case 2: + lane_command = ILI9881C_DSI_2_LANE; + break; + case 3: + case 4: + lane_command = ILI9881C_DSI_3_4_LANE; + break; + default: + ESP_LOGE(TAG, "Invalid lane number %d", ili9881c->lane_num); + return ESP_ERR_INVALID_ARG; + } + + // back to CMD_Page 1 + ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, ILI9881C_CMD_CNDBKxSEL, (uint8_t[]) { + ILI9881C_CMD_BKxSEL_BYTE0, ILI9881C_CMD_BKxSEL_BYTE1, ILI9881C_CMD_BKxSEL_BYTE2_PAGE1 + }, 3), TAG, "send command failed"); + ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, ILI9881C_PAD_CONTROL, (uint8_t[]) { + lane_command, + }, 1), TAG, "send command failed"); + + // back to CMD_Page 0 + ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, ILI9881C_CMD_CNDBKxSEL, (uint8_t[]) { + ILI9881C_CMD_BKxSEL_BYTE0, ILI9881C_CMD_BKxSEL_BYTE1, ILI9881C_CMD_BKxSEL_BYTE2_PAGE0 + }, 3), TAG, "send command failed"); + // exit sleep mode + ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, LCD_CMD_SLPOUT, NULL, 0), TAG, + "io tx param failed"); + vTaskDelay(pdMS_TO_TICKS(120)); + + ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, LCD_CMD_MADCTL, (uint8_t[]) { + ili9881c->madctl_val, + }, 1), TAG, "send command failed"); + ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, LCD_CMD_COLMOD, (uint8_t[]) { + ili9881c->colmod_val, + }, 1), TAG, "send command failed"); + + // vendor specific initialization, it can be different between manufacturers + // should consult the LCD supplier for initialization sequence code + if (ili9881c->init_cmds) { + init_cmds = ili9881c->init_cmds; + init_cmds_size = ili9881c->init_cmds_size; + } else { + init_cmds = vendor_specific_init_default; + init_cmds_size = sizeof(vendor_specific_init_default) / sizeof(esp_lcd_panel_vendor_init_cmd_t); + } + + for (int i = 0; i < init_cmds_size; i++) { + // Check if the command has been used or conflicts with the internal + if (is_command0_enable && init_cmds[i].data_bytes > 0) { + switch (init_cmds[i].cmd) { + case LCD_CMD_MADCTL: + is_cmd_overwritten = true; + ili9881c->madctl_val = ((uint8_t *)init_cmds[i].data)[0]; + break; + case LCD_CMD_COLMOD: + is_cmd_overwritten = true; + ili9881c->colmod_val = ((uint8_t *)init_cmds[i].data)[0]; + break; + default: + is_cmd_overwritten = false; + break; + } + + if (is_cmd_overwritten) { + is_cmd_overwritten = false; + ESP_LOGW(TAG, "The %02Xh command has been used and will be overwritten by external initialization sequence", + init_cmds[i].cmd); + } + } + + // Send command + ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, init_cmds[i].cmd, init_cmds[i].data, init_cmds[i].data_bytes), TAG, "send command failed"); + vTaskDelay(pdMS_TO_TICKS(init_cmds[i].delay_ms)); + + if ((init_cmds[i].cmd == ILI9881C_CMD_CNDBKxSEL) && (((uint8_t *)init_cmds[i].data)[2] == ILI9881C_CMD_BKxSEL_BYTE2_PAGE0)) { + is_command0_enable = true; + } else if ((init_cmds[i].cmd == ILI9881C_CMD_CNDBKxSEL) && (((uint8_t *)init_cmds[i].data)[2] != ILI9881C_CMD_BKxSEL_BYTE2_PAGE0)) { + is_command0_enable = false; + } + } + ESP_LOGD(TAG, "send init commands success"); + + ESP_RETURN_ON_ERROR(ili9881c->init(panel), TAG, "init MIPI DPI panel failed"); + + return ESP_OK; +} + +static esp_err_t panel_ili9881c_reset(esp_lcd_panel_t *panel) +{ + ili9881c_panel_t *ili9881c = (ili9881c_panel_t *)panel->user_data; + esp_lcd_panel_io_handle_t io = ili9881c->io; + + // Perform hardware reset + if (ili9881c->reset_gpio_num >= 0) { + gpio_set_level(ili9881c->reset_gpio_num, ili9881c->flags.reset_level); + vTaskDelay(pdMS_TO_TICKS(10)); + gpio_set_level(ili9881c->reset_gpio_num, !ili9881c->flags.reset_level); + vTaskDelay(pdMS_TO_TICKS(10)); + } else if (io) { // Perform software reset + ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, LCD_CMD_SWRESET, NULL, 0), TAG, "send command failed"); + vTaskDelay(pdMS_TO_TICKS(20)); + } + + return ESP_OK; +} + +static esp_err_t panel_ili9881c_invert_color(esp_lcd_panel_t *panel, bool invert_color_data) +{ + ili9881c_panel_t *ili9881c = (ili9881c_panel_t *)panel->user_data; + esp_lcd_panel_io_handle_t io = ili9881c->io; + uint8_t command = 0; + + ESP_RETURN_ON_FALSE(io, ESP_ERR_INVALID_STATE, TAG, "invalid panel IO"); + + if (invert_color_data) { + command = LCD_CMD_INVON; + } else { + command = LCD_CMD_INVOFF; + } + ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, command, NULL, 0), TAG, "send command failed"); + + return ESP_OK; +} + +static esp_err_t panel_ili9881c_mirror(esp_lcd_panel_t *panel, bool mirror_x, bool mirror_y) +{ + ili9881c_panel_t *ili9881c = (ili9881c_panel_t *)panel->user_data; + esp_lcd_panel_io_handle_t io = ili9881c->io; + uint8_t madctl_val = ili9881c->madctl_val; + + ESP_RETURN_ON_FALSE(io, ESP_ERR_INVALID_STATE, TAG, "invalid panel IO"); + + // Control mirror through LCD command + if (mirror_x) { + madctl_val |= ILI9881C_CMD_GS_BIT; + } else { + madctl_val &= ~ILI9881C_CMD_GS_BIT; + } + if (mirror_y) { + madctl_val |= ILI9881C_CMD_SS_BIT; + } else { + madctl_val &= ~ILI9881C_CMD_SS_BIT; + } + + ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, LCD_CMD_MADCTL, (uint8_t []) { + madctl_val + }, 1), TAG, "send command failed"); + ili9881c->madctl_val = madctl_val; + + return ESP_OK; +} + +static esp_err_t panel_ili9881c_disp_on_off(esp_lcd_panel_t *panel, bool on_off) +{ + ili9881c_panel_t *ili9881c = (ili9881c_panel_t *)panel->user_data; + esp_lcd_panel_io_handle_t io = ili9881c->io; + int command = 0; + + if (on_off) { + command = LCD_CMD_DISPON; + } else { + command = LCD_CMD_DISPOFF; + } + ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, command, NULL, 0), TAG, "send command failed"); + return ESP_OK; +} + +static esp_err_t panel_ili9881c_sleep(esp_lcd_panel_t *panel, bool sleep) +{ + ili9881c_panel_t *ili9881c = (ili9881c_panel_t *)panel->user_data; + esp_lcd_panel_io_handle_t io = ili9881c->io; + int command = 0; + + if (sleep) { + command = LCD_CMD_SLPIN; + } else { + command = LCD_CMD_SLPOUT; + } + ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, command, NULL, 0), TAG, "send command failed"); + vTaskDelay(pdMS_TO_TICKS(100)); + + return ESP_OK; +} +#endif // SOC_MIPI_DSI_SUPPORTED diff --git a/src/lcd/base/esp_lcd_ili9881c.h b/src/lcd/base/esp_lcd_ili9881c.h new file mode 100644 index 00000000..f4d9ceba --- /dev/null +++ b/src/lcd/base/esp_lcd_ili9881c.h @@ -0,0 +1,99 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +/** + * @file + * @brief ESP LCD: ILI9881C + */ + +#pragma once + +#include "soc/soc_caps.h" + +#if SOC_MIPI_DSI_SUPPORTED +#include +#include "esp_lcd_panel_vendor.h" +#include "esp_lcd_mipi_dsi.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ESP_LCD_ILI9881C_VER_MAJOR (1) +#define ESP_LCD_ILI9881C_VER_MINOR (0) +#define ESP_LCD_ILI9881C_VER_PATCH (0) + +/** + * @brief Create LCD panel for model ILI9881C + * + * @note Vendor specific initialization can be different between manufacturers, should consult the LCD supplier for initialization sequence code. + * + * @param[in] io LCD panel IO handle + * @param[in] panel_dev_config General panel device configuration + * @param[out] ret_panel Returned LCD panel handle + * @return + * - ESP_ERR_INVALID_ARG if parameter is invalid + * - ESP_OK on success + * - Otherwise on fail + */ +esp_err_t esp_lcd_new_panel_ili9881c(const esp_lcd_panel_io_handle_t io, const esp_lcd_panel_dev_config_t *panel_dev_config, + esp_lcd_panel_handle_t *ret_panel); + +/** + * @brief MIPI-DSI bus configuration structure + * + */ +#define ILI9881C_PANEL_BUS_DSI_2CH_CONFIG() \ + { \ + .bus_id = 0, \ + .num_data_lanes = 2, \ + .phy_clk_src = MIPI_DSI_PHY_CLK_SRC_DEFAULT, \ + .lane_bit_rate_mbps = 1000, \ + } + +/** + * @brief MIPI-DBI panel IO configuration structure + * + */ +#define ILI9881C_PANEL_IO_DBI_CONFIG() \ + { \ + .virtual_channel = 0, \ + .lcd_cmd_bits = 8, \ + .lcd_param_bits = 8, \ + } + +/** + * @brief MIPI DPI configuration structure + * + * @note refresh_rate = (dpi_clock_freq_mhz * 1000000) / (h_res + hsync_pulse_width + hsync_back_porch + hsync_front_porch) + * / (v_res + vsync_pulse_width + vsync_back_porch + vsync_front_porch) + * + * @param[in] px_format Pixel format of the panel + * + */ +#define ILI9881C_800_1280_PANEL_60HZ_DPI_CONFIG(px_format) \ + { \ + .dpi_clk_src = MIPI_DSI_DPI_CLK_SRC_DEFAULT, \ + .dpi_clock_freq_mhz = 80, \ + .virtual_channel = 0, \ + .pixel_format = px_format, \ + .num_fbs = 1, \ + .video_timing = { \ + .h_size = 800, \ + .v_size = 1280, \ + .hsync_back_porch = 140, \ + .hsync_pulse_width = 40, \ + .hsync_front_porch = 40, \ + .vsync_back_porch = 16, \ + .vsync_pulse_width = 4, \ + .vsync_front_porch = 16, \ + }, \ + .flags.use_dma2d = true, \ + } +#endif + +#ifdef __cplusplus +} +#endif diff --git a/src/lcd/base/esp_lcd_nv3022b.c b/src/lcd/base/esp_lcd_nv3022b.c index ba9ab985..00337aa0 100644 --- a/src/lcd/base/esp_lcd_nv3022b.c +++ b/src/lcd/base/esp_lcd_nv3022b.c @@ -18,7 +18,7 @@ #include "esp_log.h" #include "esp_check.h" -#include "esp_lcd_custom_types.h" +#include "esp_lcd_vendor_types.h" #include "esp_lcd_nv3022b.h" static const char *TAG = "lcd_panel.nv3022b"; diff --git a/src/lcd/base/esp_lcd_sh8601.c b/src/lcd/base/esp_lcd_sh8601.c index 36bd73c9..1af95a8e 100644 --- a/src/lcd/base/esp_lcd_sh8601.c +++ b/src/lcd/base/esp_lcd_sh8601.c @@ -19,7 +19,7 @@ #include "esp_lcd_panel_commands.h" #include "esp_log.h" -#include "esp_lcd_custom_types.h" +#include "esp_lcd_vendor_types.h" #include "esp_lcd_sh8601.h" #define LCD_OPCODE_WRITE_CMD (0x02ULL) diff --git a/src/lcd/base/esp_lcd_spd2010.c b/src/lcd/base/esp_lcd_spd2010.c index 1b3ccf28..979a67cc 100644 --- a/src/lcd/base/esp_lcd_spd2010.c +++ b/src/lcd/base/esp_lcd_spd2010.c @@ -19,7 +19,7 @@ #include "esp_lcd_panel_commands.h" #include "esp_log.h" -#include "esp_lcd_custom_types.h" +#include "esp_lcd_vendor_types.h" #include "esp_lcd_spd2010.h" #define LCD_OPCODE_WRITE_CMD (0x02ULL) diff --git a/src/lcd/base/esp_lcd_st7701.c b/src/lcd/base/esp_lcd_st7701.c index 8f2c678a..8e921f89 100644 --- a/src/lcd/base/esp_lcd_st7701.c +++ b/src/lcd/base/esp_lcd_st7701.c @@ -19,7 +19,7 @@ #include "esp_lcd_panel_vendor.h" #include "esp_log.h" -#include "esp_lcd_custom_types.h" +#include "esp_lcd_vendor_types.h" #include "esp_lcd_st7701.h" #define ST7701_CMD_SDIR (0xC7) diff --git a/src/lcd/base/esp_lcd_st7789.c b/src/lcd/base/esp_lcd_st7789.c index 84c787c5..c4eb8276 100644 --- a/src/lcd/base/esp_lcd_st7789.c +++ b/src/lcd/base/esp_lcd_st7789.c @@ -18,7 +18,7 @@ #include "esp_log.h" #include "esp_check.h" -#include "esp_lcd_custom_types.h" +#include "esp_lcd_vendor_types.h" #include "esp_lcd_st7789.h" static const char *TAG = "st7789"; diff --git a/src/lcd/base/esp_lcd_st77916.c b/src/lcd/base/esp_lcd_st77916.c index e91cdf9f..d3082a36 100644 --- a/src/lcd/base/esp_lcd_st77916.c +++ b/src/lcd/base/esp_lcd_st77916.c @@ -19,7 +19,7 @@ #include "esp_lcd_panel_commands.h" #include "esp_log.h" -#include "esp_lcd_custom_types.h" +#include "esp_lcd_vendor_types.h" #include "esp_lcd_st77916.h" #define LCD_OPCODE_WRITE_CMD (0x02ULL) diff --git a/src/lcd/base/esp_lcd_st77922.c b/src/lcd/base/esp_lcd_st77922.c index 3d9c49b9..a0d1089a 100644 --- a/src/lcd/base/esp_lcd_st77922.c +++ b/src/lcd/base/esp_lcd_st77922.c @@ -18,7 +18,7 @@ #include "esp_lcd_panel_commands.h" #include "esp_log.h" -#include "esp_lcd_custom_types.h" +#include "esp_lcd_vendor_types.h" #include "esp_lcd_st77922.h" #define LCD_OPCODE_WRITE_CMD (0x02ULL) diff --git a/src/lcd/base/esp_lcd_st7796.c b/src/lcd/base/esp_lcd_st7796.c index 7ce75275..aac6e8f7 100644 --- a/src/lcd/base/esp_lcd_st7796.c +++ b/src/lcd/base/esp_lcd_st7796.c @@ -18,7 +18,7 @@ #include "esp_log.h" #include "esp_check.h" -#include "esp_lcd_custom_types.h" +#include "esp_lcd_vendor_types.h" #include "esp_lcd_st7796.h" static const char *TAG = "st7796"; diff --git a/src/lcd/base/esp_lcd_custom_types.h b/src/lcd/base/esp_lcd_vendor_types.h similarity index 59% rename from src/lcd/base/esp_lcd_custom_types.h rename to src/lcd/base/esp_lcd_vendor_types.h index 19342b70..78fc9047 100644 --- a/src/lcd/base/esp_lcd_custom_types.h +++ b/src/lcd/base/esp_lcd_vendor_types.h @@ -6,12 +6,14 @@ #pragma once +#include "sdkconfig.h" #include "soc/soc_caps.h" #if SOC_LCD_RGB_SUPPORTED #include "esp_lcd_panel_rgb.h" #endif -#include "soc/soc_caps.h" -#include "sdkconfig.h" +#if SOC_MIPI_DSI_SUPPORTED +#include "esp_lcd_mipi_dsi.h" +#endif #ifdef __cplusplus extern "C" { @@ -42,19 +44,32 @@ typedef struct { unsigned int init_cmds_size; /*getHandle(), &config, &handle), false, "New driver failed"); + ESP_PANEL_CHECK_ERR_RET(esp_lcd_touch_new_i2c_cst816s(bus->getPanelIO_Handle(), &config, &handle), false, "New driver failed"); return true; } diff --git a/src/touch/ESP_PanelTouch.cpp b/src/touch/ESP_PanelTouch.cpp index 64e93065..c80ea441 100644 --- a/src/touch/ESP_PanelTouch.cpp +++ b/src/touch/ESP_PanelTouch.cpp @@ -78,6 +78,12 @@ ESP_PanelTouch::ESP_PanelTouch(ESP_PanelBus *bus, const esp_lcd_touch_config_t & } } +void ESP_PanelTouch::configLevels(int reset_level, int interrupt_level) +{ + config.levels.reset = reset_level; + config.levels.interrupt = interrupt_level; +} + bool ESP_PanelTouch::attachInterruptCallback(std::function callback, void *user_data) { ESP_PANEL_CHECK_FALSE_RET((config.interrupt_callback == onTouchInterrupt), false, "Interruption is not enabled"); @@ -109,6 +115,11 @@ bool ESP_PanelTouch::del(void) ESP_PANEL_CHECK_NULL_RET(handle, false, "Invalid handle"); ESP_PANEL_CHECK_ERR_RET(esp_lcd_touch_del(handle), false, "Delete touch panel failed"); + if (_isr_sem != NULL) { + vSemaphoreDelete(_isr_sem); + _isr_sem = NULL; + } + ESP_LOGD(TAG, "Touch panel @%p deleted", handle); handle = NULL; diff --git a/src/touch/ESP_PanelTouch.h b/src/touch/ESP_PanelTouch.h index 1a8e4d7f..342eada0 100644 --- a/src/touch/ESP_PanelTouch.h +++ b/src/touch/ESP_PanelTouch.h @@ -84,6 +84,14 @@ class ESP_PanelTouch { */ virtual ~ESP_PanelTouch() = default; + /** + * @brief Configure the levels of the reset and interrupt signals + * + * @param reset_level The level of the reset signal + * @param interrupt_level The level of the interrupt signal + */ + void configLevels(int reset_level, int interrupt_level); + /** * @brief Attach a callback function, which will be called when the refreshing is finished * diff --git a/src/touch/FT5x06.cpp b/src/touch/FT5x06.cpp index 08e5431d..d0fd6464 100644 --- a/src/touch/FT5x06.cpp +++ b/src/touch/FT5x06.cpp @@ -40,7 +40,7 @@ bool ESP_PanelTouch_FT5x06::begin(void) { ESP_PANEL_CHECK_NULL_RET(bus, false, "Invalid bus"); - ESP_PANEL_CHECK_ERR_RET(esp_lcd_touch_new_i2c_ft5x06(bus->getHandle(), &config, &handle), false, "New driver failed"); + ESP_PANEL_CHECK_ERR_RET(esp_lcd_touch_new_i2c_ft5x06(bus->getPanelIO_Handle(), &config, &handle), false, "New driver failed"); return true; } diff --git a/src/touch/GT1151.cpp b/src/touch/GT1151.cpp index 09134db0..cf468b46 100644 --- a/src/touch/GT1151.cpp +++ b/src/touch/GT1151.cpp @@ -40,7 +40,7 @@ bool ESP_PanelTouch_GT1151::begin(void) { ESP_PANEL_CHECK_NULL_RET(bus, false, "Invalid bus"); - ESP_PANEL_CHECK_ERR_RET(esp_lcd_touch_new_i2c_gt1151(bus->getHandle(), &config, &handle), false, "New driver failed"); + ESP_PANEL_CHECK_ERR_RET(esp_lcd_touch_new_i2c_gt1151(bus->getPanelIO_Handle(), &config, &handle), false, "New driver failed"); return true; } diff --git a/src/touch/GT911.cpp b/src/touch/GT911.cpp index cc3a06f8..f0c6e4fb 100644 --- a/src/touch/GT911.cpp +++ b/src/touch/GT911.cpp @@ -50,7 +50,7 @@ bool ESP_PanelTouch_GT911::begin(void) config.driver_data = (void *)&tp_gt911_config; } - ESP_PANEL_CHECK_ERR_RET(esp_lcd_touch_new_i2c_gt911(bus->getHandle(), &config, &handle), false, "New driver failed"); + ESP_PANEL_CHECK_ERR_RET(esp_lcd_touch_new_i2c_gt911(bus->getPanelIO_Handle(), &config, &handle), false, "New driver failed"); return true; } diff --git a/src/touch/ST1633.cpp b/src/touch/ST1633.cpp index 3b43989a..618ea213 100644 --- a/src/touch/ST1633.cpp +++ b/src/touch/ST1633.cpp @@ -40,7 +40,7 @@ bool ESP_PanelTouch_ST1633::begin(void) { ESP_PANEL_CHECK_NULL_RET(bus, false, "Invalid bus"); - ESP_PANEL_CHECK_ERR_RET(esp_lcd_touch_new_i2c_st1633(bus->getHandle(), &config, &handle), false, "New driver failed"); + ESP_PANEL_CHECK_ERR_RET(esp_lcd_touch_new_i2c_st1633(bus->getPanelIO_Handle(), &config, &handle), false, "New driver failed"); return true; } diff --git a/src/touch/ST7123.cpp b/src/touch/ST7123.cpp index f57df649..f64e8007 100644 --- a/src/touch/ST7123.cpp +++ b/src/touch/ST7123.cpp @@ -40,7 +40,7 @@ bool ESP_PanelTouch_ST7123::begin(void) { ESP_PANEL_CHECK_NULL_RET(bus, false, "Invalid bus"); - ESP_PANEL_CHECK_ERR_RET(esp_lcd_touch_new_i2c_st7123(bus->getHandle(), &config, &handle), false, "New driver failed"); + ESP_PANEL_CHECK_ERR_RET(esp_lcd_touch_new_i2c_st7123(bus->getPanelIO_Handle(), &config, &handle), false, "New driver failed"); return true; } diff --git a/src/touch/TT21100.cpp b/src/touch/TT21100.cpp index 78dc8582..4ca5e2e3 100644 --- a/src/touch/TT21100.cpp +++ b/src/touch/TT21100.cpp @@ -40,7 +40,7 @@ bool ESP_PanelTouch_TT21100::begin(void) { ESP_PANEL_CHECK_NULL_RET(bus, false, "Invalid bus"); - ESP_PANEL_CHECK_ERR_RET(esp_lcd_touch_new_i2c_tt21100(bus->getHandle(), &config, &handle), false, "New driver failed"); + ESP_PANEL_CHECK_ERR_RET(esp_lcd_touch_new_i2c_tt21100(bus->getPanelIO_Handle(), &config, &handle), false, "New driver failed"); return true; } diff --git a/src/touch/XPT2046.cpp b/src/touch/XPT2046.cpp index e770e12b..fe2d80fd 100644 --- a/src/touch/XPT2046.cpp +++ b/src/touch/XPT2046.cpp @@ -39,7 +39,7 @@ bool ESP_PanelTouch_XPT2046::begin(void) { ESP_PANEL_CHECK_NULL_RET(bus, false, "Invalid bus"); - ESP_PANEL_CHECK_ERR_RET(esp_lcd_touch_new_spi_xpt2046(bus->getHandle(), &config, &handle), false, "New driver failed"); + ESP_PANEL_CHECK_ERR_RET(esp_lcd_touch_new_spi_xpt2046(bus->getPanelIO_Handle(), &config, &handle), false, "New driver failed"); return true; } diff --git a/src/touch/base/esp_lcd_touch_xpt2046.h b/src/touch/base/esp_lcd_touch_xpt2046.h index 9539ce0a..c0e3c12f 100644 --- a/src/touch/base/esp_lcd_touch_xpt2046.h +++ b/src/touch/base/esp_lcd_touch_xpt2046.h @@ -135,6 +135,35 @@ extern "C" { .cs_high_active = 0 \ } \ } +#elif ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5,4,0) + +/** + * @brief Communication SPI device IO structure + * + */ +#define ESP_LCD_TOUCH_IO_SPI_XPT2046_CONFIG(touch_cs) \ + { \ + .cs_gpio_num = (gpio_num_t)touch_cs, \ + .dc_gpio_num = GPIO_NUM_NC, \ + .spi_mode = 0, \ + .pclk_hz = ESP_LCD_TOUCH_SPI_CLOCK_HZ, \ + .trans_queue_depth = 3, \ + .on_color_trans_done = NULL, \ + .user_ctx = NULL, \ + .lcd_cmd_bits = 8, \ + .lcd_param_bits = 8, \ + .flags = \ + { \ + .dc_high_on_cmd = 0, \ + .dc_low_on_data = 0, \ + .dc_low_on_param = 0, \ + .octal_mode = 0, \ + .quad_mode = 0, \ + .sio_mode = 0, \ + .lsb_first = 0, \ + .cs_high_active = 0 \ + } \ + } #else /** @@ -152,6 +181,8 @@ extern "C" { .user_ctx = NULL, \ .lcd_cmd_bits = 8, \ .lcd_param_bits = 8, \ + .cs_ena_pretrans = 0, \ + .cs_ena_posttrans = 0, \ .flags = \ { \ .dc_high_on_cmd = 0, \ diff --git a/test_apps/lcd/3wire_spi_rgb/main/test_3wire_spi_rgb_lcd.cpp b/test_apps/lcd/3wire_spi_rgb/main/test_3wire_spi_rgb_lcd.cpp index 550d5ffa..c409b390 100644 --- a/test_apps/lcd/3wire_spi_rgb/main/test_3wire_spi_rgb_lcd.cpp +++ b/test_apps/lcd/3wire_spi_rgb/main/test_3wire_spi_rgb_lcd.cpp @@ -17,15 +17,16 @@ using namespace std; // *INDENT-OFF* +/* The following default configurations are for the board 'jingcai: ESP32_4848S040C_I_Y_3, ST7701' */ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// Please update the following configuration according to your LCD spec ////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#define TEST_LCD_WIDTH (800) +#define TEST_LCD_WIDTH (480) #define TEST_LCD_HEIGHT (480) // | 8-bit RGB888 | 16-bit RGB565 | #define TEST_LCD_COLOR_BITS (18) // | 24 | 16/18/24 | #define TEST_LCD_RGB_DATA_WIDTH (16) // | 8 | 16 | -#define TEST_LCD_RGB_TIMING_FREQ_HZ (16 * 1000 * 1000) +#define TEST_LCD_RGB_TIMING_FREQ_HZ (26 * 1000 * 1000) #define TEST_LCD_RGB_TIMING_HPW (10) #define TEST_LCD_RGB_TIMING_HBP (10) #define TEST_LCD_RGB_TIMING_HFP (20) @@ -55,10 +56,39 @@ const esp_lcd_panel_vendor_init_cmd_t lcd_init_cmd[] = { // {0xC1, (uint8_t []){0x0D, 0x02}, 2, 0}, // {0x29, (uint8_t []){0x00}, 0, 120}, // // or - ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xFF, {0x77, 0x01, 0x00, 0x00, 0x10}), - ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xC0, {0x3B, 0x00}), - ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xC1, {0x0D, 0x02}), - ESP_PANEL_LCD_CMD_WITH_NONE_PARAM(120, 0x29), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xFF, {0x77, 0x01, 0x00, 0x00, 0x10}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xC0, {0x3B, 0x00}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xC1, {0x0D, 0x02}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xC2, {0x31, 0x05}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xCD, {0x00}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xB0, {0x00, 0x11, 0x18, 0x0E, 0x11, 0x06, 0x07, 0x08, 0x07, 0x22, 0x04, 0x12, 0x0F, 0xAA, 0x31, 0x18}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xB1, {0x00, 0x11, 0x19, 0x0E, 0x12, 0x07, 0x08, 0x08, 0x08, 0x22, 0x04, 0x11, 0x11, 0xA9, 0x32, 0x18}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xFF, {0x77, 0x01, 0x00, 0x00, 0x11}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xB0, {0x60}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xB1, {0x32}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xB2, {0x07}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xB3, {0x80}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xB5, {0x49}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xB7, {0x85}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xB8, {0x21}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xC1, {0x78}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xC2, {0x78}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xE0, {0x00, 0x1B, 0x02}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xE1, {0x08, 0xA0, 0x00, 0x00, 0x07, 0xA0, 0x00, 0x00, 0x00, 0x44, 0x44}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xE2, {0x11, 0x11, 0x44, 0x44, 0xED, 0xA0, 0x00, 0x00, 0xEC, 0xA0, 0x00, 0x00}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xE3, {0x00, 0x00, 0x11, 0x11}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xE4, {0x44, 0x44}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xE5, {0x0A, 0xE9, 0xD8, 0xA0, 0x0C, 0xEB, 0xD8, 0xA0, 0x0E, 0xED, 0xD8, 0xA0, 0x10, 0xEF, 0xD8, 0xA0}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xE6, {0x00, 0x00, 0x11, 0x11}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xE7, {0x44, 0x44}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xE8, {0x09, 0xE8, 0xD8, 0xA0, 0x0B, 0xEA, 0xD8, 0xA0, 0x0D, 0xEC, 0xD8, 0xA0, 0x0F, 0xEE, 0xD8, 0xA0}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xEB, {0x02, 0x00, 0xE4, 0xE4, 0x88, 0x00, 0x40}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xEC, {0x3C, 0x00}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xED, {0xAB, 0x89, 0x76, 0x54, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x20, 0x45, 0x67, 0x98, 0xBA}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xFF, {0x77, 0x01, 0x00, 0x00, 0x13}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xE5, {0xE4}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xFF, {0x77, 0x01, 0x00, 0x00, 0x00}), + ESP_PANEL_LCD_CMD_WITH_NONE_PARAM(120, 0x11), }; #endif @@ -66,45 +96,44 @@ const esp_lcd_panel_vendor_init_cmd_t lcd_init_cmd[] = { //////////////////// Please update the following configuration according to your board spec //////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #define TEST_LCD_PIN_NUM_RGB_DISP (-1) -#define TEST_LCD_PIN_NUM_RGB_VSYNC (3) -#define TEST_LCD_PIN_NUM_RGB_HSYNC (46) -#define TEST_LCD_PIN_NUM_RGB_DE (17) -#define TEST_LCD_PIN_NUM_RGB_PCLK (9) +#define TEST_LCD_PIN_NUM_RGB_VSYNC (17) +#define TEST_LCD_PIN_NUM_RGB_HSYNC (16) +#define TEST_LCD_PIN_NUM_RGB_DE (18) +#define TEST_LCD_PIN_NUM_RGB_PCLK (21) // | RGB565 | RGB666 | RGB888 | // |--------|--------|--------| -#define TEST_LCD_PIN_NUM_RGB_DATA0 (10) // | B0 | B0-1 | B0-3 | -#define TEST_LCD_PIN_NUM_RGB_DATA1 (11) // | B1 | B2 | B4 | -#define TEST_LCD_PIN_NUM_RGB_DATA2 (12) // | B2 | B3 | B5 | -#define TEST_LCD_PIN_NUM_RGB_DATA3 (13) // | B3 | B4 | B6 | -#define TEST_LCD_PIN_NUM_RGB_DATA4 (14) // | B4 | B5 | B7 | -#define TEST_LCD_PIN_NUM_RGB_DATA5 (21) // | G0 | G0 | G0-2 | -#define TEST_LCD_PIN_NUM_RGB_DATA6 (47) // | G1 | G1 | G3 | -#define TEST_LCD_PIN_NUM_RGB_DATA7 (48) // | G2 | G2 | G4 | +#define TEST_LCD_PIN_NUM_RGB_DATA0 (4) // | B0 | B0-1 | B0-3 | +#define TEST_LCD_PIN_NUM_RGB_DATA1 (5) // | B1 | B2 | B4 | +#define TEST_LCD_PIN_NUM_RGB_DATA2 (6) // | B2 | B3 | B5 | +#define TEST_LCD_PIN_NUM_RGB_DATA3 (7) // | B3 | B4 | B6 | +#define TEST_LCD_PIN_NUM_RGB_DATA4 (15) // | B4 | B5 | B7 | +#define TEST_LCD_PIN_NUM_RGB_DATA5 (8) // | G0 | G0 | G0-2 | +#define TEST_LCD_PIN_NUM_RGB_DATA6 (20) // | G1 | G1 | G3 | +#define TEST_LCD_PIN_NUM_RGB_DATA7 (3) // | G2 | G2 | G4 | #if TEST_LCD_RGB_DATA_WIDTH > 8 -#define TEST_LCD_PIN_NUM_RGB_DATA8 (45) // | G3 | G3 | G5 | -#define TEST_LCD_PIN_NUM_RGB_DATA9 (38) // | G4 | G4 | G6 | -#define TEST_LCD_PIN_NUM_RGB_DATA10 (39) // | G5 | G5 | G7 | -#define TEST_LCD_PIN_NUM_RGB_DATA11 (40) // | R0 | R0-1 | R0-3 | -#define TEST_LCD_PIN_NUM_RGB_DATA12 (41) // | R1 | R2 | R4 | -#define TEST_LCD_PIN_NUM_RGB_DATA13 (42) // | R2 | R3 | R5 | -#define TEST_LCD_PIN_NUM_RGB_DATA14 (2) // | R3 | R4 | R6 | -#define TEST_LCD_PIN_NUM_RGB_DATA15 (1) // | R4 | R5 | R7 | +#define TEST_LCD_PIN_NUM_RGB_DATA8 (46) // | G3 | G3 | G5 | +#define TEST_LCD_PIN_NUM_RGB_DATA9 (9) // | G4 | G4 | G6 | +#define TEST_LCD_PIN_NUM_RGB_DATA10 (10) // | G5 | G5 | G7 | +#define TEST_LCD_PIN_NUM_RGB_DATA11 (11) // | R0 | R0-1 | R0-3 | +#define TEST_LCD_PIN_NUM_RGB_DATA12 (12) // | R1 | R2 | R4 | +#define TEST_LCD_PIN_NUM_RGB_DATA13 (13) // | R2 | R3 | R5 | +#define TEST_LCD_PIN_NUM_RGB_DATA14 (14) // | R3 | R4 | R6 | +#define TEST_LCD_PIN_NUM_RGB_DATA15 (0) // | R4 | R5 | R7 | #endif #define TEST_LCD_PIN_NUM_SPI_CS (39) #define TEST_LCD_PIN_NUM_SPI_SCK (48) #define TEST_LCD_PIN_NUM_SPI_SDA (47) #define TEST_LCD_PIN_NUM_RST (-1) // Set to -1 if not used -#define TEST_LCD_PIN_NUM_BK_LIGHT (-1) // Set to -1 if not used +#define TEST_LCD_PIN_NUM_BK_LIGHT (38) // Set to -1 if not used #define TEST_LCD_BK_LIGHT_ON_LEVEL (1) #define TEST_LCD_BK_LIGHT_OFF_LEVEL !TEST_LCD_BK_LIGHT_ON_LEVEL // *INDENT-OFF* -/* Enable or disable printing RGB refresh rate */ +/* Enable or disable printing LCD refresh rate */ #define TEST_ENABLE_PRINT_LCD_FPS (1) -/* Enable or disable the attachment of a callback function that is called after each bitmap drawing is completed */ -#define TEST_ENABLE_ATTACH_CALLBACK (1) -#define TEST_COLOR_BAR_SHOW_TIME_MS (3000) +#define TEST_PRINT_LCD_FPS_PERIOD_MS (1000) +#define TEST_COLOR_BAR_SHOW_TIME_MS (5000) static const char *TAG = "test_3wire_spi_rgb_lcd"; @@ -162,9 +191,9 @@ static shared_ptr init_panel_bus(void) } #if TEST_ENABLE_PRINT_LCD_FPS -#define TEST_LCD_FPS_COUNT_MAX (100) +#define TEST_LCD_FPS_COUNT_MAX (100) #ifndef millis -#define millis() (esp_timer_get_time() / 1000) +#define millis() (esp_timer_get_time() / 1000) #endif DRAM_ATTR int frame_count = 0; @@ -193,6 +222,10 @@ IRAM_ATTR bool onVsyncEndCallback(void *user_data) static void run_test(shared_ptr lcd) { + frame_count = 0; + fps = 0; + start_time = 0; + #if TEST_LCD_USE_EXTERNAL_CMD // Configure external initialization commands, should called before `init()` lcd->configVendorCommands(lcd_init_cmd, sizeof(lcd_init_cmd) / sizeof(lcd_init_cmd[0])); @@ -200,9 +233,7 @@ static void run_test(shared_ptr lcd) TEST_ASSERT_TRUE_MESSAGE(lcd->init(), "LCD init failed"); TEST_ASSERT_TRUE_MESSAGE(lcd->reset(), "LCD reset failed"); TEST_ASSERT_TRUE_MESSAGE(lcd->begin(), "LCD begin failed"); -#if TEST_LCD_PIN_NUM_RGB_DISP >= 0 TEST_ASSERT_TRUE_MESSAGE(lcd->displayOn(), "LCD display on failed"); -#endif #if TEST_ENABLE_PRINT_LCD_FPS TEST_ASSERT_TRUE_MESSAGE( lcd->attachRefreshFinishCallback(onVsyncEndCallback, (void *)&start_time), "Attach refresh callback failed" @@ -211,6 +242,17 @@ static void run_test(shared_ptr lcd) ESP_LOGI(TAG, "Draw color bar from top left to bottom right, the order is B - G - R"); TEST_ASSERT_TRUE_MESSAGE(lcd->colorBarTest(TEST_LCD_WIDTH, TEST_LCD_HEIGHT), "LCD color bar test failed"); + + ESP_LOGI(TAG, "Wait for %d ms to show the color bar", TEST_COLOR_BAR_SHOW_TIME_MS); +#if TEST_ENABLE_PRINT_LCD_FPS + int i = 0; + while (i++ < TEST_COLOR_BAR_SHOW_TIME_MS / TEST_PRINT_LCD_FPS_PERIOD_MS) { + ESP_LOGI(TAG, "FPS: %d", fps); + vTaskDelay(pdMS_TO_TICKS(TEST_PRINT_LCD_FPS_PERIOD_MS)); + } +#else + vTaskDelay(pdMS_TO_TICKS(TEST_COLOR_BAR_SHOW_TIME_MS)); +#endif } #define CREATE_LCD(name, panel_bus) \ diff --git a/test_apps/lcd/3wire_spi_rgb/sdkconfig.defaults b/test_apps/lcd/3wire_spi_rgb/sdkconfig.defaults index f627e6eb..c97863dd 100644 --- a/test_apps/lcd/3wire_spi_rgb/sdkconfig.defaults +++ b/test_apps/lcd/3wire_spi_rgb/sdkconfig.defaults @@ -1,7 +1,2 @@ -CONFIG_SPIRAM=y -CONFIG_SPIRAM_MODE_OCT=y -CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y -CONFIG_SPIRAM_RODATA=y -CONFIG_SPIRAM_SPEED_80M=y CONFIG_ESP_TASK_WDT_INIT=n CONFIG_FREERTOS_HZ=1000 diff --git a/test_apps/lcd/3wire_spi_rgb/sdkconfig.defaults.esp32s3 b/test_apps/lcd/3wire_spi_rgb/sdkconfig.defaults.esp32s3 new file mode 100644 index 00000000..b7977b69 --- /dev/null +++ b/test_apps/lcd/3wire_spi_rgb/sdkconfig.defaults.esp32s3 @@ -0,0 +1,10 @@ +CONFIG_SPIRAM=y +CONFIG_SPIRAM_MODE_OCT=y +CONFIG_SPIRAM_SPEED_80M=y + +# Enable the XIP-PSRAM feature, so the ext-mem cache won't be disabled when SPI1 is operating the main flash +# For v5.2 and below +CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y +CONFIG_SPIRAM_RODATA=y +# For v5.3 and above +CONFIG_SPIRAM_XIP_FROM_PSRAM=y diff --git a/test_apps/lcd/mipi_dsi/CMakeLists.txt b/test_apps/lcd/mipi_dsi/CMakeLists.txt new file mode 100644 index 00000000..0821d1fb --- /dev/null +++ b/test_apps/lcd/mipi_dsi/CMakeLists.txt @@ -0,0 +1,5 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.5) +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(mipi_dsi_lcd_test) diff --git a/test_apps/lcd/mipi_dsi/main/CMakeLists.txt b/test_apps/lcd/mipi_dsi/main/CMakeLists.txt new file mode 100644 index 00000000..c6527dc6 --- /dev/null +++ b/test_apps/lcd/mipi_dsi/main/CMakeLists.txt @@ -0,0 +1,5 @@ +idf_component_register( + SRCS "test_app_main.c" "test_mipi_dsi_lcd.cpp" + PRIV_REQUIRES esp_lcd driver esp_timer + WHOLE_ARCHIVE +) diff --git a/test_apps/lcd/mipi_dsi/main/idf_component.yml b/test_apps/lcd/mipi_dsi/main/idf_component.yml new file mode 100644 index 00000000..bbace3aa --- /dev/null +++ b/test_apps/lcd/mipi_dsi/main/idf_component.yml @@ -0,0 +1,9 @@ +## IDF Component Manager Manifest File +dependencies: + test_utils: + path: ${IDF_PATH}/tools/unit-test-app/components/test_utils + test_driver_utils: + path: ${IDF_PATH}/components/driver/test_apps/components/test_driver_utils + ESP32_Display_Panel: + version: "*" + override_path: "../../../../../ESP32_Display_Panel" diff --git a/test_apps/lcd/mipi_dsi/main/test_app_main.c b/test_apps/lcd/mipi_dsi/main/test_app_main.c new file mode 100644 index 00000000..5a550e08 --- /dev/null +++ b/test_apps/lcd/mipi_dsi/main/test_app_main.c @@ -0,0 +1,63 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: CC0-1.0 + */ +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_heap_caps.h" +#include "unity.h" +#include "unity_test_runner.h" + +// Some resources are lazy allocated in the LCD driver, the threadhold is left for that case +#define TEST_MEMORY_LEAK_THRESHOLD (-300) + +static size_t before_free_8bit; +static size_t before_free_32bit; + +static void check_leak(size_t before_free, size_t after_free, const char *type) +{ + ssize_t delta = after_free - before_free; + printf("MALLOC_CAP_%s: Before %u bytes free, After %u bytes free (delta %d)\n", type, before_free, after_free, delta); + TEST_ASSERT_MESSAGE(delta >= TEST_MEMORY_LEAK_THRESHOLD, "memory leak"); +} + +void setUp(void) +{ + before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT); + before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT); +} + +void tearDown(void) +{ + size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT); + size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT); + check_leak(before_free_8bit, after_free_8bit, "8BIT"); + check_leak(before_free_32bit, after_free_32bit, "32BIT"); +} + +void app_main(void) +{ + /** + * __ __ ______ _______ ______ _______ ______ ______ __ ______ _______ + * | \ / \| \| \| \ | \ / \ | \ | \ / \ | \ + * | $$\ / $$ \$$$$$$| $$$$$$$\\$$$$$$ | $$$$$$$\| $$$$$$\ \$$$$$$ | $$ | $$$$$$\| $$$$$$$\ + * | $$$\ / $$$ | $$ | $$__/ $$ | $$ ______ | $$ | $$| $$___\$$ | $$ | $$ | $$ \$$| $$ | $$ + * | $$$$\ $$$$ | $$ | $$ $$ | $$| \| $$ | $$ \$$ \ | $$ | $$ | $$ | $$ | $$ + * | $$\$$ $$ $$ | $$ | $$$$$$$ | $$ \$$$$$$| $$ | $$ _\$$$$$$\ | $$ | $$ | $$ __ | $$ | $$ + * | $$ \$$$| $$ _| $$_ | $$ _| $$_ | $$__/ $$| \__| $$ _| $$_ | $$_____| $$__/ \| $$__/ $$ + * | $$ \$ | $$| $$ \| $$ | $$ \ | $$ $$ \$$ $$| $$ \ | $$ \\$$ $$| $$ $$ + * \$$ \$$ \$$$$$$ \$$ \$$$$$$ \$$$$$$$ \$$$$$$ \$$$$$$ \$$$$$$$$ \$$$$$$ \$$$$$$$ + */ + printf(" __ __ ______ _______ ______ _______ ______ ______ __ ______ _______\r\n"); + printf("| \\ / \\| \\| \\| \\ | \\ / \\ | \\ | \\ / \\ | \\\r\n"); + printf("| $$\\ / $$ \\$$$$$$| $$$$$$$\\\\$$$$$$ | $$$$$$$\\| $$$$$$\\ \\$$$$$$ | $$ | $$$$$$\\| $$$$$$$\\\r\n"); + printf("| $$$\\ / $$$ | $$ | $$__/ $$ | $$ ______ | $$ | $$| $$___\\$$ | $$ | $$ | $$ \\$$| $$ | $$\r\n"); + printf("| $$$$\\ $$$$ | $$ | $$ $$ | $$| \\| $$ | $$ \\$$ \\ | $$ | $$ | $$ | $$ | $$\r\n"); + printf("| $$\\$$ $$ $$ | $$ | $$$$$$$ | $$ \\$$$$$$| $$ | $$ _\\$$$$$$\\ | $$ | $$ | $$ __ | $$ | $$\r\n"); + printf("| $$ \\$$$| $$ _| $$_ | $$ _| $$_ | $$__/ $$| \\__| $$ _| $$_ | $$_____| $$__/ \\| $$__/ $$\r\n"); + printf("| $$ \\$ | $$| $$ \\| $$ | $$ \\ | $$ $$ \\$$ $$| $$ \\ | $$ \\\\$$ $$| $$ $$\r\n"); + printf(" \\$$ \\$$ \\$$$$$$ \\$$ \\$$$$$$ \\$$$$$$$ \\$$$$$$ \\$$$$$$ \\$$$$$$$$ \\$$$$$$ \\$$$$$$$\r\n"); + unity_run_menu(); +} diff --git a/test_apps/lcd/mipi_dsi/main/test_mipi_dsi_lcd.cpp b/test_apps/lcd/mipi_dsi/main/test_mipi_dsi_lcd.cpp new file mode 100644 index 00000000..6dec2604 --- /dev/null +++ b/test_apps/lcd/mipi_dsi/main/test_mipi_dsi_lcd.cpp @@ -0,0 +1,240 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: CC0-1.0 + */ +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_heap_caps.h" +#include "esp_log.h" +#include "esp_timer.h" +#include "unity.h" +#include "unity_test_runner.h" +#include "ESP_Panel_Library.h" + +using namespace std; + +/* The following default configurations are for the board 'Espressif: ESP32-P4-Function-EV-Board, EK79007' */ +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////// Please update the following configuration according to your LCD spec ////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#define TEST_LCD_WIDTH (1024) +#define TEST_LCD_HEIGHT (600) +#define TEST_LCD_COLOR_BITS (ESP_PANEL_LCD_RGB888_COLOR_BITS_24) +#define TEST_LCD_DSI_PHY_LDO_ID (3) +#define TEST_LCD_DSI_LANE_NUM (2) +#define TEST_LCD_DSI_LANE_RATE_MBPS (1000) +#define TEST_LCD_DPI_CLK_MHZ (52) +#define TEST_LCD_DPI_COLOR_BITS (ESP_PANEL_LCD_RGB888_COLOR_BITS_24) +#define TEST_LCD_DPI_HPW (10) +#define TEST_LCD_DPI_HBP (160) +#define TEST_LCD_DPI_HFP (160) +#define TEST_LCD_DPI_VPW (1) +#define TEST_LCD_DPI_VBP (23) +#define TEST_LCD_DPI_VFP (12) +#define TEST_LCD_USE_EXTERNAL_CMD (0) +#if TEST_LCD_USE_EXTERNAL_CMD +/** + * LCD initialization commands. + * + * Vendor specific initialization can be different between manufacturers, should consult the LCD supplier for + * initialization sequence code. + * + * Please uncomment and change the following macro definitions, then use `configVendorCommands()` to pass them in the + * same format if needed. Otherwise, the LCD driver will use the default initialization sequence code. + * + * There are two formats for the sequence code: + * 1. Raw data: {command, (uint8_t []){ data0, data1, ... }, data_size, delay_ms} + * 2. Formatter: ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(delay_ms, command, { data0, data1, ... }) and + * ESP_PANEL_LCD_CMD_WITH_NONE_PARAM(delay_ms, command) + */ +const esp_lcd_panel_vendor_init_cmd_t lcd_init_cmd[] = { + // {0xFF, (uint8_t []){0x77, 0x01, 0x00, 0x00, 0x10}, 5, 0}, + // {0xC0, (uint8_t []){0x3B, 0x00}, 2, 0}, + // {0xC1, (uint8_t []){0x0D, 0x02}, 2, 0}, + // {0x29, (uint8_t []){0x00}, 0, 120}, + // // or + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xFF, {0x77, 0x01, 0x00, 0x00, 0x10}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xC0, {0x3B, 0x00}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xC1, {0x0D, 0x02}), + ESP_PANEL_LCD_CMD_WITH_NONE_PARAM(120, 0x29), +}; +#endif + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////// Please update the following configuration according to your board spec //////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#define TEST_LCD_PIN_NUM_RST (27) // Set to -1 if not used +#define TEST_LCD_PIN_NUM_BK_LIGHT (26) // Set to -1 if not used +#define TEST_LCD_BK_LIGHT_ON_LEVEL (1) +#define TEST_LCD_BK_LIGHT_OFF_LEVEL !TEST_LCD_BK_LIGHT_ON_LEVEL + +/* Enable or disable pattern test */ +#define TEST_ENABLE_PATTERN_TEST (1) +/* Enable or disable printing LCD refresh rate */ +#define TEST_ENABLE_PRINT_LCD_FPS (1) +#define TEST_PRINT_LCD_FPS_PERIOD_MS (1000) +/* Enable or disable the attachment of a callback function that is called after each bitmap drawing is completed */ +#define TEST_ENABLE_ATTACH_CALLBACK (1) +#define TEST_COLOR_BAR_SHOW_TIME_MS (5000) + +#define delay(ms) vTaskDelay(pdMS_TO_TICKS(ms)) + +static const char *TAG = "test_spi_lcd"; + +static shared_ptr init_backlight(void) +{ +#if TEST_LCD_PIN_NUM_BK_LIGHT >= 0 + ESP_LOGI(TAG, "Initialize backlight control pin and turn it on"); + shared_ptr backlight = make_shared( + TEST_LCD_PIN_NUM_BK_LIGHT, TEST_LCD_BK_LIGHT_ON_LEVEL, true + ); + TEST_ASSERT_NOT_NULL_MESSAGE(backlight, "Create backlight object failed"); + + TEST_ASSERT_TRUE_MESSAGE(backlight->begin(), "Backlight begin failed"); + TEST_ASSERT_TRUE_MESSAGE(backlight->on(), "Backlight on failed"); + + return backlight; +#else + return nullptr; +#endif +} + +static shared_ptr init_panel_bus(void) +{ + ESP_LOGI(TAG, "Create LCD bus"); + shared_ptr panel_bus = make_shared( + TEST_LCD_DSI_LANE_NUM, TEST_LCD_DSI_LANE_RATE_MBPS, + TEST_LCD_DPI_CLK_MHZ, TEST_LCD_DPI_COLOR_BITS, TEST_LCD_WIDTH, TEST_LCD_HEIGHT, + TEST_LCD_DPI_HPW, TEST_LCD_DPI_HBP, TEST_LCD_DPI_HFP, + TEST_LCD_DPI_VPW, TEST_LCD_DPI_VBP, TEST_LCD_DPI_VFP, + TEST_LCD_DSI_PHY_LDO_ID + ); + TEST_ASSERT_NOT_NULL_MESSAGE(panel_bus, "Create panel bus object failed"); + + TEST_ASSERT_TRUE_MESSAGE(panel_bus->begin(), "Panel bus begin failed"); + + return panel_bus; +} + +#if TEST_ENABLE_ATTACH_CALLBACK +IRAM_ATTR static bool onDrawBitmapFinishCallback(void *user_data) +{ + esp_rom_printf("Draw bitmap finish callback\n"); + + return false; +} +#endif + +#if TEST_ENABLE_PRINT_LCD_FPS +#define TEST_LCD_FPS_COUNT_MAX (100) +#ifndef millis +#define millis() (esp_timer_get_time() / 1000) +#endif + +DRAM_ATTR int frame_count = 0; +DRAM_ATTR int fps = 0; +DRAM_ATTR long start_time = 0; + +IRAM_ATTR bool onVsyncEndCallback(void *user_data) +{ + long frame_start_time = *(long *)user_data; + if (frame_start_time == 0) { + (*(long *)user_data) = millis(); + + return false; + } + + frame_count++; + if (frame_count >= TEST_LCD_FPS_COUNT_MAX) { + fps = TEST_LCD_FPS_COUNT_MAX * 1000 / (millis() - frame_start_time); + frame_count = 0; + (*(long *)user_data) = millis(); + } + + return false; +} +#endif + +static void run_test(shared_ptr lcd) +{ + frame_count = 0; + fps = 0; + start_time = 0; + +#if TEST_LCD_USE_EXTERNAL_CMD + // Configure external initialization commands, should called before `init()` + lcd->configVendorCommands(lcd_init_cmd, sizeof(lcd_init_cmd) / sizeof(lcd_init_cmd[0])); +#endif + TEST_ASSERT_TRUE_MESSAGE(lcd->init(), "LCD init failed"); + TEST_ASSERT_TRUE_MESSAGE(lcd->reset(), "LCD reset failed"); + TEST_ASSERT_TRUE_MESSAGE(lcd->begin(), "LCD begin failed"); + TEST_ASSERT_TRUE_MESSAGE(lcd->displayOn(), "LCD display on failed"); + +#if TEST_ENABLE_PATTERN_TEST + ESP_LOGI(TAG, "Show MIPI-DSI patterns"); + TEST_ASSERT_TRUE_MESSAGE( + lcd->showDsiPattern(ESP_PanelLcd::DsiPatternType::BAR_HORIZONTAL), "MIPI DPI bar horizontal pattern test failed" + ); + delay(1000); + TEST_ASSERT_TRUE_MESSAGE( + lcd->showDsiPattern(ESP_PanelLcd::DsiPatternType::BAR_VERTICAL), "MIPI DPI bar vertical pattern test failed" + ); + delay(1000); + TEST_ASSERT_TRUE_MESSAGE( + lcd->showDsiPattern(ESP_PanelLcd::DsiPatternType::BER_VERTICAL), "MIPI DPI ber vertical pattern test failed" + ); + delay(1000); + TEST_ASSERT_TRUE_MESSAGE( + lcd->showDsiPattern(ESP_PanelLcd::DsiPatternType::NONE), "MIPI DPI none pattern test failed" + ); +#endif +#if TEST_ENABLE_ATTACH_CALLBACK + TEST_ASSERT_TRUE_MESSAGE( + lcd->attachDrawBitmapFinishCallback(onDrawBitmapFinishCallback, nullptr), "Attach callback failed" + ); +#endif +#if TEST_ENABLE_PRINT_LCD_FPS + TEST_ASSERT_TRUE_MESSAGE( + lcd->attachRefreshFinishCallback(onVsyncEndCallback, (void *)&start_time), "Attach refresh callback failed" + ); +#endif + + ESP_LOGI(TAG, "Draw color bar from top left to bottom right, the order is B - G - R"); + TEST_ASSERT_TRUE_MESSAGE(lcd->colorBarTest(TEST_LCD_WIDTH, TEST_LCD_HEIGHT), "LCD color bar test failed"); + + ESP_LOGI(TAG, "Wait for %d ms to show the color bar", TEST_COLOR_BAR_SHOW_TIME_MS); +#if TEST_ENABLE_PRINT_LCD_FPS + int i = 0; + while (i++ < TEST_COLOR_BAR_SHOW_TIME_MS / TEST_PRINT_LCD_FPS_PERIOD_MS) { + ESP_LOGI(TAG, "FPS: %d", fps); + vTaskDelay(pdMS_TO_TICKS(TEST_PRINT_LCD_FPS_PERIOD_MS)); + } +#else + vTaskDelay(pdMS_TO_TICKS(TEST_COLOR_BAR_SHOW_TIME_MS)); +#endif +} + +#define CREATE_LCD(name, panel_bus) \ + ({ \ + ESP_LOGI(TAG, "Create LCD device: " #name); \ + shared_ptr lcd = make_shared(panel_bus, TEST_LCD_COLOR_BITS, TEST_LCD_PIN_NUM_RST); \ + TEST_ASSERT_NOT_NULL_MESSAGE(lcd, "Create LCD object failed"); \ + lcd; \ + }) +#define CREATE_TEST_CASE(name) \ + TEST_CASE("Test LCD (" #name ") to draw color bar", "[spi_lcd][" #name "]") \ + { \ + shared_ptr backlight = init_backlight(); \ + shared_ptr panel_bus = init_panel_bus(); \ + shared_ptr lcd = CREATE_LCD(name, panel_bus.get()); \ + run_test(lcd); \ + } + +/** + * Here to create test cases for different LCDs + * + */ +CREATE_TEST_CASE(EK79007) +CREATE_TEST_CASE(ILI9881C) diff --git a/test_apps/lcd/mipi_dsi/sdkconfig.defaults b/test_apps/lcd/mipi_dsi/sdkconfig.defaults new file mode 100644 index 00000000..c97863dd --- /dev/null +++ b/test_apps/lcd/mipi_dsi/sdkconfig.defaults @@ -0,0 +1,2 @@ +CONFIG_ESP_TASK_WDT_INIT=n +CONFIG_FREERTOS_HZ=1000 diff --git a/test_apps/lcd/mipi_dsi/sdkconfig.defaults.esp32p4 b/test_apps/lcd/mipi_dsi/sdkconfig.defaults.esp32p4 new file mode 100644 index 00000000..85fd77f5 --- /dev/null +++ b/test_apps/lcd/mipi_dsi/sdkconfig.defaults.esp32p4 @@ -0,0 +1,5 @@ +CONFIG_SPIRAM=y +CONFIG_SPIRAM_MODE_HEX=y +CONFIG_SPIRAM_SPEED_200M=y +CONFIG_SPIRAM_XIP_FROM_PSRAM=y +CONFIG_IDF_EXPERIMENTAL_FEATURES=y diff --git a/test_apps/lcd/qspi/main/test_qspi_lcd.cpp b/test_apps/lcd/qspi/main/test_qspi_lcd.cpp index e69d530a..a3aa45de 100644 --- a/test_apps/lcd/qspi/main/test_qspi_lcd.cpp +++ b/test_apps/lcd/qspi/main/test_qspi_lcd.cpp @@ -14,6 +14,7 @@ using namespace std; +/* The following default configurations are for the board 'Espressif: Custom, ST77922' */ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// Please update the following configuration according to your LCD spec ////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -21,7 +22,7 @@ using namespace std; #define TEST_LCD_HEIGHT (300) #define TEST_LCD_COLOR_BITS (16) #define TEST_LCD_SPI_FREQ_HZ (40 * 1000 * 1000) -#define TEST_LCD_USE_EXTERNAL_CMD (1) +#define TEST_LCD_USE_EXTERNAL_CMD (0) #if TEST_LCD_USE_EXTERNAL_CMD /** * LCD initialization commands. @@ -125,12 +126,15 @@ static void run_test(shared_ptr lcd) TEST_ASSERT_TRUE_MESSAGE(lcd->displayOn(), "LCD display on failed"); #if TEST_ENABLE_ATTACH_CALLBACK TEST_ASSERT_TRUE_MESSAGE( - lcd->attachRefreshFinishCallback(onDrawBitmapFinishCallback, nullptr), "Attach callback failed" + lcd->attachDrawBitmapFinishCallback(onDrawBitmapFinishCallback, nullptr), "Attach callback failed" ); #endif ESP_LOGI(TAG, "Draw color bar from top left to bottom right, the order is B - G - R"); TEST_ASSERT_TRUE_MESSAGE(lcd->colorBarTest(TEST_LCD_WIDTH, TEST_LCD_HEIGHT), "LCD color bar test failed"); + + ESP_LOGI(TAG, "Wait for %d ms to show the color bar", TEST_COLOR_BAR_SHOW_TIME_MS); + vTaskDelay(pdMS_TO_TICKS(TEST_COLOR_BAR_SHOW_TIME_MS)); } #define CREATE_LCD(name, panel_bus) \ diff --git a/test_apps/lcd/rgb/main/test_rgb_lcd.cpp b/test_apps/lcd/rgb/main/test_rgb_lcd.cpp index 5c837770..b34d926f 100644 --- a/test_apps/lcd/rgb/main/test_rgb_lcd.cpp +++ b/test_apps/lcd/rgb/main/test_rgb_lcd.cpp @@ -17,21 +17,22 @@ using namespace std; // *INDENT-OFF* +/* The following default configurations are for the board 'Espressif: ESP32_S3_LCD_EV_BOARD_2_V1_5, ST7262' */ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// Please update the following configuration according to your LCD spec ////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #define TEST_LCD_WIDTH (800) #define TEST_LCD_HEIGHT (480) // | 8-bit RGB888 | 16-bit RGB565 | -#define TEST_LCD_COLOR_BITS (18) // | 24 | 16/18/24 | +#define TEST_LCD_COLOR_BITS (16) // | 24 | 16/18/24 | #define TEST_LCD_RGB_DATA_WIDTH (16) // | 8 | 16 | #define TEST_LCD_RGB_TIMING_FREQ_HZ (16 * 1000 * 1000) -#define TEST_LCD_RGB_TIMING_HPW (10) -#define TEST_LCD_RGB_TIMING_HBP (10) -#define TEST_LCD_RGB_TIMING_HFP (20) -#define TEST_LCD_RGB_TIMING_VPW (10) -#define TEST_LCD_RGB_TIMING_VBP (10) -#define TEST_LCD_RGB_TIMING_VFP (10) +#define TEST_LCD_RGB_TIMING_HPW (40) +#define TEST_LCD_RGB_TIMING_HBP (40) +#define TEST_LCD_RGB_TIMING_HFP (40) +#define TEST_LCD_RGB_TIMING_VPW (23) +#define TEST_LCD_RGB_TIMING_VBP (32) +#define TEST_LCD_RGB_TIMING_VFP (13) #define TEST_LCD_RGB_BOUNCE_BUFFER_SIZE (TEST_LCD_WIDTH * 10) //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -50,8 +51,8 @@ using namespace std; #define TEST_LCD_PIN_NUM_RGB_DATA3 (13) // | B3 | B4 | B6 | #define TEST_LCD_PIN_NUM_RGB_DATA4 (14) // | B4 | B5 | B7 | #define TEST_LCD_PIN_NUM_RGB_DATA5 (21) // | G0 | G0 | G0-2 | -#define TEST_LCD_PIN_NUM_RGB_DATA6 (47) // | G1 | G1 | G3 | -#define TEST_LCD_PIN_NUM_RGB_DATA7 (48) // | G2 | G2 | G4 | +#define TEST_LCD_PIN_NUM_RGB_DATA6 (8) // | G1 | G1 | G3 | +#define TEST_LCD_PIN_NUM_RGB_DATA7 (18) // | G2 | G2 | G4 | #if TEST_LCD_RGB_DATA_WIDTH > 8 #define TEST_LCD_PIN_NUM_RGB_DATA8 (45) // | G3 | G3 | G5 | #define TEST_LCD_PIN_NUM_RGB_DATA9 (38) // | G4 | G4 | G6 | @@ -69,11 +70,12 @@ using namespace std; // *INDENT-OFF* -/* Enable or disable printing RGB refresh rate */ +/* Enable or disable printing LCD refresh rate */ #define TEST_ENABLE_PRINT_LCD_FPS (1) +#define TEST_PRINT_LCD_FPS_PERIOD_MS (1000) /* Enable or disable the attachment of a callback function that is called after each bitmap drawing is completed */ #define TEST_ENABLE_ATTACH_CALLBACK (1) -#define TEST_COLOR_BAR_SHOW_TIME_MS (3000) +#define TEST_COLOR_BAR_SHOW_TIME_MS (5000) static const char *TAG = "test_rgb_lcd"; @@ -129,9 +131,9 @@ static shared_ptr init_panel_bus(void) } #if TEST_ENABLE_PRINT_LCD_FPS -#define TEST_LCD_FPS_COUNT_MAX (100) +#define TEST_LCD_FPS_COUNT_MAX (100) #ifndef millis -#define millis() (esp_timer_get_time() / 1000) +#define millis() (esp_timer_get_time() / 1000) #endif DRAM_ATTR int frame_count = 0; @@ -156,7 +158,7 @@ IRAM_ATTR bool onVsyncEndCallback(void *user_data) return false; } -#endif +#endif /* TEST_ENABLE_PRINT_LCD_FPS */ static void run_test(shared_ptr lcd) { @@ -167,9 +169,7 @@ static void run_test(shared_ptr lcd) TEST_ASSERT_TRUE_MESSAGE(lcd->init(), "LCD init failed"); TEST_ASSERT_TRUE_MESSAGE(lcd->reset(), "LCD reset failed"); TEST_ASSERT_TRUE_MESSAGE(lcd->begin(), "LCD begin failed"); -#if TEST_LCD_PIN_NUM_RGB_DISP >= 0 TEST_ASSERT_TRUE_MESSAGE(lcd->displayOn(), "LCD display on failed"); -#endif #if TEST_ENABLE_PRINT_LCD_FPS TEST_ASSERT_TRUE_MESSAGE( lcd->attachRefreshFinishCallback(onVsyncEndCallback, (void *)&start_time), "Attach refresh callback failed" @@ -178,6 +178,17 @@ static void run_test(shared_ptr lcd) ESP_LOGI(TAG, "Draw color bar from top left to bottom right, the order is B - G - R"); TEST_ASSERT_TRUE_MESSAGE(lcd->colorBarTest(TEST_LCD_WIDTH, TEST_LCD_HEIGHT), "LCD color bar test failed"); + + ESP_LOGI(TAG, "Wait for %d ms to show the color bar", TEST_COLOR_BAR_SHOW_TIME_MS); +#if TEST_ENABLE_PRINT_LCD_FPS + int i = 0; + while (i++ < TEST_COLOR_BAR_SHOW_TIME_MS / TEST_PRINT_LCD_FPS_PERIOD_MS) { + ESP_LOGI(TAG, "FPS: %d", fps); + vTaskDelay(pdMS_TO_TICKS(TEST_PRINT_LCD_FPS_PERIOD_MS)); + } +#else + vTaskDelay(pdMS_TO_TICKS(TEST_COLOR_BAR_SHOW_TIME_MS)); +#endif } #define CREATE_LCD(name, panel_bus) \ diff --git a/test_apps/lcd/rgb/sdkconfig.defaults b/test_apps/lcd/rgb/sdkconfig.defaults index f627e6eb..c97863dd 100644 --- a/test_apps/lcd/rgb/sdkconfig.defaults +++ b/test_apps/lcd/rgb/sdkconfig.defaults @@ -1,7 +1,2 @@ -CONFIG_SPIRAM=y -CONFIG_SPIRAM_MODE_OCT=y -CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y -CONFIG_SPIRAM_RODATA=y -CONFIG_SPIRAM_SPEED_80M=y CONFIG_ESP_TASK_WDT_INIT=n CONFIG_FREERTOS_HZ=1000 diff --git a/test_apps/lcd/rgb/sdkconfig.defaults.esp32s3 b/test_apps/lcd/rgb/sdkconfig.defaults.esp32s3 new file mode 100644 index 00000000..f71f272f --- /dev/null +++ b/test_apps/lcd/rgb/sdkconfig.defaults.esp32s3 @@ -0,0 +1,16 @@ +CONFIG_SPIRAM=y +CONFIG_SPIRAM_MODE_OCT=y +CONFIG_SPIRAM_SPEED_80M=y + +CONFIG_SPIRAM=y +CONFIG_SPIRAM_MODE_OCT=y +CONFIG_SPIRAM_SPEED_80M=y +# Enable the XIP-PSRAM feature, so the ext-mem cache won't be disabled when SPI1 is operating the main flash +# For v5.2 and below +CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y +CONFIG_SPIRAM_RODATA=y +# For v5.3 and above +CONFIG_SPIRAM_XIP_FROM_PSRAM=y + +# Used in conjunction with "RGB Bounce Buffer" +CONFIG_ESP32S3_DATA_CACHE_LINE_64B=y diff --git a/test_apps/lcd/spi/main/test_spi_lcd.cpp b/test_apps/lcd/spi/main/test_spi_lcd.cpp index 61cb6454..5dd4a348 100644 --- a/test_apps/lcd/spi/main/test_spi_lcd.cpp +++ b/test_apps/lcd/spi/main/test_spi_lcd.cpp @@ -14,6 +14,7 @@ using namespace std; +/* The following default configurations are for the board 'Espressif: ESP32_S3_BOX_3, ILI9341' */ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// Please update the following configuration according to your LCD spec ////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -43,10 +44,22 @@ const esp_lcd_panel_vendor_init_cmd_t lcd_init_cmd[] = { // {0xC1, (uint8_t []){0x0D, 0x02}, 2, 0}, // {0x29, (uint8_t []){0x00}, 0, 120}, // // or - ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xFF, {0x77, 0x01, 0x00, 0x00, 0x10}), - ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xC0, {0x3B, 0x00}), - ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xC1, {0x0D, 0x02}), - ESP_PANEL_LCD_CMD_WITH_NONE_PARAM(120, 0x29), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xC8, {0xFF, 0x93, 0x42}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xC0, {0x0E, 0x0E}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xC5, {0xD0}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xC1, {0x02}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xB4, {0x02}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xE0, { + 0x00, 0x03, 0x08, 0x06, 0x13, 0x09, 0x39, 0x39, 0x48, 0x02, 0x0a, 0x08, + 0x17, 0x17, 0x0F + }), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xE1, { + 0x00, 0x28, 0x29, 0x01, 0x0d, 0x03, 0x3f, 0x33, 0x52, 0x04, 0x0f, 0x0e, + 0x37, 0x38, 0x0F + }), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xB1, {00, 0x1B}), + ESP_PANEL_LCD_CMD_WITH_8BIT_PARAM(0, 0xB7, {0x06}), + ESP_PANEL_LCD_CMD_WITH_NONE_PARAM(100, 0x11), }; #endif @@ -56,10 +69,10 @@ const esp_lcd_panel_vendor_init_cmd_t lcd_init_cmd[] = { #define TEST_LCD_PIN_NUM_SPI_CS (5) #define TEST_LCD_PIN_NUM_SPI_DC (4) #define TEST_LCD_PIN_NUM_SPI_SCK (7) -#define TEST_LCD_PIN_NUM_SPI_SDA (6) -#define TEST_LCD_PIN_NUM_SPI_SDO (-1) -#define TEST_LCD_PIN_NUM_RST (-1) // Set to -1 if not used -#define TEST_LCD_PIN_NUM_BK_LIGHT (45) // Set to -1 if not used +#define TEST_LCD_PIN_NUM_SPI_MOSI (6) +#define TEST_LCD_PIN_NUM_SPI_MISO (-1) +#define TEST_LCD_PIN_NUM_RST (48) // Set to -1 if not used +#define TEST_LCD_PIN_NUM_BK_LIGHT (47) // Set to -1 if not used #define TEST_LCD_BK_LIGHT_ON_LEVEL (1) #define TEST_LCD_BK_LIGHT_OFF_LEVEL !TEST_LCD_BK_LIGHT_ON_LEVEL @@ -92,7 +105,7 @@ static shared_ptr init_panel_bus(void) ESP_LOGI(TAG, "Create LCD bus"); shared_ptr panel_bus = make_shared( TEST_LCD_PIN_NUM_SPI_CS, TEST_LCD_PIN_NUM_SPI_DC, TEST_LCD_PIN_NUM_SPI_SCK, - TEST_LCD_PIN_NUM_SPI_SDA, TEST_LCD_PIN_NUM_SPI_SDO + TEST_LCD_PIN_NUM_SPI_MOSI, TEST_LCD_PIN_NUM_SPI_MISO ); TEST_ASSERT_NOT_NULL_MESSAGE(panel_bus, "Create panel bus object failed"); @@ -117,18 +130,25 @@ static void run_test(shared_ptr lcd) // Configure external initialization commands, should called before `init()` lcd->configVendorCommands(lcd_init_cmd, sizeof(lcd_init_cmd) / sizeof(lcd_init_cmd[0])); #endif + lcd->configColorRgbOrder(true); + lcd->configResetActiveLevel(1); TEST_ASSERT_TRUE_MESSAGE(lcd->init(), "LCD init failed"); TEST_ASSERT_TRUE_MESSAGE(lcd->reset(), "LCD reset failed"); TEST_ASSERT_TRUE_MESSAGE(lcd->begin(), "LCD begin failed"); + TEST_ASSERT_TRUE_MESSAGE(lcd->mirrorX(true), "LCD mirror X failed"); + TEST_ASSERT_TRUE_MESSAGE(lcd->mirrorY(true), "LCD mirror Y failed"); TEST_ASSERT_TRUE_MESSAGE(lcd->displayOn(), "LCD display on failed"); #if TEST_ENABLE_ATTACH_CALLBACK TEST_ASSERT_TRUE_MESSAGE( - lcd->attachRefreshFinishCallback(onDrawBitmapFinishCallback, nullptr), "Attach callback failed" + lcd->attachDrawBitmapFinishCallback(onDrawBitmapFinishCallback, nullptr), "Attach callback failed" ); #endif ESP_LOGI(TAG, "Draw color bar from top left to bottom right, the order is B - G - R"); TEST_ASSERT_TRUE_MESSAGE(lcd->colorBarTest(TEST_LCD_WIDTH, TEST_LCD_HEIGHT), "LCD color bar test failed"); + + ESP_LOGI(TAG, "Wait for %d ms to show the color bar", TEST_COLOR_BAR_SHOW_TIME_MS); + vTaskDelay(pdMS_TO_TICKS(TEST_COLOR_BAR_SHOW_TIME_MS)); } #define CREATE_LCD(name, panel_bus) \ @@ -153,6 +173,7 @@ static void run_test(shared_ptr lcd) */ CREATE_TEST_CASE(GC9A01) CREATE_TEST_CASE(GC9B71) +CREATE_TEST_CASE(ILI9341) CREATE_TEST_CASE(NV3022B) CREATE_TEST_CASE(SH8601) CREATE_TEST_CASE(SPD2010) diff --git a/test_apps/lvgl_port/main/CMakeLists.txt b/test_apps/lvgl_port/main/CMakeLists.txt index 43ee3b82..341b8146 100644 --- a/test_apps/lvgl_port/main/CMakeLists.txt +++ b/test_apps/lvgl_port/main/CMakeLists.txt @@ -1,5 +1,5 @@ idf_component_register( - SRCS "test_app_main.c" "test_lvgl_port.cpp" "lvgl_port_v8.cpp" + SRCS "test_app_main.cpp" "test_lvgl_port.cpp" "lvgl_port_v8.cpp" WHOLE_ARCHIVE ) diff --git a/test_apps/lvgl_port/main/Kconfig.projbuild b/test_apps/lvgl_port/main/Kconfig.projbuild index 7446973a..da91251b 100644 --- a/test_apps/lvgl_port/main/Kconfig.projbuild +++ b/test_apps/lvgl_port/main/Kconfig.projbuild @@ -1,8 +1,8 @@ menu "Test Configurations" choice LVGL_PORT_AVOID_TEARING_MODE_CHOICE prompt "Avoid Tearing Mode" - depends on SOC_LCD_RGB_SUPPORTED - default LVGL_PORT_AVOID_TEARING_MODE_3 + depends on SOC_LCD_RGB_SUPPORTED || SOC_MIPI_DSI_SUPPORTED + default LVGL_PORT_AVOID_TEARING_MODE_NONE config LVGL_PORT_AVOID_TEARING_MODE_NONE bool "None" diff --git a/test_apps/lvgl_port/main/lvgl_port_v8.cpp b/test_apps/lvgl_port/main/lvgl_port_v8.cpp index 9478c387..c9f0d4a2 100644 --- a/test_apps/lvgl_port/main/lvgl_port_v8.cpp +++ b/test_apps/lvgl_port/main/lvgl_port_v8.cpp @@ -6,11 +6,14 @@ #include "esp_timer.h" #include "lvgl_port_v8.h" +#define LVGL_PORT_ENABLE_ROTATION_OPTIMIZED (1) #define LVGL_PORT_BUFFER_NUM_MAX (2) static const char *TAG = "lvgl_port"; static SemaphoreHandle_t lvgl_mux = nullptr; // LVGL mutex static TaskHandle_t lvgl_task_handle = nullptr; +static esp_timer_handle_t lvgl_tick_timer = NULL; +static void *lvgl_buf[LVGL_PORT_BUFFER_NUM_MAX] = {}; #if LVGL_PORT_ROTATION_DEGREE != 0 static void *get_next_frame_buffer(ESP_PanelLcd *lcd) @@ -19,8 +22,8 @@ static void *get_next_frame_buffer(ESP_PanelLcd *lcd) static void *fbs[2] = { NULL }; if (next_fb == NULL) { - fbs[0] = lcd->getRgbBufferByIndex(0); - fbs[1] = lcd->getRgbBufferByIndex(1); + fbs[0] = lcd->getFrameBufferByIndex(0); + fbs[1] = lcd->getFrameBufferByIndex(1); next_fb = fbs[1]; } else { next_fb = (next_fb == fbs[0]) ? fbs[1] : fbs[0]; @@ -29,53 +32,167 @@ static void *get_next_frame_buffer(ESP_PanelLcd *lcd) return next_fb; } -IRAM_ATTR static void rotate_copy_pixel(const lv_color_t *from, lv_color_t *to, uint16_t x_start, uint16_t y_start, - uint16_t x_end, uint16_t y_end, uint16_t w, uint16_t h, uint16_t rotate) +__attribute__((always_inline)) +static inline void copy_pixel_8bpp(uint8_t *to, const uint8_t *from) { + *to++ = *from++; +} + +__attribute__((always_inline)) +static inline void copy_pixel_16bpp(uint8_t *to, const uint8_t *from) +{ + *(uint16_t *)to++ = *(const uint16_t *)from++; +} + +__attribute__((always_inline)) +static inline void copy_pixel_24bpp(uint8_t *to, const uint8_t *from) +{ + *to++ = *from++; + *to++ = *from++; + *to++ = *from++; +} + +#define _COPY_PIXEL(_bpp, to, from) copy_pixel_##_bpp##bpp(to, from) +#define COPY_PIXEL(_bpp, to, from) _COPY_PIXEL(_bpp, to, from) + +#define ROTATE_90_ALL_BPP() \ + { \ + to_bytes_per_line = h * to_bytes_per_piexl; \ + to_index_const = (w - x_start - 1) * to_bytes_per_line; \ + for (int from_y = y_start; from_y < y_end + 1; from_y++) { \ + from_index = from_y * from_bytes_per_line + x_start * from_bytes_per_piexl; \ + to_index = to_index_const + from_y * to_bytes_per_piexl; \ + for (int from_x = x_start; from_x < x_end + 1; from_x++) { \ + COPY_PIXEL(LV_COLOR_DEPTH, to + to_index, from + from_index); \ + from_index += from_bytes_per_piexl; \ + to_index -= to_bytes_per_line; \ + } \ + } \ + } + +/** + * @brief Optimized transpose function for RGB565 format. + * + * @note ESP32-P4 1024x600 full-screen: 738ms -> 34ms + * @note ESP32-S3 480x480 full-screen: 380ms -> 37ms + * + */ +#define ROTATE_90_OPTIMIZED_16BPP(block_w, block_h) \ + { \ + for (int i = 0; i < h; i += block_h) { \ + max_height = (i + block_h > h) ? h : (i + block_h); \ + for (int j = 0; j < w; j += block_w) { \ + max_width = (j + block_w > w) ? w : (j + block_w); \ + start_y = w - 1 - j; \ + for (int x = i; x < max_height; x++) { \ + from_next = (uint16_t *)from + x * w; \ + for (int y = j, mirrored_y = start_y; y < max_width; y += 4, mirrored_y -= 4) { \ + ((uint16_t *)to)[(mirrored_y) * h + x] = *((uint32_t *)(from_next + y)) & 0xFFFF; \ + ((uint16_t *)to)[(mirrored_y - 1) * h + x] = (*((uint32_t *)(from_next + y)) >> 16) & 0xFFFF; \ + ((uint16_t *)to)[(mirrored_y - 2) * h + x] = *((uint32_t *)(from_next + y + 2)) & 0xFFFF; \ + ((uint16_t *)to)[(mirrored_y - 3) * h + x] = (*((uint32_t *)(from_next + y + 2)) >> 16) & 0xFFFF; \ + } \ + } \ + } \ + } \ + } + +#define ROTATE_180_ALL_BPP() \ + { \ + to_bytes_per_line = w * to_bytes_per_piexl; \ + to_index_const = (h - 1) * to_bytes_per_line + (w - x_start - 1) * to_bytes_per_piexl; \ + for (int from_y = y_start; from_y < y_end + 1; from_y++) { \ + from_index = from_y * from_bytes_per_line + x_start * from_bytes_per_piexl; \ + to_index = to_index_const - from_y * to_bytes_per_line; \ + for (int from_x = x_start; from_x < x_end + 1; from_x++) { \ + COPY_PIXEL(LV_COLOR_DEPTH, to + to_index, from + from_index); \ + from_index += from_bytes_per_piexl; \ + to_index -= to_bytes_per_piexl; \ + } \ + } \ + } + +#define ROTATE_270_OPTIMIZED_16BPP(block_w, block_h) \ + { \ + for (int i = 0; i < h; i += block_h) { \ + max_height = i + block_h > h ? h : i + block_h; \ + for (int j = 0; j < w; j += block_w) { \ + max_width = j + block_w > w ? w : j + block_w; \ + for (int x = i; x < max_height; x++) { \ + from_next = (uint16_t *)from + x * w; \ + for (int y = j; y < max_width; y += 4) { \ + ((uint16_t *)to)[y * h + (h - 1 - x)] = *((uint32_t *)(from_next + y)) & 0xFFFF; \ + ((uint16_t *)to)[(y + 1) * h + (h - 1 - x)] = (*((uint32_t *)(from_next + y)) >> 16) & 0xFFFF; \ + ((uint16_t *)to)[(y + 2) * h + (h - 1 - x)] = *((uint32_t *)(from_next + y + 2)) & 0xFFFF; \ + ((uint16_t *)to)[(y + 3) * h + (h - 1 - x)] = (*((uint32_t *)(from_next + y + 2)) >> 16) & 0xFFFF; \ + } \ + } \ + } \ + } \ + } + +#define ROTATE_270_ALL_BPP() \ + { \ + to_bytes_per_line = h * to_bytes_per_piexl; \ + from_index_const = x_start * from_bytes_per_piexl; \ + to_index_const = x_start * to_bytes_per_line + (h - 1) * to_bytes_per_piexl; \ + for (int from_y = y_start; from_y < y_end + 1; from_y++) { \ + from_index = from_y * from_bytes_per_line + from_index_const; \ + to_index = to_index_const - from_y * to_bytes_per_piexl; \ + for (int from_x = x_start; from_x < x_end + 1; from_x++) { \ + COPY_PIXEL(LV_COLOR_DEPTH, to + to_index, from + from_index); \ + from_index += from_bytes_per_piexl; \ + to_index += to_bytes_per_line; \ + } \ + } \ + } + +__attribute__((always_inline)) +IRAM_ATTR static inline void rotate_copy_pixel( + const uint8_t *from, uint8_t *to, uint16_t x_start, uint16_t y_start, uint16_t x_end, uint16_t y_end, uint16_t w, + uint16_t h, uint16_t rotate +) +{ + int from_bytes_per_piexl = sizeof(lv_color_t); + int from_bytes_per_line = w * from_bytes_per_piexl; int from_index = 0; + int from_index_const = 0; + + int to_bytes_per_piexl = LV_COLOR_DEPTH >> 3; + int to_bytes_per_line; int to_index = 0; int to_index_const = 0; +#if (LV_COLOR_DEPTH == 16) && LVGL_PORT_ENABLE_ROTATION_OPTIMIZED + int max_height = 0; + int max_width = 0; + int start_y = 0; + uint16_t *from_next = NULL; +#endif + + // uint32_t time = esp_log_timestamp(); switch (rotate) { case 90: - 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; - 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; - } - } +#if (LV_COLOR_DEPTH == 16) && LVGL_PORT_ENABLE_ROTATION_OPTIMIZED + ROTATE_90_OPTIMIZED_16BPP(32, 256); +#else + ROTATE_90_ALL_BPP(); +#endif break; case 180: - to_index_const = h * w - x_start - 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 * w; - for (int from_x = x_start; from_x < x_end + 1; from_x++) { - *(to + to_index) = *(from + from_index); - from_index += 1; - to_index -= 1; - } - } + ROTATE_180_ALL_BPP(); break; case 270: - 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; - 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; - } - } +#if (LV_COLOR_DEPTH == 16) && LVGL_PORT_ENABLE_ROTATION_OPTIMIZED + ROTATE_270_OPTIMIZED_16BPP(32, 256); +#else + ROTATE_270_ALL_BPP(); +#endif break; default: break; } + // ESP_LOGI(TAG, "rotate: end, time used:%d", (int)(esp_log_timestamp() - time)); } #endif /* LVGL_PORT_ROTATION_DEGREE */ @@ -172,8 +289,10 @@ static void flush_dirty_copy(void *dst, void *src, lv_port_dirty_area_t *dirty_a y_start = dirty_area->inv_areas[i].y1; y_end = dirty_area->inv_areas[i].y2; - rotate_copy_pixel((lv_color_t *)src, (lv_color_t *)dst, x_start, y_start, x_end, y_end, LV_HOR_RES, LV_VER_RES, - LVGL_PORT_ROTATION_DEGREE); + rotate_copy_pixel( + (uint8_t *)src, (uint8_t *)dst, x_start, y_start, x_end, y_end, LV_HOR_RES, LV_VER_RES, + LVGL_PORT_ROTATION_DEGREE + ); } } } @@ -198,10 +317,12 @@ static void flush_callback(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t // Rotate and copy data from the whole screen LVGL's buffer to the next frame buffer next_fb = flush_get_next_buf(lcd); - rotate_copy_pixel((lv_color_t *)color_map, (lv_color_t *)next_fb, offsetx1, offsety1, offsetx2, offsety2, - LV_HOR_RES, LV_VER_RES, LVGL_PORT_ROTATION_DEGREE); + rotate_copy_pixel( + (uint8_t *)color_map, (uint8_t *)next_fb, offsetx1, offsety1, offsetx2, offsety2, + LV_HOR_RES, LV_VER_RES, LVGL_PORT_ROTATION_DEGREE + ); - /* Switch the current RGB frame buffer to `next_fb` */ + /* Switch the current LCD frame buffer to `next_fb` */ lcd->drawBitmap(offsetx1, offsety1, offsetx2 - offsetx1 + 1, offsety2 - offsety1 + 1, (const uint8_t *)next_fb); /* Waiting for the current frame buffer to complete transmission */ @@ -232,7 +353,7 @@ static void flush_callback(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t flush_dirty_save(&dirty_area); flush_dirty_copy(next_fb, color_map, &dirty_area); - /* Switch the current RGB frame buffer to `next_fb` */ + /* Switch the current LCD frame buffer to `next_fb` */ lcd->drawBitmap(offsetx1, offsety1, offsetx2 - offsetx1 + 1, offsety2 - offsety1 + 1, (const uint8_t *)next_fb); /* Waiting for the current frame buffer to complete transmission */ @@ -264,7 +385,7 @@ static void flush_callback(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t /* Action after last area refresh */ if (lv_disp_flush_is_last(drv)) { - /* Switch the current RGB frame buffer to `color_map` */ + /* Switch the current LCD frame buffer to `color_map` */ lcd->drawBitmap(offsetx1, offsety1, offsetx2 - offsetx1 + 1, offsety2 - offsety1 + 1, (const uint8_t *)color_map); /* Waiting for the last frame buffer to complete transmission */ @@ -286,7 +407,7 @@ 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; - /* Switch the current RGB frame buffer to `color_map` */ + /* Switch the current LCD frame buffer to `color_map` */ lcd->drawBitmap(offsetx1, offsety1, offsetx2 - offsetx1 + 1, offsety2 - offsety1 + 1, (const uint8_t *)color_map); /* Waiting for the last frame buffer to complete transmission */ @@ -299,8 +420,8 @@ static void flush_callback(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t #elif LVGL_PORT_FULL_REFRESH && LVGL_PORT_DISP_BUFFER_NUM == 3 #if LVGL_PORT_ROTATION_DEGREE == 0 -static void *lvgl_port_rgb_last_buf = NULL; -static void *lvgl_port_rgb_next_buf = NULL; +static void *lvgl_port_lcd_last_buf = NULL; +static void *lvgl_port_lcd_next_buf = NULL; static void *lvgl_port_flush_next_buf = NULL; #endif @@ -315,38 +436,38 @@ void flush_callback(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color #if LVGL_PORT_ROTATION_DEGREE != 0 void *next_fb = get_next_frame_buffer(lcd); - /* Rotate and copy dirty area from the current LVGL's buffer to the next RGB frame buffer */ + /* Rotate and copy dirty area from the current LVGL's buffer to the next LCD frame buffer */ rotate_copy_pixel((lv_color_t *)color_map, (lv_color_t *)next_fb, offsetx1, offsety1, offsetx2, offsety2, LV_HOR_RES, LV_VER_RES, LVGL_PORT_ROTATION_DEGREE); - /* Switch the current RGB frame buffer to `next_fb` */ + /* Switch the current LCD frame buffer to `next_fb` */ lcd->drawBitmap(offsetx1, offsety1, offsetx2 - offsetx1 + 1, offsety2 - offsety1 + 1, (const uint8_t *)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; - /* Switch the current RGB frame buffer to `color_map` */ + /* Switch the current LCD frame buffer to `color_map` */ lcd->drawBitmap(offsetx1, offsety1, offsetx2 - offsetx1 + 1, offsety2 - offsety1 + 1, (const uint8_t *)color_map); - lvgl_port_rgb_next_buf = color_map; + lvgl_port_lcd_next_buf = color_map; #endif lv_disp_flush_ready(drv); } #endif -IRAM_ATTR bool onRgbVsyncCallback(void *user_data) +IRAM_ATTR bool onLcdVsyncCallback(void *user_data) { BaseType_t need_yield = pdFALSE; #if LVGL_PORT_FULL_REFRESH && (LVGL_PORT_DISP_BUFFER_NUM == 3) && (LVGL_PORT_ROTATION_DEGREE == 0) - if (lvgl_port_rgb_next_buf != lvgl_port_rgb_last_buf) { - lvgl_port_flush_next_buf = lvgl_port_rgb_last_buf; - lvgl_port_rgb_last_buf = lvgl_port_rgb_next_buf; + if (lvgl_port_lcd_next_buf != lvgl_port_lcd_last_buf) { + lvgl_port_flush_next_buf = lvgl_port_lcd_last_buf; + lvgl_port_lcd_last_buf = lvgl_port_lcd_next_buf; } #else TaskHandle_t task_handle = (TaskHandle_t)user_data; - // Notify that the current RGB frame buffer has been transmitted + // Notify that the current LCD frame buffer has been transmitted xTaskNotifyFromISR(task_handle, ULONG_MAX, eNoAction, &need_yield); #endif return (need_yield == pdTRUE); @@ -439,7 +560,6 @@ static lv_disp_t *display_init(ESP_PanelLcd *lcd) static lv_disp_drv_t disp_drv; // Alloc draw buffers used by LVGL - void *buf[LVGL_PORT_BUFFER_NUM_MAX] = { nullptr }; int buffer_size = 0; ESP_LOGD(TAG, "Malloc memory for LVGL buffer"); @@ -447,38 +567,38 @@ static lv_disp_t *display_init(ESP_PanelLcd *lcd) // Avoid tearing function is disabled buffer_size = LVGL_PORT_BUFFER_SIZE; for (int i = 0; (i < LVGL_PORT_BUFFER_NUM) && (i < LVGL_PORT_BUFFER_NUM_MAX); i++) { - buf[i] = heap_caps_malloc(buffer_size * sizeof(lv_color_t), LVGL_PORT_BUFFER_MALLOC_CAPS); - assert(buf[i]); - ESP_LOGD(TAG, "Buffer[%d] address: %p, size: %d", i, buf[i], buffer_size * sizeof(lv_color_t)); + lvgl_buf[i] = heap_caps_malloc(buffer_size * sizeof(lv_color_t), LVGL_PORT_BUFFER_MALLOC_CAPS); + assert(lvgl_buf[i]); + ESP_LOGD(TAG, "Buffer[%d] address: %p, size: %d", i, lvgl_buf[i], buffer_size * sizeof(lv_color_t)); } #else - // To avoid the tearing effect, we should use at least two frame buffers: one for LVGL rendering and another for RGB output + // To avoid the tearing effect, we should use at least two frame buffers: one for LVGL rendering and another for LCD refresh buffer_size = LVGL_PORT_DISP_WIDTH * LVGL_PORT_DISP_HEIGHT; #if (LVGL_PORT_DISP_BUFFER_NUM >= 3) && (LVGL_PORT_ROTATION_DEGREE == 0) && LVGL_PORT_FULL_REFRESH // With the usage of three buffers and full-refresh, we always have one buffer available for rendering, - // eliminating the need to wait for the RGB's sync signal - lvgl_port_rgb_last_buf = lcd->getRgbBufferByIndex(0); - buf[0] = lcd->getRgbBufferByIndex(1); - buf[1] = lcd->getRgbBufferByIndex(2); - lvgl_port_rgb_next_buf = lvgl_port_rgb_last_buf; - lvgl_port_flush_next_buf = buf[1]; + // eliminating the need to wait for the LCD's sync signal + lvgl_port_lcd_last_buf = lcd->getFrameBufferByIndex(0); + lvgl_buf[0] = lcd->getFrameBufferByIndex(1); + lvgl_buf[1] = lcd->getFrameBufferByIndex(2); + lvgl_port_lcd_next_buf = lvgl_port_lcd_last_buf; + lvgl_port_flush_next_buf = lvgl_buf[1]; #elif (LVGL_PORT_DISP_BUFFER_NUM >= 3) && (LVGL_PORT_ROTATION_DEGREE != 0) - buf[0] = lcd->getRgbBufferByIndex(2); + lvgl_buf[0] = lcd->getFrameBufferByIndex(2); #elif LVGL_PORT_DISP_BUFFER_NUM >= 2 for (int i = 0; (i < LVGL_PORT_DISP_BUFFER_NUM) && (i < LVGL_PORT_BUFFER_NUM_MAX); i++) { - buf[i] = lcd->getRgbBufferByIndex(i); + lvgl_buf[i] = lcd->getFrameBufferByIndex(i); } #endif #endif /* LVGL_PORT_AVOID_TEAR */ // initialize LVGL draw buffers - lv_disp_draw_buf_init(&disp_buf, buf[0], buf[1], buffer_size); + lv_disp_draw_buf_init(&disp_buf, lvgl_buf[0], lvgl_buf[1], buffer_size); ESP_LOGD(TAG, "Register display driver to LVGL"); lv_disp_drv_init(&disp_drv); @@ -548,16 +668,33 @@ static void tick_increment(void *arg) lv_tick_inc(LVGL_PORT_TICK_PERIOD_MS); } -static esp_err_t tick_init(void) +static bool tick_init(void) { // Tick interface for LVGL (using esp_timer to generate 2ms periodic event) const esp_timer_create_args_t lvgl_tick_timer_args = { .callback = &tick_increment, .name = "LVGL tick" }; - esp_timer_handle_t lvgl_tick_timer = NULL; - ESP_ERROR_CHECK(esp_timer_create(&lvgl_tick_timer_args, &lvgl_tick_timer)); - return esp_timer_start_periodic(lvgl_tick_timer, LVGL_PORT_TICK_PERIOD_MS * 1000); + ESP_PANEL_CHECK_ERR_RET( + esp_timer_create(&lvgl_tick_timer_args, &lvgl_tick_timer), false, "Create LVGL tick timer failed" + ); + ESP_PANEL_CHECK_ERR_RET( + esp_timer_start_periodic(lvgl_tick_timer, LVGL_PORT_TICK_PERIOD_MS * 1000), false, + "Start LVGL tick timer failed" + ); + + return true; +} + +static bool tick_deinit(void) +{ + ESP_PANEL_CHECK_ERR_RET( + esp_timer_stop(lvgl_tick_timer), false, "Stop LVGL tick timer failed" + ); + ESP_PANEL_CHECK_ERR_RET( + esp_timer_delete(lvgl_tick_timer), false, "Delete LVGL tick timer failed" + ); + return true; } #endif @@ -580,7 +717,7 @@ static void lvgl_port_task(void *arg) } } -IRAM_ATTR bool onRefreshFinishCallback(void *user_data) +IRAM_ATTR bool onDrawBitmapFinishCallback(void *user_data) { lv_disp_drv_t *drv = (lv_disp_drv_t *)user_data; @@ -592,9 +729,14 @@ IRAM_ATTR bool onRefreshFinishCallback(void *user_data) bool lvgl_port_init(ESP_PanelLcd *lcd, ESP_PanelTouch *tp) { ESP_PANEL_CHECK_FALSE_RET(lcd != nullptr, false, "Invalid LCD device"); + + auto bus_type = lcd->getBus()->getType(); #if LVGL_PORT_AVOID_TEAR - ESP_PANEL_CHECK_FALSE_RET(lcd->getBus()->getType() == ESP_PANEL_BUS_TYPE_RGB, false, "Avoid tearing function only works with RGB LCD now"); - ESP_LOGD(TAG, "Avoid tearing is enabled, mode: %d", LVGL_PORT_AVOID_TEARING_MODE); + ESP_PANEL_CHECK_FALSE_RET( + (bus_type == ESP_PANEL_BUS_TYPE_RGB) || (bus_type == ESP_PANEL_BUS_TYPE_MIPI_DSI), false, + "Avoid tearing function only works with RGB/MIPI-DSI LCD now" + ); + ESP_LOGI(TAG, "Avoid tearing is enabled, mode: %d", LVGL_PORT_AVOID_TEARING_MODE); #endif lv_disp_t *disp = nullptr; @@ -602,7 +744,7 @@ bool lvgl_port_init(ESP_PanelLcd *lcd, ESP_PanelTouch *tp) lv_init(); #if !LV_TICK_CUSTOM - ESP_PANEL_CHECK_ERR_RET(tick_init(), false, "Initialize LVGL tick failed"); + ESP_PANEL_CHECK_FALSE_RET(tick_init(), false, "Initialize LVGL tick failed"); #endif ESP_LOGD(TAG, "Initialize LVGL display driver"); @@ -612,9 +754,9 @@ bool lvgl_port_init(ESP_PanelLcd *lcd, ESP_PanelTouch *tp) lv_disp_set_rotation(disp, LV_DISP_ROT_NONE); // For non-RGB LCD, need to notify LVGL that the buffer is ready when the refresh is finished - if (lcd->getBus()->getType() != ESP_PANEL_BUS_TYPE_RGB) { + if (bus_type != ESP_PANEL_BUS_TYPE_RGB) { ESP_LOGD(TAG, "Attach refresh finish callback to LCD"); - lcd->attachRefreshFinishCallback(onRefreshFinishCallback, (void *)disp->driver); + lcd->attachDrawBitmapFinishCallback(onDrawBitmapFinishCallback, (void *)disp->driver); } if (tp != nullptr) { @@ -645,7 +787,7 @@ bool lvgl_port_init(ESP_PanelLcd *lcd, ESP_PanelTouch *tp) ESP_PANEL_CHECK_FALSE_RET(ret == pdPASS, false, "Create LVGL task failed"); #if LVGL_PORT_AVOID_TEAR - lcd->attachRefreshFinishCallback(onRgbVsyncCallback, (void *)lvgl_task_handle); + lcd->attachRefreshFinishCallback(onLcdVsyncCallback, (void *)lvgl_task_handle); #endif return true; @@ -670,14 +812,28 @@ bool lvgl_port_unlock(void) bool lvgl_port_deinit(void) { - lvgl_port_lock(-1); +#if !LV_TICK_CUSTOM + ESP_PANEL_CHECK_FALSE_RET(tick_deinit(), false, "Deinitialize LVGL tick failed"); +#endif + + ESP_PANEL_CHECK_FALSE_RET(lvgl_port_lock(-1), false, "Lock LVGL failed"); if (lvgl_task_handle != nullptr) { vTaskDelete(lvgl_task_handle); lvgl_task_handle = nullptr; } - lvgl_port_unlock(); + ESP_PANEL_CHECK_FALSE_RET(lvgl_port_unlock(), false, "Unlock LVGL failed"); +#if LV_ENABLE_GC || !LV_MEM_CUSTOM lv_deinit(); +#endif +#if !LVGL_PORT_AVOID_TEAR + for (int i = 0; i < LVGL_PORT_BUFFER_NUM; i++) { + if (lvgl_buf[i] != nullptr) { + free(lvgl_buf[i]); + lvgl_buf[i] = nullptr; + } + } +#endif if (lvgl_mux != nullptr) { vSemaphoreDelete(lvgl_mux); lvgl_mux = nullptr; diff --git a/test_apps/lvgl_port/main/lvgl_port_v8.h b/test_apps/lvgl_port/main/lvgl_port_v8.h index 67948749..1f39050c 100644 --- a/test_apps/lvgl_port/main/lvgl_port_v8.h +++ b/test_apps/lvgl_port/main/lvgl_port_v8.h @@ -73,6 +73,7 @@ #define LVGL_PORT_AVOID_TEARING_MODE (CONFIG_LVGL_PORT_AVOID_TEARING_MODE) #if LVGL_PORT_AVOID_TEARING_MODE != 0 +#if ESP_PANEL_LCD_BUS_TYPE == ESP_PANEL_BUS_TYPE_RGB /** * As the anti-tearing feature typically consumes more PSRAM bandwidth, for the ESP32-S3, we need to utilize the Bounce * buffer functionality to enhance the RGB data bandwidth. @@ -81,10 +82,11 @@ * */ #define LVGL_PORT_RGB_BOUNCE_BUFFER_SIZE (LVGL_PORT_DISP_WIDTH * 10) +#endif + /** * When avoid tearing is enabled, the LVGL software rotation `lv_disp_set_rotation()` is not supported. - * But users can set the rotation degree(0/90/180/270) here, but this function will extremely reduce FPS. - * So it is recommended to be used when using a low resolution display. + * But users can set the rotation degree(0/90/180/270) here, but this function will reduce FPS. * * Set the rotation degree: * - 0: 0 degree diff --git a/test_apps/lvgl_port/main/test_app_main.c b/test_apps/lvgl_port/main/test_app_main.cpp similarity index 90% rename from test_apps/lvgl_port/main/test_app_main.c rename to test_apps/lvgl_port/main/test_app_main.cpp index bf8ef112..50372fd5 100644 --- a/test_apps/lvgl_port/main/test_app_main.c +++ b/test_apps/lvgl_port/main/test_app_main.cpp @@ -11,7 +11,13 @@ #include "unity_test_runner.h" // Some resources are lazy allocated in the LCD driver, the threadhold is left for that case +#if ESP_PANEL_LCD_BUS_TYPE == ESP_PANEL_BUS_TYPE_MIPI_DSI +#define TEST_MEMORY_LEAK_THRESHOLD (-800) +#elif ESP_PANEL_LCD_BUS_TYPE == ESP_PANEL_BUS_TYPE_RGB +#define TEST_MEMORY_LEAK_THRESHOLD (-500) +#else #define TEST_MEMORY_LEAK_THRESHOLD (-300) +#endif static size_t before_free_8bit; static size_t before_free_32bit; @@ -37,7 +43,7 @@ void tearDown(void) check_leak(before_free_32bit, after_free_32bit, "32BIT"); } -void app_main(void) +extern "C" void app_main(void) { /** * _______ ______ __ __ ________ __ diff --git a/test_apps/lvgl_port/main/test_lvgl_port.cpp b/test_apps/lvgl_port/main/test_lvgl_port.cpp index 64931df2..71caa3bc 100644 --- a/test_apps/lvgl_port/main/test_lvgl_port.cpp +++ b/test_apps/lvgl_port/main/test_lvgl_port.cpp @@ -31,10 +31,14 @@ TEST_CASE("Test panel lvgl port to show demo", "[panel][lvgl]") ESP_LOGI(TAG, "Initialize display panel"); TEST_ASSERT_TRUE_MESSAGE(panel->init(), "Panel init failed"); #if LVGL_PORT_AVOID_TEAR - // When avoid tearing function is enabled, configure the RGB bus according to the LVGL configuration - ESP_PanelBus_RGB *rgb_bus = static_cast(panel->getLcd()->getBus()); - rgb_bus->configRgbFrameBufferNumber(LVGL_PORT_DISP_BUFFER_NUM); - rgb_bus->configRgbBounceBufferSize(LVGL_PORT_RGB_BOUNCE_BUFFER_SIZE); + // When avoid tearing function is enabled, configure the bus according to the LVGL configuration + ESP_PanelBus *lcd_bus = panel->getLcd()->getBus(); +#if ESP_PANEL_LCD_BUS_TYPE == ESP_PANEL_BUS_TYPE_RGB + static_cast(lcd_bus)->configRgbBounceBufferSize(LVGL_PORT_RGB_BOUNCE_BUFFER_SIZE); + static_cast(lcd_bus)->configRgbFrameBufferNumber(LVGL_PORT_DISP_BUFFER_NUM); +#elif ESP_PANEL_LCD_BUS_TYPE == ESP_PANEL_BUS_TYPE_MIPI_DSI + static_cast(lcd_bus)->configDpiFrameBufferNumber(LVGL_PORT_DISP_BUFFER_NUM); +#endif #endif TEST_ASSERT_TRUE_MESSAGE(panel->begin(), "Panel begin failed"); diff --git a/test_apps/lvgl_port/sdkconfig.ci.elecrow_crowpanel_7_0 b/test_apps/lvgl_port/sdkconfig.ci.elecrow_crowpanel_7_0 index adeda816..677bab1a 100644 --- a/test_apps/lvgl_port/sdkconfig.ci.elecrow_crowpanel_7_0 +++ b/test_apps/lvgl_port/sdkconfig.ci.elecrow_crowpanel_7_0 @@ -1,11 +1,19 @@ CONFIG_IDF_TARGET="esp32s3" +CONFIG_COMPILER_OPTIMIZATION_PERF=y CONFIG_BOARD_MANUFACTURER_ALL=y CONFIG_BOARD_ELECROW_CROWPANEL_7_0=y CONFIG_SPIRAM=y CONFIG_SPIRAM_MODE_OCT=y +CONFIG_SPIRAM_SPEED_80M=y +# Enable the XIP-PSRAM feature, so the ext-mem cache won't be disabled when SPI1 is operating the main flash +# For v5.2 and below CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y CONFIG_SPIRAM_RODATA=y -CONFIG_SPIRAM_SPEED_80M=y +# For v5.3 and above +CONFIG_SPIRAM_XIP_FROM_PSRAM=y + +# Used in conjunction with "RGB Bounce Buffer" +CONFIG_ESP32S3_DATA_CACHE_LINE_64B=y CONFIG_LVGL_PORT_AVOID_TEARING_MODE_3=y diff --git a/test_apps/lvgl_port/sdkconfig.ci.espressif_esp32_c3_lcdkit b/test_apps/lvgl_port/sdkconfig.ci.espressif_esp32_c3_lcdkit index e81429f1..59c9fe7a 100644 --- a/test_apps/lvgl_port/sdkconfig.ci.espressif_esp32_c3_lcdkit +++ b/test_apps/lvgl_port/sdkconfig.ci.espressif_esp32_c3_lcdkit @@ -1,3 +1,8 @@ CONFIG_IDF_TARGET="esp32c3" CONFIG_BOARD_MANUFACTURER_ALL=y CONFIG_BOARD_ESP32_C3_LCDKIT=y +CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y +CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y + +# lvgl +CONFIG_LV_COLOR_16_SWAP=y diff --git a/test_apps/lvgl_port/sdkconfig.ci.espressif_esp32_p4_function_ev_board b/test_apps/lvgl_port/sdkconfig.ci.espressif_esp32_p4_function_ev_board new file mode 100644 index 00000000..a5815a9f --- /dev/null +++ b/test_apps/lvgl_port/sdkconfig.ci.espressif_esp32_p4_function_ev_board @@ -0,0 +1,15 @@ +CONFIG_IDF_TARGET="esp32p4" +CONFIG_BOARD_MANUFACTURER_ALL=y +CONFIG_BOARD_ESP32_P4_FUNCTION_EV_BOARD=y + +CONFIG_SPIRAM=y +CONFIG_SPIRAM_MODE_HEX=y +CONFIG_SPIRAM_SPEED_200M=y +CONFIG_SPIRAM_XIP_FROM_PSRAM=y +CONFIG_IDF_EXPERIMENTAL_FEATURES=y + +# Improve FPS +CONFIG_CACHE_L2_CACHE_256KB=y +CONFIG_CACHE_L2_CACHE_LINE_128B=y + +CONFIG_LVGL_PORT_AVOID_TEARING_MODE_3=y diff --git a/test_apps/lvgl_port/sdkconfig.ci.espressif_esp32_s3_box b/test_apps/lvgl_port/sdkconfig.ci.espressif_esp32_s3_box index 6e15d03d..4d6a2b7b 100644 --- a/test_apps/lvgl_port/sdkconfig.ci.espressif_esp32_s3_box +++ b/test_apps/lvgl_port/sdkconfig.ci.espressif_esp32_s3_box @@ -1,9 +1,21 @@ CONFIG_IDF_TARGET="esp32s3" +CONFIG_COMPILER_OPTIMIZATION_PERF=y CONFIG_BOARD_MANUFACTURER_ALL=y CONFIG_BOARD_ESP32_S3_BOX=y +CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y CONFIG_SPIRAM=y CONFIG_SPIRAM_MODE_OCT=y +CONFIG_SPIRAM_SPEED_80M=y +# Enable the XIP-PSRAM feature, so the ext-mem cache won't be disabled when SPI1 is operating the main flash +# For v5.2 and below CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y CONFIG_SPIRAM_RODATA=y -CONFIG_SPIRAM_SPEED_80M=y +# For v5.3 and above +CONFIG_SPIRAM_XIP_FROM_PSRAM=y + +# Used in conjunction with "RGB Bounce Buffer" +CONFIG_ESP32S3_DATA_CACHE_LINE_64B=y + +# lvgl +CONFIG_LV_COLOR_16_SWAP=y diff --git a/test_apps/lvgl_port/sdkconfig.ci.espressif_esp32_s3_box_3 b/test_apps/lvgl_port/sdkconfig.ci.espressif_esp32_s3_box_3 index efa09e4b..05319b36 100644 --- a/test_apps/lvgl_port/sdkconfig.ci.espressif_esp32_s3_box_3 +++ b/test_apps/lvgl_port/sdkconfig.ci.espressif_esp32_s3_box_3 @@ -1,9 +1,21 @@ CONFIG_IDF_TARGET="esp32s3" +CONFIG_COMPILER_OPTIMIZATION_PERF=y CONFIG_BOARD_MANUFACTURER_ALL=y CONFIG_BOARD_ESP32_S3_BOX_3=y +CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y CONFIG_SPIRAM=y CONFIG_SPIRAM_MODE_OCT=y +CONFIG_SPIRAM_SPEED_80M=y +# Enable the XIP-PSRAM feature, so the ext-mem cache won't be disabled when SPI1 is operating the main flash +# For v5.2 and below CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y CONFIG_SPIRAM_RODATA=y -CONFIG_SPIRAM_SPEED_80M=y +# For v5.3 and above +CONFIG_SPIRAM_XIP_FROM_PSRAM=y + +# Used in conjunction with "RGB Bounce Buffer" +CONFIG_ESP32S3_DATA_CACHE_LINE_64B=y + +# lvgl +CONFIG_LV_COLOR_16_SWAP=y diff --git a/test_apps/lvgl_port/sdkconfig.ci.espressif_esp32_s3_box_3_beta b/test_apps/lvgl_port/sdkconfig.ci.espressif_esp32_s3_box_3_beta index e859d720..e32d3c5f 100644 --- a/test_apps/lvgl_port/sdkconfig.ci.espressif_esp32_s3_box_3_beta +++ b/test_apps/lvgl_port/sdkconfig.ci.espressif_esp32_s3_box_3_beta @@ -1,9 +1,21 @@ CONFIG_IDF_TARGET="esp32s3" +CONFIG_COMPILER_OPTIMIZATION_PERF=y CONFIG_BOARD_MANUFACTURER_ALL=y CONFIG_BOARD_ESP32_S3_BOX_3_BETA=y +CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y CONFIG_SPIRAM=y CONFIG_SPIRAM_MODE_OCT=y +CONFIG_SPIRAM_SPEED_80M=y +# Enable the XIP-PSRAM feature, so the ext-mem cache won't be disabled when SPI1 is operating the main flash +# For v5.2 and below CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y CONFIG_SPIRAM_RODATA=y -CONFIG_SPIRAM_SPEED_80M=y +# For v5.3 and above +CONFIG_SPIRAM_XIP_FROM_PSRAM=y + +# Used in conjunction with "RGB Bounce Buffer" +CONFIG_ESP32S3_DATA_CACHE_LINE_64B=y + +# lvgl +CONFIG_LV_COLOR_16_SWAP=y diff --git a/test_apps/lvgl_port/sdkconfig.ci.espressif_esp32_s3_box_lite b/test_apps/lvgl_port/sdkconfig.ci.espressif_esp32_s3_box_lite index 5c3fe36e..df03890d 100644 --- a/test_apps/lvgl_port/sdkconfig.ci.espressif_esp32_s3_box_lite +++ b/test_apps/lvgl_port/sdkconfig.ci.espressif_esp32_s3_box_lite @@ -1,9 +1,21 @@ CONFIG_IDF_TARGET="esp32s3" +CONFIG_COMPILER_OPTIMIZATION_PERF=y CONFIG_BOARD_MANUFACTURER_ALL=y CONFIG_BOARD_ESP32_S3_BOX_LITE=y +CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y CONFIG_SPIRAM=y CONFIG_SPIRAM_MODE_OCT=y +CONFIG_SPIRAM_SPEED_80M=y +# Enable the XIP-PSRAM feature, so the ext-mem cache won't be disabled when SPI1 is operating the main flash +# For v5.2 and below CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y CONFIG_SPIRAM_RODATA=y -CONFIG_SPIRAM_SPEED_80M=y +# For v5.3 and above +CONFIG_SPIRAM_XIP_FROM_PSRAM=y + +# Used in conjunction with "RGB Bounce Buffer" +CONFIG_ESP32S3_DATA_CACHE_LINE_64B=y + +# lvgl +CONFIG_LV_COLOR_16_SWAP=y diff --git a/test_apps/lvgl_port/sdkconfig.ci.espressif_esp32_s3_eye b/test_apps/lvgl_port/sdkconfig.ci.espressif_esp32_s3_eye index 236bdd7c..598da3d3 100644 --- a/test_apps/lvgl_port/sdkconfig.ci.espressif_esp32_s3_eye +++ b/test_apps/lvgl_port/sdkconfig.ci.espressif_esp32_s3_eye @@ -1,9 +1,21 @@ CONFIG_IDF_TARGET="esp32s3" +CONFIG_COMPILER_OPTIMIZATION_PERF=y CONFIG_BOARD_MANUFACTURER_ALL=y CONFIG_BOARD_ESP32_S3_EYE=y +CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y CONFIG_SPIRAM=y CONFIG_SPIRAM_MODE_OCT=y +CONFIG_SPIRAM_SPEED_80M=y +# Enable the XIP-PSRAM feature, so the ext-mem cache won't be disabled when SPI1 is operating the main flash +# For v5.2 and below CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y CONFIG_SPIRAM_RODATA=y -CONFIG_SPIRAM_SPEED_80M=y +# For v5.3 and above +CONFIG_SPIRAM_XIP_FROM_PSRAM=y + +# Used in conjunction with "RGB Bounce Buffer" +CONFIG_ESP32S3_DATA_CACHE_LINE_64B=y + +# lvgl +CONFIG_LV_COLOR_16_SWAP=y diff --git a/test_apps/lvgl_port/sdkconfig.ci.espressif_esp32_s3_korvo_2 b/test_apps/lvgl_port/sdkconfig.ci.espressif_esp32_s3_korvo_2 index ce44a69c..05824538 100644 --- a/test_apps/lvgl_port/sdkconfig.ci.espressif_esp32_s3_korvo_2 +++ b/test_apps/lvgl_port/sdkconfig.ci.espressif_esp32_s3_korvo_2 @@ -1,9 +1,20 @@ CONFIG_IDF_TARGET="esp32s3" +CONFIG_COMPILER_OPTIMIZATION_PERF=y CONFIG_BOARD_MANUFACTURER_ALL=y CONFIG_BOARD_ESP32_S3_KORVO_2=y CONFIG_SPIRAM=y CONFIG_SPIRAM_MODE_OCT=y +CONFIG_SPIRAM_SPEED_80M=y +# Enable the XIP-PSRAM feature, so the ext-mem cache won't be disabled when SPI1 is operating the main flash +# For v5.2 and below CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y CONFIG_SPIRAM_RODATA=y -CONFIG_SPIRAM_SPEED_80M=y +# For v5.3 and above +CONFIG_SPIRAM_XIP_FROM_PSRAM=y + +# Used in conjunction with "RGB Bounce Buffer" +CONFIG_ESP32S3_DATA_CACHE_LINE_64B=y + +# lvgl +CONFIG_LV_COLOR_16_SWAP=y diff --git a/test_apps/lvgl_port/sdkconfig.ci.espressif_esp32_s3_lcd_ev_board b/test_apps/lvgl_port/sdkconfig.ci.espressif_esp32_s3_lcd_ev_board index 2f555ac0..85cb761b 100644 --- a/test_apps/lvgl_port/sdkconfig.ci.espressif_esp32_s3_lcd_ev_board +++ b/test_apps/lvgl_port/sdkconfig.ci.espressif_esp32_s3_lcd_ev_board @@ -1,11 +1,19 @@ CONFIG_IDF_TARGET="esp32s3" +CONFIG_COMPILER_OPTIMIZATION_PERF=y CONFIG_BOARD_MANUFACTURER_ALL=y CONFIG_BOARD_ESP32_S3_LCD_EV_BOARD=y CONFIG_SPIRAM=y CONFIG_SPIRAM_MODE_OCT=y +CONFIG_SPIRAM_SPEED_80M=y +# Enable the XIP-PSRAM feature, so the ext-mem cache won't be disabled when SPI1 is operating the main flash +# For v5.2 and below CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y CONFIG_SPIRAM_RODATA=y -CONFIG_SPIRAM_SPEED_80M=y +# For v5.3 and above +CONFIG_SPIRAM_XIP_FROM_PSRAM=y + +# Used in conjunction with "RGB Bounce Buffer" +CONFIG_ESP32S3_DATA_CACHE_LINE_64B=y CONFIG_LVGL_PORT_AVOID_TEARING_MODE_3=y diff --git a/test_apps/lvgl_port/sdkconfig.ci.espressif_esp32_s3_lcd_ev_board_2 b/test_apps/lvgl_port/sdkconfig.ci.espressif_esp32_s3_lcd_ev_board_2 index c2794b33..9496f02e 100644 --- a/test_apps/lvgl_port/sdkconfig.ci.espressif_esp32_s3_lcd_ev_board_2 +++ b/test_apps/lvgl_port/sdkconfig.ci.espressif_esp32_s3_lcd_ev_board_2 @@ -1,11 +1,19 @@ CONFIG_IDF_TARGET="esp32s3" +CONFIG_COMPILER_OPTIMIZATION_PERF=y CONFIG_BOARD_MANUFACTURER_ALL=y CONFIG_BOARD_ESP32_S3_LCD_EV_BOARD_2=y CONFIG_SPIRAM=y CONFIG_SPIRAM_MODE_OCT=y +CONFIG_SPIRAM_SPEED_80M=y +# Enable the XIP-PSRAM feature, so the ext-mem cache won't be disabled when SPI1 is operating the main flash +# For v5.2 and below CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y CONFIG_SPIRAM_RODATA=y -CONFIG_SPIRAM_SPEED_80M=y +# For v5.3 and above +CONFIG_SPIRAM_XIP_FROM_PSRAM=y + +# Used in conjunction with "RGB Bounce Buffer" +CONFIG_ESP32S3_DATA_CACHE_LINE_64B=y CONFIG_LVGL_PORT_AVOID_TEARING_MODE_3=y diff --git a/test_apps/lvgl_port/sdkconfig.ci.espressif_esp32_s3_lcd_ev_board_2_v1_5 b/test_apps/lvgl_port/sdkconfig.ci.espressif_esp32_s3_lcd_ev_board_2_v1_5 index 4eff920e..62011779 100644 --- a/test_apps/lvgl_port/sdkconfig.ci.espressif_esp32_s3_lcd_ev_board_2_v1_5 +++ b/test_apps/lvgl_port/sdkconfig.ci.espressif_esp32_s3_lcd_ev_board_2_v1_5 @@ -1,11 +1,19 @@ CONFIG_IDF_TARGET="esp32s3" +CONFIG_COMPILER_OPTIMIZATION_PERF=y CONFIG_BOARD_MANUFACTURER_ALL=y CONFIG_BOARD_ESP32_S3_LCD_EV_BOARD_2_V1_5=y CONFIG_SPIRAM=y CONFIG_SPIRAM_MODE_OCT=y +CONFIG_SPIRAM_SPEED_80M=y +# Enable the XIP-PSRAM feature, so the ext-mem cache won't be disabled when SPI1 is operating the main flash +# For v5.2 and below CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y CONFIG_SPIRAM_RODATA=y -CONFIG_SPIRAM_SPEED_80M=y +# For v5.3 and above +CONFIG_SPIRAM_XIP_FROM_PSRAM=y + +# Used in conjunction with "RGB Bounce Buffer" +CONFIG_ESP32S3_DATA_CACHE_LINE_64B=y CONFIG_LVGL_PORT_AVOID_TEARING_MODE_3=y diff --git a/test_apps/lvgl_port/sdkconfig.ci.espressif_esp32_s3_lcd_ev_board_v1_5 b/test_apps/lvgl_port/sdkconfig.ci.espressif_esp32_s3_lcd_ev_board_v1_5 index 057721b7..5371fbc5 100644 --- a/test_apps/lvgl_port/sdkconfig.ci.espressif_esp32_s3_lcd_ev_board_v1_5 +++ b/test_apps/lvgl_port/sdkconfig.ci.espressif_esp32_s3_lcd_ev_board_v1_5 @@ -1,11 +1,19 @@ CONFIG_IDF_TARGET="esp32s3" +CONFIG_COMPILER_OPTIMIZATION_PERF=y CONFIG_BOARD_MANUFACTURER_ALL=y CONFIG_BOARD_ESP32_S3_LCD_EV_BOARD_V1_5=y CONFIG_SPIRAM=y CONFIG_SPIRAM_MODE_OCT=y +CONFIG_SPIRAM_SPEED_80M=y +# Enable the XIP-PSRAM feature, so the ext-mem cache won't be disabled when SPI1 is operating the main flash +# For v5.2 and below CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y CONFIG_SPIRAM_RODATA=y -CONFIG_SPIRAM_SPEED_80M=y +# For v5.3 and above +CONFIG_SPIRAM_XIP_FROM_PSRAM=y + +# Used in conjunction with "RGB Bounce Buffer" +CONFIG_ESP32S3_DATA_CACHE_LINE_64B=y CONFIG_LVGL_PORT_AVOID_TEARING_MODE_3=y diff --git a/test_apps/lvgl_port/sdkconfig.ci.espressif_esp32_s3_usb_otg b/test_apps/lvgl_port/sdkconfig.ci.espressif_esp32_s3_usb_otg index 266fd377..ec33415a 100644 --- a/test_apps/lvgl_port/sdkconfig.ci.espressif_esp32_s3_usb_otg +++ b/test_apps/lvgl_port/sdkconfig.ci.espressif_esp32_s3_usb_otg @@ -1,3 +1,7 @@ CONFIG_IDF_TARGET="esp32s3" +CONFIG_COMPILER_OPTIMIZATION_PERF=y CONFIG_BOARD_MANUFACTURER_ALL=y CONFIG_BOARD_ESP32_S3_USB_OTG=y + +# lvgl +CONFIG_LV_COLOR_16_SWAP=y diff --git a/test_apps/lvgl_port/sdkconfig.ci.jingcai_esp32_4848S040C_I_Y_3 b/test_apps/lvgl_port/sdkconfig.ci.jingcai_esp32_4848S040C_I_Y_3 index 200614be..4ea4f368 100644 --- a/test_apps/lvgl_port/sdkconfig.ci.jingcai_esp32_4848S040C_I_Y_3 +++ b/test_apps/lvgl_port/sdkconfig.ci.jingcai_esp32_4848S040C_I_Y_3 @@ -1,11 +1,19 @@ CONFIG_IDF_TARGET="esp32s3" +CONFIG_COMPILER_OPTIMIZATION_PERF=y CONFIG_BOARD_MANUFACTURER_ALL=y CONFIG_BOARD_ESP32_4848S040C_I_Y_3=y CONFIG_SPIRAM=y CONFIG_SPIRAM_MODE_OCT=y +CONFIG_SPIRAM_SPEED_80M=y +# Enable the XIP-PSRAM feature, so the ext-mem cache won't be disabled when SPI1 is operating the main flash +# For v5.2 and below CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y CONFIG_SPIRAM_RODATA=y -CONFIG_SPIRAM_SPEED_80M=y +# For v5.3 and above +CONFIG_SPIRAM_XIP_FROM_PSRAM=y + +# Used in conjunction with "RGB Bounce Buffer" +CONFIG_ESP32S3_DATA_CACHE_LINE_64B=y CONFIG_LVGL_PORT_AVOID_TEARING_MODE_3=y diff --git a/test_apps/lvgl_port/sdkconfig.ci.m5stack_m5core2 b/test_apps/lvgl_port/sdkconfig.ci.m5stack_m5core2 index ef2f58da..8f056a5d 100644 --- a/test_apps/lvgl_port/sdkconfig.ci.m5stack_m5core2 +++ b/test_apps/lvgl_port/sdkconfig.ci.m5stack_m5core2 @@ -1,3 +1,7 @@ CONFIG_IDF_TARGET="esp32s3" +CONFIG_COMPILER_OPTIMIZATION_PERF=y CONFIG_BOARD_MANUFACTURER_ALL=y CONFIG_BOARD_M5STACK_M5CORE2=y + +# lvgl +CONFIG_LV_COLOR_16_SWAP=y diff --git a/test_apps/lvgl_port/sdkconfig.ci.m5stack_m5core3 b/test_apps/lvgl_port/sdkconfig.ci.m5stack_m5core3 index e8126d4b..e34a32a9 100644 --- a/test_apps/lvgl_port/sdkconfig.ci.m5stack_m5core3 +++ b/test_apps/lvgl_port/sdkconfig.ci.m5stack_m5core3 @@ -1,9 +1,21 @@ CONFIG_IDF_TARGET="esp32s3" +CONFIG_COMPILER_OPTIMIZATION_PERF=y CONFIG_BOARD_MANUFACTURER_ALL=y CONFIG_BOARD_M5STACK_M5CORES3=y +CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y CONFIG_SPIRAM=y CONFIG_SPIRAM_MODE_OCT=y +CONFIG_SPIRAM_SPEED_80M=y +# Enable the XIP-PSRAM feature, so the ext-mem cache won't be disabled when SPI1 is operating the main flash +# For v5.2 and below CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y CONFIG_SPIRAM_RODATA=y -CONFIG_SPIRAM_SPEED_80M=y +# For v5.3 and above +CONFIG_SPIRAM_XIP_FROM_PSRAM=y + +# Used in conjunction with "RGB Bounce Buffer" +CONFIG_ESP32S3_DATA_CACHE_LINE_64B=y + +# lvgl +CONFIG_LV_COLOR_16_SWAP=y diff --git a/test_apps/lvgl_port/sdkconfig.ci.m5stack_m5dial b/test_apps/lvgl_port/sdkconfig.ci.m5stack_m5dial index 89f97068..280f68c7 100644 --- a/test_apps/lvgl_port/sdkconfig.ci.m5stack_m5dial +++ b/test_apps/lvgl_port/sdkconfig.ci.m5stack_m5dial @@ -1,9 +1,17 @@ CONFIG_IDF_TARGET="esp32s3" +CONFIG_COMPILER_OPTIMIZATION_PERF=y CONFIG_BOARD_MANUFACTURER_ALL=y CONFIG_BOARD_M5STACK_M5DIAL=y CONFIG_SPIRAM=y CONFIG_SPIRAM_MODE_OCT=y +CONFIG_SPIRAM_SPEED_80M=y +# Enable the XIP-PSRAM feature, so the ext-mem cache won't be disabled when SPI1 is operating the main flash +# For v5.2 and below CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y CONFIG_SPIRAM_RODATA=y -CONFIG_SPIRAM_SPEED_80M=y +# For v5.3 and above +CONFIG_SPIRAM_XIP_FROM_PSRAM=y + +# lvgl +CONFIG_LV_COLOR_16_SWAP=y diff --git a/test_apps/lvgl_port/sdkconfig.ci.waveshare_esp32_s3_touch_lcd_1_85 b/test_apps/lvgl_port/sdkconfig.ci.waveshare_esp32_s3_touch_lcd_1_85 index 2dc3c165..bc98d906 100644 --- a/test_apps/lvgl_port/sdkconfig.ci.waveshare_esp32_s3_touch_lcd_1_85 +++ b/test_apps/lvgl_port/sdkconfig.ci.waveshare_esp32_s3_touch_lcd_1_85 @@ -1,11 +1,21 @@ CONFIG_IDF_TARGET="esp32s3" +CONFIG_COMPILER_OPTIMIZATION_PERF=y CONFIG_BOARD_MANUFACTURER_ALL=y CONFIG_BOARD_WAVESHARE_ESP32_S3_Touch_LCD_1_85=y +CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y CONFIG_SPIRAM=y CONFIG_SPIRAM_MODE_OCT=y +CONFIG_SPIRAM_SPEED_80M=y +# Enable the XIP-PSRAM feature, so the ext-mem cache won't be disabled when SPI1 is operating the main flash +# For v5.2 and below CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y CONFIG_SPIRAM_RODATA=y -CONFIG_SPIRAM_SPEED_80M=y +# For v5.3 and above +CONFIG_SPIRAM_XIP_FROM_PSRAM=y + +# Used in conjunction with "RGB Bounce Buffer" +CONFIG_ESP32S3_DATA_CACHE_LINE_64B=y -CONFIG_LVGL_PORT_AVOID_TEARING_MODE_3=y +# lvgl +CONFIG_LV_COLOR_16_SWAP=y diff --git a/test_apps/lvgl_port/sdkconfig.ci.waveshare_esp32_s3_touch_lcd_2_1 b/test_apps/lvgl_port/sdkconfig.ci.waveshare_esp32_s3_touch_lcd_2_1 index 55839aba..41eb76ba 100644 --- a/test_apps/lvgl_port/sdkconfig.ci.waveshare_esp32_s3_touch_lcd_2_1 +++ b/test_apps/lvgl_port/sdkconfig.ci.waveshare_esp32_s3_touch_lcd_2_1 @@ -1,9 +1,20 @@ CONFIG_IDF_TARGET="esp32s3" +CONFIG_COMPILER_OPTIMIZATION_PERF=y CONFIG_BOARD_MANUFACTURER_ALL=y CONFIG_BOARD_WAVESHARE_ESP32_S3_Touch_LCD_2_1=y +CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y CONFIG_SPIRAM=y CONFIG_SPIRAM_MODE_OCT=y +CONFIG_SPIRAM_SPEED_80M=y +# Enable the XIP-PSRAM feature, so the ext-mem cache won't be disabled when SPI1 is operating the main flash +# For v5.2 and below CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y CONFIG_SPIRAM_RODATA=y -CONFIG_SPIRAM_SPEED_80M=y +# For v5.3 and above +CONFIG_SPIRAM_XIP_FROM_PSRAM=y + +# Used in conjunction with "RGB Bounce Buffer" +CONFIG_ESP32S3_DATA_CACHE_LINE_64B=y + +CONFIG_LVGL_PORT_AVOID_TEARING_MODE_3=y diff --git a/test_apps/lvgl_port/sdkconfig.ci.waveshare_esp32_s3_touch_lcd_4_3 b/test_apps/lvgl_port/sdkconfig.ci.waveshare_esp32_s3_touch_lcd_4_3 index 0b31c5f1..d2a84d8c 100644 --- a/test_apps/lvgl_port/sdkconfig.ci.waveshare_esp32_s3_touch_lcd_4_3 +++ b/test_apps/lvgl_port/sdkconfig.ci.waveshare_esp32_s3_touch_lcd_4_3 @@ -1,11 +1,19 @@ CONFIG_IDF_TARGET="esp32s3" +CONFIG_COMPILER_OPTIMIZATION_PERF=y CONFIG_BOARD_MANUFACTURER_ALL=y CONFIG_BOARD_WAVESHARE_ESP32_S3_Touch_LCD_4_3=y CONFIG_SPIRAM=y CONFIG_SPIRAM_MODE_OCT=y +CONFIG_SPIRAM_SPEED_80M=y +# Enable the XIP-PSRAM feature, so the ext-mem cache won't be disabled when SPI1 is operating the main flash +# For v5.2 and below CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y CONFIG_SPIRAM_RODATA=y -CONFIG_SPIRAM_SPEED_80M=y +# For v5.3 and above +CONFIG_SPIRAM_XIP_FROM_PSRAM=y + +# Used in conjunction with "RGB Bounce Buffer" +CONFIG_ESP32S3_DATA_CACHE_LINE_64B=y CONFIG_LVGL_PORT_AVOID_TEARING_MODE_3=y diff --git a/test_apps/panel/main/CMakeLists.txt b/test_apps/panel/main/CMakeLists.txt index 6489599d..ffc7a5dc 100644 --- a/test_apps/panel/main/CMakeLists.txt +++ b/test_apps/panel/main/CMakeLists.txt @@ -1,4 +1,4 @@ idf_component_register( - SRCS "test_app_main.c" "test_panel.cpp" + SRCS "test_app_main.cpp" "test_panel.cpp" WHOLE_ARCHIVE ) diff --git a/test_apps/panel/main/test_app_main.c b/test_apps/panel/main/test_app_main.cpp similarity index 90% rename from test_apps/panel/main/test_app_main.c rename to test_apps/panel/main/test_app_main.cpp index bf8ef112..9b5a6232 100644 --- a/test_apps/panel/main/test_app_main.c +++ b/test_apps/panel/main/test_app_main.cpp @@ -9,9 +9,16 @@ #include "esp_heap_caps.h" #include "unity.h" #include "unity_test_runner.h" +#include "ESP_Panel.h" // Some resources are lazy allocated in the LCD driver, the threadhold is left for that case +#if ESP_PANEL_LCD_BUS_TYPE == ESP_PANEL_BUS_TYPE_MIPI_DSI +#define TEST_MEMORY_LEAK_THRESHOLD (-800) +#elif ESP_PANEL_LCD_BUS_TYPE == ESP_PANEL_BUS_TYPE_RGB +#define TEST_MEMORY_LEAK_THRESHOLD (-500) +#else #define TEST_MEMORY_LEAK_THRESHOLD (-300) +#endif static size_t before_free_8bit; static size_t before_free_32bit; @@ -37,7 +44,7 @@ void tearDown(void) check_leak(before_free_32bit, after_free_32bit, "32BIT"); } -void app_main(void) +extern "C" void app_main(void) { /** * _______ ______ __ __ ________ __ diff --git a/test_apps/panel/main/test_panel.cpp b/test_apps/panel/main/test_panel.cpp index f545cf13..8bc0c810 100644 --- a/test_apps/panel/main/test_panel.cpp +++ b/test_apps/panel/main/test_panel.cpp @@ -13,7 +13,7 @@ #include "ESP_Panel_Library.h" #define TEST_LCD_ENABLE_ATTACH_CALLBACK (0) -#define TEST_LCD_SHOW_TIME_MS (3000) +#define TEST_LCD_SHOW_TIME_MS (5000) #define TEST_TOUCH_ENABLE_ATTACH_CALLBACK (0) #define TEST_TOUCH_READ_POINTS_NUM (5) @@ -74,7 +74,6 @@ TEST_CASE("Test panel to draw color bar and read touch", "[panel]") TEST_ASSERT_TRUE_MESSAGE( lcd->colorBarTest(panel->getLcdWidth(), panel->getLcdHeight()), "LCD color bar test failed" ); - delay(TEST_LCD_SHOW_TIME_MS); } else { ESP_LOGI(TAG, "LCD is not available"); } @@ -84,6 +83,11 @@ TEST_CASE("Test panel to draw color bar and read touch", "[panel]") TEST_ASSERT_TRUE_MESSAGE(backlight->on(), "Backlight on failed"); } + if (lcd != nullptr) { + ESP_LOGI(TAG, "Wait for %d ms to show the color bar", TEST_LCD_SHOW_TIME_MS); + vTaskDelay(pdMS_TO_TICKS(TEST_LCD_SHOW_TIME_MS)); + } + if (touch != nullptr) { #if TEST_LCD_ENABLE_ATTACH_CALLBACK && (ESP_PANEL_TOUCH_IO_INT >= 0) TEST_ASSERT_TRUE_MESSAGE( diff --git a/test_apps/panel/sdkconfig.ci.elecrow_crowpanel_7_0 b/test_apps/panel/sdkconfig.ci.elecrow_crowpanel_7_0 index 7d488c6c..0437db6f 100644 --- a/test_apps/panel/sdkconfig.ci.elecrow_crowpanel_7_0 +++ b/test_apps/panel/sdkconfig.ci.elecrow_crowpanel_7_0 @@ -1,9 +1,17 @@ CONFIG_IDF_TARGET="esp32s3" +CONFIG_COMPILER_OPTIMIZATION_PERF=y CONFIG_BOARD_MANUFACTURER_ALL=y CONFIG_BOARD_ELECROW_CROWPANEL_7_0=y CONFIG_SPIRAM=y CONFIG_SPIRAM_MODE_OCT=y +CONFIG_SPIRAM_SPEED_80M=y +# Enable the XIP-PSRAM feature, so the ext-mem cache won't be disabled when SPI1 is operating the main flash +# For v5.2 and below CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y CONFIG_SPIRAM_RODATA=y -CONFIG_SPIRAM_SPEED_80M=y +# For v5.3 and above +CONFIG_SPIRAM_XIP_FROM_PSRAM=y + +# Used in conjunction with "RGB Bounce Buffer" +CONFIG_ESP32S3_DATA_CACHE_LINE_64B=y diff --git a/test_apps/panel/sdkconfig.ci.espressif_esp32_c3_lcdkit b/test_apps/panel/sdkconfig.ci.espressif_esp32_c3_lcdkit index e81429f1..e887afa1 100644 --- a/test_apps/panel/sdkconfig.ci.espressif_esp32_c3_lcdkit +++ b/test_apps/panel/sdkconfig.ci.espressif_esp32_c3_lcdkit @@ -1,3 +1,4 @@ CONFIG_IDF_TARGET="esp32c3" CONFIG_BOARD_MANUFACTURER_ALL=y CONFIG_BOARD_ESP32_C3_LCDKIT=y +CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y diff --git a/test_apps/panel/sdkconfig.ci.espressif_esp32_p4_function_ev_board b/test_apps/panel/sdkconfig.ci.espressif_esp32_p4_function_ev_board new file mode 100644 index 00000000..c2a39505 --- /dev/null +++ b/test_apps/panel/sdkconfig.ci.espressif_esp32_p4_function_ev_board @@ -0,0 +1,10 @@ +CONFIG_IDF_TARGET="esp32p4" +CONFIG_COMPILER_OPTIMIZATION_PERF=y +CONFIG_BOARD_MANUFACTURER_ALL=y +CONFIG_BOARD_ESP32_P4_FUNCTION_EV_BOARD=y + +CONFIG_SPIRAM=y +CONFIG_SPIRAM_MODE_HEX=y +CONFIG_SPIRAM_SPEED_200M=y +CONFIG_SPIRAM_XIP_FROM_PSRAM=y +CONFIG_IDF_EXPERIMENTAL_FEATURES=y diff --git a/test_apps/panel/sdkconfig.ci.espressif_esp32_s3_box b/test_apps/panel/sdkconfig.ci.espressif_esp32_s3_box index 6e15d03d..696c6d13 100644 --- a/test_apps/panel/sdkconfig.ci.espressif_esp32_s3_box +++ b/test_apps/panel/sdkconfig.ci.espressif_esp32_s3_box @@ -1,9 +1,18 @@ CONFIG_IDF_TARGET="esp32s3" +CONFIG_COMPILER_OPTIMIZATION_PERF=y CONFIG_BOARD_MANUFACTURER_ALL=y CONFIG_BOARD_ESP32_S3_BOX=y +CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y CONFIG_SPIRAM=y CONFIG_SPIRAM_MODE_OCT=y +CONFIG_SPIRAM_SPEED_80M=y +# Enable the XIP-PSRAM feature, so the ext-mem cache won't be disabled when SPI1 is operating the main flash +# For v5.2 and below CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y CONFIG_SPIRAM_RODATA=y -CONFIG_SPIRAM_SPEED_80M=y +# For v5.3 and above +CONFIG_SPIRAM_XIP_FROM_PSRAM=y + +# Used in conjunction with "RGB Bounce Buffer" +CONFIG_ESP32S3_DATA_CACHE_LINE_64B=y diff --git a/test_apps/panel/sdkconfig.ci.espressif_esp32_s3_box_3 b/test_apps/panel/sdkconfig.ci.espressif_esp32_s3_box_3 index efa09e4b..7a0dd29e 100644 --- a/test_apps/panel/sdkconfig.ci.espressif_esp32_s3_box_3 +++ b/test_apps/panel/sdkconfig.ci.espressif_esp32_s3_box_3 @@ -1,9 +1,18 @@ CONFIG_IDF_TARGET="esp32s3" +CONFIG_COMPILER_OPTIMIZATION_PERF=y CONFIG_BOARD_MANUFACTURER_ALL=y CONFIG_BOARD_ESP32_S3_BOX_3=y +CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y CONFIG_SPIRAM=y CONFIG_SPIRAM_MODE_OCT=y +CONFIG_SPIRAM_SPEED_80M=y +# Enable the XIP-PSRAM feature, so the ext-mem cache won't be disabled when SPI1 is operating the main flash +# For v5.2 and below CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y CONFIG_SPIRAM_RODATA=y -CONFIG_SPIRAM_SPEED_80M=y +# For v5.3 and above +CONFIG_SPIRAM_XIP_FROM_PSRAM=y + +# Used in conjunction with "RGB Bounce Buffer" +CONFIG_ESP32S3_DATA_CACHE_LINE_64B=y diff --git a/test_apps/panel/sdkconfig.ci.espressif_esp32_s3_box_3_beta b/test_apps/panel/sdkconfig.ci.espressif_esp32_s3_box_3_beta index e859d720..66661b39 100644 --- a/test_apps/panel/sdkconfig.ci.espressif_esp32_s3_box_3_beta +++ b/test_apps/panel/sdkconfig.ci.espressif_esp32_s3_box_3_beta @@ -1,9 +1,18 @@ CONFIG_IDF_TARGET="esp32s3" +CONFIG_COMPILER_OPTIMIZATION_PERF=y CONFIG_BOARD_MANUFACTURER_ALL=y CONFIG_BOARD_ESP32_S3_BOX_3_BETA=y +CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y CONFIG_SPIRAM=y CONFIG_SPIRAM_MODE_OCT=y +CONFIG_SPIRAM_SPEED_80M=y +# Enable the XIP-PSRAM feature, so the ext-mem cache won't be disabled when SPI1 is operating the main flash +# For v5.2 and below CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y CONFIG_SPIRAM_RODATA=y -CONFIG_SPIRAM_SPEED_80M=y +# For v5.3 and above +CONFIG_SPIRAM_XIP_FROM_PSRAM=y + +# Used in conjunction with "RGB Bounce Buffer" +CONFIG_ESP32S3_DATA_CACHE_LINE_64B=y diff --git a/test_apps/panel/sdkconfig.ci.espressif_esp32_s3_box_lite b/test_apps/panel/sdkconfig.ci.espressif_esp32_s3_box_lite index 5c3fe36e..882bada8 100644 --- a/test_apps/panel/sdkconfig.ci.espressif_esp32_s3_box_lite +++ b/test_apps/panel/sdkconfig.ci.espressif_esp32_s3_box_lite @@ -1,9 +1,18 @@ CONFIG_IDF_TARGET="esp32s3" +CONFIG_COMPILER_OPTIMIZATION_PERF=y CONFIG_BOARD_MANUFACTURER_ALL=y CONFIG_BOARD_ESP32_S3_BOX_LITE=y +CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y CONFIG_SPIRAM=y CONFIG_SPIRAM_MODE_OCT=y +CONFIG_SPIRAM_SPEED_80M=y +# Enable the XIP-PSRAM feature, so the ext-mem cache won't be disabled when SPI1 is operating the main flash +# For v5.2 and below CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y CONFIG_SPIRAM_RODATA=y -CONFIG_SPIRAM_SPEED_80M=y +# For v5.3 and above +CONFIG_SPIRAM_XIP_FROM_PSRAM=y + +# Used in conjunction with "RGB Bounce Buffer" +CONFIG_ESP32S3_DATA_CACHE_LINE_64B=y diff --git a/test_apps/panel/sdkconfig.ci.espressif_esp32_s3_eye b/test_apps/panel/sdkconfig.ci.espressif_esp32_s3_eye index 236bdd7c..86f11b14 100644 --- a/test_apps/panel/sdkconfig.ci.espressif_esp32_s3_eye +++ b/test_apps/panel/sdkconfig.ci.espressif_esp32_s3_eye @@ -1,9 +1,18 @@ CONFIG_IDF_TARGET="esp32s3" +CONFIG_COMPILER_OPTIMIZATION_PERF=y CONFIG_BOARD_MANUFACTURER_ALL=y CONFIG_BOARD_ESP32_S3_EYE=y +CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y CONFIG_SPIRAM=y CONFIG_SPIRAM_MODE_OCT=y +CONFIG_SPIRAM_SPEED_80M=y +# Enable the XIP-PSRAM feature, so the ext-mem cache won't be disabled when SPI1 is operating the main flash +# For v5.2 and below CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y CONFIG_SPIRAM_RODATA=y -CONFIG_SPIRAM_SPEED_80M=y +# For v5.3 and above +CONFIG_SPIRAM_XIP_FROM_PSRAM=y + +# Used in conjunction with "RGB Bounce Buffer" +CONFIG_ESP32S3_DATA_CACHE_LINE_64B=y diff --git a/test_apps/panel/sdkconfig.ci.espressif_esp32_s3_korvo_2 b/test_apps/panel/sdkconfig.ci.espressif_esp32_s3_korvo_2 index ce44a69c..1a5ad395 100644 --- a/test_apps/panel/sdkconfig.ci.espressif_esp32_s3_korvo_2 +++ b/test_apps/panel/sdkconfig.ci.espressif_esp32_s3_korvo_2 @@ -1,9 +1,17 @@ CONFIG_IDF_TARGET="esp32s3" +CONFIG_COMPILER_OPTIMIZATION_PERF=y CONFIG_BOARD_MANUFACTURER_ALL=y CONFIG_BOARD_ESP32_S3_KORVO_2=y CONFIG_SPIRAM=y CONFIG_SPIRAM_MODE_OCT=y +CONFIG_SPIRAM_SPEED_80M=y +# Enable the XIP-PSRAM feature, so the ext-mem cache won't be disabled when SPI1 is operating the main flash +# For v5.2 and below CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y CONFIG_SPIRAM_RODATA=y -CONFIG_SPIRAM_SPEED_80M=y +# For v5.3 and above +CONFIG_SPIRAM_XIP_FROM_PSRAM=y + +# Used in conjunction with "RGB Bounce Buffer" +CONFIG_ESP32S3_DATA_CACHE_LINE_64B=y diff --git a/test_apps/panel/sdkconfig.ci.espressif_esp32_s3_lcd_ev_board b/test_apps/panel/sdkconfig.ci.espressif_esp32_s3_lcd_ev_board index 0246bddb..40c62318 100644 --- a/test_apps/panel/sdkconfig.ci.espressif_esp32_s3_lcd_ev_board +++ b/test_apps/panel/sdkconfig.ci.espressif_esp32_s3_lcd_ev_board @@ -1,9 +1,17 @@ CONFIG_IDF_TARGET="esp32s3" +CONFIG_COMPILER_OPTIMIZATION_PERF=y CONFIG_BOARD_MANUFACTURER_ALL=y CONFIG_BOARD_ESP32_S3_LCD_EV_BOARD=y CONFIG_SPIRAM=y CONFIG_SPIRAM_MODE_OCT=y +CONFIG_SPIRAM_SPEED_80M=y +# Enable the XIP-PSRAM feature, so the ext-mem cache won't be disabled when SPI1 is operating the main flash +# For v5.2 and below CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y CONFIG_SPIRAM_RODATA=y -CONFIG_SPIRAM_SPEED_80M=y +# For v5.3 and above +CONFIG_SPIRAM_XIP_FROM_PSRAM=y + +# Used in conjunction with "RGB Bounce Buffer" +CONFIG_ESP32S3_DATA_CACHE_LINE_64B=y diff --git a/test_apps/panel/sdkconfig.ci.espressif_esp32_s3_lcd_ev_board_2 b/test_apps/panel/sdkconfig.ci.espressif_esp32_s3_lcd_ev_board_2 index 71375001..5ff41467 100644 --- a/test_apps/panel/sdkconfig.ci.espressif_esp32_s3_lcd_ev_board_2 +++ b/test_apps/panel/sdkconfig.ci.espressif_esp32_s3_lcd_ev_board_2 @@ -1,9 +1,17 @@ CONFIG_IDF_TARGET="esp32s3" +CONFIG_COMPILER_OPTIMIZATION_PERF=y CONFIG_BOARD_MANUFACTURER_ALL=y CONFIG_BOARD_ESP32_S3_LCD_EV_BOARD_2=y CONFIG_SPIRAM=y CONFIG_SPIRAM_MODE_OCT=y +CONFIG_SPIRAM_SPEED_80M=y +# Enable the XIP-PSRAM feature, so the ext-mem cache won't be disabled when SPI1 is operating the main flash +# For v5.2 and below CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y CONFIG_SPIRAM_RODATA=y -CONFIG_SPIRAM_SPEED_80M=y +# For v5.3 and above +CONFIG_SPIRAM_XIP_FROM_PSRAM=y + +# Used in conjunction with "RGB Bounce Buffer" +CONFIG_ESP32S3_DATA_CACHE_LINE_64B=y diff --git a/test_apps/panel/sdkconfig.ci.espressif_esp32_s3_lcd_ev_board_2_v1_5 b/test_apps/panel/sdkconfig.ci.espressif_esp32_s3_lcd_ev_board_2_v1_5 index 605f2d29..4a519889 100644 --- a/test_apps/panel/sdkconfig.ci.espressif_esp32_s3_lcd_ev_board_2_v1_5 +++ b/test_apps/panel/sdkconfig.ci.espressif_esp32_s3_lcd_ev_board_2_v1_5 @@ -1,9 +1,17 @@ CONFIG_IDF_TARGET="esp32s3" +CONFIG_COMPILER_OPTIMIZATION_PERF=y CONFIG_BOARD_MANUFACTURER_ALL=y CONFIG_BOARD_ESP32_S3_LCD_EV_BOARD_2_V1_5=y CONFIG_SPIRAM=y CONFIG_SPIRAM_MODE_OCT=y +CONFIG_SPIRAM_SPEED_80M=y +# Enable the XIP-PSRAM feature, so the ext-mem cache won't be disabled when SPI1 is operating the main flash +# For v5.2 and below CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y CONFIG_SPIRAM_RODATA=y -CONFIG_SPIRAM_SPEED_80M=y +# For v5.3 and above +CONFIG_SPIRAM_XIP_FROM_PSRAM=y + +# Used in conjunction with "RGB Bounce Buffer" +CONFIG_ESP32S3_DATA_CACHE_LINE_64B=y diff --git a/test_apps/panel/sdkconfig.ci.espressif_esp32_s3_lcd_ev_board_v1_5 b/test_apps/panel/sdkconfig.ci.espressif_esp32_s3_lcd_ev_board_v1_5 index 3186a9a8..91766341 100644 --- a/test_apps/panel/sdkconfig.ci.espressif_esp32_s3_lcd_ev_board_v1_5 +++ b/test_apps/panel/sdkconfig.ci.espressif_esp32_s3_lcd_ev_board_v1_5 @@ -1,9 +1,17 @@ CONFIG_IDF_TARGET="esp32s3" +CONFIG_COMPILER_OPTIMIZATION_PERF=y CONFIG_BOARD_MANUFACTURER_ALL=y CONFIG_BOARD_ESP32_S3_LCD_EV_BOARD_V1_5=y CONFIG_SPIRAM=y CONFIG_SPIRAM_MODE_OCT=y +CONFIG_SPIRAM_SPEED_80M=y +# Enable the XIP-PSRAM feature, so the ext-mem cache won't be disabled when SPI1 is operating the main flash +# For v5.2 and below CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y CONFIG_SPIRAM_RODATA=y -CONFIG_SPIRAM_SPEED_80M=y +# For v5.3 and above +CONFIG_SPIRAM_XIP_FROM_PSRAM=y + +# Used in conjunction with "RGB Bounce Buffer" +CONFIG_ESP32S3_DATA_CACHE_LINE_64B=y diff --git a/test_apps/panel/sdkconfig.ci.espressif_esp32_s3_usb_otg b/test_apps/panel/sdkconfig.ci.espressif_esp32_s3_usb_otg index 266fd377..9b984dca 100644 --- a/test_apps/panel/sdkconfig.ci.espressif_esp32_s3_usb_otg +++ b/test_apps/panel/sdkconfig.ci.espressif_esp32_s3_usb_otg @@ -1,3 +1,4 @@ CONFIG_IDF_TARGET="esp32s3" +CONFIG_COMPILER_OPTIMIZATION_PERF=y CONFIG_BOARD_MANUFACTURER_ALL=y CONFIG_BOARD_ESP32_S3_USB_OTG=y diff --git a/test_apps/panel/sdkconfig.ci.jingcai_esp32_4848S040C_I_Y_3 b/test_apps/panel/sdkconfig.ci.jingcai_esp32_4848S040C_I_Y_3 index 7904e91b..58cab0c7 100644 --- a/test_apps/panel/sdkconfig.ci.jingcai_esp32_4848S040C_I_Y_3 +++ b/test_apps/panel/sdkconfig.ci.jingcai_esp32_4848S040C_I_Y_3 @@ -1,9 +1,17 @@ CONFIG_IDF_TARGET="esp32s3" +CONFIG_COMPILER_OPTIMIZATION_PERF=y CONFIG_BOARD_MANUFACTURER_ALL=y CONFIG_BOARD_ESP32_4848S040C_I_Y_3=y CONFIG_SPIRAM=y CONFIG_SPIRAM_MODE_OCT=y +CONFIG_SPIRAM_SPEED_80M=y +# Enable the XIP-PSRAM feature, so the ext-mem cache won't be disabled when SPI1 is operating the main flash +# For v5.2 and below CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y CONFIG_SPIRAM_RODATA=y -CONFIG_SPIRAM_SPEED_80M=y +# For v5.3 and above +CONFIG_SPIRAM_XIP_FROM_PSRAM=y + +# Used in conjunction with "RGB Bounce Buffer" +CONFIG_ESP32S3_DATA_CACHE_LINE_64B=y diff --git a/test_apps/panel/sdkconfig.ci.m5stack_m5core2 b/test_apps/panel/sdkconfig.ci.m5stack_m5core2 index ef2f58da..2ea44f44 100644 --- a/test_apps/panel/sdkconfig.ci.m5stack_m5core2 +++ b/test_apps/panel/sdkconfig.ci.m5stack_m5core2 @@ -1,3 +1,4 @@ CONFIG_IDF_TARGET="esp32s3" +CONFIG_COMPILER_OPTIMIZATION_PERF=y CONFIG_BOARD_MANUFACTURER_ALL=y CONFIG_BOARD_M5STACK_M5CORE2=y diff --git a/test_apps/panel/sdkconfig.ci.m5stack_m5core3 b/test_apps/panel/sdkconfig.ci.m5stack_m5core3 index e8126d4b..b19879d1 100644 --- a/test_apps/panel/sdkconfig.ci.m5stack_m5core3 +++ b/test_apps/panel/sdkconfig.ci.m5stack_m5core3 @@ -1,9 +1,18 @@ CONFIG_IDF_TARGET="esp32s3" +CONFIG_COMPILER_OPTIMIZATION_PERF=y CONFIG_BOARD_MANUFACTURER_ALL=y CONFIG_BOARD_M5STACK_M5CORES3=y +CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y CONFIG_SPIRAM=y CONFIG_SPIRAM_MODE_OCT=y +CONFIG_SPIRAM_SPEED_80M=y +# Enable the XIP-PSRAM feature, so the ext-mem cache won't be disabled when SPI1 is operating the main flash +# For v5.2 and below CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y CONFIG_SPIRAM_RODATA=y -CONFIG_SPIRAM_SPEED_80M=y +# For v5.3 and above +CONFIG_SPIRAM_XIP_FROM_PSRAM=y + +# Used in conjunction with "RGB Bounce Buffer" +CONFIG_ESP32S3_DATA_CACHE_LINE_64B=y diff --git a/test_apps/panel/sdkconfig.ci.m5stack_m5dial b/test_apps/panel/sdkconfig.ci.m5stack_m5dial index 89f97068..f01a02e9 100644 --- a/test_apps/panel/sdkconfig.ci.m5stack_m5dial +++ b/test_apps/panel/sdkconfig.ci.m5stack_m5dial @@ -1,9 +1,17 @@ CONFIG_IDF_TARGET="esp32s3" +CONFIG_COMPILER_OPTIMIZATION_PERF=y CONFIG_BOARD_MANUFACTURER_ALL=y CONFIG_BOARD_M5STACK_M5DIAL=y CONFIG_SPIRAM=y CONFIG_SPIRAM_MODE_OCT=y +CONFIG_SPIRAM_SPEED_80M=y +# Enable the XIP-PSRAM feature, so the ext-mem cache won't be disabled when SPI1 is operating the main flash +# For v5.2 and below CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y CONFIG_SPIRAM_RODATA=y -CONFIG_SPIRAM_SPEED_80M=y +# For v5.3 and above +CONFIG_SPIRAM_XIP_FROM_PSRAM=y + +# Used in conjunction with "RGB Bounce Buffer" +CONFIG_ESP32S3_DATA_CACHE_LINE_64B=y diff --git a/test_apps/panel/sdkconfig.ci.waveshare_esp32_s3_touch_lcd_1_85 b/test_apps/panel/sdkconfig.ci.waveshare_esp32_s3_touch_lcd_1_85 index 7848f3e2..5c69a91c 100644 --- a/test_apps/panel/sdkconfig.ci.waveshare_esp32_s3_touch_lcd_1_85 +++ b/test_apps/panel/sdkconfig.ci.waveshare_esp32_s3_touch_lcd_1_85 @@ -1,9 +1,18 @@ CONFIG_IDF_TARGET="esp32s3" +CONFIG_COMPILER_OPTIMIZATION_PERF=y CONFIG_BOARD_MANUFACTURER_ALL=y CONFIG_BOARD_WAVESHARE_ESP32_S3_Touch_LCD_1_85=y +CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y CONFIG_SPIRAM=y CONFIG_SPIRAM_MODE_OCT=y +CONFIG_SPIRAM_SPEED_80M=y +# Enable the XIP-PSRAM feature, so the ext-mem cache won't be disabled when SPI1 is operating the main flash +# For v5.2 and below CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y CONFIG_SPIRAM_RODATA=y -CONFIG_SPIRAM_SPEED_80M=y +# For v5.3 and above +CONFIG_SPIRAM_XIP_FROM_PSRAM=y + +# Used in conjunction with "RGB Bounce Buffer" +CONFIG_ESP32S3_DATA_CACHE_LINE_64B=y diff --git a/test_apps/panel/sdkconfig.ci.waveshare_esp32_s3_touch_lcd_2_1 b/test_apps/panel/sdkconfig.ci.waveshare_esp32_s3_touch_lcd_2_1 index 55839aba..67dcc67b 100644 --- a/test_apps/panel/sdkconfig.ci.waveshare_esp32_s3_touch_lcd_2_1 +++ b/test_apps/panel/sdkconfig.ci.waveshare_esp32_s3_touch_lcd_2_1 @@ -1,9 +1,18 @@ CONFIG_IDF_TARGET="esp32s3" +CONFIG_COMPILER_OPTIMIZATION_PERF=y CONFIG_BOARD_MANUFACTURER_ALL=y CONFIG_BOARD_WAVESHARE_ESP32_S3_Touch_LCD_2_1=y +CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y CONFIG_SPIRAM=y CONFIG_SPIRAM_MODE_OCT=y +CONFIG_SPIRAM_SPEED_80M=y +# Enable the XIP-PSRAM feature, so the ext-mem cache won't be disabled when SPI1 is operating the main flash +# For v5.2 and below CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y CONFIG_SPIRAM_RODATA=y -CONFIG_SPIRAM_SPEED_80M=y +# For v5.3 and above +CONFIG_SPIRAM_XIP_FROM_PSRAM=y + +# Used in conjunction with "RGB Bounce Buffer" +CONFIG_ESP32S3_DATA_CACHE_LINE_64B=y diff --git a/test_apps/panel/sdkconfig.ci.waveshare_esp32_s3_touch_lcd_4_3 b/test_apps/panel/sdkconfig.ci.waveshare_esp32_s3_touch_lcd_4_3 index 9cdf5a34..faac3260 100644 --- a/test_apps/panel/sdkconfig.ci.waveshare_esp32_s3_touch_lcd_4_3 +++ b/test_apps/panel/sdkconfig.ci.waveshare_esp32_s3_touch_lcd_4_3 @@ -1,9 +1,17 @@ CONFIG_IDF_TARGET="esp32s3" +CONFIG_COMPILER_OPTIMIZATION_PERF=y CONFIG_BOARD_MANUFACTURER_ALL=y CONFIG_BOARD_WAVESHARE_ESP32_S3_Touch_LCD_4_3=y CONFIG_SPIRAM=y CONFIG_SPIRAM_MODE_OCT=y +CONFIG_SPIRAM_SPEED_80M=y +# Enable the XIP-PSRAM feature, so the ext-mem cache won't be disabled when SPI1 is operating the main flash +# For v5.2 and below CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y CONFIG_SPIRAM_RODATA=y -CONFIG_SPIRAM_SPEED_80M=y +# For v5.3 and above +CONFIG_SPIRAM_XIP_FROM_PSRAM=y + +# Used in conjunction with "RGB Bounce Buffer" +CONFIG_ESP32S3_DATA_CACHE_LINE_64B=y diff --git a/test_apps/touch/i2c/main/test_i2c_touch.cpp b/test_apps/touch/i2c/main/test_i2c_touch.cpp index 741d7272..067f0543 100644 --- a/test_apps/touch/i2c/main/test_i2c_touch.cpp +++ b/test_apps/touch/i2c/main/test_i2c_touch.cpp @@ -14,6 +14,7 @@ using namespace std; +/* The following default configurations are for the board 'Espressif: ESP32_S3_LCD_EV_BOARD_V1_5, GT1151' */ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// Please update the following configuration according to your touch_device spec //////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -29,11 +30,11 @@ using namespace std; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// Please update the following configuration according to your board spec //////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#define TEST_TOUCH_PIN_NUM_I2C_SCL (10) -#define TEST_TOUCH_PIN_NUM_I2C_SDA (9) -#define TEST_TOUCH_PIN_NUM_RST (13) // Set to `-1` if not used +#define TEST_TOUCH_PIN_NUM_I2C_SCL (48) +#define TEST_TOUCH_PIN_NUM_I2C_SDA (47) +#define TEST_TOUCH_PIN_NUM_RST (-1) // Set to `-1` if not used // For GT911, the RST pin is also used to configure the I2C address -#define TEST_TOUCH_PIN_NUM_INT (14) // Set to `-1` if not used +#define TEST_TOUCH_PIN_NUM_INT (-1) // Set to `-1` if not used // For GT911, the INT pin is also used to configure the I2C address #define TEST_READ_TOUCH_DELAY_MS (30) @@ -60,6 +61,8 @@ static void run_test(shared_ptr touch_device) touch_device->attachInterruptCallback(onTouchInterruptCallback, NULL); #endif + ESP_LOGI(TAG, "Reading touch_device point..."); + uint32_t t = 0; while (t++ < TEST_READ_TOUCH_TIME_MS / TEST_READ_TOUCH_DELAY_MS) { ESP_PanelTouchPoint point[TEST_TOUCH_READ_POINTS_NUM]; @@ -114,6 +117,7 @@ static void run_test(shared_ptr touch_device) CREATE_TEST_CASE(CST816S) CREATE_TEST_CASE(FT5x06) CREATE_TEST_CASE(GT1151) +CREATE_TEST_CASE(GT911) CREATE_TEST_CASE(TT21100) CREATE_TEST_CASE(ST1633) CREATE_TEST_CASE(ST7123) diff --git a/test_apps/touch/spi/main/test_spi_touch.cpp b/test_apps/touch/spi/main/test_spi_touch.cpp index 319b81da..3eef989c 100644 --- a/test_apps/touch/spi/main/test_spi_touch.cpp +++ b/test_apps/touch/spi/main/test_spi_touch.cpp @@ -14,6 +14,7 @@ using namespace std; +/* The following default configurations are for the board 'Espressif: Custom, XPT2046' */ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// Please update the following configuration according to your touch_device spec //////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -56,6 +57,8 @@ static void run_test(shared_ptr touch_device) touch_device->attachInterruptCallback(onTouchInterruptCallback, NULL); #endif + ESP_LOGI(TAG, "Reading touch_device point..."); + uint32_t t = 0; while (t++ < TEST_READ_TOUCH_TIME_MS / TEST_READ_TOUCH_DELAY_MS) { ESP_PanelTouchPoint point[TEST_TOUCH_READ_POINTS_NUM];