diff --git a/examples/peripherals/parlio/parlio_tx/simple_rgb_led_matrix/main/Kconfig.projbuild b/examples/peripherals/parlio/parlio_tx/simple_rgb_led_matrix/main/Kconfig.projbuild new file mode 100644 index 0000000000..1529a312ac --- /dev/null +++ b/examples/peripherals/parlio/parlio_tx/simple_rgb_led_matrix/main/Kconfig.projbuild @@ -0,0 +1,55 @@ +menu "Example Configuration" + + config EXAMPLE_PIN_NUM_R1 + int "Red Pin 1" + default 7 + + config EXAMPLE_PIN_NUM_G1 + int "Green Pin 1" + default 4 + + config EXAMPLE_PIN_NUM_B1 + int "Blue Pin 1" + default 1 + + config EXAMPLE_PIN_NUM_R2 + int "Red Pin 2" + default 6 + + config EXAMPLE_PIN_NUM_G2 + int "Green Pin 2" + default 3 + + config EXAMPLE_PIN_NUM_B2 + int "Blue Pin 2" + default 0 + + config EXAMPLE_PIN_NUM_LATCH + int "Latch Pin" + default 5 + + config EXAMPLE_PIN_NUM_PCLK + int "PCLK Pin" + default 10 + + config EXAMPLE_PIN_NUM_OE + int "OE Pin" + default 2 + + config EXAMPLE_PIN_NUM_A + int "A Pin" + default 20 + + config EXAMPLE_PIN_NUM_B + int "B Pin" + default 21 + + config EXAMPLE_PIN_NUM_C + int "C Pin" + default 22 + + config EXAMPLE_PIN_NUM_D + int "D Pin" + default 23 + +endmenu diff --git a/examples/peripherals/parlio/parlio_tx/simple_rgb_led_matrix/main/idf_component.yml b/examples/peripherals/parlio/parlio_tx/simple_rgb_led_matrix/main/idf_component.yml index 7dba8c85e0..c91c519e78 100644 --- a/examples/peripherals/parlio/parlio_tx/simple_rgb_led_matrix/main/idf_component.yml +++ b/examples/peripherals/parlio/parlio_tx/simple_rgb_led_matrix/main/idf_component.yml @@ -1,3 +1,3 @@ dependencies: idf: ">=5.1" - lvgl/lvgl: "8.3.0" + lvgl/lvgl: "9.2.2" diff --git a/examples/peripherals/parlio/parlio_tx/simple_rgb_led_matrix/main/lvgl_demo_ui.c b/examples/peripherals/parlio/parlio_tx/simple_rgb_led_matrix/main/lvgl_demo_ui.c index 0cd90f48bb..846fcdf771 100644 --- a/examples/peripherals/parlio/parlio_tx/simple_rgb_led_matrix/main/lvgl_demo_ui.c +++ b/examples/peripherals/parlio/parlio_tx/simple_rgb_led_matrix/main/lvgl_demo_ui.c @@ -1,25 +1,32 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: CC0-1.0 */ #include "lvgl.h" -void example_lvgl_demo_ui(lv_disp_t *disp) +void example_lvgl_demo_ui(lv_display_t *disp) { - lv_obj_t *scr = lv_disp_get_scr_act(disp); + lv_obj_t *scr = lv_display_get_screen_active(disp); + static lv_style_t up_style; + lv_style_init(&up_style); lv_obj_t *up_label = lv_label_create(scr); - lv_label_set_recolor(up_label, true); - lv_label_set_text(up_label, "#FF0000 Hello# #0000FF World#"); + lv_style_set_text_color(&up_style, lv_palette_main(LV_PALETTE_RED)); + lv_obj_add_style(up_label, &up_style, 0); + lv_label_set_text(up_label, "Hello World"); lv_label_set_long_mode(up_label, LV_LABEL_LONG_SCROLL_CIRCULAR); /* Circular scroll */ /* Size of the screen */ - lv_obj_set_width(up_label, disp->driver->hor_res); + lv_obj_set_width(up_label, lv_display_get_horizontal_resolution(disp)); lv_obj_align_to(up_label, scr, LV_ALIGN_TOP_MID, 0, 0); + static lv_style_t low_style; + lv_style_init(&low_style); lv_obj_t *low_label = lv_label_create(scr); + lv_style_set_text_color(&low_style, lv_palette_main(LV_PALETTE_GREEN)); + lv_obj_add_style(low_label, &low_style, 0); lv_label_set_text(low_label, LV_SYMBOL_WIFI LV_SYMBOL_GPS LV_SYMBOL_BATTERY_2 LV_SYMBOL_AUDIO); /* Size of the screen */ - lv_obj_set_width(low_label, disp->driver->hor_res); + lv_obj_set_width(low_label, lv_display_get_horizontal_resolution(disp)); lv_obj_align_to(low_label, scr, LV_ALIGN_BOTTOM_MID, 0, 0); } diff --git a/examples/peripherals/parlio/parlio_tx/simple_rgb_led_matrix/main/rgb_led_matrix_example_main.c b/examples/peripherals/parlio/parlio_tx/simple_rgb_led_matrix/main/rgb_led_matrix_example_main.c index 588f4cb96b..fa248198e3 100644 --- a/examples/peripherals/parlio/parlio_tx/simple_rgb_led_matrix/main/rgb_led_matrix_example_main.c +++ b/examples/peripherals/parlio/parlio_tx/simple_rgb_led_matrix/main/rgb_led_matrix_example_main.c @@ -1,8 +1,9 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ +#include #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "esp_attr.h" @@ -28,20 +29,21 @@ static const char *TAG = "example"; #define EXAMPLE_HUB75_B1_IDX 1 // B1 bit position #define EXAMPLE_HUB75_B2_IDX 0 // B2 bit position // GPIO assignment -#define EXAMPLE_PIN_NUM_R1 7 -#define EXAMPLE_PIN_NUM_G1 4 -#define EXAMPLE_PIN_NUM_B1 1 -#define EXAMPLE_PIN_NUM_R2 6 -#define EXAMPLE_PIN_NUM_G2 3 -#define EXAMPLE_PIN_NUM_B2 0 -#define EXAMPLE_PIN_NUM_LATCH 5 -#define EXAMPLE_PIN_NUM_OE 2 -#define EXAMPLE_PIN_NUM_PCLK 10 +#define EXAMPLE_PIN_NUM_R1 CONFIG_EXAMPLE_PIN_NUM_R1 +#define EXAMPLE_PIN_NUM_G1 CONFIG_EXAMPLE_PIN_NUM_G1 +#define EXAMPLE_PIN_NUM_B1 CONFIG_EXAMPLE_PIN_NUM_B1 +#define EXAMPLE_PIN_NUM_R2 CONFIG_EXAMPLE_PIN_NUM_R2 +#define EXAMPLE_PIN_NUM_G2 CONFIG_EXAMPLE_PIN_NUM_G2 +#define EXAMPLE_PIN_NUM_B2 CONFIG_EXAMPLE_PIN_NUM_B2 +#define EXAMPLE_PIN_NUM_LATCH CONFIG_EXAMPLE_PIN_NUM_LATCH +#define EXAMPLE_PIN_NUM_OE CONFIG_EXAMPLE_PIN_NUM_OE +#define EXAMPLE_PIN_NUM_PCLK CONFIG_EXAMPLE_PIN_NUM_PCLK // address signals are powered by fast GPIO module -#define EXAMPLE_PIN_NUM_A 20 -#define EXAMPLE_PIN_NUM_B 21 -#define EXAMPLE_PIN_NUM_C 22 -#define EXAMPLE_PIN_NUM_D 23 +#define EXAMPLE_PIN_NUM_A CONFIG_EXAMPLE_PIN_NUM_A +#define EXAMPLE_PIN_NUM_B CONFIG_EXAMPLE_PIN_NUM_B +#define EXAMPLE_PIN_NUM_C CONFIG_EXAMPLE_PIN_NUM_C +#define EXAMPLE_PIN_NUM_D CONFIG_EXAMPLE_PIN_NUM_D + // The pixel clock frequency #define EXAMPLE_LED_MATRIX_PIXEL_CLOCK_HZ (10 * 1000 * 1000) // 10MHz // The pixel number in horizontal and vertical @@ -52,42 +54,36 @@ static const char *TAG = "example"; #define EXAMPLE_GPTIMER_RESOLUTION_HZ (1 * 1000 * 1000) // 1MHz #define EXAMPLE_LVGL_TICK_PERIOD_MS 5 // 5ms -// 0x92: we pick the first bit of each RGB element in the order of 3-3-2, that's 0b10010010 -// p1: pixel on the upper half screen -// p2: pixel on the lower half screen -// OE=1: disable the output -#define MERGE_TWO_LVGL_PIXELS(p1, p2) \ - do \ - { \ - p1->full &= 0x92; \ - p1->full |= (p2->full & 0x92) >> 1; \ - p1->full |= 1 << EXAMPLE_HUB75_OE_IDX; \ - } while (0) - -extern void example_lvgl_demo_ui(lv_disp_t *disp); - // LED Matrix frame buffer, we use a dedicated task to flush this frame buffer -static lv_color_t s_frame_buffer[EXAMPLE_LED_MATRIX_H_RES * EXAMPLE_LED_MATRIX_V_RES / 2]; +static uint8_t s_frame_buffer[EXAMPLE_LED_MATRIX_H_RES * EXAMPLE_LED_MATRIX_V_RES / 2] = {}; -static void example_lvgl_flush_cb(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_map) +// upper_half: pixel on the upper half screen +// lower_half: pixel on the lower half screen +static void merge_two_pixels(lv_color16_t *upper_half, lv_color16_t *lower_half, int index) { - lv_color_t *upper_half = color_map; - lv_color_t *lower_half = color_map + EXAMPLE_LED_MATRIX_V_RES * EXAMPLE_LED_MATRIX_H_RES / 2; + s_frame_buffer[index] = (upper_half->red >> 4) << EXAMPLE_HUB75_R1_IDX | (upper_half->green >> 5) << EXAMPLE_HUB75_G1_IDX | (upper_half->blue >> 4) << EXAMPLE_HUB75_B1_IDX; + s_frame_buffer[index] |= (lower_half->red >> 4) << EXAMPLE_HUB75_R2_IDX | (lower_half->green >> 5) << EXAMPLE_HUB75_G2_IDX | (lower_half->blue >> 4) << EXAMPLE_HUB75_B2_IDX; + // OE=1: enable the output + s_frame_buffer[index] |= 1 << EXAMPLE_HUB75_OE_IDX; +} + +extern void example_lvgl_demo_ui(lv_display_t *disp); + +static void example_lvgl_flush_cb(lv_display_t *display, const lv_area_t *area, uint8_t *color_map) +{ + lv_color16_t *upper_half = (lv_color16_t *)color_map; + lv_color16_t *lower_half = (lv_color16_t *)color_map + EXAMPLE_LED_MATRIX_V_RES * EXAMPLE_LED_MATRIX_H_RES / 2; + int index = 0; for (int line = 0; line < EXAMPLE_LED_MATRIX_V_RES / 2; line++) { for (int col = 0; col < EXAMPLE_LED_MATRIX_H_RES - 1; col++) { - MERGE_TWO_LVGL_PIXELS(upper_half, lower_half); - upper_half++; - lower_half++; + merge_two_pixels(upper_half++, lower_half++, index++); } - MERGE_TWO_LVGL_PIXELS(upper_half, lower_half); + merge_two_pixels(upper_half++, lower_half++, index); // need special handling for the last pixel in each line // latch up at the end of each line - upper_half->full |= (1 << EXAMPLE_HUB75_LATCH_IDX); - upper_half++; - lower_half++; + s_frame_buffer[index++] |= (1 << EXAMPLE_HUB75_LATCH_IDX); } - memcpy(s_frame_buffer, color_map, sizeof(s_frame_buffer)); - lv_disp_flush_ready(drv); + lv_display_flush_ready(display); } static IRAM_ATTR bool parlio_tx_line_done_cb(parlio_tx_unit_handle_t tx_unit, const parlio_tx_done_event_data_t *edata, void *user_ctx) @@ -107,9 +103,6 @@ static IRAM_ATTR bool gptimer_alarm_cb_lvgl_tick(gptimer_handle_t timer, const g void app_main(void) { - static lv_disp_draw_buf_t disp_buf; - static lv_disp_drv_t disp_drv; - ESP_LOGI(TAG, "Install fast GPIO bundle for line address control"); dedic_gpio_bundle_config_t dedic_gpio_conf = { .flags.out_en = true, @@ -144,7 +137,7 @@ void app_main(void) }, .output_clk_freq_hz = EXAMPLE_LED_MATRIX_PIXEL_CLOCK_HZ, .trans_queue_depth = 32, - .max_transfer_size = EXAMPLE_LED_MATRIX_H_RES * sizeof(lv_color_t) * 2, // 2 lines as the maximum transfer size + .max_transfer_size = EXAMPLE_LED_MATRIX_H_RES * sizeof(uint8_t) * 2, // 2 lines as the maximum transfer size .sample_edge = PARLIO_SAMPLE_EDGE_POS, }; ESP_ERROR_CHECK(parlio_new_tx_unit(&config, &tx_unit)); @@ -158,23 +151,21 @@ void app_main(void) ESP_LOGI(TAG, "Initialize LVGL library"); lv_init(); - // allocate two full-screen draw buffers - lv_color_t *buf1 = malloc(EXAMPLE_LED_MATRIX_H_RES * EXAMPLE_LED_MATRIX_V_RES * sizeof(lv_color_t)); - assert(buf1); - lv_color_t *buf2 = malloc(EXAMPLE_LED_MATRIX_H_RES * EXAMPLE_LED_MATRIX_V_RES * sizeof(lv_color_t)); - assert(buf2); - // initialize LVGL draw buffers - lv_disp_draw_buf_init(&disp_buf, buf1, buf2, EXAMPLE_LED_MATRIX_H_RES * EXAMPLE_LED_MATRIX_V_RES); + lv_display_t *display = lv_display_create(EXAMPLE_LED_MATRIX_H_RES, EXAMPLE_LED_MATRIX_V_RES); - ESP_LOGI(TAG, "Register display driver to LVGL"); - lv_disp_drv_init(&disp_drv); - disp_drv.hor_res = EXAMPLE_LED_MATRIX_H_RES; - disp_drv.ver_res = EXAMPLE_LED_MATRIX_V_RES; - disp_drv.flush_cb = example_lvgl_flush_cb; - disp_drv.draw_buf = &disp_buf; - disp_drv.user_data = NULL; - disp_drv.full_refresh = true; // the full_refresh mode can maintain the synchronization between two adjacent frame buffers - lv_disp_t *disp = lv_disp_drv_register(&disp_drv); + // allocate two full-screen draw buffers + size_t draw_buffer_sz = EXAMPLE_LED_MATRIX_H_RES * EXAMPLE_LED_MATRIX_V_RES * sizeof(lv_color16_t); + void *buf1 = heap_caps_calloc(1, draw_buffer_sz, MALLOC_CAP_INTERNAL); + assert(buf1); + void *buf2 = heap_caps_calloc(1, draw_buffer_sz, MALLOC_CAP_INTERNAL); + assert(buf2); + // Use RGB565 because RGB332 is not supported in LVGL9.2 + lv_display_set_color_format(display, LV_COLOR_FORMAT_RGB565); + // initialize LVGL draw buffers + // Since the rgb matrix needs to be refreshed dynamically, use fullmode + lv_display_set_buffers(display, buf1, buf2, draw_buffer_sz, LV_DISPLAY_RENDER_MODE_FULL); + // set the callback which can copy the rendered image to an area of the display + lv_display_set_flush_cb(display, example_lvgl_flush_cb); ESP_LOGI(TAG, "Install LVGL tick timer"); // increase the LVGL tick in the GPTimer alarm callback @@ -198,7 +189,7 @@ void app_main(void) ESP_ERROR_CHECK(gptimer_enable(lvgl_tick_timer)); ESP_LOGI(TAG, "Display LVGL UI"); - example_lvgl_demo_ui(disp); + example_lvgl_demo_ui(display); ESP_ERROR_CHECK(gptimer_start(lvgl_tick_timer)); @@ -210,7 +201,7 @@ void app_main(void) while (1) { for (int i = 0; i < EXAMPLE_LED_MATRIX_V_RES / 2; i++) { ESP_ERROR_CHECK(parlio_tx_unit_transmit(tx_unit, payload + EXAMPLE_LED_MATRIX_H_RES * i, - EXAMPLE_LED_MATRIX_H_RES * sizeof(lv_color_t) * 8, &transmit_config)); + EXAMPLE_LED_MATRIX_H_RES * sizeof(uint8_t) * 8, &transmit_config)); } ESP_ERROR_CHECK(parlio_tx_unit_wait_all_done(tx_unit, -1)); lv_timer_handler(); diff --git a/examples/peripherals/parlio/parlio_tx/simple_rgb_led_matrix/pytest_simple_rgb_led_matrix.py b/examples/peripherals/parlio/parlio_tx/simple_rgb_led_matrix/pytest_simple_rgb_led_matrix.py index 940d78c615..9376556578 100644 --- a/examples/peripherals/parlio/parlio_tx/simple_rgb_led_matrix/pytest_simple_rgb_led_matrix.py +++ b/examples/peripherals/parlio/parlio_tx/simple_rgb_led_matrix/pytest_simple_rgb_led_matrix.py @@ -1,6 +1,5 @@ -# SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: CC0-1.0 - import pytest from pytest_embedded import Dut @@ -11,6 +10,5 @@ def test_simple_rgb_led_matrix_example(dut: Dut) -> None: dut.expect_exact('example: Install fast GPIO bundle for line address control') dut.expect_exact('example: Install parallel IO TX unit') dut.expect_exact('example: Initialize LVGL library') - dut.expect_exact('example: Register display driver to LVGL') dut.expect_exact('example: Install LVGL tick timer') dut.expect_exact('example: Display LVGL UI') diff --git a/examples/peripherals/parlio/parlio_tx/simple_rgb_led_matrix/sdkconfig.defaults b/examples/peripherals/parlio/parlio_tx/simple_rgb_led_matrix/sdkconfig.defaults index 788db18578..3d0db7cbae 100644 --- a/examples/peripherals/parlio/parlio_tx/simple_rgb_led_matrix/sdkconfig.defaults +++ b/examples/peripherals/parlio/parlio_tx/simple_rgb_led_matrix/sdkconfig.defaults @@ -2,5 +2,4 @@ # Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration # CONFIG_ESP_TASK_WDT_INIT=n -CONFIG_LV_COLOR_DEPTH_8=y CONFIG_LV_THEME_DEFAULT_DARK=y diff --git a/examples/peripherals/parlio/parlio_tx/simple_rgb_led_matrix/sdkconfig.defaults.esp32c6 b/examples/peripherals/parlio/parlio_tx/simple_rgb_led_matrix/sdkconfig.defaults.esp32c6 new file mode 100644 index 0000000000..645d154d34 --- /dev/null +++ b/examples/peripherals/parlio/parlio_tx/simple_rgb_led_matrix/sdkconfig.defaults.esp32c6 @@ -0,0 +1,13 @@ +CONFIG_EXAMPLE_PIN_NUM_R1=7 +CONFIG_EXAMPLE_PIN_NUM_G1=4 +CONFIG_EXAMPLE_PIN_NUM_B1=1 +CONFIG_EXAMPLE_PIN_NUM_R2=6 +CONFIG_EXAMPLE_PIN_NUM_G2=3 +CONFIG_EXAMPLE_PIN_NUM_B2=0 +CONFIG_EXAMPLE_PIN_NUM_LATCH=5 +CONFIG_EXAMPLE_PIN_NUM_OE=2 +CONFIG_EXAMPLE_PIN_NUM_PCLK=10 +CONFIG_EXAMPLE_PIN_NUM_A=20 +CONFIG_EXAMPLE_PIN_NUM_B=21 +CONFIG_EXAMPLE_PIN_NUM_C=22 +CONFIG_EXAMPLE_PIN_NUM_D=23 diff --git a/examples/peripherals/parlio/parlio_tx/simple_rgb_led_matrix/sdkconfig.defaults.esp32h2 b/examples/peripherals/parlio/parlio_tx/simple_rgb_led_matrix/sdkconfig.defaults.esp32h2 new file mode 100644 index 0000000000..6ae3d6cbfe --- /dev/null +++ b/examples/peripherals/parlio/parlio_tx/simple_rgb_led_matrix/sdkconfig.defaults.esp32h2 @@ -0,0 +1,13 @@ +CONFIG_EXAMPLE_PIN_NUM_R1=12 +CONFIG_EXAMPLE_PIN_NUM_G1=0 +CONFIG_EXAMPLE_PIN_NUM_B1=22 +CONFIG_EXAMPLE_PIN_NUM_R2=2 +CONFIG_EXAMPLE_PIN_NUM_G2=1 +CONFIG_EXAMPLE_PIN_NUM_B2=3 +CONFIG_EXAMPLE_PIN_NUM_LATCH=11 +CONFIG_EXAMPLE_PIN_NUM_OE=26 +CONFIG_EXAMPLE_PIN_NUM_PCLK=27 +CONFIG_EXAMPLE_PIN_NUM_A=8 +CONFIG_EXAMPLE_PIN_NUM_B=5 +CONFIG_EXAMPLE_PIN_NUM_C=9 +CONFIG_EXAMPLE_PIN_NUM_D=10