Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(lvgl_port): Used PPA for rotation on ESP32-P4 and added SW rotation #352

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions bsp/esp32_p4_function_ev_board/esp32_p4_function_ev_board.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ static lv_indev_t *disp_indev = NULL;
#endif // (BSP_CONFIG_NO_GRAPHIC_LIB == 0)

sdmmc_card_t *bsp_sdcard = NULL; // Global uSD card handler
static esp_lcd_touch_handle_t tp; // LCD touch handle
static bool i2c_initialized = false;
static TaskHandle_t usb_host_task; // USB Host Library task

Expand Down Expand Up @@ -357,15 +356,14 @@ static lv_display_t *bsp_display_lcd_init(const bsp_display_cfg_t *cfg)
.mirror_x = true,
.mirror_y = true,
},
.color_format = LV_COLOR_FORMAT_RGB565,
.flags = {
.buff_dma = cfg->flags.buff_dma,
.buff_spiram = cfg->flags.buff_spiram,
#if LVGL_VERSION_MAJOR >= 9
.swap_bytes = (BSP_LCD_BIGENDIAN ? true : false),
#endif
#if LVGL_VERSION_MAJOR == 8
.sw_rotate = cfg->flags.sw_rotate, /* Only SW rotation is supported for 90° and 270° */
#endif
}
};

Expand All @@ -374,6 +372,7 @@ static lv_display_t *bsp_display_lcd_init(const bsp_display_cfg_t *cfg)

static lv_indev_t *bsp_display_indev_init(lv_display_t *disp)
{
esp_lcd_touch_handle_t tp;
BSP_ERROR_CHECK_RETURN_NULL(bsp_touch_new(NULL, &tp));
assert(tp);

Expand All @@ -395,6 +394,7 @@ lv_display_t *bsp_display_start(void)
.flags = {
.buff_dma = true,
.buff_spiram = false,
.sw_rotate = true,
}
};
return bsp_display_start_with_config(&cfg);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ esp_err_t bsp_sdcard_unmount(void);

#if (BSP_CONFIG_NO_GRAPHIC_LIB == 0)

#define BSP_LCD_DRAW_BUFF_SIZE (BSP_LCD_H_RES * 100) // Frame buffer size in pixels
#define BSP_LCD_DRAW_BUFF_SIZE (BSP_LCD_H_RES * 50) // Frame buffer size in pixels
#define BSP_LCD_DRAW_BUFF_DOUBLE (0)

/**
Expand Down
5 changes: 5 additions & 0 deletions components/esp_lvgl_port/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Changelog

## 2.3.0
- Fixed LVGL port for using with LVGL9 OS FreeRTOS enabled
- Added support for SW rotation in LVGL9
- Added support for PPA rotation in LVGL9 (available for ESP32P4)

## 2.2.2

### Fixes
Expand Down
12 changes: 10 additions & 2 deletions components/esp_lvgl_port/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,20 @@ endif()

set(PORT_PATH "src/${PORT_FOLDER}")


set(PRIV_REQUIRES "esp_timer")
set(PPA_PATH "")
if("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_GREATER_EQUAL "5.3")
list(APPEND PRIV_REQUIRES "esp_driver_ppa")
list(APPEND PPA_PATH "src/common/ppa/lcd_ppa.c")
endif()

idf_component_register(
SRCS "${PORT_PATH}/esp_lvgl_port.c" "${PORT_PATH}/esp_lvgl_port_disp.c"
SRCS "${PORT_PATH}/esp_lvgl_port.c" "${PORT_PATH}/esp_lvgl_port_disp.c" "${PPA_PATH}"
INCLUDE_DIRS "include"
PRIV_INCLUDE_DIRS "priv_include"
REQUIRES "esp_lcd"
PRIV_REQUIRES "esp_timer")
PRIV_REQUIRES "${PRIV_REQUIRES}")

set(ADD_SRCS "")
set(ADD_LIBS "")
Expand Down
4 changes: 2 additions & 2 deletions components/esp_lvgl_port/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -265,8 +265,8 @@ Display rotation can be changed at runtime.
lv_disp_set_rotation(disp_handle, LV_DISP_ROT_90);
```

> [!WARNING]
> Software rotation is available only in LVGL 8.
> [!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.
Expand Down
2 changes: 1 addition & 1 deletion components/esp_lvgl_port/idf_component.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
version: "2.2.2"
version: "2.3.0"
description: ESP LVGL port
url: https://github.com/espressif/esp-bsp/tree/master/components/esp_lvgl_port
dependencies:
Expand Down
4 changes: 1 addition & 3 deletions components/esp_lvgl_port/include/esp_lvgl_port_disp.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,7 @@ typedef struct {
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 */
#if LVGL_VERSION_MAJOR == 8
unsigned int sw_rotate: 1; /*!< Use software rotation (slower) */
#endif
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
Expand Down
199 changes: 199 additions & 0 deletions components/esp_lvgl_port/src/common/ppa/lcd_ppa.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/


