Skip to content

Commit

Permalink
feat(lvgl_port): Used PPA for rotation on ESP32-P4 and added SW rotation
Browse files Browse the repository at this point in the history
  • Loading branch information
espzav committed Jul 22, 2024
1 parent 7f12e73 commit 43290a2
Show file tree
Hide file tree
Showing 14 changed files with 660 additions and 38 deletions.
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
10 changes: 8 additions & 2 deletions components/esp_lvgl_port/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,18 @@ endif()

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


set(PRIV_REQUIRES "esp_timer")
if("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_GREATER_EQUAL "5.3")
list(APPEND PRIV_REQUIRES "esp_driver_ppa")
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" "src/common/ppa/lcd_ppa.c"
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
6 changes: 2 additions & 4 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 Expand Up @@ -104,7 +102,7 @@ lv_display_t *lvgl_port_add_disp(const lvgl_port_display_cfg_t *disp_cfg);
* @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);
lv_display_t *lvgl_port_add_disp_dsi(lvgl_port_display_cfg_t *disp_cfg, const lvgl_port_display_dsi_cfg_t *dsi_cfg);

/**
* @brief Add RGB display handling to LVGL
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 && ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0))
#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

0 comments on commit 43290a2

Please sign in to comment.