Showing results for 
Search instead for 
Did you mean: 

ADC noise on stm32f401

Associate III

I've been messing around with a LMT86 temperature sensor

This sensor is deemed high output impedance as the documented loads it drives is 50uA.

ADC noise on STM32 isn't 'new'. Just that for a first time I'm observing such volatility up close. The problem is mere millivolts differences means a different temperature reading from the sensor, and accordingly there is already a sort of 'amplification' from the sensor itself.

Threads found from a Google search are like such.

It is explored in a thread discussing the temperature sensor here:

Among the discussions is that given this is a high impedance source, an Op-Amp is needed to buffer inputs to the ADC.

So next I strapped up an LMV358 Op-Amp as a buffer and here are the observations. This is with the Op-Amp

common parameters for charts below: adc clock 84 mhz / 4 ~ 21 mhz, 84 clocks sample time

2000 samples, 10 samples/s, measuring room temperature about 30.5-31 deg C

0693W00000Dnmj4QAB.pngcount   2000.000000

mean      30.882000

std        6.782125

min     -213.360000

median  30.960000

max       57.800000

No, temperature did not accidentally drop to near absolute zero. It is room temperature all the while during measurement, a multimeter did not change a single millivolt while variances are recorded by the ADC.

Next, I set up a filter to remove all values outside +/- 2 deg C from the median, 555 outlier values removed.

0693W00000DnmjsQAB.pngcount   1445.000000

mean      30.973156

std        0.733296

min       29.030000

median  30.890000

max       32.950000

Next remove that Op Amp and connect the sensor LMT86 directly to the ADC (on stm32f401)

2000 samples, 10 samples/s, measuring room temperature about 30.5-31 deg C

0693W00000DnmlPQAR.pngcount   2000.000000

mean      30.930100

std        4.062343

min        3.670000

median 30.810000

max       59.260000

Next, I set up a filter to remove all values outside +/- 2 deg C from the median, 500 outlier values removed.

 0693W00000DnmmwQAB.pngcount   1500.000000

mean      30.817787

std        0.698166

min       28.810000

median  30.810000

max       32.800000

It is a dilemma kind of. The Op-Amp probably reduce the impedance (significantly?), but that the errors/variance are about the same !

What is more concerning is the large outlier values as those are observed in the unfiltered input. This didn't seem to go away when the OpAmp is placed as a buffer between the sensor to stm32f401.

Associate III

Thanks @Georgy Moshkin​, I'd do a next test with batteries, that'd take some work. I'd think most of that 'noise' would disappear. That'd kind of verify the likeliness of the noise coming from the power supply (at the 5v USB VCC), or possibly induced A/C voltages etc. I've on occasions seen stm32 ADCs detect millivolts of A/C voltages. But I'd guess this is less likely to account for the rather large outliers.

It seemed for now STM32 is able to read that high impedance LMT86 temperature sensor with little issues, the test with and without an Op Amp in between apparently show a similar variance where the values go. I'd likely repeat the tests to verify it. (edit: the opamp, sensor, stm32 sits on the same 3.3v rail, I'd likely do a slightly different test as well by running the opamp and/or temperature sensor on batteries.)

But I'd think, the Op Amps would still be provision in the final design as this is going to be replaced with 100k thermistors. It is actually going to the 3d printer hot end and heated bed. My guess is if I can get issues with this semiconductor temperature sensor, using high resistance thermistors from 3.3v or 5v is likely to cause similar or worse troubles. This 'issue' is kind of interesting if you consider that many 3d printer boards in the wild are based off stm32, and I'd not be surprised if that 100k thermistor and a 4.7k as a resistor divider bridge is connected directly to stm32 ADC inputs and likely from the same 3.3v or 5v rails that power the stm32.

In terms of the 'input' tests, e.g. replacing the temperature sensor with a battery. That is an interesting suggestion I'd test. I've kind of done similar but different tests by replacing the sensor with resistor dividers (actually potentiometers). And I literally observed variances measuring 'resistor dividers'.

The battery test would be good as if 'variances' are observed, it likely point to noise possibly coming from VREF+/VREF- etc.

Initially, i kind of inferred from the 'resistor divider' tests that between a 50k resistor divider vs a 5k resistor divider, that the 5k resistor divider shows a smaller variance. And initially I thought it is simply due to impedance and that an Op-Amp would make a difference.

