2025-05-27 10:23 AM
Hi,
I need to understand better how the "HAL_SAI_Receive_DMA(&hsai_BlockB1,ADC_Buffer,CodecBuffer_Size)" works.
I've a codec connected to the SAI 1 of a STMH723 MPU and I implemented a Ping-Pong routine to acquire and send the data to the Codec; two Callback function swap the buffers:
uint8_t ADC_Buffer[80000] __attribute__ ((aligned (4)));
void HAL_SAI_RxCpltCallback(SAI_HandleTypeDef *hsai_BlockB1){
adcp31=(q31_t *)&ADC_Buffer[BUFFER_SIZE_R/2];
RxDataReady1=1;
}
void HAL_SAI_RxHalfCpltCallback(SAI_HandleTypeDef *hsai_BlockB1){
adcp31=(q31_t *)&ADC_Buffer;
dacp31=(q31_t *)&DAC_Buffer;
RxDataReady=1;
}
If I write HAL_SAI_Receive_DMA(&hsai_BlockB1,ADC_Buffer,20000) what happens (in details) ?
Thank you
Solved! Go to Solution.
2025-06-01 11:19 PM - edited 2025-06-01 11:22 PM
At half complete and a size of 20k, there will be 10k samples in the buffer, if you enabled both Codec channels, then "Left / Right" interleaved (L1R1 L2R2 L3R3 L4R4...), with 5k each.
Don't be afraid to play with it, and check the buffers with a debugger / UART / test signal.
Test signal: I like using another SAI as a virtual DAC, putting out a sample-sync'd counter (or simpler a prepared buffer), then connecting directly SDATA-out to SDATA-in.
Then I should see 1,2,3,4, ... in the ADC buffer.
2025-05-27 11:42 AM
HAL_SAI_RxHalfCpltCallback is called when the first half of the buffer is populated.
HAL_SAI_RxCpltCallback is called when the second half of the buffer is populated.
If these are in circular mode, you will need to process each half-buffer before it starts to be overwritten on the next loop.
There is a 65535 item limit for DMA transfers.
2025-05-28 3:03 AM
Thank you for your fast reply,
I need to sample at 50KHz, 32 bit stereo, with a frequency resolution of 10Hz, then I need a buffer of 5000 uint32 for the left channel and the same for the right channel.
The SAI is connected to a stereo codec, there is a stream of L-R samples between the codec and the SAI, then I
set the "uint16_t Size" at 20000 (5000 x 4 uint8); is it correct ?
HAL_SAI_Receive_DMA(SAI_HandleTypeDef *hsai, uint8_t *pData, uint16_t Size)
uint8_t ADC_Buffer[80000] __attribute__ ((aligned (4))); 80000 ---> 20000 x 4 (L-R ping-pong)
HAL_SAI_Receive_DMA(&hsai_BlockB1,ADC_Buffer,20000)
My question is: after how many DMA transfers is the "HAL_SAI_RxHalfCpltCallback" called ?
2025-05-28 3:23 AM
> My question is: after how many DMA transfers is the "HAL_SAI_RxHalfCpltCallback" called ?
I admit that I don't know for byte buffers...
Is there a specific reason that you are using an byte / uint8_t buffer?
If you are sampling 32-bit anyway, everything gets simpler to further use 32-bit buffers and DMA.
Then half complete is called at half of Size given to DMA.
Here's my SAI RX DMA setup, also for H723 (and one of the few places that I'm using HAL):
/* Peripheral DMA init */
hDMA_Sai_1_A.Instance = DMA1_Stream0;
hDMA_Sai_1_A.Init.Request = DMA_REQUEST_SAI1_A;
hDMA_Sai_1_A.Init.Direction = DMA_PERIPH_TO_MEMORY;
hDMA_Sai_1_A.Init.PeriphInc = DMA_PINC_DISABLE;
hDMA_Sai_1_A.Init.MemInc = DMA_MINC_ENABLE;
hDMA_Sai_1_A.Init.Mode = DMA_CIRCULAR;
hDMA_Sai_1_A.Init.Priority = DMA_PRIORITY_VERY_HIGH;
hDMA_Sai_1_A.Init.FIFOMode = SAI2S_DMA_FIFO_MODE;
hDMA_Sai_1_A.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
hDMA_Sai_1_A.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
hDMA_Sai_1_A.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
hDMA_Sai_1_A.Init.MemBurst = SAI2S_DMA_MEMORY_BURST;
hDMA_Sai_1_A.Init.PeriphBurst = SAI2S_DMA_PERIPH_BURST;
if( HAL_DMA_Init(&hDMA_Sai_1_A) != HAL_OK ) Error_Handler_FL(__FILE__, __LINE__);
2025-05-28 3:42 AM
Thank you for your reply,
the HAL_SAI_Receive_DMA(SAI_HandleTypeDef *hsai, uint8_t *pData, uint16_t Size) function requires a uint8_t buffer.
2025-05-28 6:37 AM
> HAL_SAI_Receive_DMA(&hsai_BlockB1,ADC_Buffer,20000)
> My question is: after how many DMA transfers is the "HAL_SAI_RxHalfCpltCallback" called ?
To answer the direct question: 10000.
But I suspect you have this misconfigured if you are using byte transfers.
You can cast a pointer to whatever type you want.
uint16_t ADC_Buffer[20000];
HAL_SAI_Receive_DMA(&hsai_BlockB1,(uint8_t*)ADC_Buffer,20000);
2025-05-28 6:53 AM
carloV:
> the HAL_SAI_Receive_DMA(SAI_HandleTypeDef *hsai, uint8_t *pData, uint16_t Size) function requires a uint8_t buffer.
TDK:
> You can cast a pointer to whatever type you want.
So that's what I do, but to the int32_t SaiAdc buffers, and all DMA stuff set to 32 bit / WORD.
Works like a charm!
2025-05-28 7:22 AM
Thank you,
I'm very confused: the codec transmit two channels (left and right, sequentially) , every sample is 32 bit long (4 bytes), then if I set to 20000 the "Size" field of the "HAL_SAI_Receive_DMA(SAI_HandleTypeDef *hsai, uint8_t *pData, uint16_t Size)" function , when the "HAL_SAI_RxHalfCpltCallback" function is called what is the content of the ADC_buffer ?
2025-06-01 11:19 PM - edited 2025-06-01 11:22 PM
At half complete and a size of 20k, there will be 10k samples in the buffer, if you enabled both Codec channels, then "Left / Right" interleaved (L1R1 L2R2 L3R3 L4R4...), with 5k each.
Don't be afraid to play with it, and check the buffers with a debugger / UART / test signal.
Test signal: I like using another SAI as a virtual DAC, putting out a sample-sync'd counter (or simpler a prepared buffer), then connecting directly SDATA-out to SDATA-in.
Then I should see 1,2,3,4, ... in the ADC buffer.
2025-06-04 12:16 AM
Thank you !!