2025-01-10 07:31 PM - edited 2025-01-10 07:43 PM
I'm testing whether HAL_I2S_TxCpltCallback or HAL_I2S_TxHalfCpltCallback is called properly by setting i2s to normal and periodically calling HAL_I2S_Transmit_DMA. However, HAL_I2S_TxCpltCallback or HAL_I2S_TxHalfCpltCallback is called only once and not again. I want to use i2s in normal mode, not circular mode, so I'm testing like below. Is there something wrong?
When I check the return value with status = HAL_I2S_Transmit_DMA(&hi2s2, audioBuffer, AUDIO_BUFFER_SIZE);, HAL_BUSY(2) is returned.
while (1)
{
HAL_I2S_Transmit_DMA(&hi2s2, audioBuffer, AUDIO_BUFFER_SIZE);
HAL_Delay(1000);
}
void HAL_I2S_TxCpltCallback(I2S_HandleTypeDef *hi2s)
{
dma_count++;
}
void HAL_I2S_TxHalfCpltCallback(I2S_HandleTypeDef *hi2s)
{
dma_count++;
}
Solved! Go to Solution.
2025-01-11 04:28 AM - edited 2025-01-11 04:31 AM
nonono--- wrong.
You set all in Cube : I2S mode, DMA circular and half-word (if using 16b data words).
Then in prog you just start it once - then its running...
just in callbacks you put new data in the 1/2 block of the whole data array.
like here, in my audio player : (just i use the SAI for I2S, so you replace the SAI-calls with I2S-calls)
HAL_SAI_RegisterCallback(&hsai_BlockA1, HAL_SAI_TX_HALFCOMPLETE_CB_ID, HAL_SAI_TxHalfCpltCallback);
HAL_SAI_RegisterCallback(&hsai_BlockA1, HAL_SAI_TX_COMPLETE_CB_ID, HAL_SAI_TxCpltCallback);
fresult = HAL_DMA_Init(&hdma_sai1_a); // set DMA data stream -> SAI
for(int a=0;a<4096*2; a++)playbuf[a]=0; // clear dac i2s buf = silence
fresult = HAL_SAI_Transmit_DMA(&hsai_BlockA1, (uint8_t *)playbuf , (sizeof(playbuf))/4); // start continuous data stream
btw : the playbuffer is 16 KB size, giving about 40ms for every callback, to fill new data in. Or just 00 , for silence/pause/stop.
2025-01-11 12:57 AM
>I want to use i2s in normal mode, not circular mode, so I'm testing like below. Is there something wrong?
Nothing wrong.
I2S "normal" = standard, you have to use with all I2S DACs .This is the protocol of the transfer.
But the DMA mode is the point :
Start DMA in "normal" mode, transfers data one time. end.
In circular mode, its sending continuous. (the usual DMA mode for constant working DAC or ADC on I2S )
So - just your decision, what it should do: normal DMA = one block , circular DMA = continuous stream.
2025-01-11 03:09 AM
Thanks for your reply
Since you are calling HAL_I2S_Transmit_DMA every second
Shouldn't HAL_I2S_TxCpltCallback be called every second?
2025-01-11 04:28 AM - edited 2025-01-11 04:31 AM
nonono--- wrong.
You set all in Cube : I2S mode, DMA circular and half-word (if using 16b data words).
Then in prog you just start it once - then its running...
just in callbacks you put new data in the 1/2 block of the whole data array.
like here, in my audio player : (just i use the SAI for I2S, so you replace the SAI-calls with I2S-calls)
HAL_SAI_RegisterCallback(&hsai_BlockA1, HAL_SAI_TX_HALFCOMPLETE_CB_ID, HAL_SAI_TxHalfCpltCallback);
HAL_SAI_RegisterCallback(&hsai_BlockA1, HAL_SAI_TX_COMPLETE_CB_ID, HAL_SAI_TxCpltCallback);
fresult = HAL_DMA_Init(&hdma_sai1_a); // set DMA data stream -> SAI
for(int a=0;a<4096*2; a++)playbuf[a]=0; // clear dac i2s buf = silence
fresult = HAL_SAI_Transmit_DMA(&hsai_BlockA1, (uint8_t *)playbuf , (sizeof(playbuf))/4); // start continuous data stream
btw : the playbuffer is 16 KB size, giving about 40ms for every callback, to fill new data in. Or just 00 , for silence/pause/stop.
2025-01-15 10:52 PM
I am not convinced with the answer. if somebody does not want to use circular mode then how he/she can do it?
I am in the similar situation. Is there real solution to the problem?
2025-01-16 12:24 AM - edited 2025-01-16 12:29 AM
>I am not convinced with the answer.
So if you know a better way - tell the world !
>if somebody does not want to use circular mode then how he/she can do it?
You can do , whatever you want . Put the data in small pieces to the dma and some noise or unknown-state errors between - as you prefer.
>Is there real solution to the problem?
So : WHAT is the problem then ? DMA not working correct ? Or not understanding, how it should work ?
2025-01-16 04:33 PM
> So : WHAT is the problem then ? DMA not working correct ? Or not understanding, how it should work ?
The problem is when using normal mode, the callback is called only once. second time I2S_Transmit_DMA return HAL_BUSY error. The reason why I want to use normal mode is to have more control on timing. The audio is coming from other sources and mixed. The device is kind of intercom system which has other microcontrollers as well. We want to implement the same way in STM32 as we implemented in other microcontrollers. We cannot have delay. I hope you understand the issue.
2025-01-16 11:46 PM
>We cannot have delay. I hope you understand the issue.
This - is ok.
> The reason why I want to use normal mode is to have more control on timing.
This - not. Its just wrong. I2S is basically a continuous data stream, so circular DMA is the "natural" way to comply with this and to meet the requirement. You cannot do it better than 100% perfect (with circular dma).
>We want to implement the same way in STM32 as we implemented in other microcontrollers.
So show, how you do it there - an ARM (by STM here) is not different in any basic way.