cancel
Showing results for 
Search instead for 
Did you mean: 

STM32H747 DMA Linked List (or Double Buffering) and ADC Interleaved

ABett.3
Associate II

Hi all,

I'm implementing a DAQ (data acquisition chain), using STM32H747Xi Discovery board.

What I need to do is sample as fast as possible 1 adc channel and do some light processing on the data. I need to understand how to configure the system to get the best results.

So far here's my guess:

  • ADC1 & 2 in interleaved mode (ADC 1 as master)
  • ADCs in continuous mode
  • Transfer data to Memory using DMA in Linked List (or Double Buffering)

What I would like to do is set up 2 buffers and having the M7 process the 1st while the 2nd is beeing filled by the DMA. And viceversa.

I think that using linked list is the right way to go, because it also allows to target 2 different memory banks to avoid collision.

I started off with this example from stm32cubeh7 repo, which shows ADC interleaved functioning and uses circular buffering. I also found this one on MDMA linked lists.

Now I need to understand how to "merge" them.

Here are my questions:

  • How's the flow between sw, adc and dma? Should the ADC ask the DMA to start a transaction or the 2 should be started independently by sw?
  • from stm32h7xx_hal_adc.h "In continuous mode, DMA must be configured in circular mode. Otherwise an overrun will be triggered when DMA buffer maximum pointer is reached." But I guess it is possible to use it in linked mode as well right?
  • What do you think of the LinkedList approach as opposed to the circular buffer with HalfCompletion and Completion callback?

Any help/example on this topic would be of much help.

12 REPLIES 12

Memory-to-memory is like Tx+Rx. Do cache cleaning for source memory like on Tx buffers and invalidation for destination memory like on Rx buffers. The only exception is DTCM, which is never cached and can be accessed by MDMA through the dedicated AHBS bus.

As Georgy said, you can always disable (actually just do not enable it) D-cache for debugging purposes. I-cache can still be left enabled.

0693W00000Sv4KBQAZ.png@Piranha​ Thanks for the guidance.

Here's a diagram of what I implemented so far, hope that is clear.

(edit: spotted a typo, the 2° m2m callback invalidates the 2nd half)

At the moment I can see that the m2m callback is never called.

Here's my code for it:

static void m2mCallback(DMA_HandleTypeDef *_hdma);
 
HAL_DMA_RegisterCallback(&hdma_memtomem_dma2_stream0, HAL_DMA_XFER_CPLT_CB_ID, m2mCallback);
 
/* Track mem2mem complete */
void m2mCallback(DMA_HandleTypeDef *_hdma)
{
  if(status == SECOND_HALF_COPY_STARTED)
  {
    /*Invalidate 2nd half of Rx Buffer (copied ADC values)*/
    SCB_InvalidateDCache_by_Addr((uint32_t *) &aADCDualConvertedValuesCopied[ADCCONVERTEDVALUES_BUFFER_SIZE/2], 4*ADCCONVERTEDVALUES_BUFFER_SIZE/2);
    status = SECOND_HALF_COPY_COMPLETED;
    BSP_LED_Off(LED_ORANGE);
  } else if (status == FIRST_HALF_COPY_STARTED) {
    /*Invalidate 1st half of Rx Buffer (copied ADC values)*/
    SCB_InvalidateDCache_by_Addr((uint32_t *) &aADCDualConvertedValuesCopied, 4*ADCCONVERTEDVALUES_BUFFER_SIZE/2);
    status = FIRST_HALF_COPY_COMPLETED;
    BSP_LED_On(LED_ORANGE);
  }
}

HAL_DMA_RegisterCallback(&hdma_memtomem_dma2_stream0, HAL_DMA_XFER_CPLT_CB_ID, m2mCallback);

Make sure that MEM2MEM's "dma 2 stream 0" global interrupt is enabled. In my case it was "dma 1 stream 5 global interrupt":0693W00000Sv4aiQAB.png

Disappointed with crowdfunding projects? Make a lasting, meaningful impact as a Tech Sponsor instead: Visit TechSponsor.io to Start Your Journey!