From 070dc53e0b591bbf960135297a7f635a708e1302 Mon Sep 17 00:00:00 2001 From: morris Date: Tue, 28 Dec 2021 15:30:22 +0800 Subject: [PATCH 1/2] lcd: i80 bus can transfer PSRAM buffer Closes https://github.com/espressif/esp-idf/issues/8085 --- components/esp_lcd/include/esp_lcd_panel_io.h | 4 +++- components/esp_lcd/src/esp_lcd_panel_io_i80.c | 24 +++++++++++++++++-- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/components/esp_lcd/include/esp_lcd_panel_io.h b/components/esp_lcd/include/esp_lcd_panel_io.h index 330f4d9a16..74b3335987 100644 --- a/components/esp_lcd/include/esp_lcd_panel_io.h +++ b/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; /** diff --git a/components/esp_lcd/src/esp_lcd_panel_io_i80.c b/components/esp_lcd/src/esp_lcd_panel_io_i80.c index bc8c3b0fc2..7e7e1d3687 100644 --- a/components/esp_lcd/src/esp_lcd_panel_io_i80.c +++ b/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) { From a611b3925438b39376d3e0f6b8cf7fa2790f027e Mon Sep 17 00:00:00 2001 From: morris Date: Mon, 10 Jan 2022 19:00:40 +0800 Subject: [PATCH 2/2] lcd: update i80 lcd example to work with PSRAM --- components/esp_lcd/test/test_i80_lcd_panel.c | 151 ------------------ docs/en/api-reference/peripherals/lcd.rst | 2 +- examples/peripherals/lcd/gc9a01/README.md | 2 +- .../{lvgl => i80_controller}/CMakeLists.txt | 2 +- .../lcd/{lvgl => i80_controller}/README.md | 18 ++- .../lcd/i80_controller/main/CMakeLists.txt | 4 + .../lcd/i80_controller/main/Kconfig.projbuild | 11 ++ .../main/i80_controller_example_main.c} | 58 ++++--- .../main/idf_component.yml | 2 +- .../main/images/esp_logo.c | 8 + .../main/images/esp_logo.png | Bin .../main/images/esp_text.c | 5 + .../main/images/esp_text.png | Bin .../main/lvgl_demo_ui.c | 2 +- .../sdkconfig.defaults | 2 + .../i80_controller/sdkconfig.defaults.esp32s3 | 4 + .../peripherals/lcd/lvgl/main/CMakeLists.txt | 4 - 17 files changed, 93 insertions(+), 182 deletions(-) rename examples/peripherals/lcd/{lvgl => i80_controller}/CMakeLists.txt (94%) rename examples/peripherals/lcd/{lvgl => i80_controller}/README.md (72%) create mode 100644 examples/peripherals/lcd/i80_controller/main/CMakeLists.txt create mode 100644 examples/peripherals/lcd/i80_controller/main/Kconfig.projbuild rename examples/peripherals/lcd/{lvgl/main/lvgl_example_main.c => i80_controller/main/i80_controller_example_main.c} (76%) rename examples/peripherals/lcd/{lvgl => i80_controller}/main/idf_component.yml (55%) rename examples/peripherals/lcd/{lvgl => i80_controller}/main/images/esp_logo.c (99%) rename examples/peripherals/lcd/{lvgl => i80_controller}/main/images/esp_logo.png (100%) rename examples/peripherals/lcd/{lvgl => i80_controller}/main/images/esp_text.c (99%) rename examples/peripherals/lcd/{lvgl => i80_controller}/main/images/esp_text.png (100%) rename examples/peripherals/lcd/{lvgl => i80_controller}/main/lvgl_demo_ui.c (97%) rename examples/peripherals/lcd/{lvgl => i80_controller}/sdkconfig.defaults (60%) create mode 100644 examples/peripherals/lcd/i80_controller/sdkconfig.defaults.esp32s3 delete mode 100644 examples/peripherals/lcd/lvgl/main/CMakeLists.txt diff --git a/components/esp_lcd/test/test_i80_lcd_panel.c b/components/esp_lcd/test/test_i80_lcd_panel.c index 85ba5a544e..a70a1ea992 100644 --- a/components/esp_lcd/test/test_i80_lcd_panel.c +++ b/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 diff --git a/docs/en/api-reference/peripherals/lcd.rst b/docs/en/api-reference/peripherals/lcd.rst index 7fdf780759..6b4cf66a38 100644 --- a/docs/en/api-reference/peripherals/lcd.rst +++ b/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 diff --git a/examples/peripherals/lcd/gc9a01/README.md b/examples/peripherals/lcd/gc9a01/README.md index 79f7bc787a..91a25e8261 100644 --- a/examples/peripherals/lcd/gc9a01/README.md +++ b/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 diff --git a/examples/peripherals/lcd/lvgl/CMakeLists.txt b/examples/peripherals/lcd/i80_controller/CMakeLists.txt similarity index 94% rename from examples/peripherals/lcd/lvgl/CMakeLists.txt rename to examples/peripherals/lcd/i80_controller/CMakeLists.txt index eb8d60b2df..00a14efea6 100644 --- a/examples/peripherals/lcd/lvgl/CMakeLists.txt +++ b/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 diff --git a/examples/peripherals/lcd/lvgl/README.md b/examples/peripherals/lcd/i80_controller/README.md similarity index 72% rename from examples/peripherals/lcd/lvgl/README.md rename to examples/peripherals/lcd/i80_controller/README.md index e01686bcdb..fbe77e0d1f 100644 --- a/examples/peripherals/lcd/lvgl/README.md +++ b/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 ` 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. \ No newline at end of file diff --git a/examples/peripherals/lcd/i80_controller/main/CMakeLists.txt b/examples/peripherals/lcd/i80_controller/main/CMakeLists.txt new file mode 100644 index 0000000000..0a9682d388 --- /dev/null +++ b/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 ".") diff --git a/examples/peripherals/lcd/i80_controller/main/Kconfig.projbuild b/examples/peripherals/lcd/i80_controller/main/Kconfig.projbuild new file mode 100644 index 0000000000..208bd16277 --- /dev/null +++ b/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 diff --git a/examples/peripherals/lcd/lvgl/main/lvgl_example_main.c b/examples/peripherals/lcd/i80_controller/main/i80_controller_example_main.c similarity index 76% rename from examples/peripherals/lcd/lvgl/main/lvgl_example_main.c rename to examples/peripherals/lcd/i80_controller/main/i80_controller_example_main.c index 0f79aed3b4..98f665ebb1 100644 --- a/examples/peripherals/lcd/lvgl/main/lvgl_example_main.c +++ b/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); diff --git a/examples/peripherals/lcd/lvgl/main/idf_component.yml b/examples/peripherals/lcd/i80_controller/main/idf_component.yml similarity index 55% rename from examples/peripherals/lcd/lvgl/main/idf_component.yml rename to examples/peripherals/lcd/i80_controller/main/idf_component.yml index c5592991c9..eedaf75ade 100644 --- a/examples/peripherals/lcd/lvgl/main/idf_component.yml +++ b/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" diff --git a/examples/peripherals/lcd/lvgl/main/images/esp_logo.c b/examples/peripherals/lcd/i80_controller/main/images/esp_logo.c similarity index 99% rename from examples/peripherals/lcd/lvgl/main/images/esp_logo.c rename to examples/peripherals/lcd/i80_controller/main/images/esp_logo.c index 96f0ad48cf..5248d430e8 100644 --- a/examples/peripherals/lcd/lvgl/main/images/esp_logo.c +++ b/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" diff --git a/examples/peripherals/lcd/lvgl/main/images/esp_logo.png b/examples/peripherals/lcd/i80_controller/main/images/esp_logo.png similarity index 100% rename from examples/peripherals/lcd/lvgl/main/images/esp_logo.png rename to examples/peripherals/lcd/i80_controller/main/images/esp_logo.png diff --git a/examples/peripherals/lcd/lvgl/main/images/esp_text.c b/examples/peripherals/lcd/i80_controller/main/images/esp_text.c similarity index 99% rename from examples/peripherals/lcd/lvgl/main/images/esp_text.c rename to examples/peripherals/lcd/i80_controller/main/images/esp_text.c index 5daf2b64f9..85c1b14464 100644 --- a/examples/peripherals/lcd/lvgl/main/images/esp_text.c +++ b/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 diff --git a/examples/peripherals/lcd/lvgl/main/images/esp_text.png b/examples/peripherals/lcd/i80_controller/main/images/esp_text.png similarity index 100% rename from examples/peripherals/lcd/lvgl/main/images/esp_text.png rename to examples/peripherals/lcd/i80_controller/main/images/esp_text.png diff --git a/examples/peripherals/lcd/lvgl/main/lvgl_demo_ui.c b/examples/peripherals/lcd/i80_controller/main/lvgl_demo_ui.c similarity index 97% rename from examples/peripherals/lcd/lvgl/main/lvgl_demo_ui.c rename to examples/peripherals/lcd/i80_controller/main/lvgl_demo_ui.c index 2fa619cd67..cd4731e6a4 100644 --- a/examples/peripherals/lcd/lvgl/main/lvgl_demo_ui.c +++ b/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 */ diff --git a/examples/peripherals/lcd/lvgl/sdkconfig.defaults b/examples/peripherals/lcd/i80_controller/sdkconfig.defaults similarity index 60% rename from examples/peripherals/lcd/lvgl/sdkconfig.defaults rename to examples/peripherals/lcd/i80_controller/sdkconfig.defaults index 3e91de13f0..c111342bb6 100644 --- a/examples/peripherals/lcd/lvgl/sdkconfig.defaults +++ b/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 diff --git a/examples/peripherals/lcd/i80_controller/sdkconfig.defaults.esp32s3 b/examples/peripherals/lcd/i80_controller/sdkconfig.defaults.esp32s3 new file mode 100644 index 0000000000..a39b658841 --- /dev/null +++ b/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 diff --git a/examples/peripherals/lcd/lvgl/main/CMakeLists.txt b/examples/peripherals/lcd/lvgl/main/CMakeLists.txt deleted file mode 100644 index 39845d7ae6..0000000000 --- a/examples/peripherals/lcd/lvgl/main/CMakeLists.txt +++ /dev/null @@ -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 ".")