ESP32外接DAC输出音频时出现周期性噪声问题排查
问题分析:ESP32变声设备周期性刺耳噪声问题
问题背景
使用ESP32开发板(PlatformIO + Arduino IDE)制作变声设备,硬件组成:外接麦克风→ESP32内置ADC(通过I2S协议处理音频)→PCM5102 DAC(I2S协议输出)。系统可正常启动,但运行约1分钟后出现渐强刺耳噪声(衰减时长约3秒),之后每5秒周期性重复该噪声,怀疑ADC或DAC配置错误。
硬件连接
采用面包板连接:
代码实现
#include <driver/i2s.h> #define I2S_SAMPLE_RATE 100000 #define I2S_DMA_BUF_LEN 1024 #define ADC_INPUT ADC1_CHANNEL_4 //pin 32 #define I2S_DATA_PIN GPIO_NUM_22 // DIN #define I2S_LRCK_PIN GPIO_NUM_25 // LCK #define I2S_BCLK_PIN GPIO_NUM_26 // BCK /* * Configure ADC. */ void i2sInputInit() { i2s_config_t i2s_config = { .mode = (i2s_mode_t) (I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN), .sample_rate = I2S_SAMPLE_RATE, // The format of the signal using ADC_BUILT_IN .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, // is fixed at 12bit, stereo, MSB .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, .communication_format = I2S_COMM_FORMAT_STAND_I2S, .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, .dma_buf_count = 2048, .dma_buf_len = I2S_DMA_BUF_LEN, .use_apll = true, .tx_desc_auto_clear = true, .fixed_mclk = 0 }; i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL); i2s_set_adc_mode(ADC_UNIT_1, ADC_INPUT); // i2s_adc_enable(I2S_NUM_0); // adc1_config_channel_atten(ADC_INPUT, ADC_ATTEN_DB_11); } /* * Configure DAC. */ void i2sOutputInit() { // Initialize I2S i2s_config_t i2s_config = { .mode = (i2s_mode_t) (I2S_MODE_MASTER | I2S_MODE_TX), .sample_rate = I2S_SAMPLE_RATE, .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, .communication_format = I2S_COMM_FORMAT_STAND_I2S, .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, .dma_buf_count = 2048, .dma_buf_len = I2S_DMA_BUF_LEN, .use_apll = false, .tx_desc_auto_clear = true, .fixed_mclk = 0 }; i2s_driver_install(I2S_NUM_1, &i2s_config, 0, NULL); // Configure I2S pins i2s_pin_config_t pin_config = { .bck_io_num = I2S_BCLK_PIN, .ws_io_num = I2S_LRCK_PIN, .data_out_num = I2S_DATA_PIN, .data_in_num = I2S_PIN_NO_CHANGE, }; i2s_set_pin(I2S_NUM_1, &pin_config); } void setup() { Serial.begin(115200); i2sInputInit(); i2sOutputInit(); } void loop() { size_t bytes_read; size_t bytes_written; int *int_buffer = (int *) malloc(I2S_DMA_BUF_LEN * sizeof(int)); i2s_read(I2S_NUM_0, int_buffer, I2S_DMA_BUF_LEN * sizeof(int), &bytes_read, portMAX_DELAY); applyEffect(int_buffer); i2s_write(I2S_NUM_1, int_buffer, I2S_DMA_BUF_LEN * sizeof(int), &bytes_written, portMAX_DELAY); free(int_buffer); }
可能的问题排查方向
1. ADC关键配置缺失
代码中注释掉了两项核心配置:
adc1_config_channel_atten(ADC_INPUT, ADC_ATTEN_DB_11):未配置ADC通道衰减,麦克风输入信号可能超出ADC量程,长时间运行后信号饱和或漂移,引发噪声。i2s_adc_enable(I2S_NUM_0):未启用I2S ADC模式,模块初始化不完全,运行中易出现异常。
2. I2S时钟不同步
输入I2S(ADC侧)开启use_apll = true,输出I2S(DAC侧)设置use_apll = false,两个外设使用不同时钟源,长时间运行会出现时钟漂移,导致音频数据错位,产生周期性噪声。建议统一使用APLL时钟,或配置固定MCLK保证同步。
3. DMA缓冲区参数不合理
dma_buf_count = 2048设置过大,ESP32 DMA资源有限,超大缓冲区会占用大量内存,引发内存碎片化或分配失败,导致音频处理异常。建议将dma_buf_count调整为8~32的合理范围。
4. 动态内存分配引发碎片
loop中每次循环都执行malloc和free,长时间运行会产生内存碎片,导致内存分配失败,缓冲区出现垃圾数据,输出噪声。建议将缓冲区改为全局变量或静态变量,避免频繁动态分配。
5. 硬件连接稳定性
面包板连接易出现接触不良,长时间运行后引脚松动会引入信号干扰。检查麦克风、PCM5102与ESP32的电源、地线及I2S信号线连接,确保接触可靠。
内容的提问来源于stack exchange,提问作者Kenion
相关产品推荐
相关产品推荐

