ADC: single, continuous and timer-synchronised sampling
STM32 ADC conversion modes, sampling time, scanning several channels, and sampling at an exact period with a timer trigger.
Conversion modes
| Mode | Behaviour | Use |
|---|---|---|
| Single conversion | Once, when commanded | A battery voltage read now and then |
| Continuous conversion | Starts again as soon as it finishes | Fast continuous monitoring |
| Scan | Several channels in turn | Several sensors |
| External trigger | On every timer event | Fixed-period sampling for control |
| Injected channels | Cut into the regular conversion and convert first | Motor phase currents |
Sampling time
For each channel you set the number of sampling cycles (3, 15, 28, 56 … 480). Use a longer time when the source impedance is high. Conversion time = sampling cycles + 12 cycles (12-bit).
Timer trigger
TIM1 PWM centre → TRGO → ADC injected conversion → FOC calculation in the completion interrupt
In motor control the phase current has to be sampled at a fixed instant of the PWM period (the centre, while the low side is on) to avoid switching noise. The key is doing this synchronisation in hardware.
Improving accuracy
- Read the internal reference channel (VREFINT), calculate the real VDDA and correct for it
- Run the chip's calibration at start-up
- Read several times and average, or use hardware oversampling
Turning the number into a voltage
A 12-bit ADC gives a number from 0 to 4095.
voltage = ADC value × Vref / 4095
1 LSB = 3.3 V / 4096 ≈ 0.8 mV
uint32_t mv = (uint32_t)adc * 3300u / 4095u; // mV with integers
If you divide first, as in adc / 4095 * 3300, integer division makes the result almost always 0. Multiply first.
A short sampling time gives wrong values
Inside the ADC there is a small capacitor that charges to the input voltage during the sampling time. If the source resistance is high, the conversion starts before the capacitor is fully charged and the value comes out low.
| Source | What to do |
|---|---|
| Op-amp output, low resistance | A short sampling time is enough |
| Divider of tens of kΩ | Longer sampling time, add 100 nF at the input |
| Reading several channels in turn | Right after a channel change the value is pulled towards the previous channel. Lengthen the sampling time |
Three ways to read
- Polling: start a conversion and wait until it ends. For temperature or battery voltage read occasionally.
- Interrupt: when the conversion ends, the handler picks up the value.
- Timer trigger + DMA: a timer starts conversions at an exact period and DMA stacks the results in a buffer. For signal processing and motor control, where the period must be constant.
Motor current has to be measured in the middle of the PWM period to avoid switching noise, so the PWM timer is set up to trigger the ADC directly.
In a picture: sampling at the PWM centre
Reducing noise
- Averaging: add 16 readings and shift right by 4 bits for a simple average. The response gets slower.
- Input filter: an RC filter with a cut-off a little above the signal band.
- Reference voltage: if the 3.3 V supply is used directly as the reference, supply ripple becomes measurement error. Use a separate reference for precise measurements.
- Analog ground: keep the path of large currents apart from the path of the ADC signal.
Problems that come up in practice
- No calibration after power-up, leaving an offset
- The input exceeds Vref and the value sticks at 4095 (check the divider ratio)
- The internal temperature sensor and reference channels need a long sampling time but were read with the default