Skip to content

Commit

Permalink
feat(LVGL port): Generate C arrays for images during build process
Browse files Browse the repository at this point in the history
  • Loading branch information
espzav committed Apr 23, 2024
1 parent c1692db commit 0350c47
Show file tree
Hide file tree
Showing 26 changed files with 387 additions and 644 deletions.
15 changes: 7 additions & 8 deletions components/esp_lvgl_port/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
# Changelog

## 2.0.1
## 2.1.0

### Features
- Added unit test
- Allow to sleep main LVGL task
- Wake LVGL task from touch and display, when set big maximum sleep
- Allow to select display color mode (only with LVGL9)
- Added LVGL sleep feature: The esp_lvgl_port handling can sleep if the display and touch are inactive (only with LVGL9)
- Added support for different display color modes (only with LVGL9)
- Added script for generating C array images during build (depends on LVGL version)

### Fixes
- Apply display rotation from configuration
- Wait for stop task when deinit
- Added esp_idf_version.h
- Applied initial display rotation from configuration https://github.com/espressif/esp-bsp/pull/278
- Added blocking wait for LVGL task stop during esp_lvgl_port de-initialization https://github.com/espressif/esp-bsp/issues/277
- Added missing esp_idf_version.h include

## 2.0.0

Expand Down
34 changes: 32 additions & 2 deletions components/esp_lvgl_port/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -280,30 +280,60 @@ If the SRAM is insufficient, you can use the PSRAM as a canvas and use a small t
}
```
### Generating images (C Array)
Images can be generated during build by adding these lines to end of the main CMakeLists.txt:
```
# Generate C array for each image
lvgl_port_create_c_image("images/logo.png" "images/" "ARGB8888" "NONE")
lvgl_port_create_c_image("images/image.png" "images/" "ARGB8888" "NONE")
# Add generated images to build
lvgl_port_add_images(${COMPONENT_LIB} "images/")
```
Usage of create C image function:
```
lvgl_port_create_c_image(input_image output_folder color_format compression)
```
Available color formats:
L8,I1,I2,I4,I8,A1,A2,A4,A8,ARGB8888,XRGB8888,RGB565,RGB565A8,RGB888,TRUECOLOR,TRUECOLOR_ALPHA,AUTO
Available compression:
NONE,RLE,LZ4
**Note:** Parameters `color_format` and `compression` are used only in LVGL 9.
## Power Saving
The LVGL port can be optimized for power saving mode. There are two main features.
### LVGL task sleep
For optimization power saving, the LVGL task should sleep, when it does nothing. Set `task_max_sleep_ms` to big value, the LVGL task will wait for events only.
The LVGL task can sleep till these situations:
* LVGL display invalidate
* LVGL animation in process
* Touch interrupt
* Button interrupt
* Knob interrupt
* USB mouse/keyboard interrupt
* Timeout (`task_max_sleep_ms` in configuration structure)
* User wake (by function `lvgl_port_task_wake`)
**Warning:** This feature is available from LVGL 9.
**Note:** Don't forget to set the interrupt pin in LCD touch when you set a big time for sleep in `task_max_sleep_ms`.
### Stopping the timer
For sleep, you can stop LVGL timer by function:
Timers can still work during light-sleep mode. You can stop LVGL timer before use light-sleep by function:
```
lvgl_port_stop();
```
and resume LVGL timer by function:
and resume LVGL timer after wake by function:
```
lvgl_port_resume();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
idf_component_register(SRCS "main.c"
INCLUDE_DIRS ".")

lvgl_port_create_c_image("images/esp_logo.png" "images/" "ARGB8888" "NONE")
lvgl_port_add_images(${COMPONENT_LIB} "images/")
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.c
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 13 additions & 1 deletion components/esp_lvgl_port/examples/touchscreen/main/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@

static const char *TAG = "EXAMPLE";

// LVGL image declare
LV_IMG_DECLARE(esp_logo)

/* LCD IO and panel */
static esp_lcd_panel_io_handle_t lcd_io = NULL;
static esp_lcd_panel_handle_t lcd_panel = NULL;
Expand Down Expand Up @@ -182,15 +185,19 @@ static esp_err_t app_lvgl_init(void)
.hres = EXAMPLE_LCD_H_RES,
.vres = EXAMPLE_LCD_V_RES,
.monochrome = false,
#if LVGL_VERSION_MAJOR >= 9
.color_format = LV_COLOR_FORMAT_RGB565,
#endif
.rotation = {
.swap_xy = false,
.mirror_x = true,
.mirror_y = true,
},
.flags = {
.buff_dma = true,
#if LVGL_VERSION_MAJOR >= 9
.swap_bytes = true,
#endif
}
};
lvgl_disp = lvgl_port_add_disp(&disp_cfg);
Expand Down Expand Up @@ -226,6 +233,11 @@ static void app_main_display(void)

