Finally, I succeeded implementing what I wanted: Starting the ADC in continuous circular mode by a timer. Doing so, all ADC values which are read now, are EXACTLY matching the timer values of the timer which triggered the ADC conversion. I.e. the timer becomes the absolute time reference for the ADC values.
To achieve that I had to modify the function adc_lld_start_conversion (in my case in hal/ports/STM32/STM32F1xx/adc_lld.c)
Code: Select all
void adc_lld_start_conversion(ADCDriver *adcp) {
uint32_t mode, cr2;
const ADCConversionGroup *grpp = adcp->grpp;
/* DMA setup.*/
mode = adcp->dmamode;
if (grpp->circular) {
mode |= STM32_DMA_CR_CIRC;
if (adcp->depth > 1) {
/* If circular buffer depth > 1, then the half transfer interrupt
is enabled in order to allow streaming processing.*/
mode |= STM32_DMA_CR_HTIE;
}
}
dmaStreamSetMemory0(adcp->dmastp, adcp->samples);
dmaStreamSetTransactionSize(adcp->dmastp, (uint32_t)grpp->num_channels *
(uint32_t)adcp->depth);
dmaStreamSetMode(adcp->dmastp, mode);
dmaStreamEnable(adcp->dmastp);
/* ADC setup.*/
adcp->adc->CR1 = grpp->cr1 | ADC_CR1_SCAN;
cr2 = grpp->cr2 | ADC_CR2_DMA | ADC_CR2_ADON;
if ((cr2 & (ADC_CR2_EXTTRIG | ADC_CR2_JEXTTRIG)) == 0) // activate continuous mode if EXTRIG is NOT selected
cr2 |= ADC_CR2_CONT;
adcp->adc->CR2 = grpp->cr2 | cr2;
adcp->adc->SMPR1 = grpp->smpr1;
adcp->adc->SMPR2 = grpp->smpr2;
adcp->adc->SQR1 = grpp->sqr1;
adcp->adc->SQR2 = grpp->sqr2;
adcp->adc->SQR3 = grpp->sqr3;
/* ADC start by writing ADC_CR2_ADON a second time - if EXTTRIG and CONT is NOT selected */
if ((cr2 & (ADC_CR2_EXTTRIG | ADC_CR2_JEXTTRIG | ADC_CR2_CONT)) == 0) adcp->adc->CR2 = cr2;
}
The only thing I added is the condition in the last line. This prevents ADON being set the second time because this would immediately start the conversion although the EXTRIG flag is set.
Here is the ADC configuration:
Code: Select all
static const ADCConversionGroup adc_commutate_group = {
TRUE, // circular mode
ADC_COMMUTATE_NUM_CHANNELS,
adc_commutate_cb,
adc_commutate_err_cb,
0, // ADC_CR1
ADC_CR2_EXTTRIG | ADC_CR2_CONT, // ADC_CR2: use ext event | select TIM1_CC1 event | Cont-mode (start once, always run)
0, // ADC_SMPR1
ADC_SMPR2_SMP_AN0(ADC_SAMPLE_1P5), // ADC_SMPR2
ADC_SQR1_NUM_CH(ADC_COMMUTATE_NUM_CHANNELS), // ADC_SQR1
0, // ADC_SQR2
// ADC regular sequence register 3 (ADC_SQR3): U_VOLTAGE (see schematic)
ADC_SQR3_SQ1_N(ADC_CHANNEL_IN0)// ADC_SQR3
};
So, we have to set ADC_CR2 to ADC_CR2_EXTTRIG | ADC_CR2_CONT plus the respective trigger source...
Do you think you could integrate this in all the ADC drivers?
It would be definately helpful, demonstrating the new feature in an example program then.
Cheers
Jörg