Răsfoiți Sursa

Merge branch 'feature/i80_lcd_psram_s3' into 'master'

lcd: i80 lcd can transfer framebuffer in PSRAM

Closes IDFGH-6426

See merge request espressif/esp-idf!16548
morris 4 ani în urmă
părinte
comite
6050388f51

+ 3 - 1
components/esp_lcd/include/esp_lcd_panel_io.h

@@ -1,5 +1,5 @@
 /*
- * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
+ * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
  *
  * SPDX-License-Identifier: Apache-2.0
  */
@@ -151,6 +151,8 @@ typedef struct {
     int data_gpio_nums[SOC_LCD_I80_BUS_WIDTH]; /*!< GPIOs used for data lines */
     size_t bus_width;          /*!< Number of data lines, 8 or 16 */
     size_t max_transfer_bytes; /*!< Maximum transfer size, this determines the length of internal DMA link */
+    size_t psram_trans_align;  /*!< DMA transfer alignment for data allocated from PSRAM */
+    size_t sram_trans_align;   /*!< DMA transfer alignment for data allocated from SRAM */
 } esp_lcd_i80_bus_config_t;
 
 /**

+ 22 - 2
components/esp_lcd/src/esp_lcd_panel_io_i80.c

@@ -24,6 +24,7 @@
 #include "esp_rom_gpio.h"
 #include "soc/soc_caps.h"
 #include "soc/rtc.h" // for `rtc_clk_xtal_freq_get()`
+#include "soc/soc_memory_types.h"
 #include "hal/dma_types.h"
 #include "hal/gpio_hal.h"
 #include "esp_private/gdma.h"
@@ -41,6 +42,9 @@ typedef struct esp_lcd_i80_bus_t esp_lcd_i80_bus_t;
 typedef struct lcd_panel_io_i80_t lcd_panel_io_i80_t;
 typedef struct lcd_i80_trans_descriptor_t lcd_i80_trans_descriptor_t;
 
+// This function is located in ROM (also see esp_rom/${target}/ld/${target}.rom.ld)
+extern int Cache_WriteBack_Addr(uint32_t addr, uint32_t size);
+
 static esp_err_t panel_io_i80_tx_param(esp_lcd_panel_io_t *io, int lcd_cmd, const void *param, size_t param_size);
 static esp_err_t panel_io_i80_tx_color(esp_lcd_panel_io_t *io, int lcd_cmd, const void *color, size_t color_size);
 static esp_err_t panel_io_i80_del(esp_lcd_panel_io_t *io);
@@ -63,6 +67,8 @@ struct esp_lcd_i80_bus_t {
     uint8_t *format_buffer;  // The driver allocates an internal buffer for DMA to do data format transformer
     size_t resolution_hz;    // LCD_CLK resolution, determined by selected clock source
     gdma_channel_handle_t dma_chan; // DMA channel handle
+    size_t psram_trans_align; // DMA transfer alignment for data allocated from PSRAM
+    size_t sram_trans_align;  // DMA transfer alignment for data allocated from SRAM
     lcd_i80_trans_descriptor_t *cur_trans; // Current transaction
     lcd_panel_io_i80_t *cur_device; // Current working device
     LIST_HEAD(i80_device_list, lcd_panel_io_i80_t) device_list; // Head of i80 device list
@@ -120,11 +126,11 @@ esp_err_t esp_lcd_new_i80_bus(const esp_lcd_i80_bus_config_t *bus_config, esp_lc
     ESP_GOTO_ON_FALSE(bus_config && ret_bus, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
     size_t num_dma_nodes = bus_config->max_transfer_bytes / DMA_DESCRIPTOR_BUFFER_MAX_SIZE + 1;
     // DMA descriptors must be placed in internal SRAM
-    bus = heap_caps_calloc(1, sizeof(esp_lcd_i80_bus_t) + num_dma_nodes * sizeof(dma_descriptor_t), MALLOC_CAP_DMA);
+    bus = heap_caps_calloc(1, sizeof(esp_lcd_i80_bus_t) + num_dma_nodes * sizeof(dma_descriptor_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA);
     ESP_GOTO_ON_FALSE(bus, ESP_ERR_NO_MEM, err, TAG, "no mem for i80 bus");
     bus->num_dma_nodes = num_dma_nodes;
     bus->bus_id = -1;
-    bus->format_buffer = heap_caps_calloc(1, CONFIG_LCD_PANEL_IO_FORMAT_BUF_SIZE, MALLOC_CAP_DMA);
+    bus->format_buffer = heap_caps_calloc(1, CONFIG_LCD_PANEL_IO_FORMAT_BUF_SIZE, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA);
     ESP_GOTO_ON_FALSE(bus->format_buffer, ESP_ERR_NO_MEM, err, TAG, "no mem for format buffer");
     // register to platform
     int bus_id = lcd_com_register_device(LCD_COM_DEVICE_TYPE_I80, bus);
@@ -151,6 +157,8 @@ esp_err_t esp_lcd_new_i80_bus(const esp_lcd_i80_bus_config_t *bus_config, esp_lc
     lcd_ll_enable_interrupt(bus->hal.dev, LCD_LL_EVENT_TRANS_DONE, false); // disable all interrupts
     lcd_ll_clear_interrupt_status(bus->hal.dev, UINT32_MAX); // clear pending interrupt
     // install DMA service
+    bus->psram_trans_align = bus_config->psram_trans_align;
+    bus->sram_trans_align = bus_config->sram_trans_align;
     ret = lcd_i80_init_dma_link(bus);
     ESP_GOTO_ON_ERROR(ret, err, TAG, "install DMA failed");
     // enable 8080 mode and set bus width
@@ -436,6 +444,12 @@ static esp_err_t panel_io_i80_tx_color(esp_lcd_panel_io_t *io, int lcd_cmd, cons
     trans_desc->data_length = color_size;
     trans_desc->trans_done_cb = i80_device->on_color_trans_done;
     trans_desc->user_ctx = i80_device->user_ctx;
+
+    if (esp_ptr_external_ram(color)) {
+        // flush framebuffer from cache to the physical PSRAM
+        Cache_WriteBack_Addr((uint32_t)color, color_size);
+    }
+
     // send transaction to trans_queue
     xQueueSend(i80_device->trans_queue, &trans_desc, portMAX_DELAY);
     i80_device->num_trans_inflight++;
@@ -489,6 +503,12 @@ static esp_err_t lcd_i80_init_dma_link(esp_lcd_i80_bus_handle_t bus)
         .owner_check = true
     };
     gdma_apply_strategy(bus->dma_chan, &strategy_config);
+    // set DMA transfer ability
+    gdma_transfer_ability_t ability = {
+        .psram_trans_align = bus->psram_trans_align,
+        .sram_trans_align = bus->sram_trans_align,
+    };
+    gdma_set_transfer_ability(bus->dma_chan, &ability);
     return ESP_OK;
 err:
     if (bus->dma_chan) {

+ 0 - 151
components/esp_lcd/test/test_i80_lcd_panel.c

@@ -408,157 +408,6 @@ TEST_CASE("lcd panel with i80 interface (st7789, 8bits)", "[lcd]")
 #undef TEST_IMG_SIZE
 }
 
-// The following test shows a porting example of LVGL GUI library
-// To run the LVGL tests, you need to clone the LVGL library into components directory firstly
-#if CONFIG_LV_USE_USER_DATA
-#include "test_lvgl_port.h"
-
-static bool notify_lvgl_ready_to_flush(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *edata, void *user_ctx)
-{
-    lv_disp_t *disp = *(lv_disp_t **)user_ctx;
-    lv_disp_flush_ready(&disp->driver);
-    return false;
-}
-
-TEST_CASE("lvgl gui with i80 interface (st7789, 8bits)", "[lcd][lvgl][ignore]")
-{
-    // initialize LVGL graphics library
-    lv_disp_t *disp = NULL;
-    lv_init();
-
-    gpio_config_t bk_gpio_config = {
-        .mode = GPIO_MODE_OUTPUT,
-        .pin_bit_mask = 1ULL << TEST_LCD_BK_LIGHT_GPIO
-    };
-    TEST_ESP_OK(gpio_config(&bk_gpio_config));
-
-    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,
-        .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 = TEST_LCD_H_RES * 40 * sizeof(uint16_t)
-    };
-    TEST_ESP_OK(esp_lcd_new_i80_bus(&bus_config, &i80_bus));
-    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 = 10000000, // 10MHz
-        .trans_queue_depth = 10,
-        .dc_levels = {
-            .dc_idle_level = 0,
-            .dc_cmd_level = 0,
-            .dc_dummy_level = 0,
-            .dc_data_level = 1,
-        },
-        .flags = {
-            .swap_color_bytes = 1,
-        },
-        .on_color_trans_done = notify_lvgl_ready_to_flush,
-        .user_ctx = &disp,
-        .lcd_cmd_bits = 8,
-        .lcd_param_bits = 8,
-    };
-    TEST_ESP_OK(esp_lcd_new_panel_io_i80(i80_bus, &io_config, &io_handle));
-
-    esp_lcd_panel_handle_t panel_handle = NULL;
-    esp_lcd_panel_dev_config_t panel_config = {
-        .reset_gpio_num = TEST_LCD_RST_GPIO,
-        .color_space = ESP_LCD_COLOR_SPACE_RGB,
-        .bits_per_pixel = 16,
-    };
-    TEST_ESP_OK(esp_lcd_new_panel_st7789(io_handle, &panel_config, &panel_handle));
-
-    // turn off backlight
-    gpio_set_level(TEST_LCD_BK_LIGHT_GPIO, 0);
-    esp_lcd_panel_reset(panel_handle);
-    esp_lcd_panel_init(panel_handle);
-    esp_lcd_panel_invert_color(panel_handle, true);
-    // the gap is LCD panel specific, even panels with the same driver IC, can have different gap value
-    esp_lcd_panel_set_gap(panel_handle, 0, 20);
-    // turn on backlight
-    gpio_set_level(TEST_LCD_BK_LIGHT_GPIO, 1);
-
-    test_lvgl_task_loop(panel_handle, TEST_LCD_H_RES, TEST_LCD_V_RES, &disp);
-}
-
-#define TEST_NT35510_DATA_WIDTH (8) // change this to 16 when NT35510 is configured to 16bit in length
-TEST_CASE("lvgl gui with i80 interface (nt35510, 8/16bits)", "[lcd][lvgl][ignore]")
-{
-    // initialize LVGL graphics library
-    lv_disp_t *disp = NULL;
-    lv_init();
-
-    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,
-        .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,
-            TEST_LCD_DATA8_GPIO,
-            TEST_LCD_DATA9_GPIO,
-            TEST_LCD_DATA10_GPIO,
-            TEST_LCD_DATA11_GPIO,
-            TEST_LCD_DATA12_GPIO,
-            TEST_LCD_DATA13_GPIO,
-            TEST_LCD_DATA14_GPIO,
-            TEST_LCD_DATA15_GPIO,
-        },
-        .bus_width = TEST_NT35510_DATA_WIDTH,
-        .max_transfer_bytes = TEST_LCD_H_RES * 40 * sizeof(uint16_t)
-    };
-    TEST_ESP_OK(esp_lcd_new_i80_bus(&bus_config, &i80_bus));
-    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 = 10000000, // 10MHz
-        .trans_queue_depth = 4,
-        .dc_levels = {
-            .dc_idle_level = 0,
-            .dc_cmd_level = 0,
-            .dc_dummy_level = 0,
-            .dc_data_level = 1,
-        },
-        .on_color_trans_done = notify_lvgl_ready_to_flush,
-        .user_ctx = &disp,
-        .lcd_cmd_bits = 16,
-        .lcd_param_bits = 16,
-    };
-    TEST_ESP_OK(esp_lcd_new_panel_io_i80(i80_bus, &io_config, &io_handle));
-
-    esp_lcd_panel_handle_t panel_handle = NULL;
-    esp_lcd_panel_dev_config_t panel_config = {
-        .reset_gpio_num = -1,
-        .color_space = ESP_LCD_COLOR_SPACE_RGB,
-        .bits_per_pixel = 16,
-    };
-    TEST_ESP_OK(esp_lcd_new_panel_nt35510(io_handle, &panel_config, &panel_handle));
-
-    esp_lcd_panel_reset(panel_handle);
-    esp_lcd_panel_init(panel_handle);
-    esp_lcd_panel_swap_xy(panel_handle, true);
-    esp_lcd_panel_mirror(panel_handle, true, false);
-
-    test_lvgl_task_loop(panel_handle, TEST_LCD_H_RES, TEST_LCD_V_RES, &disp);
-}
-#endif // CONFIG_LV_USE_USER_DATA
 #endif // SOC_LCD_I80_SUPPORTED
 
 #if SOC_I2S_LCD_I80_VARIANT

+ 1 - 1
docs/en/api-reference/peripherals/lcd.rst

@@ -23,7 +23,7 @@ Application Example
 LCD examples are located under: :example:`peripherals/lcd`:
 
 * Jpeg decoding and LCD display - :example:`peripherals/lcd/tjpgd`
-* LVGL porting and animation UI - :example:`peripherals/lcd/lvgl`
+* i80 controller based LCD and LVGL animation UI - :example:`peripherals/lcd/i80_controller`
 * GC9A01 user customized driver and dash board UI - :example:`peripherals/lcd/gc9a01`
 
 API Reference

+ 1 - 1
examples/peripherals/lcd/gc9a01/README.md

@@ -4,7 +4,7 @@
 
 `esp_lcd` allows user to add their own panel drivers in the project scope (i.e. panel driver can live outside of esp-idf), so that the upper layer code like LVGL porting code can be reused without any modifications, as long as user-implemented panel driver follows the interface defined in the `esp_lcd` component.
 
-This example shows how to add the GC9A01 driver in the project folder but still use the API provided by `esp_lcd` component. As GC9A01 is famous in the form of a circular screen, this example will draw a fancy dash board with the LVGL library. For more information about porting the LVGL library, you can also refer to another [lvgl porting example](../lvgl/README.md).
+This example shows how to add the GC9A01 driver in the project folder but still use the API provided by `esp_lcd` component. As GC9A01 is famous in the form of a circular screen, this example will draw a fancy dash board with the LVGL library. For more information about porting the LVGL library, you can also refer to another [lvgl porting example](../i80_controller/README.md).
 
 ## How to use the example
 

+ 1 - 1
examples/peripherals/lcd/lvgl/CMakeLists.txt → examples/peripherals/lcd/i80_controller/CMakeLists.txt

@@ -1,7 +1,7 @@
 cmake_minimum_required(VERSION 3.5)
 
 include($ENV{IDF_PATH}/tools/cmake/project.cmake)
-project(lcd_lvgl)
+project(i80_controller)
 
 # As the upstream LVGL library has build warnings in esp-idf build system, this is only for temporarily workaround
 # Will remove this workaround when upstream LVGL fixes the warnings in the next release

+ 14 - 4
examples/peripherals/lcd/lvgl/README.md → examples/peripherals/lcd/i80_controller/README.md

@@ -1,12 +1,12 @@
 | Supported Targets | ESP32 | ESP32-S2 | ESP32-S3 |
 | ----------------- | ----- | -------- | -------- |
-# LVGL porting example
+# LVGL porting example (based on i80 interfaced LCD controller)
 
 LVGL is an open-source graphics library for creating modern GUIs. It has plenty of built-in graphical elements with low memory footprint, which is friendly for embedded GUI applications.
 
 This example can be taken as a skeleton of porting the LVGL library onto the `esp_lcd` driver layer. **Note** that, this example only focuses on the display interface, regardless of the input device driver.
 
-The whole porting code is located in [this main file](main/lvgl_example_main.c), and the UI demo code is located in [another single file](main/lvgl_demo_ui.c).
+The whole porting code is located in [i80_controller_example_main.c](main/i80_controller_example_main.c), and the UI demo code is located in [lvgl_demo_ui.c](main/lvgl_demo_ui.c).
 
 The UI will display two images (one Espressif logo and another Espressif text), which have been converted into C arrays by the [online converting tool](https://lvgl.io/tools/imageconverter), and will be compiled directly into application binary.
 
@@ -49,11 +49,17 @@ The connection between ESP Board and the LCD is as follows:
 └─────────────┘              └────────────────┘
 ```
 
-The GPIO number used by this example can be changed in [lvgl_example_main.c](main/lvgl_example_main.c).
-Especially, please pay attention to the level used to turn on the LCD backlight, some LCD module needs a low level to turn it on, while others take a high level. You can change the backlight level macro `EXAMPLE_LCD_BK_LIGHT_ON_LEVEL` in [lvgl_example_main.c](main/lvgl_example_main.c).
+The GPIO number used by this example can be changed in [i80_controller_example_main.c](main/i80_controller_example_main.c).
+Especially, please pay attention to the binary signal level used to turn the LCD backlight on, some LCD modules need a low level to turn it on, while others require a high level. You can change the backlight level macro `EXAMPLE_LCD_BK_LIGHT_ON_LEVEL` in [i80_controller_example_main.c](main/i80_controller_example_main.c).
 
 ### Build and Flash
 
+Run `idf.py set-target <target-name>` to select one supported target that can run this example. This step will also apply the default Kconfig configurations into the `sdkconfig` file.
+
+Run `idf.py menuconfig` to open a terminal UI where you can tune specific configuration for this example in the `Example Configuration` menu.
+
+* `Allocate color data from PSRAM`: Select this option if you want to allocate the LVGL draw buffers from PSRAM.
+
 Run `idf.py -p PORT build flash monitor` to build, flash and monitor the project. A fancy animation will show up on the LCD as expected.
 
 The first time you run `idf.py` for the example will cost extra time as the build system needs to address the component dependencies and downloads the missing components from registry into `managed_components` folder.
@@ -80,4 +86,8 @@ I (558) example: Display LVGL animation
 
 ## Troubleshooting
 
+* Can't get a stable UI when `EXAMPLE_LCD_I80_COLOR_IN_PSRAM` is enabled.
+
+   This is because of the limited PSRAM bandwidth, compared to the internal SRAM. You can either decrease the PCLK clock `EXAMPLE_LCD_PIXEL_CLOCK_HZ` in [i80_controller_example_main.c](main/i80_controller_example_main.c) or increase the PSRAM working frequency `SPIRAM_SPEED` from the KConfig (e.g. **ESP32S3-Specific** -> **Set RAM clock speed**) or decrease the FPS in LVGL configuration. For illustration, this example has set the refresh period to 100ms in the default sdkconfig file.
+
 For any technical queries, please open an [issue] (https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon.

+ 4 - 0
examples/peripherals/lcd/i80_controller/main/CMakeLists.txt

@@ -0,0 +1,4 @@
+file(GLOB_RECURSE IMAGE_SOURCES images/*.c)
+
+idf_component_register(SRCS "i80_controller_example_main.c" "lvgl_demo_ui.c" ${IMAGE_SOURCES}
+                       INCLUDE_DIRS ".")

+ 11 - 0
examples/peripherals/lcd/i80_controller/main/Kconfig.projbuild

@@ -0,0 +1,11 @@
+menu "Example Configuration"
+
+    config EXAMPLE_LCD_I80_COLOR_IN_PSRAM
+        bool "Allocate color data from PSRAM"
+        depends on IDF_TARGET_ESP32S3
+        default y
+        help
+            Enable this option if you wish to allocate the color buffer used by LVGL from PSRAM.
+            Unmatched PSRAM band width with LCD requirement can lead to blurred image display.
+
+endmenu

+ 40 - 18
examples/peripherals/lcd/lvgl/main/lvgl_example_main.c → examples/peripherals/lcd/i80_controller/main/i80_controller_example_main.c

@@ -1,5 +1,5 @@
 /*
- * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
+ * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
  *
  * SPDX-License-Identifier: CC0-1.0
  */
