让 AI 给桌面搭子装上耳朵和嘴巴:喇叭麦克风驱动实录
玩嵌入式的谁没被驱动折磨过:数据手册几十页,例程跑不通,一行行抠寄存器。这期我把 MAX98357(功放喇叭)和 INMP441(数字麦克风)两颗芯片的驱动整个交给 AI agent——资料先喂给它,出一份图文学习报告;需求一句话提进去,它追问、拆任务、写代码;我负责接线、编译、烧录。成品就是本期视频开头那样:长按屏幕播《起风了》高潮段,单击录音再回放。
视频看操作过程,这篇放干货:接线表、I2S 关键配置、踩坑清单,照着能复现。
硬件就两颗芯片:MAX98357 出声,INMP441 拾音
声音链路一进一出,各用一颗专用芯片,都挂在同一种总线上:
- MAX98357:内置 16bit DAC + D 类功放,把 ESP32 发来的数字采样变成推得动喇叭的电流。它自动识别 I2S 时钟,没有寄存器可配——供电、给时钟、给数据,就出声。
- INMP441:MEMS 拾音 + 片上 24bit ADC + I2S 从接口,声音进芯片、数字出芯片,ESP32 拿到的直接是采样值。
两颗芯片与 ESP32-S3 之间都走 I2S 三根线:BCLK(位时钟)、WS(帧同步)、SD(串行数据)。全链路统一 16kHz / 16bit——人声能量集中在 4kHz 以下,采样率取最高频率两倍就够还原。

接线表如下,引脚是我按避让原则挑的:避开屏幕触摸(17/10/18/21)、USB(19/20)、strapping(0/45/46)和 PSRAM 专用(2637)。
接线表按模块分开列,「接」一列就是对面要接的引脚:
MAX98357(喇叭,I2S1 发送)
| 模块引脚 | 接 | 说明 |
|---|---|---|
| VIN | 3.3V | 就近并联 220µF 电解,缓冲功放峰值电流 |
| GND | GND | 与数字地单点汇接,防交流嗡嗡声 |
| DIN | GPIO14 | 串行数据 |
| BCLK | GPIO12 | 位时钟 |
| LRC | GPIO13 | 帧时钟 |
| SD | GPIO15 | 使能脚:拉高发声,拉低静音 |
| GAIN | 悬空 | 不接线,3.3V 供电下即 9dB 档 |
| OUT± | 8Ω 2W 喇叭 | 功率输出,无极性随便接 |
INMP441(麦克风,I2S0 接收)
| 模块引脚 | 接 | 说明 |
|---|---|---|
| VDD | 3.3V | 就近 100nF,严禁 5V |
| GND | GND | 共地 |
| SCK | GPIO9 | 位时钟,ESP32 发出 |
| WS | GPIO8 | 帧时钟,ESP32 发出 |
| SD | GPIO11 | 串行数据,唯一回流的线 |
| L/R | GND | 左声道选择,不许悬空 |
器材清单:ESP32-S3 开发板、MAX98357 模块、INMP441 模块、8Ω 2W 喇叭、公对公杜邦线若干。
第一步不是写代码,是让 AI 先学
驱动写错多半是原理没吃透,所以流程第一步是把资料交给 agent 学习。我用的编排技能是自己的 EM skill(安装见文末),调它的 learn 命令,提示词大概这样:
学习 MAX98357 和 INMP441 的驱动原理与接线。资料在 docs 目录:ESP32-S3 数据手册、核心板原理图、两颗芯片的数据手册。产出图文学习报告,作为后续开发参考。
它会检索资料、读数据手册,最后产出一份带图的报告。这份报告后来就是全程的技术底座,两段核心结论贴在这里。
播放方向:音频文件本来就是一个采样数列,ESP32 把数列写进 DMA 环形缓冲,I2S 硬件按节拍把采样送上三根线,MAX98357 接到后依次做数字转电压、电压放大功率,膜片推动空气。CPU 只负责填缓冲,搬运是 DMA 的活。

录音方向正好相反:三根线里 SCK、WS 两根时钟是 ESP32 发出去的,只有 SD 一根回来。INMP441 内部完成声音到数字的转换,ESP32 按同样的节拍收数。

有一个细节值得单独记:INMP441 的 24bit 采样装在 32bit 帧槽的高位。ESP32 按 32bit 槽收到 int32 后移位取值即可;要是按 16bit 槽配置,MSB 直接被截掉,录出来全是错位噪声——这是社区第一大配置错误。

