Actually, the job should be easy. Since that has been an issue plaguing STM32 for some time, let me give you a very detailed response.
It should be easy because DMA is highly modularized and you really do not have to write any low-level code at all; just plug the DMA calls into the drivers. The DMA module interface is defined in arch/arm/src/stm32/stm32_dma.h.
The only other important file is the DMA header file in chip/ sub-directory. Let's say for discussion that you are using an STM32 F429, then that would be chip/stm32f42xxx_dma.h. The only thing that is important in those files are the DMA stream definitions at the bottom of that file:
$ grep -n ADC chip/stm32f42xxx_dma.h
478:#define DMAMAP_ADC1_1 STM32_DMA_MAP(DMA2,DMA_STREAM0,DMA_CHAN0)
482:#define DMAMAP_ADC1_2 STM32_DMA_MAP(DMA2,DMA_STREAM4,DMA_CHAN0)
488:#define DMAMAP_ADC2_1 STM32_DMA_MAP(DMA2,DMA_STREAM2,DMA_CHAN1)
489:#define DMAMAP_ADC2_2 STM32_DMA_MAP(DMA2,DMA_STREAM3,DMA_CHAN1)
494:#define DMAMAP_ADC3_1 STM32_DMA_MAP(DMA2,DMA_STREAM0,DMA_CHAN2)
495:#define DMAMAP_ADC3_2 STM32_DMA_MAP(DMA2,DMA_STREAM1,DMA_CHAN2)
Notice that there are multiple options for each DMA stream. You have to disambiguate that stream numbers in your board.h header file, just as you have to do for pin multiplexing options (the F429 refers to these as streams, but a lot of the older F1 channel terminology is used).
Notice also that all ADC DMA is on DMA2 which you will have to enable in the configuration.
I see that the DAC driver, stm32_dac.c, supports DMA. The direction is in the wrong direction and, as a write only device, it is much simpler, but should be a good example for DMA.
Here is a step by step:
1. Add the DMA stream disambiguation to to the board.h header file.
2. Add an option to the STM32/Kconfig file to enable per ADC DMA operations. This option should depend on DMA2 being enabled. Let's say CONFIG_STM32_ADC_DMA.
Everything else would be done in stm32_adc.c:
3. Add two new fields to struct stm32_dev_s (both conditioned on CONFIG_STM32_ADC_DMA).
- A uint8_t field to hold the DMA stream number
- A DMA_HANDLE type stream handle
- Whatever else you need to manage the DMA
See line 337 of stm32_dac.c. These are the dmachan and dma fields in stm32_chan_s.
4. Add an initializer for the DMA stream number in g_adcpriv1, g_adcpriv2, and g_adcpriv3.
See line 394 of stm32_dac.c.
5. In stm32_adcinitialize(), call stm32_dmachannel() to allocate a DMA stream and save it in the device structure.
See line 965 of stm32_dac.c
6. Then when ADC is enabled, call stm32_dmasetup() using the handle, the address of the ADC data register, and the address in memory to receive the DMA data, the number of transfers, and the value of the DMA CCR register to use.
See line 713 of stm32_dac.c
This last part is the trickiest, CCR was an F1 DMA register but the name has stuck. For the F4, it is the SCR register. You will have to look at the chip/stm32f42xxx_dma.h file for SCR register settings and also look at other RX transfer examples in other C files (grep for SCR in stm32/ and you will see many). It is just a magic number that will require some thought.
7. Then call stm32_dmastart(). You have to provide a callback to this function. When the DMA completes, you will get a callback from the DMA completion interrupt handler with a code to tell you the DMA completed successfully.
See line 718 and line 662 of stm32_dac.c
The DAC version of the DMA callback does not anything. You will probably need logic to buffer the the ADC data that you read and to wake up any application waiting for the availability of ADC data.
So that is it: On new configuration setting, on new handle variable, on new function, and three new function calls.