修复了屏幕颜色异常问题
This commit is contained in:
@@ -63,6 +63,19 @@ target_add_binary_data(${COMPONENT_LIB}
|
||||
BINARY
|
||||
)
|
||||
|
||||
foreach(lcd_rle_asset
|
||||
jichubiaoqing0
|
||||
jichubiaoqing1
|
||||
jichubiaoqing2
|
||||
muyu0
|
||||
muyu1
|
||||
muyu2)
|
||||
target_add_binary_data(${COMPONENT_LIB}
|
||||
"assets/lcd/${lcd_rle_asset}.rle"
|
||||
BINARY
|
||||
)
|
||||
endforeach()
|
||||
|
||||
set(platform_audio_prompt_src_dir "${CMAKE_CURRENT_SOURCE_DIR}/assets/audio_prompts")
|
||||
set(platform_asset_image_dir "${CMAKE_CURRENT_BINARY_DIR}/asset_image")
|
||||
set(platform_asset_stage_stamp "${CMAKE_CURRENT_BINARY_DIR}/asset_image.stamp")
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 248 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 249 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 250 KiB |
@@ -361,6 +361,7 @@ typedef struct {
|
||||
size_t frame_order_count;
|
||||
uint16_t repeat_count;
|
||||
uint32_t frame_ms;
|
||||
uint32_t duration_ms;
|
||||
} platform_lcd_presentation_request_t;
|
||||
|
||||
/**
|
||||
|
||||
@@ -34,6 +34,7 @@ typedef struct {
|
||||
#define LCD_DIRECT_DEFAULT_ICON_COUNT 5U
|
||||
|
||||
const lcd_direct_image_t *lcd_direct_default_image(void);
|
||||
const lcd_direct_image_t *lcd_direct_asset_frame(const char *asset_dir, uint8_t frame_index);
|
||||
const lcd_direct_icon_t *lcd_direct_icon(uint16_t icon_id);
|
||||
const lcd_direct_icon_draw_t *lcd_direct_default_icon_sequence(size_t *out_count);
|
||||
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
|
||||
#define LCD_CMD_MADCTL 0x36
|
||||
#define LCD_CMD_RAMCTRL 0xB0
|
||||
#define LCD_RAMCTRL_LE_BIT (1U << 3)
|
||||
|
||||
static const char *TAG = "lcd_direct";
|
||||
|
||||
@@ -43,8 +42,11 @@ typedef struct {
|
||||
bool interrupt_current;
|
||||
bool return_to_idle;
|
||||
char asset_dir[PLATFORM_LCD_PRESENTATION_ASSET_DIR_MAX];
|
||||
uint8_t frame_order[PLATFORM_LCD_PRESENTATION_FRAME_ORDER_MAX];
|
||||
size_t frame_order_count;
|
||||
uint16_t repeat_count;
|
||||
uint32_t frame_ms;
|
||||
uint32_t duration_ms;
|
||||
} lcd_direct_request_t;
|
||||
|
||||
typedef struct {
|
||||
@@ -84,6 +86,8 @@ static uint32_t s_completion_count;
|
||||
static portMUX_TYPE s_state_lock = portMUX_INITIALIZER_UNLOCKED;
|
||||
static uint16_t s_line_buffer[LCD_DIRECT_PIXELS_PER_TRANSFER];
|
||||
|
||||
static void lcd_direct_signal_completion(void);
|
||||
|
||||
static uint16_t lcd_direct_swap_color(uint16_t color)
|
||||
{
|
||||
#if CONFIG_TQ_SCREEN_SWAP_COLOR_BYTES
|
||||
@@ -166,11 +170,7 @@ static esp_err_t lcd_direct_panel_init(void)
|
||||
#else
|
||||
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
|
||||
#endif
|
||||
#if CONFIG_TQ_SCREEN_SWAP_COLOR_BYTES
|
||||
.data_endian = LCD_RGB_DATA_ENDIAN_LITTLE,
|
||||
#else
|
||||
.data_endian = LCD_RGB_DATA_ENDIAN_BIG,
|
||||
#endif
|
||||
.bits_per_pixel = 16,
|
||||
};
|
||||
ESP_RETURN_ON_ERROR(esp_lcd_new_panel_st7789(s_panel_io, &panel_config, &s_panel),
|
||||
@@ -207,9 +207,6 @@ static esp_err_t lcd_direct_panel_init(void)
|
||||
madctl |= 0x08;
|
||||
#endif
|
||||
uint8_t ramctrl[] = {0x00, 0xF0};
|
||||
#if CONFIG_TQ_SCREEN_SWAP_COLOR_BYTES
|
||||
ramctrl[1] |= LCD_RAMCTRL_LE_BIT;
|
||||
#endif
|
||||
ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(s_panel_io, LCD_CMD_MADCTL, &madctl, 1),
|
||||
TAG,
|
||||
"panel MADCTL failed");
|
||||
@@ -333,25 +330,6 @@ static void lcd_direct_overlay_icons(uint16_t *pixel_buffer,
|
||||
}
|
||||
}
|
||||
|
||||
static void lcd_direct_overlay_boot_marker(uint16_t *pixel_buffer, uint16_t row_start, uint16_t row_count)
|
||||
{
|
||||
const uint16_t marker_color = lcd_direct_swap_color(0xFFFF);
|
||||
const uint16_t row_end = row_start + row_count;
|
||||
|
||||
for (uint16_t y = row_start; y < row_end; ++y) {
|
||||
uint16_t local_y = y - row_start;
|
||||
for (uint16_t x = 0; x < LCD_DIRECT_WIDTH; ++x) {
|
||||
const bool border = y < 2U || y >= (LCD_DIRECT_HEIGHT - 2U) ||
|
||||
x < 2U || x >= (LCD_DIRECT_WIDTH - 2U);
|
||||
const bool center_line = (x >= 158U && x <= 161U && y >= 100U && y <= 140U) ||
|
||||
(y >= 118U && y <= 121U && x >= 140U && x <= 180U);
|
||||
if (border || center_line) {
|
||||
pixel_buffer[(uint32_t)local_y * LCD_DIRECT_WIDTH + x] = marker_color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static esp_err_t lcd_direct_draw_rle_image(const lcd_direct_image_t *image,
|
||||
const lcd_direct_icon_draw_t *icons,
|
||||
size_t icon_count)
|
||||
@@ -399,7 +377,6 @@ static esp_err_t lcd_direct_draw_rle_image(const lcd_direct_image_t *image,
|
||||
}
|
||||
|
||||
lcd_direct_overlay_icons(s_line_buffer, row_start, row_count, icons, icon_count);
|
||||
lcd_direct_overlay_boot_marker(s_line_buffer, row_start, row_count);
|
||||
ESP_RETURN_ON_ERROR(lcd_direct_draw_rows(row_start, row_count),
|
||||
TAG,
|
||||
"write image pixels failed");
|
||||
@@ -408,12 +385,169 @@ static esp_err_t lcd_direct_draw_rle_image(const lcd_direct_image_t *image,
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t lcd_direct_draw_default_image(void)
|
||||
static esp_err_t lcd_direct_draw_asset_sequence_once(const lcd_direct_request_t *request)
|
||||
{
|
||||
size_t icon_count = 0;
|
||||
const lcd_direct_icon_draw_t *icons = lcd_direct_default_icon_sequence(&icon_count);
|
||||
ESP_LOGI(TAG, "Drawing default LCD image icons=%u", (unsigned)icon_count);
|
||||
return lcd_direct_draw_rle_image(lcd_direct_default_image(), icons, icon_count);
|
||||
ESP_RETURN_ON_FALSE(request != NULL,
|
||||
ESP_ERR_INVALID_ARG,
|
||||
TAG,
|
||||
"invalid asset request");
|
||||
|
||||
const size_t frame_count = request->frame_order_count > 0U ? request->frame_order_count : 1U;
|
||||
for (size_t i = 0; i < frame_count; ++i) {
|
||||
bool stop = false;
|
||||
portENTER_CRITICAL(&s_state_lock);
|
||||
stop = s_stop_requested || s_pending_valid;
|
||||
portEXIT_CRITICAL(&s_state_lock);
|
||||
if (stop) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
const uint8_t frame_index = request->frame_order_count > 0U ? request->frame_order[i] : (uint8_t)i;
|
||||
const lcd_direct_image_t *frame = lcd_direct_asset_frame(request->asset_dir, frame_index);
|
||||
ESP_RETURN_ON_FALSE(frame != NULL,
|
||||
ESP_ERR_NOT_FOUND,
|
||||
TAG,
|
||||
"LCD asset frame not found asset=%s frame=%u",
|
||||
request->asset_dir,
|
||||
(unsigned)frame_index);
|
||||
|
||||
ESP_RETURN_ON_ERROR(lcd_direct_draw_rle_image(frame, NULL, 0),
|
||||
TAG,
|
||||
"draw asset frame failed");
|
||||
|
||||
const uint32_t frame_ms = request->frame_ms > 0U ? request->frame_ms : 100U;
|
||||
vTaskDelay(pdMS_TO_TICKS(frame_ms));
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t lcd_direct_draw_asset_sequence_for_duration(const lcd_direct_request_t *request,
|
||||
TickType_t start_tick,
|
||||
TickType_t duration_ticks)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(request != NULL,
|
||||
ESP_ERR_INVALID_ARG,
|
||||
TAG,
|
||||
"invalid timed asset request");
|
||||
|
||||
const size_t frame_count = request->frame_order_count > 0U ? request->frame_order_count : 1U;
|
||||
while ((xTaskGetTickCount() - start_tick) < duration_ticks) {
|
||||
for (size_t i = 0; i < frame_count; ++i) {
|
||||
bool stop = false;
|
||||
portENTER_CRITICAL(&s_state_lock);
|
||||
stop = s_stop_requested || s_pending_valid;
|
||||
portEXIT_CRITICAL(&s_state_lock);
|
||||
if (stop) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
const uint8_t frame_index = request->frame_order_count > 0U ? request->frame_order[i] : (uint8_t)i;
|
||||
const lcd_direct_image_t *frame = lcd_direct_asset_frame(request->asset_dir, frame_index);
|
||||
ESP_RETURN_ON_FALSE(frame != NULL,
|
||||
ESP_ERR_NOT_FOUND,
|
||||
TAG,
|
||||
"LCD asset frame not found asset=%s frame=%u",
|
||||
request->asset_dir,
|
||||
(unsigned)frame_index);
|
||||
|
||||
ESP_RETURN_ON_ERROR(lcd_direct_draw_rle_image(frame, NULL, 0),
|
||||
TAG,
|
||||
"draw timed asset frame failed");
|
||||
|
||||
const TickType_t now = xTaskGetTickCount();
|
||||
const TickType_t elapsed_ticks = now - start_tick;
|
||||
if (elapsed_ticks >= duration_ticks) {
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
const uint32_t frame_ms = request->frame_ms > 0U ? request->frame_ms : 100U;
|
||||
const TickType_t frame_ticks = pdMS_TO_TICKS(frame_ms);
|
||||
const TickType_t remaining_ticks = duration_ticks - elapsed_ticks;
|
||||
vTaskDelay(frame_ticks < remaining_ticks ? frame_ticks : remaining_ticks);
|
||||
}
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t lcd_direct_play_asset_sequence(const lcd_direct_request_t *request)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(request != NULL,
|
||||
ESP_ERR_INVALID_ARG,
|
||||
TAG,
|
||||
"invalid asset sequence");
|
||||
|
||||
if (request->asset_dir[0] == '\0' ||
|
||||
lcd_direct_asset_frame(request->asset_dir,
|
||||
request->frame_order_count > 0U ? request->frame_order[0] : 0U) == NULL) {
|
||||
ESP_LOGW(TAG, "LCD asset sequence unavailable, fallback to basic face asset=%s", request->asset_dir);
|
||||
const lcd_direct_request_t fallback = {
|
||||
.kind = PLATFORM_LCD_PRESENTATION_ASSET_SEQUENCE,
|
||||
.asset_dir = "jichubiaoqing",
|
||||
.frame_order = {0, 1, 2},
|
||||
.frame_order_count = 3,
|
||||
.repeat_count = 1,
|
||||
.frame_ms = 100,
|
||||
};
|
||||
esp_err_t fallback_err = lcd_direct_draw_asset_sequence_once(&fallback);
|
||||
if (fallback_err == ESP_OK && request->repeat_count > 0U) {
|
||||
lcd_direct_signal_completion();
|
||||
}
|
||||
return fallback_err;
|
||||
}
|
||||
|
||||
if (request->duration_ms > 0U) {
|
||||
const TickType_t start_tick = xTaskGetTickCount();
|
||||
const TickType_t duration_ticks = pdMS_TO_TICKS(request->duration_ms);
|
||||
esp_err_t err = lcd_direct_draw_asset_sequence_for_duration(request, start_tick, duration_ticks);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
lcd_direct_signal_completion();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
uint16_t remaining = request->repeat_count;
|
||||
do {
|
||||
esp_err_t err = lcd_direct_draw_asset_sequence_once(request);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
if (request->repeat_count > 0U) {
|
||||
remaining--;
|
||||
}
|
||||
} while (request->repeat_count == 0U || remaining > 0U);
|
||||
|
||||
lcd_direct_signal_completion();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t lcd_direct_play_basic_face_until_pending(void)
|
||||
{
|
||||
const lcd_direct_request_t request = {
|
||||
.kind = PLATFORM_LCD_PRESENTATION_ASSET_SEQUENCE,
|
||||
.asset_dir = "jichubiaoqing",
|
||||
.frame_order = {0, 1, 2},
|
||||
.frame_order_count = 3,
|
||||
.repeat_count = 0,
|
||||
.frame_ms = 100,
|
||||
};
|
||||
|
||||
while (true) {
|
||||
bool stop = false;
|
||||
portENTER_CRITICAL(&s_state_lock);
|
||||
stop = s_stop_requested || s_pending_valid;
|
||||
portEXIT_CRITICAL(&s_state_lock);
|
||||
if (stop) {
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t err = lcd_direct_draw_asset_sequence_once(&request);
|
||||
if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void lcd_direct_signal_completion(void)
|
||||
@@ -486,8 +620,6 @@ void lcd_direct_start_render_loop(void)
|
||||
portEXIT_CRITICAL(&s_state_lock);
|
||||
|
||||
ESP_LOGI(TAG, "Direct LCD render loop started");
|
||||
esp_err_t default_draw_err = lcd_direct_draw_default_image();
|
||||
ESP_LOGI(TAG, "Direct LCD default image draw result=%s", esp_err_to_name(default_draw_err));
|
||||
|
||||
while (true) {
|
||||
bool stop = false;
|
||||
@@ -503,13 +635,33 @@ void lcd_direct_start_render_loop(void)
|
||||
if (xSemaphoreTake(s_lock, pdMS_TO_TICKS(1000)) == pdTRUE) {
|
||||
esp_err_t draw_err = ESP_OK;
|
||||
if (request.kind == PLATFORM_LCD_PRESENTATION_IDLE) {
|
||||
draw_err = lcd_direct_draw_default_image();
|
||||
draw_err = lcd_direct_play_basic_face_until_pending();
|
||||
} else if (request.kind == PLATFORM_LCD_PRESENTATION_ASSET_SEQUENCE) {
|
||||
draw_err = lcd_direct_play_asset_sequence(&request);
|
||||
if (draw_err == ESP_OK && request.return_to_idle) {
|
||||
lcd_direct_request_t idle = {
|
||||
.kind = PLATFORM_LCD_PRESENTATION_IDLE,
|
||||
};
|
||||
portENTER_CRITICAL(&s_state_lock);
|
||||
s_pending = idle;
|
||||
s_pending_valid = true;
|
||||
portEXIT_CRITICAL(&s_state_lock);
|
||||
}
|
||||
} else {
|
||||
draw_err = lcd_direct_draw_test_pattern(&request);
|
||||
}
|
||||
xSemaphoreGive(s_lock);
|
||||
if (draw_err == ESP_OK && request.repeat_count > 0U) {
|
||||
lcd_direct_signal_completion();
|
||||
if (draw_err != ESP_OK && draw_err != ESP_ERR_INVALID_STATE) {
|
||||
ESP_LOGW(TAG, "LCD presentation draw failed: %s", esp_err_to_name(draw_err));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (xSemaphoreTake(s_lock, pdMS_TO_TICKS(1000)) == pdTRUE) {
|
||||
esp_err_t idle_err = lcd_direct_play_basic_face_until_pending();
|
||||
xSemaphoreGive(s_lock);
|
||||
if (idle_err != ESP_OK && idle_err != ESP_ERR_INVALID_STATE) {
|
||||
ESP_LOGW(TAG, "LCD idle draw failed: %s", esp_err_to_name(idle_err));
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -587,10 +739,18 @@ esp_err_t lcd_direct_request_presentation(const platform_lcd_presentation_reques
|
||||
.return_to_idle = request->return_to_idle,
|
||||
.repeat_count = request->repeat_count,
|
||||
.frame_ms = request->frame_ms,
|
||||
.duration_ms = request->duration_ms,
|
||||
};
|
||||
if (request->asset_dir != NULL) {
|
||||
strlcpy(copied.asset_dir, request->asset_dir, sizeof(copied.asset_dir));
|
||||
}
|
||||
if (request->frame_order != NULL && request->frame_order_count > 0U) {
|
||||
copied.frame_order_count = request->frame_order_count;
|
||||
if (copied.frame_order_count > PLATFORM_LCD_PRESENTATION_FRAME_ORDER_MAX) {
|
||||
copied.frame_order_count = PLATFORM_LCD_PRESENTATION_FRAME_ORDER_MAX;
|
||||
}
|
||||
memcpy(copied.frame_order, request->frame_order, copied.frame_order_count);
|
||||
}
|
||||
|
||||
TaskHandle_t task = NULL;
|
||||
portENTER_CRITICAL(&s_state_lock);
|
||||
|
||||
@@ -1,19 +1,79 @@
|
||||
/* Generated from D:\Code\chaowan\lcd(1)\lcd\lcd\main\eye_image.c buyunqian1. */
|
||||
#include "lcd_direct_assets.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
extern const uint8_t _binary_buyunqian1_rle_start[] asm("_binary_buyunqian1_rle_start");
|
||||
extern const uint8_t _binary_buyunqian1_rle_end[] asm("_binary_buyunqian1_rle_end");
|
||||
extern const uint8_t _binary_jichubiaoqing0_rle_start[] asm("_binary_jichubiaoqing0_rle_start");
|
||||
extern const uint8_t _binary_jichubiaoqing1_rle_start[] asm("_binary_jichubiaoqing1_rle_start");
|
||||
extern const uint8_t _binary_jichubiaoqing2_rle_start[] asm("_binary_jichubiaoqing2_rle_start");
|
||||
extern const uint8_t _binary_muyu0_rle_start[] asm("_binary_muyu0_rle_start");
|
||||
extern const uint8_t _binary_muyu1_rle_start[] asm("_binary_muyu1_rle_start");
|
||||
extern const uint8_t _binary_muyu2_rle_start[] asm("_binary_muyu2_rle_start");
|
||||
|
||||
static const lcd_direct_image_t s_default_image = {
|
||||
.runs = (const lcd_direct_rle_run_t *)_binary_buyunqian1_rle_start,
|
||||
.run_count = 72552U,
|
||||
};
|
||||
|
||||
static const lcd_direct_image_t s_basic_face_frames[] = {
|
||||
{
|
||||
.runs = (const lcd_direct_rle_run_t *)_binary_jichubiaoqing0_rle_start,
|
||||
.run_count = 5893U,
|
||||
},
|
||||
{
|
||||
.runs = (const lcd_direct_rle_run_t *)_binary_jichubiaoqing1_rle_start,
|
||||
.run_count = 4581U,
|
||||
},
|
||||
{
|
||||
.runs = (const lcd_direct_rle_run_t *)_binary_jichubiaoqing2_rle_start,
|
||||
.run_count = 3651U,
|
||||
},
|
||||
};
|
||||
|
||||
static const lcd_direct_image_t s_muyu_frames[] = {
|
||||
{
|
||||
.runs = (const lcd_direct_rle_run_t *)_binary_muyu0_rle_start,
|
||||
.run_count = 63459U,
|
||||
},
|
||||
{
|
||||
.runs = (const lcd_direct_rle_run_t *)_binary_muyu1_rle_start,
|
||||
.run_count = 63665U,
|
||||
},
|
||||
{
|
||||
.runs = (const lcd_direct_rle_run_t *)_binary_muyu2_rle_start,
|
||||
.run_count = 63894U,
|
||||
},
|
||||
};
|
||||
|
||||
const lcd_direct_image_t *lcd_direct_default_image(void)
|
||||
{
|
||||
return &s_default_image;
|
||||
}
|
||||
|
||||
const lcd_direct_image_t *lcd_direct_asset_frame(const char *asset_dir, uint8_t frame_index)
|
||||
{
|
||||
if (asset_dir == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (strcmp(asset_dir, "jichubiaoqing") == 0) {
|
||||
if (frame_index < sizeof(s_basic_face_frames) / sizeof(s_basic_face_frames[0])) {
|
||||
return &s_basic_face_frames[frame_index];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (strcmp(asset_dir, "muyu") == 0) {
|
||||
if (frame_index < sizeof(s_muyu_frames) / sizeof(s_muyu_frames[0])) {
|
||||
return &s_muyu_frames[frame_index];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const lcd_direct_icon_t *lcd_direct_icon(uint16_t icon_id)
|
||||
{
|
||||
(void)icon_id;
|
||||
|
||||
Reference in New Issue
Block a user