STM32 ADC DMA Double/Multi Buffer example

7.3k Views Asked by At

According to documentation, many of STM32's supports DMA in Double-Buffer (or also known as Multi-Buffer) mode. In HAL, there are two functions for this feature: HAL_DMAEx_MultiBufferStart and HAL_DMAEx_MultiBufferStart_IT in stm32xxxx_hal_adc_ex file. But in any SDK (H7, F7, F4 etc.), there are not single example of usage of those two functions. How to get this double-buffering DMA working together with ADC?

3

There are 3 best solutions below

5
On

I never used the functions you mentioned for double buffer technique. I simply create a buffer, which has double the size of a "normal" buffer and use the DMA Callback functions HAL_ADC_ConvCpltCallback and HAL_ADC_ConvHalfCpltCallback for the decision which half of the buffer needs to be processed.

On an "HAL_ADC_ConvCpltCallback" Interrupt the upper half of the Double Buffer is processed while the ADC is writing its data in the lower half and vice versa ...

So: if I want e.g. to process my data in blocks of 100 samples, I create a buffer with 200 samples

uint32_t ADC_DMABuffer[ADC_DMABufferSize * 2];

and start the ADC with

HAL_ADC_Start_DMA(&hadc1, ADC_DMABuffer, ((uint32_t)(ADC_DMABufferSize * 2)));  // Double Buffer

For processing the data in the lower half the start pointer is

ADC_DMABuffer[0]

for the upper half the start pointer is

ADC_DMABuffer[ADC_DMABufferSize]

and the count of data, that need to be processed is of course "ADC_DMABufferSize" ...

0
On

I`ve configure DMA in Double buffer mode for I2S interface. My sequence looks like this:

/*Starting with DMA in single buffer mode*/
HAL_I2S_Transmit_DMA(&hi2s3, Addr, Size);

/* Pause current DMA by disconnecting it from periphery (in my case - i2s interface) */
HAL_I2S_DMAPause(&hi2s3);

/* Mask all DMA interrupt, deal with internal state machine of dma handle */
HAL_DMA_Abort(hi2s3.hdmatx);

/* Set callback for XferCplt/XferHalfCplt interrupt for second buffer (I just set it to the same, that I`ve already have for first buffer) */
hi2s3.hdmatx->XferM1CpltCallback = hi2s3.hdmatx->XferCpltCallback;
hi2s3.hdmatx->XferM1HalfCpltCallback = hi2s3.hdmatx->XferHalfCpltCallback;

/*Configure DMA in Double Buffer mode*/
HAL_DMAEx_MultiBufferStart_IT(hi2s3.hdmatx,
                                  (uint32_t)Addr,
                                  (uint32_t)&hi2s3.Instance->DR,
                                  (uint32_t)(Addr + (Size >> 1)),
                                  Size >> 1);


/*Connect periphery to newly configured DMA in double buffer mode*/
HAL_I2S_DMAResume(&hi2s3);

Hope this will help.

0
On

HAL_ADC_Start_DMA and HAL_DMAEx_MultiBufferStart_IT, these two functions have conflicts. If you insist on using HAL_DMAEx_MultiBufferStart_IT, you should modify it or do something outside as _hal_unlock(hdma).