Преглед изворни кода

Merge branch 'feature/i80_lcd_allow_skip_command_phase' into 'master'

i80_lcd: allow skip command phase

Closes IDFGH-9426

See merge request espressif/esp-idf!23042
morris пре 2 година
родитељ
комит
b5ccdc911d

+ 4 - 4
components/esp_lcd/include/esp_lcd_panel_commands.h

@@ -1,5 +1,5 @@
 /*
- * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
+ * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
  *
  * SPDX-License-Identifier: Apache-2.0
  */
@@ -31,7 +31,7 @@
 #define LCD_CMD_RAMRD        0x2E // Read frame memory
 #define LCD_CMD_PTLAR        0x30 // Define the partial area
 #define LCD_CMD_VSCRDEF      0x33 // Vertical scrolling definition
-#define LCD_CMD_TEOFF        0x34 // Turns of tearing effect
+#define LCD_CMD_TEOFF        0x34 // Turns off tearing effect
 #define LCD_CMD_TEON         0x35 // Turns on tearing effect
 
 #define LCD_CMD_MADCTL       0x36     // Memory data access control
@@ -48,7 +48,7 @@
 #define LCD_CMD_COLMOD       0x3A // Defines the format of RGB picture data
 #define LCD_CMD_RAMWRC       0x3C // Memory write continue
 #define LCD_CMD_RAMRDC       0x3E // Memory read continue
-#define LCD_CMD_STE          0x44 // Set tear scanline, tearing effect output signal when display module reaches line N
-#define LCD_CMD_GDCAN        0x45 // Get scanline
+#define LCD_CMD_STE          0x44 // Set tear scan line, tearing effect output signal when display module reaches line N
+#define LCD_CMD_GDCAN        0x45 // Get scan line
 #define LCD_CMD_WRDISBV      0x51 // Write display brightness
 #define LCD_CMD_RDDISBV      0x52 // Read display brightness value

+ 2 - 2
components/esp_lcd/include/esp_lcd_panel_io.h

@@ -1,5 +1,5 @@
 /*
- * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
+ * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
  *
  * SPDX-License-Identifier: Apache-2.0
  */