Thus far, the most significant difference alone is found from use of the rather large 220 uF bypass capacitor at the 5v or 3.3v rails. That alone actually reduced the variance of the values sampled, and it significantly reduced the number of outliers sampled on my board. I'd guess that in part, as on my board, VREF+ is tied to VDD and VREF- is tied to GND. So I'd guess noise are in part transmitted from there. And in other cases the LDO is possibly inadequate.

Associate III

I've done a little different experiment, I turned the stm32f401 into a little 'oscilloscope', here is what is seen at PA0 ADC1, the temperature sensor LMT86 is connected there.

This is at 1 k samples per sec. scaled at 0.1 xdiv (so 10 is actually 1 second).

STM32F401 is running at 72 MHz, ADC clock = 72 / 2 = 36 MHz.

Sample time is 3 clocks for these charts.

0693W00000F9vAfQAJ.pngThe axis seemed to be obscured when zoomed in, it may be necessary to download and view it.

1.77-1-8V is the voltages from LMT86. What is more interesting are the spikes, they seemed rather irregular and quite large, the large ones seemed to be around 0.3 v.

It seemed there is no observable periodic A/C signals, as A/C signals are around 50/60 Hz, they should be rather visible if they are present.

Another view at 10 kHz. xdiv is 0.01 so 10 on x-axis is 0.1 of a sec.

0693W00000F9vEXQAZ.pngAnother view at 100 kHz. xdiv is 0.001, so each unit is a millisecond


Associate III

The above 'scope' charts seem to suggest why, apparently, that 'median' filtering seemed to work. The sensor voltages is concentrated in a narrow band.

I'd continue to work the tests to see if those (noise/spikes) could be identified to particular sources. Prior to this, as I used rather low sample rates, I'd guess it is a reason sometimes I do not encounter the spikes and the readings fall within range. But given the spikes, and a rather long sample time of 84 clocks, if a spike occur, it may change the sampled voltages in the ADC.

Note that the 220 uF capacitor is connected at 3.3v rail for these 'oscilloscope' charts.

It seemed this may be affected by impedance issues, 3 clocks at 36mhz is a pretty short sample time. And the LMT86 has a 50 uA max output.

It seemed as a wild possibility, that these could be radio waves. There is a wire/cord connecting the temperature sensor (probe) of about 70 cm. That works out to be around 420 MHz for full wavelength. Well, but for now it is a wild guess.


I placed that LMV358 in the path as a buffer, full negative feedback, so gain = 1. This should work like a low pass filter with cut-off at about 1 MHz (in spec). Then I do that ADC 'scope' again.

500 k samples per sec, I chanced upon this. It doesn't always look like this, it so happen to be one of a random capture. Note this is the output from the Op Amp with the sensor + cable as input.

0693W00000F9vlWQAR.pngMore often it looks like this (300 k samples per sec)


I could nearly imagine, if I put a diode and a capacitor in the former, I'd probably hear some sounds. It seemed there is a possibility it is after all radio waves.

The 220 uF bypass cap is still connected at 3.3v to GND.

I have the exact same board, let me know what pin you configured as ADC input and I'll do a quick test.

Are you transferring those graphs from MCU while sampling? It can be source of noise.

Thanks @Georgy Moshkin​, the 'scope' graphs is a little app I created on stm32f401 that capture ADC samples from PA0 ADC1. It records 1200 samples in a buffer at a time using DMA and send them (the buffer) across after the capture. Capture is initiated with a single char command received from the host, During capture nothing is transmitted. This is configured to run at 72 MHz / 2 = 36 MHz ADC clock speeds. Sample time is 3 clocks per sec, so adding another 12 clocks for the conversion time, it is 15 clocks which gives a max sample rate of 2.4 MHz sample rates. This is the fastest achievable on stm32f401 ADC.

As I need to move away from my desk for a while, here is a snapshot of the contraption I've setup for the experiment.

0693W00000F9zK1QAJ.jpgThe STM32F401CCU board and the SSD1306 is visible on the right. Those things on the breadboard are the LMV358 op amps (there are 2 sets of them, but only one of them is used currently). There is a capacitor overhanging that LMV358, that is the 220 uF capacitor connected across 3.3v power rail to ground.

3.3v Power is currently drawn from the LDO on the STM32F401CCU board, that is supplying all the components seen in the experiment.

This includes the stm32f401 MCU itself (its VREF+ goes to VDD, VREF- goes to GND as seen in a schematic for the board). This same 3.3v LDO on the board powers the

  • LMT86 temperature sensor (accordingly, this only draws micro Amps)
  • LMV358 op amp
  • STM32F401ccu
  • SSD1306 LCD

