2025-09-10 12:45 AM - last edited on 2025-09-10 12:58 AM by mƎALLEm
Post edited by ST moderator to be inline with the community rules especially for sharing a code. Please read this post.
I’m working on playing audio on the TAS2110 codec using the STM32U5G9J-DK1 board via SAI.
I tested with generated sine and square waves, and I can hear output on the speaker.
However, when I try to play audio data stored in memory, I don’t get any sound.
To store the audio file, I created a .s file as shown below:
.section .wav_data, "a"
.global _wav_data
_wav_data:
.incbin "C:/Work/Project/Project/audio_codec/Core/Src/wav/audio.wav"
.global _wav_data_end
_wav_data_end:
I can parse the WAV data using my parser API. Parsing works fine, and I copy the samples into a buffer, then send it to SAI via DMA.
Could you please help me identify what I might be missing? Why do I not get audio output from the speaker when streaming from the WAV file?
My GPDMA and SAI configurations are set up accordingly.
In the linker script
.wav_data :
{
. = ALIGN(4);
_swav_data_start = .;
KEEP(*(.wav_data))
_swav_data_end = .;
} >FLASH
Parse API
int parse_wav_file(uint8_t *wav_data, uint32_t wav_size, wav_info_t *info) {
if (wav_size < 44) return -1; // Too small for header
// Check RIFF header
if (strncmp((char *)wav_data, "RIFF", 4) != 0) return -1;
if (strncmp((char *)(wav_data + 8), "WAVE", 4) != 0) return -1;
// Find fmt chunk
uint32_t offset = 12;
while (offset + 8 < wav_size) {
if (strncmp((char *)(wav_data + offset), "fmt ", 4) == 0) {
break;
}
offset += 8 + *(uint32_t *)(wav_data + offset + 4);
}
if (offset + 8 >= wav_size) return -1;
// Parse fmt chunk
uint16_t audio_format = *(uint16_t *)(wav_data + offset + 8);
info->num_channels = *(uint16_t *)(wav_data + offset + 10);
info->sample_rate = *(uint32_t *)(wav_data + offset + 12);
info->bits_per_sample = *(uint16_t *)(wav_data + offset + 22);
if (audio_format != 1 || info->num_channels != 1 || info->bits_per_sample != 16) {
return -1; // Only support mono, 16-bit PCM
}
// Find data chunk
offset += 8 + *(uint32_t *)(wav_data + offset + 4);
while (offset + 8 < wav_size) {
if (strncmp((char *)(wav_data + offset), "data", 4) == 0) {
info->data_size = *(uint32_t *)(wav_data + offset + 4);
info->data_start = wav_data + offset + 8;
return 0;
}
offset += 8 + *(uint32_t *)(wav_data + offset + 4);
}
return -1;
}
Filling audio as per below API
#define AUDIO_BUFFER_SIZE 4096
uint32_t wav_index = 0;
void fill_audio_buffer(void) {
uint32_t samples_to_copy = AUDIO_BUFFER_SIZE;
if (wav_index + samples_to_copy > wav_info.data_size / 2) {
samples_to_copy = (wav_info.data_size / 2) - wav_index;
}
memcpy(audio_buffer,
(int16_t *)(wav_info.data_start + wav_index * 2),
samples_to_copy * sizeof(int16_t));
wav_index += samples_to_copy;
}
Audio Play API
static int audio_play(uint16_t *paudioBuff, uint32_t len)
{
if(HAL_OK != HAL_SAI_Transmit_DMA(saiptr,(uint8_t*)paudioBuff, AUDIO_BUFFER_SIZE))
{
return -1;
}
return 0;
}
int wavPlayer_play(tas2110_data_t *tas_data)
{
uint32_t wav_size = _swav_data_end - _swav_data_start;
file_size = wav_size;
if (parse_wav_file(_wav_data, wav_size, &wav_info) != 0)
{
return -1;
}
tas2110_Configuration(tas_data);
fill_audio_buffer();
if(audio_play((uint16_t *)&audio_buffer[0], AUDIO_BUFFER_SIZE) != 0)
{
return -1;
}
return 0;
}
Callback APIs:
void HAL_SAI_TxHalfCpltCallback(SAI_HandleTypeDef *hsai)
{
fill_audio_buffer();
HAL_SAI_Transmit_DMA(hsai, (uint8_t*)audio_buffer, AUDIO_BUFFER_SIZE);
}
void HAL_SAI_TxCpltCallback(SAI_HandleTypeDef *hsai)
{
fill_audio_buffer();
HAL_SAI_Transmit_DMA(hsai, (uint8_t*)audio_buffer, AUDIO_BUFFER_SIZE);
}