xiaozhi-esp32 自定义开发板接入指南:从 config.json 到固件构建的完整流程
2026/9/11 20:32:07 网站建设 项目流程

xiaozhi-esp32 自定义开发板接入指南:从 config.json 到固件构建的完整流程

【免费下载链接】xiaozhi-esp32An MCP-based chatbot | 一个基于MCP的聊天机器人项目地址: https://gitcode.com/GitHub_Trending/xia/xiaozhi-esp32

本指南以 docs/custom-board.md 为核心骨架,讲解如何在 xiaozhi-esp32 开源项目中从零新增一款自定义开发板:包括目录结构约定、config.h/config.json配置要点、板级 C++ 类的实现、Kconfig 与 CMake 的构建系统接入,以及通过scripts/build.py一键配置编译的完整流程。读完本文,你将具备把任意基于 ESP32 系列芯片的硬件(音频编解码器、屏幕、按键、4G 模块等组合)接入该项目,并生成带独立 OTA 固件通道的完整能力。

适用前提:本文基于当前仓库的实际代码(main/boards/下 70+ 款板级实现、scripts/build.py、main/Kconfig.projbuild 与 main/CMakeLists.txt)编写;文中涉及的 ESP-IDF、LVGL 等外部工具链的使用以其官方文档为准。

一、为什么需要“自定义开发板”机制

xiaozhi-esp32 是一个基于 ESP32 系列芯片的 AI 语音助手项目,支持 70 多款官方与社区开发板,每一款都在main/boards/下拥有自己的独立目录。新增硬件支持的本质,就是为你的板卡建立一套"身份 + 配置 + 实现"三件套:

  • 身份(identity):由config.json中的typename字段决定,固件会向服务端上报该标识,OTA 升级也依赖它定位固件;
  • 配置(configuration)config.h中的引脚、采样率、屏幕参数等硬件级设定;
  • 实现(implementation)xxx_board.cc中继承基类的板级初始化与虚函数实现。

最重要的一条警告:永远不要覆盖已有板卡的配置

Warning:对于 IO 配置与现有板卡不同的自定义硬件,绝不要直接覆盖原有板卡的配置文件。必须新建一种板型,或利用config.jsonbuilds数组生成固件名不同、sdkconfig宏不同的独立变体。构建请使用python scripts/build.py [board-directory]

原因在 docs/custom-board.md 中有明确说明:覆盖已有板卡配置是危险的,因为 OTA 更新可能用原板卡的官方固件替换你的自定义固件。每一款板卡都必须拥有唯一身份和自己的固件更新通道——这与 scripts/build.py 中_collect_variants()type/name全局唯一性的严格校验(重复即报错)是相互印证的。

二、目录布局约定

一个板卡目录通常包含以下文件:

文件作用
xxx_board.cc板级初始化和胶水代码(板级类、虚函数覆写、DECLARE_BOARD注册)
config.h引脚分配与板级设置
config.json上报的板卡类型与发布配置,供 CMake 和scripts/build.py消费
README.md板卡专属说明(硬件要求、烧录方法、特殊注意事项)

板卡可以平铺在main/boards/下,也可以按厂商分组放在main/boards/<manufacturer>/<board>/下(详见后文"厂商子目录"一节)。当前仓库两种布局都有实例,例如平铺的 main/boards/bread-compact-wifi/ 与分组存放的 main/boards/waveshare/esp32-p4-nano/。

三、第一步:创建板卡目录

main/boards/下按[厂商]-[型号]的命名风格新建目录(示例:m5stack-tab5):

mkdir main/boards/my-custom-board

命名约定:目录名使用小写字母与连字符(如wavesharelceda-course-examples),便于与 Kconfig 符号、构建产物名称保持一致。

四、第二步:编写配置文件

4.1 config.h:引脚与硬件参数