@@ -71,7 +71,7 @@ esp_err_t esp_lcd_panel_io_rx_param(esp_lcd_panel_io_handle_t io, int lcd_cmd, v
  *       this function will wait until they are finished and the queue is empty before sending the command(s).
  *
  * @param[in] io LCD panel IO handle, which is created by other factory API like `esp_lcd_new_panel_io_spi()`
- * @param[in] lcd_cmd The specific LCD command (set to -1 if no command needed - only in SPI and I2C)
+ * @param[in] lcd_cmd The specific LCD command, set to -1 if no command needed
  * @param[in] param Buffer that holds the command specific parameters, set to NULL if no parameter is needed for the command
  * @param[in] param_size Size of `param` in memory, in bytes, set to zero if no parameter is needed for the command
  * @return

+ 10 - 3
components/esp_lcd/src/esp_lcd_panel_io_i80.c

@@ -1,5 +1,5 @@
 /*
- * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
+ * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
  *
  * SPDX-License-Identifier: Apache-2.0
  */
@@ -578,9 +578,16 @@ static void lcd_periph_trigger_quick_trans_done_event(esp_lcd_i80_bus_handle_t b
 static void lcd_start_transaction(esp_lcd_i80_bus_t *bus, lcd_i80_trans_descriptor_t *trans_desc)
 {
     // by default, the dummy phase is disabled because it's not common for most LCDs
+    uint32_t dummy_cycles = 0;
+    uint32_t cmd_cycles = trans_desc->cmd_value >= 0 ? trans_desc->cmd_cycles : 0;
     // Number of data phase cycles are controlled by DMA buffer length, we only need to enable/disable the phase here
-    lcd_ll_set_phase_cycles(bus->hal.dev, trans_desc->cmd_cycles, 0, trans_desc->data ? 1 : 0);
-    lcd_ll_set_command(bus->hal.dev, bus->bus_width, trans_desc->cmd_value);
+    uint32_t data_cycles = trans_desc->data ? 1 : 0;
+    if (trans_desc->cmd_value >= 0) {
+        lcd_ll_set_command(bus->hal.dev, bus->bus_width, trans_desc->cmd_value);
+    }
+    lcd_ll_set_phase_cycles(bus->hal.dev, cmd_cycles, dummy_cycles, data_cycles);
+    lcd_ll_set_blank_cycles(bus->hal.dev, 1, 1);
+
     if (trans_desc->data) { // some specific LCD commands can have no parameters
         gdma_start(bus->dma_chan, (intptr_t)(bus->dma_nodes));
         // delay 1us is sufficient for DMA to pass data to LCD FIFO

+ 53 - 0
components/esp_lcd/test_apps/i80_lcd/main/test_i80_lcd_panel.c

@@ -453,3 +453,56 @@ TEST_CASE("lcd_panel_with_i80_interface_(st7789, 8bits)", "[lcd]")
     free(img);
 #undef TEST_IMG_SIZE
 }
+
+TEST_CASE("i80_io_skip_command_phase", "[lcd]")
+{
+    esp_lcd_i80_bus_handle_t i80_bus = NULL;
+    esp_lcd_i80_bus_config_t bus_config = {
+        .dc_gpio_num = TEST_LCD_DC_GPIO,
+        .wr_gpio_num = TEST_LCD_PCLK_GPIO,
+        .clk_src = LCD_CLK_SRC_DEFAULT,
+        .data_gpio_nums = {
+            TEST_LCD_DATA0_GPIO,
+            TEST_LCD_DATA1_GPIO,
+            TEST_LCD_DATA2_GPIO,
+            TEST_LCD_DATA3_GPIO,
+            TEST_LCD_DATA4_GPIO,
+            TEST_LCD_DATA5_GPIO,
+            TEST_LCD_DATA6_GPIO,
+            TEST_LCD_DATA7_GPIO,
+        },
+        .bus_width = 8,
+        .max_transfer_bytes = 100,
+    };
+    esp_lcd_panel_io_handle_t io_handle = NULL;
+    esp_lcd_panel_io_i80_config_t io_config = {
+        .cs_gpio_num = TEST_LCD_CS_GPIO,
+        .pclk_hz = 5000000, // 5MHz
+        .trans_queue_depth = 10,
+        .dc_levels = {
+            .dc_idle_level = 0,
+            .dc_cmd_level = 0,
+            .dc_dummy_level = 0,
+            .dc_data_level = 1,
+        },
+        .lcd_cmd_bits = 8,
+        .lcd_param_bits = 8,
+    };
+
+    TEST_ESP_OK(esp_lcd_new_i80_bus(&bus_config, &i80_bus));
+    TEST_ESP_OK(esp_lcd_new_panel_io_i80(i80_bus, &io_config, &io_handle));
+
+    uint8_t buf[4] = {0x01, 0x02, 0x03, 0x04};
+    // lcd_cmd = -1 to skip the command phase
+    TEST_ESP_OK(esp_lcd_panel_io_tx_color(io_handle, -1, buf, 4));
+    vTaskDelay(100 / portTICK_PERIOD_MS);
+    TEST_ESP_OK(esp_lcd_panel_io_tx_param(io_handle, -1, buf, 4));
+
+    // use command phase
+    TEST_ESP_OK(esp_lcd_panel_io_tx_color(io_handle, 0x2C, buf, 4));
+    vTaskDelay(100 / portTICK_PERIOD_MS);
+    TEST_ESP_OK(esp_lcd_panel_io_tx_param(io_handle, 0x2A, buf, 4));
+
+    TEST_ESP_OK(esp_lcd_panel_io_del(io_handle));
+    TEST_ESP_OK(esp_lcd_del_i80_bus(i80_bus));
+}

+ 1 - 1
examples/peripherals/lcd/i80_controller/main/Kconfig.projbuild

@@ -47,7 +47,7 @@ menu "Example Configuration"
 
     config EXAMPLE_LCD_TOUCH_ENABLED
         bool "Enable LCD touch"
-        default y
+        default n
         help
             Enable this option if you wish to use display touch. You can select from three touch controllers.
 

+ 5 - 2
examples/peripherals/lcd/i80_controller/sdkconfig.defaults.esp32s3

@@ -1,4 +1,7 @@
 CONFIG_SPIRAM=y
 CONFIG_SPIRAM_SPEED_80M=y
-# Can't set the FPS too high due to the limitation of PSRAM bandwidth
-CONFIG_LV_DISP_DEF_REFR_PERIOD=100
+
+# Enabling the following configurations can help increase the PCLK frequency in the case when
+# the Frame Buffer is allocated from the PSRAM and fetched by EDMA
+CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y
+CONFIG_SPIRAM_RODATA=y