feat(platform): smooth preview transitions and recover shared SPI/audio state
This commit is contained in:
@@ -109,6 +109,7 @@ esp_err_t platform_display_show_png(const uint8_t *png,
|
||||
uint32_t timeout_ms,
|
||||
char *err,
|
||||
size_t err_len);
|
||||
void platform_display_mark_shared_spi_dirty(void);
|
||||
void platform_display_deinit(void);
|
||||
|
||||
// ---------- voice_audio ----------
|
||||
|
||||
@@ -23,6 +23,7 @@ esp_err_t lcd_module_show_png(const uint8_t *png,
|
||||
uint32_t timeout_ms,
|
||||
char *err,
|
||||
size_t err_len);
|
||||
void lcd_module_mark_shared_spi_dirty(void);
|
||||
void lcd_module_deinit(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -79,6 +79,7 @@ esp_err_t st7789p3_set_backlight(st7789p3_handle_t panel, bool on);
|
||||
esp_err_t st7789p3_set_madctl(st7789p3_handle_t panel, uint8_t madctl_val);
|
||||
esp_err_t st7789p3_set_invert(st7789p3_handle_t panel, bool invert_color);
|
||||
esp_err_t st7789p3_set_swap_color_bytes(st7789p3_handle_t panel, bool swap_color_bytes);
|
||||
esp_err_t st7789p3_recover_spi_bus(st7789p3_handle_t panel);
|
||||
|
||||
esp_err_t st7789p3_set_window(
|
||||
st7789p3_handle_t panel, uint16_t x_start, uint16_t y_start, uint16_t x_end, uint16_t y_end);
|
||||
|
||||
@@ -163,6 +163,8 @@ static esp_err_t config_input_pin(int gpio_num, bool pull_up, const char *name)
|
||||
}
|
||||
|
||||
static esp_err_t ensure_shared_shift_pins_gpio_locked(void) {
|
||||
platform_display_mark_shared_spi_dirty();
|
||||
|
||||
esp_err_t err = config_output_pin(CONFIG_TQ_SPI_SHARED_MOSI_PIN, 0, "print_mosi");
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
|
||||
@@ -22,6 +22,8 @@ static const char *TAG = "lcd_module";
|
||||
#define LCD_PREVIEW_TIMEOUT_MS_DEFAULT 200
|
||||
#define LCD_LOCK_TIMEOUT_MS 1000
|
||||
#define LCD_DEFAULT_DRAW_LINES 20
|
||||
#define LCD_PREVIEW_FADE_DURATION_MS 150
|
||||
#define LCD_PREVIEW_FADE_STEPS 3
|
||||
|
||||
#ifndef CONFIG_TQ_SCREEN_PIXEL_CLOCK_HZ
|
||||
#define CONFIG_TQ_SCREEN_PIXEL_CLOCK_HZ (10 * 1000 * 1000)
|
||||
@@ -110,10 +112,16 @@ typedef struct {
|
||||
bool lvgl_inited;
|
||||
bool lvgl_ready;
|
||||
bool initialized;
|
||||
bool shared_spi_dirty;
|
||||
} lcd_state_t;
|
||||
|
||||
static lcd_state_t s_lcd;
|
||||
|
||||
void lcd_module_mark_shared_spi_dirty(void)
|
||||
{
|
||||
s_lcd.shared_spi_dirty = true;
|
||||
}
|
||||
|
||||
static int resolve_reset_pin(void)
|
||||
{
|
||||
if (CONFIG_TQ_SCREEN_RESET_PIN >= 0) {
|
||||
@@ -189,13 +197,29 @@ static void lcd_free_lvgl_buffers(void)
|
||||
|
||||
static esp_err_t lcd_recover_panel_for_shared_spi(void)
|
||||
{
|
||||
/*
|
||||
* Printer bit-bang path reconfigures shared MOSI/CLK as GPIO.
|
||||
* Re-initialize panel before each preview draw to restore SPI pin routing.
|
||||
*/
|
||||
if (s_lcd.initialized) {
|
||||
lcd_module_deinit();
|
||||
if (!s_lcd.initialized || s_lcd.panel == NULL) {
|
||||
return lcd_module_init();
|
||||
}
|
||||
|
||||
if (!s_lcd.shared_spi_dirty) {
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Direct-printer path temporarily takes over shared MOSI/CLK as GPIO.
|
||||
* Recover LCD SPI routing only when printer touched shared pins.
|
||||
*/
|
||||
esp_err_t recover_rc = st7789p3_recover_spi_bus(s_lcd.panel);
|
||||
if (recover_rc == ESP_OK) {
|
||||
s_lcd.shared_spi_dirty = false;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
ESP_LOGW(TAG,
|
||||
"fast SPI recover failed: rc=0x%x, fallback to full panel reinit",
|
||||
(unsigned)recover_rc);
|
||||
|
||||
lcd_module_deinit();
|
||||
return lcd_module_init();
|
||||
}
|
||||
|
||||
@@ -412,7 +436,62 @@ static esp_err_t lcd_scale_rgb565_to_preview(const uint16_t *src_pixels,
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t lcd_apply_preview_locked(lv_color_t bg_color, char *err, size_t err_len)
|
||||
static uint16_t lcd_blend_rgb565(uint16_t from, uint16_t to, uint8_t alpha_255)
|
||||
{
|
||||
uint32_t inv = (uint32_t)(255u - alpha_255);
|
||||
|
||||
uint32_t fr = (from >> 11) & 0x1Fu;
|
||||
uint32_t fg = (from >> 5) & 0x3Fu;
|
||||
uint32_t fb = from & 0x1Fu;
|
||||
|
||||
uint32_t tr = (to >> 11) & 0x1Fu;
|
||||
uint32_t tg = (to >> 5) & 0x3Fu;
|
||||
uint32_t tb = to & 0x1Fu;
|
||||
|
||||
uint32_t r = (fr * inv + tr * alpha_255 + 127u) / 255u;
|
||||
uint32_t g = (fg * inv + tg * alpha_255 + 127u) / 255u;
|
||||
uint32_t b = (fb * inv + tb * alpha_255 + 127u) / 255u;
|
||||
|
||||
return (uint16_t)((r << 11) | (g << 5) | b);
|
||||
}
|
||||
|
||||
static esp_err_t lcd_draw_preview_pixels_locked(const uint16_t *pixels,
|
||||
uint16_t preview_w,
|
||||
uint16_t preview_h,
|
||||
char *err,
|
||||
size_t err_len)
|
||||
{
|
||||
if (s_lcd.panel == NULL || pixels == NULL) {
|
||||
lcd_fill_err(err, err_len, "display panel not ready");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
if (preview_w == 0 || preview_h == 0 || preview_w > LCD_PANEL_H_RES || preview_h > LCD_PANEL_V_RES) {
|
||||
lcd_fill_err(err, err_len, "invalid preview size");
|
||||
return ESP_ERR_INVALID_SIZE;
|
||||
}
|
||||
|
||||
uint16_t x = (uint16_t)((LCD_PANEL_H_RES - preview_w) / 2u);
|
||||
uint16_t y = (uint16_t)((LCD_PANEL_V_RES - preview_h) / 2u);
|
||||
esp_err_t draw_rc = st7789p3_draw_bitmap(s_lcd.panel,
|
||||
x,
|
||||
y,
|
||||
(uint16_t)(x + preview_w),
|
||||
(uint16_t)(y + preview_h),
|
||||
pixels);
|
||||
if (draw_rc != ESP_OK) {
|
||||
lcd_fill_err(err, err_len, "display draw failed");
|
||||
return draw_rc;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t lcd_apply_preview_locked(const uint16_t *prev_pixels,
|
||||
uint16_t prev_w,
|
||||
uint16_t prev_h,
|
||||
bool clear_before_draw,
|
||||
lv_color_t bg_color,
|
||||
char *err,
|
||||
size_t err_len)
|
||||
{
|
||||
if (s_lcd.panel == NULL || s_lcd.preview_pixels == NULL) {
|
||||
lcd_fill_err(err, err_len, "display panel not ready");
|
||||
@@ -426,31 +505,72 @@ static esp_err_t lcd_apply_preview_locked(lv_color_t bg_color, char *err, size_t
|
||||
return ESP_ERR_INVALID_SIZE;
|
||||
}
|
||||
|
||||
esp_err_t draw_rc = st7789p3_fill_color(s_lcd.panel, (uint16_t)bg_color.full);
|
||||
if (draw_rc != ESP_OK) {
|
||||
lcd_fill_err(err, err_len, "display clear failed");
|
||||
if (clear_before_draw) {
|
||||
esp_err_t clear_rc = st7789p3_fill_color(s_lcd.panel, (uint16_t)bg_color.full);
|
||||
if (clear_rc != ESP_OK) {
|
||||
lcd_fill_err(err, err_len, "display clear failed");
|
||||
return clear_rc;
|
||||
}
|
||||
esp_err_t draw_rc = lcd_draw_preview_pixels_locked(s_lcd.preview_pixels, preview_w, preview_h, err, err_len);
|
||||
if (draw_rc == ESP_OK) {
|
||||
ESP_LOGI(TAG, "preview drawn directly: size=%ux%u", (unsigned)preview_w, (unsigned)preview_h);
|
||||
}
|
||||
return draw_rc;
|
||||
}
|
||||
|
||||
uint16_t x = (uint16_t)((LCD_PANEL_H_RES - preview_w) / 2u);
|
||||
uint16_t y = (uint16_t)((LCD_PANEL_V_RES - preview_h) / 2u);
|
||||
draw_rc = st7789p3_draw_bitmap(s_lcd.panel,
|
||||
x,
|
||||
y,
|
||||
(uint16_t)(x + preview_w),
|
||||
(uint16_t)(y + preview_h),
|
||||
s_lcd.preview_pixels);
|
||||
if (draw_rc != ESP_OK) {
|
||||
lcd_fill_err(err, err_len, "display draw failed");
|
||||
bool can_fade = (prev_pixels != NULL && prev_w == preview_w && prev_h == preview_h);
|
||||
if (!can_fade) {
|
||||
esp_err_t draw_rc = lcd_draw_preview_pixels_locked(s_lcd.preview_pixels, preview_w, preview_h, err, err_len);
|
||||
if (draw_rc == ESP_OK) {
|
||||
ESP_LOGI(TAG, "preview drawn directly: size=%ux%u", (unsigned)preview_w, (unsigned)preview_h);
|
||||
}
|
||||
return draw_rc;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "preview drawn directly: size=%ux%u offset=(%u,%u)",
|
||||
(unsigned)preview_w,
|
||||
(unsigned)preview_h,
|
||||
(unsigned)x,
|
||||
(unsigned)y);
|
||||
return ESP_OK;
|
||||
size_t pixel_count = (size_t)preview_w * (size_t)preview_h;
|
||||
uint16_t *fade_pixels = (uint16_t *)heap_caps_malloc(pixel_count * sizeof(uint16_t),
|
||||
MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
||||
if (fade_pixels == NULL) {
|
||||
fade_pixels = (uint16_t *)heap_caps_malloc(pixel_count * sizeof(uint16_t), MALLOC_CAP_8BIT);
|
||||
}
|
||||
if (fade_pixels == NULL) {
|
||||
// Fallback to direct draw when memory is tight.
|
||||
esp_err_t draw_rc = lcd_draw_preview_pixels_locked(s_lcd.preview_pixels, preview_w, preview_h, err, err_len);
|
||||
if (draw_rc == ESP_OK) {
|
||||
ESP_LOGI(TAG, "preview drawn directly (fade fallback): size=%ux%u", (unsigned)preview_w, (unsigned)preview_h);
|
||||
}
|
||||
return draw_rc;
|
||||
}
|
||||
|
||||
const uint32_t frame_count = LCD_PREVIEW_FADE_STEPS + 1u;
|
||||
uint32_t frame_delay_ms = LCD_PREVIEW_FADE_DURATION_MS / frame_count;
|
||||
if (frame_delay_ms == 0) {
|
||||
frame_delay_ms = 1;
|
||||
}
|
||||
|
||||
for (uint32_t step = 1; step <= LCD_PREVIEW_FADE_STEPS; ++step) {
|
||||
uint8_t alpha = (uint8_t)((step * 255u) / frame_count);
|
||||
for (size_t i = 0; i < pixel_count; ++i) {
|
||||
fade_pixels[i] = lcd_blend_rgb565(prev_pixels[i], s_lcd.preview_pixels[i], alpha);
|
||||
}
|
||||
|
||||
esp_err_t draw_rc = lcd_draw_preview_pixels_locked(fade_pixels, preview_w, preview_h, err, err_len);
|
||||
if (draw_rc != ESP_OK) {
|
||||
heap_caps_free(fade_pixels);
|
||||
return draw_rc;
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(frame_delay_ms));
|
||||
}
|
||||
|
||||
heap_caps_free(fade_pixels);
|
||||
esp_err_t draw_rc = lcd_draw_preview_pixels_locked(s_lcd.preview_pixels, preview_w, preview_h, err, err_len);
|
||||
if (draw_rc == ESP_OK) {
|
||||
ESP_LOGI(TAG, "preview drawn with fade: size=%ux%u fade_ms=%u",
|
||||
(unsigned)preview_w,
|
||||
(unsigned)preview_h,
|
||||
(unsigned)LCD_PREVIEW_FADE_DURATION_MS);
|
||||
}
|
||||
return draw_rc;
|
||||
}
|
||||
|
||||
void lcd_module_deinit(void)
|
||||
@@ -547,6 +667,7 @@ esp_err_t lcd_module_init(void)
|
||||
}
|
||||
|
||||
s_lcd.initialized = true;
|
||||
s_lcd.shared_spi_dirty = false;
|
||||
ESP_LOGI(TAG,
|
||||
"st7789p3 ready: spi_host=%d mosi=%d clk=%d miso=%d dc=%d cs=%d rst=%d bk=%d pclk=%u mode=%u res=%ux%u madctl=0x%02x gap=%u,%u invert=%d swap_bytes=%d",
|
||||
ST7789_SPI_HOST,
|
||||
@@ -609,9 +730,12 @@ esp_err_t lcd_module_show_raster_1bpp(const uint8_t *raster,
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
|
||||
if (s_lcd.preview_pixels != NULL) {
|
||||
heap_caps_free(s_lcd.preview_pixels);
|
||||
}
|
||||
uint16_t *prev_pixels = s_lcd.preview_pixels;
|
||||
uint16_t prev_w = s_lcd.preview_dsc.header.w;
|
||||
uint16_t prev_h = s_lcd.preview_dsc.header.h;
|
||||
bool clear_before_draw = (s_lcd.preview_pixels == NULL ||
|
||||
s_lcd.preview_dsc.header.w != preview_w ||
|
||||
s_lcd.preview_dsc.header.h != preview_h);
|
||||
s_lcd.preview_pixels = preview_pixels;
|
||||
|
||||
memset(&s_lcd.preview_dsc, 0, sizeof(s_lcd.preview_dsc));
|
||||
@@ -622,7 +746,16 @@ esp_err_t lcd_module_show_raster_1bpp(const uint8_t *raster,
|
||||
s_lcd.preview_dsc.data_size = (uint32_t)((size_t)preview_w * preview_h * sizeof(uint16_t));
|
||||
s_lcd.preview_dsc.data = (const uint8_t *)s_lcd.preview_pixels;
|
||||
|
||||
esp_err_t draw_err = lcd_apply_preview_locked(lv_color_white(), err, err_len);
|
||||
esp_err_t draw_err = lcd_apply_preview_locked(prev_pixels,
|
||||
prev_w,
|
||||
prev_h,
|
||||
clear_before_draw,
|
||||
lv_color_white(),
|
||||
err,
|
||||
err_len);
|
||||
if (prev_pixels != NULL) {
|
||||
heap_caps_free(prev_pixels);
|
||||
}
|
||||
lcd_lock_give();
|
||||
return draw_err;
|
||||
#endif
|
||||
@@ -679,9 +812,12 @@ esp_err_t lcd_module_show_png(const uint8_t *png,
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
|
||||
if (s_lcd.preview_pixels != NULL) {
|
||||
heap_caps_free(s_lcd.preview_pixels);
|
||||
}
|
||||
uint16_t *prev_pixels = s_lcd.preview_pixels;
|
||||
uint16_t prev_w = s_lcd.preview_dsc.header.w;
|
||||
uint16_t prev_h = s_lcd.preview_dsc.header.h;
|
||||
bool clear_before_draw = (s_lcd.preview_pixels == NULL ||
|
||||
s_lcd.preview_dsc.header.w != preview_w ||
|
||||
s_lcd.preview_dsc.header.h != preview_h);
|
||||
s_lcd.preview_pixels = preview_pixels;
|
||||
|
||||
memset(&s_lcd.preview_dsc, 0, sizeof(s_lcd.preview_dsc));
|
||||
@@ -692,7 +828,16 @@ esp_err_t lcd_module_show_png(const uint8_t *png,
|
||||
s_lcd.preview_dsc.data_size = (uint32_t)((size_t)preview_w * preview_h * sizeof(uint16_t));
|
||||
s_lcd.preview_dsc.data = (const uint8_t *)s_lcd.preview_pixels;
|
||||
|
||||
esp_err_t draw_err = lcd_apply_preview_locked(lv_color_white(), err, err_len);
|
||||
esp_err_t draw_err = lcd_apply_preview_locked(prev_pixels,
|
||||
prev_w,
|
||||
prev_h,
|
||||
clear_before_draw,
|
||||
lv_color_white(),
|
||||
err,
|
||||
err_len);
|
||||
if (prev_pixels != NULL) {
|
||||
heap_caps_free(prev_pixels);
|
||||
}
|
||||
lcd_lock_give();
|
||||
return draw_err;
|
||||
#endif
|
||||
@@ -723,9 +868,12 @@ esp_err_t lcd_module_start_demo(void)
|
||||
return decode_rc;
|
||||
}
|
||||
|
||||
if (s_lcd.preview_pixels != NULL) {
|
||||
heap_caps_free(s_lcd.preview_pixels);
|
||||
}
|
||||
uint16_t *prev_pixels = s_lcd.preview_pixels;
|
||||
uint16_t prev_w = s_lcd.preview_dsc.header.w;
|
||||
uint16_t prev_h = s_lcd.preview_dsc.header.h;
|
||||
bool clear_before_draw = (s_lcd.preview_pixels == NULL ||
|
||||
s_lcd.preview_dsc.header.w != demo_w ||
|
||||
s_lcd.preview_dsc.header.h != demo_h);
|
||||
s_lcd.preview_pixels = demo_pixels;
|
||||
|
||||
memset(&s_lcd.preview_dsc, 0, sizeof(s_lcd.preview_dsc));
|
||||
@@ -736,7 +884,16 @@ esp_err_t lcd_module_start_demo(void)
|
||||
s_lcd.preview_dsc.data_size = (uint32_t)((size_t)demo_w * demo_h * sizeof(uint16_t));
|
||||
s_lcd.preview_dsc.data = (const uint8_t *)s_lcd.preview_pixels;
|
||||
|
||||
esp_err_t draw_err = lcd_apply_preview_locked(lv_color_black(), decode_err, sizeof(decode_err));
|
||||
esp_err_t draw_err = lcd_apply_preview_locked(prev_pixels,
|
||||
prev_w,
|
||||
prev_h,
|
||||
clear_before_draw,
|
||||
lv_color_black(),
|
||||
decode_err,
|
||||
sizeof(decode_err));
|
||||
if (prev_pixels != NULL) {
|
||||
heap_caps_free(prev_pixels);
|
||||
}
|
||||
lcd_lock_give();
|
||||
if (draw_err != ESP_OK) {
|
||||
ESP_LOGW(TAG, "demo draw failed: rc=0x%x msg=%s", (unsigned)draw_err, decode_err);
|
||||
|
||||
@@ -36,3 +36,8 @@ esp_err_t platform_display_show_png(const uint8_t *png,
|
||||
{
|
||||
return lcd_module_show_png(png, png_len, timeout_ms, err, err_len);
|
||||
}
|
||||
|
||||
void platform_display_mark_shared_spi_dirty(void)
|
||||
{
|
||||
lcd_module_mark_shared_spi_dirty();
|
||||
}
|
||||
|
||||
@@ -199,6 +199,53 @@ static esp_err_t st7789p3_run_init_cmds(st7789p3_handle_t panel)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t st7789p3_attach_spi_device(st7789p3_handle_t panel)
|
||||
{
|
||||
if (panel == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (panel->cfg.init_spi_bus) {
|
||||
spi_bus_config_t buscfg = {
|
||||
.mosi_io_num = panel->cfg.pin_mosi,
|
||||
.miso_io_num = panel->cfg.pin_miso,
|
||||
.sclk_io_num = panel->cfg.pin_sclk,
|
||||
.quadwp_io_num = -1,
|
||||
.quadhd_io_num = -1,
|
||||
.max_transfer_sz = panel->cfg.max_transfer_sz,
|
||||
};
|
||||
|
||||
esp_err_t ret = spi_bus_initialize(panel->cfg.spi_host, &buscfg, SPI_DMA_CH_AUTO);
|
||||
if (ret == ESP_OK) {
|
||||
panel->bus_owned = true;
|
||||
} else if (ret == ESP_ERR_INVALID_STATE) {
|
||||
panel->bus_owned = false;
|
||||
ESP_LOGW(TAG, "SPI host already initialized, skip bus init");
|
||||
} else {
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
panel->bus_owned = false;
|
||||
}
|
||||
|
||||
spi_device_interface_config_t devcfg = {
|
||||
.clock_speed_hz = panel->cfg.pclk_hz,
|
||||
.mode = panel->cfg.spi_mode,
|
||||
.spics_io_num = panel->cfg.pin_cs,
|
||||
.queue_size = panel->cfg.queue_size,
|
||||
};
|
||||
|
||||
esp_err_t ret = spi_bus_add_device(panel->cfg.spi_host, &devcfg, &panel->spi);
|
||||
if (ret != ESP_OK) {
|
||||
if (panel->bus_owned) {
|
||||
(void)spi_bus_free(panel->cfg.spi_host);
|
||||
panel->bus_owned = false;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t st7789p3_new_panel(const st7789p3_config_t *config, st7789p3_handle_t *ret_panel)
|
||||
{
|
||||
if (ret_panel == NULL) {
|
||||
@@ -233,39 +280,8 @@ esp_err_t st7789p3_new_panel(const st7789p3_config_t *config, st7789p3_handle_t
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (panel->cfg.init_spi_bus) {
|
||||
spi_bus_config_t buscfg = {
|
||||
.mosi_io_num = panel->cfg.pin_mosi,
|
||||
.miso_io_num = panel->cfg.pin_miso,
|
||||
.sclk_io_num = panel->cfg.pin_sclk,
|
||||
.quadwp_io_num = -1,
|
||||
.quadhd_io_num = -1,
|
||||
.max_transfer_sz = panel->cfg.max_transfer_sz,
|
||||
};
|
||||
|
||||
ret = spi_bus_initialize(panel->cfg.spi_host, &buscfg, SPI_DMA_CH_AUTO);
|
||||
if (ret == ESP_OK) {
|
||||
panel->bus_owned = true;
|
||||
} else if (ret == ESP_ERR_INVALID_STATE) {
|
||||
ESP_LOGW(TAG, "SPI host already initialized, skip bus init");
|
||||
} else {
|
||||
free(panel);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
spi_device_interface_config_t devcfg = {
|
||||
.clock_speed_hz = panel->cfg.pclk_hz,
|
||||
.mode = panel->cfg.spi_mode,
|
||||
.spics_io_num = panel->cfg.pin_cs,
|
||||
.queue_size = panel->cfg.queue_size,
|
||||
};
|
||||
|
||||
ret = spi_bus_add_device(panel->cfg.spi_host, &devcfg, &panel->spi);
|
||||
ret = st7789p3_attach_spi_device(panel);
|
||||
if (ret != ESP_OK) {
|
||||
if (panel->bus_owned) {
|
||||
spi_bus_free(panel->cfg.spi_host);
|
||||
}
|
||||
free(panel);
|
||||
return ret;
|
||||
}
|
||||
@@ -297,6 +313,42 @@ esp_err_t st7789p3_del(st7789p3_handle_t panel)
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t st7789p3_recover_spi_bus(st7789p3_handle_t panel)
|
||||
{
|
||||
if (panel == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
esp_err_t ret = st7789p3_configure_gpio(panel);
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (panel->spi != NULL) {
|
||||
ret = spi_bus_remove_device(panel->spi);
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
panel->spi = NULL;
|
||||
}
|
||||
|
||||
if (panel->bus_owned) {
|
||||
ret = spi_bus_free(panel->cfg.spi_host);
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
panel->bus_owned = false;
|
||||
}
|
||||
|
||||
ret = st7789p3_attach_spi_device(panel);
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Keep current frame on panel; just ensure display state remains on.
|
||||
return st7789p3_send_cmd(panel, 0x29);
|
||||
}
|
||||
|
||||
esp_err_t st7789p3_set_backlight(st7789p3_handle_t panel, bool on)
|
||||
{
|
||||
if (panel == NULL) {
|
||||
|
||||
@@ -52,6 +52,7 @@ static bool s_opened;
|
||||
static uint32_t s_sample_rate;
|
||||
static uint8_t s_channels;
|
||||
static uint8_t s_bits_per_sample;
|
||||
static bool s_i2s_need_enable_before_open;
|
||||
|
||||
static void fill_err(char *err, size_t err_len, const char *msg) {
|
||||
if (err != NULL && err_len > 0) {
|
||||
@@ -302,6 +303,29 @@ static esp_err_t voice_audio_prepare(const voice_audio_open_config_t *cfg) {
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t voice_audio_reenable_i2s_if_needed(void) {
|
||||
if (!s_i2s_need_enable_before_open) {
|
||||
return ESP_OK;
|
||||
}
|
||||
if (s_i2s_tx == NULL || s_i2s_rx == NULL) {
|
||||
s_i2s_need_enable_before_open = false;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t tx_rc = i2s_channel_enable(s_i2s_tx);
|
||||
if (tx_rc != ESP_OK && tx_rc != ESP_ERR_INVALID_STATE) {
|
||||
return tx_rc;
|
||||
}
|
||||
|
||||
esp_err_t rx_rc = i2s_channel_enable(s_i2s_rx);
|
||||
if (rx_rc != ESP_OK && rx_rc != ESP_ERR_INVALID_STATE) {
|
||||
return rx_rc;
|
||||
}
|
||||
|
||||
s_i2s_need_enable_before_open = false;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t voice_audio_open(const voice_audio_open_config_t *cfg, char *err, size_t err_len) {
|
||||
if (cfg == NULL || cfg->sample_rate == 0 || cfg->channels == 0 || cfg->bits_per_sample != 16) {
|
||||
fill_err(err, err_len, "invalid voice audio config");
|
||||
@@ -345,6 +369,13 @@ esp_err_t voice_audio_open(const voice_audio_open_config_t *cfg, char *err, size
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
esp_err_t i2s_rc = voice_audio_reenable_i2s_if_needed();
|
||||
if (i2s_rc != ESP_OK) {
|
||||
fill_err(err, err_len, "i2s re-enable failed");
|
||||
xSemaphoreGive(s_lock);
|
||||
return i2s_rc;
|
||||
}
|
||||
|
||||
esp_codec_dev_sample_info_t fs = {
|
||||
.sample_rate = cfg->sample_rate,
|
||||
.channel = cfg->channels,
|
||||
@@ -392,6 +423,7 @@ void voice_audio_close(void) {
|
||||
(void)esp_codec_dev_set_out_mute(s_codec_dev, true);
|
||||
(void)esp_codec_dev_close(s_codec_dev);
|
||||
s_opened = false;
|
||||
s_i2s_need_enable_before_open = true;
|
||||
}
|
||||
|
||||
xSemaphoreGive(s_lock);
|
||||
|
||||
Reference in New Issue
Block a user