config.h集中定义全部硬件设定,主要包括:

  • 音频采样率与 I2S 引脚映射;
  • 音频编解码器 I2C 地址与引脚;
  • 按键与 LED 引脚;
  • 显示参数与引脚。

以下示例取自 docs/custom-board.md(参照lichuang-c3-dev风格),AUDIO_I2S_GPIO_*系列宏被 main/boards/common/wifi_board.h 等基类通过GetAudioCodec()间接消费:

#ifndef _BOARD_CONFIG_H_ #define _BOARD_CONFIG_H_ #include <driver/gpio.h> // Audio #define AUDIO_INPUT_SAMPLE_RATE 24000 #define AUDIO_OUTPUT_SAMPLE_RATE 24000 #define AUDIO_I2S_GPIO_MCLK GPIO_NUM_10 #define AUDIO_I2S_GPIO_WS GPIO_NUM_12 #define AUDIO_I2S_GPIO_BCLK GPIO_NUM_8 #define AUDIO_I2S_GPIO_DIN GPIO_NUM_7 #define AUDIO_I2S_GPIO_DOUT GPIO_NUM_11 #define AUDIO_CODEC_PA_PIN GPIO_NUM_13 #define AUDIO_CODEC_I2C_SDA_PIN GPIO_NUM_0 #define AUDIO_CODEC_I2C_SCL_PIN GPIO_NUM_1 #define AUDIO_CODEC_ES8311_ADDR ES8311_CODEC_DEFAULT_ADDR // Buttons #define BOOT_BUTTON_GPIO GPIO_NUM_9 // Display #define DISPLAY_SPI_SCK_PIN GPIO_NUM_3 #define DISPLAY_SPI_MOSI_PIN GPIO_NUM_5 #define DISPLAY_DC_PIN GPIO_NUM_6 #define DISPLAY_SPI_CS_PIN GPIO_NUM_4 #define DISPLAY_WIDTH 320 #define DISPLAY_HEIGHT 240 #define DISPLAY_MIRROR_X true #define DISPLAY_MIRROR_Y false #define DISPLAY_SWAP_XY true #define DISPLAY_OFFSET_X 0 #define DISPLAY_OFFSET_Y 0 #define DISPLAY_BACKLIGHT_PIN GPIO_NUM_2 #define DISPLAY_BACKLIGHT_OUTPUT_INVERT true #endif // _BOARD_CONFIG_H_

参数说明与取值提示

  • AUDIO_INPUT/OUTPUT_SAMPLE_RATE:语音链路采样率,项目常见取值为 16000 或 24000,需与所选音频编解码器及服务端协议匹配;
  • AUDIO_CODEC_PA_PIN:功放(PA)使能引脚,若硬件无独立 PA 使能,可留空或不定义;
  • DISPLAY_MIRROR_X/YDISPLAY_SWAP_XY:屏幕镜像与横竖屏交换开关,与后文esp_lcd_panel_mirror()/esp_lcd_panel_swap_xy()调用一一对应;
  • DISPLAY_BACKLIGHT_OUTPUT_INVERT:背光 PWM 极性是否反转,取决于背光驱动电路是共阳还是共阴;
  • DISPLAY_WIDTH/HEIGHT/OFFSET_*:分辨率与偏移,用于SpiLcdDisplay的初始化参数。

4.2 config.json:兼容敏感的上报身份与构建配置

config.json定义了对兼容性敏感的上报类型,并驱动scripts/build.py

{ "type": "my-custom-board", "target": "esp32s3", "builds": [ { "name": "my-custom-board", "sdkconfig_append": [ "CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y", "CONFIG_PARTITION_TABLE_CUSTOM_FILENAME=\"partitions/v2/8m.csv\"" ] } ] }

字段含义

字段说明
type兼容敏感的板卡家族标识,固件上报给服务端。发布后应保持稳定,变更会导致 OTA 通道失效
target目标芯片,必须与真实硬件一致(esp32esp32s3esp32c3esp32c6esp32p4等)
name发布构建上报的固件变体名,通常与type一致
sdkconfig_append追加到默认配置中的额外 sdkconfig 行

