cancel
Showing results for 
Search instead for 
Did you mean: 

Trouble With Streaming Audio From External SD Card (.WAV file format)

MattRuk
Associate

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:

  • sample rate = 48000,  format =  16-bit PCM, file size = 1.3MB

Tim6:

  • PSC = 0, ARR = 1663, Trigger Event = Update

SPI (used to interface with the SD card):

  • Slow speed (for initialization) = 312.5KBits/s
  • High speed = 5.0MBits/s
  • Data Size = 8-bits, CPOL = Low, CPHA = 1 Edge

DAC:

  • Trigger = tim6 trigger out event
  • DMA added set to circular with Half-Word data width

 

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 */

 

 

 

 

   

 

 

 

0 REPLIES 0