2
votes

I enabled DMA peripheral to memory tranfer for ADC1 in CubeMX and generated the code. However I'm confused as to where the data from the ADC will be written to? Should I explicitly define a variable to contain this data? How can I retrieve the data in the DMA Channel 1 ISR?

4
To configure the DMA you have to give it the address and effective (in term of word size and count) size of a memory buffer, hopefully at a valid place in RAM. The data will land there. Only you have the code, so only you know where that is.Chris Stratton
The DMA stands for direct memory address. It means, the ADC will write directly into the memory address you give it. So first uint16_t adcvalues[10];, then configure DMA to write 10 values into adcvalues pointer, wait for completion, then you read values just from adcvalues.KamilCuk
Note: DMA buffers should always be declared as volatile, or you may get all manner of strange optimization bugs. You also have to consider re-entrancy between the DMA hardware and your application.Lundin

4 Answers

5
votes

The DMA does not manage memory nor choose a valid address to set the data. General speaking, the DMA allows data transfers without using the CPU, but no more.


The STM32 microcontrollers provide transfers from:

  • memory to memory
  • memory to peripheral
  • peripheral to memory

In all of them, the developers have to be aware about them purpose in order to configure (besides of DMA) the source and destination places, such as address of the peripherals, reserve memory (and what kind of memory), etc.


In your particular case (check RM, AN, docs, etc), the main actors in an ADC to memory (peripheral to memory) transfer are:

  • Source: ADC peripheral, the developer has to know where the ADC peripheral is located and configure (besides of ADC) the DMA based on the ADC parameters as the source of information.
  • Destination: memory, the developer has to reserve a bunch of memory (heap/stack/global/etc) and configure the DMA according to the already allocated space of memory. Doing that, DMA will allow you to set the values in different ways (depending on the device), such as continuous ring buffer, one cycle, ping-pong buffer (stm32 uses the term "circular double buffer"), etc.
  • DMA and ADC configuration: there are vast amount of factors which for the sake of simplicity I am not going to include, usually simplified by the manufacturer's HAL (it is up to you to use it).
3
votes

You instruct the HAL DMA ADC driver where to put the sample data when you start the conversion:

volatile uint32_t adcBuffer[SAMPLE_COUNT]; 
HAL_ADC_Start_DMA( &hadc, 
                   adcBuffer, 
                   SAMPLE_COUNT ); 

Note that some STM32 parts have SRAM divided across multiple buses with one section very much smaller than others. There are performance benefits to be had in reserving this section for DMA buffers since it reduces bus contention with normal software data fetches. So you may want to customise your linker script to create sections and explicitly place DMA buffers in one while excluding placement of application data there.

2
votes

If you have a look at the HAL documents and examples you findet an example how to use the ADC with DMA.

In short :

To start the conversion you use the function:

HAL_StatusTypeDef HAL_ADC_Start_DMA(ADC_HandleTypeDef* hadc, uint32_t* pData, uint32_t Length);

Where pData is your variable / array where the DMA should put the data.

1
votes

DMA and uC do not know anything about the variables. DMA peripheral has two configuration registers where you store the peripheral address and the memory address. If you start from reading the uC documentation instead of HAL everything would be clear instantly