命名硬性约束typename只能包含小写字母、数字、句点(.)与连字符(-),不允许下划线、空格和大写字母。这条规则在 scripts/build.py 中由_REPORTED_IDENTIFIER_PATTERN = re.compile(r"^[a-z0-9.-]+$")_validate_reported_identifier()强制校验,违规会直接抛出ValueError

常用的sdkconfig_append条目

// Flash size "CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y" "CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y" // Partition table "CONFIG_PARTITION_TABLE_CUSTOM_FILENAME=\"partitions/v2/4m.csv\"" "CONFIG_PARTITION_TABLE_CUSTOM_FILENAME=\"partitions/v2/8m.csv\"" // Audio pipeline "CONFIG_USE_DEVICE_AEC=y" // enable on-device AEC

项目在适用目标上默认使用 16MB Flash 与partitions/v2/16m.csv不要重复写入与项目/目标默认值一致的条目,只在确有板卡级差异时才使用sdkconfig_append覆盖。分区表定义见 partitions/v2/。

不要在板卡config.json中选择语言或指定唤醒词。这些属于用户构建选项,必须统一通过menuconfig或构建脚本参数配置,以保证 CLI、Agent 与在线构建共用同一套接口(这也正是 scripts/build.py 提供--language/--wake-word参数的原因)。

多变体(builds 数组)示例:以仓库现有板卡 main/boards/bread-compact-wifi/config.json 为例,同一块板通过两个 build 条目分别产出 128x32 与 128x64 OLED 的固件变体:

{ "type": "bread-compact-wifi", "target": "esp32s3", "builds": [ { "name": "bread-compact-wifi", "sdkconfig_append": ["CONFIG_OLED_SSD1306_128X32=y"] }, { "name": "bread-compact-wifi-128x64", "sdkconfig_append": ["CONFIG_OLED_SSD1306_128X64=y"] } ] }

此外,builds条目还可选配idf_version字段(如"<6.0")做 ESP-IDF 版本门控,由 scripts/build.py 的_get_builds_for_idf()处理,便于在同一板卡下兼容不同 IDF 版本。

五、第三步:实现板级类

创建my_custom_board.cc,一个基础板级类包含四部分:

  1. 类声明:继承WifiBoard(WiFi 板)或Ml307Board(4G 板);
  2. 初始化辅助方法:I2C、显示、按键、IoT/MCP 工具等;
  3. 虚函数覆写GetAudioCodec()GetDisplay()GetBacklight()等;
  4. 板卡注册DECLARE_BOARD(ClassName)

完整示例(来自 docs/custom-board.md):

