FireBeetle 2 ESP32-C5 使用I2S协议读取INMP441实现音频采集
简介本文章主要简介如何使用FireBeetle 2 ESP32-C5 在Arduino的环境下通过ESP-IDF自带的i2s驱动来实现INMP441的I2S数据采集。如果想实现Loopback的效果,比如说类似下面的视频效果(https://www.bilibili.com/video/BV1tRwUe7Eo9)可以额外的加一个MAX98357即可。 视频中的代码使用ESP-IDF实现的,在Arduino中实现也是一模一样。但是我的MAX98357还在这里,但是我的扬声器找不到在哪了。所以今天的文章只能做音频的采集,对于播放的话直接写出去即可。
I2S协议和INMP441简介
I²S(Inter-IC Sound)是一种专门用于数字音频设备之间传输音频数据的总线协议。它由 Philips(飞利浦)公司提出,广泛用于:
[*]音频编解码器(Codec)
[*]数字麦克风(如 INMP441)
[*]数字功放、DAC/ADC
[*]MP3 播放器、语音识别模块等
INMP441 是一款由 Analog Devices(亚德诺) 推出的高性能、低功耗 数字 MEMS 麦克风,通过 I²S 接口 输出 24 位 PCM 音频数据。它支持 8 kHz 至 48 kHz 的采样率范围,工作电压为 1.8V~3.3V,功耗仅约 1mA,具有极低的输出延迟,非常适合用于语音识别、环境音监测以及实时音频采集等应用场景。 (来源于百度百科)
如上图所示INMP441一共具有几个比较重要的PIN 即
[*]WS (LRCL) 左右声道选择切换
[*]SCK (BCLK)数据时钟
[*]SD (DOUT)输入输出
[*]L/R声道切换,如果高电平的话则右声道,如果低电平的话则是左声道
得益于ESP32的IO交换矩阵让我们不需要根据PIN的对应功能去选择引脚,我们可以将上述的pin接到任意的esp32的pin上。代码定义如下
// ===== I2S 配置 =====
#define I2S_WS 23 // LRCLK
#define I2S_SD 25 // DOUT
#define I2S_SCK 24 // BCLK
#define I2S_PORT I2S_NUM_0
之后我们使用IDF的函数来初始化I2S
// ===== I2S 初始化函数 =====
void i2sInit() {
i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX),// 主机接收模式
.sample_rate = 16000, // 采样率 16kHz
.bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT,// INMP441 输出 24bit,接收端按32位处理
.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT, // 单声道
.communication_format =I2S_COMM_FORMAT_I2S_MSB,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
.dma_buf_count = 4,
.dma_buf_len = 128,
.use_apll = false
};
i2s_pin_config_t pin_config = {
.bck_io_num = I2S_SCK,
.ws_io_num = I2S_WS,
.data_out_num = I2S_PIN_NO_CHANGE,// 不用发送
.data_in_num = I2S_SD
};
i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL);
i2s_set_pin(I2S_PORT, &pin_config);
i2s_zero_dma_buffer(I2S_PORT);
}
上述的代码主要是对I2S的进行了初始化,并且配置了非发送的模式,即仅仅采集,如果你想做一个类似远程送话器一样的效果即可以改变data_out_num, 这样采集的数据会按照采集的采样率进行发送,使其达到播放的效果。
然后我们在主程序中进行调用初始化和调用i2s read的方式即可读取到原本的PCM数据(非压缩数据,数据较大)
// ===== 采集并显示原始音频数据 =====
void readAudioData() {
const int bufferSize = 512;
int32_t samples;
size_t bytes_read;
// 从 I2S 读取音频数据
i2s_read(I2S_PORT, (void*)samples, sizeof(samples), &bytes_read, portMAX_DELAY);
int samples_read = bytes_read / sizeof(int32_t);
// 打印原始采样数据
Serial.println("Raw audio samples:");
for (int i = 0; i < samples_read; i++) {
Serial.println(samples);
}
}
void setup() {
Serial.begin(115200);
Serial.println("Initializing I2S microphone (INMP441)...");
i2sInit();
}
void loop() {
readAudioData();
delay(100);
}像上述的代码仅仅是读的话并不需要多大的ram, 但是如果想实现边读边写或者这种录音的效果的话则可以根据上述的采样率和自己的采样时间来判断到底需要多少PSRAM来避免这种内存溢出的清空。
效果展示
页:
[1]