#include <string.h>
#include "esp_err.h"
#include "esp_check.h"
#include "esp_heap_caps.h"
#include "soc/soc_caps.h"
#include "lcd_ppa.h"

#define PPA_LCD_ENABLE_CB 0

#if SOC_PPA_SUPPORTED
#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))

struct lcd_ppa_t {
uint8_t *buffer;
uint32_t buffer_size;
ppa_client_handle_t srm_handle;
uint32_t color_type_id;
};

static const char *TAG = "PPA";
/*******************************************************************************
* Function definitions
*******************************************************************************/
#if PPA_LCD_ENABLE_CB
static bool _lcd_ppa_callback(ppa_client_handle_t ppa_client, ppa_event_data_t *event_data, void *user_data);
#endif
/*******************************************************************************
* Public API functions
*******************************************************************************/

lcd_ppa_handle_t esp_lcd_ppa_create(const lcd_ppa_cfg_t *cfg)
{
esp_err_t ret = ESP_OK;
assert(cfg != NULL);

lcd_ppa_t *ppa_ctx = malloc(sizeof(lcd_ppa_t));
ESP_GOTO_ON_FALSE(ppa_ctx, ESP_ERR_NO_MEM, err, TAG, "Not enough memory for PPA context allocation!");
memset(ppa_ctx, 0, sizeof(lcd_ppa_t));

uint32_t buffer_caps = 0;
if (cfg->flags.buff_dma) {
buffer_caps |= MALLOC_CAP_DMA;
}
if (cfg->flags.buff_spiram) {
buffer_caps |= MALLOC_CAP_SPIRAM;
}
if (buffer_caps == 0) {
buffer_caps |= MALLOC_CAP_DEFAULT;
}

ppa_ctx->buffer_size = ALIGN_UP(cfg->buffer_size, 64);
ppa_ctx->buffer = heap_caps_aligned_calloc(64, ppa_ctx->buffer_size, sizeof(uint8_t), buffer_caps);
assert(ppa_ctx->buffer != NULL);

ppa_client_config_t ppa_client_config = {
.oper_type = PPA_OPERATION_SRM,
};
ESP_GOTO_ON_ERROR(ppa_register_client(&ppa_client_config, &ppa_ctx->srm_handle), err, TAG, "Error when registering PPA client!");

#if PPA_LCD_ENABLE_CB
ppa_event_callbacks_t ppa_cbs = {
.on_trans_done = _lcd_ppa_callback,
};
ESP_GOTO_ON_ERROR(ppa_client_register_event_callbacks(ppa_ctx->srm_handle, &ppa_cbs), err, TAG, "Error when registering PPA callbacks!");
#endif

ppa_ctx->color_type_id = COLOR_TYPE_ID(cfg->color_space, cfg->pixel_format);

err:
if (ret != ESP_OK) {
if (ppa_ctx->buffer) {
free(ppa_ctx->buffer);
}
if (ppa_ctx) {
free(ppa_ctx);
}
}

return ppa_ctx;
}

void esp_lcd_ppa_delete(lcd_ppa_handle_t handle)
{
lcd_ppa_t *ppa_ctx = (lcd_ppa_t *)handle;
assert(ppa_ctx != NULL);

if (ppa_ctx->buffer) {
free(ppa_ctx->buffer);
}

ppa_unregister_client(ppa_ctx->srm_handle);

free(ppa_ctx);
}