/* Your LVGL objects code here .... */

/* Create image */
lv_obj_t *img_logo = lv_img_create(scr);
lv_img_set_src(img_logo, &esp_logo);
lv_obj_align(img_logo, LV_ALIGN_TOP_MID, 0, 20);

/* Label */
lv_obj_t *label = lv_label_create(scr);
lv_obj_set_width(label, EXAMPLE_LCD_H_RES);
Expand All @@ -236,7 +248,7 @@ static void app_main_display(void)
#else
lv_label_set_text(label, LV_SYMBOL_BELL" Hello world Espressif and LVGL "LV_SYMBOL_BELL"\n "LV_SYMBOL_WARNING" For simplier initialization, use BSP "LV_SYMBOL_WARNING);
#endif
lv_obj_align(label, LV_ALIGN_CENTER, 0, -30);
lv_obj_align(label, LV_ALIGN_CENTER, 0, 20);

/* Button */
lv_obj_t *btn = lv_btn_create(scr);
Expand Down
2 changes: 1 addition & 1 deletion components/esp_lvgl_port/idf_component.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
version: "2.0.0"
version: "2.1.0"
description: ESP LVGL port
url: https://github.com/espressif/esp-bsp/tree/master/components/esp_lvgl_port
dependencies:
Expand Down
2 changes: 1 addition & 1 deletion components/esp_lvgl_port/include/esp_lvgl_port.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ esp_err_t lvgl_port_resume(void);
* - ESP_ERR_NOT_SUPPORTED if it is not implemented
* - ESP_ERR_INVALID_STATE if queue is not initialized (can be returned after LVGL deinit)
*/
esp_err_t lvgl_port_task_wake(lvgl_port_event_t event, bool isr);
esp_err_t lvgl_port_task_wake(lvgl_port_event_t event);

#ifdef __cplusplus
}
Expand Down
69 changes: 69 additions & 0 deletions components/esp_lvgl_port/project_include.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# lvgl_port_create_c_image
#
# Create a C array of image for using with LVGL
function(lvgl_port_create_c_image image_path output_path color_format compression)

#Get LVGL version
idf_component_get_property(lvgl_ver lvgl__lvgl COMPONENT_VERSION)
set(LVGL_NAME "lvgl__lvgl")
if(lvgl_ver EQUAL "")
idf_component_get_property(lvgl_ver lvgl COMPONENT_VERSION)
set(LVGL_NAME "lvgl")
endif()

get_filename_component(image_full_path ${image_path} ABSOLUTE)
get_filename_component(output_full_path ${output_path} ABSOLUTE)
if(NOT EXISTS ${image_full_path})
message(FATAL_ERROR "Input image (${image_full_path}) not exists!")
endif()

message(STATUS "Generating C array image: ${image_path}")

#Create C array image by LVGL version
if(lvgl_ver VERSION_LESS "9.0.0")
if(NOT DEFINED ${CONFIG_LV_COLOR_16_SWAP})
set(CONFIG_LV_COLOR_16_SWAP "n")
endif()

if(${CONFIG_LV_COLOR_16_SWAP} STREQUAL "y")
set(color_format "RGB565SWAP")
else()
set(color_format "RGB565")
endif()