On the left of the breadboard is a breadboard power supply that can be powered from a 5v USB mobile charger, it has 5v - 3.3v LDO on board. In this experiment, that external power supply is currently unused.

The 'transistor' in the bottom right in the foreground is the LMT86 temperature sensor. I connect it to the ADC over long wires (the cord) as this is intended to be used as a probe to calibrate thermistors with unknown parameters.

My guess is with the long wires, I've accidentally made this an antenna and that LMT86 is a diode kind of, and with amplification internally. That may have accidentally turned this setup into a radio, a simple diode detector. And what is seen at the STM32 ADC may be the AM demodulated signals.

If this is true, it probably explains the large volatility, variance seen in what is assumed to be a static voltage from the 'temperature sensor'.

Associate III

Here is an update, I patched a LMT86 directly on the breadboard - no long wires / no cords / no op amps etc.

2000 samples, LMT86 direct to STM32F401 ADC PA0


LMT86 direct to STM32F401 ADC PA0 discarding 122 values outside 0.5 deg C range from median, this is barely around 5% of 2000 samples.

0693W00000FA8jbQAD.pngcount   1878.000000

mean      31.195000

std        0.162021

min       30.740000

25%       31.110000

median   31.180000

75%       31.330000

max       31.620000

This result is astonishing, standard deviation is 0.162 deg C. 95% confidence interval is 1.959 sigma ~ 0.31736.

Now LMT86 measured on stm32f401 ADC pa0 is +/- 0.31736 deg C accurate at 95% confidence interval.

Then taking the full 0.5 deg C interval, that is 3.08 sigma, that is > 99.8% (accurate) confidence interval

LMT86 is an accurate device, and it meets the specs published by TI, when a near noiseless measurement on stm32f401 ADC is possible.

The histogram is showing bars for temperatures well within 0.1 of a degree C. And I'm using only 12 bins for 2000 samples.

Working this back to the specs for LMT86, it is -10.9 mV average gain per deg C.

This translates to a +/-3.46 mV accuracy measured on STM32F401 ADC at 95% confidence interval.

And at 0.5 deg C at 3.08 sigma (> 99.8% confidence interval) it is +/- 5.45 mV at pretty much > 99.8% confidence interval measured on stm32f401 ADC.

Measurements are still stochastic, as I can observe varying numbers with each sample. But the samples and mean conforms well to a bell curve (normal distribution), after dropping the *outliers*.

Still can't rule out radio interference etc as noise sources which probably cause the variations and especially the outliers.

The data analysis looks like such

each line of these is the Anderson–Darling statistics

This analysis is done by rejecting values outside a tolerance starting with 2 deg C and reducing it.

The Anderson–Darling statistic reduces to the smallest and finally increase, showing a poorer fit as tolerance is narrowed.

Now the tightest fit to normal distribution is 0.5 deg C at 99.8% confidence interval

n = 2000, lmt86 direct - no cord
no filter
145.97371710597236 [0.575 0.655 0.785 0.916 1.09 ] [15. 10.  5.  2.5 1. ]
tol = 2 del 13
95.23121766618078 [0.575 0.655 0.785 0.916 1.09 ] [15. 10.  5.  2.5 1. ]
tol = 1.5 del 29
59.96725246650158 [0.575 0.655 0.785 0.916 1.09 ] [15. 10.  5.  2.5 1. ]
tol = 1 del 56
33.59035490934821 [0.575 0.655 0.785 0.916 1.09 ] [15. 10.  5.  2.5 1. ]
tol = 0.5 del 122
20.692436455313555 [0.575 0.655 0.785 0.916 1.09 ] [15. 10.  5.  2.5 1. ]
count   1878.000000
mean      31.195000
std        0.162021
min       30.740000
25%       31.110000
median   31.180000
75%       31.330000
max       31.620000
tol = 0.3 del 197
22.802556095985665 [0.575 0.655 0.785 0.916 1.09 ] [15. 10.  5.  2.5 1. ]

This kind of also confirms the 'radio waves' interference hypothesis, that those outliers, and variances are due to interferences from radio waves.

But that'd need 1 more set of 'scope' charts, to verify it.

Associate III

And one more round of checks on the 'scope' graphs. LMT86 patched directly on the breadboard - no long wires / no cords / no op amps etc.

10k samples per sec STM32F401 ADC PA0

0693W00000FA98nQAD.png100k samples per sec

0693W00000FA99HQAT.png500k samples per sec0693W00000FA99MQAT.png 

There are still some visible artefacts, but that the amplitudes are much smaller.

This basically confirms the 'radio waves' interference hypothesis