#include "wifi_board.h" #include "codecs/es8311_audio_codec.h" #include "display/lcd_display.h" #include "application.h" #include "button.h" #include "config.h" #include "mcp_server.h" #include <esp_log.h> #include <driver/i2c_master.h> #include <driver/spi_common.h> #define TAG "MyCustomBoard" class MyCustomBoard : public WifiBoard { private: i2c_master_bus_handle_t codec_i2c_bus_; Button boot_button_; LcdDisplay* display_; void InitializeI2c() { i2c_master_bus_config_t i2c_bus_cfg = { .i2c_port = I2C_NUM_0, .sda_io_num = AUDIO_CODEC_I2C_SDA_PIN, .scl_io_num = AUDIO_CODEC_I2C_SCL_PIN, .clk_source = I2C_CLK_SRC_DEFAULT, .glitch_ignore_cnt = 7, .intr_priority = 0, .trans_queue_depth = 0, .flags = { .enable_internal_pullup = 1, }, }; ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_cfg, &codec_i2c_bus_)); } void InitializeSpi() { spi_bus_config_t buscfg = {}; buscfg.mosi_io_num = DISPLAY_SPI_MOSI_PIN; buscfg.miso_io_num = GPIO_NUM_NC; buscfg.sclk_io_num = DISPLAY_SPI_SCK_PIN; buscfg.quadwp_io_num = GPIO_NUM_NC; buscfg.quadhd_io_num = GPIO_NUM_NC; buscfg.max_transfer_sz = DISPLAY_WIDTH * DISPLAY_HEIGHT * sizeof(uint16_t); ESP_ERROR_CHECK(spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_CH_AUTO)); } void InitializeButtons() { boot_button_.OnClick([this]() { auto& app = Application::GetInstance(); if (app.GetDeviceState() == kDeviceStateStarting) { EnterWifiConfigMode(); return; } app.ToggleChatState(); }); } void InitializeDisplay() { esp_lcd_panel_io_handle_t panel_io = nullptr; esp_lcd_panel_handle_t panel = nullptr; esp_lcd_panel_io_spi_config_t io_config = {}; io_config.cs_gpio_num = DISPLAY_SPI_CS_PIN; io_config.dc_gpio_num = DISPLAY_DC_PIN; io_config.spi_mode = 2; io_config.pclk_hz = 80 * 1000 * 1000; io_config.trans_queue_depth = 10; io_config.lcd_cmd_bits = 8; io_config.lcd_param_bits = 8; ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(SPI2_HOST, &io_config, &panel_io)); esp_lcd_panel_dev_config_t panel_config = {}; panel_config.reset_gpio_num = GPIO_NUM_NC; panel_config.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB; panel_config.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_swap_xy(panel, DISPLAY_SWAP_XY); esp_lcd_panel_mirror(panel, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y); display_ = new SpiLcdDisplay(panel_io, panel, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY); } void InitializeTools() { // Register MCP tools here; see docs/mcp-usage.md. } public: MyCustomBoard() : boot_button_(BOOT_BUTTON_GPIO) { InitializeI2c(); InitializeSpi(); InitializeDisplay(); InitializeButtons(); InitializeTools(); GetBacklight()->SetBrightness(100); } virtual AudioCodec* GetAudioCodec() override { static Es8311AudioCodec audio_codec( codec_i2c_bus_, I2C_NUM_0, AUDIO_INPUT_SAMPLE_RATE, AUDIO_OUTPUT_SAMPLE_RATE, AUDIO_I2S_GPIO_MCLK, AUDIO_I2S_GPIO_BCLK, AUDIO_I2S_GPIO_WS, AUDIO_I2S_GPIO_DOUT, AUDIO_I2S_GPIO_DIN, AUDIO_CODEC_PA_PIN, AUDIO_CODEC_ES8311_ADDR); return &audio_codec; } virtual Display* GetDisplay() override { return display_; } virtual Backlight* GetBacklight() override { static PwmBacklight backlight(DISPLAY_BACKLIGHT_PIN, DISPLAY_BACKLIGHT_OUTPUT_INVERT); return &backlight; } }; DECLARE_BOARD(MyCustomBoard);

实现要点

  • 基类WifiBoard定义于 main/boards/common/wifi_board.h,它继承自Board,默认的GetAudioCodec()返回nullptr,并提供EnterWifiConfigMode()等辅助方法;板级类只需覆写自己需要的虚函数;
  • 按键回调中kDeviceStateStarting状态下进入 WiFi 配网模式(EnterWifiConfigMode()),否则切换对话状态(app.ToggleChatState()),这是项目通用的按键交互范式;
  • InitializeTools()留空即支持 MCP 工具注册(如喇叭控制、亮度调节、电量读取等),详见 MCP 使用指南;
  • 若板卡带摄像头,可参考 main/boards/common/esp32_camera.h 或 main/boards/common/esp_video.h 接入。

六、第四步:接入构建系统

6.1 在 Kconfig 中添加条目

