From d2cc2e009046e616ded953663a2d1c7048689386 Mon Sep 17 00:00:00 2001 From: Xiaoxia Date: Sat, 25 Jan 2025 15:17:37 +0800 Subject: [PATCH] move display init code to board (#109) --- main/CMakeLists.txt | 1 - main/audio_codecs/es8311_audio_codec.cc | 2 +- main/audio_codecs/es8388_audio_codec.cc | 22 +- main/audio_codecs/es8388_audio_codec.h | 1 + main/audio_codecs/no_audio_codec.cc | 2 +- .../atk-dnesp32s3-box/atk_dnesp32s3_box.cc | 111 +++++- main/boards/atk-dnesp32s3-box/config.h | 17 + main/boards/atk-dnesp32s3/atk_dnesp32s3.cc | 25 +- main/display/atk_st7789_80i.cc | 337 ------------------ main/display/atk_st7789_80i.h | 46 --- 10 files changed, 137 insertions(+), 427 deletions(-) delete mode 100644 main/display/atk_st7789_80i.cc delete mode 100644 main/display/atk_st7789_80i.h diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index a60b6170..33a9148c 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -7,7 +7,6 @@ set(SOURCES "audio_codecs/audio_codec.cc" "audio_codecs/tcircles3_audio_codec.cc" "led/single_led.cc" "led/circular_strip.cc" - "display/atk_st7789_80i.cc" "display/display.cc" "display/no_display.cc" "display/lcd_display.cc" diff --git a/main/audio_codecs/es8311_audio_codec.cc b/main/audio_codecs/es8311_audio_codec.cc index 41719869..2b5e3b52 100644 --- a/main/audio_codecs/es8311_audio_codec.cc +++ b/main/audio_codecs/es8311_audio_codec.cc @@ -144,7 +144,7 @@ void Es8311AudioCodec::EnableInput(bool enable) { .bits_per_sample = 16, .channel = 1, .channel_mask = 0, - .sample_rate = (uint32_t)output_sample_rate_, + .sample_rate = (uint32_t)input_sample_rate_, .mclk_multiple = 0, }; ESP_ERROR_CHECK(esp_codec_dev_open(input_dev_, &fs)); diff --git a/main/audio_codecs/es8388_audio_codec.cc b/main/audio_codecs/es8388_audio_codec.cc index 4db8153d..47522a75 100644 --- a/main/audio_codecs/es8388_audio_codec.cc +++ b/main/audio_codecs/es8388_audio_codec.cc @@ -12,8 +12,7 @@ Es8388AudioCodec::Es8388AudioCodec(void* i2c_master_handle, i2c_port_t i2c_port, input_channels_ = 1; // 输入通道数 input_sample_rate_ = input_sample_rate; output_sample_rate_ = output_sample_rate; - - CreateDuplexChannels(mclk, bclk, ws, dout, din); + pa_pin_ = pa_pin; CreateDuplexChannels(mclk, bclk, ws, dout, din); // Do initialize of related interface: data_if, ctrl_if and gpio_if audio_codec_i2s_cfg_t i2s_cfg = { @@ -62,8 +61,9 @@ Es8388AudioCodec::Es8388AudioCodec(void* i2c_master_handle, i2c_port_t i2c_port, .data_if = data_if_, }; input_dev_ = esp_codec_dev_new(&indev_cfg); - assert(input_dev_ != NULL); - + assert(input_dev_ != NULL); + esp_codec_set_disable_when_closed(output_dev_, false); + esp_codec_set_disable_when_closed(input_dev_, false); ESP_LOGI(TAG, "Es8388AudioCodec initialized"); } @@ -86,7 +86,7 @@ void Es8388AudioCodec::CreateDuplexChannels(gpio_num_t mclk, gpio_num_t bclk, gp .id = I2S_NUM_0, .role = I2S_ROLE_MASTER, .dma_desc_num = 6, - .dma_frame_num = 240 * 3, + .dma_frame_num = 240, .auto_clear_after_cb = true, .auto_clear_before_cb = false, .intr_priority = 0, @@ -126,8 +126,8 @@ void Es8388AudioCodec::CreateDuplexChannels(gpio_num_t mclk, gpio_num_t bclk, gp } }; - ESP_ERROR_CHECK(i2s_channel_init_std_mode(rx_handle_, &std_cfg)); ESP_ERROR_CHECK(i2s_channel_init_std_mode(tx_handle_, &std_cfg)); + ESP_ERROR_CHECK(i2s_channel_init_std_mode(rx_handle_, &std_cfg)); ESP_LOGI(TAG, "Duplex channels created"); } @@ -151,7 +151,7 @@ void Es8388AudioCodec::EnableInput(bool enable) { ESP_ERROR_CHECK(esp_codec_dev_open(input_dev_, &fs)); ESP_ERROR_CHECK(esp_codec_dev_set_in_gain(input_dev_, 40.0)); } else { - // ESP_ERROR_CHECK(esp_codec_dev_close(input_dev_)); //输入输出共用的i2s,只关闭了输出后会把输入也关没了,所以得注释关闭 + ESP_ERROR_CHECK(esp_codec_dev_close(input_dev_)); } AudioCodec::EnableInput(enable); } @@ -170,8 +170,14 @@ void Es8388AudioCodec::EnableOutput(bool enable) { }; ESP_ERROR_CHECK(esp_codec_dev_open(output_dev_, &fs)); ESP_ERROR_CHECK(esp_codec_dev_set_out_vol(output_dev_, output_volume_)); + if (pa_pin_ != GPIO_NUM_NC) { + gpio_set_level(pa_pin_, 1); + } } else { - // ESP_ERROR_CHECK(esp_codec_dev_close(output_dev_)); //输入输出共用的i2s,只关闭了输出后会把输入也关没了,所以得注释关闭 + ESP_ERROR_CHECK(esp_codec_dev_close(output_dev_)); + if (pa_pin_ != GPIO_NUM_NC) { + gpio_set_level(pa_pin_, 0); + } } AudioCodec::EnableOutput(enable); } diff --git a/main/audio_codecs/es8388_audio_codec.h b/main/audio_codecs/es8388_audio_codec.h index 949ffb5c..10807a41 100644 --- a/main/audio_codecs/es8388_audio_codec.h +++ b/main/audio_codecs/es8388_audio_codec.h @@ -16,6 +16,7 @@ private: esp_codec_dev_handle_t output_dev_ = nullptr; esp_codec_dev_handle_t input_dev_ = nullptr; + gpio_num_t pa_pin_ = GPIO_NUM_NC; void CreateDuplexChannels(gpio_num_t mclk, gpio_num_t bclk, gpio_num_t ws, gpio_num_t dout, gpio_num_t din); diff --git a/main/audio_codecs/no_audio_codec.cc b/main/audio_codecs/no_audio_codec.cc index 56c486d5..12e0d500 100644 --- a/main/audio_codecs/no_audio_codec.cc +++ b/main/audio_codecs/no_audio_codec.cc @@ -25,7 +25,7 @@ NoAudioCodecDuplex::NoAudioCodecDuplex(int input_sample_rate, int output_sample_ .role = I2S_ROLE_MASTER, .dma_desc_num = 6, .dma_frame_num = 240, - .auto_clear_after_cb = false, + .auto_clear_after_cb = true, .auto_clear_before_cb = false, .intr_priority = 0, }; diff --git a/main/boards/atk-dnesp32s3-box/atk_dnesp32s3_box.cc b/main/boards/atk-dnesp32s3-box/atk_dnesp32s3_box.cc index a0b2bc05..b9b44dbc 100644 --- a/main/boards/atk-dnesp32s3-box/atk_dnesp32s3_box.cc +++ b/main/boards/atk-dnesp32s3-box/atk_dnesp32s3_box.cc @@ -1,19 +1,23 @@ #include "wifi_board.h" #include "audio_codec.h" #include "audio_codecs/no_audio_codec.h" -#include "display/atk_st7789_80i.h" +#include "display/lcd_display.h" #include "application.h" #include "button.h" #include "config.h" #include "led/single_led.h" #include "iot/thing_manager.h" +#include "i2c_device.h" + #include #include #include -#include "i2c_device.h" -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "freertos/timers.h" +#include +#include +#include +#include +#include +#include #define TAG "atk_dnesp32s3_box" @@ -51,7 +55,7 @@ private: i2c_master_bus_handle_t i2c_bus_; i2c_master_dev_handle_t xl9555_handle_; Button boot_button_; - ATK_ST7789_80_Display* display_; + LcdDisplay* display_; XL9555* xl9555_; void InitializeI2c() { @@ -75,17 +79,92 @@ private: } void InitializeATK_ST7789_80_Display() { - display_ = new ATK_ST7789_80_Display(DISPLAY_BACKLIGHT_PIN,DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_OFFSET_X, - DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY); - xl9555_->SetOutputState(5, 1); - xl9555_->SetOutputState(7, 1); + esp_lcd_panel_io_handle_t panel_io = nullptr; + esp_lcd_panel_handle_t panel = nullptr; + /* 配置RD引脚 */ + gpio_config_t gpio_init_struct; + gpio_init_struct.intr_type = GPIO_INTR_DISABLE; + gpio_init_struct.mode = GPIO_MODE_INPUT_OUTPUT; + gpio_init_struct.pin_bit_mask = 1ull << LCD_NUM_RD; + gpio_init_struct.pull_down_en = GPIO_PULLDOWN_DISABLE; + gpio_init_struct.pull_up_en = GPIO_PULLUP_ENABLE; + gpio_config(&gpio_init_struct); + gpio_set_level(LCD_NUM_RD, 1); + + esp_lcd_i80_bus_handle_t i80_bus = NULL; + esp_lcd_i80_bus_config_t bus_config = { + .dc_gpio_num = LCD_NUM_DC, + .wr_gpio_num = LCD_NUM_WR, + .clk_src = LCD_CLK_SRC_DEFAULT, + .data_gpio_nums = { + GPIO_LCD_D0, + GPIO_LCD_D1, + GPIO_LCD_D2, + GPIO_LCD_D3, + GPIO_LCD_D4, + GPIO_LCD_D5, + GPIO_LCD_D6, + GPIO_LCD_D7, + }, + .bus_width = 8, + .max_transfer_bytes = DISPLAY_WIDTH * DISPLAY_HEIGHT * sizeof(uint16_t), + .psram_trans_align = 64, + .sram_trans_align = 4, + }; + ESP_ERROR_CHECK(esp_lcd_new_i80_bus(&bus_config, &i80_bus)); + + esp_lcd_panel_io_i80_config_t io_config = { + .cs_gpio_num = LCD_NUM_CS, + .pclk_hz = (10 * 1000 * 1000), + .trans_queue_depth = 10, + .on_color_trans_done = nullptr, + .user_ctx = nullptr, + .lcd_cmd_bits = 8, + .lcd_param_bits = 8, + .dc_levels = { + .dc_idle_level = 0, + .dc_cmd_level = 0, + .dc_dummy_level = 0, + .dc_data_level = 1, + }, + .flags = { + .swap_color_bytes = 0, + }, + }; + ESP_ERROR_CHECK(esp_lcd_new_panel_io_i80(i80_bus, &io_config, &panel_io)); + + esp_lcd_panel_dev_config_t panel_config = { + .reset_gpio_num = LCD_NUM_RST, + .rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB, + .bits_per_pixel = 16, + }; + ESP_ERROR_CHECK(esp_lcd_new_panel_st7789(panel_io, &panel_config, &panel)); + + esp_lcd_panel_reset(panel); + esp_lcd_panel_init(panel); + esp_lcd_panel_invert_color(panel, true); + esp_lcd_panel_set_gap(panel, 0, 0); + uint8_t data0[] = {0x00}; + uint8_t data1[] = {0x65}; + esp_lcd_panel_io_tx_param(panel_io, 0x36, data0, 1); + esp_lcd_panel_io_tx_param(panel_io, 0x3A, data1, 1); + esp_lcd_panel_swap_xy(panel, DISPLAY_SWAP_XY); + esp_lcd_panel_mirror(panel, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y); + ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel, true)); + + display_ = new LcdDisplay(panel_io, panel, DISPLAY_BACKLIGHT_PIN, DISPLAY_BACKLIGHT_OUTPUT_INVERT, + DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY, + { + .text_font = &font_puhui_20_4, + .icon_font = &font_awesome_20_4, + .emoji_font = emoji_font_64_lite_init(), + }); } void InitializeButtons() { boot_button_.OnClick([this]() { auto& app = Application::GetInstance(); - if (app.GetDeviceState() == kDeviceStateStarting && !WifiStation::GetInstance().IsConnected()) - { + if (app.GetDeviceState() == kDeviceStateStarting && !WifiStation::GetInstance().IsConnected()) { ResetWifiConfiguration(); } }); @@ -95,22 +174,20 @@ private: boot_button_.OnPressUp([this]() { Application::GetInstance().StopListening(); }); - - auto codec = GetAudioCodec(); - GetAudioCodec()->SetOutputVolume(50); } // 物联网初始化,添加对 AI 可见设备 void InitializeIot() { auto& thing_manager = iot::ThingManager::GetInstance(); thing_manager.AddThing(iot::CreateThing("Speaker")); - thing_manager.AddThing(iot::CreateThing("Lamp")); } public: atk_dnesp32s3_box() : boot_button_(BOOT_BUTTON_GPIO) { InitializeI2c(); - InitializeATK_ST7789_80_Display(); + InitializeATK_ST7789_80_Display(); + xl9555_->SetOutputState(5, 1); + xl9555_->SetOutputState(7, 1); InitializeButtons(); InitializeIot(); } diff --git a/main/boards/atk-dnesp32s3-box/config.h b/main/boards/atk-dnesp32s3-box/config.h index 2479fc57..6b27e95b 100644 --- a/main/boards/atk-dnesp32s3-box/config.h +++ b/main/boards/atk-dnesp32s3-box/config.h @@ -25,4 +25,21 @@ #define DISPLAY_BACKLIGHT_PIN GPIO_NUM_NC #define DISPLAY_BACKLIGHT_OUTPUT_INVERT true + +// Pin Definitions +#define LCD_NUM_CS GPIO_NUM_1 +#define LCD_NUM_DC GPIO_NUM_2 +#define LCD_NUM_RD GPIO_NUM_41 +#define LCD_NUM_WR GPIO_NUM_42 +#define LCD_NUM_RST GPIO_NUM_NC + +#define GPIO_LCD_D0 GPIO_NUM_40 +#define GPIO_LCD_D1 GPIO_NUM_39 +#define GPIO_LCD_D2 GPIO_NUM_38 +#define GPIO_LCD_D3 GPIO_NUM_12 +#define GPIO_LCD_D4 GPIO_NUM_11 +#define GPIO_LCD_D5 GPIO_NUM_10 +#define GPIO_LCD_D6 GPIO_NUM_9 +#define GPIO_LCD_D7 GPIO_NUM_46 + #endif // _BOARD_CONFIG_H_ diff --git a/main/boards/atk-dnesp32s3/atk_dnesp32s3.cc b/main/boards/atk-dnesp32s3/atk_dnesp32s3.cc index e21e1db4..0c610613 100644 --- a/main/boards/atk-dnesp32s3/atk_dnesp32s3.cc +++ b/main/boards/atk-dnesp32s3/atk_dnesp32s3.cc @@ -53,8 +53,7 @@ private: LcdDisplay* display_; XL9555* xl9555_; - void InitializeI2c() - { + void InitializeI2c() { // Initialize I2C peripheral i2c_master_bus_config_t i2c_bus_cfg = { .i2c_port = (i2c_port_t)I2C_NUM_0, @@ -75,8 +74,7 @@ private: } // Initialize spi peripheral - void InitializeSpi() - { + void InitializeSpi() { spi_bus_config_t buscfg = {}; buscfg.mosi_io_num = LCD_MOSI_PIN; buscfg.miso_io_num = GPIO_NUM_NC; @@ -87,27 +85,22 @@ private: ESP_ERROR_CHECK(spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_CH_AUTO)); } - void InitializeButtons() - { - boot_button_.OnClick([this]() - { + void InitializeButtons() { + boot_button_.OnClick([this]() { auto& app = Application::GetInstance(); - if (app.GetDeviceState() == kDeviceStateStarting && !WifiStation::GetInstance().IsConnected()){ + if (app.GetDeviceState() == kDeviceStateStarting && !WifiStation::GetInstance().IsConnected()) { ResetWifiConfiguration(); } }); - boot_button_.OnPressDown([this]() - { + boot_button_.OnPressDown([this]() { Application::GetInstance().StartListening(); }); - boot_button_.OnPressUp([this]() - { + boot_button_.OnPressUp([this]() { Application::GetInstance().StopListening(); }); } - void InitializeSt7789Display() - { + void InitializeSt7789Display() { esp_lcd_panel_io_handle_t panel_io = nullptr; esp_lcd_panel_handle_t panel = nullptr; ESP_LOGD(TAG, "Install panel IO"); @@ -149,7 +142,7 @@ private: } // 物联网初始化,添加对 AI 可见设备 - void InitializeIot(){ + void InitializeIot() { auto& thing_manager = iot::ThingManager::GetInstance(); thing_manager.AddThing(iot::CreateThing("Speaker")); } diff --git a/main/display/atk_st7789_80i.cc b/main/display/atk_st7789_80i.cc deleted file mode 100644 index 3d32ff9a..00000000 --- a/main/display/atk_st7789_80i.cc +++ /dev/null @@ -1,337 +0,0 @@ -#include "atk_st7789_80i.h" -#include "font_awesome_symbols.h" - -#include -#include -#include -#include "driver/gpio.h" -#include "esp_lcd_panel_io.h" -#include "esp_lcd_panel_vendor.h" -#include "esp_lcd_panel_ops.h" - - -#define TAG "atk_st7789" - -#define ATK_ST7789_80_LVGL_TICK_PERIOD_MS 2 -#define ATK_ST7789_80_LVGL_TASK_MAX_DELAY_MS 20 -#define ATK_ST7789_80_LVGL_TASK_MIN_DELAY_MS 1 -#define ATK_ST7789_80_LVGL_TASK_STACK_SIZE (10 * 1024) -#define ATK_ST7789_80_LVGL_TASK_PRIORITY 10 - -// Pin Definitions -#define LCD_NUM_CS GPIO_NUM_1 -#define LCD_NUM_DC GPIO_NUM_2 -#define LCD_NUM_RD GPIO_NUM_41 -#define LCD_NUM_WR GPIO_NUM_42 -#define LCD_NUM_RST GPIO_NUM_NC - -#define GPIO_LCD_D0 GPIO_NUM_40 -#define GPIO_LCD_D1 GPIO_NUM_39 -#define GPIO_LCD_D2 GPIO_NUM_38 -#define GPIO_LCD_D3 GPIO_NUM_12 -#define GPIO_LCD_D4 GPIO_NUM_11 -#define GPIO_LCD_D5 GPIO_NUM_10 -#define GPIO_LCD_D6 GPIO_NUM_9 -#define GPIO_LCD_D7 GPIO_NUM_46 - -LV_FONT_DECLARE(font_puhui_14_1); -LV_FONT_DECLARE(font_awesome_30_1); -LV_FONT_DECLARE(font_awesome_14_1); - -static lv_disp_drv_t disp_drv; -static bool example_notify_lvgl_flush_ready(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *edata, void *user_ctx) { - lv_disp_drv_t *disp_driver = (lv_disp_drv_t *)user_ctx; - lv_disp_flush_ready(disp_driver); - return false; -} - -static void lvgl_disp_flush_cb(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_map) { - esp_lcd_panel_handle_t panel_handle = (esp_lcd_panel_handle_t)drv->user_data; - // copy a buffer's content to a specific area of the display - esp_lcd_panel_draw_bitmap(panel_handle, area->x1, area->y1, area->x2 + 1, area->y2 + 1, color_map); -} - -void ATK_ST7789_80_Display::LvglTask() { - ESP_LOGI(TAG, "Starting LVGL task"); - uint32_t task_delay_ms = ATK_ST7789_80_LVGL_TASK_MAX_DELAY_MS; - while (1) { - // Lock the mutex due to the LVGL APIs are not thread-safe - if (Lock()) { - task_delay_ms = lv_timer_handler(); - Unlock(); - } - if (task_delay_ms > ATK_ST7789_80_LVGL_TASK_MAX_DELAY_MS) { - task_delay_ms = ATK_ST7789_80_LVGL_TASK_MAX_DELAY_MS; - } - else if (task_delay_ms < ATK_ST7789_80_LVGL_TASK_MIN_DELAY_MS) { - task_delay_ms = ATK_ST7789_80_LVGL_TASK_MIN_DELAY_MS; - } - - vTaskDelay(pdMS_TO_TICKS(task_delay_ms)); - } -} - -extern "C" void emoji_font_init(); - - -ATK_ST7789_80_Display::ATK_ST7789_80_Display(gpio_num_t backlight_pin, - int width, int height, int offset_x, int offset_y, bool mirror_x, bool mirror_y, bool swap_xy) - : backlight_pin_(backlight_pin),mirror_x_(mirror_x), mirror_y_(mirror_y), swap_xy_(swap_xy) { - width_ = 320; - height_ = 240; - - width_ = width; - height_ = height; - offset_x_ = offset_x; - offset_y_ = offset_y; - esp_lcd_panel_io_handle_t io_handle = NULL; - esp_lcd_panel_handle_t panel_handle = NULL; - static lv_disp_draw_buf_t disp_buf; // contains internal graphic buffer(s) called draw buffer(s) - gpio_config_t gpio_init_struct; - InitializeBacklight(backlight_pin); // light set - emoji_font_init(); - - /* 配置RD引脚 */ - gpio_init_struct.intr_type = GPIO_INTR_DISABLE; - gpio_init_struct.mode = GPIO_MODE_INPUT_OUTPUT; - gpio_init_struct.pin_bit_mask = 1ull << LCD_NUM_RD; - gpio_init_struct.pull_down_en = GPIO_PULLDOWN_DISABLE; - gpio_init_struct.pull_up_en = GPIO_PULLUP_ENABLE; - gpio_config(&gpio_init_struct); - gpio_set_level(LCD_NUM_RD, 1); - - esp_lcd_i80_bus_handle_t i80_bus = NULL; - esp_lcd_i80_bus_config_t bus_config = { - .dc_gpio_num = LCD_NUM_DC, - .wr_gpio_num = LCD_NUM_WR, - .clk_src = LCD_CLK_SRC_DEFAULT, - .data_gpio_nums = { - GPIO_LCD_D0, - GPIO_LCD_D1, - GPIO_LCD_D2, - GPIO_LCD_D3, - GPIO_LCD_D4, - GPIO_LCD_D5, - GPIO_LCD_D6, - GPIO_LCD_D7, - }, - .bus_width = 8, - .max_transfer_bytes = width_ * height_ * sizeof(uint16_t), - .psram_trans_align = 64, - .sram_trans_align = 4, - }; - ESP_ERROR_CHECK(esp_lcd_new_i80_bus(&bus_config, &i80_bus)); - - esp_lcd_panel_io_i80_config_t io_config = { - .cs_gpio_num = LCD_NUM_CS, - .pclk_hz = (10 * 1000 * 1000), - .trans_queue_depth = 10, - .on_color_trans_done = example_notify_lvgl_flush_ready, - .user_ctx = &disp_drv, - .lcd_cmd_bits = 8, - .lcd_param_bits = 8, - .dc_levels = { - .dc_idle_level = 0, - .dc_cmd_level = 0, - .dc_dummy_level = 0, - .dc_data_level = 1, - }, - .flags = { - .swap_color_bytes = 0, - }, - }; - ESP_ERROR_CHECK(esp_lcd_new_panel_io_i80(i80_bus, &io_config, &io_handle)); - - esp_lcd_panel_dev_config_t panel_config = { - .reset_gpio_num = LCD_NUM_RST, - .rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB, - .bits_per_pixel = 16, - }; - ESP_ERROR_CHECK(esp_lcd_new_panel_st7789(io_handle, &panel_config, &panel_handle)); - - esp_lcd_panel_reset(panel_handle); - esp_lcd_panel_init(panel_handle); - esp_lcd_panel_invert_color(panel_handle, true); - esp_lcd_panel_set_gap(panel_handle, 0, 0); - uint8_t data0[] = {0x00}; - uint8_t data1[] = {0x65}; - esp_lcd_panel_io_tx_param(io_handle, 0x36, data0, 1); - esp_lcd_panel_io_tx_param(io_handle, 0x3A, data1, 1); - esp_lcd_panel_swap_xy(panel_handle, swap_xy); - esp_lcd_panel_mirror(panel_handle, mirror_x, mirror_y); - ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_handle, true)); - - ESP_LOGI(TAG, "Initialize LVGL library"); - lv_init(); - void *buf1 = NULL; - void *buf2 = NULL; - - buf1 = heap_caps_malloc(width_ * 60 * sizeof(lv_color_t), MALLOC_CAP_DMA); - buf2 = heap_caps_malloc(width_ * 60 * sizeof(lv_color_t), MALLOC_CAP_DMA); - - lv_disp_draw_buf_init(&disp_buf, buf1, buf2, width_ * 60); - - ESP_LOGI(TAG, "Register display driver to LVGL"); - lv_disp_drv_init(&disp_drv); - disp_drv.hor_res = width_; - disp_drv.ver_res = height_; - disp_drv.offset_x = offset_x_; - disp_drv.offset_y = offset_y_; - disp_drv.flush_cb = lvgl_disp_flush_cb; - disp_drv.draw_buf = &disp_buf; - disp_drv.user_data = panel_handle; - lv_disp_drv_register(&disp_drv); - - ESP_LOGI(TAG, "Install LVGL tick timer"); - // Tick interface for LVGL (using esp_timer to generate 2ms periodic event) - const esp_timer_create_args_t lvgl_tick_timer_args = { - .callback = [](void* arg) { - lv_tick_inc(ATK_ST7789_80_LVGL_TICK_PERIOD_MS); - }, - .arg = NULL, - .dispatch_method = ESP_TIMER_TASK, - .name = "LVGL Tick Timer", - .skip_unhandled_events = false - }; - ESP_ERROR_CHECK(esp_timer_create(&lvgl_tick_timer_args, &lvgl_tick_timer_)); - ESP_ERROR_CHECK(esp_timer_start_periodic(lvgl_tick_timer_, ATK_ST7789_80_LVGL_TICK_PERIOD_MS * 1000)); - - lvgl_mutex_ = xSemaphoreCreateRecursiveMutex(); - assert(lvgl_mutex_ != nullptr); - ESP_LOGI(TAG, "Create LVGL task"); - xTaskCreate([](void *arg) { - static_cast(arg)->LvglTask(); - vTaskDelete(NULL); - }, "LVGL", ATK_ST7789_80_LVGL_TASK_STACK_SIZE, this, ATK_ST7789_80_LVGL_TASK_PRIORITY, NULL); - - SetupUI(); -} - -ATK_ST7789_80_Display::~ATK_ST7789_80_Display() { - ESP_ERROR_CHECK(esp_timer_stop(lvgl_tick_timer_)); - ESP_ERROR_CHECK(esp_timer_delete(lvgl_tick_timer_)); - - if (content_ != nullptr) { - lv_obj_del(content_); - } - - if (status_bar_ != nullptr) { - lv_obj_del(status_bar_); - } - - if (side_bar_ != nullptr) { - lv_obj_del(side_bar_); - } - - if (container_ != nullptr) { - lv_obj_del(container_); - } - - if (panel_ != nullptr) { - esp_lcd_panel_del(panel_); - } - - if (panel_io_ != nullptr) { - esp_lcd_panel_io_del(panel_io_); - } - - vSemaphoreDelete(lvgl_mutex_); -} - -void ATK_ST7789_80_Display::InitializeBacklight(gpio_num_t backlight_pin) { - if (backlight_pin == GPIO_NUM_NC) { - return; - } - /* Setup LEDC peripheral for PWM backlight control */ -} - -bool ATK_ST7789_80_Display::Lock(int timeout_ms) { - // Convert timeout in milliseconds to FreeRTOS ticks - // If `timeout_ms` is set to 0, the program will block until the condition is met - const TickType_t timeout_ticks = (timeout_ms == 0) ? portMAX_DELAY : pdMS_TO_TICKS(timeout_ms); - return xSemaphoreTakeRecursive(lvgl_mutex_, timeout_ticks) == pdTRUE; -} - -void ATK_ST7789_80_Display::Unlock() { - xSemaphoreGiveRecursive(lvgl_mutex_); -} - -void ATK_ST7789_80_Display::SetupUI() { - DisplayLockGuard lock(this); - - auto screen = lv_disp_get_scr_act(lv_disp_get_default()); - lv_obj_set_style_text_font(screen, &font_puhui_14_1, 0); - lv_obj_set_style_text_color(screen, lv_color_black(), 0); - - /* Container */ - container_ = lv_obj_create(screen); - lv_obj_set_size(container_, LV_HOR_RES, LV_VER_RES); - lv_obj_set_flex_flow(container_, LV_FLEX_FLOW_COLUMN); - lv_obj_set_style_pad_all(container_, 0, 0); - lv_obj_set_style_border_width(container_, 0, 0); - lv_obj_set_style_pad_row(container_, 0, 0); - - /* Status bar */ - status_bar_ = lv_obj_create(container_); - lv_obj_set_size(status_bar_, LV_HOR_RES, 18); - lv_obj_set_style_radius(status_bar_, 0, 0); - - /* Content */ - content_ = lv_obj_create(container_); - lv_obj_set_scrollbar_mode(content_, LV_SCROLLBAR_MODE_OFF); - lv_obj_set_style_radius(content_, 0, 0); - lv_obj_set_width(content_, LV_HOR_RES); - lv_obj_set_flex_grow(content_, 1); - - lv_obj_set_flex_flow(content_, LV_FLEX_FLOW_COLUMN); // 垂直布局(从上到下) - lv_obj_set_flex_align(content_, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_SPACE_EVENLY); // 子对象居中对齐,等距分布 - - emotion_label_ = lv_label_create(content_); - lv_obj_set_style_text_font(emotion_label_, &font_awesome_30_1, 0); - lv_label_set_text(emotion_label_, FONT_AWESOME_AI_CHIP); - // lv_obj_center(emotion_label_); - - chat_message_label_ = lv_label_create(content_); - lv_label_set_text(chat_message_label_, ""); - lv_obj_set_width(chat_message_label_, LV_HOR_RES * 0.8); // 限制宽度为屏幕宽度的 80% - lv_label_set_long_mode(chat_message_label_, LV_LABEL_LONG_WRAP); // 设置为自动换行模式 - lv_obj_set_style_text_align(chat_message_label_, LV_TEXT_ALIGN_CENTER, 0); // 设置文本居中对齐 - - /* Status bar */ - lv_obj_set_flex_flow(status_bar_, LV_FLEX_FLOW_ROW); - lv_obj_set_style_pad_all(status_bar_, 0, 0); - lv_obj_set_style_border_width(status_bar_, 0, 0); - lv_obj_set_style_pad_column(status_bar_, 0, 0); - - network_label_ = lv_label_create(status_bar_); - lv_label_set_text(network_label_, ""); - lv_obj_set_style_text_font(network_label_, &font_awesome_14_1, 0); - - notification_label_ = lv_label_create(status_bar_); - lv_obj_set_flex_grow(notification_label_, 1); - lv_obj_set_style_text_align(notification_label_, LV_TEXT_ALIGN_CENTER, 0); - lv_label_set_text(notification_label_, "通知"); - lv_obj_add_flag(notification_label_, LV_OBJ_FLAG_HIDDEN); - - status_label_ = lv_label_create(status_bar_); - lv_obj_set_flex_grow(status_label_, 1); - lv_label_set_long_mode(status_label_, LV_LABEL_LONG_SCROLL_CIRCULAR); - lv_label_set_text(status_label_, "正在初始化"); - lv_obj_set_style_text_align(status_label_, LV_TEXT_ALIGN_CENTER, 0); - - mute_label_ = lv_label_create(status_bar_); - lv_label_set_text(mute_label_, ""); - lv_obj_set_style_text_font(mute_label_, &font_awesome_14_1, 0); - - battery_label_ = lv_label_create(status_bar_); - lv_label_set_text(battery_label_, ""); - lv_obj_set_style_text_font(battery_label_, &font_awesome_14_1, 0); -} - -void ATK_ST7789_80_Display::SetChatMessage(const std::string &role, const std::string &content) { - if (chat_message_label_ == nullptr) { - return; - } - - lv_label_set_text(chat_message_label_, content.c_str()); -} diff --git a/main/display/atk_st7789_80i.h b/main/display/atk_st7789_80i.h deleted file mode 100644 index 32297793..00000000 --- a/main/display/atk_st7789_80i.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef ATK_ST7789_80I_H -#define ATK_ST7789_80I_H - -#include "display.h" - -#include -#include -#include -#include -#include -#include - -class ATK_ST7789_80_Display : public Display { -protected: - esp_lcd_panel_io_handle_t panel_io_ = nullptr; - esp_lcd_panel_handle_t panel_ = nullptr; - gpio_num_t backlight_pin_ = GPIO_NUM_4; - bool backlight_output_invert_ = false; - bool mirror_x_ = false; - bool mirror_y_ = false; - bool swap_xy_ = false; - int offset_x_ = 0; - int offset_y_ = 0; - SemaphoreHandle_t lvgl_mutex_ = nullptr; - esp_timer_handle_t lvgl_tick_timer_ = nullptr; - - lv_obj_t* status_bar_ = nullptr; - lv_obj_t* content_ = nullptr; - lv_obj_t* container_ = nullptr; - lv_obj_t* side_bar_ = nullptr; - lv_obj_t* chat_message_label_ = nullptr; - - void InitializeBacklight(gpio_num_t backlight_pin); - void LvglTask(); - - virtual void SetupUI(); - virtual bool Lock(int timeout_ms = 0) override; - virtual void Unlock() override; - -public: - ATK_ST7789_80_Display(gpio_num_t backlight_pin,int width, int height, int offset_x, int offset_y, bool mirror_x, bool mirror_y, bool swap_xy); - ~ATK_ST7789_80_Display(); - void SetChatMessage(const std::string &role, const std::string &content) override; -}; - -#endif // LCD_DISPLAY_H