@@ -21,22 +21,28 @@ static const char *TAG = "example";
 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 //////////////////// Please update the following configuration according to your LCD spec //////////////////////////////
 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#if CONFIG_EXAMPLE_LCD_I80_COLOR_IN_PSRAM
+// PCLK frequency can't go too high as the limitation of PSRAM bandwidth
+#define EXAMPLE_LCD_PIXEL_CLOCK_HZ     (2 * 1000 * 1000)
+#else
 #define EXAMPLE_LCD_PIXEL_CLOCK_HZ     (10 * 1000 * 1000)
+#endif // CONFIG_EXAMPLE_LCD_I80_COLOR_IN_PSRAM
+
 #define EXAMPLE_LCD_BK_LIGHT_ON_LEVEL  1
 #define EXAMPLE_LCD_BK_LIGHT_OFF_LEVEL !EXAMPLE_LCD_BK_LIGHT_ON_LEVEL
-#define EXAMPLE_PIN_NUM_DATA0          19
-#define EXAMPLE_PIN_NUM_DATA1          21
-#define EXAMPLE_PIN_NUM_DATA2          0
-#define EXAMPLE_PIN_NUM_DATA3          22
-#define EXAMPLE_PIN_NUM_DATA4          23
-#define EXAMPLE_PIN_NUM_DATA5          33
-#define EXAMPLE_PIN_NUM_DATA6          32
-#define EXAMPLE_PIN_NUM_DATA7          27
-#define EXAMPLE_PIN_NUM_PCLK           18
-#define EXAMPLE_PIN_NUM_CS             4
-#define EXAMPLE_PIN_NUM_DC             5
-#define EXAMPLE_PIN_NUM_RST            -1
-#define EXAMPLE_PIN_NUM_BK_LIGHT       2
+#define EXAMPLE_PIN_NUM_DATA0          6
+#define EXAMPLE_PIN_NUM_DATA1          7
+#define EXAMPLE_PIN_NUM_DATA2          8
+#define EXAMPLE_PIN_NUM_DATA3          9
+#define EXAMPLE_PIN_NUM_DATA4          10
+#define EXAMPLE_PIN_NUM_DATA5          11
+#define EXAMPLE_PIN_NUM_DATA6          12
+#define EXAMPLE_PIN_NUM_DATA7          13
+#define EXAMPLE_PIN_NUM_PCLK           5
+#define EXAMPLE_PIN_NUM_CS             3
+#define EXAMPLE_PIN_NUM_DC             4
+#define EXAMPLE_PIN_NUM_RST            2
+#define EXAMPLE_PIN_NUM_BK_LIGHT       1
 
 // The pixel number in horizontal and vertical
 #define EXAMPLE_LCD_H_RES              240