打开 main/Kconfig.projbuild,在choice BOARD_TYPE("Target Board" 选择块)中追加条目:

choice BOARD_TYPE prompt "Target Board" default BOARD_TYPE_BREAD_COMPACT_WIFI help Board type. # ... other entries ... config BOARD_TYPE_MY_CUSTOM_BOARD bool "My Custom Board" depends on IDF_TARGET_ESP32S3 # pick the matching target endchoice

注意(与 main/Kconfig.projbuild 中现有 70+ 条目保持一致):

  • 符号标识必须大写、下划线分隔(如BOARD_TYPE_MY_CUSTOM_BOARD);
  • depends on将条目限定到正确目标芯片(IDF_TARGET_ESP32S3IDF_TARGET_ESP32C3等);
  • bool后的标签文本可以是中英文或本地化描述;
  • 该 choice 为每个目标芯片配置了默认板型(如 ESP32-S3 默认BOARD_TYPE_BREAD_COMPACT_WIFI)。

6.2 在 CMakeLists.txt 中添加分支

打开 main/CMakeLists.txt,在板型条件链中追加:

elseif(CONFIG_BOARD_TYPE_MY_CUSTOM_BOARD) set(BOARD_DIR "my-custom-board") set(BUILTIN_TEXT_FONT font_puhui_basic_20_4) # pick a font for the display set(BUILTIN_ICON_FONT font_awesome_20_4) set(DEFAULT_EMOJI_COLLECTION twemoji_64) # optional, for emoji display

构建系统从main/boards/${BOARD_DIR}/加载源码,并从该目录的config.json读取上报板型。config.json或其顶层type缺失,则回退使用完整BOARD_DIR(将/替换为-)作为板型。当前仓库 main/CMakeLists.txt 中的真实分支(如CONFIG_BOARD_TYPE_ESP32_S3_BOX_3对应set(BOARD_DIR "espressif/esp32-s3-box-3"))可直接对照参考。

字体与 emoji 选择建议(按屏幕分辨率匹配):

  • 小屏(128x64 OLED):font_puhui_basic_14_1/font_awesome_14_1
  • 中小屏(240x240):font_puhui_basic_16_4/font_awesome_16_4
  • 中屏(240x320):font_puhui_basic_20_4/font_awesome_20_4
  • 大屏(480x320 及以上):font_puhui_basic_30_4/font_awesome_30_4

emoji 集合:twemoji_32(32x32 像素,适合小屏)、twemoji_64(64x64 像素,适合大屏)。仓库中的高分辨率板型(如 main/boards/espressif/esp32-s3-box-3/)实际使用noto-color-emoji_128等更高规格集合,可按需取用。

七、第五步:构建与烧录

方案 A:手动使用 idf.py

  1. 设置目标芯片(首次或切换目标时):
    idf.py set-target esp32s3 # ESP32-S3 idf.py set-target esp32c3 # ESP32-C3 idf.py set-target esp32 # ESP32
  2. 清理过期配置:
    idf.py fullclean
  3. 通过 menuconfig 选择板型:
    idf.py menuconfig

    导航到Xiaozhi Assistant -> Target Board,选择你的板卡。

  4. 构建并烧录:
    idf.py build idf.py flash monitor

方案 B:使用 build.py(推荐)

只要板卡目录包含config.json,即可一键配置并构建:

python scripts/build.py my-custom-board

语言与唤醒词属于用户构建选项,可显式指定:

python scripts/build.py my-custom-board \ --language en-US \ --wake-word wn9_jarvis_tts

参数取值规则(与 scripts/build.py 的_normalize_language()_wake_word_sdkconfig_options()实现一致):

  • --language接受 main/assets/locales/ 下列出的任意 locale;
  • --wake-word接受 ESP-SR 模型名、nihaoxiaozhi(按目标芯片自动选择兼容模型)或disabled
  • ESP32-C3/C5/C6 目标仅支持 WakeNet9s 模型(wn9s_*);ESP32-S3/P4/S31 构建自动使用 AFE 唤醒词引擎;ESP32 使用 ESP 唤醒词引擎——目标不匹配会被显式拒绝(见_WAKE_WORD_MODEL_PATTERN与目标判定逻辑)。

