如何通过I2S在ESP32-WROOM-32D上播放8KHz 8bit PCM音频?
ESP32 + MAX98357A 播放8bit 8KHz PCM无声音问题排查
问题背景
使用ESP32-WROOM-32D开发板搭配MAX98357A I2S音频板,需播放存储在wavedata.h中的8KHz 8bit PCM音频,常量数组定义如下:
const uint8_t rawData[49428] = {0x52, 0x49, 0x46, 0x46,.......};
尝试两段代码均无声音输出,代码如下:
第一段Arduino I2S库代码
#include "wavedata.h" #include <Arduino.h> #include <I2S.h> #define LRC_PIN 26 #define BCLK_PIN 27 #define DOUT_PIN 25 void setup() { I2S.begin(I2S_PHILIPS_MODE, 8000, 8); I2S.setSckPin(BCLK_PIN); I2S.setFsPin(LRC_PIN); I2S.setDataPin(DOUT_PIN); } void loop() { I2S.write_blocking(rawData,49428); delay(1000); }
第二段ESP-IDF原生I2S代码
#include "driver/i2s.h" #include "wavedata.h" #define I2S_SAMPLE_RATE (8000) #define I2S_SAMPLE_BITS (I2S_BITS_PER_SAMPLE_8BIT) #define I2S_CHANNEL_NUM (1) #define I2S_BUFFER_SIZE (512) #define PIN_LRC 25 #define PIN_BCLK 14 #define PIN_DIN I2S_PIN_NO_CHANGE #define PIN_DOUT 25 #define MCK I2S_PIN_NO_CHANGE void setup() { i2s_config_t i2s_config = { .mode = (i2s_mode_t)(I2S_MODE_MASTER), .sample_rate = I2S_SAMPLE_RATE, .bits_per_sample = I2S_SAMPLE_BITS, .channel_format = I2S_CHANNEL_FMT_ALL_LEFT, .communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_STAND_I2S), .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, .dma_buf_count = 16, .dma_buf_len = I2S_BUFFER_SIZE, .use_apll = false, // must be disabled in V2.0.1-RC1 .tx_desc_auto_clear = true, // new in V1.0.1 .fixed_mclk = I2S_PIN_NO_CHANGE, }; i2s_pin_config_t pin_config = { .bck_io_num = PIN_BCLK, .ws_io_num = PIN_LRC, .data_out_num = PIN_DOUT, .data_in_num = PIN_DIN, }; i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL); i2s_set_pin(I2S_NUM_0, &pin_config); i2s_set_sample_rates(I2S_NUM_0, I2S_SAMPLE_RATE); size_t written_bytes = 0; while (written_bytes < sizeof(rawData)) { size_t bytes_to_write = sizeof(rawData) - written_bytes; if (bytes_to_write > I2S_BUFFER_SIZE) { bytes_to_write = I2S_BUFFER_SIZE; } i2s_write(I2S_NUM_0, &rawData[written_bytes], bytes_to_write, &written_bytes, portMAX_DELAY); } i2s_driver_uninstall(I2S_NUM_0); } void loop() { }
问题排查与修正
第一段代码的问题
- I2S模式缺失发送配置:仅指定主模式未开启发送,需添加
I2S_MODE_TX - 引脚设置顺序错误:必须先配置引脚再初始化I2S,否则配置不生效
- 单声道参数缺失:初始化时未指定单声道,需补充对应参数
修正后的第一段代码:
#include "wavedata.h" #include <Arduino.h> #include <I2S.h> #define LRC_PIN 26 #define BCLK_PIN 27 #define DOUT_PIN 25 void setup() { // 先配置引脚 I2S.setSckPin(BCLK_PIN); I2S.setFsPin(LRC_PIN); I2S.setDataPin(DOUT_PIN); // 开启主发送模式,指定采样率、位深、单声道 I2S.begin(I2S_PHILIPS_MODE, 8000, 8, 1); } void loop() { // 阻塞式写入整个音频缓冲区 I2S.write_blocking(rawData, sizeof(rawData)); delay(1000); }
第二段代码的问题
- 引脚冲突:
PIN_LRC和PIN_DOUT都设为25,导致信号混乱 - I2S模式未开启发送:
.mode字段仅设置主模式,需添加I2S_MODE_TX - 播放逻辑错误:一次性写完音频后立即卸载驱动,导致播放不完整且仅播放一次
修正后的第二段代码:
#include "driver/i2s.h" #include "wavedata.h" #define I2S_SAMPLE_RATE 8000 #define I2S_SAMPLE_BITS I2S_BITS_PER_SAMPLE_8BIT #define I2S_BUFFER_SIZE 512 // 修正引脚冲突,统一引脚定义 #define PIN_LRC 26 #define PIN_BCLK 27 #define PIN_DOUT 25 #define PIN_DIN I2S_PIN_NO_CHANGE void setup() { i2s_config_t i2s_config = { .mode = I2S_MODE_MASTER | I2S_MODE_TX, // 开启主发送模式 .sample_rate = I2S_SAMPLE_RATE, .bits_per_sample = I2S_SAMPLE_BITS, .channel_format = I2S_CHANNEL_FMT_ALL_LEFT, // 单声道左声道 .communication_format = I2S_COMM_FORMAT_STAND_I2S, .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, .dma_buf_count = 8, // 减少缓冲区数量,降低内存占用 .dma_buf_len = I2S_BUFFER_SIZE, .use_apll = false, .tx_desc_auto_clear = true, .fixed_mclk = I2S_PIN_NO_CHANGE, }; i2s_pin_config_t pin_config = { .bck_io_num = PIN_BCLK, .ws_io_num = PIN_LRC, .data_out_num = PIN_DOUT, .data_in_num = PIN_DIN, }; i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL); i2s_set_pin(I2S_NUM_0, &pin_config); i2s_set_sample_rates(I2S_NUM_0, I2S_SAMPLE_RATE); } void loop() { size_t total_written = 0; const size_t total_size = sizeof(rawData); // 循环播放整个音频缓冲区 while (total_written < total_size) { size_t bytes_to_write = total_size - total_written; if (bytes_to_write > I2S_BUFFER_SIZE) { bytes_to_write = I2S_BUFFER_SIZE; } size_t bytes_written = 0; // 使用临时变量接收实际写入字节数 i2s_write(I2S_NUM_0, &rawData[total_written], bytes_to_write, &bytes_written, portMAX_DELAY); total_written += bytes_written; } delay(1000); }
额外注意事项
- 硬件连接检查:确认MAX98357A的BCLK、LRC、DIN分别对应ESP32的指定引脚;VCC接3.3V/5V(依模块规格),GND共地,SD引脚需接高电平或悬空(避免静音)
- PCM数据格式:
rawData开头是0x52 0x49 0x46 0x46(RIFF头),需去除WAV文件头,仅保留纯PCM采样数据 - 增益调节:若声音异常,可检查MAX98357A的增益设置电阻
内容的提问来源于stack exchange,提问作者Arun K
相关产品推荐
相关产品推荐