@@ -47,6 +53,9 @@ static const char *TAG = "example";
 
 #define EXAMPLE_LVGL_TICK_PERIOD_MS    2
 
+// Supported alignment: 16, 32, 64. A higher alignment can enables higher burst transfer size, thus a higher i80 bus throughput.
+#define EXAMPLE_PSRAM_DATA_ALIGNMENT   64
+
 extern void example_lvgl_demo_ui(lv_obj_t *scr);
 
 static bool example_notify_lvgl_flush_ready(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *edata, void *user_ctx)
@@ -102,7 +111,9 @@ void app_main(void)
             EXAMPLE_PIN_NUM_DATA7,
         },
         .bus_width = 8,
-        .max_transfer_bytes = EXAMPLE_LCD_H_RES * 40 * sizeof(uint16_t)
+        .max_transfer_bytes = EXAMPLE_LCD_H_RES * 100 * sizeof(uint16_t),
+        .psram_trans_align = EXAMPLE_PSRAM_DATA_ALIGNMENT,
+        .sram_trans_align = 4,
     };
     ESP_ERROR_CHECK(esp_lcd_new_i80_bus(&bus_config, &i80_bus));
     esp_lcd_panel_io_handle_t io_handle = NULL;
@@ -145,12 +156,23 @@ void app_main(void)
     lv_init();
     // alloc draw buffers used by LVGL
     // it's recommended to choose the size of the draw buffer(s) to be at least 1/10 screen sized
