Revert to LVGL 9.0.0 (#64)
* Revert "Update ESP LCD Touch dependencies (#63)" This reverts commitcbd0355cec. * Revert "Updated board configs for LVGL changes (#62)" This reverts commit52d769854f. * Revert "Various updates (#60)" This reverts commita8a664703b.
This commit is contained in:
committed by
GitHub
parent
cbd0355cec
commit
62d30e8b7b
@@ -4,7 +4,6 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#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 */
|
||||
|
||||
@@ -4,27 +4,13 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#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;
|
||||
}
|
||||
|
||||
@@ -4,14 +4,10 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#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"
|
||||
|
||||
@@ -4,34 +4,25 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -4,27 +4,13 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -4,14 +4,10 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#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:
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user