2

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?

GAMELASTER
  • 1,071
  • 1
  • 12
  • 23

3 Answers3

1

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

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" ...

Chris_B
  • 359
  • 5
  • 13
  • I allmost forgot - here you can find a ADC DMA Double Buffer example for the STM32F103: http://www.bepat.de/2020/11/27/stm32f103c8-adc-dual-regular-simultaneous-mode/ - you can ignore the "Dual Regular simultaneous" featrue, the principle of how to handle the data buffer stays the same ... – Chris_B Jan 31 '21 at 06:05
  • 1
    Thanks for you message. Yes, this is one of the ways how to have double buffering, but there is one catch. The DMA's Multi-Buffer feature have one great feature, you can change the pointers of buffers on the fly `HAL_DMAEx_ChangeMemory`. That's the feature I need, and it's not possible to do it with your current solution. – GAMELASTER Jan 31 '21 at 10:14
  • Hi @GAMELASTER I am trying to do the same thing, any update on this? – a_bet Jul 26 '22 at 18:36
  • Hi @a_bet , I'm sorry but I don't remember exactly, but I think I wasn't able to solve it :( – GAMELASTER Jul 28 '22 at 11:50
  • @GAMELASTER no problem, will reply here if I manage to do it – a_bet Jul 31 '22 at 13:21
0

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).

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
robert
  • 1