execute_process(COMMAND git clone https://github.com/W-Mai/lvgl_image_converter.git "${CMAKE_BINARY_DIR}/lvgl_image_converter")
execute_process(COMMAND git checkout 9174634e9dcc1b21a63668969406897aad650f35 WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/lvgl_image_converter" OUTPUT_QUIET)
execute_process(COMMAND python -m pip install -r "${CMAKE_BINARY_DIR}/lvgl_image_converter/requirements.txt")
execute_process(COMMAND ${PYTHON} "${CMAKE_BINARY_DIR}/lvgl_image_converter/lv_img_conv.py"
-ff C
-f true_color_alpha
-cf ${color_format}
-o ${output_full_path}
${image_full_path})
else()
idf_component_get_property(lvgl_dir ${LVGL_NAME} COMPONENT_DIR)
get_filename_component(script_path ${lvgl_dir}/scripts/LVGLImage.py ABSOLUTE)
set(lvglimage_py ${PYTHON} ${script_path})

#Install dependencies
execute_process(COMMAND python -m pip3 install pypng lz4)

execute_process(COMMAND ${lvglimage_py}
--ofmt=C
--cf=${color_format}
--compress=${compression}
-o ${output_full_path}
${image_full_path})
endif()

endfunction()

# lvgl_port_add_images
#
# Add all images to build
function(lvgl_port_add_images component output_path)
#Add images to sources
file(GLOB_RECURSE IMAGE_SOURCES ${output_path}*.c)
target_sources(${component} PRIVATE ${IMAGE_SOURCES})
idf_build_set_property(COMPILE_OPTIONS "-DLV_LVGL_H_INCLUDE_SIMPLE=1" APPEND)
endfunction()
2 changes: 1 addition & 1 deletion components/esp_lvgl_port/src/lvgl8/esp_lvgl_port.c
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ void lvgl_port_unlock(void)
xSemaphoreGiveRecursive(lvgl_port_ctx.lvgl_mux);
}

esp_err_t lvgl_port_task_wake(lvgl_port_event_t event, bool isr)
esp_err_t lvgl_port_task_wake(lvgl_port_event_t event)
{
ESP_LOGE(TAG, "Task wake is not supported, when used LVGL8!");
return ESP_ERR_NOT_SUPPORTED;
Expand Down
5 changes: 3 additions & 2 deletions components/esp_lvgl_port/src/lvgl9/esp_lvgl_port.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "esp_check.h"
#include "esp_timer.h"
#include "freertos/FreeRTOS.h"
#include "freertos/portmacro.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "esp_lvgl_port.h"
Expand Down Expand Up @@ -157,13 +158,13 @@ void lvgl_port_unlock(void)
xSemaphoreGiveRecursive(lvgl_port_ctx.lvgl_mux);
}

esp_err_t lvgl_port_task_wake(lvgl_port_event_t event, bool isr)
esp_err_t lvgl_port_task_wake(lvgl_port_event_t event)
{
if (!lvgl_port_ctx.lvgl_queue) {
return ESP_ERR_INVALID_STATE;
}

if (isr) {
if (xPortInIsrContext() == pdTRUE) {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xQueueSendFromISR(lvgl_port_ctx.lvgl_queue, &event, &xHigherPriorityTaskWoken);
if (xHigherPriorityTaskWoken) {
Expand Down
6 changes: 6 additions & 0 deletions components/esp_lvgl_port/src/lvgl9/esp_lvgl_port_button.c
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,9 @@ static void lvgl_port_btn_down_handler(void *arg, void *arg2)
ctx->btn_enter = true;
}
}

/* Wake LVGL task, if needed */
lvgl_port_task_wake(LVGL_PORT_EVENT_TOUCH);
}

static void lvgl_port_btn_up_handler(void *arg, void *arg2)
Expand All @@ -200,4 +203,7 @@ static void lvgl_port_btn_up_handler(void *arg, void *arg2)
ctx->btn_enter = false;
}
}

/* Wake LVGL task, if needed */
lvgl_port_task_wake(LVGL_PORT_EVENT_TOUCH);
}
4 changes: 2 additions & 2 deletions components/esp_lvgl_port/src/lvgl9/esp_lvgl_port_disp.c
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ static void lvgl_port_disp_rotation_update(lvgl_port_display_ctx_t *disp_ctx)
}

/* Wake LVGL task, if needed */
lvgl_port_task_wake(LVGL_PORT_EVENT_DISPLAY, false);
lvgl_port_task_wake(LVGL_PORT_EVENT_DISPLAY);
}

static void lvgl_port_disp_size_update_callback(lv_event_t *e)
Expand All @@ -350,5 +350,5 @@ static void lvgl_port_disp_size_update_callback(lv_event_t *e)
static void lvgl_port_display_invalidate_callback(lv_event_t *e)
{
/* Wake LVGL task, if needed */
lvgl_port_task_wake(LVGL_PORT_EVENT_DISPLAY, false);
lvgl_port_task_wake(LVGL_PORT_EVENT_DISPLAY);
}
17 changes: 17 additions & 0 deletions components/esp_lvgl_port/src/lvgl9/esp_lvgl_port_knob.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ typedef struct {
static void lvgl_port_encoder_read(lv_indev_t *indev_drv, lv_indev_data_t *data);
static void lvgl_port_encoder_btn_down_handler(void *arg, void *arg2);
static void lvgl_port_encoder_btn_up_handler(void *arg, void *arg2);
static void lvgl_port_encoder_knob_handler(void *arg, void *arg2);

/*******************************************************************************
* Public API functions
Expand All @@ -52,6 +53,10 @@ lv_indev_t *lvgl_port_add_encoder(const lvgl_port_encoder_cfg_t *encoder_cfg)
if (encoder_cfg->encoder_a_b != NULL) {
encoder_ctx->knob_handle = iot_knob_create(encoder_cfg->encoder_a_b);
ESP_GOTO_ON_FALSE(encoder_ctx->knob_handle, ESP_ERR_NO_MEM, err, TAG, "Not enough memory for knob create!");

iot_knob_register_cb
ESP_ERROR_CHECK(iot_knob_register_cb(encoder_ctx->knob_handle, KNOB_LEFT, lvgl_port_encoder_knob_handler, encoder_ctx));
ESP_ERROR_CHECK(iot_knob_register_cb(encoder_ctx->knob_handle, KNOB_RIGHT, lvgl_port_encoder_knob_handler, encoder_ctx));
}

/* Encoder Enter */
Expand Down Expand Up @@ -152,6 +157,9 @@ static void lvgl_port_encoder_btn_down_handler(void *arg, void *arg2)
ctx->btn_enter = true;
}
}

