STM32F4+FreeRTOS+FATFS录音卡顿带噪声问题求助
I2S音频录制卡顿噪声问题求助
免责声明:我的I2S接收代码实现大量参考Stack Overflow上的相关方案,这是我最接近可行方案的来源。
基于STM32F405RGT6开发,从ICS43432(MSB优先,32位帧中传输24位数据)接收音频。

使用循环DMA(双缓冲)读取音频数据。经过3天调试,解决大量内存损坏和栈溢出问题后,终于实现无内存损坏的数据流。
实现逻辑如下:
UItask处理按键输入并切换系统状态;StartWriteAudioTask()启动DMA并创建.wav文件,同时将systemState设置为STATE_RECORDING;- DMA填充缓冲区后释放信号量给
MicTask,该任务负责字节序转换并写入WAV数据块; - 为防止DMA在写入完成前覆盖缓冲区,实现了音频缓冲区的拷贝。
通过调试器确认状态机逻辑、启停流程、文件初始化均正常,生成的文件可播放,但音频时序异常,整体卡顿且伴有噪声。
mic.c代码
#include "mic.h" #include "sd.h" #include "stm32f4xx_hal.h" #include "freertos.h" #include "cmsis_os.h" #include "ui.h" extern I2S_HandleTypeDef hi2s3; extern osSemaphoreId RxAudioSemHandle; extern SemaphoreHandle_t xAudioReady; extern SemaphoreHandle_t xRecordStop; extern SemaphoreHandle_t xAudioBlock; #define I2S_DATA_WORD_LENGTH (24) // 24-bit MSB #define I2S_FRAME (32) // bits per sample #define READ_SIZE (512) // samples to read from I2S #define BUFFER_SIZE (READ_SIZE*I2S_FRAME/16) // number of uint16_t elements expected #define WRITE_SIZE_BYTES (BUFFER_SIZE*2) // bytes to write #define SAMPLE_RATE (44100) #define BITS (24) #define CHANNELS (1) uint16_t aud_buf[2*BUFFER_SIZE]; // Double buffering static volatile uint16_t *BufPtr; static uint16_t localBuf[BUFFER_SIZE]; static FIL file; static uint32_t totalBytesWritten = 0; void convert_endianness(uint32_t *array, uint16_t Size) { for (int i = 0; i < Size; i++) { array[i] = __REV(array[i]); } } void HAL_I2S_RxHalfCpltCallback(I2S_HandleTypeDef *hi2s) { BufPtr = aud_buf; osSemaphoreRelease(RxAudioSemHandle); } void HAL_I2S_RxCpltCallback(I2S_HandleTypeDef *hi2s) { BufPtr = &aud_buf[BUFFER_SIZE]; osSemaphoreRelease(RxAudioSemHandle); } void StartMicTask(void const *argument){ for(;;){ osSemaphoreWait(RxAudioSemHandle, osWaitForever); if (systemState != STATE_RECORDING){ continue; } memcpy(localBuf, (void*)BufPtr, WRITE_SIZE_BYTES); convert_endianness((uint32_t *)localBuf, READ_SIZE); if (SD_WriteWavBlock(&file, (int32_t *)localBuf, READ_SIZE, WRITE_SIZE_BYTES) == 0) totalBytesWritten += WRITE_SIZE_BYTES; } } void StartWriteAudioTask(void const *argument){ for(;;){ switch(systemState){ case STATE_START_RECORDING: totalBytesWritten = 0; if (SD_CreateWavFile(&file, 0, SAMPLE_RATE, BITS, CHANNELS) != 0) { SetState(STATE_MAIN_MENU); break; } HAL_I2S_Receive_DMA(&hi2s3, aud_buf, READ_SIZE); SetState(STATE_RECORDING); break; case STATE_RECORD_STOP: HAL_I2S_DMAStop(&hi2s3); osSemaphoreWait(RxAudioSemHandle, osWaitForever); SD_FinalizeWavFile(&file, totalBytesWritten, SAMPLE_RATE, BITS, CHANNELS); totalBytesWritten = 0; SetState(STATE_MAIN_MENU); break; default: osDelay(50); break; } } }
sd.c代码
#include "sd.h" #include "fatfs_platform.h" #include <string.h> #include <stdlib.h> #include "main.h" #define SUB_DIR "/REC_DIKTOFON" extern SD_HandleTypeDef hsd; static FATFS sdFatFs; static uint8_t sdMounted = 0; SDStatus sdStatus = SD_STATUS_MISSING; extern osMutexId fsMutex; void SD_Unmount(void){ f_mount(NULL, "", 0); sdMounted = 0; sdStatus = SD_STATUS_MISSING; } uint8_t SD_Init(void) { if(BSP_PlatformIsDetected() == SD_PRESENT){ f_mount(NULL, "", 0); HAL_SD_Init(&hsd); if(f_mount(&sdFatFs, "", 1) != FR_OK) { sdMounted = 0; sdStatus = SD_STATUS_MISSING; return 0; } sdMounted = 1; sdStatus = SD_STATUS_OK; return 1; } return 0; } static uint8_t IsWavFile(const char *name) { const char *dot = strrchr(name, '.'); if(!dot) return 0; return (!strcasecmp(dot, ".wav")); } typedef struct { char ChunkID[4]; uint32_t ChunkSize; char Format[4]; char Subchunk1ID[4]; uint32_t Subchunk1Size; uint16_t AudioFormat; uint16_t NumChannels; uint32_t SampleRate; uint32_t ByteRate; uint16_t BlockAlign; uint16_t BitsPerSample; char Subchunk2ID[4]; uint32_t Subchunk2Size; } WAVHeader; static void WAV_FillHeader(WAVHeader *hdr, uint32_t dataSize, uint32_t sampleRate, uint16_t bits, uint16_t channels) { memcpy(hdr->ChunkID, "RIFF", 4); memcpy(hdr->Format, "WAVE", 4); memcpy(hdr->Subchunk1ID, "fmt ", 4); memcpy(hdr->Subchunk2ID, "data", 4); hdr->ChunkSize = 36 + dataSize; hdr->Subchunk1Size = 16; hdr->AudioFormat = 1; hdr->NumChannels = channels; hdr->SampleRate = sampleRate; hdr->BitsPerSample = bits; hdr->ByteRate = sampleRate * channels * (bits / 8); hdr->BlockAlign = channels * (bits / 8); hdr->Subchunk2Size = dataSize; } static uint8_t GetNextRecIndex(uint16_t *nextIndex) { DIR dir; FILINFO fno; int16_t maxIndex = -1; if (f_opendir(&dir, SUB_DIR) != FR_OK) return 1; while (1) { if (f_readdir(&dir, &fno) != FR_OK || fno.fname[0] == 0) break; if (fno.fattrib & AM_DIR) continue; // otsi RECXX.wav if (strncasecmp(fno.fname, "REC", 3) == 0 && IsWavFile(fno.fname)) { int idx = 0; int i = 3; while (fno.fname[i] >= '0' && fno.fname[i] <= '9') { idx = idx * 10 + (fno.fname[i] - '0'); i++; } if (idx > maxIndex) maxIndex = idx; } } f_closedir(&dir); *nextIndex = maxIndex + 1; return 0; } uint8_t SD_CreateWavFile(FIL *file, uint32_t dataSize, uint32_t sampleRate, uint16_t bits, uint16_t channels){ UINT bw; WAVHeader hdr; osMutexWait(fsMutex, osWaitForever); uint16_t idx; char path[64]; if (GetNextRecIndex(&idx) != 0) { osMutexRelease(fsMutex); return 1; } // REC00.wav stiil snprintf(path, sizeof(path), SUB_DIR "/REC%02u.wav", idx); if (f_open(file, path, FA_CREATE_ALWAYS | FA_WRITE) != FR_OK){ osMutexRelease(fsMutex); return 1; } WAV_FillHeader(&hdr, dataSize, sampleRate, bits, channels); f_write(file, &hdr, sizeof(hdr), &bw); f_sync(file); // Kirjuta päis kohe kettale osMutexRelease(fsMutex); return 0; } uint8_t SD_WriteWavBlock(FIL *file, int32_t *data, uint32_t samples, uint32_t bytes) { UINT bw; osMutexWait(fsMutex, osWaitForever); FRESULT res = f_write(file, data, bytes, &bw); osMutexRelease(fsMutex); return (res == FR_OK && bw == bytes) ? 0 : 1; } uint8_t SD_FinalizeWavFile(FIL *file, uint32_t dataSize, uint32_t sampleRate, uint16_t bits, uint16_t channels) { UINT bw; osMutexWait(fsMutex, osWaitForever); uint32_t filesize = f_size(file); uint32_t data_len = filesize - 44; uint32_t total_len = filesize - 8; f_lseek(file, 4); f_write(file, &total_len, 4, &bw); f_lseek(file, 40); f_write(file, &data_len, 4, &bw); f_close(file); osMutexRelease(fsMutex); return 0; }
恳请各位提供技术帮助!
内容的提问来源于stack exchange,提问作者tomaito
相关产品推荐
相关产品推荐