报告里同时定稿了两个容易踩雷的时序:上电时先起 I2S 时钟、延时约 250ms 再拉高 SD(防爆音);停止时先拉低 SD 再停时钟(BCLK 运行中撤掉 WS 会输出大直流,有烧喇叭风险)。
看完报告接好线,有不懂的地方直接追问 agent,直到自己想明白再开工。
需求一句话给够,agent 追问四轮再动手
开工用 EM skill 的 new 命令,需求原文就这么一句:
实现麦克风和喇叭驱动。长按屏幕播放《起风了》高潮段,播放中再长按停止;单击屏幕开始录音,再次单击停止并立即回放。
它没有直接开写,先追问了四个问题,都是影响边界的:
- 和上一版音频代码什么关系?——从零重写极简版,旧版留作参考。
- 重写边界?——只写这两颗芯片的驱动和应用逻辑,屏幕触摸沿用。
- 歌曲素材哪来?——从 150 秒完整版里自动剪出高潮三句。
- 什么算完成?——编译通过 + 真机四个交互全过;录音 16kHz/16bit/单声道,上限 60 秒。
追问完它给出理解摘要,我确认后进入拆分:五个子系统(喇叭驱动、麦克风驱动、演示应用、歌曲素材、界面复用),每个都有明确参数。接着是硬件对齐环节,agent 把接线表列出来让我核对——这一步拦住过我的错接,值得留着。
全部确认后,需求和拆分落成文档存在工程的 features 目录里。这一设计的实际好处在第二天兑现:我中断了一次开发,新会话里敲一条 rec 命令,agent 把上下文完整恢复到中断点,接着干。
代码只有两段值得看
整个驱动一千多行,真正决定成败的是两段。
第一段,I2S 初始化。标准 Philips 时序、16kHz、16bit、单声道(硬件自动复制左右声道),MAX98357 不需要 MCLK:
1 | /* bsp_audio_out.c(节选) */ |
第二段,麦克风收数。按 32bit 槽读进 int32,取高 16 位,算术移位自动保符号:
1 | /* bsp_audio_in.c(节选) */ |
写代码的活 agent 用多 agent 分工完成:主 agent 拆任务,三个子 agent 分别做各子系统,完成后再互查一遍。我全程没改一行,只负责看懂。
编译烧录,四条交互全过才算完
代码写完回到 VS Code,用 ESP-IDF 插件编译烧录。两个注意点:目标芯片要选对(选错构建直接失败);首次全量编译要等几分钟,之后增量很快。
验收清单就四条,对照着按一遍:
- 长按屏幕 → 播放《起风了》高潮段
- 播放中再长按 → 停止,回待机
- 单击 → 开始录音,界面计时
- 录音中再单击 → 停止并立即回放
实测一次通过:喇叭出声、录音回放,串口没有 brownout 和爆音。最后一条 result 命令发给 agent,它更新项目文档、归档这个步骤——工作流闭环。要是哪条不过,把失败现象描述发过去,它按现象排查原因,改完再验。
踩坑速查
下面这些坑学习报告里都有,贴出来省得再踩:
| 症状 | 原因 | 处理 |
|---|---|---|
| 喇叭完全无声 | SD 引脚被拉低 | SD 拉高才发声,先查使能脚 |
| 上电”噗”一声 | 先开功放后起时钟 | 先 init I2S,延时 250ms 再放 SD |
| 麦克风读出全 0 | L/R 悬空(静默模式) | L/R 必须接 GND 或 VDD |
| 录音全是错位噪声 | I2S 槽配成 16bit,MSB 被截 | 按 32bit 槽收,再移位取值 |
| 麦克风无响应 | 误接 5V 烧毁 | INMP441 只吃 3.3V,别照抄喇叭接法 |
| 反复 brownout 复位 | 3.3V 顶不住功放峰值电流 | 退 5V 供电方案 + GAIN 接 GND |
资料包
本期资料包在粉丝群公告,里面是:驱动源码(bsp/audio 目录)、学习报告全文、需求与拆分文档(features/S10)、接线表、本文用到的全部提示词,以及一张可直接打印的接线图。
EM skill 的安装方法见站内这篇:EM skill 安装指引。任意一个 AI 编程工具(Claude Code / Codex / ZCode)都能跑这套流程,编排技能是通用的。
桌面搭子系列继续往下走:耳朵嘴巴装上了,下期让它把听到的听懂。

