STM32L4开发板DFSDM录音回放有杂音问题求助
问题
在STM32L4 IoT节点开发板(B-L47E-IOT0A1)上搭载两颗MP34DT01麦克风:一颗LR引脚接VDD,另一颗LR引脚拉低,均连接DFSDM1_CKOUT与DFSDM1_DATIN2。系统时钟设为80MHz,启用DFSDM CH2的DMA模式,滤波器设为连续模式,Fosr=52、Iosr=8。能获取数据但回放音频全是杂音,计算采样率应为48KHz——(80MHz/4)/(52 * 8) = 48KHz。
相关代码如下:
Audio.c
#define AUDIO_LEN 240 #define H_AUDIO_LEN 120 int32_t micRecBuf[AUDIO_LEN]; int32_t micAudioBuf[AUDIO_LEN]; volatile uint8_t audioFilterHalfCplt = 0; volatile uint8_t audioFilterCplt = 0; void HAL_DFSDM_FilterRegConvHalfCpltCallback(DFSDM_Filter_HandleTypeDef *hdfsdm_filter) { audioFilterHalfCplt = 1; } void HAL_DFSDM_FilterRegConvCpltCallback(DFSDM_Filter_HandleTypeDef *hdfsdm_filter) { audioFilterCplt = 1; } void micInit(DFSDM_Filter_HandleTypeDef *hdfsdm_filter) { HAL_DFSDM_FilterRegularStart_DMA(hdfsdm_filter, micRecBuf, AUDIO_LEN); }
主循环代码
while(true) { // first half of DMA is filled, now process if (audioFilterHalfCplt == 1) { // fill the audio buffer for (i = 0; i < H_AUDIO_LEN; i++) { micAudioBuf[i] = micRecBuf[i] << 8; // remove meta data } // reset the flag audioFilterHalfCplt = 0; } // second half is filled, finish process if (audioFilterCplt == 1) { // fill the audio buffer for (i = H_AUDIO_LEN; i < AUDIO_LEN; i++) { micAudioBuf[i] = micRecBuf[i] << 8; // remove meta data } }
数据导出流程:
- 用shell命令保存二进制文件:
screen -S audio -L -Logfile audio.bin /dev/ttyACM1 9600, cs8
- Python脚本转存为WAV:
#!/usr/bin/env python3 import wave with open("audio.bin", "rb") as input_file: data = input_file.read() with wave.open("output.wav", "wb") as output_file: output_file.setnchannels(1) # Assuming mono output_file.setsampwidth(4) # Assuming 16-bit samples (2 bytes) output_file.setframerate(48077) # Set the sample rate output_file.writeframesraw(data)
回放WAV文件全是杂音,请问流程中哪里出错了?
分析与解决
1. Screen日志非纯二进制数据
screen -L默认会在日志中插入时间戳、状态信息等额外内容,不是纯原始音频数据,这会直接导致audio.bin包含大量无效数据,回放必然是杂音。
修正:
改用纯二进制捕获工具,比如先配置串口参数:
stty -F /dev/ttyACM1 115200 cs8 -cstopb -parenb
再直接捕获原始数据:
cat /dev/ttyACM1 > audio.bin
2. 串口波特率严重不足
48K采样率下,每个32位采样占4字节,每秒需传输48000*4=192000字节,但9600波特率(cs8配置)的实际传输速度仅约960字节/秒,远低于需求,会导致数据大量丢失、错位。
修正:
- 将STM32串口波特率至少提升至230400,建议用115200或460800
- 确保
screen或捕获命令的波特率与STM32配置完全一致
3. WAV参数配置矛盾
Python脚本中setsampwidth(4)表示32位采样,但注释标注“16-bit samples (2 bytes)”,参数与实际意图不符;若实际需要16位音频,直接写入32位数据会导致格式错误。
修正:
- 若保留32位采样:将注释改为
// 32-bit samples (4 bytes),保持setsampwidth(4) - 若转16位采样:将数据缩放到16位范围(比如
micAudioBuf[i] >> 16,确保数据在-32768~32767区间),然后设置setsampwidth(2)
4. DFSDM数据处理错误
两颗麦克风共用DATIN2,通过LR引脚实现时分复用双声道,但当前代码按单声道处理,会把左右声道数据混叠;同时micRecBuf[i] << 8的操作盲目,DFSDM的32位输出中有效音频数据的位置需根据配置确定,盲目移位可能丢失有效数据或保留无效位。
修正:
- 区分双声道数据:每两个采样对应左、右声道,单独提取目标声道的数据
- 确认DFSDM输出格式:查看CubeMX配置或STM32手册,找到有效数据的位数与偏移,比如若有效数据是24位,可能需要右移8位而非左移
5. DMA回调标志未完全重置
主循环中处理audioFilterCplt时未重置标志位,会导致该分支被反复执行,重复处理同一数据块,造成数据错乱。
修正:
在audioFilterCplt分支末尾添加标志重置:
if (audioFilterCplt == 1) { // fill the audio buffer for (i = H_AUDIO_LEN; i < AUDIO_LEN; i++) { micAudioBuf[i] = micRecBuf[i] << 8; // remove meta data } audioFilterCplt = 0; // 新增:重置完成标志 }
内容的提问来源于stack exchange,提问作者richbai90