-    lv_color_t *buf1 = heap_caps_malloc(EXAMPLE_LCD_H_RES * 20 * sizeof(lv_color_t), MALLOC_CAP_DMA);
+    lv_color_t *buf1 = NULL;
+    lv_color_t *buf2 = NULL;
+#if CONFIG_EXAMPLE_LCD_I80_COLOR_IN_PSRAM
+    buf1 = heap_caps_aligned_alloc(EXAMPLE_PSRAM_DATA_ALIGNMENT, EXAMPLE_LCD_H_RES * 100 * sizeof(lv_color_t), MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
+#else
+    buf1 = heap_caps_malloc(EXAMPLE_LCD_H_RES * 100 * sizeof(lv_color_t), MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
+#endif
     assert(buf1);
-    lv_color_t *buf2 = heap_caps_malloc(EXAMPLE_LCD_H_RES * 20 * sizeof(lv_color_t), MALLOC_CAP_DMA);
+#if CONFIG_EXAMPLE_LCD_I80_COLOR_IN_PSRAM
+    buf2 = heap_caps_aligned_alloc(EXAMPLE_PSRAM_DATA_ALIGNMENT, EXAMPLE_LCD_H_RES * 100 * sizeof(lv_color_t), MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
+#else
+    buf2 = heap_caps_malloc(EXAMPLE_LCD_H_RES * 100 * sizeof(lv_color_t), MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
+#endif
     assert(buf2);
+    ESP_LOGI(TAG, "buf1@%p, buf2@%p", buf1, buf2);
     // initialize LVGL draw buffers
-    lv_disp_draw_buf_init(&disp_buf, buf1, buf2, EXAMPLE_LCD_H_RES * 20);
+    lv_disp_draw_buf_init(&disp_buf, buf1, buf2, EXAMPLE_LCD_H_RES * 100);
 
     ESP_LOGI(TAG, "Register display driver to LVGL");
     lv_disp_drv_init(&disp_drv);

+ 1 - 1
examples/peripherals/lcd/lvgl/main/idf_component.yml → examples/peripherals/lcd/i80_controller/main/idf_component.yml

@@ -1,3 +1,3 @@
 dependencies:
   idf: ">=4.4"
-  lvgl/lvgl: "==8.0.2"
+  lvgl/lvgl: "~8.0.2"

+ 8 - 0
examples/peripherals/lcd/lvgl/main/images/esp_logo.c → examples/peripherals/lcd/i80_controller/main/images/esp_logo.c

@@ -1,3 +1,11 @@
+/*
+ * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Unlicense OR CC0-1.0
+ */
+
+// NOTE: The logo in this file is registered trademark by Espressif Systems (Shanghai) CO LTD.
+
 #include "lvgl.h"
 
 

+ 0 - 0
examples/peripherals/lcd/lvgl/main/images/esp_logo.png → examples/peripherals/lcd/i80_controller/main/images/esp_logo.png


+ 5 - 0
examples/peripherals/lcd/lvgl/main/images/esp_text.c → examples/peripherals/lcd/i80_controller/main/images/esp_text.c

@@ -1,3 +1,8 @@
+/*
+ * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Unlicense OR CC0-1.0
+ */
 #include "lvgl.h"
 
 #ifndef LV_ATTRIBUTE_MEM_ALIGN

+ 0 - 0
examples/peripherals/lcd/lvgl/main/images/esp_text.png → examples/peripherals/lcd/i80_controller/main/images/esp_text.png


+ 1 - 1
examples/peripherals/lcd/lvgl/main/lvgl_demo_ui.c → examples/peripherals/lcd/i80_controller/main/lvgl_demo_ui.c

@@ -1,5 +1,5 @@
 /*
- * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
+ * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
  *
  * SPDX-License-Identifier: CC0-1.0
  */

+ 2 - 0
examples/peripherals/lcd/lvgl/sdkconfig.defaults → examples/peripherals/lcd/i80_controller/sdkconfig.defaults

@@ -1,3 +1,5 @@
+CONFIG_LV_MEM_CUSTOM=y
+CONFIG_LV_MEMCPY_MEMSET_STD=y
 CONFIG_LV_USE_PERF_MONITOR=y
 CONFIG_LV_USE_USER_DATA=y
 CONFIG_LV_COLOR_16_SWAP=y

+ 4 - 0
examples/peripherals/lcd/i80_controller/sdkconfig.defaults.esp32s3

@@ -0,0 +1,4 @@
+CONFIG_ESP32S3_SPIRAM_SUPPORT=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

+ 0 - 4
examples/peripherals/lcd/lvgl/main/CMakeLists.txt

@@ -1,4 +0,0 @@
-file(GLOB_RECURSE IMAGE_SOURCES images/*.c)
-
-idf_component_register(SRCS "lvgl_example_main.c" "lvgl_demo_ui.c" ${IMAGE_SOURCES}
-                       INCLUDE_DIRS ".")