From 63ccbd095e42f8439c4caec24b4eb4683296a7c1 Mon Sep 17 00:00:00 2001 From: morris Date: Mon, 23 Sep 2024 15:56:18 +0800 Subject: [PATCH] feat(lcd): add Kconfig to assign default GPIO for RGB LCD example --- .../include/example_dsi_init_config.h | 4 +- examples/peripherals/lcd/mipi_dsi/README.md | 4 +- .../lcd/mipi_dsi/main/Kconfig.projbuild | 8 +- .../lcd/mipi_dsi/main/idf_component.yml | 2 +- .../mipi_dsi/main/mipi_dsi_lcd_example_main.c | 35 ++-- examples/peripherals/lcd/rgb_panel/README.md | 43 ++--- .../lcd/rgb_panel/main/Kconfig.projbuild | 97 ++++++++++ .../lcd/rgb_panel/main/idf_component.yml | 2 +- .../lcd/rgb_panel/main/lvgl_demo_ui.c | 174 +++++++++++++----- .../lcd/rgb_panel/main/rgb_lcd_example_main.c | 74 +++++--- .../lcd/rgb_panel/pytest_rgb_panel_lvgl.py | 5 +- .../lcd/rgb_panel/sdkconfig.defaults.esp32s3 | 32 ++++ 12 files changed, 356 insertions(+), 124 deletions(-) diff --git a/examples/peripherals/camera/camera_dsi/components/dsi_init/include/example_dsi_init_config.h b/examples/peripherals/camera/camera_dsi/components/dsi_init/include/example_dsi_init_config.h index b27fcb2239..2873b5a31e 100644 --- a/examples/peripherals/camera/camera_dsi/components/dsi_init/include/example_dsi_init_config.h +++ b/examples/peripherals/camera/camera_dsi/components/dsi_init/include/example_dsi_init_config.h @@ -13,7 +13,7 @@ extern "C" { #endif #if CONFIG_EXAMPLE_LCD_PATTERN_ILI9881C -// FPS = 80000000/(40+140+40+800)/(4+16+16+1280) = 60Hz +// Refresh Rate = 80000000/(40+140+40+800)/(4+16+16+1280) = 60Hz #define EXAMPLE_MIPI_DSI_DPI_CLK_MHZ 80 #define EXAMPLE_MIPI_DSI_IMAGE_HSYNC 40 #define EXAMPLE_MIPI_DSI_IMAGE_HBP 140 @@ -22,7 +22,7 @@ extern "C" { #define EXAMPLE_MIPI_DSI_IMAGE_VBP 16 #define EXAMPLE_MIPI_DSI_IMAGE_VFP 16 #elif CONFIG_EXAMPLE_LCD_PATTERN_EK79007 -// FPS = 48000000/(10+120+120+1024)/(1+20+10+600) = 60Hz +// Refresh Rate = 48000000/(10+120+120+1024)/(1+20+10+600) = 60Hz #define EXAMPLE_MIPI_DSI_DPI_CLK_MHZ 48 #define EXAMPLE_MIPI_DSI_IMAGE_HSYNC 10 #define EXAMPLE_MIPI_DSI_IMAGE_HBP 120 diff --git a/examples/peripherals/lcd/mipi_dsi/README.md b/examples/peripherals/lcd/mipi_dsi/README.md index ed655f8f99..8d9ff8a9eb 100644 --- a/examples/peripherals/lcd/mipi_dsi/README.md +++ b/examples/peripherals/lcd/mipi_dsi/README.md @@ -51,8 +51,8 @@ Run `idf.py menuconfig` and go to `Example Configuration`: * Choose the LCD model in `Select MIPI LCD model` according to your board. * Choose whether to `Use DMA2D to copy draw buffer to frame buffer` asynchronously. If you choose `No`, the draw buffer will be copied to the frame buffer synchronously by CPU. -* Choose if you want to `Monitor FPS by GPIO`. If you choose `Yes`, then you can attach an oscilloscope or logic analyzer to the GPIO pin to monitor the FPS of the display. - Please note, the actual FPS should be **double** the square wave frequency. +* Choose if you want to `Monitor Refresh Rate by GPIO`. If you choose `Yes`, then you can attach an oscilloscope or logic analyzer to the GPIO pin to monitor the Refresh Rate of the display. + Please note, the actual Refresh Rate should be **double** the square wave frequency. ### Build and Flash diff --git a/examples/peripherals/lcd/mipi_dsi/main/Kconfig.projbuild b/examples/peripherals/lcd/mipi_dsi/main/Kconfig.projbuild index bde4d4b00f..dd92087a34 100644 --- a/examples/peripherals/lcd/mipi_dsi/main/Kconfig.projbuild +++ b/examples/peripherals/lcd/mipi_dsi/main/Kconfig.projbuild @@ -6,12 +6,12 @@ menu "Example Configuration" Enable this option, DMA2D will be used to copy the LVGL draw buffer to the target frame buffer. This can save some CPU time and improve the performance. - config EXAMPLE_MONITOR_FPS_BY_GPIO - bool "Monitor FPS by GPIO" + config EXAMPLE_MONITOR_REFRESH_BY_GPIO + bool "Monitor Refresh Rate by GPIO" default y help - Enable this option, you can visualize the FPS by attaching a logic analyzer to a specific GPIO. - The GPIO will output a square wave with the frequency of FPS/2. + Enable this option, you can visualize the refresh rate by attaching a logic analyzer to a specific GPIO. + The GPIO will output a square wave with the frequency equals to half of the refresh rate. choice prompt "Select MIPI LCD model" diff --git a/examples/peripherals/lcd/mipi_dsi/main/idf_component.yml b/examples/peripherals/lcd/mipi_dsi/main/idf_component.yml index a0e6249c4d..856f24237a 100644 --- a/examples/peripherals/lcd/mipi_dsi/main/idf_component.yml +++ b/examples/peripherals/lcd/mipi_dsi/main/idf_component.yml @@ -1,4 +1,4 @@ dependencies: - lvgl/lvgl: "^9.0.0" + lvgl/lvgl: "~9.2.0" esp_lcd_ili9881c: "^1.0.0" esp_lcd_ek79007: "^1.0.0" diff --git a/examples/peripherals/lcd/mipi_dsi/main/mipi_dsi_lcd_example_main.c b/examples/peripherals/lcd/mipi_dsi/main/mipi_dsi_lcd_example_main.c index f66f8fea92..8ae435e7e4 100644 --- a/examples/peripherals/lcd/mipi_dsi/main/mipi_dsi_lcd_example_main.c +++ b/examples/peripherals/lcd/mipi_dsi/main/mipi_dsi_lcd_example_main.c @@ -29,7 +29,7 @@ static const char *TAG = "example"; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #if CONFIG_EXAMPLE_LCD_USE_ILI9881C -// FPS = 80000000/(40+140+40+800)/(4+16+16+1280) = 60Hz +// Refresh Rate = 80000000/(40+140+40+800)/(4+16+16+1280) = 60Hz #define EXAMPLE_MIPI_DSI_DPI_CLK_MHZ 80 #define EXAMPLE_MIPI_DSI_LCD_H_RES 800 #define EXAMPLE_MIPI_DSI_LCD_V_RES 1280 @@ -40,7 +40,7 @@ static const char *TAG = "example"; #define EXAMPLE_MIPI_DSI_LCD_VBP 16 #define EXAMPLE_MIPI_DSI_LCD_VFP 16 #elif CONFIG_EXAMPLE_LCD_USE_EK79007 -// FPS = 48000000/(10+120+120+1024)/(1+20+10+600) = 60Hz +// Refresh Rate = 48000000/(10+120+120+1024)/(1+20+10+600) = 60Hz #define EXAMPLE_MIPI_DSI_DPI_CLK_MHZ 48 #define EXAMPLE_MIPI_DSI_LCD_H_RES 1024 #define EXAMPLE_MIPI_DSI_LCD_V_RES 600 @@ -67,8 +67,8 @@ static const char *TAG = "example"; #define EXAMPLE_PIN_NUM_BK_LIGHT -1 #define EXAMPLE_PIN_NUM_LCD_RST -1 -#if CONFIG_EXAMPLE_MONITOR_FPS_BY_GPIO -#define EXAMPLE_PIN_NUM_FPS_MONITOR 20 // Monitor the FPS by toggling the GPIO +#if CONFIG_EXAMPLE_MONITOR_REFRESH_BY_GPIO +#define EXAMPLE_PIN_NUM_REFRESH_MONITOR 20 // Monitor the Refresh Rate by toggling the GPIO #endif //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -110,6 +110,11 @@ static void example_lvgl_port_task(void *arg) _lock_acquire(&lvgl_api_lock); time_till_next_ms = lv_timer_handler(); _lock_release(&lvgl_api_lock); + + // in case of task watch dog timeout, set the minimal delay to 10ms + if (time_till_next_ms < 10) { + time_till_next_ms = 10; + } usleep(1000 * time_till_next_ms); } } @@ -121,12 +126,12 @@ static bool example_notify_lvgl_flush_ready(esp_lcd_panel_handle_t panel, esp_lc return false; } -#if CONFIG_EXAMPLE_MONITOR_FPS_BY_GPIO -static bool example_monitor_fps(esp_lcd_panel_handle_t panel, esp_lcd_dpi_panel_event_data_t *edata, void *user_ctx) +#if CONFIG_EXAMPLE_MONITOR_REFRESH_BY_GPIO +static bool example_monitor_refresh_rate(esp_lcd_panel_handle_t panel, esp_lcd_dpi_panel_event_data_t *edata, void *user_ctx) { static int io_level = 0; - // please note, the real FPS should be 2*frequency of this GPIO toggling - gpio_set_level(EXAMPLE_PIN_NUM_FPS_MONITOR, io_level); + // please note, the real refresh rate should be 2*frequency of this GPIO toggling + gpio_set_level(EXAMPLE_PIN_NUM_REFRESH_MONITOR, io_level); io_level = !io_level; return false; } @@ -164,12 +169,12 @@ static void example_bsp_set_lcd_backlight(uint32_t level) #endif } -#if CONFIG_EXAMPLE_MONITOR_FPS_BY_GPIO -static void example_bsp_init_fps_monitor_io(void) +#if CONFIG_EXAMPLE_MONITOR_REFRESH_BY_GPIO +static void example_bsp_init_refresh_monitor_io(void) { gpio_config_t monitor_io_conf = { .mode = GPIO_MODE_OUTPUT, - .pin_bit_mask = 1ULL << EXAMPLE_PIN_NUM_FPS_MONITOR, + .pin_bit_mask = 1ULL << EXAMPLE_PIN_NUM_REFRESH_MONITOR, }; ESP_ERROR_CHECK(gpio_config(&monitor_io_conf)); } @@ -177,8 +182,8 @@ static void example_bsp_init_fps_monitor_io(void) void app_main(void) { -#if CONFIG_EXAMPLE_MONITOR_FPS_BY_GPIO - example_bsp_init_fps_monitor_io(); +#if CONFIG_EXAMPLE_MONITOR_REFRESH_BY_GPIO + example_bsp_init_refresh_monitor_io(); #endif example_bsp_enable_dsi_phy_power(); @@ -291,8 +296,8 @@ void app_main(void) ESP_LOGI(TAG, "Register DPI panel event callback for LVGL flush ready notification"); esp_lcd_dpi_panel_event_callbacks_t cbs = { .on_color_trans_done = example_notify_lvgl_flush_ready, -#if CONFIG_EXAMPLE_MONITOR_FPS_BY_GPIO - .on_refresh_done = example_monitor_fps, +#if CONFIG_EXAMPLE_MONITOR_REFRESH_BY_GPIO + .on_refresh_done = example_monitor_refresh_rate, #endif }; ESP_ERROR_CHECK(esp_lcd_dpi_panel_register_event_callbacks(mipi_dpi_panel, &cbs, display)); diff --git a/examples/peripherals/lcd/rgb_panel/README.md b/examples/peripherals/lcd/rgb_panel/README.md index b219e4207c..97b9915461 100644 --- a/examples/peripherals/lcd/rgb_panel/README.md +++ b/examples/peripherals/lcd/rgb_panel/README.md @@ -27,7 +27,7 @@ This example uses 3 kinds of **buffering mode**: The connection between ESP Board and the LCD is as follows: -``` +```text ESP Board RGB Panel +-----------------------+ +-------------------+ | GND +--------------+GND | @@ -51,12 +51,6 @@ 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/rgb_lcd_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/rgb_lcd_example_main.c). - -If the RGB LCD panel only supports DE mode, you can even bypass the `HSYNC` and `VSYNC` signals, by assigning `EXAMPLE_PIN_NUM_HSYNC` and `EXAMPLE_PIN_NUM_VSYNC` with `-1`. - ### Configure Run `idf.py menuconfig` and go to `Example Configuration`: @@ -64,6 +58,8 @@ Run `idf.py menuconfig` and go to `Example Configuration`: 1. Choose whether to `Use double Frame Buffer` 2. Choose whether to `Avoid tearing effect` (available only when step `1` was chosen to false) 3. Choose whether to `Use bounce buffer` (available only when step `1` was chosen to false) +4. Choose the number of LCD data lines in `RGB LCD Data Lines` +5. Set the GPIOs used by RGB LCD peripheral in `GPIO assignment`, e.g. the synchronization signals (HSYNC, VSYNC, DE) and the data lines ### Build and Flash @@ -79,29 +75,28 @@ See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/l ```bash ... -I (0) cpu_start: Starting scheduler on APP CPU. -I (856) esp_psram: Reserving pool of 32K of internal memory for DMA/internal allocations -I (856) example: Create semaphores -I (866) example: Turn off LCD backlight -I (866) gpio: GPIO[4]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 -I (876) example: Install RGB LCD panel driver -I (906) example: Register event callbacks -I (906) example: Initialize RGB LCD panel -I (906) example: Turn on LCD backlight -I (906) example: Initialize LVGL library -I (916) example: Allocate separate LVGL draw buffers from PSRAM -I (916) example: Register display driver to LVGL -I (926) example: Install LVGL tick timer -I (926) example: Create LVGL task -I (926) example: Starting LVGL task -I (926) example: Display LVGL Scatter Chart +I (872) main_task: Started on CPU0 +I (882) esp_psram: Reserving pool of 32K of internal memory for DMA/internal allocations +I (882) main_task: Calling app_main() +I (892) example: Turn off LCD backlight +I (892) example: Install RGB LCD panel driver +I (922) example: Initialize RGB LCD panel +I (922) example: Turn on LCD backlight +I (922) example: Initialize LVGL library +I (932) example: Allocate LVGL draw buffers +I (932) example: Register event callbacks +I (932) example: Install LVGL tick timer +I (942) example: Create LVGL task +I (942) example: Starting LVGL task +I (992) example: Display LVGL UI +I (1102) main_task: Returned from app_main() ... ``` ## Troubleshooting * Why the LCD doesn't light up? - * Check the backlight's turn-on level, and update it in `EXAMPLE_LCD_BK_LIGHT_ON_LEVEL` + * 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/rgb_lcd_example_main.c). * No memory for frame buffer * The frame buffer of RGB panel is located in ESP side (unlike other controller based LCDs, where the frame buffer is located in external chip). As the frame buffer usually consumes much RAM (depends on the LCD resolution and color depth), we recommend to put the frame buffer into PSRAM (like what we do in this example). However, putting frame buffer in PSRAM will limit the maximum PCLK due to the bandwidth of **SPI0**. * LCD screen drift diff --git a/examples/peripherals/lcd/rgb_panel/main/Kconfig.projbuild b/examples/peripherals/lcd/rgb_panel/main/Kconfig.projbuild index 8c852669e8..34415bb278 100644 --- a/examples/peripherals/lcd/rgb_panel/main/Kconfig.projbuild +++ b/examples/peripherals/lcd/rgb_panel/main/Kconfig.projbuild @@ -18,4 +18,101 @@ menu "Example Configuration" help Enable this option, the example will use a pair of semaphores to avoid the tearing effect. Note, if the Double Frame Buffer is used, then we can also avoid the tearing effect without the lock. + + choice EXAMPLE_LCD_DATA_LINES + prompt "RGB LCD Data Lines" + default EXAMPLE_LCD_DATA_LINES_16 + help + Select the number of data lines of the RGB LCD. + + config EXAMPLE_LCD_DATA_LINES_16 + bool "16 data lines" + endchoice + + config EXAMPLE_LCD_DATA_LINES + int + default 16 if EXAMPLE_LCD_DATA_LINES_16 + + menu "GPIO assignment" + config EXAMPLE_LCD_VSYNC_GPIO + int "VSYNC GPIO" + help + GPIO pin number for VSYNC signal. + config EXAMPLE_LCD_HSYNC_GPIO + int "HSYNC GPIO" + help + GPIO pin number for HSYNC signal. + config EXAMPLE_LCD_DE_GPIO + int "DE GPIO" + help + GPIO pin number for DE signal. + config EXAMPLE_LCD_PCLK_GPIO + int "PCLK GPIO" + help + GPIO pin number for PCLK signal. + config EXAMPLE_LCD_DATA0_GPIO + int "DATA0 GPIO" + help + GPIO pin number for data bus[0]. + config EXAMPLE_LCD_DATA1_GPIO + int "DATA1 GPIO" + help + GPIO pin number for data bus[1]. + config EXAMPLE_LCD_DATA2_GPIO + int "DATA2 GPIO" + help + GPIO pin number for data bus[2]. + config EXAMPLE_LCD_DATA3_GPIO + int "DATA3 GPIO" + help + GPIO pin number for data bus[3]. + config EXAMPLE_LCD_DATA4_GPIO + int "DATA4 GPIO" + help + GPIO pin number for data bus[4]. + config EXAMPLE_LCD_DATA5_GPIO + int "DATA5 GPIO" + help + GPIO pin number for data bus[5]. + config EXAMPLE_LCD_DATA6_GPIO + int "DATA6 GPIO" + help + GPIO pin number for data bus[6]. + config EXAMPLE_LCD_DATA7_GPIO + int "DATA7 GPIO" + help + GPIO pin number for data bus[7]. + config EXAMPLE_LCD_DATA8_GPIO + int "DATA8 GPIO" + help + GPIO pin number for data bus[8]. + config EXAMPLE_LCD_DATA9_GPIO + int "DATA9 GPIO" + help + GPIO pin number for data bus[9]. + config EXAMPLE_LCD_DATA10_GPIO + int "DATA10 GPIO" + help + GPIO pin number for data bus[10]. + config EXAMPLE_LCD_DATA11_GPIO + int "DATA11 GPIO" + help + GPIO pin number for data bus[11]. + config EXAMPLE_LCD_DATA12_GPIO + int "DATA12 GPIO" + help + GPIO pin number for data bus[12]. + config EXAMPLE_LCD_DATA13_GPIO + int "DATA13 GPIO" + help + GPIO pin number for data bus[13]. + config EXAMPLE_LCD_DATA14_GPIO + int "DATA14 GPIO" + help + GPIO pin number for data bus[14]. + config EXAMPLE_LCD_DATA15_GPIO + int "DATA15 GPIO" + help + GPIO pin number for data bus[15]. + endmenu endmenu diff --git a/examples/peripherals/lcd/rgb_panel/main/idf_component.yml b/examples/peripherals/lcd/rgb_panel/main/idf_component.yml index 43f5954cfd..f929e7f74a 100644 --- a/examples/peripherals/lcd/rgb_panel/main/idf_component.yml +++ b/examples/peripherals/lcd/rgb_panel/main/idf_component.yml @@ -1,2 +1,2 @@ dependencies: - lvgl/lvgl: "^9.0.0" + lvgl/lvgl: "~9.2.0" diff --git a/examples/peripherals/lcd/rgb_panel/main/lvgl_demo_ui.c b/examples/peripherals/lcd/rgb_panel/main/lvgl_demo_ui.c index b0ef9bcfa4..34727eec95 100644 --- a/examples/peripherals/lcd/rgb_panel/main/lvgl_demo_ui.c +++ b/examples/peripherals/lcd/rgb_panel/main/lvgl_demo_ui.c @@ -4,65 +4,153 @@ * SPDX-License-Identifier: CC0-1.0 */ -// This demo UI is adapted from LVGL official example: https://docs.lvgl.io/master/widgets/chart.html#scatter-chart - #include "lvgl.h" -static void draw_event_cb(lv_event_t *e) +static lv_style_t style_bullet; +static lv_obj_t *scale1; +static const lv_font_t *font_normal = &lv_font_montserrat_14; + +static lv_obj_t *create_scale_box(lv_obj_t *parent, const char *text1, const char *text2, const char *text3) { - lv_draw_task_t *draw_task = lv_event_get_draw_task(e); - lv_draw_dsc_base_t *base_dsc = lv_draw_task_get_draw_dsc(draw_task); - if (base_dsc->part == LV_PART_INDICATOR) { - lv_obj_t *obj = lv_event_get_target(e); - lv_chart_series_t *ser = lv_chart_get_series_next(obj, NULL); - lv_draw_rect_dsc_t *rect_draw_dsc = lv_draw_task_get_draw_dsc(draw_task); - uint32_t cnt = lv_chart_get_point_count(obj); + lv_obj_t *scale = lv_scale_create(parent); + lv_obj_center(scale); + lv_obj_set_size(scale, 300, 300); + lv_scale_set_mode(scale, LV_SCALE_MODE_ROUND_OUTER); + lv_scale_set_label_show(scale, false); + lv_scale_set_post_draw(scale, true); + lv_obj_set_width(scale, LV_PCT(100)); + lv_obj_set_style_pad_all(scale, 30, 0); - /*Make older value more transparent*/ - rect_draw_dsc->bg_opa = (LV_OPA_COVER * base_dsc->id2) / (cnt - 1); + lv_obj_t *bullet1 = lv_obj_create(parent); + lv_obj_set_size(bullet1, 13, 13); + lv_obj_remove_style(bullet1, NULL, LV_PART_SCROLLBAR); + lv_obj_add_style(bullet1, &style_bullet, 0); + lv_obj_set_style_bg_color(bullet1, lv_palette_main(LV_PALETTE_RED), 0); + lv_obj_t *label1 = lv_label_create(parent); + lv_label_set_text(label1, text1); - /*Make smaller values blue, higher values red*/ - int32_t *x_array = lv_chart_get_x_array(obj, ser); - int32_t *y_array = lv_chart_get_y_array(obj, ser); - /*dsc->id is the tells drawing order, but we need the ID of the point being drawn.*/ - uint32_t start_point = lv_chart_get_x_start_point(obj, ser); - uint32_t p_act = (start_point + base_dsc->id2) % cnt; /*Consider start point to get the index of the array*/ - lv_opa_t x_opa = (x_array[p_act] * LV_OPA_50) / 200; - lv_opa_t y_opa = (y_array[p_act] * LV_OPA_50) / 1000; + lv_obj_t *bullet2 = lv_obj_create(parent); + lv_obj_set_size(bullet2, 13, 13); + lv_obj_remove_style(bullet2, NULL, LV_PART_SCROLLBAR); + lv_obj_add_style(bullet2, &style_bullet, 0); + lv_obj_set_style_bg_color(bullet2, lv_palette_main(LV_PALETTE_BLUE), 0); + lv_obj_t *label2 = lv_label_create(parent); + lv_label_set_text(label2, text2); - rect_draw_dsc->bg_color = lv_color_mix(lv_palette_main(LV_PALETTE_RED), - lv_palette_main(LV_PALETTE_BLUE), - x_opa + y_opa); - } + lv_obj_t *bullet3 = lv_obj_create(parent); + lv_obj_set_size(bullet3, 13, 13); + lv_obj_remove_style(bullet3, NULL, LV_PART_SCROLLBAR); + lv_obj_add_style(bullet3, &style_bullet, 0); + lv_obj_set_style_bg_color(bullet3, lv_palette_main(LV_PALETTE_GREEN), 0); + lv_obj_t *label3 = lv_label_create(parent); + lv_label_set_text(label3, text3); + + static int32_t grid_col_dsc[] = {LV_GRID_CONTENT, LV_GRID_FR(1), LV_GRID_TEMPLATE_LAST}; + static int32_t grid_row_dsc[] = {LV_GRID_CONTENT, LV_GRID_CONTENT, LV_GRID_CONTENT, LV_GRID_CONTENT, LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST}; + lv_obj_set_grid_dsc_array(parent, grid_col_dsc, grid_row_dsc); + lv_obj_set_grid_cell(scale, LV_GRID_ALIGN_START, 0, 2, LV_GRID_ALIGN_START, 1, 1); + lv_obj_set_grid_cell(bullet1, LV_GRID_ALIGN_START, 0, 1, LV_GRID_ALIGN_START, 2, 1); + lv_obj_set_grid_cell(bullet2, LV_GRID_ALIGN_START, 0, 1, LV_GRID_ALIGN_START, 3, 1); + lv_obj_set_grid_cell(bullet3, LV_GRID_ALIGN_START, 0, 1, LV_GRID_ALIGN_START, 4, 1); + lv_obj_set_grid_cell(label1, LV_GRID_ALIGN_STRETCH, 1, 1, LV_GRID_ALIGN_START, 2, 1); + lv_obj_set_grid_cell(label2, LV_GRID_ALIGN_STRETCH, 1, 1, LV_GRID_ALIGN_START, 3, 1); + lv_obj_set_grid_cell(label3, LV_GRID_ALIGN_STRETCH, 1, 1, LV_GRID_ALIGN_START, 4, 1); + return scale; } -static void add_data(lv_timer_t *timer) +static void scale1_indic1_anim_cb(void *var, int32_t v) { - lv_obj_t *chart = lv_timer_get_user_data(timer); - lv_chart_set_next_value2(chart, lv_chart_get_series_next(chart, NULL), lv_rand(0, 200), lv_rand(0, 1000)); + lv_arc_set_value(var, v); + + lv_obj_t *card = lv_obj_get_parent(scale1); + lv_obj_t *label = lv_obj_get_child(card, -5); + lv_label_set_text_fmt(label, "Revenue: %"LV_PRId32" %%", v); +} + +static void scale1_indic2_anim_cb(void *var, int32_t v) +{ + lv_arc_set_value(var, v); + + lv_obj_t *card = lv_obj_get_parent(scale1); + lv_obj_t *label = lv_obj_get_child(card, -3); + lv_label_set_text_fmt(label, "Sales: %"LV_PRId32" %%", v); +} + +static void scale1_indic3_anim_cb(void *var, int32_t v) +{ + lv_arc_set_value(var, v); + + lv_obj_t *card = lv_obj_get_parent(scale1); + lv_obj_t *label = lv_obj_get_child(card, -1); + lv_label_set_text_fmt(label, "Costs: %"LV_PRId32" %%", v); } void example_lvgl_demo_ui(lv_display_t *disp) { - lv_obj_t *scr = lv_display_get_screen_active(disp); - lv_obj_t *chart = lv_chart_create(scr); - lv_obj_set_size(chart, 400, 300); - lv_obj_align(chart, LV_ALIGN_CENTER, 0, 0); - lv_obj_add_event_cb(chart, draw_event_cb, LV_EVENT_DRAW_TASK_ADDED, NULL); - lv_obj_add_flag(chart, LV_OBJ_FLAG_SEND_DRAW_TASK_EVENTS); - lv_obj_set_style_line_width(chart, 0, LV_PART_ITEMS); + // init default theme + lv_theme_default_init(disp, lv_palette_main(LV_PALETTE_BLUE), lv_palette_main(LV_PALETTE_RED), LV_THEME_DEFAULT_DARK, + font_normal); + // bullet style + lv_style_init(&style_bullet); + lv_style_set_border_width(&style_bullet, 0); + lv_style_set_radius(&style_bullet, LV_RADIUS_CIRCLE); - lv_chart_set_type(chart, LV_CHART_TYPE_SCATTER); + lv_obj_t *parent = lv_display_get_screen_active(disp); - lv_chart_set_range(chart, LV_CHART_AXIS_PRIMARY_X, 0, 200); - lv_chart_set_range(chart, LV_CHART_AXIS_PRIMARY_Y, 0, 1000); + // create scale widget + scale1 = create_scale_box(parent, "Revenue", "Sales", "Costs"); - lv_chart_set_point_count(chart, 50); + // create arc indicators + lv_obj_t *arc; + arc = lv_arc_create(scale1); + lv_obj_remove_style(arc, NULL, LV_PART_KNOB); + lv_obj_remove_style(arc, NULL, LV_PART_MAIN); + lv_obj_set_size(arc, lv_pct(100), lv_pct(100)); + lv_obj_set_style_arc_opa(arc, 0, 0); + lv_obj_set_style_arc_width(arc, 15, LV_PART_INDICATOR); + lv_obj_set_style_arc_color(arc, lv_palette_main(LV_PALETTE_BLUE), LV_PART_INDICATOR); + lv_obj_remove_flag(arc, LV_OBJ_FLAG_CLICKABLE); - lv_chart_series_t *ser = lv_chart_add_series(chart, lv_palette_main(LV_PALETTE_RED), LV_CHART_AXIS_PRIMARY_Y); - for (int i = 0; i < 50; i++) { - lv_chart_set_next_value2(chart, ser, lv_rand(0, 200), lv_rand(0, 1000)); - } + // animation + lv_anim_t a; + lv_anim_init(&a); + lv_anim_set_values(&a, 20, 100); + lv_anim_set_repeat_count(&a, LV_ANIM_REPEAT_INFINITE); + lv_anim_set_exec_cb(&a, scale1_indic1_anim_cb); + lv_anim_set_var(&a, arc); + lv_anim_set_duration(&a, 4100); + lv_anim_set_playback_duration(&a, 2700); + lv_anim_start(&a); - lv_timer_create(add_data, 100, chart); + arc = lv_arc_create(scale1); + lv_obj_remove_style(arc, NULL, LV_PART_KNOB); + lv_obj_set_size(arc, lv_pct(100), lv_pct(100)); + lv_obj_set_style_margin_all(arc, 20, 0); + lv_obj_set_style_arc_opa(arc, 0, 0); + lv_obj_set_style_arc_width(arc, 15, LV_PART_INDICATOR); + lv_obj_set_style_arc_color(arc, lv_palette_main(LV_PALETTE_RED), LV_PART_INDICATOR); + lv_obj_remove_flag(arc, LV_OBJ_FLAG_CLICKABLE); + lv_obj_center(arc); + + lv_anim_set_exec_cb(&a, scale1_indic2_anim_cb); + lv_anim_set_var(&a, arc); + lv_anim_set_duration(&a, 2600); + lv_anim_set_playback_duration(&a, 3200); + lv_anim_start(&a); + + arc = lv_arc_create(scale1); + lv_obj_remove_style(arc, NULL, LV_PART_KNOB); + lv_obj_set_size(arc, lv_pct(100), lv_pct(100)); + lv_obj_set_style_margin_all(arc, 40, 0); + lv_obj_set_style_arc_opa(arc, 0, 0); + lv_obj_set_style_arc_width(arc, 15, LV_PART_INDICATOR); + lv_obj_set_style_arc_color(arc, lv_palette_main(LV_PALETTE_GREEN), LV_PART_INDICATOR); + lv_obj_remove_flag(arc, LV_OBJ_FLAG_CLICKABLE); + lv_obj_center(arc); + + lv_anim_set_exec_cb(&a, scale1_indic3_anim_cb); + lv_anim_set_var(&a, arc); + lv_anim_set_duration(&a, 2800); + lv_anim_set_playback_duration(&a, 1800); + lv_anim_start(&a); } diff --git a/examples/peripherals/lcd/rgb_panel/main/rgb_lcd_example_main.c b/examples/peripherals/lcd/rgb_panel/main/rgb_lcd_example_main.c index 624c4aea4d..8823c8c01d 100644 --- a/examples/peripherals/lcd/rgb_panel/main/rgb_lcd_example_main.c +++ b/examples/peripherals/lcd/rgb_panel/main/rgb_lcd_example_main.c @@ -24,7 +24,7 @@ static const char *TAG = "example"; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// Please update the following configuration according to your LCD spec ////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// FPS = 18000000/(1+40+20+800)/(1+8+4+480) = 42Hz +// Refresh Rate = 18000000/(1+40+20+800)/(1+10+5+480) = 42Hz #define EXAMPLE_LCD_PIXEL_CLOCK_HZ (18 * 1000 * 1000) #define EXAMPLE_LCD_H_RES 800 #define EXAMPLE_LCD_V_RES 480 @@ -32,47 +32,55 @@ static const char *TAG = "example"; #define EXAMPLE_LCD_HBP 40 #define EXAMPLE_LCD_HFP 20 #define EXAMPLE_LCD_VSYNC 1 -#define EXAMPLE_LCD_VBP 8 -#define EXAMPLE_LCD_VFP 4 +#define EXAMPLE_LCD_VBP 10 +#define EXAMPLE_LCD_VFP 5 #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_BK_LIGHT 4 -#define EXAMPLE_PIN_NUM_HSYNC 46 -#define EXAMPLE_PIN_NUM_VSYNC 3 -#define EXAMPLE_PIN_NUM_DE 0 -#define EXAMPLE_PIN_NUM_PCLK 9 -#define EXAMPLE_PIN_NUM_DATA0 14 // B0 -#define EXAMPLE_PIN_NUM_DATA1 13 // B1 -#define EXAMPLE_PIN_NUM_DATA2 12 // B2 -#define EXAMPLE_PIN_NUM_DATA3 11 // B3 -#define EXAMPLE_PIN_NUM_DATA4 10 // B4 -#define EXAMPLE_PIN_NUM_DATA5 39 // G0 -#define EXAMPLE_PIN_NUM_DATA6 38 // G1 -#define EXAMPLE_PIN_NUM_DATA7 45 // G2 -#define EXAMPLE_PIN_NUM_DATA8 48 // G3 -#define EXAMPLE_PIN_NUM_DATA9 47 // G4 -#define EXAMPLE_PIN_NUM_DATA10 21 // G5 -#define EXAMPLE_PIN_NUM_DATA11 1 // R0 -#define EXAMPLE_PIN_NUM_DATA12 2 // R1 -#define EXAMPLE_PIN_NUM_DATA13 42 // R2 -#define EXAMPLE_PIN_NUM_DATA14 41 // R3 -#define EXAMPLE_PIN_NUM_DATA15 40 // R4 +#define EXAMPLE_PIN_NUM_BK_LIGHT -1 #define EXAMPLE_PIN_NUM_DISP_EN -1 +#define EXAMPLE_PIN_NUM_HSYNC CONFIG_EXAMPLE_LCD_HSYNC_GPIO +#define EXAMPLE_PIN_NUM_VSYNC CONFIG_EXAMPLE_LCD_VSYNC_GPIO +#define EXAMPLE_PIN_NUM_DE CONFIG_EXAMPLE_LCD_DE_GPIO +#define EXAMPLE_PIN_NUM_PCLK CONFIG_EXAMPLE_LCD_PCLK_GPIO + +#define EXAMPLE_PIN_NUM_DATA0 CONFIG_EXAMPLE_LCD_DATA0_GPIO +#define EXAMPLE_PIN_NUM_DATA1 CONFIG_EXAMPLE_LCD_DATA1_GPIO +#define EXAMPLE_PIN_NUM_DATA2 CONFIG_EXAMPLE_LCD_DATA2_GPIO +#define EXAMPLE_PIN_NUM_DATA3 CONFIG_EXAMPLE_LCD_DATA3_GPIO +#define EXAMPLE_PIN_NUM_DATA4 CONFIG_EXAMPLE_LCD_DATA4_GPIO +#define EXAMPLE_PIN_NUM_DATA5 CONFIG_EXAMPLE_LCD_DATA5_GPIO +#define EXAMPLE_PIN_NUM_DATA6 CONFIG_EXAMPLE_LCD_DATA6_GPIO +#define EXAMPLE_PIN_NUM_DATA7 CONFIG_EXAMPLE_LCD_DATA7_GPIO +#define EXAMPLE_PIN_NUM_DATA8 CONFIG_EXAMPLE_LCD_DATA8_GPIO +#define EXAMPLE_PIN_NUM_DATA9 CONFIG_EXAMPLE_LCD_DATA9_GPIO +#define EXAMPLE_PIN_NUM_DATA10 CONFIG_EXAMPLE_LCD_DATA10_GPIO +#define EXAMPLE_PIN_NUM_DATA11 CONFIG_EXAMPLE_LCD_DATA11_GPIO +#define EXAMPLE_PIN_NUM_DATA12 CONFIG_EXAMPLE_LCD_DATA12_GPIO +#define EXAMPLE_PIN_NUM_DATA13 CONFIG_EXAMPLE_LCD_DATA13_GPIO +#define EXAMPLE_PIN_NUM_DATA14 CONFIG_EXAMPLE_LCD_DATA14_GPIO +#define EXAMPLE_PIN_NUM_DATA15 CONFIG_EXAMPLE_LCD_DATA15_GPIO + #if CONFIG_EXAMPLE_DOUBLE_FB #define EXAMPLE_LCD_NUM_FB 2 #else #define EXAMPLE_LCD_NUM_FB 1 #endif // CONFIG_EXAMPLE_DOUBLE_FB +#if CONFIG_EXAMPLE_LCD_DATA_LINES_16 +#define EXAMPLE_DATA_BUS_WIDTH 16 +#define EXAMPLE_PIXEL_SIZE 2 +#define EXAMPLE_LV_COLOR_FORMAT LV_COLOR_FORMAT_RGB565 +#endif + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// Please update the following configuration according to your Application /////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #define EXAMPLE_LVGL_DRAW_BUF_LINES 50 // number of display lines in each draw buffer #define EXAMPLE_LVGL_TICK_PERIOD_MS 2 -#define EXAMPLE_LVGL_TASK_STACK_SIZE (4 * 1024) +#define EXAMPLE_LVGL_TASK_STACK_SIZE (5 * 1024) #define EXAMPLE_LVGL_TASK_PRIORITY 2 // LVGL library is not thread-safe, this example will call LVGL APIs from different tasks, so use a mutex to protect it @@ -127,6 +135,12 @@ static void example_lvgl_port_task(void *arg) _lock_acquire(&lvgl_api_lock); time_till_next_ms = lv_timer_handler(); _lock_release(&lvgl_api_lock); + + // in case of task watch dog timeout, set the minimal delay to 10ms + if (time_till_next_ms < 10) { + time_till_next_ms = 10; + } + usleep(1000 * time_till_next_ms); } } @@ -166,7 +180,7 @@ void app_main(void) ESP_LOGI(TAG, "Install RGB LCD panel driver"); esp_lcd_panel_handle_t panel_handle = NULL; esp_lcd_rgb_panel_config_t panel_config = { - .data_width = 16, // RGB565 in parallel mode, thus 16bit in width + .data_width = EXAMPLE_DATA_BUS_WIDTH, .dma_burst_size = 64, .num_fbs = EXAMPLE_LCD_NUM_FB, #if CONFIG_EXAMPLE_USE_BOUNCE_BUFFER @@ -228,7 +242,7 @@ void app_main(void) // associate the rgb panel handle to the display lv_display_set_user_data(display, panel_handle); // set color depth - lv_display_set_color_format(display, LV_COLOR_FORMAT_RGB565); + lv_display_set_color_format(display, EXAMPLE_LV_COLOR_FORMAT); // create draw buffers void *buf1 = NULL; void *buf2 = NULL; @@ -236,11 +250,11 @@ void app_main(void) ESP_LOGI(TAG, "Use frame buffers as LVGL draw buffers"); ESP_ERROR_CHECK(esp_lcd_rgb_panel_get_frame_buffer(panel_handle, 2, &buf1, &buf2)); // set LVGL draw buffers and direct mode - lv_display_set_buffers(display, buf1, buf2, EXAMPLE_LCD_H_RES * EXAMPLE_LCD_V_RES * sizeof(lv_color16_t), LV_DISPLAY_RENDER_MODE_DIRECT); + lv_display_set_buffers(display, buf1, buf2, EXAMPLE_LCD_H_RES * EXAMPLE_LCD_V_RES * EXAMPLE_PIXEL_SIZE, LV_DISPLAY_RENDER_MODE_DIRECT); #else ESP_LOGI(TAG, "Allocate LVGL draw buffers"); // it's recommended to allocate the draw buffer from internal memory, for better performance - size_t draw_buffer_sz = EXAMPLE_LCD_H_RES * EXAMPLE_LVGL_DRAW_BUF_LINES * sizeof(lv_color16_t); + size_t draw_buffer_sz = EXAMPLE_LCD_H_RES * EXAMPLE_LVGL_DRAW_BUF_LINES * EXAMPLE_PIXEL_SIZE; buf1 = heap_caps_malloc(draw_buffer_sz, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); assert(buf1); // set LVGL draw buffers and partial mode @@ -269,7 +283,7 @@ void app_main(void) ESP_LOGI(TAG, "Create LVGL task"); xTaskCreate(example_lvgl_port_task, "LVGL", EXAMPLE_LVGL_TASK_STACK_SIZE, NULL, EXAMPLE_LVGL_TASK_PRIORITY, NULL); - ESP_LOGI(TAG, "Display LVGL Scatter Chart"); + ESP_LOGI(TAG, "Display LVGL UI"); // Lock the mutex due to the LVGL APIs are not thread-safe _lock_acquire(&lvgl_api_lock); example_lvgl_demo_ui(display); diff --git a/examples/peripherals/lcd/rgb_panel/pytest_rgb_panel_lvgl.py b/examples/peripherals/lcd/rgb_panel/pytest_rgb_panel_lvgl.py index 5c525ec260..7b0c751ee5 100644 --- a/examples/peripherals/lcd/rgb_panel/pytest_rgb_panel_lvgl.py +++ b/examples/peripherals/lcd/rgb_panel/pytest_rgb_panel_lvgl.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: CC0-1.0 import pytest from pytest_embedded import Dut @@ -22,4 +22,5 @@ def test_rgb_lcd_lvgl(dut: Dut) -> None: dut.expect_exact('example: Turn on LCD backlight') dut.expect_exact('example: Initialize LVGL library') dut.expect_exact('example: Install LVGL tick timer') - dut.expect_exact('example: Display LVGL Scatter Chart') + dut.expect_exact('example: Create LVGL task') + dut.expect_exact('example: Display LVGL UI') diff --git a/examples/peripherals/lcd/rgb_panel/sdkconfig.defaults.esp32s3 b/examples/peripherals/lcd/rgb_panel/sdkconfig.defaults.esp32s3 index 4801a05ba0..71d433a146 100644 --- a/examples/peripherals/lcd/rgb_panel/sdkconfig.defaults.esp32s3 +++ b/examples/peripherals/lcd/rgb_panel/sdkconfig.defaults.esp32s3 @@ -2,6 +2,38 @@ CONFIG_SPIRAM=y CONFIG_SPIRAM_MODE_OCT=y CONFIG_SPIRAM_SPEED_80M=y +# LCD_CAM support 16 data lines at most +CONFIG_EXAMPLE_LCD_DATA_LINES_16=y +CONFIG_LV_COLOR_DEPTH_16=y + # 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_XIP_FROM_PSRAM=y + +# Default GPIO assignment +CONFIG_EXAMPLE_LCD_VSYNC_GPIO=3 +CONFIG_EXAMPLE_LCD_HSYNC_GPIO=46 +CONFIG_EXAMPLE_LCD_DE_GPIO=0 +CONFIG_EXAMPLE_LCD_PCLK_GPIO=9 + +# B3:B7 <=> DATA0:DATA4 +CONFIG_EXAMPLE_LCD_DATA0_GPIO=14 +CONFIG_EXAMPLE_LCD_DATA1_GPIO=13 +CONFIG_EXAMPLE_LCD_DATA2_GPIO=12 +CONFIG_EXAMPLE_LCD_DATA3_GPIO=11 +CONFIG_EXAMPLE_LCD_DATA4_GPIO=10 + +# G2:G7 <=> DATA5:DATA10 +CONFIG_EXAMPLE_LCD_DATA5_GPIO=39 +CONFIG_EXAMPLE_LCD_DATA6_GPIO=38 +CONFIG_EXAMPLE_LCD_DATA7_GPIO=45 +CONFIG_EXAMPLE_LCD_DATA8_GPIO=48 +CONFIG_EXAMPLE_LCD_DATA9_GPIO=47 +CONFIG_EXAMPLE_LCD_DATA10_GPIO=21 + +# R3:R7 <=> DATA11:DATA15 +CONFIG_EXAMPLE_LCD_DATA11_GPIO=1 +CONFIG_EXAMPLE_LCD_DATA12_GPIO=2 +CONFIG_EXAMPLE_LCD_DATA13_GPIO=42 +CONFIG_EXAMPLE_LCD_DATA14_GPIO=41 +CONFIG_EXAMPLE_LCD_DATA15_GPIO=40