uint8_t *esp_lcd_ppa_get_output_buffer(lcd_ppa_handle_t handle)
{
lcd_ppa_t *ppa_ctx = (lcd_ppa_t *)handle;
assert(ppa_ctx != NULL);
return ppa_ctx->buffer;
}

esp_err_t esp_lcd_ppa_rotate(lcd_ppa_handle_t handle, lcd_ppa_disp_rotate_t *rotate_cfg)
{
lcd_ppa_t *ppa_ctx = (lcd_ppa_t *)handle;
assert(ppa_ctx != NULL);
assert(rotate_cfg != NULL);
const int w = rotate_cfg->area.x2 - rotate_cfg->area.x1 + 1;
const int h = rotate_cfg->area.y2 - rotate_cfg->area.y1 + 1;

/* Set dimension by screen size and rotation */
int out_w = w;
int out_h = h;

int x1 = rotate_cfg->area.x1;
int x2 = rotate_cfg->area.x2;
int y1 = rotate_cfg->area.y1;
int y2 = rotate_cfg->area.y2;

/* Rotate coordinates */
switch (rotate_cfg->rotation) {
case PPA_SRM_ROTATION_ANGLE_0:
break;
case PPA_SRM_ROTATION_ANGLE_90:
out_w = h;
out_h = w;
x1 = rotate_cfg->area.y1;
x2 = rotate_cfg->area.y2;
y1 = rotate_cfg->disp_size.hres - rotate_cfg->area.x2;
y2 = rotate_cfg->disp_size.hres - rotate_cfg->area.x1;
break;
case PPA_SRM_ROTATION_ANGLE_180:
x1 = rotate_cfg->disp_size.hres - rotate_cfg->area.x2 - 1;
x2 = rotate_cfg->disp_size.hres - rotate_cfg->area.x1 - 1;
y1 = rotate_cfg->disp_size.vres - rotate_cfg->area.y2;
y2 = rotate_cfg->disp_size.vres - rotate_cfg->area.y1;
break;
case PPA_SRM_ROTATION_ANGLE_270:
out_w = h;
out_h = w;
x1 = rotate_cfg->disp_size.vres - rotate_cfg->area.y2 - 1;
x2 = rotate_cfg->disp_size.vres - rotate_cfg->area.y1 - 1;
y1 = rotate_cfg->area.x1;
y2 = rotate_cfg->area.x2;
break;
}
/* Return new coordinates */
rotate_cfg->area.x1 = x1;
rotate_cfg->area.x2 = x2;
rotate_cfg->area.y1 = y1;
rotate_cfg->area.y2 = y2;

/* Prepare Operation */
ppa_srm_oper_config_t srm_oper_config = {
.in.buffer = rotate_cfg->in_buff,
.in.pic_w = w,
.in.pic_h = h,
.in.block_w = w,
.in.block_h = h,
.in.block_offset_x = 0,
.in.block_offset_y = 0,
.in.srm_cm = ppa_ctx->color_type_id,

.out.buffer = ppa_ctx->buffer,
.out.buffer_size = ppa_ctx->buffer_size,
.out.pic_w = out_w,
.out.pic_h = out_h,
.out.block_offset_x = 0,
.out.block_offset_y = 0,
.out.srm_cm = ppa_ctx->color_type_id,

.rotation_angle = rotate_cfg->rotation,
.scale_x = 1.0,
.scale_y = 1.0,

.byte_swap = rotate_cfg->swap_bytes,

.mode = rotate_cfg->ppa_mode,
.user_data = rotate_cfg->user_data,
};

return ppa_do_scale_rotate_mirror(ppa_ctx->srm_handle, &srm_oper_config);
}

#if PPA_LCD_ENABLE_CB
static bool _lcd_ppa_callback(ppa_client_handle_t ppa_client, ppa_event_data_t *event_data, void *user_data)
{
return false;
}
#endif

#endif
Loading
Loading