EvoAgent

小智语音板(evo-voice-v1)

基于 xiaozhi-esp32 的板卡定制包。裸 I2S 方案:INMP441 数字麦克风 + MAX98357A 数字功放, 没有 I2C codec 芯片。5 小时从零 bring-up,踩了 7 类问题。

独立开发ESP32-S3I2S硬件排障


方案取舍

为什么用裸 I2S 而不是 codec

INMP441 直接输出 I2S 数字流,MAX98357A 直接吃 I2S 数字流——两个都是数字器件, 中间不需要 ADC/DAC,也不需要 I2C 去配寄存器,省掉了 codec 和它的控制线。

代价:采样率、槽宽、声道全得自己在软件里配对。 而这也正是"四连坑"的来源——见 排障案例 2。


接线图

ESP32-S3 N16R8 I2S 主机(Master) I2S0 RX · I2S1 TX 16 kHz / 16-bit 槽位 MCLK 不接 GPIO2 → 板载 LED GPIO0 → BOOT 键 避开 GPIO33-37(PSRAM) 避开 GPIO26-32(Flash) INMP441 I2S MEMS 麦克风 SCK · WS · SD L/R → GND(左声道) VDD 3.3V 输出幅度仅满幅 ~1.5% → 固件 ×16 增益 + 限幅 MAX98357A I2S D 类功放 BCLK · LRC · DIN SD → 使能(高开低关) GAIN 悬空 = 9 dB ⚠ VIN 建议 5V 3.3V 取电会瞬态拉垮电源轨 GPIO12 / 13 / 21 GPIO4 / 14 / 18 / 5 供电是这块板最容易翻车的地方 功放从 3.3V 轨取电,播放瞬态电流把轨压拉到 2.1V 以下 → 触发 BOD 硬件欠压复位,表现为「无规律复位且无任何日志」。必须用充电器/独立 5V 供电。

左边收、右边发,中间两块都是数字器件;功放供电是唯一需要特别注意的地方(图底部红框)。

接线表(逐脚对照)

模块引脚说明
INMP441
I2S 麦克风
SCK → GPIO12位时钟(BCLK),主机输出
WS → GPIO13左右声道时钟(帧同步)
SD → GPIO21数据:麦克风 → ESP32
L/R → GND⭐ 这是 WS 的硬件版本,接 GND = 输出左声道
VDD → 3.3V
GND → GND
MAX98357A
I2S 功放
BCLK → GPIO4位时钟
LRC → GPIO14左右声道时钟
DIN → GPIO18数据:ESP32 → 功放
SD → GPIO5使能:高=开、低=关。固件上电先拉低(静音),出声才拉高
GAIN → 悬空不接 = 默认 9 dB
VIN⚠️ 见下方供电说明
板载LED → GPIO2 / BOOT 键 → GPIO0短按:启动中进配网,运行中切换对话

MCLK 不接(两个器件都不需要主时钟)。


参数对齐

软件侧必须对齐的参数

项值为什么
采样率16 kHz 收发一致
I2S 端口I2S0 = 麦克风(RX)
I2S1 = 功放(TX)
两路独立通道,均主机模式
槽位宽16-bit(不是 32-bit)32-bit 下 BCLK 翻倍到 1.024 MHz,与麦克风时序不匹配 → 输出 8192 步长乱码
BCLK16k × 2 × 16 = 512 kHz能现场代公式,也能对上实测值
声道模式立体声槽(TX 需 L=R 复制)否则单声道被当双声道 → 播放速度翻倍
麦克风增益×16 + 限幅INMP441 输出幅度只有满幅 ~1.5%

排障重点

⚠️ 供电:这块板最容易翻车的地方

功放从 3.3V 轨取电,播放瞬间的瞬态大电流会把 3.3V 轨拉垮, 电压跌破 BOD 阈值(实测跌到 2.1V 以下)→ 硬件欠压复位。 现象是"无规律复位、且没有任何日志"——因为硬件复位比软件写日志快得多。

必须用充电器 / 独立 5V 电源供电(电脑 USB 口 500mA 限制撑不住)。 改善方案:功放 VIN 改接 5V 轨,或就地并联 ≥470µF 电容储能。

完整排障链(含我走的弯路)见 排障案例 1。


硬件约束

引脚避让(接错必挂)

  • GPIO33–37:PSRAM 总线(OCT 模式)→ 占用会让 I2S 初始化直接挂起
  • GPIO26–32:Flash 总线
  • GPIO15 / 16:实测异常——用 PCNT 计数器飞线测到 1.126 MHz / 120 kHz 这种"不该存在"的频率, 疑似板载信号占用。麦克风 BCLK/WS 因此从 15/16 迁到了 12/13

主动播报

让服务器能对空闲设备主动播报(keep-alive)

语音板空闲一段时间后,服务器推播报会返回 404 no active device——设备侧连接被释放了。 我给语音链路加了一个 WebSocket keep-alive 补丁,让服务端能随时推送 TTS 播报(告警 / 通知)。

边界验证:空闲 18.5 分钟后仍能推送成功(定时 700 秒,特意超过旧的 660 秒超时阈值来验证)。