Reputation: 709
I'm using I2S DMA to play some wav files (fixed format and sample rate) using double-buffer technique,
and somehow when the transmit starts, TxHalfCplt Callback only called once and then stopped working. Only TxCplt are working as expected. This cause only the second half of the buffer is getting refill every callback and left the first half of the buffer with leftover data and gets played in the DAC.
if I used printf
with UART to debug it, a UART transmit will be executed when TxHalfCplt Callback is executed. But not the other flags.
This is weird. The code is running in RTOS-CMSIS V2 and I've set the priority of the task to highest. What else am I missing here?
Codes within the task
uint32_t task_stat = STOP_TASK;
uint32_t StartAddr = 0x00000; // Sample Siren Audio Track
uint32_t EndAddr = 0x4FFFF;
uint32_t currentAddr = 0x00000;
uint32_t flashOffsetHalfBuffer = (AUDIO_BUFF_SIZE / 2) * sizeof(uint16_t); // 2 bytes per Channel sample, each half buffer is 4096 bytes
uint32_t flashOffsetFullBuffer = AUDIO_BUFF_SIZE * sizeof(uint16_t); // 2 bytes per Channel sample, each full buffer is 8196 bytes
/* Infinite loop */
for(;;)
{
if(osMessageQueueGet(test_TaskQueueHandle, &task_stat, NULL, osWaitForever) == osOK){
// Process the received message
printf("TEST STARTED\r\n");
// fill up the buffer (full buffer)
initAudioData(StartAddr, dacData);
currentAddr = StartAddr + flashOffsetFullBuffer;
FLAG_I2S_DATA_READY = 1;
// Start DAC
HAL_I2S_Transmit_DMA(&hi2s1, (uint16_t *)dacData, DMA_MAX(AUDIO_BUFF_SIZE / 2));
} else {
// Handle error
printf("ERR: TASK HANDLE MSG QT\r\n");
}
while (task_stat == RUN_TASK) {
if( FLAG_I2S_DATA_READY == 0 ){
if((currentAddr + flashOffsetHalfBuffer) <= EndAddr){
// Process Audio Data
if(processAudioData(currentAddr, dacPtr) == STAT_OK){
// Increment Start Address
currentAddr += flashOffsetHalfBuffer;
FLAG_I2S_DATA_READY = 1;
// Buffer loading debug output
//if(FLAG_FIRST_HALF_RELOAD == 1){
// printf("F\r\n");
//} else if(FLAG_SECOND_HALF_RELOAD == 1){
// printf("S\r\n");
//}
}
} else {
// Redirect Current Address to Start Address, Hence the Circular Playback
currentAddr = StartAddr;
// Process Audio Data
if(processAudioData(currentAddr, dacPtr) == STAT_OK){
// Increment Start Address
currentAddr += flashOffsetHalfBuffer;
FLAG_I2S_DATA_READY = 1;
// Buffer loading debug output
//if(FLAG_FIRST_HALF_RELOAD == 1){
// printf("F\r\n");
//} else if(FLAG_SECOND_HALF_RELOAD == 1){
// printf("S\r\n");
//}
}
}
}
if(osMessageQueueGet(test_TaskQueueHandle, &task_stat, NULL, 1) == osOK){
// Process the received message
printf("TASK PAUSE\r\n");
HAL_I2S_DMAStop(&hi2s1);
// Purge DAC Buffer?
currentAddr = 0x00000;
// Stop Task
task_stat = STOP_TASK;
}
}
osDelay(1);
}
Callbacks:
void HAL_I2S_TxCpltCallback(I2S_HandleTypeDef *hi2s){
dacPtr = &dacData[AUDIO_BUFF_SIZE/2];
FLAG_I2S_DATA_READY = 0;
FLAG_FIRST_HALF_RELOAD = 0;
FLAG_SECOND_HALF_RELOAD = 1;
/* Callback debug output*/
//printf("C\r\n");
}
void HAL_I2S_TxHalfCpltCallback(I2S_HandleTypeDef *hi2s){
dacPtr = &dacData[0];
FLAG_I2S_DATA_READY = 0;
FLAG_FIRST_HALF_RELOAD = 1;
FLAG_SECOND_HALF_RELOAD = 0;
/* Callback debug output*/
//printf("H\r\n");
}
Definitions:
// DMA Flag
volatile uint8_t FLAG_I2S_DATA_READY = 1;
volatile uint8_t FLAG_FIRST_HALF_RELOAD = 0;
volatile uint8_t FLAG_SECOND_HALF_RELOAD = 0;
// DMA Buffer
uint16_t dacData[AUDIO_BUFF_SIZE];
// Buffer Pointer
static volatile uint16_t *dacPtr = &dacData[0];
Upvotes: 0
Views: 87
Reputation: 709
Looks like it was a silly mistake.
The DMA has to be configured using Half Word (16-bit) instead of Word (32-bit) when I transmitting 16-bit audio data (Even though I2S is set transmitting 16-bit data in 32-bit frame). Otherwise the interrupt seems cannot figure out where the midpoint is.
Upvotes: 0