feat(parlio): adapt rgb_matrix example to lvgl9

This commit is contained in:
Chen Jichang
2024-11-01 18:19:58 +08:00
parent 0546805fc5
commit 87f2080705
8 changed files with 151 additions and 75 deletions

View File

@@ -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

View File

@@ -1,3 +1,3 @@
dependencies:
idf: ">=5.1"
lvgl/lvgl: "8.3.0"
lvgl/lvgl: "9.2.2"

View File

@@ -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);
}

View File

@@ -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 <string.h>
#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();

View File

@@ -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')

View File

@@ -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

View File

@@ -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

View File

@@ -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