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 Answers
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).
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.
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.
DMA
stands for direct memory address. It means, the ADC will write directly into the memory address you give it. So firstuint16_t adcvalues[10];
, then configure DMA to write 10 values intoadcvalues
pointer, wait for completion, then you read values just fromadcvalues
. – KamilCukvolatile
, 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