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];