以文本或机器可读形式查询可选值:

python scripts/build.py --list-languages python scripts/build.py --list-languages --json python scripts/build.py --list-wake-words python scripts/build.py --list-wake-words --json

注意:唤醒词列表来自当前解析的 ESP-SR 组件。若managed_components/尚未生成,请先执行idf.py reconfigure再查询。

build.py的完整行为(见 scripts/build.py):

  • 无参数运行时打印帮助;用--list-boards列出所有板型与变体(含厂商前缀的发布名,如waveshare-esp32-p4-nano-10.1-a);
  • 所选板卡存在多个 builds 变体时,会交互式提示选择;非交互环境需传--name <variant>
  • config.json读取target仅当已有构建目录的目标芯片不同才执行清理,然后通过一次idf.py reconfigure完成目标芯片、板名、默认配置与所选 build 的sdkconfig_append配置(写入build/xiaozhi-build.sdkconfig.defaults片段);随后的idf.py build直接复用该配置;
  • 将所选 build 的name作为上报的固件变体名(-DBOARD_NAME=...);
  • 默认只生成build/merged-binary.bin而不打包 ZIP;传--zip才会生成releases/v<version>_<name>.zip
  • 对上报标识(type/name)做全局唯一性校验,重复会直接报错,防止 OTA 身份冲突;
  • sdkconfig_append中写了CONFIG_USE_ESP_BLUFI_WIFI_PROVISIONING=y,会自动补全其 Kconfig select 依赖(蓝牙相关宏),模拟 menuconfig 行为。

八、第六步:编写 README

在板卡目录的README.md中描述:板卡硬件组成、硬件要求、构建与烧录说明、以及任何特殊注意事项(例如仓库中 main/boards/sensecap-watcher/README.md 这类板级文档的写法)。

九、厂商子目录布局

当同一厂商有多款变体时,推荐使用main/boards/<manufacturer>/<board>/分组布局,例如 main/boards/waveshare/esp32-p4-nano/ 或 main/boards/lceda-course-examples/eda-tv-pro/。

厂商子目录下的板卡,需在config.json中声明同样值的字段,例如"manufacturer": "waveshare"。固件会将其作为board.manufacturerboard.typeboard.name一并上报;平铺的社区板卡不声明该字段,上报空厂商字符串。同时在 CMake 分支中将BOARD_DIR设为相对main/boards/的完整路径:

elseif(CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_NANO) set(BOARD_DIR "waveshare/esp32-p4-nano") set(BUILTIN_TEXT_FONT font_puhui_basic_30_4) set(BUILTIN_ICON_FONT font_awesome_30_4) set(DEFAULT_EMOJI_COLLECTION twemoji_64)

一致性约束(由 scripts/build.py 的_collect_variants()强制校验):板卡位于某厂商子目录下时,config.json必须声明且只能声明与该子目录同名的manufacturer,否则报错;反之,平铺板卡声明manufacturer也会报错并提示移动目录。

布局经验法则

  • 同一厂商有两款以上共享驱动、资源或文档的板卡时,使用厂商布局;
  • 一次性板卡与社区示例使用平铺布局;
  • 目录名使用小写与连字符。

十、可复用的公共组件

main/boards/common/提供了大量可直接复用的组件,板级类可直接包含使用:

显示驱动

支持的 LCD 系列包括 ST7789(SPI)、ILI9341(SPI)、SH8601(QSPI)等,完整驱动见 main/display/lcd_display.h 及相关面板代码。

