ADC implementations vary significantly across STM32 families, so register/bit names and mechanisms mentioned here (based on 'L0) are only illustrative and in particular STM32 family may be different.
Similarly to other peripherals which produce (or consume) data (such as UART, I2C, SPI, etc.), data produced by ADC can be read out basically in three ways:
- polling - processor reads repeatedly the flag indicating data are ready (ADC_ISR.EOC), and then reads the freshly converted
value from the data register (ARC_DR)
- interrupt - the data-ready flag (ADC_ISR.EOC) can usually trigger an interrupt, after that is enabled through a flag specific for this event (ADC_ISR.EOCIE)
and through the NVIC enable bit respective to ADC. Then, processor in the ISR (possibly after having qualified the interrupt source)
reads out the new value from data register.
- DMA - after enabling DMA trigger in ADC (ADC_CFGR1.DMAEN) and setting up the respective DMA channel/stream, after each conversion finishes, DMA performs a transfer from the ADC data register to buffer in memory. It is then up to the processor to process the data in the memory buffer, usually after DMA triggers its half-complete and transfer-complete interrupts.
The pace (rate), at which ADC produces data, is determined by several factors:
- in the simplest setting, processor starts conversion whenever it needs (e.g. after reading out the previous conversion result, or in some timed process) by writing the appropriate ADC bit (ADC_CR.ADSTART)
- ADC conversions can be triggered automatically by a timer (or external input) when configured so by ADC_CFGR1.EXTEN/EXTSEL
- after triggered either "manually" or by timer/externally, if discontinuous mode is disabled (by setting ADC_CFGR1.DISCEN = 0)
and the programmed sequence of channels (in ADC_CHSELR) consists of more than 1 channel, then ADC automatically starts conversion of next channel
in sequence after the previous channel has been converted, and stops only after the last channel in sequence has been converted
- if continuous mode is enabled (by setting ADC_CFGR1.CONT = 1), ADC keeps converting channels in the sequence infinitely, starting next conversion immediately after the previous conversion has been finished
So, in the cases, where conversion is started automatically by ADC immediately after previous conversion has finished, i.e. in cases of whole sequence conversion or the continuous mode, the rate at which data are produced is given by the selected ADC clock and prescaler (ADC_CFGR2.CKMODE/ADC_CCR.PRESC and in case of asynchronous clock, also RCC_CCIPR.ADCSEL), selected sampling time(s) (ADC_SMPR), duration of conversion itself - which in turn is dependent on the conversion resolution (ADC_CFGR1.RES), and oversampling, if enabled (ADC_CFGR2.OVSE/OVSR, taking in consideration possibility of triggered oversampling, ADC_CFGR2.TOVS).1
Fairly often, users push this rate towards the maximum allowed by the related settings (and datasheet), which is usually in the few MHz range. It means, that in case of such automatic successive conversions, at a typical 25-100MHz system clock, there is one ADC sample produced per a few dozens of system clock.
Given that both interrupt prologue and epilogue in Cortex-M processors takes around a dozen of cycles, if ADC is read out by interrupts, in such setting, the system is saturated by interrupts, and the ISR may miss ADC conversions, resulting in confusing ADC readouts. This is especially so if Cube/HAL is used, due to its convoluted interrupt handling.2
In some STM32, there is a ADC_CFGR1.WAIT bit, which disables automatic conversion start until the previous result is read from ADC_DR. This alleviates the above problem, but then may result in irregular conversion rate, which may also be a problem in some sort of applications.