2024-11-23 05:02 PM
Hi, my goal was to play some .wav audio files from an external SD card using the onboard DAC and an Audio Booster XL Board from Texas instruments( BOOSTXL-AUDIO ). I was able to interface with the SD Card and read the audio files, but the problem came in when i tried to play the audio. What i got when playing the file is a loud repetitive static noise coupled together with the original audio signal. My first thought as to the cause of the problem which was later confirmed with a couple internet searches, was that the DAC buffer is not being updated fast enough for the audio signal to be played smoothly, so I tried to implement the double buffering approach to deal with the that static noise but still no luck. Information about the audio file, source code and configurations is listed below. Any help as to how to get rid of the noise is greatly appreciated, Thanks in advance.
micro-controller: NUCLEO-L476RG
WAV Audio File:
Tim6:
SPI (used to interface with the SD card):
DAC:
Explanation of the code for double buffering:
I have two buffers (dac_buffer0, dac_buffer1) which are in charge of storing the audio data to be played. During the first run of the program or when the onboard BTN is pressed, the 2 buffers are filled with audio data. A state variable named DEVICE_STATE is in charge of keeping track of the different states the controller can be in throughout the whole file reading process. A pointer of same type as the 2 buffers above is created and assigned one of the two buffers' addresses. During the whole audio streaming process, this pointer is the one assigned to the DAC_DMA to retrieve values from. In the DMA_ConvHalfCplt interrupt, i check which of the 2 buffers is pointed to by the pointer and update the DEVICE_STATE with a flag that indicates either the first or second buffer has been filled half way, then replacement of the already used data with new ones in the current buffer is done. In the DMA_ConvCplt interrupt I first replace the already used audio data in the current buffer with new ones then I check whether the buffer pointed to by the pointer has already been filled half way, if that's the case then set the new address pointed to by the pointer to the next buffer between the 2 and the process repeats.
Variables:
enum StateMachine{
OP_ERROR = 0x01,
SD_MOUNT = 0x02,
FIL_OPEN = 0x04,
READ_CMPLT = 0x08,
CLOSE_FILE = 0x10,
BTN_PRESSED = 0x20,
BUFFER_1_FILL = 0x40,
BUFFER_2_FILL = 0x80,
BUFFER_1_HALF_FILL = 0x100,
BUFFER_2_HALF_FILL = 0x200
};
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define f_unmount(path) f_mount(NULL, path, 0)
#define ITER_COUNT 1000
#define BUFFER_SIZE 15u *1024
#define BUFFER_HALF_SIZE BUFFER_SIZE/2
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
DAC_HandleTypeDef hdac1;
DMA_HandleTypeDef hdma_dac_ch1;
SPI_HandleTypeDef hspi2;
TIM_HandleTypeDef htim6;
UART_HandleTypeDef huart2;
/* USER CODE BEGIN PV */
int16_t audio_buffer[BUFFER_SIZE];
uint16_t dac_buffer0[BUFFER_SIZE];
uint16_t dac_buffer1[BUFFER_SIZE];
uint16_t* buf_ptr;
FATFS fs;
FIL fil;
wav_header w_header;
int DEVICE_STATE;
Read Audio Data Function:
void read_audio_data(FIL* file_handle, uint16_t* buffer, uint32_t i, uint32_t size, int* state){
if(i >= size)
return;
FRESULT res;
UINT bytes_read;
time_elapsed_read = __HAL_TIM_GET_COUNTER(&htim6);
res = f_read(file_handle, audio_buffer, size, &bytes_read);
if(res != FR_OK){
myprintf("Failed to Read Audio Data: f_read(%i)\r\n", res);
*state = OP_ERROR;
return;
}
for(; i < size; i++){
buffer[i] = ((audio_buffer[i] >> 4) +0x8000) & 0xfff;
}
time_elapsed_read = __HAL_TIM_GET_COUNTER(&htim6) - time_elapsed_read;
if(bytes_read < size){
*state = READ_CMPLT;
// myprintf("Complete Audio Data Read Successful\r\n");
}
}
Inside While Loop:
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
deinit_file_system(&fs, &fil, &DEVICE_STATE);
if((DEVICE_STATE & BTN_PRESSED) > 0){
if((DEVICE_STATE & SD_MOUNT) == 0){
init_file_system("applause.wav", &fs, &fil, &w_header, &DEVICE_STATE);
read_audio_data(&fil, dac_buffer0, 0, BUFFER_SIZE, &DEVICE_STATE);
read_audio_data(&fil, dac_buffer1, 0, BUFFER_SIZE, &DEVICE_STATE);
buf_ptr = dac_buffer0;
}
HAL_DAC_Start_DMA(&hdac1, DAC_CHANNEL_1, buf_ptr, BUFFER_SIZE, DAC_ALIGN_12B_R);
DEVICE_STATE ^= BTN_PRESSED;
}
}
Interrupts:
/* USER CODE BEGIN 4 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){
DEVICE_STATE |= BTN_PRESSED;
}
void HAL_DAC_ConvHalfCpltCallbackCh1(DAC_HandleTypeDef* hdac){
read_audio_data(&fil, buf_ptr, 0, BUFFER_HALF_SIZE, &DEVICE_STATE);
if(buf_ptr == dac_buffer0)
DEVICE_STATE |= BUFFER_1_HALF_FILL;
else
DEVICE_STATE |= BUFFER_2_HALF_FILL;
DEVICE_STATE |= CLOSE_FILE * ((DEVICE_STATE & READ_CMPLT) > 0);
}
void HAL_DAC_ConvCpltCallbackCh1(DAC_HandleTypeDef* hadc){
read_audio_data(&fil, buf_ptr, BUFFER_HALF_SIZE, BUFFER_SIZE, &DEVICE_STATE);
if((buf_ptr == dac_buffer0) && (DEVICE_STATE & BUFFER_1_HALF_FILL) > 0)
buf_ptr = dac_buffer1;
else if((buf_ptr == dac_buffer1) && (DEVICE_STATE & BUFFER_2_HALF_FILL) > 0)
buf_ptr = dac_buffer0;
DEVICE_STATE |= CLOSE_FILE * ((DEVICE_STATE & READ_CMPLT) > 0);
}
/* USER CODE END 4 */