diff --git a/app-esp/idf_component.yml b/app-esp/idf_component.yml index 2ba78651..19fa22d8 100644 --- a/app-esp/idf_component.yml +++ b/app-esp/idf_component.yml @@ -1,6 +1,6 @@ dependencies: espressif/esp_lcd_ili9341: "2.0.0" - espressif/esp_lcd_touch_cst816s: "1.0.3~1" - espressif/esp_lcd_touch_gt911: "1.1.1~1" + espressif/esp_lcd_touch_cst816s: "1.0.3" + espressif/esp_lcd_touch_gt911: "1.1.1" espressif/esp_lcd_touch: "1.1.2" idf: '~5.3.1' diff --git a/libs/esp_lvgl_port/CHANGELOG.md b/libs/esp_lvgl_port/CHANGELOG.md index 6ea7eaf6..fe87ea93 100644 --- a/libs/esp_lvgl_port/CHANGELOG.md +++ b/libs/esp_lvgl_port/CHANGELOG.md @@ -1,70 +1,11 @@ # Changelog -## 2.3.3 - -### Features -- Updated RGB screen flush handling in LVGL9. - -## 2.3.2 - -### Fixes -- Fixed rotation type compatibility with LVGL8. - -## 2.3.1 - -### Fixes -- Fixed LVGL version resolution if LVGL is not a managed component -- Fixed link error with LVGL v9.2 -- Fixed event error with LVGL v9.2 - -## 2.3.0 - -### Fixes -- Fixed LVGL port for using with LVGL9 OS FreeRTOS enabled -- Fixed bad handled touch due to synchronization timer task - -### Features -- Added support for SW rotation in LVGL9 - -## 2.2.2 - -### Fixes -- Fixed missing callback in IDF4.4.3 and lower for LVGL port - -## 2.2.1 - -### Fixes -- Added missing includes -- Fixed watchdog error in some cases in LVGL9 - -## 2.2.0 - -### Features -- Added RGB display support -- Added support for direct mode and full refresh mode - -### Breaking changes -- Removed MIPI-DSI from display configuration structure - use `lvgl_port_add_disp_dsi` instead - -## 2.1.0 - -### Features -- 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 -- 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 +## 1.5.0 ### Features - Divided into files per feature - Added support for LVGL9 -- Added support for MIPI-DSI display ## 1.4.0 diff --git a/libs/esp_lvgl_port/CMakeLists.txt b/libs/esp_lvgl_port/CMakeLists.txt index 8dc53693..2adc417f 100644 --- a/libs/esp_lvgl_port/CMakeLists.txt +++ b/libs/esp_lvgl_port/CMakeLists.txt @@ -1,34 +1,13 @@ -include($ENV{IDF_PATH}/tools/cmake/version.cmake) # $ENV{IDF_VERSION} was added after v4.3... -if("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_LESS "4.4") - return() -endif() - -# This component uses a CMake workaround, so we can compile esp_lvgl_port for both LVGL8.x and LVGL9.x -# At the time of idf_component_register() we don't know which LVGL version is used, so we only register an INTERFACE component (with no sources) -# Later, when we know the LVGL version, we create another CMake library called 'lvgl_port_lib' and link it to the 'esp_lvgl_port' INTERFACE component -idf_component_register( - INCLUDE_DIRS "include" - PRIV_INCLUDE_DIRS "priv_include" - REQUIRES "esp_lcd") - -# Get LVGL version -idf_build_get_property(build_components BUILD_COMPONENTS) -if(lvgl IN_LIST build_components) - set(lvgl_name lvgl) # Local component - set(lvgl_ver $ENV{LVGL_VERSION}) # Get the version from env variable (set from LVGL v9.2) -else() - set(lvgl_name lvgl__lvgl) # Managed component - idf_component_get_property(lvgl_ver ${lvgl_name} COMPONENT_VERSION) # Get the version from esp-idf build system -endif() - -if("${lvgl_ver}" STREQUAL "") - message("Could not determine LVGL version, assuming v9.x") - set(lvgl_ver "9.0.0") -endif() - -# Select folder by LVGL version +#Get LVGL version +#idf_component_get_property(lvgl_ver lvgl__lvgl COMPONENT_VERSION) +#if(lvgl_ver EQUAL "") +# idf_component_get_property(lvgl_ver lvgl COMPONENT_VERSION) +#endif() +set(lvgl_ver "9.0.0") message(STATUS "LVGL version: ${lvgl_ver}") + +#Select folder by LVGL version if(lvgl_ver VERSION_LESS "9.0.0") message(VERBOSE "Compiling esp_lvgl_port for LVGL8") set(PORT_FOLDER "lvgl8") @@ -37,8 +16,10 @@ else() set(PORT_FOLDER "lvgl9") endif() -# Add LVGL port extensions set(PORT_PATH "src/${PORT_FOLDER}") + +idf_component_register(SRCS "${PORT_PATH}/esp_lvgl_port.c" "${PORT_PATH}/esp_lvgl_port_disp.c" INCLUDE_DIRS "include" REQUIRES "esp_lcd" "lvgl" PRIV_REQUIRES "esp_timer") + set(ADD_SRCS "") set(ADD_LIBS "") @@ -76,43 +57,9 @@ if("usb_host_hid" IN_LIST build_components) list(APPEND ADD_LIBS idf::usb_host_hid) endif() -# Include SIMD assembly source code for rendering, only for (9.1.0 <= LVG_version < 9.2.0) and only for esp32 and esp32s3 -if((lvgl_ver VERSION_GREATER_EQUAL "9.1.0") AND (lvgl_ver VERSION_LESS "9.2.0")) - if(CONFIG_IDF_TARGET_ESP32 OR CONFIG_IDF_TARGET_ESP32S3) - message(VERBOSE "Compiling SIMD") - if(CONFIG_IDF_TARGET_ESP32S3) - file(GLOB_RECURSE ASM_SRCS ${PORT_PATH}/simd/*_esp32s3.S) # Select only esp32s3 related files - else() - file(GLOB_RECURSE ASM_SRCS ${PORT_PATH}/simd/*_esp32.S) # Select only esp32 related files - endif() - list(APPEND ADD_SRCS ${ASM_SRCS}) - - # Include component libraries, so lvgl component would see lvgl_port includes - idf_component_get_property(lvgl_lib ${lvgl_name} COMPONENT_LIB) - target_include_directories(${lvgl_lib} PRIVATE "include") - - # Force link .S files - set_property(TARGET ${COMPONENT_LIB} APPEND PROPERTY INTERFACE_LINK_LIBRARIES "-u lv_color_blend_to_argb8888_esp") - set_property(TARGET ${COMPONENT_LIB} APPEND PROPERTY INTERFACE_LINK_LIBRARIES "-u lv_color_blend_to_rgb565_esp") - endif() +if(ADD_SRCS) + target_sources(${COMPONENT_LIB} PRIVATE ${ADD_SRCS}) +endif() +if(ADD_LIBS) + target_link_libraries(${COMPONENT_LIB} PRIVATE ${ADD_LIBS}) endif() - -# Here we create the real lvgl_port_lib -add_library(lvgl_port_lib STATIC - ${PORT_PATH}/esp_lvgl_port.c - ${PORT_PATH}/esp_lvgl_port_disp.c - ${ADD_SRCS} - ) -target_include_directories(lvgl_port_lib PUBLIC "include") -target_include_directories(lvgl_port_lib PRIVATE "priv_include") -target_link_libraries(lvgl_port_lib PUBLIC - idf::esp_lcd - idf::${lvgl_name} - ) -target_link_libraries(lvgl_port_lib PRIVATE - idf::esp_timer - ${ADD_LIBS} - ) - -# Finally, link the lvgl_port_lib its esp-idf interface library -target_link_libraries(${COMPONENT_LIB} INTERFACE lvgl_port_lib) diff --git a/libs/esp_lvgl_port/README.md b/libs/esp_lvgl_port/README.md index c4a2b4ba..d634f990 100644 --- a/libs/esp_lvgl_port/README.md +++ b/libs/esp_lvgl_port/README.md @@ -1,24 +1,21 @@ # LVGL ESP Portation [![Component Registry](https://components.espressif.com/components/espressif/esp_lvgl_port/badge.svg)](https://components.espressif.com/components/espressif/esp_lvgl_port) -![maintenance-status](https://img.shields.io/badge/maintenance-actively--developed-brightgreen.svg) -This component helps with using LVGL with Espressif's LCD and touch drivers. It can be used with any project with LCD display. +This component helps with using LVGL with Espressif's LCD and touch drivers. It can be used with any project with LCD display. ## Features * Initialization of the LVGL * Create task and timer * Handle rotating - * Power saving * Add/remove display (using [`esp_lcd`](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/lcd.html)) * Add/remove touch input (using [`esp_lcd_touch`](https://github.com/espressif/esp-bsp/tree/master/components/lcd_touch)) * Add/remove navigation buttons input (using [`button`](https://github.com/espressif/esp-iot-solution/tree/master/components/button)) * Add/remove encoder input (using [`knob`](https://github.com/espressif/esp-iot-solution/tree/master/components/knob)) -* Add/remove USB HID mouse/keyboard input (using [`usb_host_hid`](https://components.espressif.com/components/espressif/usb_host_hid)) ## LVGL Version -This component supports **LVGL8** and **LVGL9**. By default, it selects the latest LVGL version. If you want to use a specific version (e.g. latest LVGL8), you can easily define this requirement in `idf_component.yml` in your project like this: +This component supports **LVGL8** and **LVGL9**. By default, it selects the latest LVGL version. If you want to use a specific version (e.g. latest LVGL8), you can easily put into `idf_component.yml` in your project like this: ``` lvgl/lvgl: @@ -28,7 +25,7 @@ This component supports **LVGL8** and **LVGL9**. By default, it selects the l ### LVGL Version Compatibility -This component is fully compatible with LVGL version 9. All types and functions are used from LVGL9. Some LVGL9 types are not supported in LVGL8 and there are retyped in [`esp_lvgl_port_compatibility.h`](include/esp_lvgl_port_compatibility.h) header file. **Please, be aware, that some draw and object functions are not compatible between LVGL8 and LVGL9.** +This component is fully compatible with LVGL version 9. All types and functions are used from LVGL9. Some LVGL9 types are not supported in LVGL8 and there are retyping in [`esp_lvgl_port_compatibility.h`](include/esp_lvgl_port_compatibility.h) header file. **Please, be aware, that some draw and object functions are not compatible between LVGL8 and LVGL9.** ## Usage @@ -40,16 +37,16 @@ This component is fully compatible with LVGL version 9. All types and functions ### Add screen -Add an LCD screen to the LVGL. It can be called multiple times for adding multiple LCD screens. +Add an LCD screen to the LVGL. It can be called multiple times for adding multiple LCD screens. ``` c static lv_disp_t * disp_handle; - + /* LCD IO */ esp_lcd_panel_io_handle_t io_handle = NULL; ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t) 1, &io_config, &io_handle)); - /* LCD driver initialization */ + /* LCD driver initialization */ esp_lcd_panel_handle_t lcd_panel_handle; ESP_ERROR_CHECK(esp_lcd_new_panel_st7789(io_handle, &panel_config, &lcd_panel_handle)); @@ -62,8 +59,7 @@ Add an LCD screen to the LVGL. It can be called multiple times for adding multip .hres = DISP_WIDTH, .vres = DISP_HEIGHT, .monochrome = false, - .mipi_dsi = false, - .color_format = LV_COLOR_FORMAT_RGB565, + /* Rotation values must be same as used in esp_lcd for initial settings of the screen */ .rotation = { .swap_xy = false, .mirror_x = false, @@ -75,20 +71,16 @@ Add an LCD screen to the LVGL. It can be called multiple times for adding multip } }; disp_handle = lvgl_port_add_disp(&disp_cfg); - + /* ... the rest of the initialization ... */ /* If deinitializing LVGL port, remember to delete all displays: */ lvgl_port_remove_disp(disp_handle); ``` -> [!NOTE] -> 1. For adding RGB or MIPI-DSI screen, use functions `lvgl_port_add_disp_rgb` or `lvgl_port_add_disp_dsi`. -> 2. DMA buffer can be used only when you use color format `LV_COLOR_FORMAT_RGB565`. - ### Add touch input -Add touch input to the LVGL. It can be called more times for adding more touch inputs. +Add touch input to the LVGL. It can be called more times for adding more touch inputs. ``` c /* Touch driver initialization */ ... @@ -101,7 +93,7 @@ Add touch input to the LVGL. It can be called more times for adding more touch i .handle = tp, }; lv_indev_t* touch_handle = lvgl_port_add_touch(&touch_cfg); - + /* ... the rest of the initialization ... */ /* If deinitializing LVGL port, remember to delete all touches: */ @@ -146,14 +138,14 @@ Add buttons input to the LVGL. It can be called more times for adding more butto /* Add buttons input (for selected screen) */ lv_indev_t* buttons_handle = lvgl_port_add_navigation_buttons(&btns); - + /* ... the rest of the initialization ... */ /* If deinitializing LVGL port, remember to delete all buttons: */ lvgl_port_remove_navigation_buttons(buttons_handle); ``` -> [!NOTE] -> When you use navigation buttons for control LVGL objects, these objects must be added to LVGL groups. See [LVGL documentation](https://docs.lvgl.io/master/overview/indev.html?highlight=lv_indev_get_act#keypad-and-encoder) for more info. + +**Note:** When you use navigation buttons for control LVGL objects, these objects must be added to LVGL groups. See [LVGL documentation](https://docs.lvgl.io/master/overview/indev.html?highlight=lv_indev_get_act#keypad-and-encoder) for more info. ### Add encoder input @@ -181,14 +173,14 @@ Add encoder input to the LVGL. It can be called more times for adding more encod /* Add encoder input (for selected screen) */ lv_indev_t* encoder_handle = lvgl_port_add_encoder(&encoder); - + /* ... the rest of the initialization ... */ /* If deinitializing LVGL port, remember to delete all encoders: */ lvgl_port_remove_encoder(encoder_handle); ``` -> [!NOTE] -> When you use encoder for control LVGL objects, these objects must be added to LVGL groups. See [LVGL documentation](https://docs.lvgl.io/master/overview/indev.html?highlight=lv_indev_get_act#keypad-and-encoder) for more info. + +**Note:** When you use encoder for control LVGL objects, these objects must be added to LVGL groups. See [LVGL documentation](https://docs.lvgl.io/master/overview/indev.html?highlight=lv_indev_get_act#keypad-and-encoder) for more info. ### Add USB HID keyboard and mouse input @@ -225,8 +217,7 @@ Keyboard special behavior (when objects are in group): - **ARROWS** or **HOME** or **END**: Move in text area - **DEL** or **Backspace**: Remove character in textarea -> [!NOTE] -> When you use keyboard for control LVGL objects, these objects must be added to LVGL groups. See [LVGL documentation](https://docs.lvgl.io/master/overview/indev.html?highlight=lv_indev_get_act#keypad-and-encoder) for more info. +**Note:** When you use keyboard for control LVGL objects, these objects must be added to LVGL groups. See [LVGL documentation](https://docs.lvgl.io/master/overview/indev.html?highlight=lv_indev_get_act#keypad-and-encoder) for more info. ### LVGL API usage @@ -263,11 +254,7 @@ Display rotation can be changed at runtime. lv_disp_set_rotation(disp_handle, LV_DISP_ROT_90); ``` -> [!NOTE] -> This feature consume more RAM. - -> [!NOTE] -> During the hardware rotating, the component call [`esp_lcd`](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/lcd.html) API. When using software rotation, you cannot use neither `direct_mode` nor `full_refresh` in the driver. See [LVGL documentation](https://docs.lvgl.io/8.3/porting/display.html?highlight=sw_rotate) for more info. +**Note:** During the hardware rotating, the component call [`esp_lcd`](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/lcd.html) API. When using software rotation, you cannot use neither `direct_mode` nor `full_refresh` in the driver. See [LVGL documentation](https://docs.lvgl.io/8.3/porting/display.html?highlight=sw_rotate) for more info. ### Using PSRAM canvas @@ -285,79 +272,6 @@ 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 - -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 after wake by function: - -``` -lvgl_port_resume(); -``` - ## Performance Key feature of every graphical application is performance. Recommended settings for improving LCD performance is described in a separate document [here](docs/performance.md). - -### Performance monitor - -For show performance monitor in LVGL9, please add these lines to sdkconfig.defaults and rebuild all. - -``` -CONFIG_LV_USE_OBSERVER=y -CONFIG_LV_USE_SYSMON=y -CONFIG_LV_USE_PERF_MONITOR=y -``` diff --git a/libs/esp_lvgl_port/docs/performance.md b/libs/esp_lvgl_port/docs/performance.md index 1a472d7f..98de4fac 100644 --- a/libs/esp_lvgl_port/docs/performance.md +++ b/libs/esp_lvgl_port/docs/performance.md @@ -1,6 +1,6 @@ # LCD & LVGL Performance -This document provides steps, how to set up your LCD and LVGL port for the best performance and comparison of different settings. All settings and measurements are valid for Espressif's chips. Examples in [ESP-BSP](https://github.com/espressif/esp-bsp) are ready to use with the best performance. +This document provides steps, how to set up your LCD and LVGL port for the best performance and comparison of different settings. All settings and measurements are valid for Espressif's chips. ## Performance metrics @@ -26,7 +26,7 @@ On the other hand, the frame buffer(s) will consume significant portion of your Main takeaways from the graph are: -* The size of **LVGL buffer** and **double buffering** feature has big impact on performance. +* The size of **LVGL buffer** and **double buffering** feature has big impact on performance. * Frame buffer size >25% of the screen does not bring relevant performance boost * Frame buffer size <10% will have severe negative effect on performance @@ -67,7 +67,7 @@ The main LVGL task can be processed on the second core of the CPU. It can increa ### Using esp-idf `memcpy` and `memset` instead LVGL's configuration -Native esp-idf implementation are a little (~1-3 FPS) faster (only for LVGL8). +Native esp-idf implementation are a little (~1-3 FPS) faster. * `CONFIG_LV_MEMCPY_MEMSET_STD=y` @@ -75,45 +75,10 @@ Native esp-idf implementation are a little (~1-3 FPS) faster (only for LVGL8). This setting can improve subjective performance during screen transitions (scrolling, etc.). -LVGL8 * `CONFIG_LV_DISP_DEF_REFR_PERIOD=10` -LVGL9 -* `CONFIG_LV_DEF_REFR_PERIOD=10` - ## Example FPS improvement vs graphical settings -The LVGL9 benchmark demo uses a different algorithm for measuring FPS. In this case, we used the same algorithm for measurement in LVGL8 for comparison. - -### RGB LCD, PSRAM (octal) with GDMA - ESP32-S3-LCD-EV-BOARD - - - -Default settings: -* BSP example `display_lvgl_demos` -* LCD: 4.3" 800x480 -* Interface: RGB -* LVGL buffer size: 800 x 480 -* LVGL buffer mode: Direct (avoid-tearing) -* LVGL double buffer: NO -* Optimization: Debug -* CPU frequency: 160 MHz -* Flash frequency: 80 MHz -* PSRAM frequency: 80 MHz -* Flash mode: DIO -* LVGL display refresh period: 30 ms - -| Average FPS (LVGL8) | Average FPS (LVGL 9.2) | Changed settings | -| :---: | :---: | ---------------- | -| 12 | 9 | Default | -| 13 | 9 | + Optimization: Performance (`CONFIG_COMPILER_OPTIMIZATION_PERF=y`) | -| 14 | 11 | + CPU frequency: 240 MHz (`CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y`) | -| 14 | 11 | + Flash mode: QIO (`CONFIG_ESPTOOLPY_FLASHMODE_QIO=y`) | -| 15 | 11 | + LVGL fast memory enabled (`CONFIG_LV_ATTRIBUTE_FAST_MEM_USE_IRAM=y`) | -| 16 | 11 | + (`CONFIG_LV_DISP_DEF_REFR_PERIOD=10` / `CONFIG_LV_DEF_REFR_PERIOD=10`) | - -### Parallel 8080 LCD (only for LVGL8) - Default settings: @@ -129,7 +94,7 @@ Default settings: * Flash mode: DIO * LVGL display refresh period: 30 ms -#### Internal RAM with DMA +### Internal RAM with DMA | Average FPS | Weighted FPS | Changed settings | | :---: | :---: | ---------------- | @@ -140,7 +105,7 @@ Default settings: | 28 | **60** | + LVGL fast memory enabled (`CONFIG_LV_ATTRIBUTE_FAST_MEM_USE_IRAM=y`) | | 41 | 55 | + (`CONFIG_LV_DISP_DEF_REFR_PERIOD=10`) | -#### PSRAM (QUAD) without DMA +### PSRAM (QUAD) without DMA Default changes: * LCD IO clock: 2 MHz @@ -159,10 +124,36 @@ Default changes: [^1]: This is not working in default and sometimes in fast changes on screen is not working properly. +### RGB LCD (without `esp_lvgl_port`), PSRAM (octal) with GDMA - ESP32-S3-LCD-EV-BOARD + + + +Default settings: +* BSP example `display_lvgl_demos` +* LCD: 4.3" 800x480 +* Interface: RGB +* LVGL buffer size: 800 x 100 +* LVGL double buffer: NO +* Optimization: Debug +* CPU frequency: 160 MHz +* Flash frequency: 80 MHz +* PSRAM frequency: 80 MHz +* Flash mode: DIO +* LVGL display refresh period: 30 ms + +| Average FPS | Weighted FPS | Changed settings | +| :---: | :---: | ---------------- | +| 18 | 24 | Default | +| 18 | 26 | + Optimization: Performance (`CONFIG_COMPILER_OPTIMIZATION_PERF=y`) | +| 21 | 32 | + CPU frequency: 240 MHz (`CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y`) | +| 21 | 32 | + Flash mode: QIO (`CONFIG_ESPTOOLPY_FLASHMODE_QIO=y`) | +| 21 | 32 | + LVGL fast memory enabled (`CONFIG_LV_ATTRIBUTE_FAST_MEM_USE_IRAM=y`) | +| 35 | 34 | + (`CONFIG_LV_DISP_DEF_REFR_PERIOD=10`) | + ## Conclusion The graphical performance depends on a lot of things and settings, many of which affect the whole system (Compiler, Flash, CPU, PSRAM configuration...). The user should primarily focus on trade-off between frame-buffer(s) size and RAM consumption of the buffer, before optimizing the design further. Other configuration options not covered in this document are: -* Hardware interfaces, color depth, screen definition (size), clocks, LCD controller and more. +* Hardware interfaces, color depth, screen definition (size), clocks, LCD controller and more. * Complexity of the graphical application (number of LVGL objects and their styles). diff --git a/libs/esp_lvgl_port/examples/touchscreen/CMakeLists.txt b/libs/esp_lvgl_port/examples/touchscreen/CMakeLists.txt new file mode 100644 index 00000000..773ae6d4 --- /dev/null +++ b/libs/esp_lvgl_port/examples/touchscreen/CMakeLists.txt @@ -0,0 +1,9 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +# "Trim" the build. Include the minimal set of components, main and anything it depends on. +set(COMPONENTS main) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(touchscreen) diff --git a/libs/esp_lvgl_port/examples/touchscreen/README.md b/libs/esp_lvgl_port/examples/touchscreen/README.md new file mode 100644 index 00000000..7cba276e --- /dev/null +++ b/libs/esp_lvgl_port/examples/touchscreen/README.md @@ -0,0 +1,19 @@ +# ESP LVGL Touch Screen Example + +Very simple example for demonstration of initialization and usage of the `esp_lvgl_port` component. This example contains four main parts: + +## 1. LCD HW initialization - `app_lcd_init()` + +Standard HW initialization of the LCD using [`esp_lcd`](https://github.com/espressif/esp-idf/tree/master/components/esp_lcd) component. Settings of this example are fully compatible with [ESP-BOX](https://github.com/espressif/esp-bsp/tree/master/esp-box) board. + +## 2. Touch HW initialization - `app_touch_init()` + +Standard HW initialization of the LCD touch using [`esp_lcd_touch`](https://github.com/espressif/esp-bsp/tree/master/components/lcd_touch/esp_lcd_touch) component. Settings of this example are fully compatible with [ESP-BOX](https://github.com/espressif/esp-bsp/tree/master/esp-box) board. + +## 3. LVGL port initialization - `app_lvgl_init()` + +Initialization of the LVGL port. + +## 4. LVGL objects example usage - `app_main_display()` + +Very simple demonstration code of using LVGL objects after LVGL port initialization. diff --git a/libs/esp_lvgl_port/examples/touchscreen/main/CMakeLists.txt b/libs/esp_lvgl_port/examples/touchscreen/main/CMakeLists.txt new file mode 100644 index 00000000..cf2c455c --- /dev/null +++ b/libs/esp_lvgl_port/examples/touchscreen/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "main.c" + INCLUDE_DIRS ".") diff --git a/libs/esp_lvgl_port/examples/touchscreen/main/idf_component.yml b/libs/esp_lvgl_port/examples/touchscreen/main/idf_component.yml new file mode 100644 index 00000000..e37ecbed --- /dev/null +++ b/libs/esp_lvgl_port/examples/touchscreen/main/idf_component.yml @@ -0,0 +1,8 @@ +dependencies: + idf: ">=4.4" + esp_lcd_touch_tt21100: + version: "^1" + override_path: "../../../../lcd_touch/esp_lcd_touch_tt21100/" + esp_lvgl_port: + version: ">=1.2.0" + override_path: "../../../" diff --git a/libs/esp_lvgl_port/examples/touchscreen/main/main.c b/libs/esp_lvgl_port/examples/touchscreen/main/main.c new file mode 100644 index 00000000..f2b3506f --- /dev/null +++ b/libs/esp_lvgl_port/examples/touchscreen/main/main.c @@ -0,0 +1,265 @@ +/* + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp_err.h" +#include "esp_log.h" +#include "esp_check.h" +#include "driver/i2c.h" +#include "driver/gpio.h" +#include "driver/spi_master.h" +#include "esp_lcd_panel_io.h" +#include "esp_lcd_panel_vendor.h" +#include "esp_lcd_panel_ops.h" +#include "esp_lvgl_port.h" + +#include "esp_lcd_touch_tt21100.h" + +/* LCD size */ +#define EXAMPLE_LCD_H_RES (320) +#define EXAMPLE_LCD_V_RES (240) + +/* LCD settings */ +#define EXAMPLE_LCD_SPI_NUM (SPI3_HOST) +#define EXAMPLE_LCD_PIXEL_CLK_HZ (40 * 1000 * 1000) +#define EXAMPLE_LCD_CMD_BITS (8) +#define EXAMPLE_LCD_PARAM_BITS (8) +#define EXAMPLE_LCD_COLOR_SPACE (ESP_LCD_COLOR_SPACE_BGR) +#define EXAMPLE_LCD_BITS_PER_PIXEL (16) +#define EXAMPLE_LCD_DRAW_BUFF_DOUBLE (1) +#define EXAMPLE_LCD_DRAW_BUFF_HEIGHT (50) +#define EXAMPLE_LCD_BL_ON_LEVEL (1) + +/* LCD pins */ +#define EXAMPLE_LCD_GPIO_SCLK (GPIO_NUM_7) +#define EXAMPLE_LCD_GPIO_MOSI (GPIO_NUM_6) +#define EXAMPLE_LCD_GPIO_RST (GPIO_NUM_48) +#define EXAMPLE_LCD_GPIO_DC (GPIO_NUM_4) +#define EXAMPLE_LCD_GPIO_CS (GPIO_NUM_5) +#define EXAMPLE_LCD_GPIO_BL (GPIO_NUM_45) + +/* Touch settings */ +#define EXAMPLE_TOUCH_I2C_NUM (0) +#define EXAMPLE_TOUCH_I2C_CLK_HZ (400000) + +/* LCD touch pins */ +#define EXAMPLE_TOUCH_I2C_SCL (GPIO_NUM_18) +#define EXAMPLE_TOUCH_I2C_SDA (GPIO_NUM_8) +#define EXAMPLE_TOUCH_GPIO_INT (GPIO_NUM_3) + +static const char *TAG = "EXAMPLE"; + +/* LCD IO and panel */ +static esp_lcd_panel_io_handle_t lcd_io = NULL; +static esp_lcd_panel_handle_t lcd_panel = NULL; +static esp_lcd_touch_handle_t touch_handle = NULL; + +/* LVGL display and touch */ +static lv_display_t *lvgl_disp = NULL; +static lv_indev_t *lvgl_touch_indev = NULL; + +static esp_err_t app_lcd_init(void) +{ + esp_err_t ret = ESP_OK; + + /* LCD backlight */ + gpio_config_t bk_gpio_config = { + .mode = GPIO_MODE_OUTPUT, + .pin_bit_mask = 1ULL << EXAMPLE_LCD_GPIO_BL + }; + ESP_ERROR_CHECK(gpio_config(&bk_gpio_config)); + + /* LCD initialization */ + ESP_LOGD(TAG, "Initialize SPI bus"); + const spi_bus_config_t buscfg = { + .sclk_io_num = EXAMPLE_LCD_GPIO_SCLK, + .mosi_io_num = EXAMPLE_LCD_GPIO_MOSI, + .miso_io_num = GPIO_NUM_NC, + .quadwp_io_num = GPIO_NUM_NC, + .quadhd_io_num = GPIO_NUM_NC, + .max_transfer_sz = EXAMPLE_LCD_H_RES * EXAMPLE_LCD_DRAW_BUFF_HEIGHT * sizeof(uint16_t), + }; + ESP_RETURN_ON_ERROR(spi_bus_initialize(EXAMPLE_LCD_SPI_NUM, &buscfg, SPI_DMA_CH_AUTO), TAG, "SPI init failed"); + + ESP_LOGD(TAG, "Install panel IO"); + const esp_lcd_panel_io_spi_config_t io_config = { + .dc_gpio_num = EXAMPLE_LCD_GPIO_DC, + .cs_gpio_num = EXAMPLE_LCD_GPIO_CS, + .pclk_hz = EXAMPLE_LCD_PIXEL_CLK_HZ, + .lcd_cmd_bits = EXAMPLE_LCD_CMD_BITS, + .lcd_param_bits = EXAMPLE_LCD_PARAM_BITS, + .spi_mode = 0, + .trans_queue_depth = 10, + }; + ESP_GOTO_ON_ERROR(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)EXAMPLE_LCD_SPI_NUM, &io_config, &lcd_io), err, TAG, "New panel IO failed"); + + ESP_LOGD(TAG, "Install LCD driver"); + const esp_lcd_panel_dev_config_t panel_config = { + .reset_gpio_num = EXAMPLE_LCD_GPIO_RST, + .color_space = EXAMPLE_LCD_COLOR_SPACE, + .bits_per_pixel = EXAMPLE_LCD_BITS_PER_PIXEL, + }; + ESP_GOTO_ON_ERROR(esp_lcd_new_panel_st7789(lcd_io, &panel_config, &lcd_panel), err, TAG, "New panel failed"); + + esp_lcd_panel_reset(lcd_panel); + esp_lcd_panel_init(lcd_panel); + esp_lcd_panel_mirror(lcd_panel, true, true); + esp_lcd_panel_disp_on_off(lcd_panel, true); + + /* LCD backlight on */ + ESP_ERROR_CHECK(gpio_set_level(EXAMPLE_LCD_GPIO_BL, EXAMPLE_LCD_BL_ON_LEVEL)); + + return ret; + +err: + if (lcd_panel) { + esp_lcd_panel_del(lcd_panel); + } + if (lcd_io) { + esp_lcd_panel_io_del(lcd_io); + } + spi_bus_free(EXAMPLE_LCD_SPI_NUM); + return ret; +} + +static esp_err_t app_touch_init(void) +{ + /* Initilize I2C */ + const i2c_config_t i2c_conf = { + .mode = I2C_MODE_MASTER, + .sda_io_num = EXAMPLE_TOUCH_I2C_SDA, + .sda_pullup_en = GPIO_PULLUP_DISABLE, + .scl_io_num = EXAMPLE_TOUCH_I2C_SCL, + .scl_pullup_en = GPIO_PULLUP_DISABLE, + .master.clk_speed = EXAMPLE_TOUCH_I2C_CLK_HZ + }; + ESP_RETURN_ON_ERROR(i2c_param_config(EXAMPLE_TOUCH_I2C_NUM, &i2c_conf), TAG, "I2C configuration failed"); + ESP_RETURN_ON_ERROR(i2c_driver_install(EXAMPLE_TOUCH_I2C_NUM, i2c_conf.mode, 0, 0, 0), TAG, "I2C initialization failed"); + + /* Initialize touch HW */ + const esp_lcd_touch_config_t tp_cfg = { + .x_max = EXAMPLE_LCD_H_RES, + .y_max = EXAMPLE_LCD_V_RES, + .rst_gpio_num = GPIO_NUM_NC, // Shared with LCD reset + .int_gpio_num = EXAMPLE_TOUCH_GPIO_INT, + .levels = { + .reset = 0, + .interrupt = 0, + }, + .flags = { + .swap_xy = 0, + .mirror_x = 1, + .mirror_y = 0, + }, + }; + esp_lcd_panel_io_handle_t tp_io_handle = NULL; + const esp_lcd_panel_io_i2c_config_t tp_io_config = ESP_LCD_TOUCH_IO_I2C_TT21100_CONFIG(); + ESP_RETURN_ON_ERROR(esp_lcd_new_panel_io_i2c((esp_lcd_i2c_bus_handle_t)EXAMPLE_TOUCH_I2C_NUM, &tp_io_config, &tp_io_handle), TAG, ""); + return esp_lcd_touch_new_i2c_tt21100(tp_io_handle, &tp_cfg, &touch_handle); +} + +static esp_err_t app_lvgl_init(void) +{ + /* Initialize LVGL */ + const lvgl_port_cfg_t lvgl_cfg = { + .task_priority = 4, /* LVGL task priority */ + .task_stack = 4096, /* LVGL task stack size */ + .task_affinity = -1, /* LVGL task pinned to core (-1 is no affinity) */ + .task_max_sleep_ms = 500, /* Maximum sleep in LVGL task */ + .timer_period_ms = 5 /* LVGL timer tick period in ms */ + }; + ESP_RETURN_ON_ERROR(lvgl_port_init(&lvgl_cfg), TAG, "LVGL port initialization failed"); + + /* Add LCD screen */ + ESP_LOGD(TAG, "Add LCD screen"); + const lvgl_port_display_cfg_t disp_cfg = { + .io_handle = lcd_io, + .panel_handle = lcd_panel, + .buffer_size = EXAMPLE_LCD_H_RES * EXAMPLE_LCD_DRAW_BUFF_HEIGHT * sizeof(uint16_t), + .double_buffer = EXAMPLE_LCD_DRAW_BUFF_DOUBLE, + .hres = EXAMPLE_LCD_H_RES, + .vres = EXAMPLE_LCD_V_RES, + .monochrome = false, + /* Rotation values must be same as used in esp_lcd for initial settings of the screen */ + .rotation = { + .swap_xy = false, + .mirror_x = true, + .mirror_y = true, + }, + .flags = { + .buff_dma = true, + .swap_bytes = true, + } + }; + lvgl_disp = lvgl_port_add_disp(&disp_cfg); + + /* Add touch input (for selected screen) */ + const lvgl_port_touch_cfg_t touch_cfg = { + .disp = lvgl_disp, + .handle = touch_handle, + }; + lvgl_touch_indev = lvgl_port_add_touch(&touch_cfg); + + return ESP_OK; +} + +static void _app_button_cb(lv_event_t *e) +{ + lv_disp_rotation_t rotation = lv_disp_get_rotation(lvgl_disp); + rotation++; + if (rotation > LV_DISPLAY_ROTATION_270) { + rotation = LV_DISPLAY_ROTATION_0; + } + + /* LCD HW rotation */ + lv_disp_set_rotation(lvgl_disp, rotation); +} + +static void app_main_display(void) +{ + lv_obj_t *scr = lv_scr_act(); + + /* Task lock */ + lvgl_port_lock(0); + + /* Your LVGL objects code here .... */ + + /* Label */ + lv_obj_t *label = lv_label_create(scr); + lv_obj_set_width(label, EXAMPLE_LCD_H_RES); + lv_obj_set_style_text_align(label, LV_TEXT_ALIGN_CENTER, 0); +#if LVGL_VERSION_MAJOR == 8 + lv_label_set_recolor(label, true); + lv_label_set_text(label, "#FF0000 "LV_SYMBOL_BELL" Hello world Espressif and LVGL "LV_SYMBOL_BELL"#\n#FF9400 "LV_SYMBOL_WARNING" For simplier initialization, use BSP "LV_SYMBOL_WARNING" #"); +#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); + + /* Button */ + lv_obj_t *btn = lv_btn_create(scr); + label = lv_label_create(btn); + lv_label_set_text_static(label, "Rotate screen"); + lv_obj_align(btn, LV_ALIGN_BOTTOM_MID, 0, -30); + lv_obj_add_event_cb(btn, _app_button_cb, LV_EVENT_CLICKED, NULL); + + /* Task unlock */ + lvgl_port_unlock(); +} + +void app_main(void) +{ + /* LCD HW initialization */ + ESP_ERROR_CHECK(app_lcd_init()); + + /* Touch initialization */ + ESP_ERROR_CHECK(app_touch_init()); + + /* LVGL initialization */ + ESP_ERROR_CHECK(app_lvgl_init()); + + /* Show LVGL objects */ + app_main_display(); +} diff --git a/libs/esp_lvgl_port/examples/touchscreen/sdkconfig.defaults b/libs/esp_lvgl_port/examples/touchscreen/sdkconfig.defaults new file mode 100644 index 00000000..f19359fb --- /dev/null +++ b/libs/esp_lvgl_port/examples/touchscreen/sdkconfig.defaults @@ -0,0 +1,4 @@ +CONFIG_IDF_TARGET="esp32s3" +CONFIG_ESPTOOLPY_FLASHMODE_QIO=y +CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y +CONFIG_LV_COLOR_16_SWAP=y diff --git a/libs/esp_lvgl_port/idf_component.yml b/libs/esp_lvgl_port/idf_component.yml index afcf8702..7aa31895 100644 --- a/libs/esp_lvgl_port/idf_component.yml +++ b/libs/esp_lvgl_port/idf_component.yml @@ -1,4 +1,4 @@ -version: "2.3.3" +version: "1.5.0" description: ESP LVGL port url: https://github.com/espressif/esp-bsp/tree/master/components/esp_lvgl_port dependencies: diff --git a/libs/esp_lvgl_port/include/esp_lvgl_port.h b/libs/esp_lvgl_port/include/esp_lvgl_port.h index 398a5c70..a7b2c6a6 100644 --- a/libs/esp_lvgl_port/include/esp_lvgl_port.h +++ b/libs/esp_lvgl_port/include/esp_lvgl_port.h @@ -12,11 +12,11 @@ #pragma once #include "esp_err.h" -#include "lvgl.h" -#include "esp_lvgl_port_disp.h" -#include "esp_lvgl_port_touch.h" -#include "esp_lvgl_port_knob.h" #include "esp_lvgl_port_button.h" +#include "esp_lvgl_port_compatibility.h" +#include "esp_lvgl_port_disp.h" +#include "esp_lvgl_port_knob.h" +#include "esp_lvgl_port_touch.h" #include "esp_lvgl_port_usbhid.h" #if LVGL_VERSION_MAJOR == 8 @@ -27,23 +27,6 @@ extern "C" { #endif -/** - * @brief LVGL Port task event type - */ -typedef enum { - LVGL_PORT_EVENT_DISPLAY = 1, - LVGL_PORT_EVENT_TOUCH = 2, - LVGL_PORT_EVENT_USER = 99, -} lvgl_port_event_type_t; - -/** - * @brief LVGL Port task events - */ -typedef struct { - lvgl_port_event_type_t type; - void *param; -} lvgl_port_event_t; - /** * @brief Init configuration structure */ @@ -89,7 +72,6 @@ esp_err_t lvgl_port_init(const lvgl_port_cfg_t *cfg); * * @return * - ESP_OK on success - * - ESP_ERR_TIMEOUT when stopping the LVGL task times out */ esp_err_t lvgl_port_deinit(void); @@ -119,7 +101,7 @@ void lvgl_port_unlock(void); void lvgl_port_flush_ready(lv_display_t *disp); /** - * @brief Stop lvgl timer + * @brief Stop lvgl task * * * @return @@ -129,7 +111,7 @@ void lvgl_port_flush_ready(lv_display_t *disp); esp_err_t lvgl_port_stop(void); /** - * @brief Resume lvgl timer + * @brief Resume lvgl task * * * @return @@ -138,20 +120,6 @@ esp_err_t lvgl_port_stop(void); */ esp_err_t lvgl_port_resume(void); -/** - * @brief Notify LVGL task, that display need reload - * - * @note It is called from LVGL events and touch interrupts - * - * @param event event type - * @param param user param - * @return - * - ESP_OK on success - * - 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_type_t event, void *param); - #ifdef __cplusplus } #endif diff --git a/libs/esp_lvgl_port/include/esp_lvgl_port_compatibility.h b/libs/esp_lvgl_port/include/esp_lvgl_port_compatibility.h index 008a09ec..40584284 100644 --- a/libs/esp_lvgl_port/include/esp_lvgl_port_compatibility.h +++ b/libs/esp_lvgl_port/include/esp_lvgl_port_compatibility.h @@ -19,13 +19,6 @@ extern "C" { * @brief Backward compatibility with LVGL 8 */ typedef lv_disp_t lv_display_t; -typedef enum { - LV_DISPLAY_ROTATION_0 = LV_DISP_ROT_NONE, - LV_DISPLAY_ROTATION_90 = LV_DISP_ROT_90, - LV_DISPLAY_ROTATION_180 = LV_DISP_ROT_180, - LV_DISPLAY_ROTATION_270 = LV_DISP_ROT_270 -} lv_disp_rotation_t; -typedef lv_disp_rotation_t lv_display_rotation_t; #ifdef __cplusplus } diff --git a/libs/esp_lvgl_port/include/esp_lvgl_port_disp.h b/libs/esp_lvgl_port/include/esp_lvgl_port_disp.h index 5efbbab2..c077f83f 100644 --- a/libs/esp_lvgl_port/include/esp_lvgl_port_disp.h +++ b/libs/esp_lvgl_port/include/esp_lvgl_port_disp.h @@ -39,52 +39,24 @@ typedef struct { typedef struct { esp_lcd_panel_io_handle_t io_handle; /*!< LCD panel IO handle */ esp_lcd_panel_handle_t panel_handle; /*!< LCD panel handle */ - esp_lcd_panel_handle_t control_handle; /*!< LCD panel control handle */ - - uint32_t buffer_size; /*!< Size of the buffer for the screen in pixels */ - bool double_buffer; /*!< True, if should be allocated two buffers */ - uint32_t trans_size; /*!< Allocated buffer will be in SRAM to move framebuf (optional) */ - + uint32_t buffer_size; /*!< Size of the buffer for the screen in pixels */ + bool double_buffer; /*!< True, if should be allocated two buffers */ + uint32_t trans_size; /*!< Allocated buffer will be in SRAM to move framebuf */ uint32_t hres; /*!< LCD display horizontal resolution */ uint32_t vres; /*!< LCD display vertical resolution */ - bool monochrome; /*!< True, if display is monochrome and using 1bit for 1px */ + lvgl_port_rotation_cfg_t rotation; /*!< Default values of the screen rotation */ - lvgl_port_rotation_cfg_t rotation; /*!< Default values of the screen rotation */ -#if LVGL_VERSION_MAJOR >= 9 - lv_color_format_t color_format; /*!< The color format of the display */ -#endif struct { unsigned int buff_dma: 1; /*!< Allocated LVGL buffer will be DMA capable */ unsigned int buff_spiram: 1; /*!< Allocated LVGL buffer will be in PSRAM */ - unsigned int sw_rotate: 1; /*!< Use software rotation (slower) or PPA if available */ -#if LVGL_VERSION_MAJOR >= 9 - unsigned int swap_bytes: 1; /*!< Swap bytes in RGB656 (16-bit) color format before send to LCD driver */ -#endif - unsigned int full_refresh: 1;/*!< 1: Always make the whole screen redrawn */ - unsigned int direct_mode: 1; /*!< 1: Use screen-sized buffers and draw to absolute coordinates */ + unsigned int sw_rotate: 1; /*!< Use software rotation (slower) */ + unsigned int swap_bytes: 1; /*!< Swap bytes in RGB656 (16-bit) before send to LCD driver */ } flags; } lvgl_port_display_cfg_t; /** - * @brief Configuration RGB display structure - */ -typedef struct { - struct { - unsigned int bb_mode: 1; /*!< 1: Use bounce buffer mode */ - unsigned int avoid_tearing: 1; /*!< 1: Use internal RGB buffers as a LVGL draw buffers to avoid tearing effect */ - } flags; -} lvgl_port_display_rgb_cfg_t; - -/** - * @brief Configuration MIPI-DSI display structure - */ -typedef struct { - int dummy; -} lvgl_port_display_dsi_cfg_t; - -/** - * @brief Add I2C/SPI/I8080 display handling to LVGL + * @brief Add display handling to LVGL * * @note Allocated memory in this function is not free in deinit. You must call lvgl_port_remove_disp for free all memory! * @@ -93,28 +65,6 @@ typedef struct { */ lv_display_t *lvgl_port_add_disp(const lvgl_port_display_cfg_t *disp_cfg); -/** - * @brief Add MIPI-DSI display handling to LVGL - * - * @note Allocated memory in this function is not free in deinit. You must call lvgl_port_remove_disp for free all memory! - * - * @param disp_cfg Display configuration structure - * @param dsi_cfg MIPI-DSI display specific configuration structure - * @return Pointer to LVGL display or NULL when error occurred - */ -lv_display_t *lvgl_port_add_disp_dsi(const lvgl_port_display_cfg_t *disp_cfg, const lvgl_port_display_dsi_cfg_t *dsi_cfg); - -/** - * @brief Add RGB display handling to LVGL - * - * @note Allocated memory in this function is not free in deinit. You must call lvgl_port_remove_disp for free all memory! - * - * @param disp_cfg Display configuration structure - * @param rgb_cfg RGB display specific configuration structure - * @return Pointer to LVGL display or NULL when error occurred - */ -lv_display_t *lvgl_port_add_disp_rgb(const lvgl_port_display_cfg_t *disp_cfg, const lvgl_port_display_rgb_cfg_t *rgb_cfg); - /** * @brief Remove display handling from LVGL * diff --git a/libs/esp_lvgl_port/include/esp_lvgl_port_knob.h b/libs/esp_lvgl_port/include/esp_lvgl_port_knob.h index 47b667fb..7f37d6e1 100644 --- a/libs/esp_lvgl_port/include/esp_lvgl_port_knob.h +++ b/libs/esp_lvgl_port/include/esp_lvgl_port_knob.h @@ -15,9 +15,6 @@ #include "lvgl.h" #if __has_include ("iot_knob.h") -#if !__has_include("iot_button.h") -#error LVLG Knob requires button component. Please add it with idf.py add-dependency espressif/button -#endif #include "iot_knob.h" #include "iot_button.h" #define ESP_LVGL_PORT_KNOB_COMPONENT 1 diff --git a/libs/esp_lvgl_port/include/esp_lvgl_port_lv_blend.h b/libs/esp_lvgl_port/include/esp_lvgl_port_lv_blend.h deleted file mode 100644 index c00de1c0..00000000 --- a/libs/esp_lvgl_port/include/esp_lvgl_port_lv_blend.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -/********************* - * INCLUDES - *********************/ - -#if !CONFIG_LV_DRAW_SW_ASM_CUSTOM -#warning "esp_lvgl_port_lv_blend.h included, but CONFIG_LV_DRAW_SW_ASM_CUSTOM not set. Assembly rendering not used" -#else - -/********************* - * DEFINES - *********************/ - -#ifndef LV_DRAW_SW_COLOR_BLEND_TO_ARGB8888 -#define LV_DRAW_SW_COLOR_BLEND_TO_ARGB8888(dsc) \ - _lv_color_blend_to_argb8888_esp(dsc) -#endif - -#ifndef LV_DRAW_SW_COLOR_BLEND_TO_RGB565 -#define LV_DRAW_SW_COLOR_BLEND_TO_RGB565(dsc) \ - _lv_color_blend_to_rgb565_esp(dsc) -#endif - - -/********************** - * TYPEDEFS - **********************/ - -typedef struct { - uint32_t opa; - void *dst_buf; - uint32_t dst_w; - uint32_t dst_h; - uint32_t dst_stride; - const void *src_buf; - uint32_t src_stride; - const lv_opa_t *mask_buf; - uint32_t mask_stride; -} asm_dsc_t; - -/********************** - * GLOBAL PROTOTYPES - **********************/ - -extern int lv_color_blend_to_argb8888_esp(asm_dsc_t *asm_dsc); - -static inline lv_result_t _lv_color_blend_to_argb8888_esp(_lv_draw_sw_blend_fill_dsc_t *dsc) -{ - asm_dsc_t asm_dsc = { - .dst_buf = dsc->dest_buf, - .dst_w = dsc->dest_w, - .dst_h = dsc->dest_h, - .dst_stride = dsc->dest_stride, - .src_buf = &dsc->color, - }; - - return lv_color_blend_to_argb8888_esp(&asm_dsc); -} - -extern int lv_color_blend_to_rgb565_esp(asm_dsc_t *asm_dsc); - -static inline lv_result_t _lv_color_blend_to_rgb565_esp(_lv_draw_sw_blend_fill_dsc_t *dsc) -{ - asm_dsc_t asm_dsc = { - .dst_buf = dsc->dest_buf, - .dst_w = dsc->dest_w, - .dst_h = dsc->dest_h, - .dst_stride = dsc->dest_stride, - .src_buf = &dsc->color, - }; - - return lv_color_blend_to_rgb565_esp(&asm_dsc); -} - -#endif // CONFIG_LV_DRAW_SW_ASM_CUSTOM - -#ifdef __cplusplus -} /*extern "C"*/ -#endif diff --git a/libs/esp_lvgl_port/priv_include/esp_lvgl_port_priv.h b/libs/esp_lvgl_port/priv_include/esp_lvgl_port_priv.h deleted file mode 100644 index 16bdca3b..00000000 --- a/libs/esp_lvgl_port/priv_include/esp_lvgl_port_priv.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief ESP LVGL port private - */ - -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @brief Rotation configuration - */ -typedef enum { - LVGL_PORT_DISP_TYPE_OTHER, - LVGL_PORT_DISP_TYPE_DSI, - LVGL_PORT_DISP_TYPE_RGB, -} lvgl_port_disp_type_t; - -/** - * @brief Rotation configuration - */ -typedef struct { - unsigned int avoid_tearing: 1; /*!< Use internal RGB buffers as a LVGL draw buffers to avoid tearing effect */ -} lvgl_port_disp_priv_cfg_t; - -/** - * @brief Notify LVGL task - * - * @note It is called from RGB vsync ready - * - * @param value notification value - * @return - * - true, whether a high priority task has been waken up by this function - */ -bool lvgl_port_task_notify(uint32_t value); - -#ifdef __cplusplus -} -#endif diff --git a/libs/esp_lvgl_port/project_include.cmake b/libs/esp_lvgl_port/project_include.cmake deleted file mode 100644 index 02ce6e38..00000000 --- a/libs/esp_lvgl_port/project_include.cmake +++ /dev/null @@ -1,78 +0,0 @@ -# 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 Python - idf_build_get_property(python PYTHON) - - #Get LVGL version - idf_build_get_property(build_components BUILD_COMPONENTS) - if(lvgl IN_LIST build_components) - set(lvgl_name lvgl) # Local component - set(lvgl_ver $ENV{LVGL_VERSION}) # Get the version from env variable (set from LVGL v9.2) - else() - set(lvgl_name lvgl__lvgl) # Managed component - idf_component_get_property(lvgl_ver ${lvgl_name} COMPONENT_VERSION) # Get the version from esp-idf build system - endif() - - if("${lvgl_ver}" STREQUAL "") - message("Could not determine LVGL version, assuming v9.x") - set(lvgl_ver "9.0.0") - 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(CONFIG_LV_COLOR_16_SWAP) - 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 --upgrade pip) - execute_process(COMMAND ${python} -m pip install pillow==10.3.0) - #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 pip install pypng lz4 OUTPUT_QUIET) - - 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() diff --git a/libs/esp_lvgl_port/src/lvgl8/esp_lvgl_port.c b/libs/esp_lvgl_port/src/lvgl8/esp_lvgl_port.c index 3bdc4506..423f0e20 100644 --- a/libs/esp_lvgl_port/src/lvgl8/esp_lvgl_port.c +++ b/libs/esp_lvgl_port/src/lvgl8/esp_lvgl_port.c @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include "esp_system.h" #include "esp_log.h" #include "esp_err.h" @@ -14,21 +13,16 @@ #include "freertos/task.h" #include "freertos/semphr.h" #include "esp_lvgl_port.h" -#include "esp_lvgl_port_priv.h" #include "lvgl.h" static const char *TAG = "LVGL"; -#define ESP_LVGL_PORT_TASK_MUX_DELAY_MS 10000 - /******************************************************************************* * Types definitions *******************************************************************************/ typedef struct lvgl_port_ctx_s { - TaskHandle_t lvgl_task; SemaphoreHandle_t lvgl_mux; - SemaphoreHandle_t task_mux; esp_timer_handle_t tick_timer; bool running; int task_max_sleep_ms; @@ -69,18 +63,14 @@ esp_err_t lvgl_port_init(const lvgl_port_cfg_t *cfg) if (lvgl_port_ctx.task_max_sleep_ms == 0) { lvgl_port_ctx.task_max_sleep_ms = 500; } - /* LVGL semaphore */ lvgl_port_ctx.lvgl_mux = xSemaphoreCreateRecursiveMutex(); ESP_GOTO_ON_FALSE(lvgl_port_ctx.lvgl_mux, ESP_ERR_NO_MEM, err, TAG, "Create LVGL mutex fail!"); - /* Task semaphore */ - lvgl_port_ctx.task_mux = xSemaphoreCreateMutex(); - ESP_GOTO_ON_FALSE(lvgl_port_ctx.task_mux, ESP_ERR_NO_MEM, err, TAG, "Create LVGL task sem fail!"); BaseType_t res; if (cfg->task_affinity < 0) { - res = xTaskCreate(lvgl_port_task, "taskLVGL", cfg->task_stack, NULL, cfg->task_priority, &lvgl_port_ctx.lvgl_task); + res = xTaskCreate(lvgl_port_task, "LVGL task", cfg->task_stack, NULL, cfg->task_priority, NULL); } else { - res = xTaskCreatePinnedToCore(lvgl_port_task, "taskLVGL", cfg->task_stack, NULL, cfg->task_priority, &lvgl_port_ctx.lvgl_task, cfg->task_affinity); + res = xTaskCreatePinnedToCore(lvgl_port_task, "LVGL task", cfg->task_stack, NULL, cfg->task_priority, NULL, cfg->task_affinity); } ESP_GOTO_ON_FALSE(res == pdPASS, ESP_FAIL, err, TAG, "Create LVGL task fail!"); @@ -128,17 +118,10 @@ esp_err_t lvgl_port_deinit(void) /* Stop running task */ if (lvgl_port_ctx.running) { lvgl_port_ctx.running = false; + } else { + lvgl_port_task_deinit(); } - /* Wait for stop task */ - if (xSemaphoreTake(lvgl_port_ctx.task_mux, pdMS_TO_TICKS(ESP_LVGL_PORT_TASK_MUX_DELAY_MS)) != pdTRUE) { - ESP_LOGE(TAG, "Failed to stop LVGL task"); - return ESP_ERR_TIMEOUT; - } - ESP_LOGI(TAG, "Stopped LVGL task"); - - lvgl_port_task_deinit(); - return ESP_OK; } @@ -156,26 +139,6 @@ void lvgl_port_unlock(void) xSemaphoreGiveRecursive(lvgl_port_ctx.lvgl_mux); } -esp_err_t lvgl_port_task_wake(lvgl_port_event_type_t event, void *param) -{ - ESP_LOGE(TAG, "Task wake is not supported, when used LVGL8!"); - return ESP_ERR_NOT_SUPPORTED; -} - -IRAM_ATTR bool lvgl_port_task_notify(uint32_t value) -{ - BaseType_t need_yield = pdFALSE; - - // Notify LVGL task - if (xPortInIsrContext() == pdTRUE) { - xTaskNotifyFromISR(lvgl_port_ctx.lvgl_task, value, eNoAction, &need_yield); - } else { - xTaskNotify(lvgl_port_ctx.lvgl_task, value, eNoAction); - } - - return (need_yield == pdTRUE); -} - /******************************************************************************* * Private functions *******************************************************************************/ @@ -184,13 +147,6 @@ static void lvgl_port_task(void *arg) { uint32_t task_delay_ms = lvgl_port_ctx.task_max_sleep_ms; - /* Take the task semaphore */ - if (xSemaphoreTake(lvgl_port_ctx.task_mux, 0) != pdTRUE) { - ESP_LOGE(TAG, "Failed to take LVGL task sem"); - lvgl_port_task_deinit(); - vTaskDelete( NULL ); - } - ESP_LOGI(TAG, "Starting LVGL task"); lvgl_port_ctx.running = true; while (lvgl_port_ctx.running) { @@ -206,8 +162,7 @@ static void lvgl_port_task(void *arg) vTaskDelay(pdMS_TO_TICKS(task_delay_ms)); } - /* Give semaphore back */ - xSemaphoreGive(lvgl_port_ctx.task_mux); + lvgl_port_task_deinit(); /* Close task */ vTaskDelete( NULL ); @@ -218,9 +173,6 @@ static void lvgl_port_task_deinit(void) if (lvgl_port_ctx.lvgl_mux) { vSemaphoreDelete(lvgl_port_ctx.lvgl_mux); } - if (lvgl_port_ctx.task_mux) { - vSemaphoreDelete(lvgl_port_ctx.task_mux); - } memset(&lvgl_port_ctx, 0, sizeof(lvgl_port_ctx)); #if LV_ENABLE_GC || !LV_MEM_CUSTOM /* Deinitialize LVGL */ diff --git a/libs/esp_lvgl_port/src/lvgl8/esp_lvgl_port_disp.c b/libs/esp_lvgl_port/src/lvgl8/esp_lvgl_port_disp.c index 46db46a9..45bae0a9 100644 --- a/libs/esp_lvgl_port/src/lvgl8/esp_lvgl_port_disp.c +++ b/libs/esp_lvgl_port/src/lvgl8/esp_lvgl_port_disp.c @@ -4,27 +4,13 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include "esp_log.h" #include "esp_err.h" #include "esp_check.h" #include "esp_heap_caps.h" -#include "esp_idf_version.h" #include "esp_lcd_panel_io.h" #include "esp_lcd_panel_ops.h" #include "esp_lvgl_port.h" -#include "esp_lvgl_port_priv.h" -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "freertos/semphr.h" - -#if CONFIG_IDF_TARGET_ESP32S3 && ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) -#include "esp_lcd_panel_rgb.h" -#endif - -#if (CONFIG_IDF_TARGET_ESP32P4 && ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0)) -#include "esp_lcd_mipi_dsi.h" -#endif #if (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 4, 4)) || (ESP_IDF_VERSION == ESP_IDF_VERSION_VAL(5, 0, 0)) #define LVGL_PORT_HANDLE_FLUSH_READY 0 @@ -39,10 +25,8 @@ static const char *TAG = "LVGL"; *******************************************************************************/ typedef struct { - lvgl_port_disp_type_t disp_type; /* Display type */ esp_lcd_panel_io_handle_t io_handle; /* LCD panel IO handle */ esp_lcd_panel_handle_t panel_handle; /* LCD panel handle */ - esp_lcd_panel_handle_t control_handle; /* LCD panel control handle */ lvgl_port_rotation_cfg_t rotation; /* Default values of the screen rotation */ lv_disp_drv_t disp_drv; /* LVGL display driver */ lv_color_t *trans_buf; /* Buffer send to driver */ @@ -53,16 +37,9 @@ typedef struct { /******************************************************************************* * Function definitions *******************************************************************************/ -static lv_disp_t *lvgl_port_add_disp_priv(const lvgl_port_display_cfg_t *disp_cfg, const lvgl_port_disp_priv_cfg_t *priv_cfg); -static lvgl_port_display_ctx_t *lvgl_port_get_display_ctx(lv_disp_t *disp); + #if LVGL_PORT_HANDLE_FLUSH_READY -static bool lvgl_port_flush_io_ready_callback(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *edata, void *user_ctx); -#if CONFIG_IDF_TARGET_ESP32S3 && ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) -static bool lvgl_port_flush_vsync_ready_callback(esp_lcd_panel_handle_t panel_io, const esp_lcd_rgb_panel_event_data_t *edata, void *user_ctx); -#endif -#if (CONFIG_IDF_TARGET_ESP32P4 && ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0)) -static bool lvgl_port_flush_panel_ready_callback(esp_lcd_panel_handle_t panel_io, esp_lcd_dpi_panel_event_data_t *edata, void *user_ctx); -#endif +static bool lvgl_port_flush_ready_callback(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *edata, void *user_ctx); #endif static void lvgl_port_flush_callback(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_map); static void lvgl_port_update_callback(lv_disp_drv_t *drv); @@ -74,83 +51,111 @@ static void lvgl_port_pix_monochrome_callback(lv_disp_drv_t *drv, uint8_t *buf, lv_disp_t *lvgl_port_add_disp(const lvgl_port_display_cfg_t *disp_cfg) { - lv_disp_t *disp = lvgl_port_add_disp_priv(disp_cfg, NULL); + esp_err_t ret = ESP_OK; + lv_disp_t *disp = NULL; + lv_color_t *buf1 = NULL; + lv_color_t *buf2 = NULL; + lv_color_t *buf3 = NULL; + SemaphoreHandle_t trans_sem = NULL; + assert(disp_cfg != NULL); + assert(disp_cfg->io_handle != NULL); + assert(disp_cfg->panel_handle != NULL); + assert(disp_cfg->buffer_size > 0); + assert(disp_cfg->hres > 0); + assert(disp_cfg->vres > 0); - if (disp != NULL) { - lvgl_port_display_ctx_t *disp_ctx = lvgl_port_get_display_ctx(disp); - /* Set display type */ - disp_ctx->disp_type = LVGL_PORT_DISP_TYPE_OTHER; + /* Display context */ + lvgl_port_display_ctx_t *disp_ctx = malloc(sizeof(lvgl_port_display_ctx_t)); + ESP_GOTO_ON_FALSE(disp_ctx, ESP_ERR_NO_MEM, err, TAG, "Not enough memory for display context allocation!"); + disp_ctx->io_handle = disp_cfg->io_handle; + disp_ctx->panel_handle = disp_cfg->panel_handle; + disp_ctx->rotation.swap_xy = disp_cfg->rotation.swap_xy; + disp_ctx->rotation.mirror_x = disp_cfg->rotation.mirror_x; + disp_ctx->rotation.mirror_y = disp_cfg->rotation.mirror_y; + disp_ctx->trans_size = disp_cfg->trans_size; - assert(disp_ctx->io_handle != NULL); + uint32_t buff_caps = MALLOC_CAP_DEFAULT; + if (disp_cfg->flags.buff_dma && disp_cfg->flags.buff_spiram && (0 == disp_cfg->trans_size)) { + ESP_GOTO_ON_FALSE(false, ESP_ERR_NOT_SUPPORTED, err, TAG, "Alloc DMA capable buffer in SPIRAM is not supported!"); + } else if (disp_cfg->flags.buff_dma) { + buff_caps = MALLOC_CAP_DMA; + } else if (disp_cfg->flags.buff_spiram) { + buff_caps = MALLOC_CAP_SPIRAM; + } + + if (disp_cfg->trans_size) { + buf3 = heap_caps_malloc(disp_cfg->trans_size * sizeof(lv_color_t), MALLOC_CAP_DMA); + ESP_GOTO_ON_FALSE(buf3, ESP_ERR_NO_MEM, err, TAG, "Not enough memory for buffer(transport) allocation!"); + disp_ctx->trans_buf = buf3; + + trans_sem = xSemaphoreCreateCounting(1, 0); + ESP_GOTO_ON_FALSE(trans_sem, ESP_ERR_NO_MEM, err, TAG, "Failed to create transport counting Semaphore"); + disp_ctx->trans_sem = trans_sem; + } + + /* 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 */ + buf1 = heap_caps_malloc(disp_cfg->buffer_size * sizeof(lv_color_t), buff_caps); + ESP_GOTO_ON_FALSE(buf1, ESP_ERR_NO_MEM, err, TAG, "Not enough memory for LVGL buffer (buf1) allocation!"); + if (disp_cfg->double_buffer) { + buf2 = heap_caps_malloc(disp_cfg->buffer_size * sizeof(lv_color_t), buff_caps); + ESP_GOTO_ON_FALSE(buf2, ESP_ERR_NO_MEM, err, TAG, "Not enough memory for LVGL buffer (buf2) allocation!"); + } + lv_disp_draw_buf_t *disp_buf = malloc(sizeof(lv_disp_draw_buf_t)); + ESP_GOTO_ON_FALSE(disp_buf, ESP_ERR_NO_MEM, err, TAG, "Not enough memory for LVGL display buffer allocation!"); + + /* initialize LVGL draw buffers */ + lv_disp_draw_buf_init(disp_buf, buf1, buf2, disp_cfg->buffer_size); + + ESP_LOGD(TAG, "Register display driver to LVGL"); + lv_disp_drv_init(&disp_ctx->disp_drv); + disp_ctx->disp_drv.hor_res = disp_cfg->hres; + disp_ctx->disp_drv.ver_res = disp_cfg->vres; + disp_ctx->disp_drv.flush_cb = lvgl_port_flush_callback; + disp_ctx->disp_drv.draw_buf = disp_buf; + disp_ctx->disp_drv.user_data = disp_ctx; + + disp_ctx->disp_drv.sw_rotate = disp_cfg->flags.sw_rotate; + if (disp_ctx->disp_drv.sw_rotate == false) { + disp_ctx->disp_drv.drv_update_cb = lvgl_port_update_callback; + } #if LVGL_PORT_HANDLE_FLUSH_READY - const esp_lcd_panel_io_callbacks_t cbs = { - .on_color_trans_done = lvgl_port_flush_io_ready_callback, - }; - /* Register done callback */ - esp_lcd_panel_io_register_event_callbacks(disp_ctx->io_handle, &cbs, &disp_ctx->disp_drv); -#endif - } - - return disp; -} - -lv_display_t *lvgl_port_add_disp_dsi(const lvgl_port_display_cfg_t *disp_cfg, const lvgl_port_display_dsi_cfg_t *dsi_cfg) -{ - lv_disp_t *disp = lvgl_port_add_disp_priv(disp_cfg, NULL); - - if (disp != NULL) { - lvgl_port_display_ctx_t *disp_ctx = lvgl_port_get_display_ctx(disp); - /* Set display type */ - disp_ctx->disp_type = LVGL_PORT_DISP_TYPE_DSI; - -#if (CONFIG_IDF_TARGET_ESP32P4 && ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0)) - const esp_lcd_dpi_panel_event_callbacks_t cbs = { - .on_color_trans_done = lvgl_port_flush_panel_ready_callback, - }; - /* Register done callback */ - esp_lcd_dpi_panel_register_event_callbacks(disp_ctx->panel_handle, &cbs, &disp_ctx->disp_drv); -#else - ESP_RETURN_ON_FALSE(false, NULL, TAG, "MIPI-DSI is supported only on ESP32P4 and from IDF 5.3!"); -#endif - } - - return disp; -} - -lv_display_t *lvgl_port_add_disp_rgb(const lvgl_port_display_cfg_t *disp_cfg, const lvgl_port_display_rgb_cfg_t *rgb_cfg) -{ - assert(rgb_cfg != NULL); - const lvgl_port_disp_priv_cfg_t priv_cfg = { - .avoid_tearing = rgb_cfg->flags.avoid_tearing, + /* Register done callback */ + const esp_lcd_panel_io_callbacks_t cbs = { + .on_color_trans_done = lvgl_port_flush_ready_callback, }; - lv_disp_t *disp = lvgl_port_add_disp_priv(disp_cfg, &priv_cfg); - - if (disp != NULL) { - lvgl_port_display_ctx_t *disp_ctx = lvgl_port_get_display_ctx(disp); - /* Set display type */ - disp_ctx->disp_type = LVGL_PORT_DISP_TYPE_RGB; - -#if (CONFIG_IDF_TARGET_ESP32S3 && ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)) - /* Register done callback */ - const esp_lcd_rgb_panel_event_callbacks_t vsync_cbs = { - .on_vsync = lvgl_port_flush_vsync_ready_callback, - }; - - const esp_lcd_rgb_panel_event_callbacks_t bb_cbs = { -#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 1, 2) - .on_bounce_frame_finish = lvgl_port_flush_vsync_ready_callback, + esp_lcd_panel_io_register_event_callbacks(disp_ctx->io_handle, &cbs, &disp_ctx->disp_drv); #endif - }; - if (rgb_cfg->flags.bb_mode && (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 1, 2))) { - ESP_ERROR_CHECK(esp_lcd_rgb_panel_register_event_callbacks(disp_ctx->panel_handle, &bb_cbs, &disp_ctx->disp_drv)); - } else { - ESP_ERROR_CHECK(esp_lcd_rgb_panel_register_event_callbacks(disp_ctx->panel_handle, &vsync_cbs, &disp_ctx->disp_drv)); + /* Monochrome display settings */ + if (disp_cfg->monochrome) { + /* When using monochromatic display, there must be used full bufer! */ + ESP_GOTO_ON_FALSE((disp_cfg->hres * disp_cfg->vres == disp_cfg->buffer_size), ESP_ERR_INVALID_ARG, err, TAG, "Monochromatic display must using full buffer!"); + + disp_ctx->disp_drv.full_refresh = 1; + disp_ctx->disp_drv.set_px_cb = lvgl_port_pix_monochrome_callback; + } + + disp = lv_disp_drv_register(&disp_ctx->disp_drv); + +err: + if (ret != ESP_OK) { + if (buf1) { + free(buf1); + } + if (buf2) { + free(buf2); + } + if (buf3) { + free(buf3); + } + if (trans_sem) { + vSemaphoreDelete(trans_sem); + } + if (disp_ctx) { + free(disp_ctx); } -#else - ESP_RETURN_ON_FALSE(false, NULL, TAG, "RGB is supported only on ESP32S3 and from IDF 5.0!"); -#endif } return disp; @@ -196,147 +201,8 @@ void lvgl_port_flush_ready(lv_disp_t *disp) * Private functions *******************************************************************************/ -static lvgl_port_display_ctx_t *lvgl_port_get_display_ctx(lv_disp_t *disp) -{ - assert(disp); - lv_disp_drv_t *disp_drv = disp->driver; - assert(disp_drv); - lvgl_port_display_ctx_t *disp_ctx = (lvgl_port_display_ctx_t *)disp_drv->user_data; - return disp_ctx; -} - -static lv_disp_t *lvgl_port_add_disp_priv(const lvgl_port_display_cfg_t *disp_cfg, const lvgl_port_disp_priv_cfg_t *priv_cfg) -{ - esp_err_t ret = ESP_OK; - lv_disp_t *disp = NULL; - lv_color_t *buf1 = NULL; - lv_color_t *buf2 = NULL; - lv_color_t *buf3 = NULL; - uint32_t buffer_size = 0; - SemaphoreHandle_t trans_sem = NULL; - assert(disp_cfg != NULL); - assert(disp_cfg->panel_handle != NULL); - assert(disp_cfg->buffer_size > 0); - assert(disp_cfg->hres > 0); - assert(disp_cfg->vres > 0); - - /* Display context */ - lvgl_port_display_ctx_t *disp_ctx = malloc(sizeof(lvgl_port_display_ctx_t)); - ESP_GOTO_ON_FALSE(disp_ctx, ESP_ERR_NO_MEM, err, TAG, "Not enough memory for display context allocation!"); - memset(disp_ctx, 0, sizeof(lvgl_port_display_ctx_t)); - disp_ctx->io_handle = disp_cfg->io_handle; - disp_ctx->panel_handle = disp_cfg->panel_handle; - disp_ctx->control_handle = disp_cfg->control_handle; - disp_ctx->rotation.swap_xy = disp_cfg->rotation.swap_xy; - disp_ctx->rotation.mirror_x = disp_cfg->rotation.mirror_x; - disp_ctx->rotation.mirror_y = disp_cfg->rotation.mirror_y; - disp_ctx->trans_size = disp_cfg->trans_size; - - buffer_size = disp_cfg->buffer_size; - - /* Use RGB internal buffers for avoid tearing effect */ - if (priv_cfg && priv_cfg->avoid_tearing) { -#if CONFIG_IDF_TARGET_ESP32S3 && ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) - buffer_size = disp_cfg->hres * disp_cfg->vres; - ESP_GOTO_ON_ERROR(esp_lcd_rgb_panel_get_frame_buffer(disp_cfg->panel_handle, 2, (void *)&buf1, (void *)&buf2), err, TAG, "Get RGB buffers failed"); -#endif - } else { - uint32_t buff_caps = MALLOC_CAP_DEFAULT; - if (disp_cfg->flags.buff_dma && disp_cfg->flags.buff_spiram && (0 == disp_cfg->trans_size)) { - ESP_GOTO_ON_FALSE(false, ESP_ERR_NOT_SUPPORTED, err, TAG, "Alloc DMA capable buffer in SPIRAM is not supported!"); - } else if (disp_cfg->flags.buff_dma) { - buff_caps = MALLOC_CAP_DMA; - } else if (disp_cfg->flags.buff_spiram) { - buff_caps = MALLOC_CAP_SPIRAM; - } - - if (disp_cfg->trans_size) { - buf3 = heap_caps_malloc(disp_cfg->trans_size * sizeof(lv_color_t), MALLOC_CAP_DMA); - ESP_GOTO_ON_FALSE(buf3, ESP_ERR_NO_MEM, err, TAG, "Not enough memory for buffer(transport) allocation!"); - disp_ctx->trans_buf = buf3; - - trans_sem = xSemaphoreCreateCounting(1, 0); - ESP_GOTO_ON_FALSE(trans_sem, ESP_ERR_NO_MEM, err, TAG, "Failed to create transport counting Semaphore"); - disp_ctx->trans_sem = trans_sem; - } - - /* 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 */ - buf1 = heap_caps_malloc(buffer_size * sizeof(lv_color_t), buff_caps); - ESP_GOTO_ON_FALSE(buf1, ESP_ERR_NO_MEM, err, TAG, "Not enough memory for LVGL buffer (buf1) allocation!"); - if (disp_cfg->double_buffer) { - buf2 = heap_caps_malloc(buffer_size * sizeof(lv_color_t), buff_caps); - ESP_GOTO_ON_FALSE(buf2, ESP_ERR_NO_MEM, err, TAG, "Not enough memory for LVGL buffer (buf2) allocation!"); - } - } - - lv_disp_draw_buf_t *disp_buf = malloc(sizeof(lv_disp_draw_buf_t)); - ESP_GOTO_ON_FALSE(disp_buf, ESP_ERR_NO_MEM, err, TAG, "Not enough memory for LVGL display buffer allocation!"); - - /* initialize LVGL draw buffers */ - lv_disp_draw_buf_init(disp_buf, buf1, buf2, buffer_size); - - ESP_LOGD(TAG, "Register display driver to LVGL"); - lv_disp_drv_init(&disp_ctx->disp_drv); - disp_ctx->disp_drv.hor_res = disp_cfg->hres; - disp_ctx->disp_drv.ver_res = disp_cfg->vres; - disp_ctx->disp_drv.flush_cb = lvgl_port_flush_callback; - disp_ctx->disp_drv.draw_buf = disp_buf; - disp_ctx->disp_drv.user_data = disp_ctx; - - disp_ctx->disp_drv.sw_rotate = disp_cfg->flags.sw_rotate; - if (disp_ctx->disp_drv.sw_rotate == false) { - disp_ctx->disp_drv.drv_update_cb = lvgl_port_update_callback; - } - - /* Monochrome display settings */ - if (disp_cfg->monochrome) { - /* When using monochromatic display, there must be used full bufer! */ - ESP_GOTO_ON_FALSE((disp_cfg->hres * disp_cfg->vres == buffer_size), ESP_ERR_INVALID_ARG, err, TAG, "Monochromatic display must using full buffer!"); - - disp_ctx->disp_drv.full_refresh = 1; - disp_ctx->disp_drv.set_px_cb = lvgl_port_pix_monochrome_callback; - } else if (disp_cfg->flags.direct_mode) { - /* When using direct_mode, there must be used full bufer! */ - ESP_GOTO_ON_FALSE((disp_cfg->hres * disp_cfg->vres == buffer_size), ESP_ERR_INVALID_ARG, err, TAG, "Direct mode must using full buffer!"); - - disp_ctx->disp_drv.direct_mode = 1; - } else if (disp_cfg->flags.full_refresh) { - /* When using full_refresh, there must be used full bufer! */ - ESP_GOTO_ON_FALSE((disp_cfg->hres * disp_cfg->vres == buffer_size), ESP_ERR_INVALID_ARG, err, TAG, "Full refresh must using full buffer!"); - - disp_ctx->disp_drv.full_refresh = 1; - } - - disp = lv_disp_drv_register(&disp_ctx->disp_drv); - - /* Apply rotation from initial display configuration */ - lvgl_port_update_callback(&disp_ctx->disp_drv); - -err: - if (ret != ESP_OK) { - if (buf1) { - free(buf1); - } - if (buf2) { - free(buf2); - } - if (buf3) { - free(buf3); - } - if (trans_sem) { - vSemaphoreDelete(trans_sem); - } - if (disp_ctx) { - free(disp_ctx); - } - } - - return disp; -} - #if LVGL_PORT_HANDLE_FLUSH_READY -static bool lvgl_port_flush_io_ready_callback(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *edata, void *user_ctx) +static bool lvgl_port_flush_ready_callback(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *edata, void *user_ctx) { BaseType_t taskAwake = pdFALSE; @@ -352,38 +218,6 @@ static bool lvgl_port_flush_io_ready_callback(esp_lcd_panel_io_handle_t panel_io return false; } - -#if (CONFIG_IDF_TARGET_ESP32P4 && ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0)) -static bool lvgl_port_flush_panel_ready_callback(esp_lcd_panel_handle_t panel_io, esp_lcd_dpi_panel_event_data_t *edata, void *user_ctx) -{ - BaseType_t taskAwake = pdFALSE; - - lv_disp_drv_t *disp_drv = (lv_disp_drv_t *)user_ctx; - assert(disp_drv != NULL); - lvgl_port_display_ctx_t *disp_ctx = disp_drv->user_data; - assert(disp_ctx != NULL); - lv_disp_flush_ready(disp_drv); - - if (disp_ctx->trans_size && disp_ctx->trans_sem) { - xSemaphoreGiveFromISR(disp_ctx->trans_sem, &taskAwake); - } - - return false; -} -#endif - -#if CONFIG_IDF_TARGET_ESP32S3 && ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) -static bool lvgl_port_flush_vsync_ready_callback(esp_lcd_panel_handle_t panel_io, const esp_lcd_rgb_panel_event_data_t *edata, void *user_ctx) -{ - BaseType_t need_yield = pdFALSE; - - lv_disp_drv_t *disp_drv = (lv_disp_drv_t *)user_ctx; - assert(disp_drv != NULL); - need_yield = lvgl_port_task_notify(ULONG_MAX); - - return (need_yield == pdTRUE); -} -#endif #endif static void lvgl_port_flush_callback(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_map) @@ -414,22 +248,8 @@ static void lvgl_port_flush_callback(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *from = color_map; lv_color_t *to = NULL; - if (disp_ctx->trans_size == 0) { - if (disp_ctx->disp_type == LVGL_PORT_DISP_TYPE_RGB && (drv->direct_mode || drv->full_refresh)) { - if (lv_disp_flush_is_last(drv)) { - /* If the interface is I80 or SPI, this step cannot be used for drawing. */ - esp_lcd_panel_draw_bitmap(disp_ctx->panel_handle, x_start, y_start, x_end + 1, y_end + 1, color_map); - /* Waiting for the last frame buffer to complete transmission */ - ulTaskNotifyValueClear(NULL, ULONG_MAX); - ulTaskNotifyTake(pdTRUE, portMAX_DELAY); - } - } else { - esp_lcd_panel_draw_bitmap(disp_ctx->panel_handle, x_start, y_start, x_end + 1, y_end + 1, color_map); - } - - if (disp_ctx->disp_type == LVGL_PORT_DISP_TYPE_RGB) { - lv_disp_flush_ready(drv); - } + if (0 == disp_ctx->trans_size) { + esp_lcd_panel_draw_bitmap(disp_ctx->panel_handle, x_start, y_start, x_end + 1, y_end + 1, color_map); } else { y_start_tmp = y_start; max_line = ((disp_ctx->trans_size / width) > height) ? (height) : (disp_ctx->trans_size / width); @@ -463,36 +283,36 @@ static void lvgl_port_update_callback(lv_disp_drv_t *drv) assert(drv); lvgl_port_display_ctx_t *disp_ctx = (lvgl_port_display_ctx_t *)drv->user_data; assert(disp_ctx != NULL); - esp_lcd_panel_handle_t control_handle = (disp_ctx->control_handle ? disp_ctx->control_handle : disp_ctx->panel_handle); + esp_lcd_panel_handle_t panel_handle = disp_ctx->panel_handle; /* Solve rotation screen and touch */ switch (drv->rotated) { case LV_DISP_ROT_NONE: /* Rotate LCD display */ - esp_lcd_panel_swap_xy(control_handle, disp_ctx->rotation.swap_xy); - esp_lcd_panel_mirror(control_handle, disp_ctx->rotation.mirror_x, disp_ctx->rotation.mirror_y); + esp_lcd_panel_swap_xy(panel_handle, disp_ctx->rotation.swap_xy); + esp_lcd_panel_mirror(panel_handle, disp_ctx->rotation.mirror_x, disp_ctx->rotation.mirror_y); break; case LV_DISP_ROT_90: /* Rotate LCD display */ - esp_lcd_panel_swap_xy(control_handle, !disp_ctx->rotation.swap_xy); + esp_lcd_panel_swap_xy(panel_handle, !disp_ctx->rotation.swap_xy); if (disp_ctx->rotation.swap_xy) { - esp_lcd_panel_mirror(control_handle, !disp_ctx->rotation.mirror_x, disp_ctx->rotation.mirror_y); + esp_lcd_panel_mirror(panel_handle, !disp_ctx->rotation.mirror_x, disp_ctx->rotation.mirror_y); } else { - esp_lcd_panel_mirror(control_handle, disp_ctx->rotation.mirror_x, !disp_ctx->rotation.mirror_y); + esp_lcd_panel_mirror(panel_handle, disp_ctx->rotation.mirror_x, !disp_ctx->rotation.mirror_y); } break; case LV_DISP_ROT_180: /* Rotate LCD display */ - esp_lcd_panel_swap_xy(control_handle, disp_ctx->rotation.swap_xy); - esp_lcd_panel_mirror(control_handle, !disp_ctx->rotation.mirror_x, !disp_ctx->rotation.mirror_y); + esp_lcd_panel_swap_xy(panel_handle, disp_ctx->rotation.swap_xy); + esp_lcd_panel_mirror(panel_handle, !disp_ctx->rotation.mirror_x, !disp_ctx->rotation.mirror_y); break; case LV_DISP_ROT_270: /* Rotate LCD display */ - esp_lcd_panel_swap_xy(control_handle, !disp_ctx->rotation.swap_xy); + esp_lcd_panel_swap_xy(panel_handle, !disp_ctx->rotation.swap_xy); if (disp_ctx->rotation.swap_xy) { - esp_lcd_panel_mirror(control_handle, disp_ctx->rotation.mirror_x, !disp_ctx->rotation.mirror_y); + esp_lcd_panel_mirror(panel_handle, disp_ctx->rotation.mirror_x, !disp_ctx->rotation.mirror_y); } else { - esp_lcd_panel_mirror(control_handle, !disp_ctx->rotation.mirror_x, disp_ctx->rotation.mirror_y); + esp_lcd_panel_mirror(panel_handle, !disp_ctx->rotation.mirror_x, disp_ctx->rotation.mirror_y); } break; } diff --git a/libs/esp_lvgl_port/src/lvgl8/esp_lvgl_port_usbhid.c b/libs/esp_lvgl_port/src/lvgl8/esp_lvgl_port_usbhid.c index f39dbc99..98ff3623 100644 --- a/libs/esp_lvgl_port/src/lvgl8/esp_lvgl_port_usbhid.c +++ b/libs/esp_lvgl_port/src/lvgl8/esp_lvgl_port_usbhid.c @@ -4,14 +4,10 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include "esp_log.h" #include "esp_err.h" #include "esp_check.h" #include "esp_lvgl_port.h" -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "freertos/semphr.h" #include "usb/hid_host.h" #include "usb/hid_usage_keyboard.h" diff --git a/libs/esp_lvgl_port/src/lvgl9/esp_lvgl_port.c b/libs/esp_lvgl_port/src/lvgl9/esp_lvgl_port.c index 314343cf..4e65e5cb 100644 --- a/libs/esp_lvgl_port/src/lvgl9/esp_lvgl_port.c +++ b/libs/esp_lvgl_port/src/lvgl9/esp_lvgl_port.c @@ -4,34 +4,25 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include "esp_system.h" #include "esp_log.h" #include "esp_err.h" #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" -#include "esp_lvgl_port_priv.h" #include "lvgl.h" static const char *TAG = "LVGL"; -#define ESP_LVGL_PORT_TASK_MUX_DELAY_MS 10000 - /******************************************************************************* * Types definitions *******************************************************************************/ typedef struct lvgl_port_ctx_s { - TaskHandle_t lvgl_task; SemaphoreHandle_t lvgl_mux; - SemaphoreHandle_t timer_mux; - QueueHandle_t lvgl_queue; - SemaphoreHandle_t task_init_mux; esp_timer_handle_t tick_timer; bool running; int task_max_sleep_ms; @@ -62,31 +53,24 @@ esp_err_t lvgl_port_init(const lvgl_port_cfg_t *cfg) memset(&lvgl_port_ctx, 0, sizeof(lvgl_port_ctx)); + /* LVGL init */ + lv_init(); /* Tick init */ lvgl_port_ctx.timer_period_ms = cfg->timer_period_ms; + ESP_RETURN_ON_ERROR(lvgl_port_tick_init(), TAG, ""); /* Create task */ lvgl_port_ctx.task_max_sleep_ms = cfg->task_max_sleep_ms; if (lvgl_port_ctx.task_max_sleep_ms == 0) { lvgl_port_ctx.task_max_sleep_ms = 500; } - /* Timer semaphore */ - lvgl_port_ctx.timer_mux = xSemaphoreCreateMutex(); - ESP_GOTO_ON_FALSE(lvgl_port_ctx.timer_mux, ESP_ERR_NO_MEM, err, TAG, "Create timer mutex fail!"); - /* LVGL semaphore */ lvgl_port_ctx.lvgl_mux = xSemaphoreCreateRecursiveMutex(); ESP_GOTO_ON_FALSE(lvgl_port_ctx.lvgl_mux, ESP_ERR_NO_MEM, err, TAG, "Create LVGL mutex fail!"); - /* Task init semaphore */ - lvgl_port_ctx.task_init_mux = xSemaphoreCreateMutex(); - ESP_GOTO_ON_FALSE(lvgl_port_ctx.task_init_mux, ESP_ERR_NO_MEM, err, TAG, "Create LVGL task sem fail!"); - /* Task queue */ - lvgl_port_ctx.lvgl_queue = xQueueCreate(100, sizeof(lvgl_port_event_t)); - ESP_GOTO_ON_FALSE(lvgl_port_ctx.lvgl_queue, ESP_ERR_NO_MEM, err, TAG, "Create LVGL queue fail!"); BaseType_t res; if (cfg->task_affinity < 0) { - res = xTaskCreate(lvgl_port_task, "taskLVGL", cfg->task_stack, NULL, cfg->task_priority, &lvgl_port_ctx.lvgl_task); + res = xTaskCreate(lvgl_port_task, "LVGL task", cfg->task_stack, NULL, cfg->task_priority, NULL); } else { - res = xTaskCreatePinnedToCore(lvgl_port_task, "taskLVGL", cfg->task_stack, NULL, cfg->task_priority, &lvgl_port_ctx.lvgl_task, cfg->task_affinity); + res = xTaskCreatePinnedToCore(lvgl_port_task, "LVGL task", cfg->task_stack, NULL, cfg->task_priority, NULL, cfg->task_affinity); } ESP_GOTO_ON_FALSE(res == pdPASS, ESP_FAIL, err, TAG, "Create LVGL task fail!"); @@ -134,17 +118,10 @@ esp_err_t lvgl_port_deinit(void) /* Stop running task */ if (lvgl_port_ctx.running) { lvgl_port_ctx.running = false; + } else { + lvgl_port_task_deinit(); } - /* Wait for stop task */ - if (xSemaphoreTake(lvgl_port_ctx.task_init_mux, pdMS_TO_TICKS(ESP_LVGL_PORT_TASK_MUX_DELAY_MS)) != pdTRUE) { - ESP_LOGE(TAG, "Failed to stop LVGL task"); - return ESP_ERR_TIMEOUT; - } - ESP_LOGI(TAG, "Stopped LVGL task"); - - lvgl_port_task_deinit(); - return ESP_OK; } @@ -162,107 +139,30 @@ void lvgl_port_unlock(void) xSemaphoreGiveRecursive(lvgl_port_ctx.lvgl_mux); } -esp_err_t lvgl_port_task_wake(lvgl_port_event_type_t event, void *param) -{ - if (!lvgl_port_ctx.lvgl_queue) { - return ESP_ERR_INVALID_STATE; - } - - lvgl_port_event_t ev = { - .type = event, - .param = param, - }; - - if (xPortInIsrContext() == pdTRUE) { - BaseType_t xHigherPriorityTaskWoken = pdFALSE; - xQueueSendFromISR(lvgl_port_ctx.lvgl_queue, &ev, &xHigherPriorityTaskWoken); - if (xHigherPriorityTaskWoken) { - portYIELD_FROM_ISR( ); - } - } else { - xQueueSend(lvgl_port_ctx.lvgl_queue, &ev, 0); - } - - return ESP_OK; -} - -IRAM_ATTR bool lvgl_port_task_notify(uint32_t value) -{ - BaseType_t need_yield = pdFALSE; - - // Notify LVGL task - if (xPortInIsrContext() == pdTRUE) { - xTaskNotifyFromISR(lvgl_port_ctx.lvgl_task, value, eNoAction, &need_yield); - } else { - xTaskNotify(lvgl_port_ctx.lvgl_task, value, eNoAction); - } - - return (need_yield == pdTRUE); -} - /******************************************************************************* * Private functions *******************************************************************************/ static void lvgl_port_task(void *arg) { - lvgl_port_event_t event; - uint32_t task_delay_ms = 0; - lv_indev_t *indev = NULL; - - /* Take the task semaphore */ - if (xSemaphoreTake(lvgl_port_ctx.task_init_mux, 0) != pdTRUE) { - ESP_LOGE(TAG, "Failed to take LVGL task sem"); - lvgl_port_task_deinit(); - vTaskDelete( NULL ); - } - - /* LVGL init */ - lv_init(); - /* Tick init */ - lvgl_port_tick_init(); + uint32_t task_delay_ms = lvgl_port_ctx.task_max_sleep_ms; ESP_LOGI(TAG, "Starting LVGL task"); lvgl_port_ctx.running = true; while (lvgl_port_ctx.running) { - /* Wait for queue or timeout (sleep task) */ - TickType_t wait = (pdMS_TO_TICKS(task_delay_ms) >= 1 ? pdMS_TO_TICKS(task_delay_ms) : 1); - xQueueReceive(lvgl_port_ctx.lvgl_queue, &event, wait); - if (lv_display_get_default() && lvgl_port_lock(0)) { - - /* Call read input devices */ - if (event.type == LVGL_PORT_EVENT_TOUCH) { - xSemaphoreTake(lvgl_port_ctx.timer_mux, portMAX_DELAY); - if (event.param != NULL) { - lv_indev_read(event.param); - } else { - indev = lv_indev_get_next(NULL); - while (indev != NULL) { - lv_indev_read(indev); - indev = lv_indev_get_next(indev); - } - } - xSemaphoreGive(lvgl_port_ctx.timer_mux); - } - - /* Handle LVGL */ task_delay_ms = lv_timer_handler(); lvgl_port_unlock(); - } else { - task_delay_ms = 1; /*Keep trying*/ } - - if (task_delay_ms == LV_NO_TIMER_READY) { + if ((task_delay_ms > lvgl_port_ctx.task_max_sleep_ms) || (1 == task_delay_ms)) { task_delay_ms = lvgl_port_ctx.task_max_sleep_ms; + } else if (task_delay_ms < 1) { + task_delay_ms = 1; } - - /* Minimal dealy for the task. When there is too much events, it takes time for other tasks and interrupts. */ - vTaskDelay(1); + vTaskDelay(pdMS_TO_TICKS(task_delay_ms)); } - /* Give semaphore back */ - xSemaphoreGive(lvgl_port_ctx.task_init_mux); + lvgl_port_task_deinit(); /* Close task */ vTaskDelete( NULL ); @@ -270,18 +170,9 @@ static void lvgl_port_task(void *arg) static void lvgl_port_task_deinit(void) { - if (lvgl_port_ctx.timer_mux) { - vSemaphoreDelete(lvgl_port_ctx.timer_mux); - } if (lvgl_port_ctx.lvgl_mux) { vSemaphoreDelete(lvgl_port_ctx.lvgl_mux); } - if (lvgl_port_ctx.task_init_mux) { - vSemaphoreDelete(lvgl_port_ctx.task_init_mux); - } - if (lvgl_port_ctx.lvgl_queue) { - vQueueDelete(lvgl_port_ctx.lvgl_queue); - } memset(&lvgl_port_ctx, 0, sizeof(lvgl_port_ctx)); #if LV_ENABLE_GC || !LV_MEM_CUSTOM /* Deinitialize LVGL */ @@ -291,10 +182,8 @@ static void lvgl_port_task_deinit(void) static void lvgl_port_tick_increment(void *arg) { - xSemaphoreTake(lvgl_port_ctx.timer_mux, portMAX_DELAY); /* Tell LVGL how many milliseconds have elapsed */ lv_tick_inc(lvgl_port_ctx.timer_period_ms); - xSemaphoreGive(lvgl_port_ctx.timer_mux); } static esp_err_t lvgl_port_tick_init(void) diff --git a/libs/esp_lvgl_port/src/lvgl9/esp_lvgl_port_button.c b/libs/esp_lvgl_port/src/lvgl9/esp_lvgl_port_button.c index 99062d3e..4527eff7 100644 --- a/libs/esp_lvgl_port/src/lvgl9/esp_lvgl_port_button.c +++ b/libs/esp_lvgl_port/src/lvgl9/esp_lvgl_port_button.c @@ -88,7 +88,6 @@ lv_indev_t *lvgl_port_add_navigation_buttons(const lvgl_port_nav_btns_cfg_t *but /* Register a touchpad input device */ indev = lv_indev_create(); lv_indev_set_type(indev, LV_INDEV_TYPE_ENCODER); - lv_indev_set_mode(indev, LV_INDEV_MODE_EVENT); lv_indev_set_read_cb(indev, lvgl_port_navigation_buttons_read); lv_indev_set_disp(indev, buttons_cfg->disp); lv_indev_set_user_data(indev, buttons_ctx); @@ -111,7 +110,7 @@ err: } } - return NULL; + return buttons_ctx->indev; } esp_err_t lvgl_port_remove_navigation_buttons(lv_indev_t *buttons) @@ -181,9 +180,6 @@ 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, ctx->indev); } static void lvgl_port_btn_up_handler(void *arg, void *arg2) @@ -204,7 +200,4 @@ 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, ctx->indev); } diff --git a/libs/esp_lvgl_port/src/lvgl9/esp_lvgl_port_disp.c b/libs/esp_lvgl_port/src/lvgl9/esp_lvgl_port_disp.c index 25035311..4a51d864 100644 --- a/libs/esp_lvgl_port/src/lvgl9/esp_lvgl_port_disp.c +++ b/libs/esp_lvgl_port/src/lvgl9/esp_lvgl_port_disp.c @@ -4,27 +4,13 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include "esp_log.h" #include "esp_err.h" #include "esp_check.h" -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "freertos/semphr.h" #include "esp_heap_caps.h" -#include "esp_idf_version.h" #include "esp_lcd_panel_io.h" #include "esp_lcd_panel_ops.h" #include "esp_lvgl_port.h" -#include "esp_lvgl_port_priv.h" - -#if CONFIG_IDF_TARGET_ESP32S3 && ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) -#include "esp_lcd_panel_rgb.h" -#endif - -#if (CONFIG_IDF_TARGET_ESP32P4 && ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0)) -#include "esp_lcd_mipi_dsi.h" -#endif #if (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 4, 4)) || (ESP_IDF_VERSION == ESP_IDF_VERSION_VAL(5, 0, 0)) #define LVGL_PORT_HANDLE_FLUSH_READY 0 @@ -39,41 +25,26 @@ static const char *TAG = "LVGL"; *******************************************************************************/ typedef struct { - lvgl_port_disp_type_t disp_type; /* Display type */ esp_lcd_panel_io_handle_t io_handle; /* LCD panel IO handle */ esp_lcd_panel_handle_t panel_handle; /* LCD panel handle */ - esp_lcd_panel_handle_t control_handle; /* LCD panel control handle */ lvgl_port_rotation_cfg_t rotation; /* Default values of the screen rotation */ - lv_color_t *draw_buffs[3]; /* Display draw buffers */ + lv_color16_t *draw_buffs[2]; /* Display draw buffers */ lv_display_t *disp_drv; /* LVGL display driver */ - lv_display_rotation_t current_rotation; struct { unsigned int monochrome: 1; /* True, if display is monochrome and using 1bit for 1px */ unsigned int swap_bytes: 1; /* Swap bytes in RGB656 (16-bit) before send to LCD driver */ - unsigned int full_refresh: 1; /* Always make the whole screen redrawn */ - unsigned int direct_mode: 1; /* Use screen-sized buffers and draw to absolute coordinates */ - unsigned int sw_rotate: 1; /* Use software rotation (slower) or PPA if available */ } flags; } lvgl_port_display_ctx_t; /******************************************************************************* * Function definitions *******************************************************************************/ -static lv_display_t *lvgl_port_add_disp_priv(const lvgl_port_display_cfg_t *disp_cfg, const lvgl_port_disp_priv_cfg_t *priv_cfg); + #if LVGL_PORT_HANDLE_FLUSH_READY -static bool lvgl_port_flush_io_ready_callback(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *edata, void *user_ctx); -#if CONFIG_IDF_TARGET_ESP32S3 && ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) -static bool lvgl_port_flush_vsync_ready_callback(esp_lcd_panel_handle_t panel_io, const esp_lcd_rgb_panel_event_data_t *edata, void *user_ctx); -#endif -#if (CONFIG_IDF_TARGET_ESP32P4 && ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0)) -static bool lvgl_port_flush_panel_ready_callback(esp_lcd_panel_handle_t panel_io, esp_lcd_dpi_panel_event_data_t *edata, void *user_ctx); -#endif +static bool lvgl_port_flush_ready_callback(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *edata, void *user_ctx); #endif static void lvgl_port_flush_callback(lv_display_t *drv, const lv_area_t *area, uint8_t *color_map); -static void lvgl_port_flush_wait_callback(lv_display_t *drv); static void lvgl_port_disp_size_update_callback(lv_event_t *e); -static void lvgl_port_disp_rotation_update(lvgl_port_display_ctx_t *disp_ctx); -static void lvgl_port_display_invalidate_callback(lv_event_t *e); /******************************************************************************* * Public API functions @@ -81,106 +52,94 @@ static void lvgl_port_display_invalidate_callback(lv_event_t *e); lv_display_t *lvgl_port_add_disp(const lvgl_port_display_cfg_t *disp_cfg) { + esp_err_t ret = ESP_OK; + lv_display_t *disp = NULL; + lv_color16_t *buf1 = NULL; + lv_color16_t *buf2 = NULL; + assert(disp_cfg != NULL); + assert(disp_cfg->io_handle != NULL); + assert(disp_cfg->panel_handle != NULL); + assert(disp_cfg->buffer_size > 0); + assert(disp_cfg->hres > 0); + assert(disp_cfg->vres > 0); + + /* Display context */ + lvgl_port_display_ctx_t *disp_ctx = malloc(sizeof(lvgl_port_display_ctx_t)); + ESP_GOTO_ON_FALSE(disp_ctx, ESP_ERR_NO_MEM, err, TAG, "Not enough memory for display context allocation!"); + disp_ctx->io_handle = disp_cfg->io_handle; + disp_ctx->panel_handle = disp_cfg->panel_handle; + disp_ctx->rotation.swap_xy = disp_cfg->rotation.swap_xy; + disp_ctx->rotation.mirror_x = disp_cfg->rotation.mirror_x; + disp_ctx->rotation.mirror_y = disp_cfg->rotation.mirror_y; + disp_ctx->flags.swap_bytes = disp_cfg->flags.swap_bytes; + + uint32_t buff_caps = MALLOC_CAP_DEFAULT; + if (disp_cfg->flags.buff_dma && disp_cfg->flags.buff_spiram) { + ESP_GOTO_ON_FALSE(false, ESP_ERR_NOT_SUPPORTED, err, TAG, "Alloc DMA capable buffer in SPIRAM is not supported!"); + } else if (disp_cfg->flags.buff_dma) { + buff_caps = MALLOC_CAP_DMA; + } else if (disp_cfg->flags.buff_spiram) { + buff_caps = MALLOC_CAP_SPIRAM; + } + + /* 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 */ + buf1 = heap_caps_malloc(disp_cfg->buffer_size * sizeof(lv_color16_t), buff_caps); + ESP_GOTO_ON_FALSE(buf1, ESP_ERR_NO_MEM, err, TAG, "Not enough memory for LVGL buffer (buf1) allocation!"); + if (disp_cfg->double_buffer) { + buf2 = heap_caps_malloc(disp_cfg->buffer_size * sizeof(lv_color16_t), buff_caps); + ESP_GOTO_ON_FALSE(buf2, ESP_ERR_NO_MEM, err, TAG, "Not enough memory for LVGL buffer (buf2) allocation!"); + } + + disp_ctx->draw_buffs[0] = buf1; + disp_ctx->draw_buffs[1] = buf2; + lvgl_port_lock(0); - lv_disp_t *disp = lvgl_port_add_disp_priv(disp_cfg, NULL); + disp = lv_display_create(disp_cfg->hres, disp_cfg->vres); - if (disp != NULL) { - lvgl_port_display_ctx_t *disp_ctx = (lvgl_port_display_ctx_t *)lv_display_get_user_data(disp); - /* Set display type */ - disp_ctx->disp_type = LVGL_PORT_DISP_TYPE_OTHER; + /* Monochrome display settings */ + if (disp_cfg->monochrome) { + /* When using monochromatic display, there must be used full bufer! */ + ESP_GOTO_ON_FALSE((disp_cfg->hres * disp_cfg->vres == disp_cfg->buffer_size), ESP_ERR_INVALID_ARG, err, TAG, "Monochromatic display must using full buffer!"); - assert(disp_cfg->io_handle != NULL); + disp_ctx->flags.monochrome = 1; + + //lv_display_set_color_format(disp, LV_COLOR_FORMAT_RGB565); + lv_display_set_buffers(disp, buf1, buf2, disp_cfg->buffer_size * sizeof(lv_color16_t), LV_DISPLAY_RENDER_MODE_FULL); + } else { + lv_display_set_buffers(disp, buf1, buf2, disp_cfg->buffer_size * sizeof(lv_color16_t), LV_DISPLAY_RENDER_MODE_PARTIAL); + } + + + lv_display_set_flush_cb(disp, lvgl_port_flush_callback); + lv_display_add_event_cb(disp, lvgl_port_disp_size_update_callback, LV_EVENT_RESOLUTION_CHANGED, disp_ctx); + + lv_display_set_user_data(disp, disp_ctx); + disp_ctx->disp_drv = disp; #if LVGL_PORT_HANDLE_FLUSH_READY - const esp_lcd_panel_io_callbacks_t cbs = { - .on_color_trans_done = lvgl_port_flush_io_ready_callback, - }; - /* Register done callback */ - esp_lcd_panel_io_register_event_callbacks(disp_ctx->io_handle, &cbs, disp); -#endif - - /* Apply rotation from initial display configuration */ - lvgl_port_disp_rotation_update(disp_ctx); - } - lvgl_port_unlock(); - - return disp; -} - -lv_display_t *lvgl_port_add_disp_dsi(const lvgl_port_display_cfg_t *disp_cfg, const lvgl_port_display_dsi_cfg_t *dsi_cfg) -{ - lvgl_port_lock(0); - lv_disp_t *disp = lvgl_port_add_disp_priv(disp_cfg, NULL); - - if (disp != NULL) { - lvgl_port_display_ctx_t *disp_ctx = (lvgl_port_display_ctx_t *)lv_display_get_user_data(disp); - /* Set display type */ - disp_ctx->disp_type = LVGL_PORT_DISP_TYPE_DSI; - -#if (CONFIG_IDF_TARGET_ESP32P4 && ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0)) - const esp_lcd_dpi_panel_event_callbacks_t cbs = { - .on_color_trans_done = lvgl_port_flush_panel_ready_callback, - }; - /* Register done callback */ - esp_lcd_dpi_panel_register_event_callbacks(disp_ctx->panel_handle, &cbs, disp); - - /* Apply rotation from initial display configuration */ - lvgl_port_disp_rotation_update(disp_ctx); - -#else - ESP_RETURN_ON_FALSE(false, NULL, TAG, "MIPI-DSI is supported only on ESP32P4 and from IDF 5.3!"); -#endif - } - lvgl_port_unlock(); - - return disp; -} - -lv_display_t *lvgl_port_add_disp_rgb(const lvgl_port_display_cfg_t *disp_cfg, const lvgl_port_display_rgb_cfg_t *rgb_cfg) -{ - lvgl_port_lock(0); - assert(rgb_cfg != NULL); - const lvgl_port_disp_priv_cfg_t priv_cfg = { - .avoid_tearing = rgb_cfg->flags.avoid_tearing, + /* Register done callback */ + const esp_lcd_panel_io_callbacks_t cbs = { + .on_color_trans_done = lvgl_port_flush_ready_callback, }; - lv_disp_t *disp = lvgl_port_add_disp_priv(disp_cfg, &priv_cfg); - - if (disp != NULL) { - lvgl_port_display_ctx_t *disp_ctx = (lvgl_port_display_ctx_t *)lv_display_get_user_data(disp); - /* Set display type */ - disp_ctx->disp_type = LVGL_PORT_DISP_TYPE_RGB; - -#if (CONFIG_IDF_TARGET_ESP32S3 && ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)) - /* Register done callback */ - const esp_lcd_rgb_panel_event_callbacks_t vsync_cbs = { - .on_vsync = lvgl_port_flush_vsync_ready_callback, - }; - - const esp_lcd_rgb_panel_event_callbacks_t bb_cbs = { -#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 1, 2) - .on_bounce_frame_finish = lvgl_port_flush_vsync_ready_callback, -#endif - }; - - if (rgb_cfg->flags.bb_mode && (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 1, 2))) { - ESP_ERROR_CHECK(esp_lcd_rgb_panel_register_event_callbacks(disp_ctx->panel_handle, &bb_cbs, &disp_ctx->disp_drv)); - } else { - ESP_ERROR_CHECK(esp_lcd_rgb_panel_register_event_callbacks(disp_ctx->panel_handle, &vsync_cbs, &disp_ctx->disp_drv)); - } -#else - ESP_RETURN_ON_FALSE(false, NULL, TAG, "RGB is supported only on ESP32S3 and from IDF 5.0!"); + esp_lcd_panel_io_register_event_callbacks(disp_ctx->io_handle, &cbs, disp_ctx->disp_drv); #endif - /* Set wait callback */ - if (disp_ctx->flags.full_refresh || disp_ctx->flags.direct_mode) { - lv_display_set_flush_wait_cb(disp, lvgl_port_flush_wait_callback); - } - - /* Apply rotation from initial display configuration */ - lvgl_port_disp_rotation_update(disp_ctx); - } lvgl_port_unlock(); +err: + if (ret != ESP_OK) { + if (buf1) { + free(buf1); + } + if (buf2) { + free(buf2); + } + if (disp_ctx) { + free(disp_ctx); + } + } + return disp; } @@ -201,10 +160,6 @@ esp_err_t lvgl_port_remove_disp(lv_display_t *disp) free(disp_ctx->draw_buffs[1]); } - if (disp_ctx->draw_buffs[2]) { - free(disp_ctx->draw_buffs[2]); - } - free(disp_ctx); return ESP_OK; @@ -220,183 +175,20 @@ void lvgl_port_flush_ready(lv_display_t *disp) * Private functions *******************************************************************************/ -static lv_display_t *lvgl_port_add_disp_priv(const lvgl_port_display_cfg_t *disp_cfg, const lvgl_port_disp_priv_cfg_t *priv_cfg) -{ - esp_err_t ret = ESP_OK; - lv_display_t *disp = NULL; - lv_color_t *buf1 = NULL; - lv_color_t *buf2 = NULL; - uint32_t buffer_size = 0; - assert(disp_cfg != NULL); - assert(disp_cfg->panel_handle != NULL); - assert(disp_cfg->buffer_size > 0); - assert(disp_cfg->hres > 0); - assert(disp_cfg->vres > 0); - - buffer_size = disp_cfg->buffer_size; - - /* Check supported display color formats */ - ESP_RETURN_ON_FALSE(disp_cfg->color_format == 0 || disp_cfg->color_format == LV_COLOR_FORMAT_RGB565 || disp_cfg->color_format == LV_COLOR_FORMAT_RGB888 || disp_cfg->color_format == LV_COLOR_FORMAT_XRGB8888 || disp_cfg->color_format == LV_COLOR_FORMAT_ARGB8888, NULL, TAG, "Not supported display color format!"); - - lv_color_format_t display_color_format = (disp_cfg->color_format != 0 ? disp_cfg->color_format : LV_COLOR_FORMAT_RGB565); - if (disp_cfg->flags.swap_bytes) { - /* Swap bytes can be used only in RGB656 color format */ - ESP_RETURN_ON_FALSE(display_color_format == LV_COLOR_FORMAT_RGB565, NULL, TAG, "Swap bytes can be used only in display color format RGB565!"); - } - - if (disp_cfg->flags.buff_dma) { - /* DMA buffer can be used only in RGB656 color format */ - ESP_RETURN_ON_FALSE(display_color_format == LV_COLOR_FORMAT_RGB565, NULL, TAG, "DMA buffer can be used only in display color format RGB565 (not alligned copy)!"); - } - - /* Display context */ - lvgl_port_display_ctx_t *disp_ctx = malloc(sizeof(lvgl_port_display_ctx_t)); - ESP_GOTO_ON_FALSE(disp_ctx, ESP_ERR_NO_MEM, err, TAG, "Not enough memory for display context allocation!"); - memset(disp_ctx, 0, sizeof(lvgl_port_display_ctx_t)); - disp_ctx->io_handle = disp_cfg->io_handle; - disp_ctx->panel_handle = disp_cfg->panel_handle; - disp_ctx->control_handle = disp_cfg->control_handle; - disp_ctx->rotation.swap_xy = disp_cfg->rotation.swap_xy; - disp_ctx->rotation.mirror_x = disp_cfg->rotation.mirror_x; - disp_ctx->rotation.mirror_y = disp_cfg->rotation.mirror_y; - disp_ctx->flags.swap_bytes = disp_cfg->flags.swap_bytes; - disp_ctx->flags.sw_rotate = disp_cfg->flags.sw_rotate; - disp_ctx->current_rotation = LV_DISPLAY_ROTATION_0; - - uint32_t buff_caps = 0; -#if SOC_PSRAM_DMA_CAPABLE == 0 - if (disp_cfg->flags.buff_dma && disp_cfg->flags.buff_spiram) { - ESP_GOTO_ON_FALSE(false, ESP_ERR_NOT_SUPPORTED, err, TAG, "Alloc DMA capable buffer in SPIRAM is not supported!"); - } -#endif - if (disp_cfg->flags.buff_dma) { - buff_caps |= MALLOC_CAP_DMA; - } - if (disp_cfg->flags.buff_spiram) { - buff_caps |= MALLOC_CAP_SPIRAM; - } - if (buff_caps == 0) { - buff_caps |= MALLOC_CAP_DEFAULT; - } - - /* Use RGB internal buffers for avoid tearing effect */ - if (priv_cfg && priv_cfg->avoid_tearing) { -#if CONFIG_IDF_TARGET_ESP32S3 && ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) - buffer_size = disp_cfg->hres * disp_cfg->vres; - ESP_GOTO_ON_ERROR(esp_lcd_rgb_panel_get_frame_buffer(disp_cfg->panel_handle, 2, (void *)&buf1, (void *)&buf2), err, TAG, "Get RGB buffers failed"); -#endif - } else { - /* 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 */ - buf1 = heap_caps_malloc(buffer_size * sizeof(lv_color_t), buff_caps); - ESP_GOTO_ON_FALSE(buf1, ESP_ERR_NO_MEM, err, TAG, "Not enough memory for LVGL buffer (buf1) allocation!"); - if (disp_cfg->double_buffer) { - buf2 = heap_caps_malloc(buffer_size * sizeof(lv_color_t), buff_caps); - ESP_GOTO_ON_FALSE(buf2, ESP_ERR_NO_MEM, err, TAG, "Not enough memory for LVGL buffer (buf2) allocation!"); - } - - disp_ctx->draw_buffs[0] = buf1; - disp_ctx->draw_buffs[1] = buf2; - } - - disp = lv_display_create(disp_cfg->hres, disp_cfg->vres); - - /* Monochrome display settings */ - if (disp_cfg->monochrome) { - /* When using monochromatic display, there must be used full bufer! */ - ESP_GOTO_ON_FALSE((disp_cfg->hres * disp_cfg->vres == buffer_size), ESP_ERR_INVALID_ARG, err, TAG, "Monochromatic display must using full buffer!"); - - disp_ctx->flags.monochrome = 1; - lv_display_set_buffers(disp, buf1, buf2, buffer_size * sizeof(lv_color_t), LV_DISPLAY_RENDER_MODE_FULL); - } else if (disp_cfg->flags.direct_mode) { - /* When using direct_mode, there must be used full bufer! */ - ESP_GOTO_ON_FALSE((disp_cfg->hres * disp_cfg->vres == buffer_size), ESP_ERR_INVALID_ARG, err, TAG, "Direct mode must using full buffer!"); - - disp_ctx->flags.direct_mode = 1; - lv_display_set_buffers(disp, buf1, buf2, buffer_size * sizeof(lv_color_t), LV_DISPLAY_RENDER_MODE_DIRECT); - } else if (disp_cfg->flags.full_refresh) { - /* When using full_refresh, there must be used full bufer! */ - ESP_GOTO_ON_FALSE((disp_cfg->hres * disp_cfg->vres == buffer_size), ESP_ERR_INVALID_ARG, err, TAG, "Full refresh must using full buffer!"); - - disp_ctx->flags.full_refresh = 1; - lv_display_set_buffers(disp, buf1, buf2, buffer_size * sizeof(lv_color_t), LV_DISPLAY_RENDER_MODE_FULL); - } else { - lv_display_set_buffers(disp, buf1, buf2, buffer_size * sizeof(lv_color_t), LV_DISPLAY_RENDER_MODE_PARTIAL); - } - - lv_display_set_color_format(disp, display_color_format); - lv_display_set_flush_cb(disp, lvgl_port_flush_callback); - lv_display_add_event_cb(disp, lvgl_port_disp_size_update_callback, LV_EVENT_RESOLUTION_CHANGED, disp_ctx); - lv_display_add_event_cb(disp, lvgl_port_display_invalidate_callback, LV_EVENT_INVALIDATE_AREA, disp_ctx); - lv_display_add_event_cb(disp, lvgl_port_display_invalidate_callback, LV_EVENT_REFR_REQUEST, disp_ctx); - - lv_display_set_user_data(disp, disp_ctx); - disp_ctx->disp_drv = disp; - - /* Use SW rotation */ - if (disp_cfg->flags.sw_rotate) { - disp_ctx->draw_buffs[2] = heap_caps_malloc(buffer_size * sizeof(lv_color_t), buff_caps); - ESP_GOTO_ON_FALSE(disp_ctx->draw_buffs[2], ESP_ERR_NO_MEM, err, TAG, "Not enough memory for LVGL buffer (rotation buffer) allocation!"); - } - - -err: - if (ret != ESP_OK) { - if (buf1) { - free(buf1); - } - if (buf2) { - free(buf2); - } - if (disp_ctx->draw_buffs[2]) { - free(disp_ctx->draw_buffs[2]); - } - if (disp_ctx) { - free(disp_ctx); - } - } - - return disp; -} - #if LVGL_PORT_HANDLE_FLUSH_READY -static bool lvgl_port_flush_io_ready_callback(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *edata, void *user_ctx) +static bool lvgl_port_flush_ready_callback(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *edata, void *user_ctx) { lv_display_t *disp_drv = (lv_display_t *)user_ctx; assert(disp_drv != NULL); lv_disp_flush_ready(disp_drv); return false; } - -#if (CONFIG_IDF_TARGET_ESP32P4 && ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0)) -static bool lvgl_port_flush_panel_ready_callback(esp_lcd_panel_handle_t panel_io, esp_lcd_dpi_panel_event_data_t *edata, void *user_ctx) -{ - lv_display_t *disp_drv = (lv_display_t *)user_ctx; - assert(disp_drv != NULL); - lv_disp_flush_ready(disp_drv); - return false; -} -#endif - -#if CONFIG_IDF_TARGET_ESP32S3 && ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) -static bool lvgl_port_flush_vsync_ready_callback(esp_lcd_panel_handle_t panel_io, const esp_lcd_rgb_panel_event_data_t *edata, void *user_ctx) -{ - BaseType_t need_yield = pdFALSE; - - lv_display_t *disp_drv = (lv_display_t *)user_ctx; - assert(disp_drv != NULL); - need_yield = lvgl_port_task_notify(ULONG_MAX); - lvgl_port_task_wake(LVGL_PORT_EVENT_DISPLAY, disp_drv); - - return (need_yield == pdTRUE); -} -#endif #endif static void _lvgl_port_transform_monochrome(lv_display_t *display, const lv_area_t *area, uint8_t *color_map) { uint8_t *buf = color_map; - lv_color_t *color = (lv_color_t *)color_map; + lv_color16_t *color = (lv_color16_t *)color_map; uint16_t hor_res = lv_display_get_physical_horizontal_resolution(display); uint16_t ver_res = lv_display_get_physical_vertical_resolution(display); uint16_t res = hor_res; @@ -434,165 +226,67 @@ static void _lvgl_port_transform_monochrome(lv_display_t *display, const lv_area } } -void lvgl_port_rotate_area(lv_display_t *disp, lv_area_t *area) -{ - lv_display_rotation_t rotation = lv_display_get_rotation(disp); - - int32_t w = lv_area_get_width(area); - int32_t h = lv_area_get_height(area); - - int32_t hres = lv_display_get_horizontal_resolution(disp); - int32_t vres = lv_display_get_vertical_resolution(disp); - if (rotation == LV_DISPLAY_ROTATION_90 || rotation == LV_DISPLAY_ROTATION_270) { - vres = lv_display_get_horizontal_resolution(disp); - hres = lv_display_get_vertical_resolution(disp); - } - - switch (rotation) { - case LV_DISPLAY_ROTATION_0: - return; - case LV_DISPLAY_ROTATION_90: - area->y2 = vres - area->x1 - 1; - area->x1 = area->y1; - area->x2 = area->x1 + h - 1; - area->y1 = area->y2 - w + 1; - break; - case LV_DISPLAY_ROTATION_180: - area->y2 = vres - area->y1 - 1; - area->y1 = area->y2 - h + 1; - area->x2 = hres - area->x1 - 1; - area->x1 = area->x2 - w + 1; - break; - case LV_DISPLAY_ROTATION_270: - area->x1 = hres - area->y2 - 1; - area->y2 = area->x2; - area->x2 = area->x1 + h - 1; - area->y1 = area->y2 - w + 1; - break; - } -} - - -static void lvgl_port_flush_wait_callback(lv_display_t *drv) -{ - assert(drv != NULL); - if (lv_disp_flush_is_last(drv)) { - /* Waiting for the last frame buffer to complete transmission */ - ulTaskNotifyValueClear(NULL, ULONG_MAX); - ulTaskNotifyTake(pdTRUE, portMAX_DELAY); - } -} - static void lvgl_port_flush_callback(lv_display_t *drv, const lv_area_t *area, uint8_t *color_map) { assert(drv != NULL); - assert(area != NULL); - assert(color_map != NULL); lvgl_port_display_ctx_t *disp_ctx = (lvgl_port_display_ctx_t *)lv_display_get_user_data(drv); assert(disp_ctx != NULL); - int offsetx1 = area->x1; - int offsetx2 = area->x2; - int offsety1 = area->y1; - int offsety2 = area->y2; - - /* SW rotation enabled */ - if (disp_ctx->flags.sw_rotate && (disp_ctx->current_rotation > LV_DISPLAY_ROTATION_0 || disp_ctx->flags.swap_bytes)) { - /* SW rotation */ - if (disp_ctx->draw_buffs[2]) { - int32_t ww = lv_area_get_width(area); - int32_t hh = lv_area_get_height(area); - lv_color_format_t cf = lv_display_get_color_format(drv); - uint32_t w_stride = lv_draw_buf_width_to_stride(ww, cf); - uint32_t h_stride = lv_draw_buf_width_to_stride(hh, cf); - if (disp_ctx->current_rotation == LV_DISPLAY_ROTATION_180) { - lv_draw_sw_rotate(color_map, disp_ctx->draw_buffs[2], hh, ww, h_stride, h_stride, LV_DISPLAY_ROTATION_180, cf); - } else if (disp_ctx->current_rotation == LV_DISPLAY_ROTATION_90) { - lv_draw_sw_rotate(color_map, disp_ctx->draw_buffs[2], ww, hh, w_stride, h_stride, LV_DISPLAY_ROTATION_270, cf); - } else if (disp_ctx->current_rotation == LV_DISPLAY_ROTATION_270) { - lv_draw_sw_rotate(color_map, disp_ctx->draw_buffs[2], ww, hh, w_stride, h_stride, LV_DISPLAY_ROTATION_90, cf); - } - color_map = (uint8_t *)disp_ctx->draw_buffs[2]; - lvgl_port_rotate_area(drv, (lv_area_t *)area); - offsetx1 = area->x1; - offsetx2 = area->x2; - offsety1 = area->y1; - offsety2 = area->y2; - } - } else if (disp_ctx->flags.swap_bytes) { + //TODO: try to use SPI_SWAP_DATA_RX from https://docs.espressif.com/projects/esp-idf/en/v5.1/esp32s3/api-reference/peripherals/spi_master.html#c.SPI_SWAP_DATA_TX + if (disp_ctx->flags.swap_bytes) { size_t len = lv_area_get_size(area); lv_draw_sw_rgb565_swap(color_map, len); } - /* Transfer data in buffer for monochromatic screen */ + /* Transfor data in buffer for monochromatic screen */ if (disp_ctx->flags.monochrome) { _lvgl_port_transform_monochrome(drv, area, color_map); } - /* Draw */ + const int offsetx1 = area->x1; + const int offsetx2 = area->x2; + const int offsety1 = area->y1; + const int offsety2 = area->y2; + // copy a buffer's content to a specific area of the display esp_lcd_panel_draw_bitmap(disp_ctx->panel_handle, offsetx1, offsety1, offsetx2 + 1, offsety2 + 1, color_map); - - /* Call flush ready only in RGB screen when not full refresh or direct mode */ - if (disp_ctx->disp_type == LVGL_PORT_DISP_TYPE_RGB && !disp_ctx->flags.full_refresh && !disp_ctx->flags.direct_mode) { - lv_disp_flush_ready(drv); - } -} - -static void lvgl_port_disp_rotation_update(lvgl_port_display_ctx_t *disp_ctx) -{ - assert(disp_ctx != NULL); - - disp_ctx->current_rotation = lv_display_get_rotation(disp_ctx->disp_drv); - if (disp_ctx->flags.sw_rotate) { - return; - } - - esp_lcd_panel_handle_t control_handle = (disp_ctx->control_handle ? disp_ctx->control_handle : disp_ctx->panel_handle); - /* Solve rotation screen and touch */ - switch (lv_display_get_rotation(disp_ctx->disp_drv)) { - case LV_DISPLAY_ROTATION_0: - /* Rotate LCD display */ - esp_lcd_panel_swap_xy(control_handle, disp_ctx->rotation.swap_xy); - esp_lcd_panel_mirror(control_handle, disp_ctx->rotation.mirror_x, disp_ctx->rotation.mirror_y); - break; - case LV_DISPLAY_ROTATION_90: - /* Rotate LCD display */ - esp_lcd_panel_swap_xy(control_handle, !disp_ctx->rotation.swap_xy); - if (disp_ctx->rotation.swap_xy) { - esp_lcd_panel_mirror(control_handle, !disp_ctx->rotation.mirror_x, disp_ctx->rotation.mirror_y); - } else { - esp_lcd_panel_mirror(control_handle, disp_ctx->rotation.mirror_x, !disp_ctx->rotation.mirror_y); - } - break; - case LV_DISPLAY_ROTATION_180: - /* Rotate LCD display */ - esp_lcd_panel_swap_xy(control_handle, disp_ctx->rotation.swap_xy); - esp_lcd_panel_mirror(control_handle, !disp_ctx->rotation.mirror_x, !disp_ctx->rotation.mirror_y); - break; - case LV_DISPLAY_ROTATION_270: - /* Rotate LCD display */ - esp_lcd_panel_swap_xy(control_handle, !disp_ctx->rotation.swap_xy); - if (disp_ctx->rotation.swap_xy) { - esp_lcd_panel_mirror(control_handle, disp_ctx->rotation.mirror_x, !disp_ctx->rotation.mirror_y); - } else { - esp_lcd_panel_mirror(control_handle, !disp_ctx->rotation.mirror_x, disp_ctx->rotation.mirror_y); - } - break; - } - - /* Wake LVGL task, if needed */ - lvgl_port_task_wake(LVGL_PORT_EVENT_DISPLAY, disp_ctx->disp_drv); } static void lvgl_port_disp_size_update_callback(lv_event_t *e) { assert(e); - lvgl_port_display_ctx_t *disp_ctx = (lvgl_port_display_ctx_t *)lv_event_get_user_data(e); - lvgl_port_disp_rotation_update(disp_ctx); -} + lvgl_port_display_ctx_t *disp_ctx = (lvgl_port_display_ctx_t *)e->user_data; + assert(disp_ctx != NULL); + esp_lcd_panel_handle_t panel_handle = disp_ctx->panel_handle; -static void lvgl_port_display_invalidate_callback(lv_event_t *e) -{ - /* Wake LVGL task, if needed */ - lvgl_port_task_wake(LVGL_PORT_EVENT_DISPLAY, NULL); + /* Solve rotation screen and touch */ + switch (lv_display_get_rotation(disp_ctx->disp_drv)) { + case LV_DISPLAY_ROTATION_0: + /* Rotate LCD display */ + esp_lcd_panel_swap_xy(panel_handle, disp_ctx->rotation.swap_xy); + esp_lcd_panel_mirror(panel_handle, disp_ctx->rotation.mirror_x, disp_ctx->rotation.mirror_y); + break; + case LV_DISPLAY_ROTATION_90: + /* Rotate LCD display */ + esp_lcd_panel_swap_xy(panel_handle, !disp_ctx->rotation.swap_xy); + if (disp_ctx->rotation.swap_xy) { + esp_lcd_panel_mirror(panel_handle, !disp_ctx->rotation.mirror_x, disp_ctx->rotation.mirror_y); + } else { + esp_lcd_panel_mirror(panel_handle, disp_ctx->rotation.mirror_x, !disp_ctx->rotation.mirror_y); + } + break; + case LV_DISPLAY_ROTATION_180: + /* Rotate LCD display */ + esp_lcd_panel_swap_xy(panel_handle, disp_ctx->rotation.swap_xy); + esp_lcd_panel_mirror(panel_handle, !disp_ctx->rotation.mirror_x, !disp_ctx->rotation.mirror_y); + break; + case LV_DISPLAY_ROTATION_270: + /* Rotate LCD display */ + esp_lcd_panel_swap_xy(panel_handle, !disp_ctx->rotation.swap_xy); + if (disp_ctx->rotation.swap_xy) { + esp_lcd_panel_mirror(panel_handle, disp_ctx->rotation.mirror_x, !disp_ctx->rotation.mirror_y); + } else { + esp_lcd_panel_mirror(panel_handle, !disp_ctx->rotation.mirror_x, disp_ctx->rotation.mirror_y); + } + break; + } } diff --git a/libs/esp_lvgl_port/src/lvgl9/esp_lvgl_port_knob.c b/libs/esp_lvgl_port/src/lvgl9/esp_lvgl_port_knob.c index 81157182..03efe4c1 100644 --- a/libs/esp_lvgl_port/src/lvgl9/esp_lvgl_port_knob.c +++ b/libs/esp_lvgl_port/src/lvgl9/esp_lvgl_port_knob.c @@ -29,7 +29,6 @@ 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 @@ -53,9 +52,6 @@ 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!"); - - 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 */ @@ -73,15 +69,12 @@ lv_indev_t *lvgl_port_add_encoder(const lvgl_port_encoder_cfg_t *encoder_cfg) /* Register a encoder input device */ indev = lv_indev_create(); lv_indev_set_type(indev, LV_INDEV_TYPE_ENCODER); - lv_indev_set_mode(indev, LV_INDEV_MODE_EVENT); lv_indev_set_read_cb(indev, lvgl_port_encoder_read); lv_indev_set_disp(indev, encoder_cfg->disp); lv_indev_set_user_data(indev, encoder_ctx); encoder_ctx->indev = indev; lvgl_port_unlock(); - return indev; - err: if (ret != ESP_OK) { if (encoder_ctx->knob_handle != NULL) { @@ -96,7 +89,7 @@ err: free(encoder_ctx); } } - return NULL; + return encoder_ctx->indev; } esp_err_t lvgl_port_remove_encoder(lv_indev_t *encoder) @@ -157,9 +150,6 @@ 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, ctx->indev); } static void lvgl_port_encoder_btn_up_handler(void *arg, void *arg2) @@ -172,14 +162,4 @@ 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, ctx->indev); -} - -static void lvgl_port_encoder_knob_handler(void *arg, void *arg2) -{ - lvgl_port_encoder_ctx_t *ctx = (lvgl_port_encoder_ctx_t *) arg2; - /* Wake LVGL task, if needed */ - lvgl_port_task_wake(LVGL_PORT_EVENT_TOUCH, ctx->indev); } diff --git a/libs/esp_lvgl_port/src/lvgl9/esp_lvgl_port_touch.c b/libs/esp_lvgl_port/src/lvgl9/esp_lvgl_port_touch.c index a0d848e8..6aac2fb6 100644 --- a/libs/esp_lvgl_port/src/lvgl9/esp_lvgl_port_touch.c +++ b/libs/esp_lvgl_port/src/lvgl9/esp_lvgl_port_touch.c @@ -26,7 +26,6 @@ typedef struct { *******************************************************************************/ 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); /******************************************************************************* * Public API functions @@ -34,8 +33,7 @@ static void lvgl_port_touch_interrupt_callback(esp_lcd_touch_handle_t tp); lv_indev_t *lvgl_port_add_touch(const lvgl_port_touch_cfg_t *touch_cfg) { - esp_err_t ret = ESP_OK; - lv_indev_t *indev = NULL; + lv_indev_t *indev; assert(touch_cfg != NULL); assert(touch_cfg->disp != NULL); assert(touch_cfg->handle != NULL); @@ -48,33 +46,16 @@ lv_indev_t *lvgl_port_add_touch(const lvgl_port_touch_cfg_t *touch_cfg) } touch_ctx->handle = touch_cfg->handle; - if (touch_ctx->handle->config.int_gpio_num != GPIO_NUM_NC) { - /* Register touch interrupt callback */ - ret = esp_lcd_touch_register_interrupt_callback_with_data(touch_ctx->handle, lvgl_port_touch_interrupt_callback, touch_ctx); - ESP_GOTO_ON_ERROR(ret, err, TAG, "Error in register touch interrupt."); - } - lvgl_port_lock(0); /* Register a touchpad input device */ indev = lv_indev_create(); lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER); - /* Event mode can be set only, when touch interrupt enabled */ - if (touch_ctx->handle->config.int_gpio_num != GPIO_NUM_NC) { - lv_indev_set_mode(indev, LV_INDEV_MODE_EVENT); - } lv_indev_set_read_cb(indev, lvgl_port_touchpad_read); lv_indev_set_disp(indev, touch_cfg->disp); lv_indev_set_user_data(indev, touch_ctx); touch_ctx->indev = indev; lvgl_port_unlock(); -err: - if (ret != ESP_OK) { - if (touch_ctx) { - free(touch_ctx); - } - } - return indev; } @@ -88,11 +69,6 @@ esp_err_t lvgl_port_remove_touch(lv_indev_t *touch) lv_indev_delete(touch); lvgl_port_unlock(); - if (touch_ctx->handle->config.int_gpio_num != GPIO_NUM_NC) { - /* Unregister touch interrupt callback */ - esp_lcd_touch_register_interrupt_callback(touch_ctx->handle, NULL); - } - if (touch_ctx) { free(touch_ctx); } @@ -129,11 +105,3 @@ static void lvgl_port_touchpad_read(lv_indev_t *indev_drv, lv_indev_data_t *data data->state = LV_INDEV_STATE_RELEASED; } } - -static void IRAM_ATTR lvgl_port_touch_interrupt_callback(esp_lcd_touch_handle_t tp) -{ - lvgl_port_touch_ctx_t *touch_ctx = (lvgl_port_touch_ctx_t *) tp->config.user_data; - - /* Wake LVGL task, if needed */ - lvgl_port_task_wake(LVGL_PORT_EVENT_TOUCH, touch_ctx->indev); -} diff --git a/libs/esp_lvgl_port/src/lvgl9/esp_lvgl_port_usbhid.c b/libs/esp_lvgl_port/src/lvgl9/esp_lvgl_port_usbhid.c index 7f3342ad..947142f1 100644 --- a/libs/esp_lvgl_port/src/lvgl9/esp_lvgl_port_usbhid.c +++ b/libs/esp_lvgl_port/src/lvgl9/esp_lvgl_port_usbhid.c @@ -4,14 +4,10 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include "esp_log.h" #include "esp_err.h" #include "esp_check.h" #include "esp_lvgl_port.h" -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "freertos/semphr.h" #include "usb/hid_host.h" #include "usb/hid_usage_keyboard.h" @@ -95,7 +91,6 @@ lv_indev_t *lvgl_port_add_usb_hid_mouse_input(const lvgl_port_hid_mouse_cfg_t *m /* Register a mouse input device */ indev = lv_indev_create(); lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER); - lv_indev_set_mode(indev, LV_INDEV_MODE_EVENT); lv_indev_set_read_cb(indev, lvgl_port_usb_hid_read_mouse); lv_indev_set_disp(indev, mouse_cfg->disp); lv_indev_set_user_data(indev, hid_ctx); @@ -129,7 +124,6 @@ lv_indev_t *lvgl_port_add_usb_hid_keyboard_input(const lvgl_port_hid_keyboard_cf /* Register a mouse input device */ indev = lv_indev_create(); lv_indev_set_type(indev, LV_INDEV_TYPE_KEYPAD); - lv_indev_set_mode(indev, LV_INDEV_MODE_EVENT); lv_indev_set_read_cb(indev, lvgl_port_usb_hid_read_kb); lv_indev_set_disp(indev, keyboard_cfg->disp); lv_indev_set_user_data(indev, hid_ctx); @@ -331,8 +325,6 @@ 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, hid_ctx->kb.indev); } 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)) { @@ -341,9 +333,6 @@ 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, hid_ctx->mouse.indev); } break; case HID_HOST_INTERFACE_EVENT_TRANSFER_ERROR: diff --git a/libs/esp_lvgl_port/src/lvgl9/simd/lv_color_blend_to_argb8888_esp32.S b/libs/esp_lvgl_port/src/lvgl9/simd/lv_color_blend_to_argb8888_esp32.S deleted file mode 100644 index 7d060675..00000000 --- a/libs/esp_lvgl_port/src/lvgl9/simd/lv_color_blend_to_argb8888_esp32.S +++ /dev/null @@ -1,81 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -// This is LVGL ARGB8888 simple fill for ESP32 processor - - .section .text - .align 4 - .global lv_color_blend_to_argb8888_esp - .type lv_color_blend_to_argb8888_esp,@function - -// The function implements the following C code: -// void lv_color_blend_to_argb8888(_lv_draw_sw_blend_fill_dsc_t * dsc); - -// Input params -// -// dsc - a2 - -// typedef struct { -// uint32_t opa; l32i 0 -// void * dst_buf; l32i 4 -// uint32_t dst_w; l32i 8 -// uint32_t dst_h; l32i 12 -// uint32_t dst_stride; l32i 16 -// const void * src_buf; l32i 20 -// uint32_t src_stride; l32i 24 -// const lv_opa_t * mask_buf; l32i 28 -// uint32_t mask_stride; l32i 32 -// } asm_dsc_t; - -lv_color_blend_to_argb8888_esp: - - entry a1, 32 - - l32i.n a3, a2, 4 // a3 - dest_buff - l32i.n a4, a2, 8 // a4 - dest_w in uint32_t - l32i.n a5, a2, 12 // a5 - dest_h in uint32_t - l32i.n a6, a2, 16 // a6 - dest_stride in bytes - l32i.n a7, a2, 20 // a7 - src_buff (color) - l32i.n a8, a7, 0 // a8 - color as value - slli a11, a4, 2 // a11 - dest_w_bytes = sizeof(uint32_t) * dest_w - - movi a7, 0xff000000 // oppactiy mask - or a10, a7, a8 // apply oppacity - - srli a9, a4, 2 // a9 - loop_len = dest_w / 4 - sub a6, a6, a11 // dest_stride = dest_stride - dest_w_bytes - - .outer_loop: - - // Run main loop which sets 16 bytes in one loop run - loopnez a9, ._main_loop - s32i.n a10, a3, 0 // save 32 bits from a10 to dest_buff a3 - s32i.n a10, a3, 4 // save 32 bits from a10 to dest_buff a3 - s32i.n a10, a3, 8 // save 32 bits from a10 to dest_buff a3 - s32i.n a10, a3, 12 // save 32 bits from a10 to dest_buff a3 - addi.n a3, a3, 16 // increment dest_buff pointer by 16 bytes - ._main_loop: - - // Finish the remaining bytes out of the loop - // Check modulo 8 of the dest_w_bytes, if - then set 8 bytes - bbci a11, 3, _mod_8_check // branch if 2-nd bit of dest_w_bytes is clear - s32i.n a10, a3, 0 // save 32 bits from a10 to dest_buff a3, offset 0 bytes - s32i.n a10, a3, 4 // save 32 bits from a10 to dest_buff a3, offset 0 bytes - addi.n a3, a3, 8 // increment dest_buff pointer by 8 bytes - _mod_8_check: - - // Check modulo 4 of the dest_w_bytes, if - then set 4 bytes - bbci a11, 2, _mod_4_check // branch if 2-nd bit of dest_w_bytes is clear - s32i.n a10, a3, 0 // save 32 bits from a10 to dest_buff a3, offset 0 bytes - addi.n a3, a3, 4 // increment dest_buff pointer by 4 bytes - _mod_4_check: - - add a3, a3, a6 // dest_buff + dest_stride - addi.n a5, a5, -1 // decrease the outer loop - bnez a5, .outer_loop - - movi.n a2, 1 // return LV_RESULT_OK = 1 - retw.n // return diff --git a/libs/esp_lvgl_port/src/lvgl9/simd/lv_color_blend_to_argb8888_esp32s3.S b/libs/esp_lvgl_port/src/lvgl9/simd/lv_color_blend_to_argb8888_esp32s3.S deleted file mode 100644 index 4d9f84f1..00000000 --- a/libs/esp_lvgl_port/src/lvgl9/simd/lv_color_blend_to_argb8888_esp32s3.S +++ /dev/null @@ -1,328 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -// This is LVGL ARGB8888 simple fill for ESP32S3 processor - - .section .text - .align 4 - .global lv_color_blend_to_argb8888_esp - .type lv_color_blend_to_argb8888_esp,@function -// The function implements the following C code: -// void lv_color_blend_to_argb8888(_lv_draw_sw_blend_fill_dsc_t * dsc); - -// Input params -// -// dsc - a2 - -// typedef struct { -// uint32_t opa; l32i 0 -// void * dst_buf; l32i 4 -// uint32_t dst_w; l32i 8 -// uint32_t dst_h; l32i 12 -// uint32_t dst_stride; l32i 16 -// const void * src_buf; l32i 20 -// uint32_t src_stride; l32i 24 -// const lv_opa_t * mask_buf; l32i 28 -// uint32_t mask_stride; l32i 32 -// } asm_dsc_t; - - -lv_color_blend_to_argb8888_esp: - - entry a1, 32 - ee.zero.q q0 // dummy TIE instruction, to enable the TIE - - l32i.n a3, a2, 4 // a3 - dest_buff - l32i.n a4, a2, 8 // a4 - dest_w in uint32_t - l32i.n a5, a2, 12 // a5 - dest_h in uint32_t - l32i.n a6, a2, 16 // a6 - dest_stride in bytes - l32i.n a7, a2, 20 // a7 - src_buff (color) - l32i.n a8, a7, 0 // a8 - color as value - slli a11, a4, 2 // a11 - dest_w_bytes = sizeof(uint32_t) * dest_w - - movi a7, 0xff000000 // oppactiy mask - or a10, a7, a8 // apply oppacity - - // Check for short lengths - // dest_w should be at least 8, othewise it's not worth using esp32s3 TIE - bgei a4, 8, _esp32s3_implementation // Branch if dest_w is greater than or equal to 8 - j .lv_color_blend_to_argb8888_esp32_body // Jump to esp32 implementation - - _esp32s3_implementation: - - ee.movi.32.q q0, a10, 0 // fill q0 register from a10 by 32 bits - ee.movi.32.q q0, a10, 1 - ee.movi.32.q q0, a10, 2 - ee.movi.32.q q0, a10, 3 - - // Check dest_buff alignment - movi.n a7, 0xf // 0xf alignment mask (16-byte alignment) - and a15, a7, a3 // 16-byte alignment mask AND dest_buff pointer - bnez a15, _unaligned_by_4byte // branch if a15 not equals to zero - - // Check dest_stride alignment - and a15, a7, a6 // 16-byte alignment mask AND dest_stride - bnez a15, _unaligned_by_4byte // branch if a15 not equals to zero - - // Check dest_w_bytes alignment - and a15, a7, a11 // 16-byte alignment mask AND dest_w_bytes - bnez a15, _unaligned_by_4byte // branch if a15 not equals to zero - -//********************************************************************************************************************** - - // all aligned, the most ideal case - - // dest_buff (a3) - 16-byte aligned - // dest_stride (a6) - 16-byte multiple - // dest_w (a4) - 16-byte multiple - - srli a9, a4, 2 // a9 - loop_len = dest_w / 4 - sub a6, a6, a11 // dest_stride = dest_stride - dest_w_bytes - - .outer_loop_aligned: - - loopnez a9, ._main_loop_aligned // 16 bytes (4 argb8888) in one loop - ee.vst.128.ip q0, a3, 16 // store 16 bytes from q0 to dest_buff a3 - ._main_loop_aligned: - - add a3, a3, a6 // dest_buff + dest_stride - addi.n a5, a5, -1 // decrease the outer loop - bnez a5, .outer_loop_aligned - - movi.n a2, 1 // return LV_RESULT_OK = 1 - retw.n // return - - _unaligned_by_4byte: - - // Check dest_buff alignment - movi.n a7, 0x3 // 0x3 alignment mask (4-byte alignment) - and a15, a7, a3 // 4-byte alignment mask AND dest_buff pointer - bnez a15, _unaligned_by_1byte // branch if a15 not equals to zero - - // Check dest_stride alignment - and a15, a7, a6 // 4-byte alignment mask AND dest_stride pointer - bnez a15, _unaligned_by_1byte // branch if a15 not equals to zero - -//********************************************************************************************************************** - - // either dest_buff or dest_stride is not 16-byte aligned - // dest_w is always 4-byte multiple - // all of the following are 4-byte aligned - - // dest_buff (a3) - 16-byte, or 4-byte aligned - // dest_stride (a6) - 16-byte, or 4-byte multiple - // dest_w (a4) - 4-byte multiple - - sub a6, a6, a11 // dest_stride = dest_stride - dest_w_bytes - movi.n a7, 0xf // 0xf alignment mask - - .outer_loop_aligned_by_4byte: - - // alignment check - and a15, a7, a3 // 0xf (alignment mask) AND dest_buff pointer - mov a12, a11 // a12 - local_dest_w_bytes = dest_w_bytes - beqz a15, _dest_buff_aligned_by_4byte // branch if a15 equals to zero - - - movi.n a14, 16 // a14 - 16 - sub a15, a14, a15 // a15 = 16 - unalignment (lower 4 bits of dest_buff address) - sub a12, a12, a15 // local_dest_w_bytes = len - (16 - unalignment) - - // keep setting until dest_buff is aligned - // Check modulo 8 of the unalignment, if - then set 8 bytes - bbci a15, 3, _aligning_mod_8_check_4byte // branch if 3-rd bit of unalignment a15 is clear - s32i.n a10, a3, 0 // save 32 bits from a10 to dest_buff a3, offset 0 bytes - s32i.n a10, a3, 4 // save 32 bits from a10 to dest_buff a3, offset 4 bytes - addi.n a3, a3, 8 // increment dest_buff pointer by 8 bytes - _aligning_mod_8_check_4byte: - - // Check modulo 4 of the unalignment, if - then set 4 bytes - bbci a15, 2, _aligning_mod_4_check_4byte // branch if 2-nd bit unalignment a15 is clear - s32i.n a10, a3, 0 // save 32 bits from a10 to dest_buff a3, offset 0 bytes - addi.n a3, a3, 4 // increment dest_buff pointer by 4 bytes - _aligning_mod_4_check_4byte: - - _dest_buff_aligned_by_4byte: - // Calculate main loop_len - srli a9, a12, 4 // a9 - loop_len = local_dest_w_bytes / 16 - - // Main loop - loopnez a9, ._main_loop_unaligned_by_4byte // 16 bytes (4 argb8888) in one loop - ee.vst.128.ip q0, a3, 16 // store 16 bytes from q0 to dest_buff a3 - ._main_loop_unaligned_by_4byte: - - // Check modulo 8 of the dest_w, if - then set 8 bytes - bbci a12, 3, _aligned_mod_8_check_4byte // branch if 3-rd bit of local_dest_w_bytes a12 is clear - ee.vst.l.64.ip q0, a3, 8 // save lower 64 bits from q0 to dest_buff a3, increase dest_buff pointer by 8 bytes - _aligned_mod_8_check_4byte: - - // Check modulo 4 of the dest_w, if - then set 4 bytes - bbci a12, 2, _aligned_mod_4_check_4byte // branch if 2-nd bit of local_dest_w_bytes a12 is clear - s32i.n a10, a3, 0 // save 32 bits from a10 to dest_buff a3, offset 0 bytes - addi.n a3, a3, 4 // increment dest_buff pointer by 4 bytes - _aligned_mod_4_check_4byte: - - add a3, a3, a6 // dest_buff + dest_stride - addi.n a5, a5, -1 // decrease the outer loop - bnez a5, .outer_loop_aligned_by_4byte - - movi.n a2, 1 // return LV_RESULT_OK = 1 - retw.n // return - - _unaligned_by_1byte: - -//********************************************************************************************************************** - - // either dest_buff or dest_stride is not 4-byte aligned - // dest_w is always 4-byte multiple - - // dest_buff (a3) - 4-byte, or 1-byte aligned - // dest_stride (a6) - 4-byte, or 1-byte multiple - // dest_w (a4) - 4-byte multiple - - - mov a13, a3 - - ee.zero.q q1 // clear q1 - ee.orq q1, q1, q0 // copy q0 to q1 - sub a6, a6, a11 // dest_stride = dest_stride - dest_w_bytes - movi.n a7, 0xf // 0xf alignment mask - - .outer_loop_aligned_by_1byte: - - // alignment check - and a15, a7, a3 // 0xf (alignment mask) AND dest_buff pointer - mov a12, a11 // a12 - local_dest_w_bytes = dest_w_bytes - beqz a15, _dest_buff_aligned_by_1byte // branch if a15 equals to zero - - - movi.n a14, 16 // a14 - 16 - sub a15, a14, a15 // a15 = 16 - unalignment (lower 4 bits of dest_buff address) - sub a12, a12, a15 // local_dest_w_bytes = len - (16 - unalignment) - - // keep setting until dest_buff is aligned - // Check modulo 8 of the unalignment, if - then set 8 bytes - bbci a15, 3, _aligning_mod_8_check_1byte// branch if 3-rd bit of unalignment a15 is clear - s32i.n a10, a3, 0 // save 32 bits from a10 to dest_buff a3, offset 0 bytes - s32i.n a10, a3, 4 // save 32 bits from a10 to dest_buff a3, offset 4 bytes - addi.n a3, a3, 8 // increment dest_buff pointer by 8 bytes - _aligning_mod_8_check_1byte: - - // Check modulo 4 of the unalignment, if - then set 4 bytes - bbci a15, 2, _aligning_mod_4_check_1byte // branch if 2-nd bit unalignment a15 is clear - s32i.n a10, a3, 0 // save 32 bits from a10 to dest_buff a3, offset 0 bytes - addi.n a3, a3, 4 // increment dest_buff pointer by 4 bytes - _aligning_mod_4_check_1byte: - - // Check modulo 2 and 1 (the following 2 ifs do the same correction) - // modulo 2 and modulo 1 requires the same action, just once - bbci a15, 1, _aligning_mod_2_check_1byte - s32i.n a10, a3, 0 // save 32 bits from a10 to dest_buff a3, offset 0 bytes - addi.n a3, a3, 4 // increment dest_buff pointer by 4 bytes - j _dest_buff_aligned_by_1byte - _aligning_mod_2_check_1byte: - - bbci a15, 0, _dest_buff_aligned_by_1byte - s32i.n a10, a3, 0 // save 32 bits from a10 to dest_buff a3, offset 0 bytes - addi.n a3, a3, 4 // increment dest_buff pointer by 4 bytes - _dest_buff_aligned_by_1byte: - - // Shift q reg, allowing to set 16-byte unaligned adata - wur.sar_byte a15 // apply unalignment to the SAR_BYTE - ee.src.q q2, q0, q1 // shift concat. of q0 and q1 to q2 by SAR_BYTE amount - - // Calculate main loop_len - srli a9, a12, 4 // a9 - loop_len = local_dest_w_bytes / 16 - - // Main loop - loopnez a9, ._main_loop_unaligned_by_1byte // 16 bytes (4 argb8888) in one loop - ee.vst.128.ip q2, a3, 16 // store 16 bytes from q0 to dest_buff a3 - ._main_loop_unaligned_by_1byte: - - // Firstly check mod 0 and mod 1 - correcting the aligned memory access - // Go back in one Byte, allow to correct after ee.vst.128.ip aligned access - addi a3, a3, -4 - - // Check modulo 2 of the dest_w, if - then set 2 bytes - // set SSSS in 0xSSSS0000 - bbci a12, 1, _aligned_mod_2_check_1byte // branch if 1-st bit of dest_w a12 is clear - srli a14, a10, 16 // shift a10 in 16, allowing s16i (saving of lower 16 bits) - s16i a14, a3, 2 // save 16 bits from a10 to dest_buff a3, offset 2 bytes - - // Check modulo 1 of the dest_w, if - then set 1 byte - // additionally set SS in 0x0000SS00 - bbci a12, 0, _aligned_end // branch if 0-th bit of dest_w a12 is clear - srli a14, a10, 8 // shift a10 in 8, allowing s8i - s8i a14, a3, 1 // save 8 bits from a10 to dest_buff a3, offset 1 byte - j _aligned_end - _aligned_mod_2_check_1byte: - - // Check modulo 1 of the dest_w, if - then set 1 byte - // set SS in 0xSS000000 - bbci a12, 0, _aligned_end // branch if 0-th bit of dest_w a12 is clear - srli a14, a10, 24 // shift a10 in 24, allowing s8i (saving of lower 8 bits) - s8i a14, a3, 3 // save 8 bits from a10 to dest_buff a3, offset 3 bytes - _aligned_end: - - addi a3, a3, 4 // Increase the pointer back, correction for addi a3, a3, -4 - - // Check modulo 8 of the dest_w, if - then set 8 bytes - bbci a12, 3, _aligned_mod_8_check_1byte // branch if 3-rd bit of local_dest_w_bytes a12 is clear - s32i.n a10, a3, 0 // save 32 bits from a10 to dest_buff a3, offset 0 bytes - s32i.n a10, a3, 4 // save 32 bits from a10 to dest_buff a3, offset 0 bytes - addi.n a3, a3, 8 // increment dest_buff pointer by 4 bytes - //ee.vst.l.64.ip q2, a3, 8 // save lower 64 bits from q0 to dest_buff a3, increase dest_buff pointer by 8 bytes - _aligned_mod_8_check_1byte: - - // Check modulo 4 of the dest_w, if - then set 4 bytes - bbci a12, 2, _aligned_mod_4_check_1byte // branch if 2-nd bit of local_dest_w_bytes a12 is clear - s32i.n a10, a3, 0 // save 32 bits from a10 to dest_buff a3, offset 0 bytes - addi.n a3, a3, 4 // increment dest_buff pointer by 4 bytes - _aligned_mod_4_check_1byte: - - add a3, a3, a6 // dest_buff + dest_stride - addi.n a5, a5, -1 // decrease the outer loop - bnez a5, .outer_loop_aligned_by_1byte - - movi.n a2, 1 // return LV_RESULT_OK = 1 - retw.n // return - - .lv_color_blend_to_argb8888_esp32_body: - - srli a9, a4, 2 // a9 - loop_len = dest_w / 4 - sub a6, a6, a11 // dest_stride = dest_stride - dest_w_bytes - - .outer_loop: - - // Run main loop which sets 16 bytes in one loop run - loopnez a9, ._main_loop - s32i.n a10, a3, 0 // save 32 bits from a10 to dest_buff a3 - s32i.n a10, a3, 4 // save 32 bits from a10 to dest_buff a3 - s32i.n a10, a3, 8 // save 32 bits from a10 to dest_buff a3 - s32i.n a10, a3, 12 // save 32 bits from a10 to dest_buff a3 - addi.n a3, a3, 16 // increment dest_buff pointer by 16 bytes - ._main_loop: - - // Finish the remaining bytes out of the loop - // Check modulo 8 of the dest_w_bytes, if - then set 8 bytes - bbci a11, 3, _mod_8_check // branch if 2-nd bit of dest_w_bytes is clear - s32i.n a10, a3, 0 // save 32 bits from a10 to dest_buff a3, offset 0 bytes - s32i.n a10, a3, 4 // save 32 bits from a10 to dest_buff a3, offset 0 bytes - addi.n a3, a3, 8 // increment dest_buff pointer by 8 bytes - _mod_8_check: - - // Check modulo 4 of the dest_w_bytes, if - then set 4 bytes - bbci a11, 2, _mod_4_check // branch if 2-nd bit of dest_w_bytes is clear - s32i.n a10, a3, 0 // save 32 bits from a10 to dest_buff a3, offset 0 bytes - addi.n a3, a3, 4 // increment dest_buff pointer by 4 bytes - _mod_4_check: - - add a3, a3, a6 // dest_buff + dest_stride - addi.n a5, a5, -1 // decrease the outer loop - bnez a5, .outer_loop - - movi.n a2, 1 // return LV_RESULT_OK = 1 - retw.n // return diff --git a/libs/esp_lvgl_port/src/lvgl9/simd/lv_color_blend_to_rgb565_esp32.S b/libs/esp_lvgl_port/src/lvgl9/simd/lv_color_blend_to_rgb565_esp32.S deleted file mode 100644 index 07b5aa11..00000000 --- a/libs/esp_lvgl_port/src/lvgl9/simd/lv_color_blend_to_rgb565_esp32.S +++ /dev/null @@ -1,149 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -// This is LVGL RGB565 simple fill for ESP32 processor - - .section .text - .align 4 - .global lv_color_blend_to_rgb565_esp - .type lv_color_blend_to_rgb565_esp,@function -// The function implements the following C code: -// void lv_color_blend_to_rgb565(_lv_draw_sw_blend_fill_dsc_t * dsc); - -// Input params -// -// dsc - a2 - -// typedef struct { -// uint32_t opa; l32i 0 -// void * dst_buf; l32i 4 -// uint32_t dst_w; l32i 8 -// uint32_t dst_h; l32i 12 -// uint32_t dst_stride; l32i 16 -// const void * src_buf; l32i 20 -// uint32_t src_stride; l32i 24 -// const lv_opa_t * mask_buf; l32i 28 -// uint32_t mask_stride; l32i 32 -// } asm_dsc_t; - -lv_color_blend_to_rgb565_esp: - - entry a1, 32 - - l32i.n a3, a2, 4 // a3 - dest_buff - l32i.n a4, a2, 8 // a4 - dest_w in uint16_t - l32i.n a5, a2, 12 // a5 - dest_h in uint16_t - l32i.n a6, a2, 16 // a6 - dest_stride in bytes - l32i.n a7, a2, 20 // a7 - src_buff (color) - l32i.n a8, a7, 0 // a8 - color as value - slli a11, a4, 1 // a11 - dest_w_bytes = sizeof(uint16_t) * dest_w - - // Convert color to rgb656 - l8ui a15, a7, 2 // red - movi.n a14, 0xf8 - and a13, a15, a14 - slli a10, a13, 8 - - l8ui a15, a7, 0 // blue - and a13, a15, a14 - srli a12, a13, 3 - add a10, a10, a12 - - l8ui a15, a7, 1 // green - movi.n a14, 0xfc - and a13, a15, a14 - slli a12, a13, 3 - add a12, a10, a12 // a12 = 16-bit color - - slli a10, a12, 16 - movi.n a13, 0xFFFF0000 - and a10, a10, a13 - or a10, a10, a12 // a10 = 32-bit color (16bit + (16bit << 16)) - - movi.n a8, 0x3 // a8 = 0x3, dest_buff align mask - sub a6, a6, a11 // dest_stride = dest_stride - dest_w_bytes - - // cache init - // Prepare main loop length and dest_w_bytes - srli a9, a4, 4 // a9 = loop_len = dest_w / 8, calculate main loop_len for original dest_w - slli a11, a4, 1 // a11 = dest_w_bytes = sizeof(uint16_t) * dest_w - addi a4, a4, -1 // a4-- (decrement a4) - s32i.n a9, a1, 0 // cache.orig.loop_len - s32i.n a11, a1, 4 // cache.orig.dest_w_bytes - - // Prepare decreased main loop length and dest_w_bytes - srli a9, a4, 4 // a9 = loop_len = dest_w / 8, calculate main loop_len for dest_w - 1 - slli a11, a4, 1 // a11 = dest_w_bytes = sizeof(uint16_t) * (dest_w - 1) - s32i.n a9, a1, 8 // cache.decr.loop_len - s32i.n a11, a1, 12 // cache.decr.dest_w_bytes - and a7, a8, a3 // a7 = dest_buff AND 0x3 (chck if the address is 4-byte aligned) - - .outer_loop: - - // Check if the des_buff is 2-byte aligned - beqz a7, _dest_buff_2_byte_aligned // branch if a7 is equal to zero - s16i a12, a3, 0 // save 16 bits from 16-bit color a12 to dest_buff a3, offset 0 - l32i.n a9, a1, 8 // a9 = load cache.decr.loop_len - l32i.n a11, a1, 12 // a11 = load cache.decr.dest_w_bytes - addi.n a3, a3, 2 // increment dest_buff pointer by 2 - j _dest_buff_unaligned - _dest_buff_2_byte_aligned: - - l32i.n a9, a1, 0 // a11 = load cache.orig.loop_len - l32i.n a11, a1, 4 // a11 = load cache.orig.dest_w_bytes - - _dest_buff_unaligned: - - // Run main loop which sets 16 bytes in one loop run - loopnez a9, ._main_loop - s32i.n a10, a3, 0 // save 32 bits from 32-bit color a10 to dest_buff a3, offset 0 - s32i.n a10, a3, 4 // save 32 bits from 32-bit color a10 to dest_buff a3, offset 4 - s32i.n a10, a3, 8 // save 32 bits from 32-bit color a10 to dest_buff a3, offset 8 - s32i.n a10, a3, 12 // save 32 bits from 32-bit color a10 to dest_buff a3, offset 12 - s32i.n a10, a3, 16 // save 32 bits from 32-bit color a10 to dest_buff a3, offset 16 - s32i.n a10, a3, 20 // save 32 bits from 32-bit color a10 to dest_buff a3, offset 20 - s32i.n a10, a3, 24 // save 32 bits from 32-bit color a10 to dest_buff a3, offset 24 - s32i.n a10, a3, 28 // save 32 bits from 32-bit color a10 to dest_buff a3, offset 28 - addi.n a3, a3, 32 // increment dest_buff pointer by 32 - ._main_loop: - - // Finish the remaining bytes out of the loop - // Check modulo 8 of the dest_w_bytes, if - then set 16 bytes - bbci a11, 4, _mod_16_check // branch if 2-nd bit of dest_w_bytes is clear - s32i.n a10, a3, 0 // save 32 bits from 32-bit color a10 to dest_buff a3, offset 0 - s32i.n a10, a3, 4 // save 32 bits from 32-bit color a10 to dest_buff a3, offset 4 - s32i.n a10, a3, 8 // save 32 bits from 32-bit color a10 to dest_buff a3, offset 8 - s32i.n a10, a3, 12 // save 32 bits from 32-bit color a10 to dest_buff a3, offset 12 - addi.n a3, a3, 16 // increment dest_buff pointer by 16 - _mod_16_check: - - // Finish the remaining bytes out of the loop - // Check modulo 8 of the dest_w_bytes, if - then set 8 bytes - bbci a11, 3, _mod_8_check // branch if 2-nd bit of dest_w_bytes is clear - s32i.n a10, a3, 0 // save 32 bits from 32-bit color a10 to dest_buff a3, offset 0 - s32i.n a10, a3, 4 // save 32 bits from 32-bit color a10 to dest_buff a3, offset 4 - addi.n a3, a3, 8 // increment dest_buff pointer by 8 bytes - _mod_8_check: - - // Check modulo 4 of the dest_w_bytes, if - then set 4 bytes - bbci a11, 2, _mod_4_check // branch if 2-nd bit of dest_w_bytes is clear - s32i.n a10, a3, 0 // save 32 bits from 32-bit color a10 to dest_buff a3, offset 0 - addi.n a3, a3, 4 // increment dest_buff pointer by 4 - _mod_4_check: - - // Check modulo 2 of the dest_w_bytes, if - then set 2 bytes - bbci a11, 1, _mod_2_check // branch if 1-st bit of dest_w_bytes is clear - s16i a12, a3, 0 // save 16 bits from 16-bit color a12 to dest_buff a3, offset 0 - addi.n a3, a3, 2 // increment dest_buff pointer by 2 bytes - _mod_2_check: - - add a3, a3, a6 // dest_buff + dest_stride - addi.n a5, a5, -1 // decrease the outer loop - and a7, a8, a3 // a7 = dest_buff AND 0x3 (chck if the address is 4-byte aligned) - bnez a5, .outer_loop - - movi.n a2, 1 // return LV_RESULT_OK = 1 - retw.n // return diff --git a/libs/esp_lvgl_port/src/lvgl9/simd/lv_color_blend_to_rgb565_esp32s3.S b/libs/esp_lvgl_port/src/lvgl9/simd/lv_color_blend_to_rgb565_esp32s3.S deleted file mode 100644 index 07b5aa11..00000000 --- a/libs/esp_lvgl_port/src/lvgl9/simd/lv_color_blend_to_rgb565_esp32s3.S +++ /dev/null @@ -1,149 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -// This is LVGL RGB565 simple fill for ESP32 processor - - .section .text - .align 4 - .global lv_color_blend_to_rgb565_esp - .type lv_color_blend_to_rgb565_esp,@function -// The function implements the following C code: -// void lv_color_blend_to_rgb565(_lv_draw_sw_blend_fill_dsc_t * dsc); - -// Input params -// -// dsc - a2 - -// typedef struct { -// uint32_t opa; l32i 0 -// void * dst_buf; l32i 4 -// uint32_t dst_w; l32i 8 -// uint32_t dst_h; l32i 12 -// uint32_t dst_stride; l32i 16 -// const void * src_buf; l32i 20 -// uint32_t src_stride; l32i 24 -// const lv_opa_t * mask_buf; l32i 28 -// uint32_t mask_stride; l32i 32 -// } asm_dsc_t; - -lv_color_blend_to_rgb565_esp: - - entry a1, 32 - - l32i.n a3, a2, 4 // a3 - dest_buff - l32i.n a4, a2, 8 // a4 - dest_w in uint16_t - l32i.n a5, a2, 12 // a5 - dest_h in uint16_t - l32i.n a6, a2, 16 // a6 - dest_stride in bytes - l32i.n a7, a2, 20 // a7 - src_buff (color) - l32i.n a8, a7, 0 // a8 - color as value - slli a11, a4, 1 // a11 - dest_w_bytes = sizeof(uint16_t) * dest_w - - // Convert color to rgb656 - l8ui a15, a7, 2 // red - movi.n a14, 0xf8 - and a13, a15, a14 - slli a10, a13, 8 - - l8ui a15, a7, 0 // blue - and a13, a15, a14 - srli a12, a13, 3 - add a10, a10, a12 - - l8ui a15, a7, 1 // green - movi.n a14, 0xfc - and a13, a15, a14 - slli a12, a13, 3 - add a12, a10, a12 // a12 = 16-bit color - - slli a10, a12, 16 - movi.n a13, 0xFFFF0000 - and a10, a10, a13 - or a10, a10, a12 // a10 = 32-bit color (16bit + (16bit << 16)) - - movi.n a8, 0x3 // a8 = 0x3, dest_buff align mask - sub a6, a6, a11 // dest_stride = dest_stride - dest_w_bytes - - // cache init - // Prepare main loop length and dest_w_bytes - srli a9, a4, 4 // a9 = loop_len = dest_w / 8, calculate main loop_len for original dest_w - slli a11, a4, 1 // a11 = dest_w_bytes = sizeof(uint16_t) * dest_w - addi a4, a4, -1 // a4-- (decrement a4) - s32i.n a9, a1, 0 // cache.orig.loop_len - s32i.n a11, a1, 4 // cache.orig.dest_w_bytes - - // Prepare decreased main loop length and dest_w_bytes - srli a9, a4, 4 // a9 = loop_len = dest_w / 8, calculate main loop_len for dest_w - 1 - slli a11, a4, 1 // a11 = dest_w_bytes = sizeof(uint16_t) * (dest_w - 1) - s32i.n a9, a1, 8 // cache.decr.loop_len - s32i.n a11, a1, 12 // cache.decr.dest_w_bytes - and a7, a8, a3 // a7 = dest_buff AND 0x3 (chck if the address is 4-byte aligned) - - .outer_loop: - - // Check if the des_buff is 2-byte aligned - beqz a7, _dest_buff_2_byte_aligned // branch if a7 is equal to zero - s16i a12, a3, 0 // save 16 bits from 16-bit color a12 to dest_buff a3, offset 0 - l32i.n a9, a1, 8 // a9 = load cache.decr.loop_len - l32i.n a11, a1, 12 // a11 = load cache.decr.dest_w_bytes - addi.n a3, a3, 2 // increment dest_buff pointer by 2 - j _dest_buff_unaligned - _dest_buff_2_byte_aligned: - - l32i.n a9, a1, 0 // a11 = load cache.orig.loop_len - l32i.n a11, a1, 4 // a11 = load cache.orig.dest_w_bytes - - _dest_buff_unaligned: - - // Run main loop which sets 16 bytes in one loop run - loopnez a9, ._main_loop - s32i.n a10, a3, 0 // save 32 bits from 32-bit color a10 to dest_buff a3, offset 0 - s32i.n a10, a3, 4 // save 32 bits from 32-bit color a10 to dest_buff a3, offset 4 - s32i.n a10, a3, 8 // save 32 bits from 32-bit color a10 to dest_buff a3, offset 8 - s32i.n a10, a3, 12 // save 32 bits from 32-bit color a10 to dest_buff a3, offset 12 - s32i.n a10, a3, 16 // save 32 bits from 32-bit color a10 to dest_buff a3, offset 16 - s32i.n a10, a3, 20 // save 32 bits from 32-bit color a10 to dest_buff a3, offset 20 - s32i.n a10, a3, 24 // save 32 bits from 32-bit color a10 to dest_buff a3, offset 24 - s32i.n a10, a3, 28 // save 32 bits from 32-bit color a10 to dest_buff a3, offset 28 - addi.n a3, a3, 32 // increment dest_buff pointer by 32 - ._main_loop: - - // Finish the remaining bytes out of the loop - // Check modulo 8 of the dest_w_bytes, if - then set 16 bytes - bbci a11, 4, _mod_16_check // branch if 2-nd bit of dest_w_bytes is clear - s32i.n a10, a3, 0 // save 32 bits from 32-bit color a10 to dest_buff a3, offset 0 - s32i.n a10, a3, 4 // save 32 bits from 32-bit color a10 to dest_buff a3, offset 4 - s32i.n a10, a3, 8 // save 32 bits from 32-bit color a10 to dest_buff a3, offset 8 - s32i.n a10, a3, 12 // save 32 bits from 32-bit color a10 to dest_buff a3, offset 12 - addi.n a3, a3, 16 // increment dest_buff pointer by 16 - _mod_16_check: - - // Finish the remaining bytes out of the loop - // Check modulo 8 of the dest_w_bytes, if - then set 8 bytes - bbci a11, 3, _mod_8_check // branch if 2-nd bit of dest_w_bytes is clear - s32i.n a10, a3, 0 // save 32 bits from 32-bit color a10 to dest_buff a3, offset 0 - s32i.n a10, a3, 4 // save 32 bits from 32-bit color a10 to dest_buff a3, offset 4 - addi.n a3, a3, 8 // increment dest_buff pointer by 8 bytes - _mod_8_check: - - // Check modulo 4 of the dest_w_bytes, if - then set 4 bytes - bbci a11, 2, _mod_4_check // branch if 2-nd bit of dest_w_bytes is clear - s32i.n a10, a3, 0 // save 32 bits from 32-bit color a10 to dest_buff a3, offset 0 - addi.n a3, a3, 4 // increment dest_buff pointer by 4 - _mod_4_check: - - // Check modulo 2 of the dest_w_bytes, if - then set 2 bytes - bbci a11, 1, _mod_2_check // branch if 1-st bit of dest_w_bytes is clear - s16i a12, a3, 0 // save 16 bits from 16-bit color a12 to dest_buff a3, offset 0 - addi.n a3, a3, 2 // increment dest_buff pointer by 2 bytes - _mod_2_check: - - add a3, a3, a6 // dest_buff + dest_stride - addi.n a5, a5, -1 // decrease the outer loop - and a7, a8, a3 // a7 = dest_buff AND 0x3 (chck if the address is 4-byte aligned) - bnez a5, .outer_loop - - movi.n a2, 1 // return LV_RESULT_OK = 1 - retw.n // return diff --git a/libs/lv_screenshot/src/lv_screenshot.c b/libs/lv_screenshot/src/lv_screenshot.c index f8005cf6..e93b2798 100644 --- a/libs/lv_screenshot/src/lv_screenshot.c +++ b/libs/lv_screenshot/src/lv_screenshot.c @@ -3,39 +3,36 @@ #include "save_bmp.h" #include "save_png.h" -static void data_pre_processing(lv_draw_buf_t* snapshot, uint16_t bpp, lv_100ask_screenshot_sv_t screenshot_sv); +static void data_pre_processing(lv_image_dsc_t* snapshot, uint16_t bpp, lv_100ask_screenshot_sv_t screenshot_sv); bool lv_screenshot_create(lv_obj_t* obj, lv_color_format_t cf, lv_100ask_screenshot_sv_t screenshot_sv, const char* filename) { - lv_draw_buf_t* snapshot = lv_snapshot_take(obj, cf); - int32_t width = lv_obj_get_width(obj); - int32_t height = lv_obj_get_height(obj); + lv_image_dsc_t* snapshot = lv_snapshot_take(obj, cf); if (snapshot) { data_pre_processing(snapshot, LV_COLOR_DEPTH, screenshot_sv); if (screenshot_sv == LV_100ASK_SCREENSHOT_SV_PNG) { if (LV_COLOR_DEPTH == 16) { - lv_screenshot_save_png_file(snapshot->data, width, height, 24, filename); + lv_screenshot_save_png_file(snapshot->data, snapshot->header.w, snapshot->header.h, 24, filename); } else if (LV_COLOR_DEPTH == 32) { - lv_screenshot_save_png_file(snapshot->data, width, height, 32, filename); + lv_screenshot_save_png_file(snapshot->data, snapshot->header.w, snapshot->header.h, 32, filename); } } else if (screenshot_sv == LV_100ASK_SCREENSHOT_SV_BMP) { if (LV_COLOR_DEPTH == 16) { - lve_screenshot_save_bmp_file(snapshot->data, width, height, 24, filename); + lve_screenshot_save_bmp_file(snapshot->data, snapshot->header.w, snapshot->header.h, 24, filename); } else if (LV_COLOR_DEPTH == 32) { - lve_screenshot_save_bmp_file(snapshot->data, width, height, 32, filename); + lve_screenshot_save_bmp_file(snapshot->data, snapshot->header.w, snapshot->header.h, 32, filename); } } + lv_snapshot_free(snapshot); return true; } - lv_draw_buf_destroy(snapshot); - return false; } -static void data_pre_processing(lv_draw_buf_t* snapshot, uint16_t bpp, lv_100ask_screenshot_sv_t screenshot_sv) { +static void data_pre_processing(lv_image_dsc_t* snapshot, uint16_t bpp, lv_100ask_screenshot_sv_t screenshot_sv) { if (bpp == 16) { uint16_t rgb565_data = 0; uint32_t count = 0; diff --git a/libs/lv_screenshot/src/lv_screenshot.h b/libs/lv_screenshot/src/lv_screenshot.h index 4c7698ec..efaf72bf 100644 --- a/libs/lv_screenshot/src/lv_screenshot.h +++ b/libs/lv_screenshot/src/lv_screenshot.h @@ -3,6 +3,7 @@ #include "lvgl.h" #include + #ifdef __cplusplus extern "C" { #endif diff --git a/libs/lv_screenshot/src/save_bmp.c b/libs/lv_screenshot/src/save_bmp.c index e4f5cf75..29224417 100644 --- a/libs/lv_screenshot/src/save_bmp.c +++ b/libs/lv_screenshot/src/save_bmp.c @@ -1,5 +1,4 @@ #include "save_bmp.h" -#include // for memset() typedef struct tagBITMAPFILEHEADER { uint16_t bfType; diff --git a/libs/lvgl b/libs/lvgl index aa744634..09cb87cd 160000 --- a/libs/lvgl +++ b/libs/lvgl @@ -1 +1 @@ -Subproject commit aa7446344c6ec7631112ef031983ef24077e24d5 +Subproject commit 09cb87cdc6a0168a98bc0a3182a8439b13249ead diff --git a/sdkconfig.board.lilygo_tdeck b/sdkconfig.board.lilygo_tdeck index b7a670f8..9fd866b6 100644 --- a/sdkconfig.board.lilygo_tdeck +++ b/sdkconfig.board.lilygo_tdeck @@ -30,5 +30,6 @@ CONFIG_SPIRAM_MODE_OCT=y CONFIG_SPIRAM_SPEED_80M=y CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP=y # LVGL -CONFIG_LV_DEF_REFR_PERIOD=17 +CONFIG_LV_DISP_DEF_REFR_PERIOD=17 +CONFIG_LV_INDEV_DEF_READ_PERIOD=17 CONFIG_LV_DPI_DEF=139 diff --git a/sdkconfig.board.m5stack_core2 b/sdkconfig.board.m5stack_core2 index fc119770..d3d1c2f3 100644 --- a/sdkconfig.board.m5stack_core2 +++ b/sdkconfig.board.m5stack_core2 @@ -30,5 +30,6 @@ CONFIG_SPIRAM_MODE_OCT=y CONFIG_SPIRAM_SPEED_80M=y CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP=y # LVGL -CONFIG_LV_DEF_REFR_PERIOD=17 +CONFIG_LV_DISP_DEF_REFR_PERIOD=17 +CONFIG_LV_INDEV_DEF_READ_PERIOD=17 CONFIG_LV_DPI_DEF=139 diff --git a/sdkconfig.board.waveshare_s3_touch b/sdkconfig.board.waveshare_s3_touch index 7d074680..b7b586f5 100644 --- a/sdkconfig.board.waveshare_s3_touch +++ b/sdkconfig.board.waveshare_s3_touch @@ -29,5 +29,6 @@ CONFIG_ESP32S3_SPIRAM_SUPPORT=y CONFIG_SPIRAM_MODE_OCT=y CONFIG_SPIRAM_SPEED_80M=y # LVGL -CONFIG_LV_DEF_REFR_PERIOD=17 +CONFIG_LV_DISP_DEF_REFR_PERIOD=17 +CONFIG_LV_INDEV_DEF_READ_PERIOD=17 CONFIG_LV_DPI_DEF=216 diff --git a/sdkconfig.board.yellow_board b/sdkconfig.board.yellow_board index 621dbdfc..e673db09 100644 --- a/sdkconfig.board.yellow_board +++ b/sdkconfig.board.yellow_board @@ -25,5 +25,6 @@ CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y CONFIG_FLASHMODE_QIO=y # LVGL -CONFIG_LV_DEF_REFR_PERIOD=17 +CONFIG_LV_DISP_DEF_REFR_PERIOD=17 +CONFIG_LV_INDEV_DEF_READ_PERIOD=17 CONFIG_LV_DPI_DEF=160 diff --git a/sdkconfig.defaults b/sdkconfig.defaults index 94ffeece..de1f7945 100644 --- a/sdkconfig.defaults +++ b/sdkconfig.defaults @@ -20,4 +20,5 @@ CONFIG_PARTITION_TABLE_FILENAME="partitions.csv" # Hardware defaults CONFIG_TT_BOARD_CUSTOM=y # LVGL -CONFIG_LV_DEF_REFR_PERIOD=17 +CONFIG_LV_DISP_DEF_REFR_PERIOD=17 +CONFIG_LV_INDEV_DEF_READ_PERIOD=17 diff --git a/tactility-headless/src/sdcard.c b/tactility-headless/src/sdcard.c index 9811998a..d2b6a867 100644 --- a/tactility-headless/src/sdcard.c +++ b/tactility-headless/src/sdcard.c @@ -46,7 +46,11 @@ bool tt_sdcard_mount(const SdCard* sdcard) { .sdcard = sdcard }; sdcard_unlock(); - return (data.context != NULL); + if (data.context != NULL) { + return true; + } else { + return false; + } } else { TT_LOG_E(TAG, "Failed to lock"); return false; diff --git a/tactility/src/app_manifest.h b/tactility/src/app_manifest.h index e6467326..ee030b71 100644 --- a/tactility/src/app_manifest.h +++ b/tactility/src/app_manifest.h @@ -7,7 +7,7 @@ extern "C" { #endif // Forward declarations -typedef struct lv_obj_t lv_obj_t; +typedef struct _lv_obj_t lv_obj_t; typedef void* App; typedef enum { diff --git a/tactility/src/apps/gpio/gpio.c b/tactility/src/apps/gpio/gpio.c index 88520b07..dbef9a73 100644 --- a/tactility/src/apps/gpio/gpio.c +++ b/tactility/src/apps/gpio/gpio.c @@ -39,10 +39,9 @@ static void update_pin_widgets(Gpio* gpio) { for (int j = 0; j < GPIO_NUM_MAX; ++j) { int level = gpio->pin_states[j]; lv_obj_t* label = gpio->lv_pins[j]; - void* label_user_data = lv_obj_get_user_data(label); - // The user data stores the state, so we can avoid unnecessary updates - if ((void*)level != label_user_data) { - lv_obj_set_user_data(label, (void*)level); + // user_data stores the state, so we can avoid unnecessary updates + if ((void*)level != label->user_data) { + label->user_data = (void*)level; if (level == 0) { lv_obj_set_style_text_color(label, lv_color_black(), 0); } else { diff --git a/tactility/src/apps/screenshot/screenshot_ui.c b/tactility/src/apps/screenshot/screenshot_ui.c index 400053c6..874cb532 100644 --- a/tactility/src/apps/screenshot/screenshot_ui.c +++ b/tactility/src/apps/screenshot/screenshot_ui.c @@ -25,12 +25,12 @@ static void update_mode(ScreenshotUi* ui) { } static void on_mode_set(lv_event_t* event) { - ScreenshotUi* ui = (ScreenshotUi*)lv_event_get_user_data(event); + ScreenshotUi* ui = (ScreenshotUi*)event->user_data; update_mode(ui); } static void on_start_pressed(lv_event_t* event) { - ScreenshotUi* ui = lv_event_get_user_data(event); + ScreenshotUi* ui = event->user_data; if (tt_screenshot_is_started()) { TT_LOG_I(TAG, "Stop screenshot"); diff --git a/tactility/src/apps/system/files/files.c b/tactility/src/apps/system/files/files.c index 17abebc2..a617643a 100644 --- a/tactility/src/apps/system/files/files.c +++ b/tactility/src/apps/system/files/files.c @@ -47,7 +47,7 @@ static bool is_image_file(const char* filename) { static void update_views(FilesData* data); static void on_navigate_up_pressed(lv_event_t* event) { - FilesData* files_data = (FilesData*)lv_event_get_user_data(event); + FilesData* files_data = (FilesData*)event->user_data; if (strcmp(files_data->current_path, "/") != 0) { TT_LOG_I(TAG, "Navigating upwards"); char new_absolute_path[MAX_PATH_LENGTH]; @@ -62,13 +62,13 @@ static void on_exit_app_pressed(TT_UNUSED lv_event_t* event) { loader_stop_app(); } -static void on_file_pressed(lv_event_t* event) { - lv_event_code_t code = lv_event_get_code(event); +static void on_file_pressed(lv_event_t* e) { + lv_event_code_t code = lv_event_get_code(e); if (code == LV_EVENT_CLICKED) { - lv_obj_t* button = lv_event_get_current_target_obj(event); + lv_obj_t* button = e->current_target; FilesData* files_data = lv_obj_get_user_data(button); - struct dirent* dir_entry = lv_event_get_user_data(event); + struct dirent* dir_entry = e->user_data; TT_LOG_I(TAG, "Pressed %s %d", dir_entry->d_name, dir_entry->d_type); switch (dir_entry->d_type) { diff --git a/tactility/src/apps/wifi_connect/wifi_connect_view.c b/tactility/src/apps/wifi_connect/wifi_connect_view.c index d7968087..fe1e57c4 100644 --- a/tactility/src/apps/wifi_connect/wifi_connect_view.c +++ b/tactility/src/apps/wifi_connect/wifi_connect_view.c @@ -14,7 +14,7 @@ #define TAG "wifi_connect" static void on_connect(lv_event_t* event) { - WifiConnect* wifi = (WifiConnect*)lv_event_get_user_data(event); + WifiConnect* wifi = (WifiConnect*)event->user_data; WifiConnectView* view = &wifi->view; const char* ssid = lv_textarea_get_text(view->ssid_textarea); const char* password = lv_textarea_get_text(view->password_textarea); diff --git a/tactility/src/apps/wifi_manage/wifi_manage_view.c b/tactility/src/apps/wifi_manage/wifi_manage_view.c index a304e3a0..b921b533 100644 --- a/tactility/src/apps/wifi_manage/wifi_manage_view.c +++ b/tactility/src/apps/wifi_manage/wifi_manage_view.c @@ -15,27 +15,27 @@ static void on_enable_switch_changed(lv_event_t* event) { lv_obj_t* enable_switch = lv_event_get_target(event); if (code == LV_EVENT_VALUE_CHANGED) { bool is_on = lv_obj_has_state(enable_switch, LV_STATE_CHECKED); - WifiManageBindings* bindings = (WifiManageBindings*)lv_event_get_user_data(event); + WifiManageBindings* bindings = (WifiManageBindings*)event->user_data; bindings->on_wifi_toggled(is_on); } } static void on_disconnect_pressed(lv_event_t* event) { - WifiManageBindings* bindings = (WifiManageBindings*)lv_event_get_user_data(event); + WifiManageBindings* bindings = (WifiManageBindings*)event->user_data; bindings->on_disconnect(); } // region Secondary updates static void connect(lv_event_t* event) { - lv_obj_t* button = lv_event_get_current_target_obj(event); + lv_obj_t* button = event->current_target; // Assumes that the second child of the button is a label ... risky lv_obj_t* label = lv_obj_get_child(button, 1); // We get the SSID from the button label because it's safer than alloc'ing // our own and passing it as the event data const char* ssid = lv_label_get_text(label); TT_LOG_I(TAG, "Clicked AP: %s", ssid); - WifiManageBindings* bindings = (WifiManageBindings*)lv_event_get_user_data(event); + WifiManageBindings* bindings = (WifiManageBindings*)event->user_data; bindings->on_connect_ssid(ssid); } diff --git a/tactility/src/services/gui/gui.c b/tactility/src/services/gui/gui.c index 548d55d9..1a951489 100644 --- a/tactility/src/services/gui/gui.c +++ b/tactility/src/services/gui/gui.c @@ -25,7 +25,7 @@ void gui_loader_callback(const void* message, void* context) { LoaderEvent* event = (LoaderEvent*)message; if (event->type == LoaderEventTypeApplicationShowing) { App* app = event->app_showing.app; - const AppManifest* app_manifest = tt_app_get_manifest(app); + AppManifest* app_manifest = tt_app_get_manifest(app); gui_show_app(app, app_manifest->on_show, app_manifest->on_hide); } else if (event->type == LoaderEventTypeApplicationHiding) { gui_hide_app(); diff --git a/tactility/src/services/gui/gui_keyboard.c b/tactility/src/services/gui/gui_keyboard.c index cc853b96..dd239780 100644 --- a/tactility/src/services/gui/gui_keyboard.c +++ b/tactility/src/services/gui/gui_keyboard.c @@ -7,9 +7,8 @@ extern Gui* gui; static void show_keyboard(lv_event_t* event) { - lv_obj_t* target = lv_event_get_current_target_obj(event); - gui_keyboard_show(target); - lv_obj_scroll_to_view(target, LV_ANIM_ON); + gui_keyboard_show(event->current_target); + lv_obj_scroll_to_view(event->current_target, LV_ANIM_ON); } static void hide_keyboard(TT_UNUSED lv_event_t* event) { diff --git a/tactility/src/services/loader/loader.c b/tactility/src/services/loader/loader.c index 5871eb6b..f91e7580 100644 --- a/tactility/src/services/loader/loader.c +++ b/tactility/src/services/loader/loader.c @@ -262,7 +262,7 @@ static void loader_do_stop_app() { // Stop current app App app_to_stop = loader_singleton->app_stack[current_app_index]; - const AppManifest* manifest = tt_app_get_manifest(app_to_stop); + AppManifest* manifest = tt_app_get_manifest(app_to_stop); app_transition_to_state(app_to_stop, AppStateHiding); app_transition_to_state(app_to_stop, AppStateStopped); diff --git a/tactility/src/services/loader/loader.h b/tactility/src/services/loader/loader.h index 35cff42d..2827a2d1 100644 --- a/tactility/src/services/loader/loader.h +++ b/tactility/src/services/loader/loader.h @@ -39,7 +39,7 @@ typedef struct { } LoaderEventAppHiding; typedef struct { - const AppManifest* manifest; + AppManifest* manifest; } LoaderEventAppStopped; typedef struct { diff --git a/tactility/src/ui/statusbar.c b/tactility/src/ui/statusbar.c index 0779d26f..016831db 100644 --- a/tactility/src/ui/statusbar.c +++ b/tactility/src/ui/statusbar.c @@ -1,4 +1,3 @@ -#define LV_USE_PRIVATE_API 1 // For actual lv_obj_t declaration #include "statusbar.h" #include "mutex.h" diff --git a/tactility/src/ui/toolbar.c b/tactility/src/ui/toolbar.c index 2df623e9..28bc4b47 100644 --- a/tactility/src/ui/toolbar.c +++ b/tactility/src/ui/toolbar.c @@ -1,19 +1,10 @@ -#define LV_USE_PRIVATE_API 1 // For actual lv_obj_t declaration #include "toolbar.h" #include "services/loader/loader.h" #include "ui/spacer.h" #include "ui/style.h" -typedef struct { - lv_obj_t obj; - lv_obj_t* title_label; - lv_obj_t* close_button; - lv_obj_t* close_button_image; - lv_obj_t* action_container; - ToolbarAction* action_array[TOOLBAR_ACTION_LIMIT]; - uint8_t action_count; -} Toolbar; +#include "lvgl.h" static void toolbar_constructor(const lv_obj_class_t* class_p, lv_obj_t* obj); diff --git a/tactility/src/ui/toolbar.h b/tactility/src/ui/toolbar.h index bfb72583..7d873f52 100644 --- a/tactility/src/ui/toolbar.h +++ b/tactility/src/ui/toolbar.h @@ -20,6 +20,16 @@ typedef struct { void* _Nullable callback_context; } ToolbarAction; +typedef struct { + lv_obj_t obj; + lv_obj_t* title_label; + lv_obj_t* close_button; + lv_obj_t* close_button_image; + lv_obj_t* action_container; + ToolbarAction* action_array[TOOLBAR_ACTION_LIMIT]; + uint8_t action_count; +} Toolbar; + lv_obj_t* tt_toolbar_create(lv_obj_t* parent, const char* title); lv_obj_t* tt_toolbar_create_for_app(lv_obj_t* parent, App app); void tt_toolbar_set_title(lv_obj_t* obj, const char* title);