From f31a55221328e88d2ae1154b65238a8a13a31aac Mon Sep 17 00:00:00 2001 From: lvhaiyu Date: Mon, 12 Aug 2024 12:58:55 +0800 Subject: [PATCH] feat(lcd): LCD component version update --- .github/workflows/upload_component.yml | 1 + .gitlab/ci/build.yml | 10 + .gitlab/ci/rules.yml | 14 + components/.build-rules.yml | 4 + .../display/lcd/esp_lcd_ek79007/CHANGELOG.md | 6 + .../display/lcd/esp_lcd_ek79007/README.md | 2 + .../lcd/esp_lcd_ek79007/esp_lcd_ek79007.c | 63 ++- .../lcd/esp_lcd_ek79007/idf_component.yml | 4 +- .../esp_lcd_ek79007/include/esp_lcd_ek79007.h | 16 +- .../test_apps/main/test_esp_lcd_ek79007.c | 5 +- .../test_apps/pytest_esp_lcd_st7701.py | 9 - .../display/lcd/esp_lcd_gc9b71/CHANGELOG.md | 6 + .../display/lcd/esp_lcd_gc9b71/README.md | 2 + .../lcd/esp_lcd_gc9b71/idf_component.yml | 4 +- .../test_apps/main/test_esp_lcd_gc9b71.c | 31 ++ .../display/lcd/esp_lcd_hx8399/CHANGELOG.md | 7 + .../display/lcd/esp_lcd_hx8399/CMakeLists.txt | 7 + .../display/lcd/esp_lcd_hx8399/README.md | 78 ++++ .../lcd/esp_lcd_hx8399/esp_lcd_hx8399.c | 316 +++++++++++++++ .../lcd/esp_lcd_hx8399/idf_component.yml | 11 + .../esp_lcd_hx8399/include/esp_lcd_hx8399.h | 119 ++++++ .../display/lcd/esp_lcd_hx8399/license.txt | 201 ++++++++++ .../esp_lcd_hx8399/test_apps/CMakeLists.txt | 6 + .../test_apps/main/CMakeLists.txt | 1 + .../test_apps/main/idf_component.yml | 5 + .../test_apps/main/test_esp_lcd_hx8399.c | 245 ++++++++++++ .../test_apps/sdkconfig.defaults | 3 + .../test_apps/sdkconfig.defaults.esp32p4 | 4 + .../display/lcd/esp_lcd_jd9165/CHANGELOG.md | 6 + .../display/lcd/esp_lcd_jd9165/README.md | 2 + .../lcd/esp_lcd_jd9165/esp_lcd_jd9165.c | 16 - .../lcd/esp_lcd_jd9165/idf_component.yml | 4 +- .../esp_lcd_jd9165/include/esp_lcd_jd9165.h | 15 - .../test_apps/main/test_esp_lcd_jd9165.c | 34 +- .../display/lcd/esp_lcd_jd9365/CHANGELOG.md | 6 + .../display/lcd/esp_lcd_jd9365/README.md | 2 + .../lcd/esp_lcd_jd9365/esp_lcd_jd9365.c | 19 +- .../lcd/esp_lcd_jd9365/idf_component.yml | 4 +- .../esp_lcd_jd9365/include/esp_lcd_jd9365.h | 15 - .../test_apps/main/test_esp_lcd_jd9365.c | 34 +- .../display/lcd/esp_lcd_nv3022b/CHANGELOG.md | 6 + .../display/lcd/esp_lcd_nv3022b/README.md | 2 + .../lcd/esp_lcd_nv3022b/idf_component.yml | 4 +- .../test_apps/main/test_esp_lcd_nv3022b.c | 4 + .../display/lcd/esp_lcd_sh8601/CHANGELOG.md | 6 + .../lcd/esp_lcd_sh8601/idf_component.yml | 2 +- .../test_apps/main/test_esp_lcd_sh8601.c | 31 ++ .../display/lcd/esp_lcd_spd2010/CHANGELOG.md | 6 + .../display/lcd/esp_lcd_spd2010/README.md | 2 + .../lcd/esp_lcd_spd2010/idf_component.yml | 4 +- .../test_apps/main/test_esp_lcd_spd2010.c | 31 ++ .../display/lcd/esp_lcd_st7701/README.md | 2 + .../lcd/esp_lcd_st7701/esp_lcd_st7701_mipi.c | 16 - .../lcd/esp_lcd_st7701/idf_component.yml | 2 +- .../lcd/esp_lcd_st77903_qspi/CHANGELOG.md | 6 + .../lcd/esp_lcd_st77903_qspi/README.md | 2 + .../esp_lcd_st77903_qspi/idf_component.yml | 2 +- .../lcd/esp_lcd_st77903_rgb/CHANGELOG.md | 6 + .../display/lcd/esp_lcd_st77903_rgb/README.md | 2 + .../lcd/esp_lcd_st77903_rgb/idf_component.yml | 2 +- .../display/lcd/esp_lcd_st77916/CHANGELOG.md | 6 + .../display/lcd/esp_lcd_st77916/README.md | 2 + .../lcd/esp_lcd_st77916/idf_component.yml | 4 +- .../display/lcd/esp_lcd_st77922/CHANGELOG.md | 4 + .../lcd/esp_lcd_st77922/CMakeLists.txt | 2 +- .../display/lcd/esp_lcd_st77922/README.md | 85 +++- .../lcd/esp_lcd_st77922/esp_lcd_st77922.c | 24 +- .../esp_lcd_st77922/esp_lcd_st77922_mipi.c | 369 ++++++++++++++++++ .../lcd/esp_lcd_st77922/idf_component.yml | 4 +- .../esp_lcd_st77922/include/esp_lcd_st77922.h | 77 +++- .../priv_include/st77922_interface.h | 15 + .../main/test_esp_lcd_st77922_mipi.c | 249 ++++++++++++ .../test_apps/sdkconfig.defaults.esp32p4 | 5 + .../lcd/esp_lcd_usb_display/CHANGELOG.md | 6 + .../lcd/esp_lcd_usb_display/idf_component.yml | 2 +- .../esp_lcd_touch_spd2010/CHANGELOG.md | 6 + .../esp_lcd_touch_spd2010/idf_component.yml | 2 +- .../esp_lcd_touch_st7123/CHANGELOG.md | 6 + .../esp_lcd_touch_st7123/idf_component.yml | 2 +- docs/en/display/lcd/lcd_development_guide.rst | 2 +- .../display/lcd/lcd_development_guide.rst | 2 +- 81 files changed, 2120 insertions(+), 229 deletions(-) delete mode 100644 components/display/lcd/esp_lcd_ek79007/test_apps/pytest_esp_lcd_st7701.py create mode 100644 components/display/lcd/esp_lcd_hx8399/CHANGELOG.md create mode 100644 components/display/lcd/esp_lcd_hx8399/CMakeLists.txt create mode 100644 components/display/lcd/esp_lcd_hx8399/README.md create mode 100644 components/display/lcd/esp_lcd_hx8399/esp_lcd_hx8399.c create mode 100644 components/display/lcd/esp_lcd_hx8399/idf_component.yml create mode 100644 components/display/lcd/esp_lcd_hx8399/include/esp_lcd_hx8399.h create mode 100644 components/display/lcd/esp_lcd_hx8399/license.txt create mode 100644 components/display/lcd/esp_lcd_hx8399/test_apps/CMakeLists.txt create mode 100644 components/display/lcd/esp_lcd_hx8399/test_apps/main/CMakeLists.txt create mode 100644 components/display/lcd/esp_lcd_hx8399/test_apps/main/idf_component.yml create mode 100644 components/display/lcd/esp_lcd_hx8399/test_apps/main/test_esp_lcd_hx8399.c create mode 100644 components/display/lcd/esp_lcd_hx8399/test_apps/sdkconfig.defaults create mode 100644 components/display/lcd/esp_lcd_hx8399/test_apps/sdkconfig.defaults.esp32p4 create mode 100644 components/display/lcd/esp_lcd_st77922/esp_lcd_st77922_mipi.c create mode 100644 components/display/lcd/esp_lcd_st77922/test_apps/main/test_esp_lcd_st77922_mipi.c create mode 100644 components/display/lcd/esp_lcd_st77922/test_apps/sdkconfig.defaults.esp32p4 diff --git a/.github/workflows/upload_component.yml b/.github/workflows/upload_component.yml index ec6fc36fb..1b9fd5ee6 100644 --- a/.github/workflows/upload_component.yml +++ b/.github/workflows/upload_component.yml @@ -31,6 +31,7 @@ jobs: components/display/lcd/esp_lcd_jd9165; components/display/lcd/esp_lcd_jd9365; components/display/lcd/esp_lcd_gc9b71; + components/display/lcd/esp_lcd_hx8399; components/display/lcd/esp_lcd_panel_io_additions; components/display/lcd/esp_lcd_nv3022b; components/display/lcd/esp_lcd_sh8601; diff --git a/.gitlab/ci/build.yml b/.gitlab/ci/build.yml index 96e2e03e1..fe2c22cf8 100644 --- a/.gitlab/ci/build.yml +++ b/.gitlab/ci/build.yml @@ -871,6 +871,16 @@ build_components_display_lcd_esp_lcd_gc9b71_test_apps: variables: EXAMPLE_DIR: components/display/lcd/esp_lcd_gc9b71/test_apps +build_components_display_lcd_esp_lcd_hx8399_test_apps: + extends: + - .build_examples_template + - .rules:build:components_display_lcd_esp_lcd_hx8399_test_apps + parallel: + matrix: + - IMAGE: espressif/idf:release-v5.3 + variables: + EXAMPLE_DIR: components/display/lcd/esp_lcd_hx8399/test_apps + build_components_display_lcd_esp_lcd_panel_io_additions_test_apps: extends: - .build_examples_template diff --git a/.gitlab/ci/rules.yml b/.gitlab/ci/rules.yml index df5675cfa..89b3bcaf7 100644 --- a/.gitlab/ci/rules.yml +++ b/.gitlab/ci/rules.yml @@ -88,6 +88,9 @@ .patterns-components_display_lcd_esp_lcd_gc9b71: &patterns-components_display_lcd_esp_lcd_gc9b71 - "components/display/lcd/esp_lcd_gc9b71/**/*" +.patterns-components_display_lcd_esp_lcd_hx8399: &patterns-components_display_lcd_esp_lcd_hx8399 + - "components/display/lcd/esp_lcd_hx8399/**/*" + .patterns-components_display_lcd_esp_lcd_panel_io_additions: &patterns-components_display_lcd_esp_lcd_panel_io_additions - "components/display/lcd/esp_lcd_panel_io_additions/**/*" @@ -1534,6 +1537,17 @@ - <<: *if-dev-push changes: *patterns-components_display_lcd_esp_lcd_gc9b71 +.rules:build:components_display_lcd_esp_lcd_hx8399_test_apps: + 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-components_display_lcd_esp_lcd_hx8399 + .rules:build:components_display_lcd_esp_lcd_panel_io_additions_test_apps: rules: - <<: *if-protected diff --git a/components/.build-rules.yml b/components/.build-rules.yml index 235b89c5c..11fd7654c 100644 --- a/components/.build-rules.yml +++ b/components/.build-rules.yml @@ -82,6 +82,10 @@ components/display/lcd/esp_lcd_gc9b71/test_apps: enable: - if: INCLUDE_DEFAULT == 1 +components/display/lcd/esp_lcd_hx8399/test_apps: + enable: + - if: IDF_TARGET in ["esp32p4"] + components/display/lcd/esp_lcd_panel_io_additions/test_apps: enable: - if: IDF_TARGET in ["esp32s3"] diff --git a/components/display/lcd/esp_lcd_ek79007/CHANGELOG.md b/components/display/lcd/esp_lcd_ek79007/CHANGELOG.md index 926e08b5d..bfab4d386 100644 --- a/components/display/lcd/esp_lcd_ek79007/CHANGELOG.md +++ b/components/display/lcd/esp_lcd_ek79007/CHANGELOG.md @@ -1,5 +1,11 @@ # ChangeLog +## v1.0.0 - 2024-08-12 + +### Enhancements: + +* Component version maintenance, code improvement, and documentation enhancement + ## v0.1.0 - 2024-05-07 ### Enhancements: diff --git a/components/display/lcd/esp_lcd_ek79007/README.md b/components/display/lcd/esp_lcd_ek79007/README.md index 27165d4b9..e465c6170 100644 --- a/components/display/lcd/esp_lcd_ek79007/README.md +++ b/components/display/lcd/esp_lcd_ek79007/README.md @@ -10,6 +10,8 @@ Implementation of the EK79007 LCD controller with esp_lcd component. **Note**: MIPI-DSI interface only supports ESP-IDF v5.3 and above versions. +For more information on LCD, please refer to the [LCD documentation](https://docs.espressif.com/projects/esp-iot-solution/en/latest/display/lcd/index.html). + ## Add to project Packages from this repository are uploaded to [Espressif's component service](https://components.espressif.com/). diff --git a/components/display/lcd/esp_lcd_ek79007/esp_lcd_ek79007.c b/components/display/lcd/esp_lcd_ek79007/esp_lcd_ek79007.c index 4080b0dd9..99463e69d 100644 --- a/components/display/lcd/esp_lcd_ek79007/esp_lcd_ek79007.c +++ b/components/display/lcd/esp_lcd_ek79007/esp_lcd_ek79007.c @@ -17,14 +17,21 @@ #include "esp_log.h" #include "esp_lcd_ek79007.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 ek79007_lcd_init_cmd_t *init_cmds; uint16_t init_cmds_size; + uint8_t lane_num; struct { unsigned int reset_level: 1; } flags; @@ -42,7 +49,6 @@ 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); -static esp_err_t panel_ek79007_disp_on_off(esp_lcd_panel_t *panel, bool on_off); 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) @@ -69,8 +75,10 @@ esp_err_t esp_lcd_new_panel_ek79007(const esp_lcd_panel_io_handle_t io, const es 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, @@ -86,7 +94,6 @@ esp_err_t esp_lcd_new_panel_ek79007(const esp_lcd_panel_io_handle_t io, const es (*ret_panel)->reset = panel_ek79007_reset; (*ret_panel)->mirror = panel_ek79007_mirror; (*ret_panel)->invert_color = panel_ek79007_invert_color; - (*ret_panel)->disp_on_off = panel_ek79007_disp_on_off; (*ret_panel)->user_data = ek79007; ESP_LOGD(TAG, "new ek79007 panel @%p", ek79007); @@ -111,7 +118,6 @@ static const ek79007_lcd_init_cmd_t vendor_specific_init_default[] = { {0x84, (uint8_t []){0xA8}, 1, 0}, {0x85, (uint8_t []){0xE3}, 1, 0}, {0x86, (uint8_t []){0x88}, 1, 0}, - {0xB2, (uint8_t []){0x10}, 1, 0}, {0x11, (uint8_t []){0x00}, 0, 120}, }; @@ -120,6 +126,24 @@ static esp_err_t panel_ek79007_send_init_cmds(ek79007_panel_t *ek79007) esp_lcd_panel_io_handle_t io = ek79007->io; const ek79007_lcd_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 @@ -132,11 +156,30 @@ static esp_err_t panel_ek79007_send_init_cmds(ek79007_panel_t *ek79007) } 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"); + 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; @@ -190,7 +233,7 @@ static esp_err_t panel_ek79007_mirror(esp_lcd_panel_t *panel, bool mirror_x, boo { ek79007_panel_t *ek79007 = (ek79007_panel_t *)panel->user_data; esp_lcd_panel_io_handle_t io = ek79007->io; - uint8_t madctl_val = 0x01; + uint8_t madctl_val = ek79007->madctl_val; ESP_RETURN_ON_FALSE(io, ESP_ERR_INVALID_STATE, TAG, "invalid panel IO"); @@ -209,6 +252,7 @@ static esp_err_t panel_ek79007_mirror(esp_lcd_panel_t *panel, bool mirror_x, boo 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; } @@ -230,10 +274,3 @@ static esp_err_t panel_ek79007_invert_color(esp_lcd_panel_t *panel, bool invert_ return ESP_OK; } - -static esp_err_t panel_ek79007_disp_on_off(esp_lcd_panel_t *panel, bool on_off) -{ - ESP_LOGE(TAG, "display on/off is not supported"); - - return ESP_ERR_NOT_SUPPORTED; -} diff --git a/components/display/lcd/esp_lcd_ek79007/idf_component.yml b/components/display/lcd/esp_lcd_ek79007/idf_component.yml index 38c9d6acf..5426ef0f5 100644 --- a/components/display/lcd/esp_lcd_ek79007/idf_component.yml +++ b/components/display/lcd/esp_lcd_ek79007/idf_component.yml @@ -1,7 +1,7 @@ -version: "0.1.0" +version: "1.0.0" targets: - esp32p4 -description: ESP LCD EK79007 +description: ESP LCD EK79007(MIPI-DSI) url: https://github.com/espressif/esp-iot-solution/tree/master/components/display/lcd/esp_lcd_ek79007 repository: https://github.com/espressif/esp-iot-solution.git issues: https://github.com/espressif/esp-iot-solution/issues diff --git a/components/display/lcd/esp_lcd_ek79007/include/esp_lcd_ek79007.h b/components/display/lcd/esp_lcd_ek79007/include/esp_lcd_ek79007.h index a0c33bc22..8585d866d 100644 --- a/components/display/lcd/esp_lcd_ek79007/include/esp_lcd_ek79007.h +++ b/components/display/lcd/esp_lcd_ek79007/include/esp_lcd_ek79007.h @@ -43,22 +43,8 @@ typedef struct { struct { esp_lcd_dsi_bus_handle_t dsi_bus; /*!< MIPI-DSI bus configuration */ const esp_lcd_dpi_panel_config_t *dpi_config; /*!< MIPI-DPI panel configuration */ + uint8_t lane_num; /*!< Number of MIPI-DSI lanes, defaults to 2 if set to 0 */ } mipi_config; - struct { - unsigned int use_mipi_interface: 1; /* None: - dut.run_all_single_board_cases() diff --git a/components/display/lcd/esp_lcd_gc9b71/CHANGELOG.md b/components/display/lcd/esp_lcd_gc9b71/CHANGELOG.md index 56d5f93e5..71d6a5964 100644 --- a/components/display/lcd/esp_lcd_gc9b71/CHANGELOG.md +++ b/components/display/lcd/esp_lcd_gc9b71/CHANGELOG.md @@ -1,5 +1,11 @@ # ChangeLog +## v1.0.2 - 2024-08-12 + +### Enhancements: + +* Component version maintenance, code improvement, and documentation enhancement + ## v0.0.1 - 2023-08-22 ### Enhancements: diff --git a/components/display/lcd/esp_lcd_gc9b71/README.md b/components/display/lcd/esp_lcd_gc9b71/README.md index a880077c5..a78c17e74 100644 --- a/components/display/lcd/esp_lcd_gc9b71/README.md +++ b/components/display/lcd/esp_lcd_gc9b71/README.md @@ -8,6 +8,8 @@ Implementation of the GC9B71 LCD controller with [esp_lcd](https://docs.espressi | :------------: | :---------------------: | :------------: | :---------------------------------------------------------------------------: | | GC9B71 | SPI/QSPI | esp_lcd_gc9b71 | [PDF](https://dl.espressif.com/AE/esp-iot-solution/GC9B71_DataSheet_V1.0.pdf) | +For more information on LCD, please refer to the [LCD documentation](https://docs.espressif.com/projects/esp-iot-solution/en/latest/display/lcd/index.html). + ## Add to project Packages from this repository are uploaded to [Espressif's component service](https://components.espressif.com/). diff --git a/components/display/lcd/esp_lcd_gc9b71/idf_component.yml b/components/display/lcd/esp_lcd_gc9b71/idf_component.yml index a09066572..8b4b6b00e 100644 --- a/components/display/lcd/esp_lcd_gc9b71/idf_component.yml +++ b/components/display/lcd/esp_lcd_gc9b71/idf_component.yml @@ -1,5 +1,5 @@ -version: "1.0.1" -description: ESP LCD GC9B71 +version: "1.0.2" +description: ESP LCD GC9B71(SPI & QSPI) url: https://github.com/espressif/esp-iot-solution/tree/master/components/display/lcd/esp_lcd_gc9b71 repository: https://github.com/espressif/esp-iot-solution.git issues: https://github.com/espressif/esp-iot-solution/issues diff --git a/components/display/lcd/esp_lcd_gc9b71/test_apps/main/test_esp_lcd_gc9b71.c b/components/display/lcd/esp_lcd_gc9b71/test_apps/main/test_esp_lcd_gc9b71.c index e0592daf9..4b3ccb79f 100644 --- a/components/display/lcd/esp_lcd_gc9b71/test_apps/main/test_esp_lcd_gc9b71.c +++ b/components/display/lcd/esp_lcd_gc9b71/test_apps/main/test_esp_lcd_gc9b71.c @@ -34,6 +34,9 @@ #define TEST_PIN_NUM_LCD_DATA3 (GPIO_NUM_14) #define TEST_PIN_NUM_LCD_RST (GPIO_NUM_17) #define TEST_PIN_NUM_LCD_DC (GPIO_NUM_8) +#define TEST_PIN_NUM_BK_LIGHT (GPIO_NUM_0) // 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 #define TEST_DELAY_TIME_MS (3000) @@ -74,6 +77,16 @@ IRAM_ATTR static void test_draw_bitmap(esp_lcd_panel_handle_t panel_handle) TEST_CASE("test gc9b71 to draw color bar with SPI interface", "[gc9b71][spi]") { +#if TEST_PIN_NUM_BK_LIGHT >= 0 + ESP_LOGI(TAG, "Turn on LCD backlight"); + gpio_config_t bk_gpio_config = { + .mode = GPIO_MODE_OUTPUT, + .pin_bit_mask = 1ULL << TEST_PIN_NUM_BK_LIGHT + }; + TEST_ESP_OK(gpio_config(&bk_gpio_config)); + TEST_ESP_OK(gpio_set_level(TEST_PIN_NUM_BK_LIGHT, TEST_LCD_BK_LIGHT_ON_LEVEL)); +#endif + ESP_LOGI(TAG, "Initialize SPI bus"); const spi_bus_config_t buscfg = GC9B71_PANEL_BUS_SPI_CONFIG(TEST_PIN_NUM_LCD_PCLK, TEST_PIN_NUM_LCD_DATA0, @@ -104,10 +117,24 @@ TEST_CASE("test gc9b71 to draw color bar with SPI interface", "[gc9b71][spi]") TEST_ESP_OK(esp_lcd_panel_del(panel_handle)); TEST_ESP_OK(esp_lcd_panel_io_del(io_handle)); TEST_ESP_OK(spi_bus_free(TEST_LCD_HOST)); + +#if TEST_PIN_NUM_BK_LIGHT >= 0 + TEST_ESP_OK(gpio_reset_pin(TEST_PIN_NUM_BK_LIGHT)); +#endif } TEST_CASE("test gc9b71 to draw color bar with QSPI interface", "[gc9b71][qspi]") { +#if TEST_PIN_NUM_BK_LIGHT >= 0 + ESP_LOGI(TAG, "Turn on LCD backlight"); + gpio_config_t bk_gpio_config = { + .mode = GPIO_MODE_OUTPUT, + .pin_bit_mask = 1ULL << TEST_PIN_NUM_BK_LIGHT + }; + TEST_ESP_OK(gpio_config(&bk_gpio_config)); + TEST_ESP_OK(gpio_set_level(TEST_PIN_NUM_BK_LIGHT, TEST_LCD_BK_LIGHT_ON_LEVEL)); +#endif + ESP_LOGI(TAG, "Initialize SPI bus"); const spi_bus_config_t buscfg = GC9B71_PANEL_BUS_QSPI_CONFIG(TEST_PIN_NUM_LCD_PCLK, TEST_PIN_NUM_LCD_DATA0, @@ -146,6 +173,10 @@ TEST_CASE("test gc9b71 to draw color bar with QSPI interface", "[gc9b71][qspi]") TEST_ESP_OK(esp_lcd_panel_del(panel_handle)); TEST_ESP_OK(esp_lcd_panel_io_del(io_handle)); TEST_ESP_OK(spi_bus_free(TEST_LCD_HOST)); + +#if TEST_PIN_NUM_BK_LIGHT >= 0 + TEST_ESP_OK(gpio_reset_pin(TEST_PIN_NUM_BK_LIGHT)); +#endif } // Some resources are lazy allocated in the LCD driver, the threadhold is left for that case diff --git a/components/display/lcd/esp_lcd_hx8399/CHANGELOG.md b/components/display/lcd/esp_lcd_hx8399/CHANGELOG.md new file mode 100644 index 000000000..91327313e --- /dev/null +++ b/components/display/lcd/esp_lcd_hx8399/CHANGELOG.md @@ -0,0 +1,7 @@ +# ChangeLog + +## v1.0.0 - 2024-06-14 + +### Enhancements: + +* Implement the driver for the HX8399 MIPI-DSI LCD controller \ No newline at end of file diff --git a/components/display/lcd/esp_lcd_hx8399/CMakeLists.txt b/components/display/lcd/esp_lcd_hx8399/CMakeLists.txt new file mode 100644 index 000000000..f3f7e8eaf --- /dev/null +++ b/components/display/lcd/esp_lcd_hx8399/CMakeLists.txt @@ -0,0 +1,7 @@ +idf_component_register(SRCS "esp_lcd_hx8399.c" + INCLUDE_DIRS "include" + REQUIRES "esp_lcd" + PRIV_REQUIRES "esp_driver_gpio") + +include(package_manager) +cu_pkg_define_version(${CMAKE_CURRENT_LIST_DIR}) diff --git a/components/display/lcd/esp_lcd_hx8399/README.md b/components/display/lcd/esp_lcd_hx8399/README.md new file mode 100644 index 000000000..cd68e40bb --- /dev/null +++ b/components/display/lcd/esp_lcd_hx8399/README.md @@ -0,0 +1,78 @@ +# ESP LCD HX8399 + +[![Component Registry](https://components.espressif.com/components/espressif/esp_lcd_hx8399/badge.svg)](https://components.espressif.com/components/espressif/esp_lcd_hx8399) + +Implementation of the HX8399 LCD controller with esp_lcd component. + +| LCD controller | Communication interface | Component name | Link to datasheet | +| :------------: | :---------------------: | :------------: | :-----------------------------------------------------------------------------------: | +| HX8399 | MIPI-DSI | esp_lcd_hx8399 | [PDF](https://dl.espressif.com/AE/esp-iot-solution/HX8399DA-H3_DS_V0.01_20200819.pdf) | + +**Note**: MIPI-DSI interface only supports ESP-IDF v5.3 and above versions. + +For more information on LCD, please refer to the [LCD documentation](https://docs.espressif.com/projects/esp-iot-solution/en/latest/display/lcd/index.html). + +## Add to project + +Packages from this repository are uploaded to [Espressif's component service](https://components.espressif.com/). +You can add them to your project via `idf.py add-dependancy`, e.g. + +``` + idf.py add-dependency "espressif/esp_lcd_hx8399" +``` + +Alternatively, you can create `idf_component.yml`. More is in [Espressif's documentation](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/tools/idf-component-manager.html). + +## Example use + +```c +/** + * Uncomment these line if use custom initialization commands. + * The array should be declared as static const and positioned outside the function. + */ +// static const hx8399_lcd_init_cmd_t lcd_init_cmds[] = { +// {cmd, { data }, data_size, delay_ms} +// {0x11, (uint8_t []){0x00}, 120, 0}, +// {0x29, (uint8_t []){0x00}, 20, 0}, +// ... +// }; + + ESP_LOGI(TAG, "MIPI DSI PHY Powered on"); + esp_ldo_channel_handle_t ldo_mipi_phy = NULL; + esp_ldo_channel_config_t ldo_mipi_phy_config = { + .chan_id = 3, + .voltage_mv = 2500, + }; + ESP_ERROR_CHECK(esp_ldo_acquire_channel(&ldo_mipi_phy_config, &ldo_mipi_phy)); + + ESP_LOGI(TAG, "Initialize MIPI DSI bus"); + esp_lcd_dsi_bus_handle_t mipi_dsi_bus = NULL; + esp_lcd_dsi_bus_config_t bus_config = HX8399_PANEL_BUS_DSI_2CH_CONFIG(); + ESP_ERROR_CHECK(esp_lcd_new_dsi_bus(&bus_config, &mipi_dsi_bus)); + + ESP_LOGI(TAG, "Install panel IO"); + esp_lcd_panel_io_handle_t mipi_dbi_io = NULL; + esp_lcd_dbi_io_config_t dbi_config = HX8399_PANEL_IO_DBI_CONFIG(); + ESP_ERROR_CHECK(esp_lcd_new_panel_io_dbi(mipi_dsi_bus, &dbi_config, &mipi_dbi_io)); + + ESP_LOGI(TAG, "Install HX8399 panel driver"); + esp_lcd_panel_handle_t panel_handle = NULL; + const esp_lcd_dpi_panel_config_t dpi_config = HX8399_1024_600_PANEL_30HZ_DPI_CONFIG(EXAMPLE_MIPI_DPI_PX_FORMAT); + hx8399_vendor_config_t vendor_config = { + .flags = { + .use_mipi_interface = 1, + }, + .mipi_config = { + .dsi_bus = mipi_dsi_bus, + .dpi_config = &dpi_config, + }, + }; + const esp_lcd_panel_dev_config_t panel_config = { + .reset_gpio_num = EXAMPLE_LCD_IO_RST, // Set to -1 if not use + .rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB, // Implemented by LCD command `36h` + .bits_per_pixel = EXAMPLE_LCD_BIT_PER_PIXEL, // Implemented by LCD command `3Ah` (16/18/24) + .vendor_config = &vendor_config, + }; + ESP_ERROR_CHECK(esp_lcd_new_panel_hx8399(mipi_dbi_io, &panel_config, &panel_handle)); + ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle)); +``` diff --git a/components/display/lcd/esp_lcd_hx8399/esp_lcd_hx8399.c b/components/display/lcd/esp_lcd_hx8399/esp_lcd_hx8399.c new file mode 100644 index 000000000..a45921ede --- /dev/null +++ b/components/display/lcd/esp_lcd_hx8399/esp_lcd_hx8399.c @@ -0,0 +1,316 @@ +/* + * 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_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_hx8399.h" + +#define HX8399_CMD_DSI_INT0 (0xBA) +#define HX8399_DSI_1_LANE (0x00) +#define HX8399_DSI_2_LANE (0x01) +#define HX8399_DSI_3_LANE (0x10) +#define HX8399_DSI_4_LANE (0x11) + +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 hx8399_lcd_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); +} hx8399_panel_t; + +static const char *TAG = "hx8399"; + +static esp_err_t panel_hx8399_del(esp_lcd_panel_t *panel); +static esp_err_t panel_hx8399_init(esp_lcd_panel_t *panel); +static esp_err_t panel_hx8399_reset(esp_lcd_panel_t *panel); +static esp_err_t panel_hx8399_invert_color(esp_lcd_panel_t *panel, bool invert_color_data); +static esp_err_t panel_hx8399_disp_on_off(esp_lcd_panel_t *panel, bool on_off); + +esp_err_t esp_lcd_new_panel_hx8399(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_LOGI(TAG, "version: %d.%d.%d", ESP_LCD_HX8399_VER_MAJOR, ESP_LCD_HX8399_VER_MINOR, + ESP_LCD_HX8399_VER_PATCH); + ESP_RETURN_ON_FALSE(io && panel_dev_config && ret_panel, ESP_ERR_INVALID_ARG, TAG, "invalid arguments"); + hx8399_vendor_config_t *vendor_config = (hx8399_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; + hx8399_panel_t *hx8399 = (hx8399_panel_t *)calloc(1, sizeof(hx8399_panel_t)); + ESP_RETURN_ON_FALSE(hx8399, ESP_ERR_NO_MEM, TAG, "no mem for hx8399 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->color_space) { + case LCD_RGB_ELEMENT_ORDER_RGB: + hx8399->madctl_val = 0; + break; + case LCD_RGB_ELEMENT_ORDER_BGR: + hx8399->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 + hx8399->colmod_val = 0x55; + break; + case 18: // RGB666 + hx8399->colmod_val = 0x66; + break; + case 24: // RGB888 + hx8399->colmod_val = 0x77; + break; + default: + ESP_GOTO_ON_FALSE(false, ESP_ERR_NOT_SUPPORTED, err, TAG, "unsupported pixel width"); + break; + } + + hx8399->io = io; + hx8399->init_cmds = vendor_config->init_cmds; + hx8399->init_cmds_size = vendor_config->init_cmds_size; + hx8399->lane_num = vendor_config->mipi_config.lane_num; + hx8399->reset_gpio_num = panel_dev_config->reset_gpio_num; + hx8399->flags.reset_level = panel_dev_config->flags.reset_active_high; + + // Create MIPI DPI panel + esp_lcd_panel_handle_t panel_handle = NULL; + ESP_GOTO_ON_ERROR(esp_lcd_new_panel_dpi(vendor_config->mipi_config.dsi_bus, vendor_config->mipi_config.dpi_config, &panel_handle), err, TAG, + "create MIPI DPI panel failed"); + ESP_LOGD(TAG, "new MIPI DPI panel @%p", panel_handle); + + // Save the original functions of MIPI DPI panel + hx8399->del = panel_handle->del; + hx8399->init = panel_handle->init; + // Overwrite the functions of MIPI DPI panel + panel_handle->del = panel_hx8399_del; + panel_handle->init = panel_hx8399_init; + panel_handle->reset = panel_hx8399_reset; + panel_handle->invert_color = panel_hx8399_invert_color; + panel_handle->disp_on_off = panel_hx8399_disp_on_off; + panel_handle->user_data = hx8399; + *ret_panel = panel_handle; + ESP_LOGD(TAG, "new hx8399 panel @%p", hx8399); + + return ESP_OK; + +err: + if (hx8399) { + if (panel_dev_config->reset_gpio_num >= 0) { + gpio_reset_pin(panel_dev_config->reset_gpio_num); + } + free(hx8399); + } + return ret; +} + +static const hx8399_lcd_init_cmd_t vendor_specific_init_code_default[] = { + // {cmd, { data }, data_size, delay_ms} + {0xB9, (uint8_t []){0xFF, 0x83, 0x99}, 3, 0}, + {0xD2, (uint8_t []){0x77}, 1, 0}, + {0xB1, (uint8_t []){0x02, 0x04, 0x74, 0x94, 0x01, 0x32, 0x33, 0x11, 0x11, 0xAB, 0x4D, 0x56, 0x73, 0x02, 0x02}, 15, 0}, + {0xB2, (uint8_t []){0x00, 0x80, 0x80, 0xAE, 0x05, 0x07, 0x5A, 0x11, 0x00, 0x00, 0x10, 0x1E, 0x70, 0x03, 0xD4}, 15, 0}, + {0xB4, (uint8_t []){0x00, 0xFF, 0x02, 0xC0, 0x02, 0xC0, 0x00, 0x00, 0x08, 0x00, 0x04, 0x06, 0x00, 0x32, 0x04, 0x0A, 0x08, 0x21, 0x03, 0x01, 0x00, 0x0F, 0xB8, 0x8B, 0x02, 0xC0, 0x02, 0xC0, 0x00, 0x00, 0x08, 0x00, 0x04, 0x06, 0x00, 0x32, 0x04, 0x0A, 0x08, 0x01, 0x00, 0x0F, 0xB8, 0x01}, 44, 0}, + {0xD3, (uint8_t []){0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x10, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x05, 0x05, 0x07, 0x00, 0x00, 0x00, 0x05, 0x40}, 33, 10}, + {0xD5, (uint8_t []){0x18, 0x18, 0x19, 0x19, 0x18, 0x18, 0x21, 0x20, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x2F, 0x2F, 0x30, 0x30, 0x31, 0x31, 0x18, 0x18, 0x18, 0x18}, 32, 10}, + {0xD6, (uint8_t []){0x18, 0x18, 0x19, 0x19, 0x40, 0x40, 0x20, 0x21, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x2F, 0x2F, 0x30, 0x30, 0x31, 0x31, 0x40, 0x40, 0x40, 0x40}, 32, 10}, + {0xD8, (uint8_t []){0xA2, 0xAA, 0x02, 0xA0, 0xA2, 0xA8, 0x02, 0xA0, 0xB0, 0x00, 0x00, 0x00, 0xB0, 0x00, 0x00, 0x00}, 16, 0}, + {0xBD, (uint8_t []){0x01}, 1, 0}, + {0xD8, (uint8_t []){0xB0, 0x00, 0x00, 0x00, 0xB0, 0x00, 0x00, 0x00, 0xE2, 0xAA, 0x03, 0xF0, 0xE2, 0xAA, 0x03, 0xF0}, 16, 0}, + {0xBD, (uint8_t []){0x02}, 1, 0}, + {0xD8, (uint8_t []){0xE2, 0xAA, 0x03, 0xF0, 0xE2, 0xAA, 0x03, 0xF0}, 8, 0}, + {0xBD, (uint8_t []){0x00}, 1, 0}, + {0xB6, (uint8_t []){0x8D, 0x8D}, 2, 0}, + {0xE0, (uint8_t []){0x00, 0x0E, 0x19, 0x13, 0x2E, 0x39, 0x48, 0x44, 0x4D, 0x57, 0x5F, 0x66, 0x6C, 0x76, 0x7F, 0x85, 0x8A, 0x95, 0x9A, 0xA4, 0x9B, 0xAB, 0xB0, 0x5C, 0x58, 0x64, 0x77, 0x00, 0x0E, 0x19, 0x13, 0x2E, 0x39, 0x48, 0x44, 0x4D, 0x57, 0x5F, 0x66, 0x6C, 0x76, 0x7F, 0x85, 0x8A, 0x95, 0x9A, 0xA4, 0x9B, 0xAB, 0xB0, 0x5C, 0x58, 0x64, 0x77}, 54, 10}, + {0xCC, (uint8_t []){0x08}, 1, 0}, + //============ Gamma END=========== +}; + +static esp_err_t panel_hx8399_del(esp_lcd_panel_t *panel) +{ + hx8399_panel_t *hx8399 = (hx8399_panel_t *)panel->user_data; + + if (hx8399->reset_gpio_num >= 0) { + gpio_reset_pin(hx8399->reset_gpio_num); + } + // Delete MIPI DPI panel + hx8399->del(panel); + free(hx8399); + ESP_LOGD(TAG, "del hx8399 panel @%p", hx8399); + + return ESP_OK; +} + +static esp_err_t panel_hx8399_init(esp_lcd_panel_t *panel) +{ + hx8399_panel_t *hx8399 = (hx8399_panel_t *)panel->user_data; + esp_lcd_panel_io_handle_t io = hx8399->io; + const hx8399_lcd_init_cmd_t *init_cmds = NULL; + uint16_t init_cmds_size = 0; + uint8_t lane_command = HX8399_DSI_2_LANE; + bool is_cmd_overwritten = false; + + switch (hx8399->lane_num) { + case 0: + lane_command = HX8399_DSI_2_LANE; + break; + case 1: + lane_command = HX8399_DSI_1_LANE; + break; + case 2: + lane_command = HX8399_DSI_2_LANE; + break; + case 3: + lane_command = HX8399_DSI_3_LANE; + break; + case 4: + lane_command = HX8399_DSI_4_LANE; + break; + default: + ESP_LOGE(TAG, "Invalid lane number %d", hx8399->lane_num); + return ESP_ERR_INVALID_ARG; + } + + 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[]) { + hx8399->madctl_val, + }, 1), TAG, "send command failed"); + ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, LCD_CMD_COLMOD, (uint8_t[]) { + hx8399->colmod_val, + }, 1), TAG, "send command failed"); + ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, HX8399_CMD_DSI_INT0, (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 (hx8399->init_cmds) { + init_cmds = hx8399->init_cmds; + init_cmds_size = hx8399->init_cmds_size; + } else { + init_cmds = vendor_specific_init_code_default; + init_cmds_size = sizeof(vendor_specific_init_code_default) / sizeof(hx8399_lcd_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; + hx8399->madctl_val = ((uint8_t *)init_cmds[i].data)[0]; + break; + case LCD_CMD_COLMOD: + is_cmd_overwritten = true; + hx8399->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)); + } + + ESP_LOGD(TAG, "send init commands success"); + + ESP_RETURN_ON_ERROR(hx8399->init(panel), TAG, "init MIPI DPI panel failed"); + + return ESP_OK; +} + +static esp_err_t panel_hx8399_reset(esp_lcd_panel_t *panel) +{ + hx8399_panel_t *hx8399 = (hx8399_panel_t *)panel->user_data; + esp_lcd_panel_io_handle_t io = hx8399->io; + + // Perform hardware reset + if (hx8399->reset_gpio_num >= 0) { + gpio_set_level(hx8399->reset_gpio_num, hx8399->flags.reset_level); + vTaskDelay(pdMS_TO_TICKS(10)); + gpio_set_level(hx8399->reset_gpio_num, !hx8399->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(120)); + } + + return ESP_OK; +} + +static esp_err_t panel_hx8399_invert_color(esp_lcd_panel_t *panel, bool invert_color_data) +{ + hx8399_panel_t *hx8399 = (hx8399_panel_t *)panel->user_data; + esp_lcd_panel_io_handle_t io = hx8399->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_hx8399_disp_on_off(esp_lcd_panel_t *panel, bool on_off) +{ + hx8399_panel_t *hx8399 = (hx8399_panel_t *)panel->user_data; + esp_lcd_panel_io_handle_t io = hx8399->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; +} +#endif diff --git a/components/display/lcd/esp_lcd_hx8399/idf_component.yml b/components/display/lcd/esp_lcd_hx8399/idf_component.yml new file mode 100644 index 000000000..97df5372c --- /dev/null +++ b/components/display/lcd/esp_lcd_hx8399/idf_component.yml @@ -0,0 +1,11 @@ +version: "1.0.0" +targets: + - esp32p4 +description: ESP LCD HX8399 (MIPI-DSI) +url: https://github.com/espressif/esp-bsp/tree/master/components/lcd/esp_lcd_hx8399 +repository: https://github.com/espressif/esp-iot-solution.git +issues: https://github.com/espressif/esp-iot-solution/issues +dependencies: + idf: + version: '>=5.3' + cmake_utilities: "0.*" diff --git a/components/display/lcd/esp_lcd_hx8399/include/esp_lcd_hx8399.h b/components/display/lcd/esp_lcd_hx8399/include/esp_lcd_hx8399.h new file mode 100644 index 000000000..ffef39ba7 --- /dev/null +++ b/components/display/lcd/esp_lcd_hx8399/include/esp_lcd_hx8399.h @@ -0,0 +1,119 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include "soc/soc_caps.h" + +#if SOC_MIPI_DSI_SUPPORTED +#include "esp_lcd_panel_vendor.h" +#include "esp_lcd_mipi_dsi.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief LCD panel initialization commands. + * + */ +typedef struct { + int cmd; /* +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "driver/i2c.h" +#include "driver/spi_master.h" +#include "driver/gpio.h" +#include "esp_heap_caps.h" +#include "esp_log.h" +#include "esp_timer.h" +#include "esp_lcd_panel_ops.h" +#include "esp_lcd_panel_io.h" +#include "esp_lcd_mipi_dsi.h" +#include "esp_ldo_regulator.h" +#include "esp_dma_utils.h" +#include "unity.h" +#include "unity_test_runner.h" +#include "unity_test_utils_memory.h" + +#include "esp_lcd_hx8399.h" + +#define TEST_LCD_H_RES (1080) +#define TEST_LCD_V_RES (1920) +#define TEST_LCD_BIT_PER_PIXEL (24) +#define TEST_PIN_NUM_LCD_RST (-1) +#define TEST_PIN_NUM_BK_LIGHT (-1) // 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 +#define TEST_MIPI_DSI_LANE_NUM (2) + +#if TEST_LCD_BIT_PER_PIXEL == 24 +#define TEST_MIPI_DPI_PX_FORMAT (LCD_COLOR_PIXEL_FORMAT_RGB888) +#elif TEST_LCD_BIT_PER_PIXEL == 18 +#define TEST_MIPI_DPI_PX_FORMAT (LCD_COLOR_PIXEL_FORMAT_RGB666) +#elif TEST_LCD_BIT_PER_PIXEL == 16 +#define TEST_MIPI_DPI_PX_FORMAT (LCD_COLOR_PIXEL_FORMAT_RGB565) +#endif + +#define TEST_DELAY_TIME_MS (3000) + +#define TEST_MIPI_DSI_PHY_PWR_LDO_CHAN (3) +#define TEST_MIPI_DSI_PHY_PWR_LDO_VOLTAGE_MV (2500) + +static char *TAG = "hx8399_test"; +static esp_ldo_channel_handle_t ldo_mipi_phy = NULL; +static esp_lcd_panel_handle_t panel_handle = NULL; +static esp_lcd_dsi_bus_handle_t mipi_dsi_bus = NULL; +static esp_lcd_panel_io_handle_t mipi_dbi_io = NULL; +static SemaphoreHandle_t refresh_finish = NULL; + +IRAM_ATTR static bool test_notify_refresh_ready(esp_lcd_panel_handle_t panel, esp_lcd_dpi_panel_event_data_t *edata, void *user_ctx) +{ + SemaphoreHandle_t refresh_finish = (SemaphoreHandle_t)user_ctx; + BaseType_t need_yield = pdFALSE; + + xSemaphoreGiveFromISR(refresh_finish, &need_yield); + + return (need_yield == pdTRUE); +} + +static void test_init_lcd(void) +{ +#if TEST_PIN_NUM_BK_LIGHT >= 0 + ESP_LOGI(TAG, "Turn on LCD backlight"); + gpio_config_t bk_gpio_config = { + .mode = GPIO_MODE_OUTPUT, + .pin_bit_mask = 1ULL << TEST_PIN_NUM_BK_LIGHT + }; + TEST_ESP_OK(gpio_config(&bk_gpio_config)); + TEST_ESP_OK(gpio_set_level(TEST_PIN_NUM_BK_LIGHT, TEST_LCD_BK_LIGHT_ON_LEVEL)); +#endif + + // Turn on the power for MIPI DSI PHY, so it can go from "No Power" state to "Shutdown" state +#ifdef TEST_MIPI_DSI_PHY_PWR_LDO_CHAN + ESP_LOGI(TAG, "MIPI DSI PHY Powered on"); + esp_ldo_channel_config_t ldo_mipi_phy_config = { + .chan_id = TEST_MIPI_DSI_PHY_PWR_LDO_CHAN, + .voltage_mv = TEST_MIPI_DSI_PHY_PWR_LDO_VOLTAGE_MV, + }; + TEST_ESP_OK(esp_ldo_acquire_channel(&ldo_mipi_phy_config, &ldo_mipi_phy)); +#endif + + ESP_LOGI(TAG, "Initialize MIPI DSI bus"); + esp_lcd_dsi_bus_config_t bus_config = HX8399_PANEL_BUS_DSI_2CH_CONFIG(); + TEST_ESP_OK(esp_lcd_new_dsi_bus(&bus_config, &mipi_dsi_bus)); + + ESP_LOGI(TAG, "Install panel IO"); + esp_lcd_dbi_io_config_t dbi_config = HX8399_PANEL_IO_DBI_CONFIG(); + TEST_ESP_OK(esp_lcd_new_panel_io_dbi(mipi_dsi_bus, &dbi_config, &mipi_dbi_io)); + + ESP_LOGI(TAG, "Install LCD driver of hx8399"); + esp_lcd_dpi_panel_config_t dpi_config = HX8399_1080_1920_PANEL_30HZ_DPI_CONFIG(TEST_MIPI_DPI_PX_FORMAT); + hx8399_vendor_config_t vendor_config = { + .mipi_config = { + .dsi_bus = mipi_dsi_bus, + .dpi_config = &dpi_config, + .lane_num = TEST_MIPI_DSI_LANE_NUM, + }, + }; + const esp_lcd_panel_dev_config_t panel_config = { + .reset_gpio_num = TEST_PIN_NUM_LCD_RST, + .rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB, + .bits_per_pixel = TEST_LCD_BIT_PER_PIXEL, + .vendor_config = &vendor_config, + }; + TEST_ESP_OK(esp_lcd_new_panel_hx8399(mipi_dbi_io, &panel_config, &panel_handle)); + TEST_ESP_OK(esp_lcd_panel_reset(panel_handle)); + TEST_ESP_OK(esp_lcd_panel_init(panel_handle)); + TEST_ESP_OK(esp_lcd_panel_disp_on_off(panel_handle, true)); + + refresh_finish = xSemaphoreCreateBinary(); + TEST_ASSERT_NOT_NULL(refresh_finish); + esp_lcd_dpi_panel_event_callbacks_t cbs = { + .on_color_trans_done = test_notify_refresh_ready, + }; + TEST_ESP_OK(esp_lcd_dpi_panel_register_event_callbacks(panel_handle, &cbs, refresh_finish)); +} + +static void test_deinit_lcd(void) +{ + TEST_ESP_OK(esp_lcd_panel_del(panel_handle)); + TEST_ESP_OK(esp_lcd_panel_io_del(mipi_dbi_io)); + TEST_ESP_OK(esp_lcd_del_dsi_bus(mipi_dsi_bus)); + panel_handle = NULL; + mipi_dbi_io = NULL; + mipi_dsi_bus = NULL; + + if (ldo_mipi_phy) { + TEST_ESP_OK(esp_ldo_release_channel(ldo_mipi_phy)); + ldo_mipi_phy = NULL; + } + + vSemaphoreDelete(refresh_finish); + refresh_finish = NULL; + +#if TEST_PIN_NUM_BK_LIGHT >= 0 + TEST_ESP_OK(gpio_reset_pin(TEST_PIN_NUM_BK_LIGHT)); +#endif +} + +static void test_draw_color_bar(esp_lcd_panel_handle_t panel_handle, uint16_t h_res, uint16_t v_res) +{ + uint8_t byte_per_pixel = (TEST_LCD_BIT_PER_PIXEL + 7) / 8; + uint16_t row_line = v_res / byte_per_pixel / 8; + uint8_t *color = (uint8_t *)heap_caps_calloc(1, row_line * h_res * byte_per_pixel, MALLOC_CAP_DMA); + + for (int j = 0; j < byte_per_pixel * 8; j++) { + for (int i = 0; i < row_line * h_res; i++) { + for (int k = 0; k < byte_per_pixel; k++) { + color[i * byte_per_pixel + k] = (BIT(j) >> (k * 8)) & 0xff; + } + } + TEST_ESP_OK(esp_lcd_panel_draw_bitmap(panel_handle, 0, j * row_line, h_res, (j + 1) * row_line, color)); + xSemaphoreTake(refresh_finish, portMAX_DELAY); + } + + uint16_t color_line = row_line * byte_per_pixel * 8; + uint16_t res_line = v_res - color_line; + if (res_line) { + for (int i = 0; i < res_line * h_res; i++) { + for (int k = 0; k < byte_per_pixel; k++) { + color[i * byte_per_pixel + k] = 0xff; + } + } + TEST_ESP_OK(esp_lcd_panel_draw_bitmap(panel_handle, 0, color_line, h_res, v_res, color)); + xSemaphoreTake(refresh_finish, portMAX_DELAY); + } + + free(color); +} + +TEST_CASE("test hx8399 to draw pattern with MIPI interface", "[hx8399][draw_pattern]") +{ + ESP_LOGI(TAG, "Initialize LCD device"); + test_init_lcd(); + + ESP_LOGI(TAG, "Show color bar pattern drawn by hardware"); + TEST_ESP_OK(esp_lcd_dpi_panel_set_pattern(panel_handle, MIPI_DSI_PATTERN_BAR_VERTICAL)); + vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_TIME_MS)); + TEST_ESP_OK(esp_lcd_dpi_panel_set_pattern(panel_handle, MIPI_DSI_PATTERN_BAR_HORIZONTAL)); + vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_TIME_MS)); + TEST_ESP_OK(esp_lcd_dpi_panel_set_pattern(panel_handle, MIPI_DSI_PATTERN_NONE)); + + ESP_LOGI(TAG, "Deinitialize LCD device"); + test_deinit_lcd(); +} + +TEST_CASE("test hx8399 to draw color bar with MIPI interface", "[hx8399][draw_color_bar]") +{ + ESP_LOGI(TAG, "Initialize LCD device"); + test_init_lcd(); + + ESP_LOGI(TAG, "Show color bar drawn by software"); + test_draw_color_bar(panel_handle, TEST_LCD_H_RES, TEST_LCD_V_RES); + vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_TIME_MS)); + + ESP_LOGI(TAG, "Deinitialize LCD device"); + test_deinit_lcd(); +} + +// 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; + +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); + unity_utils_check_leak(before_free_8bit, after_free_8bit, "8BIT", TEST_MEMORY_LEAK_THRESHOLD); + unity_utils_check_leak(before_free_32bit, after_free_32bit, "32BIT", TEST_MEMORY_LEAK_THRESHOLD); +} + +void app_main(void) +{ + /** + * _ ___ _____ _____ ___ ___ + * | | | \ \/ ( _ )___ // _ \ / _ \ + * | |_| |\ // _ \ |_ \ (_) | (_) | + * | _ |/ \ (_) |__) \__, |\__, | + * |_| |_/_/\_\___/____/ /_/ /_/ + */ + printf(" _ ___ _____ _____ ___ ___\r\n"); + printf(" | | | \\ \\/ ( _ )___ // _ \\ / _ \\ \r\n"); + printf(" | |_| |\\ // _ \\ |_ \\ (_) | (_) |\r\n"); + printf(" | _ |/ \\ (_) |__) \\__, |\\__, |\r\n"); + printf(" |_| |_/_/\\_\\___/____/ /_/ /_/r\n"); + unity_run_menu(); +} +#endif diff --git a/components/display/lcd/esp_lcd_hx8399/test_apps/sdkconfig.defaults b/components/display/lcd/esp_lcd_hx8399/test_apps/sdkconfig.defaults new file mode 100644 index 000000000..521790c36 --- /dev/null +++ b/components/display/lcd/esp_lcd_hx8399/test_apps/sdkconfig.defaults @@ -0,0 +1,3 @@ +CONFIG_ESP_TASK_WDT_EN=n +CONFIG_FREERTOS_HZ=1000 +CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=4096 diff --git a/components/display/lcd/esp_lcd_hx8399/test_apps/sdkconfig.defaults.esp32p4 b/components/display/lcd/esp_lcd_hx8399/test_apps/sdkconfig.defaults.esp32p4 new file mode 100644 index 000000000..4621955c3 --- /dev/null +++ b/components/display/lcd/esp_lcd_hx8399/test_apps/sdkconfig.defaults.esp32p4 @@ -0,0 +1,4 @@ +CONFIG_COMPILER_OPTIMIZATION_PERF=y +CONFIG_SPIRAM=y +CONFIG_SPIRAM_SPEED_200M=y +CONFIG_IDF_EXPERIMENTAL_FEATURES=y diff --git a/components/display/lcd/esp_lcd_jd9165/CHANGELOG.md b/components/display/lcd/esp_lcd_jd9165/CHANGELOG.md index 51bc9ceca..9fbe6a6bf 100644 --- a/components/display/lcd/esp_lcd_jd9165/CHANGELOG.md +++ b/components/display/lcd/esp_lcd_jd9165/CHANGELOG.md @@ -1,5 +1,11 @@ # ChangeLog +## v1.0.0 - 2024-08-12 + +### Enhancements: + +* Component version maintenance, code improvement, and documentation enhancement + ## v0.1.0 - 2024-05-07 ### Enhancements: diff --git a/components/display/lcd/esp_lcd_jd9165/README.md b/components/display/lcd/esp_lcd_jd9165/README.md index 3a0a0444d..a552397ba 100644 --- a/components/display/lcd/esp_lcd_jd9165/README.md +++ b/components/display/lcd/esp_lcd_jd9165/README.md @@ -10,6 +10,8 @@ Implementation of the JD9165 LCD controller with esp_lcd component. **Note**: MIPI-DSI interface only supports ESP-IDF v5.3 and above versions. +For more information on LCD, please refer to the [LCD documentation](https://docs.espressif.com/projects/esp-iot-solution/en/latest/display/lcd/index.html). + ## Add to project Packages from this repository are uploaded to [Espressif's component service](https://components.espressif.com/). diff --git a/components/display/lcd/esp_lcd_jd9165/esp_lcd_jd9165.c b/components/display/lcd/esp_lcd_jd9165/esp_lcd_jd9165.c index af4c1d309..cb368970e 100644 --- a/components/display/lcd/esp_lcd_jd9165/esp_lcd_jd9165.c +++ b/components/display/lcd/esp_lcd_jd9165/esp_lcd_jd9165.c @@ -44,8 +44,6 @@ static esp_err_t panel_jd9165_init(esp_lcd_panel_t *panel); static esp_err_t panel_jd9165_reset(esp_lcd_panel_t *panel); static esp_err_t panel_jd9165_invert_color(esp_lcd_panel_t *panel, bool invert_color_data); static esp_err_t panel_jd9165_mirror(esp_lcd_panel_t *panel, bool mirror_x, bool mirror_y); -static esp_err_t panel_jd9165_swap_xy(esp_lcd_panel_t *panel, bool swap_axes); -static esp_err_t panel_jd9165_set_gap(esp_lcd_panel_t *panel, int x_gap, int y_gap); static esp_err_t panel_jd9165_disp_on_off(esp_lcd_panel_t *panel, bool on_off); esp_err_t esp_lcd_new_panel_jd9165(const esp_lcd_panel_io_handle_t io, const esp_lcd_panel_dev_config_t *panel_dev_config, @@ -106,8 +104,6 @@ esp_err_t esp_lcd_new_panel_jd9165(const esp_lcd_panel_io_handle_t io, const esp panel_handle->init = panel_jd9165_init; panel_handle->reset = panel_jd9165_reset; panel_handle->mirror = panel_jd9165_mirror; - panel_handle->swap_xy = panel_jd9165_swap_xy; - panel_handle->set_gap = panel_jd9165_set_gap; panel_handle->invert_color = panel_jd9165_invert_color; panel_handle->disp_on_off = panel_jd9165_disp_on_off; panel_handle->user_data = jd9165; @@ -267,18 +263,6 @@ static esp_err_t panel_jd9165_mirror(esp_lcd_panel_t *panel, bool mirror_x, bool return ESP_OK; } -static esp_err_t panel_jd9165_swap_xy(esp_lcd_panel_t *panel, bool swap_axes) -{ - ESP_LOGE(TAG, "swap_xy is not supported by this panel"); - return ESP_ERR_NOT_SUPPORTED; -} - -static esp_err_t panel_jd9165_set_gap(esp_lcd_panel_t *panel, int x_gap, int y_gap) -{ - ESP_LOGE(TAG, "set_gap is not supported by this panel"); - return ESP_ERR_NOT_SUPPORTED; -} - static esp_err_t panel_jd9165_disp_on_off(esp_lcd_panel_t *panel, bool on_off) { jd9165_panel_t *jd9165 = (jd9165_panel_t *)panel->user_data; diff --git a/components/display/lcd/esp_lcd_jd9165/idf_component.yml b/components/display/lcd/esp_lcd_jd9165/idf_component.yml index 77402e87c..0b6abc25d 100644 --- a/components/display/lcd/esp_lcd_jd9165/idf_component.yml +++ b/components/display/lcd/esp_lcd_jd9165/idf_component.yml @@ -1,7 +1,7 @@ -version: "0.1.0" +version: "1.0.0" targets: - esp32p4 -description: ESP LCD JD9165 (MIPI DSI) +description: ESP LCD JD9165 (MIPI-DSI) url: https://github.com/espressif/esp-bsp/tree/master/components/lcd/esp_lcd_jd9165 repository: https://github.com/espressif/esp-iot-solution.git issues: https://github.com/espressif/esp-iot-solution/issues diff --git a/components/display/lcd/esp_lcd_jd9165/include/esp_lcd_jd9165.h b/components/display/lcd/esp_lcd_jd9165/include/esp_lcd_jd9165.h index 75a3f2129..973264242 100644 --- a/components/display/lcd/esp_lcd_jd9165/include/esp_lcd_jd9165.h +++ b/components/display/lcd/esp_lcd_jd9165/include/esp_lcd_jd9165.h @@ -44,21 +44,6 @@ typedef struct { esp_lcd_dsi_bus_handle_t dsi_bus; /*!< MIPI-DSI bus configuration */ const esp_lcd_dpi_panel_config_t *dpi_config; /*!< MIPI-DPI panel configuration */ } mipi_config; - struct { - unsigned int use_mipi_interface: 1; /*init = panel_jd9365_init; panel_handle->reset = panel_jd9365_reset; panel_handle->mirror = panel_jd9365_mirror; - panel_handle->swap_xy = panel_jd9365_swap_xy; - panel_handle->set_gap = panel_jd9365_set_gap; panel_handle->invert_color = panel_jd9365_invert_color; panel_handle->disp_on_off = panel_jd9365_disp_on_off; panel_handle->user_data = jd9365; @@ -368,6 +364,9 @@ static esp_err_t panel_jd9365_init(esp_lcd_panel_t *panel) bool is_cmd_overwritten = false; switch (jd9365->lane_num) { + case 0: + lane_command = JD9365_DSI_2_LANE; + break; case 1: lane_command = JD9365_DSI_1_LANE; break; @@ -515,18 +514,6 @@ static esp_err_t panel_jd9365_mirror(esp_lcd_panel_t *panel, bool mirror_x, bool return ESP_OK; } -static esp_err_t panel_jd9365_swap_xy(esp_lcd_panel_t *panel, bool swap_axes) -{ - ESP_LOGW(TAG, "swap_xy is not supported by this panel"); - return ESP_ERR_NOT_SUPPORTED; -} - -static esp_err_t panel_jd9365_set_gap(esp_lcd_panel_t *panel, int x_gap, int y_gap) -{ - ESP_LOGE(TAG, "set_gap is not supported by this panel"); - return ESP_ERR_NOT_SUPPORTED; -} - static esp_err_t panel_jd9365_disp_on_off(esp_lcd_panel_t *panel, bool on_off) { jd9365_panel_t *jd9365 = (jd9365_panel_t *)panel->user_data; diff --git a/components/display/lcd/esp_lcd_jd9365/idf_component.yml b/components/display/lcd/esp_lcd_jd9365/idf_component.yml index ca00006d7..630f26d6c 100644 --- a/components/display/lcd/esp_lcd_jd9365/idf_component.yml +++ b/components/display/lcd/esp_lcd_jd9365/idf_component.yml @@ -1,7 +1,7 @@ -version: "0.1.0" +version: "1.0.0" targets: - esp32p4 -description: ESP LCD JD9365 +description: ESP LCD JD9365(MIPI-DSI) url: https://github.com/espressif/esp-iot-solution/tree/master/components/display/lcd/esp_lcd_jd9365 repository: https://github.com/espressif/esp-iot-solution.git issues: https://github.com/espressif/esp-iot-solution/issues diff --git a/components/display/lcd/esp_lcd_jd9365/include/esp_lcd_jd9365.h b/components/display/lcd/esp_lcd_jd9365/include/esp_lcd_jd9365.h index ab5dcf602..1c38e8da4 100644 --- a/components/display/lcd/esp_lcd_jd9365/include/esp_lcd_jd9365.h +++ b/components/display/lcd/esp_lcd_jd9365/include/esp_lcd_jd9365.h @@ -45,21 +45,6 @@ typedef struct { const esp_lcd_dpi_panel_config_t *dpi_config; /*!< MIPI-DPI panel configuration */ uint8_t lane_num; /*!< Number of MIPI-DSI lanes */ } mipi_config; - struct { - unsigned int use_mipi_interface: 1; /*= 0 + ESP_LOGI(TAG, "Turn on LCD backlight"); + gpio_config_t bk_gpio_config = { + .mode = GPIO_MODE_OUTPUT, + .pin_bit_mask = 1ULL << TEST_PIN_NUM_BK_LIGHT + }; + TEST_ESP_OK(gpio_config(&bk_gpio_config)); + TEST_ESP_OK(gpio_set_level(TEST_PIN_NUM_BK_LIGHT, TEST_LCD_BK_LIGHT_ON_LEVEL)); +#endif + ESP_LOGI(TAG, "Initialize SPI bus"); const spi_bus_config_t buscfg = SH8601_PANEL_BUS_SPI_CONFIG(TEST_PIN_NUM_LCD_PCLK, TEST_PIN_NUM_LCD_DATA0, @@ -104,10 +117,24 @@ TEST_CASE("test sh8601 to draw color bar with SPI interface", "[sh8601][spi]") TEST_ESP_OK(esp_lcd_panel_del(panel_handle)); TEST_ESP_OK(esp_lcd_panel_io_del(io_handle)); TEST_ESP_OK(spi_bus_free(TEST_LCD_HOST)); + +#if TEST_PIN_NUM_BK_LIGHT >= 0 + TEST_ESP_OK(gpio_reset_pin(TEST_PIN_NUM_BK_LIGHT)); +#endif } TEST_CASE("test sh8601 to draw color bar with QSPI interface", "[sh8601][qspi]") { +#if TEST_PIN_NUM_BK_LIGHT >= 0 + ESP_LOGI(TAG, "Turn on LCD backlight"); + gpio_config_t bk_gpio_config = { + .mode = GPIO_MODE_OUTPUT, + .pin_bit_mask = 1ULL << TEST_PIN_NUM_BK_LIGHT + }; + TEST_ESP_OK(gpio_config(&bk_gpio_config)); + TEST_ESP_OK(gpio_set_level(TEST_PIN_NUM_BK_LIGHT, TEST_LCD_BK_LIGHT_ON_LEVEL)); +#endif + ESP_LOGI(TAG, "Initialize SPI bus"); const spi_bus_config_t buscfg = SH8601_PANEL_BUS_QSPI_CONFIG(TEST_PIN_NUM_LCD_PCLK, TEST_PIN_NUM_LCD_DATA0, @@ -146,6 +173,10 @@ TEST_CASE("test sh8601 to draw color bar with QSPI interface", "[sh8601][qspi]") TEST_ESP_OK(esp_lcd_panel_del(panel_handle)); TEST_ESP_OK(esp_lcd_panel_io_del(io_handle)); TEST_ESP_OK(spi_bus_free(TEST_LCD_HOST)); + +#if TEST_PIN_NUM_BK_LIGHT >= 0 + TEST_ESP_OK(gpio_reset_pin(TEST_PIN_NUM_BK_LIGHT)); +#endif } // Some resources are lazy allocated in the LCD driver, the threadhold is left for that case diff --git a/components/display/lcd/esp_lcd_spd2010/CHANGELOG.md b/components/display/lcd/esp_lcd_spd2010/CHANGELOG.md index 3d9a19f30..a97350731 100644 --- a/components/display/lcd/esp_lcd_spd2010/CHANGELOG.md +++ b/components/display/lcd/esp_lcd_spd2010/CHANGELOG.md @@ -1,5 +1,11 @@ # ChangeLog +## v1.0.2 - 2024-08-12 + +### Enhancements: + +* Component version maintenance, code improvement, and documentation enhancement + ## v0.0.1 - 2023-08-22 ### Enhancements: diff --git a/components/display/lcd/esp_lcd_spd2010/README.md b/components/display/lcd/esp_lcd_spd2010/README.md index 78f537b10..d6da1113a 100644 --- a/components/display/lcd/esp_lcd_spd2010/README.md +++ b/components/display/lcd/esp_lcd_spd2010/README.md @@ -18,6 +18,8 @@ You can add them to your project via `idf.py add-dependancy`, e.g. Alternatively, you can create `idf_component.yml`. More is in [Espressif's documentation](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/tools/idf-component-manager.html). +For more information on LCD, please refer to the [LCD documentation](https://docs.espressif.com/projects/esp-iot-solution/en/latest/display/lcd/index.html). + ## Initialization Code ### SPI Interface diff --git a/components/display/lcd/esp_lcd_spd2010/idf_component.yml b/components/display/lcd/esp_lcd_spd2010/idf_component.yml index 05821812d..0c1b0adc9 100644 --- a/components/display/lcd/esp_lcd_spd2010/idf_component.yml +++ b/components/display/lcd/esp_lcd_spd2010/idf_component.yml @@ -1,5 +1,5 @@ -version: "1.0.1" -description: ESP LCD SPD2010 +version: "1.0.2" +description: ESP LCD SPD2010(SPI & QSPI) url: https://github.com/espressif/esp-iot-solution/tree/master/components/display/lcd/esp_lcd_spd2010 repository: https://github.com/espressif/esp-iot-solution.git issues: https://github.com/espressif/esp-iot-solution/issues diff --git a/components/display/lcd/esp_lcd_spd2010/test_apps/main/test_esp_lcd_spd2010.c b/components/display/lcd/esp_lcd_spd2010/test_apps/main/test_esp_lcd_spd2010.c index 0c58bf1e8..42fa4d2dc 100644 --- a/components/display/lcd/esp_lcd_spd2010/test_apps/main/test_esp_lcd_spd2010.c +++ b/components/display/lcd/esp_lcd_spd2010/test_apps/main/test_esp_lcd_spd2010.c @@ -34,6 +34,9 @@ #define TEST_PIN_NUM_LCD_DATA3 (GPIO_NUM_14) #define TEST_PIN_NUM_LCD_RST (GPIO_NUM_17) #define TEST_PIN_NUM_LCD_DC (GPIO_NUM_8) +#define TEST_PIN_NUM_BK_LIGHT (GPIO_NUM_0) // 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 #define TEST_DELAY_TIME_MS (3000) @@ -74,6 +77,16 @@ static void test_draw_bitmap(esp_lcd_panel_handle_t panel_handle) TEST_CASE("test spd2010 to draw color bar with SPI interface", "[spd2010][spi]") { +#if TEST_PIN_NUM_BK_LIGHT >= 0 + ESP_LOGI(TAG, "Turn on LCD backlight"); + gpio_config_t bk_gpio_config = { + .mode = GPIO_MODE_OUTPUT, + .pin_bit_mask = 1ULL << TEST_PIN_NUM_BK_LIGHT + }; + TEST_ESP_OK(gpio_config(&bk_gpio_config)); + TEST_ESP_OK(gpio_set_level(TEST_PIN_NUM_BK_LIGHT, TEST_LCD_BK_LIGHT_ON_LEVEL)); +#endif + ESP_LOGI(TAG, "Initialize SPI bus"); const spi_bus_config_t buscfg = SPD2010_PANEL_BUS_SPI_CONFIG(TEST_PIN_NUM_LCD_PCLK, TEST_PIN_NUM_LCD_DATA0, @@ -104,10 +117,24 @@ TEST_CASE("test spd2010 to draw color bar with SPI interface", "[spd2010][spi]") TEST_ESP_OK(esp_lcd_panel_del(panel_handle)); TEST_ESP_OK(esp_lcd_panel_io_del(io_handle)); TEST_ESP_OK(spi_bus_free(TEST_LCD_HOST)); + +#if TEST_PIN_NUM_BK_LIGHT >= 0 + TEST_ESP_OK(gpio_reset_pin(TEST_PIN_NUM_BK_LIGHT)); +#endif } TEST_CASE("test spd2010 to draw color bar with QSPI interface", "[spd2010][qspi]") { +#if TEST_PIN_NUM_BK_LIGHT >= 0 + ESP_LOGI(TAG, "Turn on LCD backlight"); + gpio_config_t bk_gpio_config = { + .mode = GPIO_MODE_OUTPUT, + .pin_bit_mask = 1ULL << TEST_PIN_NUM_BK_LIGHT + }; + TEST_ESP_OK(gpio_config(&bk_gpio_config)); + TEST_ESP_OK(gpio_set_level(TEST_PIN_NUM_BK_LIGHT, TEST_LCD_BK_LIGHT_ON_LEVEL)); +#endif + ESP_LOGI(TAG, "Initialize SPI bus"); const spi_bus_config_t buscfg = SPD2010_PANEL_BUS_QSPI_CONFIG(TEST_PIN_NUM_LCD_PCLK, TEST_PIN_NUM_LCD_DATA0, @@ -146,6 +173,10 @@ TEST_CASE("test spd2010 to draw color bar with QSPI interface", "[spd2010][qspi] TEST_ESP_OK(esp_lcd_panel_del(panel_handle)); TEST_ESP_OK(esp_lcd_panel_io_del(io_handle)); TEST_ESP_OK(spi_bus_free(TEST_LCD_HOST)); + +#if TEST_PIN_NUM_BK_LIGHT >= 0 + TEST_ESP_OK(gpio_reset_pin(TEST_PIN_NUM_BK_LIGHT)); +#endif } // Some resources are lazy allocated in the LCD driver, the threadhold is left for that case diff --git a/components/display/lcd/esp_lcd_st7701/README.md b/components/display/lcd/esp_lcd_st7701/README.md index 6ccb6b69f..fca7c4ebb 100644 --- a/components/display/lcd/esp_lcd_st7701/README.md +++ b/components/display/lcd/esp_lcd_st7701/README.md @@ -10,6 +10,8 @@ Implementation of the ST7701(S) LCD controller with esp_lcd component. **Note**: MIPI-DSI interface only supports ESP-IDF v5.3 and above versions. +For more information on LCD, please refer to the [LCD documentation](https://docs.espressif.com/projects/esp-iot-solution/en/latest/display/lcd/index.html). + ## Add to project Packages from this repository are uploaded to [Espressif's component service](https://components.espressif.com/). diff --git a/components/display/lcd/esp_lcd_st7701/esp_lcd_st7701_mipi.c b/components/display/lcd/esp_lcd_st7701/esp_lcd_st7701_mipi.c index 8aef94de0..6e2673951 100644 --- a/components/display/lcd/esp_lcd_st7701/esp_lcd_st7701_mipi.c +++ b/components/display/lcd/esp_lcd_st7701/esp_lcd_st7701_mipi.c @@ -28,8 +28,6 @@ static esp_err_t panel_st7701_reset(esp_lcd_panel_t *panel); static esp_err_t panel_st7701_init(esp_lcd_panel_t *panel); static esp_err_t panel_st7701_invert_color(esp_lcd_panel_t *panel, bool invert_color_data); static esp_err_t panel_st7701_mirror(esp_lcd_panel_t *panel, bool mirror_x, bool mirror_y); -static esp_err_t panel_st7701_swap_xy(esp_lcd_panel_t *panel, bool swap_axes); -static esp_err_t panel_st7701_set_gap(esp_lcd_panel_t *panel, int x_gap, int y_gap); static esp_err_t panel_st7701_disp_on_off(esp_lcd_panel_t *panel, bool off); static esp_err_t panel_st7701_sleep(esp_lcd_panel_t *panel, bool sleep); @@ -118,8 +116,6 @@ esp_err_t esp_lcd_new_panel_st7701_mipi(const esp_lcd_panel_io_handle_t io, cons panel_handle->init = panel_st7701_init; panel_handle->reset = panel_st7701_reset; panel_handle->mirror = panel_st7701_mirror; - panel_handle->swap_xy = panel_st7701_swap_xy; - panel_handle->set_gap = panel_st7701_set_gap; panel_handle->invert_color = panel_st7701_invert_color; panel_handle->disp_on_off = panel_st7701_disp_on_off; panel_handle->disp_sleep = panel_st7701_sleep; @@ -344,18 +340,6 @@ static esp_err_t panel_st7701_mirror(esp_lcd_panel_t *panel, bool mirror_x, bool return ESP_OK; } -static esp_err_t panel_st7701_swap_xy(esp_lcd_panel_t *panel, bool swap_axes) -{ - ESP_LOGW(TAG, "Swap XY is not supported in ST7701 driver. Please use SW rotation."); - return ESP_ERR_NOT_SUPPORTED; -} - -static esp_err_t panel_st7701_set_gap(esp_lcd_panel_t *panel, int x_gap, int y_gap) -{ - ESP_LOGE(TAG, "set_gap is not supported by this panel"); - return ESP_ERR_NOT_SUPPORTED; -} - static esp_err_t panel_st7701_disp_on_off(esp_lcd_panel_t *panel, bool on_off) { st7701_panel_t *st7701 = (st7701_panel_t *)panel->user_data; diff --git a/components/display/lcd/esp_lcd_st7701/idf_component.yml b/components/display/lcd/esp_lcd_st7701/idf_component.yml index 639b2fa41..0f72574a5 100644 --- a/components/display/lcd/esp_lcd_st7701/idf_component.yml +++ b/components/display/lcd/esp_lcd_st7701/idf_component.yml @@ -2,7 +2,7 @@ version: "1.1.0" targets: - esp32s3 - esp32p4 -description: ESP LCD ST7701 +description: ESP LCD ST7701(RGB & MIPI-DSI) url: https://github.com/espressif/esp-iot-solution/tree/master/components/display/lcd/esp_lcd_st7701 repository: https://github.com/espressif/esp-iot-solution.git issues: https://github.com/espressif/esp-iot-solution/issues diff --git a/components/display/lcd/esp_lcd_st77903_qspi/CHANGELOG.md b/components/display/lcd/esp_lcd_st77903_qspi/CHANGELOG.md index 43ac028c2..d4dde5428 100644 --- a/components/display/lcd/esp_lcd_st77903_qspi/CHANGELOG.md +++ b/components/display/lcd/esp_lcd_st77903_qspi/CHANGELOG.md @@ -1,5 +1,11 @@ # ChangeLog +## v1.0.0 - 2024-08-12 + +### Enhancements: + +* Component version maintenance, code improvement, and documentation enhancement + ## v0.4.1- 2024-05-09 ### Enhancements: diff --git a/components/display/lcd/esp_lcd_st77903_qspi/README.md b/components/display/lcd/esp_lcd_st77903_qspi/README.md index 5898a4c02..03d568fa9 100644 --- a/components/display/lcd/esp_lcd_st77903_qspi/README.md +++ b/components/display/lcd/esp_lcd_st77903_qspi/README.md @@ -6,6 +6,8 @@ Implementation of the ST77903 QSPI LCD controller with [esp_lcd](https://docs.es | :------------: | :---------------------: | :------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------: | | ST77903 | QSPI | esp_lcd_ST77903_qspi | [PDF1](https://dl.espressif.com/AE/esp-iot-solution/ST77903_SPEC_P0.5.pdf), [PDF2](https://dl.espressif.com/AE/esp-iot-solution/ST77903_Customer_Application_Notes.pdf) | +For more information on LCD, please refer to the [LCD documentation](https://docs.espressif.com/projects/esp-iot-solution/en/latest/display/lcd/index.html). + ## Initialization Code ```c diff --git a/components/display/lcd/esp_lcd_st77903_qspi/idf_component.yml b/components/display/lcd/esp_lcd_st77903_qspi/idf_component.yml index bdcf4e373..693a5db87 100644 --- a/components/display/lcd/esp_lcd_st77903_qspi/idf_component.yml +++ b/components/display/lcd/esp_lcd_st77903_qspi/idf_component.yml @@ -1,4 +1,4 @@ -version: "0.4.1" +version: "1.0.0" description: ESP LCD ST77903 QSPI url: https://github.com/espressif/esp-iot-solution/tree/master/components/display/lcd/esp_lcd_st77903_qspi repository: https://github.com/espressif/esp-iot-solution.git diff --git a/components/display/lcd/esp_lcd_st77903_rgb/CHANGELOG.md b/components/display/lcd/esp_lcd_st77903_rgb/CHANGELOG.md index 77eb601c7..1e1948b55 100644 --- a/components/display/lcd/esp_lcd_st77903_rgb/CHANGELOG.md +++ b/components/display/lcd/esp_lcd_st77903_rgb/CHANGELOG.md @@ -1,5 +1,11 @@ # ChangeLog +## v1.0.0 - 2024-08-12 + +### Enhancements: + +* Component version maintenance, code improvement, and documentation enhancement + ## v0.1.0 - 2024-5-10 ### bugfix: diff --git a/components/display/lcd/esp_lcd_st77903_rgb/README.md b/components/display/lcd/esp_lcd_st77903_rgb/README.md index b67417665..338897f50 100644 --- a/components/display/lcd/esp_lcd_st77903_rgb/README.md +++ b/components/display/lcd/esp_lcd_st77903_rgb/README.md @@ -6,6 +6,8 @@ Implementation of the ST77903 RGB LCD controller with [esp_lcd](https://docs.esp | :------------: | :---------------------: | :------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------: | | ST77903 | RGB | esp_lcd_ST77903_rgb | [PDF1](https://dl.espressif.com/AE/esp-iot-solution/ST77903_SPEC_P0.5.pdf)| +For more information on LCD, please refer to the [LCD documentation](https://docs.espressif.com/projects/esp-iot-solution/en/latest/display/lcd/index.html). + ## Initialization Code For most RGB LCDs, they typically use a "3-Wire SPI + Parallel RGB" interface. The "3-Wire SPI" interface is used for transmitting command data and the "Parallel RGB" interface is used for sending pixel data. diff --git a/components/display/lcd/esp_lcd_st77903_rgb/idf_component.yml b/components/display/lcd/esp_lcd_st77903_rgb/idf_component.yml index cc9b73d8c..143eb88ca 100644 --- a/components/display/lcd/esp_lcd_st77903_rgb/idf_component.yml +++ b/components/display/lcd/esp_lcd_st77903_rgb/idf_component.yml @@ -1,4 +1,4 @@ -version: "0.1.0" +version: "1.0.0" targets: - esp32s3 description: ESP LCD ST77903 RGB diff --git a/components/display/lcd/esp_lcd_st77916/CHANGELOG.md b/components/display/lcd/esp_lcd_st77916/CHANGELOG.md index 1ca78eed7..6f991c10f 100644 --- a/components/display/lcd/esp_lcd_st77916/CHANGELOG.md +++ b/components/display/lcd/esp_lcd_st77916/CHANGELOG.md @@ -1,5 +1,11 @@ # ChangeLog +## v1.0.0 - 2024-08-12 + +### Enhancements: + +* Component version maintenance, code improvement, and documentation enhancement + ## v0.0.1 - 2023-12-01 ### Enhancements: diff --git a/components/display/lcd/esp_lcd_st77916/README.md b/components/display/lcd/esp_lcd_st77916/README.md index 0ae21745b..27d87520f 100644 --- a/components/display/lcd/esp_lcd_st77916/README.md +++ b/components/display/lcd/esp_lcd_st77916/README.md @@ -8,6 +8,8 @@ Implementation of the ST77916 LCD controller with [esp_lcd](https://docs.espress | :------------: | :---------------------: | :------------: | :---------------------------------------------------------------------------: | | ST77916 | SPI/QSPI | esp_lcd_st77916 | [PDF](https://dl.espressif.com/AE/esp-iot-solution/ST77916_SPEC_V1.0.pdf) | +For more information on LCD, please refer to the [LCD documentation](https://docs.espressif.com/projects/esp-iot-solution/en/latest/display/lcd/index.html). + ## Add to project Packages from this repository are uploaded to [Espressif's component service](https://components.espressif.com/). diff --git a/components/display/lcd/esp_lcd_st77916/idf_component.yml b/components/display/lcd/esp_lcd_st77916/idf_component.yml index e3ac46f1d..8c8668617 100644 --- a/components/display/lcd/esp_lcd_st77916/idf_component.yml +++ b/components/display/lcd/esp_lcd_st77916/idf_component.yml @@ -1,5 +1,5 @@ -version: "0.0.2" -description: ESP LCD ST77916 +version: "1.0.0" +description: ESP LCD ST77916(SPI & QSPI) url: https://github.com/espressif/esp-iot-solution/tree/master/components/display/lcd/esp_lcd_st77916 repository: https://github.com/espressif/esp-iot-solution.git issues: https://github.com/espressif/esp-iot-solution/issues diff --git a/components/display/lcd/esp_lcd_st77922/CHANGELOG.md b/components/display/lcd/esp_lcd_st77922/CHANGELOG.md index 6125f8ae3..9191db379 100644 --- a/components/display/lcd/esp_lcd_st77922/CHANGELOG.md +++ b/components/display/lcd/esp_lcd_st77922/CHANGELOG.md @@ -1,5 +1,9 @@ # ChangeLog +## v1.0.0 - 2024-8-7 + +* Support MIPI-DSI interface + ## v0.1.0 - 2024-5-15 ### Enhancements: diff --git a/components/display/lcd/esp_lcd_st77922/CMakeLists.txt b/components/display/lcd/esp_lcd_st77922/CMakeLists.txt index 448b0de8f..2a32255f4 100644 --- a/components/display/lcd/esp_lcd_st77922/CMakeLists.txt +++ b/components/display/lcd/esp_lcd_st77922/CMakeLists.txt @@ -1,4 +1,4 @@ -idf_component_register(SRCS "esp_lcd_st77922.c" "esp_lcd_st77922_general.c" "esp_lcd_st77922_rgb.c" +idf_component_register(SRCS "esp_lcd_st77922.c" "esp_lcd_st77922_general.c" "esp_lcd_st77922_rgb.c" "esp_lcd_st77922_mipi.c" INCLUDE_DIRS "include" PRIV_INCLUDE_DIRS "priv_include" REQUIRES "esp_lcd" "driver") diff --git a/components/display/lcd/esp_lcd_st77922/README.md b/components/display/lcd/esp_lcd_st77922/README.md index 5827fbb82..a62ed8a05 100644 --- a/components/display/lcd/esp_lcd_st77922/README.md +++ b/components/display/lcd/esp_lcd_st77922/README.md @@ -6,7 +6,11 @@ Implementation of the ST77922 LCD controller with [esp_lcd](https://docs.espress | LCD controller | Communication interface | Component name | Link to datasheet | | :------------: | :---------------------: | :------------: | :---------------------------------------------------------------------------: | -| ST77922 | SPI/QSPI | esp_lcd_st77922 | [PDF](https://dl.espressif.com/AE/esp-iot-solution/ST77922_SPEC_V0.1.pdf) | +| ST77922 | SPI/QSPI/MIPI-DSI | esp_lcd_st77922 | [PDF](https://dl.espressif.com/AE/esp-iot-solution/ST77922_SPEC_V0.1.pdf) | + +**Note**: MIPI-DSI interface only supports ESP-IDF v5.3 and above versions. + +For more information on LCD, please refer to the [LCD documentation](https://docs.espressif.com/projects/esp-iot-solution/en/latest/display/lcd/index.html). ## Add to project @@ -118,6 +122,23 @@ Alternatively, you can create `idf_component.yml`. More is in [Espressif's docum esp_lcd_panel_init(panel_handle); esp_lcd_panel_disp_on_off(panel_handle, true); ``` +#### Notes + +* When using `esp_panel_lcd_draw_bitmap()` to refresh the screen, ensure that both `x_start` and `x_end` are divisible by `4`. This is a requirement of ST77922. For LVGL, register the following function into `rounder_cb` of `lv_disp_drv_t` to round the coordinates. + +```c +void lvgl_port_rounder_callback(struct _lv_disp_drv_t * disp_drv, lv_area_t * area) +{ + uint16_t x1 = area->x1; + uint16_t x2 = area->x2; + + // round the start of coordinate down to the nearest 4M number + area->x1 = (x1 >> 2) << 2; + + // round the end of coordinate up to the nearest 4N+3 number + area->x2 = ((x2 >> 2) << 2) + 3; +} +``` ### RGB Interface @@ -198,22 +219,56 @@ Alternatively, you can create `idf_component.yml`. More is in [Espressif's docum EXAMPLE_ESP_OK(esp_lcd_panel_init(panel_handle)); EXAMPLE_ESP_OK(esp_lcd_panel_disp_on_off(panel_handle, true)); ``` - - -## Notes - -* When using `esp_panel_lcd_draw_bitmap()` to refresh the screen, ensure that both `x_start` and `x_end` are divisible by `4`. This is a requirement of ST77922. For LVGL, register the following function into `rounder_cb` of `lv_disp_drv_t` to round the coordinates. +### MIPI Interface ```c -void lvgl_port_rounder_callback(struct _lv_disp_drv_t * disp_drv, lv_area_t * area) -{ - uint16_t x1 = area->x1; - uint16_t x2 = area->x2; +/** + * Uncomment these line if use custom initialization commands. + * The array should be declared as static const and positioned outside the function. + */ +// static const st77922_lcd_init_cmd_t lcd_init_cmds[] = { +// // cmd data data_size delay_ms +// {0xFF, (uint8_t []){0x77, 0x01, 0x00, 0x00, 0x13}, 5, 0}, +// {0xEF, (uint8_t []){0x08}, 1, 0}, +// {0xFF, (uint8_t []){0x77, 0x01, 0x00, 0x00, 0x10}, 5, 0}, +// {0xC0, (uint8_t []){0x3B, 0x00}, 2, 0}, +// ... +// }; + ESP_LOGI(TAG, "MIPI DSI PHY Powered on"); + esp_ldo_channel_config_t ldo_mipi_phy_config = { + .chan_id = EXAMPLE_MIPI_DSI_PHY_PWR_LDO_CHAN, + .voltage_mv = EXAMPLE_MIPI_DSI_PHY_PWR_LDO_VOLTAGE_MV, + }; + ESP_ERROR_CHECK(esp_ldo_acquire_channel(&ldo_mipi_phy_config, &ldo_mipi_phy)); - // round the start of coordinate down to the nearest 4M number - area->x1 = (x1 >> 2) << 2; + ESP_LOGI(TAG, "Initialize MIPI DSI bus"); + esp_lcd_dsi_bus_config_t bus_config = ST77922_PANEL_BUS_DSI_1CH_CONFIG(); + ESP_ERROR_CHECK(esp_lcd_new_dsi_bus(&bus_config, &mipi_dsi_bus)); - // round the end of coordinate up to the nearest 4N+3 number - area->x2 = ((x2 >> 2) << 2) + 3; -} + ESP_LOGI(TAG, "Install panel IO"); + esp_lcd_dbi_io_config_t dbi_config = ST77922_PANEL_IO_DBI_CONFIG(); + ESP_ERROR_CHECK(esp_lcd_new_panel_io_dbi(mipi_dsi_bus, &dbi_config, &mipi_dbi_io)); + + ESP_LOGI(TAG, "Install LCD driver of st77922"); + esp_lcd_panel_handle_t panel_handle = NULL; + esp_lcd_dpi_panel_config_t dpi_config = ST77922_480_360_PANEL_60HZ_DPI_CONFIG(EXAMPLE_MIPI_DPI_PX_FORMAT); + st77922_vendor_config_t vendor_config = { + // .init_cmds = lcd_init_cmds, // Uncomment these line if use custom initialization commands + // .init_cmds_size = sizeof(lcd_init_cmds) / sizeof(st77922_lcd_init_cmd_t), + .flags.use_mipi_interface = 1, + .mipi_config = { + .dsi_bus = mipi_dsi_bus, + .dpi_config = &dpi_config, + }, + }; + const esp_lcd_panel_dev_config_t panel_config = { + .reset_gpio_num = EXAMPLE_PIN_NUM_LCD_RST, + .rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB, + .bits_per_pixel = EXAMPLE_LCD_BIT_PER_PIXEL, + .vendor_config = &vendor_config, + }; + ESP_ERROR_CHECK(esp_lcd_new_panel_st77922(mipi_dbi_io, &panel_config, &panel_handle)); + ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle)); + ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle)); + ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_handle, true)); ``` diff --git a/components/display/lcd/esp_lcd_st77922/esp_lcd_st77922.c b/components/display/lcd/esp_lcd_st77922/esp_lcd_st77922.c index cd137469f..3e1a1cca4 100644 --- a/components/display/lcd/esp_lcd_st77922/esp_lcd_st77922.c +++ b/components/display/lcd/esp_lcd_st77922/esp_lcd_st77922.c @@ -25,24 +25,32 @@ esp_err_t esp_lcd_new_panel_st77922(const esp_lcd_panel_io_handle_t io, const es if (panel_dev_config->vendor_config) { st77922_vendor_config_t *vendor_config = (st77922_vendor_config_t *)panel_dev_config->vendor_config; - if (vendor_config->flags.use_rgb_interface && vendor_config->flags.use_qspi_interface) { - ESP_LOGE(TAG, "Both RGB and QSPI interfaces are not supported"); + if (vendor_config->flags.use_rgb_interface + vendor_config->flags.use_qspi_interface + + vendor_config->flags.use_mipi_interface > 1) { + ESP_LOGE(TAG, "Only one interface is supported"); return ESP_ERR_NOT_SUPPORTED; } +#if SOC_MIPI_DSI_SUPPORTED + if (vendor_config->flags.use_mipi_interface) { + ret = esp_lcd_new_panel_st77922_mipi(io, panel_dev_config, ret_panel); + + return ret; + } +#endif + #if SOC_LCD_RGB_SUPPORTED if (vendor_config->flags.use_rgb_interface) { - ESP_RETURN_ON_FALSE(io && vendor_config->rgb_config, ESP_ERR_INVALID_ARG, TAG, "`io` and `rgb_config` are necessary when use mipi interface"); ret = esp_lcd_new_panel_st77922_rgb(io, panel_dev_config, ret_panel); + + return ret; } #endif - if (!vendor_config->flags.use_rgb_interface) { - ESP_RETURN_ON_FALSE(io, ESP_ERR_INVALID_ARG, TAG, "`io` is necessary when use rgb interface"); - ret = esp_lcd_new_panel_st77922_general(io, panel_dev_config, ret_panel); - } + ret = esp_lcd_new_panel_st77922_general(io, panel_dev_config, ret_panel); + + return ret; } else { - ESP_RETURN_ON_FALSE(io, ESP_ERR_INVALID_ARG, TAG, "`io` is necessary when use rgb interface"); ret = esp_lcd_new_panel_st77922_general(io, panel_dev_config, ret_panel); } diff --git a/components/display/lcd/esp_lcd_st77922/esp_lcd_st77922_mipi.c b/components/display/lcd/esp_lcd_st77922/esp_lcd_st77922_mipi.c new file mode 100644 index 000000000..18a30589d --- /dev/null +++ b/components/display/lcd/esp_lcd_st77922/esp_lcd_st77922_mipi.c @@ -0,0 +1,369 @@ +/* + * 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_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_st77922.h" +#include "st77922_interface.h" + +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 st77922_lcd_init_cmd_t *init_cmds; + uint16_t init_cmds_size; + 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); +} st77922_panel_t; + +static const char *TAG = "st77922"; + +static esp_err_t panel_st77922_del(esp_lcd_panel_t *panel); +static esp_err_t panel_st77922_init(esp_lcd_panel_t *panel); +static esp_err_t panel_st77922_reset(esp_lcd_panel_t *panel); +static esp_err_t panel_st77922_invert_color(esp_lcd_panel_t *panel, bool invert_color_data); +static esp_err_t panel_st77922_mirror(esp_lcd_panel_t *panel, bool mirror_x, bool mirror_y); +static esp_err_t panel_st77922_disp_on_off(esp_lcd_panel_t *panel, bool on_off); + +esp_err_t esp_lcd_new_panel_st77922_mipi(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_LOGI(TAG, "version: %d.%d.%d", ESP_LCD_ST77922_VER_MAJOR, ESP_LCD_ST77922_VER_MINOR, + ESP_LCD_ST77922_VER_PATCH); + ESP_RETURN_ON_FALSE(io && panel_dev_config && ret_panel, ESP_ERR_INVALID_ARG, TAG, "invalid arguments"); + st77922_vendor_config_t *vendor_config = (st77922_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; + st77922_panel_t *st77922 = (st77922_panel_t *)calloc(1, sizeof(st77922_panel_t)); + ESP_RETURN_ON_FALSE(st77922, ESP_ERR_NO_MEM, TAG, "no mem for st77922 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->color_space) { + case LCD_RGB_ELEMENT_ORDER_RGB: + st77922->madctl_val = 0; + break; + case LCD_RGB_ELEMENT_ORDER_BGR: + st77922->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 + st77922->colmod_val = 0x55; + break; + case 18: // RGB666 + st77922->colmod_val = 0x66; + break; + case 24: // RGB888 + st77922->colmod_val = 0x77; + break; + default: + ESP_GOTO_ON_FALSE(false, ESP_ERR_NOT_SUPPORTED, err, TAG, "unsupported pixel width"); + break; + } + + st77922->io = io; + st77922->init_cmds = vendor_config->init_cmds; + st77922->init_cmds_size = vendor_config->init_cmds_size; + st77922->reset_gpio_num = panel_dev_config->reset_gpio_num; + st77922->flags.reset_level = panel_dev_config->flags.reset_active_high; + + // Create MIPI DPI panel + esp_lcd_panel_handle_t panel_handle = NULL; + ESP_GOTO_ON_ERROR(esp_lcd_new_panel_dpi(vendor_config->mipi_config.dsi_bus, vendor_config->mipi_config.dpi_config, &panel_handle), err, TAG, + "create MIPI DPI panel failed"); + ESP_LOGD(TAG, "new MIPI DPI panel @%p", panel_handle); + + // Save the original functions of MIPI DPI panel + st77922->del = panel_handle->del; + st77922->init = panel_handle->init; + // Overwrite the functions of MIPI DPI panel + panel_handle->del = panel_st77922_del; + panel_handle->init = panel_st77922_init; + panel_handle->reset = panel_st77922_reset; + panel_handle->mirror = panel_st77922_mirror; + panel_handle->invert_color = panel_st77922_invert_color; + panel_handle->disp_on_off = panel_st77922_disp_on_off; + panel_handle->user_data = st77922; + *ret_panel = panel_handle; + ESP_LOGD(TAG, "new st77922 panel @%p", st77922); + + return ESP_OK; + +err: + if (st77922) { + if (panel_dev_config->reset_gpio_num >= 0) { + gpio_reset_pin(panel_dev_config->reset_gpio_num); + } + free(st77922); + } + return ret; +} + +static const st77922_lcd_init_cmd_t vendor_specific_init_default[] = { +// {cmd, { data }, data_size, delay_ms} + // RGB interface + {0x28, (uint8_t []){0x00}, 0, 0}, + {0x10, (uint8_t []){0x00}, 0, 120}, + {0xD0, (uint8_t []){0x02}, 1, 0}, + // #======================CMD2====================== + {0xF1, (uint8_t []){0x00}, 1, 0}, + {0x60, (uint8_t []){0x00, 0x00, 0x00}, 3, 0}, + {0x65, (uint8_t []){0x80}, 1, 0}, + {0x66, (uint8_t []){0x02, 0x3F}, 2, 0}, + {0xBE, (uint8_t []){0x24, 0x00, 0xED}, 3, 0}, + {0x70, (uint8_t []){0x11, 0x9D, 0x11, 0xE0, 0xE0, 0x00, 0x08, 0x75, 0x00, 0x00, 0x00, 0x1A}, 12, 0}, + {0x71, (uint8_t []){0xD0}, 1, 0}, //MIPI CMD Mode + {0x71, (uint8_t []){0xD3}, 1, 0}, + {0x7B, (uint8_t []){0x00, 0x08, 0x08}, 3, 0}, + {0x80, (uint8_t []){0x55, 0x62, 0x2F, 0x17, 0xF0, 0x52, 0x70, 0xD2, 0x52, 0x62, 0xEA}, 11, 0}, + {0x81, (uint8_t []){0x26, 0x52, 0x72, 0x27}, 4, 0}, + {0x84, (uint8_t []){0x92, 0x25}, 2, 0}, + {0x86, (uint8_t []){0xC6, 0x04, 0xB1, 0x02, 0x58, 0x12, 0x58, 0x10, 0x13, 0x01, 0xA5, 0x00, 0xA5, 0xA5}, 14, 0}, + {0x87, (uint8_t []){0x10, 0x10, 0x58, 0x00, 0x02, 0x3A}, 6, 0}, + {0x88, (uint8_t []){0x00, 0x00, 0x2C, 0x10, 0x04, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x06}, 15, 0}, + {0x89, (uint8_t []){0x00, 0x00, 0x00}, 3, 0}, + {0x8A, (uint8_t []){0x13, 0x00, 0x2C, 0x00, 0x00, 0x2C, 0x10, 0x10, 0x00, 0x3E, 0x19}, 11, 0}, + {0x8B, (uint8_t []){0x15, 0xB1, 0xB1, 0x44, 0x96, 0x2C, 0x10, 0x97, 0x8E}, 9, 0}, + {0x8C, (uint8_t []){0x1D, 0xB1, 0xB1, 0x44, 0x96, 0x2C, 0x10, 0x50, 0x0F, 0x01, 0xC5, 0x12, 0x09}, 13, 0}, + {0x8D, (uint8_t []){0x0C}, 1, 0}, + {0x8E, (uint8_t []){0x33, 0x01, 0x0C, 0x13, 0x01, 0x01}, 6, 0}, + {0x90, (uint8_t []){0x00, 0x44, 0x55, 0x7A, 0x00, 0x40, 0x40, 0x3F, 0x3F}, 9, 0}, + {0x91, (uint8_t []){0x00, 0x44, 0x55, 0x7B, 0x00, 0x40, 0x7F, 0x3F, 0x3F}, 9, 0}, + {0x92, (uint8_t []){0x00, 0x44, 0x55, 0x2F, 0x00, 0x30, 0x00, 0x05, 0x3F, 0x3F}, 10, 0}, + {0x93, (uint8_t []){0x00, 0x43, 0x11, 0x3F, 0x00, 0x3F, 0x00, 0x05, 0x3F, 0x3F}, 10, 0}, + {0x94, (uint8_t []){0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 6, 0}, + {0x95, (uint8_t []){0x9D, 0x1D, 0x00, 0x00, 0xFF}, 5, 0}, + {0x96, (uint8_t []){0x44, 0x44, 0x07, 0x16, 0x3A, 0x3B, 0x01, 0x00, 0x3F, 0x3F, 0x00, 0x40}, 12, 0}, + {0x97, (uint8_t []){0x44, 0x44, 0x25, 0x34, 0x3C, 0x3D, 0x1F, 0x1E, 0x3F, 0x3F, 0x00, 0x40}, 12, 0}, + {0xBA, (uint8_t []){0x55, 0x3F, 0x3F, 0x3F, 0x3F}, 5, 0}, + {0x9A, (uint8_t []){0x40, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00}, 7, 0}, + {0x9B, (uint8_t []){0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00}, 7, 0}, + {0x9C, (uint8_t []){0x40, 0x12, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00}, 13, 0}, + {0x9D, (uint8_t []){0x80, 0x53, 0x00, 0x00, 0x00, 0x80, 0x64, 0x01}, 8, 0}, + {0x9E, (uint8_t []){0x53, 0x00, 0x00, 0x00, 0x80, 0x64, 0x01}, 7, 0}, + {0x9F, (uint8_t []){0xA0, 0x09, 0x00, 0x57}, 4, 0}, + {0xB3, (uint8_t []){0x00, 0x30, 0x0F, 0x00, 0x00, 0x00, 0x00}, 7, 0}, + {0xB4, (uint8_t []){0x10, 0x09, 0x0B, 0x02, 0x00, 0x19, 0x18, 0x13, 0x1E, 0x1D, 0x1C, 0x1E}, 12, 0}, + {0xB5, (uint8_t []){0x08, 0x12, 0x03, 0x0A, 0x19, 0x01, 0x11, 0x18, 0x1D, 0x1E, 0x1E, 0x1C}, 12, 0}, + {0xB6, (uint8_t []){0xFF, 0xFF, 0x00, 0x07, 0xFF, 0x0B, 0xFF}, 7, 0}, + {0x29, (uint8_t []){0xB7, 0x00, 0x0B, 0x12, 0x0A, 0x0B, 0x06, 0x37, 0x00, 0x02, 0x4D, 0x08, 0x14, 0x14, 0x30, 0x36, 0x0F}, 17, 0}, + {0xB8, (uint8_t []){0x00, 0x0B, 0x11, 0x09, 0x09, 0x06, 0x37, 0x06, 0x05, 0x4D, 0x08, 0x13, 0x13, 0x2F, 0x36, 0x0F}, 16, 0}, + {0xB9, (uint8_t []){0x23, 0x23}, 2, 0}, + {0xBB, (uint8_t []){0x00, 0x00}, 2, 0}, + {0xBF, (uint8_t []){0x0F, 0x13, 0x13, 0x09, 0x09, 0x09}, 6, 0}, + // #======================CMD3====================== + {0xF2, (uint8_t []){0x00}, 1, 0}, + {0x73, (uint8_t []){0x04, 0xBA, 0x12, 0x5E, 0x55}, 5, 0}, + {0x77, (uint8_t []){0x6B, 0x5B, 0xFD, 0xC3, 0xC5}, 5, 0}, + {0x7A, (uint8_t []){0x15, 0x27}, 2, 0}, + {0x7B, (uint8_t []){0x04, 0x57}, 2, 0}, + {0x7E, (uint8_t []){0x01, 0x0E}, 2, 0}, + {0xBF, (uint8_t []){0x36}, 1, 0}, + {0xE3, (uint8_t []){0x40, 0x40}, 2, 0}, + // #======================CMD1====================== + {0xF0, (uint8_t []){0x00}, 1, 0}, + {0x21, (uint8_t []){0x00}, 1, 0}, + {0x11, (uint8_t []){0x00}, 1, 120}, + {0x29, (uint8_t []){0x00}, 1, 0}, + {0x35, (uint8_t []){0x00}, 1, 0}, +}; + +static esp_err_t panel_st77922_del(esp_lcd_panel_t *panel) +{ + st77922_panel_t *st77922 = (st77922_panel_t *)panel->user_data; + + if (st77922->reset_gpio_num >= 0) { + gpio_reset_pin(st77922->reset_gpio_num); + } + // Delete MIPI DPI panel + st77922->del(panel); + free(st77922); + ESP_LOGD(TAG, "del st77922 panel @%p", st77922); + + return ESP_OK; +} + +static esp_err_t panel_st77922_init(esp_lcd_panel_t *panel) +{ + st77922_panel_t *st77922 = (st77922_panel_t *)panel->user_data; + esp_lcd_panel_io_handle_t io = st77922->io; + const st77922_lcd_init_cmd_t *init_cmds = NULL; + uint16_t init_cmds_size = 0; + bool is_command1_enable = true; + bool is_cmd_overwritten = false; + + ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, ST77922_PAGE_CMD1, (uint8_t []) { + 0x00 + }, 1), TAG, "Write cmd failed"); + // Set color format + ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, LCD_CMD_MADCTL, (uint8_t []) { + st77922->madctl_val + }, 1), TAG, "Write cmd failed"); + ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, LCD_CMD_COLMOD, (uint8_t []) { + st77922->colmod_val + }, 1), TAG, "Write cmd failed"); + + // vendor specific initialization, it can be different between manufacturers + // should consult the LCD supplier for initialization sequence code + if (st77922->init_cmds) { + init_cmds = st77922->init_cmds; + init_cmds_size = st77922->init_cmds_size; + } else { + init_cmds = vendor_specific_init_default; + init_cmds_size = sizeof(vendor_specific_init_default) / sizeof(st77922_lcd_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_command1_enable && (init_cmds[i].data_bytes > 0)) { + switch (init_cmds[i].cmd) { + case LCD_CMD_MADCTL: + is_cmd_overwritten = true; + st77922->madctl_val = ((uint8_t *)init_cmds[i].data)[0]; + break; + case LCD_CMD_COLMOD: + is_cmd_overwritten = true; + st77922->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)); + + // Check if the current cmd is the command1 enable cmd + if ((init_cmds[i].cmd == ST77922_PAGE_CMD2 || init_cmds[i].cmd == ST77922_PAGE_CMD3) && init_cmds[i].data_bytes > 0) { + is_command1_enable = false; + } else if (init_cmds[i].cmd == ST77922_PAGE_CMD1 && init_cmds[i].data_bytes > 0) { + is_command1_enable = true; + } + } + ESP_LOGD(TAG, "send init commands success"); + + ESP_RETURN_ON_ERROR(st77922->init(panel), TAG, "init MIPI DPI panel failed"); + + return ESP_OK; +} + +static esp_err_t panel_st77922_reset(esp_lcd_panel_t *panel) +{ + st77922_panel_t *st77922 = (st77922_panel_t *)panel->user_data; + esp_lcd_panel_io_handle_t io = st77922->io; + + // Perform hardware reset + if (st77922->reset_gpio_num >= 0) { + gpio_set_level(st77922->reset_gpio_num, st77922->flags.reset_level); + vTaskDelay(pdMS_TO_TICKS(10)); + gpio_set_level(st77922->reset_gpio_num, !st77922->flags.reset_level); + vTaskDelay(pdMS_TO_TICKS(120)); + } 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(120)); + } + + return ESP_OK; +} + +static esp_err_t panel_st77922_invert_color(esp_lcd_panel_t *panel, bool invert_color_data) +{ + st77922_panel_t *st77922 = (st77922_panel_t *)panel->user_data; + esp_lcd_panel_io_handle_t io = st77922->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_st77922_mirror(esp_lcd_panel_t *panel, bool mirror_x, bool mirror_y) +{ + st77922_panel_t *st77922 = (st77922_panel_t *)panel->user_data; + esp_lcd_panel_io_handle_t io = st77922->io; + uint8_t madctl_val = st77922->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 |= BIT(6); + } else { + madctl_val &= ~BIT(6); + } + if (mirror_y) { + madctl_val |= BIT(7); + } else { + madctl_val &= ~BIT(7); + } + + ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, LCD_CMD_MADCTL, (uint8_t []) { + madctl_val + }, 1), TAG, "send command failed"); + st77922->madctl_val = madctl_val; + + return ESP_OK; +} + +static esp_err_t panel_st77922_disp_on_off(esp_lcd_panel_t *panel, bool on_off) +{ + st77922_panel_t *st77922 = (st77922_panel_t *)panel->user_data; + esp_lcd_panel_io_handle_t io = st77922->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; +} +#endif diff --git a/components/display/lcd/esp_lcd_st77922/idf_component.yml b/components/display/lcd/esp_lcd_st77922/idf_component.yml index 58a3e7912..501a088e4 100644 --- a/components/display/lcd/esp_lcd_st77922/idf_component.yml +++ b/components/display/lcd/esp_lcd_st77922/idf_component.yml @@ -1,5 +1,5 @@ -version: "0.1.0" -description: ESP LCD ST77922 +version: "1.0.0" +description: ESP LCD ST77922(SPI & QSPI & RGB & MIPI-DSI) url: https://github.com/espressif/esp-iot-solution/tree/master/components/display/lcd/esp_lcd_st77922 repository: https://github.com/espressif/esp-iot-solution.git issues: https://github.com/espressif/esp-iot-solution/issues diff --git a/components/display/lcd/esp_lcd_st77922/include/esp_lcd_st77922.h b/components/display/lcd/esp_lcd_st77922/include/esp_lcd_st77922.h index 4ed35411d..7a8f3beb7 100644 --- a/components/display/lcd/esp_lcd_st77922/include/esp_lcd_st77922.h +++ b/components/display/lcd/esp_lcd_st77922/include/esp_lcd_st77922.h @@ -13,6 +13,10 @@ #include "esp_lcd_panel_rgb.h" #endif +#if SOC_MIPI_DSI_SUPPORTED +#include "esp_lcd_mipi_dsi.h" +#endif + #ifdef __cplusplus extern "C" { #endif @@ -36,17 +40,26 @@ typedef struct { * */ typedef struct { -#if SOC_LCD_RGB_SUPPORTED - const esp_lcd_rgb_panel_config_t *rgb_config; /*!< RGB panel configuration */ -#endif const st77922_lcd_init_cmd_t *init_cmds; /*!< Pointer to initialization commands array. * The array should be declared as `static const` and positioned outside the function. * Please refer to `vendor_specific_init_default` in source file */ uint16_t init_cmds_size; /* + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "driver/i2c.h" +#include "driver/spi_master.h" +#include "driver/gpio.h" +#include "esp_heap_caps.h" +#include "esp_log.h" +#include "esp_timer.h" +#include "esp_lcd_panel_ops.h" +#include "esp_lcd_panel_io.h" +#include "esp_lcd_mipi_dsi.h" +#include "esp_ldo_regulator.h" +#include "esp_dma_utils.h" +#include "unity.h" +#include "unity_test_runner.h" +#include "unity_test_utils_memory.h" + +#include "esp_lcd_st77922.h" + +#define TEST_LCD_H_RES (480) +#define TEST_LCD_V_RES (480) +#define TEST_LCD_BIT_PER_PIXEL (16) +#define TEST_PIN_NUM_LCD_RST (-1) +#define TEST_PIN_NUM_BK_LIGHT (-1) // 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 +#define TEST_MIPI_DSI_LANE_NUM (1) + +#if TEST_LCD_BIT_PER_PIXEL == 24 +#define TEST_MIPI_DPI_PX_FORMAT (LCD_COLOR_PIXEL_FORMAT_RGB888) +#elif TEST_LCD_BIT_PER_PIXEL == 18 +#define TEST_MIPI_DPI_PX_FORMAT (LCD_COLOR_PIXEL_FORMAT_RGB666) +#elif TEST_LCD_BIT_PER_PIXEL == 16 +#define TEST_MIPI_DPI_PX_FORMAT (LCD_COLOR_PIXEL_FORMAT_RGB565) +#endif + +#define TEST_DELAY_TIME_MS (3000) + +#define TEST_MIPI_DSI_PHY_PWR_LDO_CHAN (3) +#define TEST_MIPI_DSI_PHY_PWR_LDO_VOLTAGE_MV (2500) + +static char *TAG = "st77922_mipi_test"; +static esp_ldo_channel_handle_t ldo_mipi_phy = NULL; +static esp_lcd_panel_handle_t panel_handle = NULL; +static esp_lcd_dsi_bus_handle_t mipi_dsi_bus = NULL; +static esp_lcd_panel_io_handle_t mipi_dbi_io = NULL; +static SemaphoreHandle_t refresh_finish = NULL; + +IRAM_ATTR static bool test_notify_refresh_ready(esp_lcd_panel_handle_t panel, esp_lcd_dpi_panel_event_data_t *edata, void *user_ctx) +{ + SemaphoreHandle_t refresh_finish = (SemaphoreHandle_t)user_ctx; + BaseType_t need_yield = pdFALSE; + + xSemaphoreGiveFromISR(refresh_finish, &need_yield); + + return (need_yield == pdTRUE); +} + +static void test_init_lcd(void) +{ +#if TEST_PIN_NUM_BK_LIGHT >= 0 + ESP_LOGI(TAG, "Turn on LCD backlight"); + gpio_config_t bk_gpio_config = { + .mode = GPIO_MODE_OUTPUT, + .pin_bit_mask = 1ULL << TEST_PIN_NUM_BK_LIGHT + }; + TEST_ESP_OK(gpio_config(&bk_gpio_config)); + TEST_ESP_OK(gpio_set_level(TEST_PIN_NUM_BK_LIGHT, TEST_LCD_BK_LIGHT_ON_LEVEL)); +#endif + + // Turn on the power for MIPI DSI PHY, so it can go from "No Power" state to "Shutdown" state +#ifdef TEST_MIPI_DSI_PHY_PWR_LDO_CHAN + ESP_LOGI(TAG, "MIPI DSI PHY Powered on"); + esp_ldo_channel_config_t ldo_mipi_phy_config = { + .chan_id = TEST_MIPI_DSI_PHY_PWR_LDO_CHAN, + .voltage_mv = TEST_MIPI_DSI_PHY_PWR_LDO_VOLTAGE_MV, + }; + TEST_ESP_OK(esp_ldo_acquire_channel(&ldo_mipi_phy_config, &ldo_mipi_phy)); +#endif + + ESP_LOGI(TAG, "Initialize MIPI DSI bus"); + esp_lcd_dsi_bus_config_t bus_config = ST77922_MIPI_PANEL_BUS_DSI_1CH_CONFIG(); + TEST_ESP_OK(esp_lcd_new_dsi_bus(&bus_config, &mipi_dsi_bus)); + + ESP_LOGI(TAG, "Install panel IO"); + esp_lcd_dbi_io_config_t dbi_config = ST77922_MIPI_PANEL_IO_DBI_CONFIG(); + TEST_ESP_OK(esp_lcd_new_panel_io_dbi(mipi_dsi_bus, &dbi_config, &mipi_dbi_io)); + + ESP_LOGI(TAG, "Install LCD driver of st77922_mipi"); + esp_lcd_dpi_panel_config_t dpi_config = ST77922_MIPI_480_480_PANEL_60HZ_DPI_CONFIG(TEST_MIPI_DPI_PX_FORMAT); + st77922_vendor_config_t vendor_config = { + .flags = { + .use_mipi_interface = 1, + }, + .mipi_config = { + .dsi_bus = mipi_dsi_bus, + .dpi_config = &dpi_config, + }, + }; + const esp_lcd_panel_dev_config_t panel_config = { + .reset_gpio_num = TEST_PIN_NUM_LCD_RST, + .rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB, + .bits_per_pixel = TEST_LCD_BIT_PER_PIXEL, + .vendor_config = &vendor_config, + }; + TEST_ESP_OK(esp_lcd_new_panel_st77922(mipi_dbi_io, &panel_config, &panel_handle)); + TEST_ESP_OK(esp_lcd_panel_reset(panel_handle)); + TEST_ESP_OK(esp_lcd_panel_init(panel_handle)); + TEST_ESP_OK(esp_lcd_panel_disp_on_off(panel_handle, true)); + + refresh_finish = xSemaphoreCreateBinary(); + TEST_ASSERT_NOT_NULL(refresh_finish); + esp_lcd_dpi_panel_event_callbacks_t cbs = { + .on_color_trans_done = test_notify_refresh_ready, + }; + TEST_ESP_OK(esp_lcd_dpi_panel_register_event_callbacks(panel_handle, &cbs, refresh_finish)); +} + +static void test_deinit_lcd(void) +{ + TEST_ESP_OK(esp_lcd_panel_del(panel_handle)); + TEST_ESP_OK(esp_lcd_panel_io_del(mipi_dbi_io)); + TEST_ESP_OK(esp_lcd_del_dsi_bus(mipi_dsi_bus)); + panel_handle = NULL; + mipi_dbi_io = NULL; + mipi_dsi_bus = NULL; + + if (ldo_mipi_phy) { + TEST_ESP_OK(esp_ldo_release_channel(ldo_mipi_phy)); + ldo_mipi_phy = NULL; + } + + vSemaphoreDelete(refresh_finish); + refresh_finish = NULL; + +#if TEST_PIN_NUM_BK_LIGHT >= 0 + TEST_ESP_OK(gpio_reset_pin(TEST_PIN_NUM_BK_LIGHT)); +#endif +} + +static void test_draw_color_bar(esp_lcd_panel_handle_t panel_handle, uint16_t h_res, uint16_t v_res) +{ + uint8_t byte_per_pixel = (TEST_LCD_BIT_PER_PIXEL + 7) / 8; + uint16_t row_line = v_res / byte_per_pixel / 8; + uint8_t *color = (uint8_t *)heap_caps_calloc(1, row_line * h_res * byte_per_pixel, MALLOC_CAP_DMA); + + for (int j = 0; j < byte_per_pixel * 8; j++) { + for (int i = 0; i < row_line * h_res; i++) { + for (int k = 0; k < byte_per_pixel; k++) { + color[i * byte_per_pixel + k] = (BIT(j) >> (k * 8)) & 0xff; + } + } + TEST_ESP_OK(esp_lcd_panel_draw_bitmap(panel_handle, 0, j * row_line, h_res, (j + 1) * row_line, color)); + xSemaphoreTake(refresh_finish, portMAX_DELAY); + } + + uint16_t color_line = row_line * byte_per_pixel * 8; + uint16_t res_line = v_res - color_line; + if (res_line) { + for (int i = 0; i < res_line * h_res; i++) { + for (int k = 0; k < byte_per_pixel; k++) { + color[i * byte_per_pixel + k] = 0xff; + } + } + TEST_ESP_OK(esp_lcd_panel_draw_bitmap(panel_handle, 0, color_line, h_res, v_res, color)); + xSemaphoreTake(refresh_finish, portMAX_DELAY); + } + + free(color); +} + +TEST_CASE("test st77922_mipi to draw pattern with MIPI interface", "[st77922_mipi][draw_pattern]") +{ + ESP_LOGI(TAG, "Initialize LCD device"); + test_init_lcd(); + + ESP_LOGI(TAG, "Show color bar pattern drawn by hardware"); + TEST_ESP_OK(esp_lcd_dpi_panel_set_pattern(panel_handle, MIPI_DSI_PATTERN_BAR_VERTICAL)); + vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_TIME_MS)); + TEST_ESP_OK(esp_lcd_dpi_panel_set_pattern(panel_handle, MIPI_DSI_PATTERN_BAR_HORIZONTAL)); + vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_TIME_MS)); + TEST_ESP_OK(esp_lcd_dpi_panel_set_pattern(panel_handle, MIPI_DSI_PATTERN_NONE)); + + ESP_LOGI(TAG, "Deinitialize LCD device"); + test_deinit_lcd(); +} + +TEST_CASE("test st77922_mipi to draw color bar with MIPI interface", "[st77922_mipi][draw_color_bar]") +{ + ESP_LOGI(TAG, "Initialize LCD device"); + test_init_lcd(); + + ESP_LOGI(TAG, "Show color bar drawn by software"); + test_draw_color_bar(panel_handle, TEST_LCD_H_RES, TEST_LCD_V_RES); + vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_TIME_MS)); + + ESP_LOGI(TAG, "Deinitialize LCD device"); + test_deinit_lcd(); +} + +TEST_CASE("test st77922_mipi to rotate with MIPI interface", "[st77922_mipi][rotate]") +{ + esp_err_t ret = ESP_OK; + + uint16_t w = 0; + uint16_t h = 0; + int64_t t = 0; + + ESP_LOGI(TAG, "Initialize LCD device"); + test_init_lcd(); + + ESP_LOGI(TAG, "Rotate the screen"); + for (size_t i = 0; i < 8; i++) { + if (ret != ESP_ERR_NOT_SUPPORTED) { + if (i & 4) { + w = TEST_LCD_V_RES; + h = TEST_LCD_H_RES; + } else { + w = TEST_LCD_H_RES; + h = TEST_LCD_V_RES; + } + } + + TEST_ASSERT_NOT_EQUAL(esp_lcd_panel_mirror(panel_handle, i & 2, i & 1), ESP_FAIL); + ret = esp_lcd_panel_swap_xy(panel_handle, i & 4); + TEST_ASSERT_NOT_EQUAL(ret, ESP_FAIL); + + ESP_LOGI(TAG, "Rotation: %d", i); + t = esp_timer_get_time(); + test_draw_color_bar(panel_handle, w, h); + t = esp_timer_get_time() - t; + ESP_LOGI(TAG, "@resolution %dx%d time per frame=%.2fMS\r\n", w, h, (float)t / 1000.0f); + vTaskDelay(pdMS_TO_TICKS(1000)); + } + + ESP_LOGI(TAG, "Deinitialize LCD device"); + test_deinit_lcd(); +} +#endif diff --git a/components/display/lcd/esp_lcd_st77922/test_apps/sdkconfig.defaults.esp32p4 b/components/display/lcd/esp_lcd_st77922/test_apps/sdkconfig.defaults.esp32p4 new file mode 100644 index 000000000..e1b870f33 --- /dev/null +++ b/components/display/lcd/esp_lcd_st77922/test_apps/sdkconfig.defaults.esp32p4 @@ -0,0 +1,5 @@ +CONFIG_SPIRAM=y +CONFIG_COMPILER_OPTIMIZATION_PERF=y +CONFIG_IDF_EXPERIMENTAL_FEATURES=y +CONFIG_SPIRAM_MODE_HEX=y +CONFIG_SPIRAM_SPEED_200M=y diff --git a/components/display/lcd/esp_lcd_usb_display/CHANGELOG.md b/components/display/lcd/esp_lcd_usb_display/CHANGELOG.md index fb15ca46e..c420a5a37 100644 --- a/components/display/lcd/esp_lcd_usb_display/CHANGELOG.md +++ b/components/display/lcd/esp_lcd_usb_display/CHANGELOG.md @@ -1,5 +1,11 @@ # ChangeLog +## v1.0.0 - 2024-08-12 + +### Enhancements: + +* Component version maintenance, code improvement, and documentation enhancement + ## v0.1.1 - 2024-06-13 * update `usb_device_uvc` to `v1.1.*` diff --git a/components/display/lcd/esp_lcd_usb_display/idf_component.yml b/components/display/lcd/esp_lcd_usb_display/idf_component.yml index 6be331101..b5c353415 100644 --- a/components/display/lcd/esp_lcd_usb_display/idf_component.yml +++ b/components/display/lcd/esp_lcd_usb_display/idf_component.yml @@ -1,4 +1,4 @@ -version: "0.1.1" +version: "1.0.0" targets: - esp32p4 description: ESP LCD USB Display diff --git a/components/display/lcd_touch/esp_lcd_touch_spd2010/CHANGELOG.md b/components/display/lcd_touch/esp_lcd_touch_spd2010/CHANGELOG.md index 1b4ea2f77..a5b34e5f4 100644 --- a/components/display/lcd_touch/esp_lcd_touch_spd2010/CHANGELOG.md +++ b/components/display/lcd_touch/esp_lcd_touch_spd2010/CHANGELOG.md @@ -1,5 +1,11 @@ # ChangeLog +## v1.0.0 - 2024-08-12 + +### Enhancements: + +* Component version maintenance, code improvement, and documentation enhancement + ## v0.0.1 - 2023-08-21 ### Enhancements: diff --git a/components/display/lcd_touch/esp_lcd_touch_spd2010/idf_component.yml b/components/display/lcd_touch/esp_lcd_touch_spd2010/idf_component.yml index 2e92671dd..e4b094fcf 100644 --- a/components/display/lcd_touch/esp_lcd_touch_spd2010/idf_component.yml +++ b/components/display/lcd_touch/esp_lcd_touch_spd2010/idf_component.yml @@ -1,4 +1,4 @@ -version: "0.0.1" +version: "1.0.0" description: ESP LCD Touch SPD2010 - touch controller SPD2010 url: https://github.com/espressif/esp-iot-solution/tree/master/components/display/lcd_touch/esp_lcd_touch_spd2010 repository: https://github.com/espressif/esp-iot-solution.git diff --git a/components/display/lcd_touch/esp_lcd_touch_st7123/CHANGELOG.md b/components/display/lcd_touch/esp_lcd_touch_st7123/CHANGELOG.md index 040a09152..95ddde13b 100644 --- a/components/display/lcd_touch/esp_lcd_touch_st7123/CHANGELOG.md +++ b/components/display/lcd_touch/esp_lcd_touch_st7123/CHANGELOG.md @@ -1,5 +1,11 @@ # ChangeLog +## v1.0.0 - 2024-08-12 + +### Enhancements: + +* Component version maintenance, code improvement, and documentation enhancement + ## v0.0.1 - 2024-02-19 ### Enhancements: diff --git a/components/display/lcd_touch/esp_lcd_touch_st7123/idf_component.yml b/components/display/lcd_touch/esp_lcd_touch_st7123/idf_component.yml index 4d34557f0..44cf58cfc 100644 --- a/components/display/lcd_touch/esp_lcd_touch_st7123/idf_component.yml +++ b/components/display/lcd_touch/esp_lcd_touch_st7123/idf_component.yml @@ -1,4 +1,4 @@ -version: "0.0.1" +version: "1.0.0" description: ESP LCD Touch ST7123 - touch controller ST7123 url: https://github.com/espressif/esp-iot-solution/tree/master/components/display/lcd_touch/esp_lcd_touch_st7123 repository: https://github.com/espressif/esp-iot-solution.git diff --git a/docs/en/display/lcd/lcd_development_guide.rst b/docs/en/display/lcd/lcd_development_guide.rst index b35785c24..5c2222e10 100644 --- a/docs/en/display/lcd/lcd_development_guide.rst +++ b/docs/en/display/lcd/lcd_development_guide.rst @@ -88,7 +88,7 @@ Driver and Examples * - I80 - `axs15231b `_, `st7789 `_, `nt35510 `_, `ra8875 `_, `st7796 `_ * - MIPI-DSI - - `ek79007 `_, `jd9165 `_, `jd9365 `_, `st7701 `_ + - `ek79007 `_, `jd9165 `_, `jd9365 `_, `st7701 `_, `ili9881c `_ * - 3-wire SPI + RGB - `st7701 `_, `st77903_rgb `_, `st77922 `_, `gc9503 `_ diff --git a/docs/zh_CN/display/lcd/lcd_development_guide.rst b/docs/zh_CN/display/lcd/lcd_development_guide.rst index 6204e2948..a501e6c87 100644 --- a/docs/zh_CN/display/lcd/lcd_development_guide.rst +++ b/docs/zh_CN/display/lcd/lcd_development_guide.rst @@ -88,7 +88,7 @@ LCD 开发指南 * - I80 - `axs15231b `_, `st7789 `_, `nt35510 `_, `ra8875 `_, `st7796 `_ * - MIPI-DSI - - `ek79007 `_, `jd9165 `_, `jd9365 `_, `st7701 `_ + - `ek79007 `_, `jd9165 `_, `jd9365 `_, `st7701 `_, `ili9881c `_ * - 3-wire SPI + RGB - `st7701 `_, `st77903_rgb `_, `st77922 `_, `gc9503 `_