音频编解码器(main/audio/codecs/)

  • Es8311AudioCodec(最常见)
  • Es8374AudioCodec
  • Es8388AudioCodec
  • Es8389AudioCodec
  • BoxAudioCodec(ES7210 麦克风阵列 + 编解码器组合,用于 ESP-Box 系列板卡)
  • NoAudioCodec(无外部编解码器,直接 I2S)
  • DummyAudioCodec(无音频板卡的占位实现)

电源管理

  • Axp2101:电源管理 IC 辅助类;
  • Sy6970:电池充电器辅助类;
  • AdcBatteryMonitor:基于 ADC 的简单电池电压监测;
  • PowerSaveTimer/SleepTimer:浅睡眠调度辅助。

以上实现在 main/boards/common/ 下均有对应文件(如 main/boards/common/axp2101.cc、main/boards/common/adc_battery_monitor.cc)。

网络基类

  • WifiBoard:纯 WiFi 基类;
  • Ml307Board/Nt26Board:4G 模组基类;
  • DualNetworkBoard:WiFi/4G 可切换基类;
  • RndisBoard:RNDIS-over-USB 网络(ESP32-S3 / ESP32-P4);
  • EspVideo:ESP32-S3 / ESP32-P4 上的 ESP-Video 辅助。

输入辅助

  • Button:标准按键(单击、长按、多击);
  • Knob:旋转编码器封装;
  • PressToTalkMcpTool:按键通话工具,通过 MCP 自注册;
  • SystemReset:开机长按按键执行安全出厂重置。

MCP 集成

任何板卡都可以注册自定义 MCP 工具——喇叭控制、屏幕亮度、电池读数、灯光控制等,详见 MCP 使用指南。

十一、板级类继承体系

从 main/boards/common/board.h 与 main/boards/common/wifi_board.h 的源码结构可以梳理出如下继承关系:

  • Board:基类
    • WifiBoard:WiFi 连接板卡
    • Ml307Board/Nt26Board:4G 模组板卡
    • DualNetworkBoard:WiFi + 4G 可切换板卡
    • RndisBoard:RNDIS-over-USB 板卡

选择基类时:纯 WiFi 板继承WifiBoard;4G 模组板继承Ml307Board/Nt26Board;两者皆有可能的板继承DualNetworkBoard

十二、开发技巧与排错指南

技巧

  1. 从相似板卡开始:复制并修改现有板卡通常比从零开始更快——比如你的硬件用 ES8311 + ST7789,就直接参考 main/boards/espressif/esp32-s3-box-lite/ 这类板卡;
  2. 增量点亮:先让屏幕正常显示,再调音频,最后跑完整业务栈;
  3. 逐脚核对config.h中每个引脚都必须与原理图一致;
  4. 检查硬件兼容性:尤其注意编解码器/PMIC/触摸控制器的组合。

排错

  1. 显示异常:检查 SPI 配置、镜像方向与颜色反转(esp_lcd_panel_invert_color)是否正确;
  2. 无音频:检查 I2S 接线、PA 使能引脚与编解码器 I2C 地址;
  3. 无法连接 WiFi:复查 WiFi 凭据与配网方式;
  4. 无法连接服务器:验证 WebSocket / MQTT 端点配置。

十三、参考链接

  • ESP-IDF 官方文档:https://docs.espressif.com/projects/esp-idf/
  • LVGL 官方文档:https://docs.lvgl.io/
  • ESP-SR 仓库:https://github.com/espressif/esp-sr

延伸阅读:本文关联的原始指南见 docs/custom-board.md(另有 docs/custom-board_zh.md 中文版);MCP 工具注册细节见 MCP 使用指南;板卡上报协议可参考 docs/websocket.md 与 docs/mqtt-udp.md。

【免费下载链接】xiaozhi-esp32An MCP-based chatbot | 一个基于MCP的聊天机器人项目地址: https://gitcode.com/GitHub_Trending/xia/xiaozhi-esp32

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询