From 1a4ffbb8401be9b8dd2e18394b79fcafba1c4cf1 Mon Sep 17 00:00:00 2001 From: Liu Zhongwei Date: Mon, 23 Dec 2024 17:16:25 +0800 Subject: [PATCH] feat(examples): update arduino Phone --- docs/how_to_use.md | 2 +- docs/how_to_use_CN.md | 2 +- .../arduino/Phone/ESP_Panel_Board_Custom.h | 50 ++- .../arduino/Phone/ESP_Panel_Board_Supported.h | 32 +- examples/arduino/Phone/Phone.ino | 17 +- examples/arduino/Phone/README.md | 13 +- examples/arduino/Phone/README_CN.md | 13 +- examples/arduino/Phone/lvgl_port_v8.cpp | 334 +++++++++++++----- test_apps/main/test_esp_brookesia_phone.cpp | 27 +- 9 files changed, 353 insertions(+), 137 deletions(-) diff --git a/docs/how_to_use.md b/docs/how_to_use.md index b1e4964..d1d416e 100644 --- a/docs/how_to_use.md +++ b/docs/how_to_use.md @@ -100,7 +100,7 @@ Users can access them by navigating to `File` > `Examples` > `esp-brookesia` in Here are examples of using esp-brookesia on the Arduino development platform: -- [ESP_Brookesia_Phone](../examples/arduino/ESP_Brookesia_Phone): This example demonstrates how to run the Phone UI using the [ESP32_Display_Panel](https://github.com/esp-arduino-libs/ESP32_Display_Panel) library. +- [Phone](../examples/arduino/Phone): This example demonstrates how to run the Phone UI using the [ESP32_Display_Panel](https://github.com/esp-arduino-libs/ESP32_Display_Panel) library. ## App Development diff --git a/docs/how_to_use_CN.md b/docs/how_to_use_CN.md index 1fe7149..058e5e7 100644 --- a/docs/how_to_use_CN.md +++ b/docs/how_to_use_CN.md @@ -100,7 +100,7 @@ idf.py add-dependency "espressif/esp-brookesia" 以下是在 Arduino 开发平台下使用 esp-brookesia 的示例: -- [ESP_Brookesia_Phone](../examples/arduino/ESP_Brookesia_Phone): 此示例演示了如何使用 [ESP32_Display_Panel](https://github.com/esp-arduino-libs/ESP32_Display_Panel) 库运行 Phone UI。 +- [Phone](../examples/arduino/Phone): 此示例演示了如何使用 [ESP32_Display_Panel](https://github.com/esp-arduino-libs/ESP32_Display_Panel) 库运行 Phone UI。 ## App 开发 diff --git a/examples/arduino/Phone/ESP_Panel_Board_Custom.h b/examples/arduino/Phone/ESP_Panel_Board_Custom.h index 4ee0c09..003b092 100644 --- a/examples/arduino/Phone/ESP_Panel_Board_Custom.h +++ b/examples/arduino/Phone/ESP_Panel_Board_Custom.h @@ -25,6 +25,7 @@ * - EK9716B * - GC9A01, GC9B71, GC9503 * - ILI9341 + * - JD9365 * - NV3022B * - SH8601 * - SPD2010 @@ -110,8 +111,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 +120,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 +156,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." @@ -176,18 +190,20 @@ * 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), \ -// } +/* +#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 */ @@ -378,8 +394,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 2 +#define ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_MINOR 3 +#define ESP_PANEL_BOARD_CUSTOM_FILE_VERSION_PATCH 1 #endif /* ESP_PANEL_USE_CUSTOM_BOARD */ diff --git a/examples/arduino/Phone/ESP_Panel_Board_Supported.h b/examples/arduino/Phone/ESP_Panel_Board_Supported.h index a1b8821..ba8fba0 100644 --- a/examples/arduino/Phone/ESP_Panel_Board_Supported.h +++ b/examples/arduino/Phone/ESP_Panel_Board_Supported.h @@ -26,11 +26,12 @@ * - BOARD_ESP32_S3_BOX_LITE (ESP32-S3-Box-Lite): https://github.com/espressif/esp-box/tree/master * - BOARD_ESP32_S3_EYE (ESP32-S3-EYE): https://github.com/espressif/esp-who/blob/master/docs/en/get-started/ESP32-S3-EYE_Getting_Started_Guide.md * - BOARD_ESP32_S3_KORVO_2 (ESP32-S3-Korvo-2): https://docs.espressif.com/projects/esp-adf/en/latest/design-guide/dev-boards/user-guide-esp32-s3-korvo-2.html - * - BOARD_ESP32_S3_LCD_EV_BOARD (ESP32-S3-LCD-EV-Board): 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 (ESP32-S3-LCD-EV-Board(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_V1_5 (ESP32-S3-LCD-EV-Board(v1.5)): https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32s3/esp32-s3-lcd-ev-board/user_guide.html - * - BOARD_ESP32_S3_LCD_EV_BOARD_2 (ESP32-S3-LCD-EV-Board-2)): 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 (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): @@ -56,9 +58,9 @@ /* * M5Stack (https://m5stack.com/): * - * - BOARD_M5STACK_M5CORE2 (M5STACK_M5CORE2): https://docs.m5stack.com/zh_CN/core/core2 - * - BOARD_M5STACK_M5DIAL (M5STACK_M5DIAL): https://docs.m5stack.com/zh_CN/core/M5Dial - * - BOARD_M5STACK_M5CORES3 (M5STACK_M5CORES3): https://docs.m5stack.com/zh_CN/core/CoreS3 + * - BOARD_M5STACK_M5CORE2 (M5STACK_M5CORE2): https://docs.m5stack.com/en/core/core2 + * - BOARD_M5STACK_M5DIAL (M5STACK_M5DIAL): https://docs.m5stack.com/en/core/M5Dial + * - BOARD_M5STACK_M5CORES3 (M5STACK_M5CORES3): https://docs.m5stack.com/en/core/CoreS3 */ // #define BOARD_M5STACK_M5CORE2 // #define BOARD_M5STACK_M5DIAL @@ -77,11 +79,23 @@ /* * Waveshare Supported Boards (https://www.waveshare.com/): * - * - ESP32_S3_Touch_LCD_4_3: - * - https://www.waveshare.com/esp32-s3-touch-lcd-4.3.htm - * + * - BOARD_WAVESHARE_ESP32_S3_Touch_LCD_1_85 (ESP32_S3_Touch_LCD_1_85): https://www.waveshare.com/esp32-s3-touch-lcd-1.85.htm + * - BOARD_WAVESHARE_ESP32_S3_Touch_LCD_2_1 (ESP32_S3_Touch_LCD_2_1): https://www.waveshare.com/esp32-s3-touch-lcd-2.1.htm + * - BOARD_WAVESHARE_ESP32_S3_Touch_LCD_4_3 (ESP32_S3_Touch_LCD_4_3): https://www.waveshare.com/esp32-s3-touch-lcd-4.3.htm + * - BOARD_WAVESHARE_ESP32_S3_Touch_LCD_4_3_B (ESP32_S3_Touch_LCD_4_3_B): https://www.waveshare.com/esp32-s3-touch-lcd-4.3B.htm + * - BOARD_WAVESHARE_ESP32_S3_Touch_LCD_5 (ESP32_S3_Touch_LCD_5): https://www.waveshare.com/esp32-s3-touch-lcd-5.htm?sku=28117 + * - BOARD_WAVESHARE_ESP32_S3_Touch_LCD_5_B (ESP32_S3_Touch_LCD_5_B): https://www.waveshare.com/esp32-s3-touch-lcd-5.htm?sku=28151 + * - BOARD_WAVESHARE_ESP32_S3_Touch_LCD_7 (ESP32_S3_Touch_LCD_7): https://www.waveshare.com/esp32-s3-touch-lcd-7.htm + * - BOARD_WAVESHARE_ESP32_P4_NANO (ESP32_P4_NANO): https://www.waveshare.com/esp32-p4-nano.htm */ +// #define BOARD_WAVESHARE_ESP32_S3_Touch_LCD_1_85 +// #define BOARD_WAVESHARE_ESP32_S3_Touch_LCD_2_1 // #define BOARD_WAVESHARE_ESP32_S3_Touch_LCD_4_3 +// #define BOARD_WAVESHARE_ESP32_S3_Touch_LCD_4_3_B +// #define BOARD_WAVESHARE_ESP32_S3_Touch_LCD_5 +// #define BOARD_WAVESHARE_ESP32_S3_Touch_LCD_5_B +// #define BOARD_WAVESHARE_ESP32_S3_Touch_LCD_7 +// #define BOARD_WAVESHARE_ESP32_P4_NANO //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////// File Version /////////////////////////////////////////////////////////// @@ -98,7 +112,7 @@ * */ #define ESP_PANEL_BOARD_SUPPORTED_FILE_VERSION_MAJOR 0 -#define ESP_PANEL_BOARD_SUPPORTED_FILE_VERSION_MINOR 3 +#define ESP_PANEL_BOARD_SUPPORTED_FILE_VERSION_MINOR 7 #define ESP_PANEL_BOARD_SUPPORTED_FILE_VERSION_PATCH 0 #endif diff --git a/examples/arduino/Phone/Phone.ino b/examples/arduino/Phone/Phone.ino index a5e2654..0e0bc56 100644 --- a/examples/arduino/Phone/Phone.ino +++ b/examples/arduino/Phone/Phone.ino @@ -10,28 +10,29 @@ * * To use this example, please firstly install the following dependent libraries: * - * - ESP32_Display_Panel (0.1.*) + * - ESP32_Display_Panel (0.2.*) + * - ESP32_IO_Expander (0.1.*) * - lvgl (>= v8.3.9, < v9) * * Then, follow the steps below to configure the libraries and upload the example: * * 1. For **esp-brookesia**: * - * - [optional] Follow the [steps](../../../README.md#configuration-instructions-1) to configure the library. + * - [optional] Follow the [steps](https://github.com/espressif/esp-brookesia/blob/master/docs/how_to_use.md#configuration-instructions-1) to configure the library. * * 2. For **ESP32_Display_Panel**: * - * - [optional] Follow the [steps](https://github.com/esp-arduino-libs/ESP32_Display_Panel?tab=readme-ov-file#configuring-drivers) to configure drivers. - * - [mandatory] If using a supported development board, follow the [steps](https://github.com/esp-arduino-libs/ESP32_Display_Panel?tab=readme-ov-file#using-supported-development-boards) to configure it. - * - [mandatory] If using a custom board, follow the [steps](https://github.com/esp-arduino-libs/ESP32_Display_Panel?tab=readme-ov-file#using-custom-development-boards) to configure it. + * - [optional] 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. + * - [mandatory] 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. + * - [mandatory] 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. * * 3. For **lvgl**: * - * - [optional] Follow the [steps](https://github.com/esp-arduino-libs/ESP32_Display_Panel?tab=readme-ov-file#configuring-lvgl) to add *lv_conf.h* file and change the configurations. + * - [mandatory] 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. * - [mandatory] Enable the `LV_USE_SNAPSHOT` macro in the *lv_conf.h* file. * - [optional] Modify the macros in the [lvgl_port_v8.h](./lvgl_port_v8.h) file to configure the lvgl porting parameters. * - * 4. Navigate to the `Tools` menu in the Arduino IDE to choose a ESP board and configure its parameters. **Please ensure that the size of APP partition in the partition table is enough (e.g. 2 MB)**. For supported boards, please refter to [Configuring Supported Development Boards](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/Board_Instructions.md#recommended-configurations-in-the-arduino-ide) + * 4. Navigate to the `Tools` menu in the Arduino IDE to choose a ESP board and configure its parameters. **Please ensure that the size of APP partition in the partition table is enough (e.g. 4 MB)**. For supported 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) * 5. Verify and upload the example to the ESP board. * * ## Technical Support and Feedback @@ -65,6 +66,8 @@ #define EXAMPLE_ESP_BROOKESIA_PHONE_DARK_STYLESHEET() ESP_BROOKESIA_PHONE_320_480_DARK_STYLESHEET() #elif (ESP_PANEL_LCD_WIDTH == 480) && (ESP_PANEL_LCD_HEIGHT == 480) #define EXAMPLE_ESP_BROOKESIA_PHONE_DARK_STYLESHEET() ESP_BROOKESIA_PHONE_480_480_DARK_STYLESHEET() +#elif (ESP_PANEL_LCD_WIDTH == 720) && (ESP_PANEL_LCD_HEIGHT == 1280) + #define EXAMPLE_ESP_BROOKESIA_PHONE_DARK_STYLESHEET() ESP_BROOKESIA_PHONE_720_1280_DARK_STYLESHEET() #elif (ESP_PANEL_LCD_WIDTH == 800) && (ESP_PANEL_LCD_HEIGHT == 480) #define EXAMPLE_ESP_BROOKESIA_PHONE_DARK_STYLESHEET() ESP_BROOKESIA_PHONE_800_480_DARK_STYLESHEET() #elif (ESP_PANEL_LCD_WIDTH == 800) && (ESP_PANEL_LCD_HEIGHT == 1280) diff --git a/examples/arduino/Phone/README.md b/examples/arduino/Phone/README.md index b5f6a96..16b7237 100644 --- a/examples/arduino/Phone/README.md +++ b/examples/arduino/Phone/README.md @@ -8,7 +8,8 @@ The example is suitable for touchscreens with a resolution of `240 x 240` or hig To use this example, please firstly install the following dependent libraries: -- ESP32_Display_Panel (0.1.5) +- ESP32_Display_Panel (0.2.*) +- ESP32_IO_Expander (0.1.*) - lvgl (>= v8.3.9, < v9) Then, follow the steps below to configure the libraries and upload the example: @@ -19,17 +20,17 @@ Then, follow the steps below to configure the libraries and upload the example: 2. For **ESP32_Display_Panel**: - - [optional] Follow the [steps](https://github.com/esp-arduino-libs/ESP32_Display_Panel?tab=readme-ov-file#configuring-drivers) to configure drivers. - - [mandatory] If using a supported development board, follow the [steps](https://github.com/esp-arduino-libs/ESP32_Display_Panel?tab=readme-ov-file#using-supported-development-boards) to configure it. - - [mandatory] If using a custom board, follow the [steps](https://github.com/esp-arduino-libs/ESP32_Display_Panel?tab=readme-ov-file#using-custom-development-boards) to configure it. + - [optional] 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. + - [mandatory] 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. + - [mandatory] 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. 3. For **lvgl**: - - [optional] Follow the [steps](https://github.com/esp-arduino-libs/ESP32_Display_Panel?tab=readme-ov-file#configuring-lvgl) to add *lv_conf.h* file and change the configurations. + - [mandatory] 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. - [mandatory] Enable the `LV_USE_SNAPSHOT` macro in the *lv_conf.h* file. - [optional] Modify the macros in the [lvgl_port_v8.h](./lvgl_port_v8.h) file to configure the lvgl porting parameters. -4. Navigate to the `Tools` menu in the Arduino IDE to choose a ESP board and configure its parameters. **Please ensure that the size of APP partition in the partition table is enough (e.g. 2 MB)**. For supported boards, please refter to [Configuring Supported Development Boards](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/Board_Instructions.md#recommended-configurations-in-the-arduino-ide) +4. Navigate to the `Tools` menu in the Arduino IDE to choose a ESP board and configure its parameters. **Please ensure that the size of APP partition in the partition table is enough (e.g. 4 MB)**. For supported 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) 5. Verify and upload the example to the ESP board. ## Technical Support and Feedback diff --git a/examples/arduino/Phone/README_CN.md b/examples/arduino/Phone/README_CN.md index 6a33b09..a6c1eb2 100644 --- a/examples/arduino/Phone/README_CN.md +++ b/examples/arduino/Phone/README_CN.md @@ -8,7 +8,8 @@ 要使用此示例,请首先安装以下依赖库: -- ESP32_Display_Panel (0.1.5) +- ESP32_Display_Panel (0.2.1) +- ESP32_IO_Expander (0.1.0) - lvgl (>= v8.3.9, < v9) 然后,按照以下步骤配置库并上传示例: @@ -19,17 +20,17 @@ 2. 对于 **ESP32_Display_Panel**: - - [可选] 按照[步骤](https://github.com/esp-arduino-libs/ESP32_Display_Panel?tab=readme-ov-file#configuring-drivers)配置驱动程序。 - - [必需] 如果使用受支持的开发板,请按照[步骤](https://github.com/esp-arduino-libs/ESP32_Display_Panel?tab=readme-ov-file#using-supported-development-boards)配置它。 - - [必需] 如果使用自定义开发板,请按照[步骤](https://github.com/esp-arduino-libs/ESP32_Display_Panel?tab=readme-ov-file#using-custom-development-boards)配置它。 + - [可选] 按照[步骤](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/How_To_Use.md#configuring-drivers)配置驱动程序。 + - [必需] 如果使用受支持的开发板,请按照[步骤](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/How_To_Use.md#using-supported-development-boards)配置它。 + - [必需] 如果使用自定义开发板,请按照[步骤](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/How_To_Use.md#using-custom-development-boards)配置它。 3. 对于 **lvgl**: - - [可选] 按照[步骤](https://github.com/esp-arduino-libs/ESP32_Display_Panel?tab=readme-ov-file#configuring-lvgl)添加 *lv_conf.h* 文件并更改配置。 + - [必需] 按照[步骤](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/How_To_Use.md#configuring-lvgl)添加 *lv_conf.h* 文件并更改配置。 - [必需] 在 *lv_conf.h* 文件中使能 `LV_USE_SNAPSHOT` 宏。 - [可选] 修改 [lvgl_port_v8.h](./lvgl_port_v8.h) 文件中的宏,以配置 lvgl 端口参数。 -4. 在 Arduino IDE 中导航到 `工具` 菜单,选择 ESP 板并配置其参数。**请确保分区表中 APP 分区足够大(如 2 MB)**。对于受支持的板,请参阅[配置受支持的开发板](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/Board_Instructions.md#recommended-configurations-in-the-arduino-ide)。 +4. 在 Arduino IDE 中导航到 `工具` 菜单,选择 ESP 板并配置其参数。**请确保分区表中 APP 分区足够大(如 4 MB)**。对于受支持的板,请参阅[配置受支持的开发板](https://github.com/esp-arduino-libs/ESP32_Display_Panel/blob/master/docs/How_To_Use.md#configuring-supported-development-boards)。 5. 验证并将示例上传到 ESP 板。 ## 技术支持与反馈 diff --git a/examples/arduino/Phone/lvgl_port_v8.cpp b/examples/arduino/Phone/lvgl_port_v8.cpp index cfd9f29..7173f33 100644 --- a/examples/arduino/Phone/lvgl_port_v8.cpp +++ b/examples/arduino/Phone/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/test_apps/main/test_esp_brookesia_phone.cpp b/test_apps/main/test_esp_brookesia_phone.cpp index 519706a..507dd45 100644 --- a/test_apps/main/test_esp_brookesia_phone.cpp +++ b/test_apps/main/test_esp_brookesia_phone.cpp @@ -20,14 +20,23 @@ #define TEST_LVGL_RESOLUTION_HEIGHT CONFIG_TEST_LVGL_RESOLUTION_HEIGHT #define TEST_INSTALL_UNINSTALL_APP_TIMES (10) -#if (TEST_LVGL_RESOLUTION_WIDTH == 1024) && (TEST_LVGL_RESOLUTION_HEIGHT == 600) -#define EXAMPLE_ESP_BROOKESIA_PHONE_DARK_STYLESHEET() ESP_BROOKESIA_PHONE_1024_600_DARK_STYLESHEET() -#elif (TEST_LVGL_RESOLUTION_WIDTH == 800) && (TEST_LVGL_RESOLUTION_HEIGHT == 480) -#define EXAMPLE_ESP_BROOKESIA_PHONE_DARK_STYLESHEET() ESP_BROOKESIA_PHONE_800_480_DARK_STYLESHEET() +/* Try using a stylesheet that corresponds to the resolution */ +#if (TEST_LVGL_RESOLUTION_WIDTH == 320) && (TEST_LVGL_RESOLUTION_HEIGHT == 240) + #define TEST_ESP_BROOKESIA_PHONE_DARK_STYLESHEET() ESP_BROOKESIA_PHONE_320_240_DARK_STYLESHEET() +#elif (TEST_LVGL_RESOLUTION_WIDTH == 320) && (TEST_LVGL_RESOLUTION_HEIGHT == 480) + #define TEST_ESP_BROOKESIA_PHONE_DARK_STYLESHEET() ESP_BROOKESIA_PHONE_320_480_DARK_STYLESHEET() #elif (TEST_LVGL_RESOLUTION_WIDTH == 480) && (TEST_LVGL_RESOLUTION_HEIGHT == 480) -#define EXAMPLE_ESP_BROOKESIA_PHONE_DARK_STYLESHEET() ESP_BROOKESIA_PHONE_480_480_DARK_STYLESHEET() -#elif (TEST_LVGL_RESOLUTION_WIDTH == 320) && (TEST_LVGL_RESOLUTION_HEIGHT == 240) -#define EXAMPLE_ESP_BROOKESIA_PHONE_DARK_STYLESHEET() ESP_BROOKESIA_PHONE_320_240_DARK_STYLESHEET() + #define TEST_ESP_BROOKESIA_PHONE_DARK_STYLESHEET() ESP_BROOKESIA_PHONE_480_480_DARK_STYLESHEET() +#elif (TEST_LVGL_RESOLUTION_WIDTH == 720) && (TEST_LVGL_RESOLUTION_HEIGHT == 1280) + #define TEST_ESP_BROOKESIA_PHONE_DARK_STYLESHEET() ESP_BROOKESIA_PHONE_720_1280_DARK_STYLESHEET() +#elif (TEST_LVGL_RESOLUTION_WIDTH == 800) && (TEST_LVGL_RESOLUTION_HEIGHT == 480) + #define TEST_ESP_BROOKESIA_PHONE_DARK_STYLESHEET() ESP_BROOKESIA_PHONE_800_480_DARK_STYLESHEET() +#elif (TEST_LVGL_RESOLUTION_WIDTH == 800) && (TEST_LVGL_RESOLUTION_HEIGHT == 1280) + #define TEST_ESP_BROOKESIA_PHONE_DARK_STYLESHEET() ESP_BROOKESIA_PHONE_800_1280_DARK_STYLESHEET() +#elif (TEST_LVGL_RESOLUTION_WIDTH == 1024) && (TEST_LVGL_RESOLUTION_HEIGHT == 600) + #define TEST_ESP_BROOKESIA_PHONE_DARK_STYLESHEET() ESP_BROOKESIA_PHONE_1024_600_DARK_STYLESHEET() +#elif (TEST_LVGL_RESOLUTION_WIDTH == 1280) && (TEST_LVGL_RESOLUTION_HEIGHT == 800) + #define TEST_ESP_BROOKESIA_PHONE_DARK_STYLESHEET() ESP_BROOKESIA_PHONE_1280_800_DARK_STYLESHEET() #endif static const char *TAG = "test_esp_brookesia_phone"; @@ -64,7 +73,7 @@ TEST_CASE("test esp-brookesia to begin and delete", "[esp-brookesia][phone][begi test_lvgl_deinit(); } -#ifdef EXAMPLE_ESP_BROOKESIA_PHONE_DARK_STYLESHEET +#ifdef TEST_ESP_BROOKESIA_PHONE_DARK_STYLESHEET TEST_CASE("test esp-brookesia to add stylesheet", "[esp-brookesia][phone][add_stylesheet]") { lv_disp_t *disp = nullptr; @@ -75,7 +84,7 @@ TEST_CASE("test esp-brookesia to add stylesheet", "[esp-brookesia][phone][add_st test_lvgl_init(&disp, &tp); phone = test_esp_brookesia_phone_init(disp, tp, false); - phone_stylesheet = new ESP_Brookesia_PhoneStylesheet_t EXAMPLE_ESP_BROOKESIA_PHONE_DARK_STYLESHEET(); + phone_stylesheet = new ESP_Brookesia_PhoneStylesheet_t TEST_ESP_BROOKESIA_PHONE_DARK_STYLESHEET(); TEST_ASSERT_TRUE_MESSAGE(phone->addStylesheet(phone_stylesheet), "Failed to add phone stylesheet"); TEST_ASSERT_TRUE_MESSAGE(phone->activateStylesheet(phone_stylesheet), "Failed to active phone stylesheet"); delete phone_stylesheet;