If I drive an analog input from a high-impedance source, I expect it to be accurate but slow. That’s not what I’m seeing.
If I connect only a 100K resistor to ground, I expect the ADC value read to be 0 (or close to it). I’m seeing 821. If I connect the 100K resistor to 3V3*, I see 3273, not 4095. Similarly, 1M down and up gives 2035 and 2197, and 10K down and up read out as 117 and 3966. It seems as if a STM32 analog input pin has the Thevenin circuit of a 149K resistor connected to a 1.65V source when I do an analogRead(). If I replace the resistor with a 0.1uf cap, it charges to 1.65V with about a 6ms time constant.
Digging a little deeper, after reset, there is essentially no load on pins set to INPUT. (My voltmeter reads 0.000 volts.) After the first analogRead(), it jumps up as if driven by 149K and 1.65V. The specific call within analogRead() where the loading begins is “ADC_SoftwareStartConvCmd(ADC1, ENABLE);”. The loading persists after I stop calling analogRead(). Indeed, after switching the pin mode to OUTPUT and driving high or low, and then back to INPUT, the loading resumes. Only if I call ADC_Cmd(ADC1, DISABLE) does the loading disappear. So it would seem to be something in the ADC circuitry that is gated by the ADC enable bit.
My (imperfect) understanding of the ADC input is that it should appear as a ~4pf capacitor behind a 16-21K resistor (Rain = 15K, Radc = 1.5-6K). The spec mentions no DC issues (e.g., input bias current). Nonetheless, I see it being pulled to the midpoint between 3V3* and ground.
This loading makes the ADC useless for sensing high-impedance sources (e.g., thermistors), and is different from any other analog input I’ve ever seen. I must be missing something simple. Any ideas?
My circuit couldn’t be much simpler:
PIN A7 --- 100K --- Gnd
My code is simple as well:
void setup()
{
pinMode(A7, INPUT);
analogRead(A7); // After this executes, pin A7 is pulled
} // towards 3V3* / 2 by 149K
void loop()
{
return;
}