I think the ADC driver for L0 (ADCv1) could use a slight improvement for circular mode. This change causes the sample sequence to be automatically restarted at the end, therefore enabling the circular mode:
Code: Select all
@@ -297,7 +297,7 @@ void adc_lld_start_conversion(ADCDriver *adcp) {
mode = adcp->dmamode;
cfgr1 = grpp->cfgr1 | ADC_CFGR1_DMAEN;
if (grpp->circular) {
- mode |= STM32_DMA_CR_CIRC;
+ mode |= STM32_DMA_CR_CIRC | ADC_CFGR1_CONT;
cfgr1 |= ADC_CFGR1_DMACFG;
if (adcp->depth > 1) {
/* If circular buffer depth > 1, then the half transfer interrupt
I'm not an expert on the ADC peripheral and perhaps this bit is left at 0 due to a possible collision with DISCEN (user can set that bit in conv-group config).
This behaviour matches what is described in RM0377 and a code snipped contained within it:
A.8.10 DMA circular mode sequence code example
Code: Select all
/* (1) Enable the peripheral clock on DMA */
/* (2) Enable DMA transfer on ADC and circular mode */
/* (3) Configure the peripheral data register address */
/* (4) Configure the memory address */
/* (5) Configure the number of DMA tranfer to be performs
on DMA channel 1 */
/* (6) Configure increment, size, interrupts and circular mode */
/* (7) Enable DMA Channel 1 */
RCC->AHBENR |= RCC_AHBENR_DMA1EN; /* (1) */
ADC1->CFGR1 |= ADC_CFGR1_DMAEN | ADC_CFGR1_DMACFG; /* (2) */
DMA1_Channel1->CPAR = (uint32_t) (&(ADC1->DR)); /* (3) */
DMA1_Channel1->CMAR = (uint32_t)(ADC_array); /* (4) */
DMA1_Channel1->CNDTR = NUMBER_OF_ADC_CHANNEL; /* (5) */
DMA1_Channel1->CCR |= DMA_CCR_MINC | DMA_CCR_MSIZE_0 | DMA_CCR_PSIZE_0 \
| DMA_CCR_TEIE | DMA_CCR_CIRC; /* (6) */
DMA1_Channel1->CCR |= DMA_CCR_EN; /* (7) */