cancel
Showing results for 
Search instead for 
Did you mean: 

About SAI - DMA protocol

carloV
Associate III

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

1 ACCEPTED SOLUTION

Accepted Solutions
LCE
Principal II

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.

View solution in original post

9 REPLIES 9
TDK
Super User

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.

 

If you feel a post has answered your question, please click "Accept as Solution".
carloV
Associate III

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 ? 

 

 

 

LCE
Principal II

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__);

 

carloV
Associate III

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.

> 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);
If you feel a post has answered your question, please click "Accept as Solution".
LCE
Principal II

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!

carloV
Associate III

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

LCE
Principal II

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.

carloV
Associate III

Thank you !!