diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 7ccbbb84..4eec5248 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -303,6 +303,8 @@ elseif(CONFIG_BOARD_TYPE_ESP32P4_WIFI6_Touch_LCD_XC) set(BUILTIN_TEXT_FONT font_puhui_basic_30_4) set(BUILTIN_ICON_FONT font_awesome_30_4) set(DEFAULT_EMOJI_COLLECTION twemoji_64) +elseif(CONFIG_BOARD_TYPE_ESP32P4_Function_EV_Board) + set(BOARD_TYPE "esp-p4-function-ev-board") elseif(CONFIG_BOARD_TYPE_BREAD_COMPACT_WIFI_LCD) set(BOARD_TYPE "bread-compact-wifi-lcd") set(BUILTIN_TEXT_FONT font_puhui_basic_16_4) diff --git a/main/Kconfig.projbuild b/main/Kconfig.projbuild index 2ea86cc4..085c9098 100644 --- a/main/Kconfig.projbuild +++ b/main/Kconfig.projbuild @@ -290,6 +290,9 @@ choice BOARD_TYPE config BOARD_TYPE_ESP32P4_WIFI6_Touch_LCD_XC bool "Waveshare ESP32-P4-WIFI6-Touch-LCD-3.4C or ESP32-P4-WIFI6-Touch-LCD-4C" depends on IDF_TARGET_ESP32P4 + config BOARD_TYPE_ESP_P4_Function_EV_Board + bool "ESP-P4-Function-EV-Board" + depends on IDF_TARGET_ESP32P4 config BOARD_TYPE_TUDOUZI bool "土豆子" depends on IDF_TARGET_ESP32S3 diff --git a/main/audio/wake_words/custom_wake_word.cc b/main/audio/wake_words/custom_wake_word.cc index 9fa66588..2a1fb7ae 100644 --- a/main/audio/wake_words/custom_wake_word.cc +++ b/main/audio/wake_words/custom_wake_word.cc @@ -107,6 +107,10 @@ bool CustomWakeWord::Initialize(AudioCodec* codec, srmodel_list_t* models_list) // 初始化 multinet (命令词识别) mn_name_ = esp_srmodel_filter(models_, ESP_MN_PREFIX, language_.c_str()); + if (mn_name_ == nullptr) { + ESP_LOGW(TAG, "Language '%s' multinet not found, falling back to any multinet model", language_.c_str()); + mn_name_ = esp_srmodel_filter(models_, ESP_MN_PREFIX, NULL); + } if (mn_name_ == nullptr) { ESP_LOGE(TAG, "Failed to initialize multinet, mn_name is nullptr"); ESP_LOGI(TAG, "Please refer to https://pcn7cs20v8cr.feishu.cn/wiki/CpQjwQsCJiQSWSkYEvrcxcbVnwh to add custom wake word"); diff --git a/main/boards/esp-p4-function-ev-board/README.md b/main/boards/esp-p4-function-ev-board/README.md new file mode 100644 index 00000000..6320405c --- /dev/null +++ b/main/boards/esp-p4-function-ev-board/README.md @@ -0,0 +1,35 @@ +# ESP-P4-Function-EV-Board + +Board support for ESP-P4-Function-EV-Board. Wi‑Fi uses ESP‑Hosted via the on‑board ESP32‑C6. LCD is supported via the official MIPI‑DSI LCD adapter. + +## Features +- Wi‑Fi: `esp_wifi_remote` + `esp_hosted` (SDIO) with ESP32‑C6 co‑processor +- Display: 7" MIPI‑DSI LCD (1024×600) via adapter; can also run headless +- Audio: Can run with dummy codec; board includes ES8311 + PA if needed + +## Configure +In `menuconfig`: Xiaozhi Assistant -> Board Type -> ESP-P4-Function-EV-Board + +Ensure these are set (auto-set when building via config.json): +- `CONFIG_SLAVE_IDF_TARGET_ESP32C6=y` +- `CONFIG_ESP_HOSTED_P4_DEV_BOARD_FUNC_BOARD=y` +- `CONFIG_ESP_HOSTED_SDIO_HOST_INTERFACE=y` +- `CONFIG_ESP_HOSTED_SDIO_4_BIT_BUS=y` + +## LCD Connection (from Espressif user guide) +- Connect the LCD adapter board J3 to the board’s MIPI DSI connector (reverse ribbon). +- Wire `RST_LCD` (adapter J6) to `GPIO27` (board J1). +- Wire `PWM` (adapter J6) to `GPIO26` (board J1). +- Optionally power the LCD adapter via its USB or provide `5V` and `GND` from the board. + +These pins are pre-configured in `config.h` as `PIN_NUM_LCD_RST=GPIO27` and `DISPLAY_BACKLIGHT_PIN=GPIO26`. Resolution is set to 1024×600. + +## Build (example) +```powershell +idf.py set-target esp32p4 +idf.py menuconfig +idf.py build +``` + +Tip: In menuconfig, choose Xiaozhi Assistant -> Board Type -> ESP-P4-Function-EV-Board. +If building a release via scripts, the `config.json` in this folder appends the required Hosted options. diff --git a/main/boards/esp-p4-function-ev-board/config.h b/main/boards/esp-p4-function-ev-board/config.h new file mode 100644 index 00000000..aca0c939 --- /dev/null +++ b/main/boards/esp-p4-function-ev-board/config.h @@ -0,0 +1,11 @@ +#ifndef _BOARD_CONFIG_H_ +#define _BOARD_CONFIG_H_ + +#include "bsp/esp32_p4_function_ev_board.h" // Library for board configs and pins + +#define AUDIO_INPUT_SAMPLE_RATE 24000 +#define AUDIO_OUTPUT_SAMPLE_RATE 24000 + +#define DISPLAY_BACKLIGHT_OUTPUT_INVERT false + +#endif // _BOARD_CONFIG_H_ \ No newline at end of file diff --git a/main/boards/esp-p4-function-ev-board/config.json b/main/boards/esp-p4-function-ev-board/config.json new file mode 100644 index 00000000..d191f94b --- /dev/null +++ b/main/boards/esp-p4-function-ev-board/config.json @@ -0,0 +1,16 @@ +{ + "target": "esp32p4", + "builds": [ + { + "name": "esp-p4-function-ev-board", + "sdkconfig_append": [ + "CONFIG_SLAVE_IDF_TARGET_ESP32C6=y", + "CONFIG_ESP_HOSTED_P4_DEV_BOARD_FUNC_BOARD=y", + "CONFIG_ESP_HOSTED_SDIO_HOST_INTERFACE=y", + "CONFIG_ESP_HOSTED_SDIO_4_BIT_BUS=y", + "CONFIG_SPI_FLASH_SUPPORT_GD_CHIP=y", + "CONFIG_BSP_LCD_TYPE_1024_600=y" + ] + } + ] +} diff --git a/main/boards/esp-p4-function-ev-board/esp-p4-function-ev-board.cc b/main/boards/esp-p4-function-ev-board/esp-p4-function-ev-board.cc new file mode 100644 index 00000000..edc84c53 --- /dev/null +++ b/main/boards/esp-p4-function-ev-board/esp-p4-function-ev-board.cc @@ -0,0 +1,129 @@ +#include "wifi_board.h" +#include "audio/codecs/es8311_audio_codec.h" +// Display +#include "display/display.h" +#include "display/lcd_display.h" +// Backlight +// PwmBacklight is declared in backlight headers pulled by display/lcd_display includes via lvgl stack + +#include "application.h" +#include "button.h" +#include "config.h" + +#include +#include +#include +#include +#include +// SD card +#include +#include +#include +#include +// SD power control (on-chip LDO) +#include "sd_pwr_ctrl_by_on_chip_ldo.h" + +// MIPI-DSI / LCD vendor includes (library may replace some) +#include "esp_lcd_panel_ops.h" +#include "esp_lcd_mipi_dsi.h" +#include "esp_ldo_regulator.h" +#include "esp_lcd_ek79007.h" +#include "esp_lcd_touch_gt911.h" + +// Library includes +#include "bsp/esp32_p4_function_ev_board.h" +#include "bsp/touch.h" + +#define TAG "ESP32P4FuncEV" + +class ESP32P4FunctionEvBoard : public WifiBoard +{ +private: + i2c_master_bus_handle_t codec_i2c_bus_ = nullptr; + Button boot_button_; + LcdDisplay *display_ = nullptr; + esp_lcd_touch_handle_t tp_ = nullptr; + + void InitializeI2cBuses() + { + ESP_ERROR_CHECK(bsp_i2c_init()); + codec_i2c_bus_ = bsp_i2c_get_handle(); + } + + // Touch I2C bus initialization is not required for this board (handled elsewhere) + void InitializeTouchI2cBus() + { + // No implementation needed + } + + void InitializeLCD() + { + bsp_display_config_t config = { + .hdmi_resolution = BSP_HDMI_RES_NONE, + .dsi_bus = { + .phy_clk_src = MIPI_DSI_PHY_CLK_SRC_DEFAULT, + .lane_bit_rate_mbps = 1000, + }, + }; + + bsp_lcd_handles_t handles; + ESP_ERROR_CHECK(bsp_display_new_with_handles(&config, &handles)); + + display_ = new MipiLcdDisplay(handles.io, handles.panel, 1024, 600, 0, 0, true, true, false); + } + + void InitializeButtons() + { + boot_button_.OnClick([this]() + { + auto& app = Application::GetInstance(); + if (app.GetDeviceState() == kDeviceStateStarting && !WifiStation::GetInstance().IsConnected()) { + ResetWifiConfiguration(); + } + app.ToggleChatState(); }); + } + + void InitializeTouch() + { + ESP_ERROR_CHECK(bsp_touch_new(NULL, &tp_)); + } + +public: + + ESP32P4FunctionEvBoard() : boot_button_(0) + { + InitializeI2cBuses(); + // Audio is initialized by Es8311AudioCodec + InitializeLCD(); + InitializeButtons(); + InitializeTouch(); + GetBacklight()->RestoreBrightness(); + } + + ~ESP32P4FunctionEvBoard() + { + // Clean up display pointer + delete display_; + display_ = nullptr; + // If other resources need cleanup, add here + } + + virtual AudioCodec *GetAudioCodec() override + { + static Es8311AudioCodec audio_codec( + codec_i2c_bus_, (i2c_port_t)BSP_I2C_NUM, AUDIO_INPUT_SAMPLE_RATE, AUDIO_OUTPUT_SAMPLE_RATE, + BSP_I2S_MCLK, BSP_I2S_SCLK, BSP_I2S_LCLK, BSP_I2S_DOUT, BSP_I2S_DSIN, + BSP_POWER_AMP_IO, ES8311_CODEC_DEFAULT_ADDR, true, false); + return &audio_codec; + } + + virtual Display *GetDisplay() override { return display_; } + + virtual Backlight *GetBacklight() override + { + static PwmBacklight backlight(BSP_LCD_BACKLIGHT, DISPLAY_BACKLIGHT_OUTPUT_INVERT); + return &backlight; + } +}; + +DECLARE_BOARD(ESP32P4FunctionEvBoard); diff --git a/main/display/lcd_display.cc b/main/display/lcd_display.cc index f5a4aa85..7dcc656b 100644 --- a/main/display/lcd_display.cc +++ b/main/display/lcd_display.cc @@ -100,7 +100,14 @@ SpiLcdDisplay::SpiLcdDisplay(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_h // Set the display to on ESP_LOGI(TAG, "Turning display on"); - ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_, true)); + { + esp_err_t __err = esp_lcd_panel_disp_on_off(panel_, true); + if (__err == ESP_ERR_NOT_SUPPORTED) { + ESP_LOGW(TAG, "Panel does not support disp_on_off; assuming ON"); + } else { + ESP_ERROR_CHECK(__err); + } + } ESP_LOGI(TAG, "Initialize LVGL library"); lv_init(); @@ -165,6 +172,7 @@ SpiLcdDisplay::SpiLcdDisplay(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_h SetupUI(); } + // RGB LCD实现 RgbLcdDisplay::RgbLcdDisplay(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_handle_t panel, int width, int height, int offset_x, int offset_y, diff --git a/main/idf_component.yml b/main/idf_component.yml index f3f32ebf..d3bd0416 100644 --- a/main/idf_component.yml +++ b/main/idf_component.yml @@ -5,6 +5,7 @@ dependencies: espressif/esp_lcd_gc9a01: ==2.0.1 espressif/esp_lcd_st77916: ^1.0.1 espressif/esp_lcd_axs15231b: ^1.0.0 + espressif/esp_lcd_st7701: version: ^1.1.4 rules: @@ -22,7 +23,7 @@ dependencies: 78/esp-ml307: ~3.3.6 78/xiaozhi-fonts: ~1.5.4 espressif/led_strip: ~3.0.1 - espressif/esp_codec_dev: ~1.4.0 + espressif/esp_codec_dev: ~1.5 espressif/esp-sr: ~2.1.5 espressif/button: ~4.1.3 espressif/knob: ^1.0.0 @@ -65,6 +66,10 @@ dependencies: version: '*' rules: - if: target in [esp32p4] + espressif/esp32_p4_function_ev_board: + version: "^5.0.3" + rules: + - if: target in [esp32p4] espressif/esp_lcd_ili9881c: version: ^1.0.1 rules: