I have successfully utilized the ADC with DMA on F0 and F3 devices, although I’ve never tried it on a F103 device, and have accomplished this in ‘bare metal’ mode without using the ST HAL, so hopefully my advice will be applicable to your situation.
The first thing I’d recommend is that you keep the DMA channel disabled when writing to the various DMA channel configuration registers (CNDTR, CMAR, CPAR, CCR etc.). Set DMA_CCR_EN only after all other DMA channel settings have been set.I can’t say for certain if this is an absolute requirement - the ST reference docs are unclear on this point, but it’s what I do in my own ADC DMA init routine.
Also make sure that the ADC is enabled but idle (not converting) before setting DMA_CCR_EN. Explicitly clear the contents of ADCx->ISR before enabling DMA; e.g. ADC1->ISR = 0x000000FF
If you are using DMA in circular buffer mode, make sure that both DMA_CCR_CIRC -and- ADC_CFGR1_DMACFG are set.
You should be setting ADC_CR2_ADON and doing other ADC initialization tasks before enabling the ADC. Unless you’re concerned about power consumption, you should leave the ADC enabled (ADON set) and set ADC_CR_ADSTART to trigger a conversion sequence.
Here’s the basic sequence of operations I use to run the ADC in software triggered mode with DMA:
- Disable DMA channel associated with ADC (clear DMA_CCR_EN)
- Reset ADC by setting RCC_APB2RSTR_ADCRST, enable its clock (set RCC_APB2ENR_ADC1EN), clear RCC_APB2ENR_ADC1EN
- Configure ADC clock source (I set RCC_CR2_HSI14ON)
- Disable ADC (set ADC_CR_ADDIS), wait for disable confirm (ADC_CR_ADEN clear)
- Initiate ADC autocalibration process (set ADC_CR_ADCAL, wait for ADC_CR_ADCAL to be cleared by hardware)
- Set ADC config regisers to desired setup (ADC1->CFGR1, CFGR2, SMPR, TR, CHSELR, ADC->CCR)
- Clear ADC1->ISR (ADC1->ISR = 0x000000FF)
- Enable ADC (set ADC_CR_ADEN, wait for ADC_ISR_ADRDY set)
- Clear ADC1->ISR again
- Enable any desired ADC interrupts, configure NVIC
- Initialize DMA channel associated with ADC (for the STM32F091 that I’m familiar with, this is DMA->Channel1)
- Enable DMA channel (set DMA_CCR_EN)
- Set ADC_CR_ADSTART to trigger a conversion sequence
- Wait for ADC_ISR_EOSEQ set
- Read contents of DMA buffer for conversion results
When using DMA in non-circular (linear buffer) mode, I’m not certain how much DMA re-initialization is required - again, the reference docs are unclear on this point, but I clear DMA_CCR_EN, re-initialize CPAR, CMAR and CNDTR, then set DMA_CCR_EN before triggering a new conversion. I have confirmed that none of this re-init is needed if using DMA in circular buffer mode.
Essentially, I repeat the last 5 steps of the procedure I outlined above for each conversion sequence I run.
Hope this helps...