esp32s3下i2s开发记录
关键词:esp32s3,platformIO,i2s,inmp441,max98357
引言
本文将鄙人在使用esp32s3开发inmp441和max98357并用其进行收音和放音实验的重点作记录。
一,介绍
1. 硬件模块介绍
(1) esp32s3
ESP32-S3 是一款低功耗的 MCU 系统级芯片 (SoC),支持 2.4 GHz Wi-Fi 和低功耗蓝牙 (Bluetooth® LE) 无线通信。芯片集成了高性能的 Xtensa® 32 位 LX7 双核处理器、超低功耗协处理器、Wi-Fi 基带、蓝牙基带、RF 模块以及外设。拥有2个i2s接口。
(2)inmp441
INMP441是一款高性能,低功耗,数字输出,带底部端口的全向MEMS麦克风。该完整的INMP441解决方案由一个MEMS传感器,信号组成调节,模数转换器,抗混叠滤波器,电源管理和行业标准的24位I²S接口。I²S接口允许INMP441直接连接到数字处理器,如DSP和微控制器,无需使用用于系统中的音频编解码器。INMP441具有高信噪比,是一款出色的选择近场应用。
接口定义:
SCK | I²S接口的串行数据时钟 |
---|---|
WS | 用于I²S接口的串行数据字选择 |
L/R | 左/右声道选择。(设置为低电平时,麦克风在I²S帧的左声道输出信号;设置为高电平时,麦克风在右声道输出信号) |
SD | I²S接口的串行数据输出。 |
VCC | 输入电源DC1.8V至3.3V. |
GND | 电源地 |
(3)max98357
MAX98357A/MAX98357B是数字脉冲编码调制(PCM)输入D类功率放大器,可提供AB类音频性能,同时具有D类的效率。器件在I2S/左对齐模式下通过单个增益设置输入可提供5中可选择增益(3dB、6dB、9dB、12dB、15dB),在TDM模式下为固定12dB增益。
数字音频接口高度灵活,MAX98357A支持I²S数据,MAX98357B支持左对齐数据。两种器件均支持8通道时分复用(TDM)数据。对于所有支持的数据格式,数字音频接口可接收8KHz至96KHz的指定采样速率。IC通过配置可将立体声输入数据转换成左声道、右声道、(左声道/2 + 右声道/2)输出。对于I2S和左对齐模式,IC采用16/24/32位数据工作,对于TDM模式,器件采用16位或32位数据工作。IC无需PCM通讯应用中的外部MCLK信号。这有助于减小EMI以及电路板的耦合问题,另外,也可减小电路板尺寸以及IC引脚数。
IC在BCLK和LRCLK上具有很高的宽带抖动容限(12ns典型值),能够可靠工作。
有源辐射抑制、边沿速率限制以及过冲控制电路大大减小EMI。无需滤波的扩谱调制机制可省去传统D类器件中的输出滤波器件,可减少方案中的器件数量。
IC采用9引脚WLP (1.345mm x 1.435mm x 0.64mm)和16引脚TQFN (3mm x 3mm x 0.75mm)封装,工作在-40°C至+85°C温度范围。
(不清楚MAX98357A/MAX98357B/MAX98357是什么关系,只找到了MAX98357A/MAX98357B的数据手册,不过应该没多大差别)
接口定义:
VCC | 输入电源DC2.5V至5.5V. |
---|---|
GND | 电源地 |
SD | 关机和频道选择 |
GAIN | 增益和频道选择 |
DIN | 数字输入信号 |
BCLK | I²S接口的串行数据输出 |
LRC | I2S与LJ模式的左/右时钟。同步时钟用于TDM模式 |
2. 平台介绍
platformIO
二、实施
1. 硬件部分
(1)inmp441的连线为
inmp441 | esp32s3 |
---|---|
SCK | GPIO7 |
WS | GPIO6 |
L/R | GPIO4 |
SD | \ |
VCC | 3.3V |
GND | GND |
(2)max98357的连线为
max98357 | esp32s3 |
---|---|
VCC | 3.3V |
GND | GND |
SD | \ |
GAIN | \ |
DIN | GPIO18 |
BCLK | GPIO17 |
LRC | GPIO16 |
2. 软件部分
代码
#include <Arduino.h>
#include <driver/i2s.h>
#include <hal/i2s_types.h>
#define INMP441_WS 6
#define INMP441_SCK 7
#define INMP441_SD 4
#define MAX98357_LRC 16
#define MAX98357_BCLK 17
#define MAX98357_DIN 18
// #define SAMPLE_RATE 44100
#define SAMPLE_RATE 16000
i2s_config_t inmp441_i2s_config = {
.mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_RX),
.sample_rate = SAMPLE_RATE,
.bits_per_sample = i2s_bits_per_sample_t(16),
.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
.communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_STAND_MSB),
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
.dma_buf_count = 8, // buffer 的数量
.dma_buf_len = 128 // buffer的大小,单位是i2s_bits_per_sample_t 采样位数,越小播放需要越及时时延越小,否则相反
};
const i2s_pin_config_t inmp441_gpio_config = {
.bck_io_num = INMP441_SCK,
.ws_io_num = INMP441_WS,
.data_out_num = -1,
.data_in_num = INMP441_SD
};
i2s_config_t max98357_i2s_config = {
.mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_TX),
.sample_rate = SAMPLE_RATE,
.bits_per_sample = i2s_bits_per_sample_t(16),
.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
.communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_STAND_MSB),
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
.dma_buf_count = 8,
.dma_buf_len = 128
};
const i2s_pin_config_t max98357_gpio_config = {
.bck_io_num = MAX98357_BCLK,
.ws_io_num = MAX98357_LRC,
.data_out_num = MAX98357_DIN,
.data_in_num = -1
};
void setup()
{
i2s_driver_install(I2S_NUM_0, &inmp441_i2s_config, 0, NULL);
i2s_set_pin(I2S_NUM_0, &inmp441_gpio_config);
i2s_driver_install(I2S_NUM_1, &max98357_i2s_config, 0, NULL);
i2s_set_pin(I2S_NUM_1, &max98357_gpio_config);
}
void loop()
{
size_t bytes_read;
uint16_t data[256];
esp_err_t result = i2s_read(I2S_NUM_0, &data, sizeof(data), &bytes_read, portMAX_DELAY);
size_t bytes_write;
result = i2s_write(I2S_NUM_1, &data, sizeof(data), &bytes_write, portMAX_DELAY);
}
三、实验结果
靠近inmp441说话,max98357有相应声音发出,但音质不好
四、总结与归纳
1. 总结
(1)在进行inmp441及max98357进行i2s音频开发时,起初进行了多次实验,但结果均不遂人愿;因为最开始使用的是esp32c3,只有一个i2s接口。于是转换路,先尝试对单个模块进行测试,测试无误后再合并。先测试的inmp441模块,其驱动较为简单,根据【雕爷学编程】Arduino动手做(198)—INMP441全向麦克风模块-CSDN博客 的代码可以很简单的测试inmp441是否正常工作。观察后确定inmp441能随外界声音的变化而输出不同数据,使用arduino串口绘图器显示的波形随之变化,由此确定inmp441在esp32c3上的运行是正常的。但由于esp32c3只有一个i2s,因此为了测试max98357不得不单独使用一个esp32c3模块,于是从何获取音源数据又成为了一个难题。经查询,初步确定了三个方案,a)直接读取SD卡或者文件系统中的文件播放; b)将一块esp32c3上inmp441的数据传输到另一块esp32c3上,再由其驱动max98357播放声音; c)直接调用他人的库,播放网络音频
a)直接读取SD卡或者文件系统中的文件播放。这个需要对音频文件进行解码,本人在此之前没有接触过音频编解码相关领域,因此对于解码的结果是否正确存在疑问。在max98357是否能被正常驱动本身是个未知变量的情况下使用此方法无疑更增添了不确定性,因此方案优先级降低。
b)将一块esp32c3上inmp441的数据传输到另一块esp32c3上,再由其驱动max98357播放声音。对于此方法,我使用了ESP NOW和MQTT两种方案进行测试,但结果均不理想,max98357没有声音发出。(可能原因见下文)
c)直接调用他人的库,播放网络音频。该方案实际为使用库 ESP32-audioI2S 播放网络音频,但esp32c3不再其支持的平台之内。(关于 ESP32-audioI2S,我在使用esp32s3进行开发时,其依然报错,起先我以为是我的音频放在云服务器上,而我的云服务器带宽不够导致的。但后来使用nodejs在局域网搭建服务器测试依旧报错“request http://{链接}/audio.mp3 failed”, 我就有点糊涂了)
实在是花费太多时间了,于是直接买了块esp32s3进行测试,几次实验后终于成功
(2)在使用esp32s3进行测试时,也出现过在代码正确的情况下播放没声音或噪声很大的情况,但在我吃完晚饭准备再次尝试时意外驱动成功——max98357随着外界声音的变化发出声音。于是我怀疑是max98357的几个引脚没接加上我手上有静电或者外界电磁环境不稳导致的(在数据手册中有这么一段话“Shutdown and Channel Select. Pull SD_MODE low to place the device in shutdown. In I2S or LJ mode”),这就需要仔细地翻一翻数据手册了,但是由于我的时间安排,只能暂时先做记录,等有空再去做测试了
2. 展望1)即使按理说驱动已经完成,但是依然存在音频失真的问题,播放效果就想上世纪的村里的广播大喇叭。目前暂时没有找到原因
参考资料
- 《ESP32-S3 系列芯片技术规格书》
- 使用ESP32做一个实时语音对讲机 - 田帅康学习笔记 (shumei52.top)
- 一起玩儿物联网人工智能小车(ESP32)——69 使用INMP441模块采集声音_esp32在线语音识别inmp441-CSDN博客
- 【雕爷学编程】Arduino动手做(198)—INMP441全向麦克风模块-CSDN博客
- 半导小芯-芯片查询工具_芯片替代查询_数据手册查询_规格书查询_datasheet查询_IC查询 (semiee.com)