/* Wake LVGL task, if needed */
lvgl_port_task_wake(LVGL_PORT_EVENT_TOUCH);
}

static void lvgl_port_encoder_btn_up_handler(void *arg, void *arg2)
Expand All @@ -164,4 +172,13 @@ static void lvgl_port_encoder_btn_up_handler(void *arg, void *arg2)
ctx->btn_enter = false;
}
}

/* Wake LVGL task, if needed */
lvgl_port_task_wake(LVGL_PORT_EVENT_TOUCH);
}

static void lvgl_port_encoder_knob_handler(void *arg, void *arg2)
{
/* Wake LVGL task, if needed */
lvgl_port_task_wake(LVGL_PORT_EVENT_TOUCH);
}
2 changes: 1 addition & 1 deletion components/esp_lvgl_port/src/lvgl9/esp_lvgl_port_touch.c
Original file line number Diff line number Diff line change
Expand Up @@ -129,5 +129,5 @@ static void lvgl_port_touchpad_read(lv_indev_t *indev_drv, lv_indev_data_t *data
static void lvgl_port_touch_interrupt_callback(esp_lcd_touch_handle_t tp)
{
/* Wake LVGL task, if needed */
lvgl_port_task_wake(LVGL_PORT_EVENT_TOUCH, true);
lvgl_port_task_wake(LVGL_PORT_EVENT_TOUCH);
}
5 changes: 5 additions & 0 deletions components/esp_lvgl_port/src/lvgl9/esp_lvgl_port_usbhid.c
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,8 @@ static void lvgl_port_usb_hid_host_interface_callback(hid_host_device_handle_t h
}
}

/* Wake LVGL task, if needed */
lvgl_port_task_wake(LVGL_PORT_EVENT_TOUCH);
} else if (dev.proto == HID_PROTOCOL_MOUSE) {
hid_mouse_input_report_boot_t *mouse = (hid_mouse_input_report_boot_t *)data;
if (data_length < sizeof(hid_mouse_input_report_boot_t)) {
Expand All @@ -336,6 +338,9 @@ static void lvgl_port_usb_hid_host_interface_callback(hid_host_device_handle_t h
hid_ctx->mouse.left_button = mouse->buttons.button1;
hid_ctx->mouse.x += mouse->x_displacement;
hid_ctx->mouse.y += mouse->y_displacement;

/* Wake LVGL task, if needed */
lvgl_port_task_wake(LVGL_PORT_EVENT_TOUCH);
}
break;
case HID_HOST_INTERFACE_EVENT_TRANSFER_ERROR:
Expand Down
1 change: 1 addition & 0 deletions examples/display/main/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.c
12 changes: 11 additions & 1 deletion examples/display/main/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,12 @@
idf_component_register(SRCS "display_main.c" "esp_logo.c" "esp_text.c" "lvgl_demo_ui.c"
idf_component_register(SRCS "display_main.c" "lvgl_demo_ui.c"
INCLUDE_DIRS ".")

if(COMMAND lvgl_port_create_c_image)
lvgl_port_create_c_image("images/esp_logo.png" "images/" "ARGB8888" "NONE")
lvgl_port_create_c_image("images/esp_text.png" "images/" "ARGB8888" "NONE")
lvgl_port_add_images(${COMPONENT_LIB} "images/")
else()
file(GLOB_RECURSE IMAGE_SOURCES images/*.c)
target_sources(${COMPONENT_LIB} PRIVATE ${IMAGE_SOURCES})
idf_build_set_property(COMPILE_OPTIONS "-DLV_LVGL_H_INCLUDE_SIMPLE=1" APPEND)
endif()
Loading

0 comments on commit 0350c47

Please sign in to comment.