Analog pin outputs 1.7v when set to input?

Hi there!

I’m a little new to hardware and electronics so please bear with me.

I’m trying to make a very simple circuit - reading from a TMP36 into the Spark Core; the TMP36 works perfectly well with an Arduino in an identical circuit.

I tried the same deal with a Spark Core but the readings were off and I set out to debug it. I stuck a multimeter in and the readings were OK again. This is what we call in the software industry a “Heisenbug”. I believe that you in the hardware world call it “voodoo”.

I removed the temperature sensor entirely from the circuit and just tested the analog pin I was reading to ground - it read 1.7v. Since it was A0 I feared interference from the antennae and moved it ( and the analogRead and pinmode) to another A1, same thing on A1 , only now A0 tests 0v like it should be.

It looks like pinmode(INPUT) is rising the voltage level on that pin to 1.7 and that interferes with my sensor; am I doing anything wrong?

Nir.

Addendum: it seems to happen after the first analogRead()

Hi @TheNirEast! Sorry your having trouble with the TMP36. Try reading through this thread and see if you can find some improvement in your situation:

I did read through it - but even with the TMP36 completely removed I’m still having a weird experience.

I have a completely empty circuit. The only thing I have attached is a voltmeter between A1 and GND.

Below is the code in its entirety - it is a simple registration of an analogRead to a web function.

Upon core reset - the voltmeter reads 0.04v - which is close enough to 0 for me.

After the FIRST time I read the voltage using analogRead - the voltmeter spikes to 1.66v and stays there.

Is that the expected behavior? Why is analogRead changing the output voltage on an analog pin?

Nir.

int testpin = A1;

int testPin(String args) {
  return analogRead(testpin);
}

void setup() {
  pinMode(testpin, INPUT);
  Spark.function("test",testPin);
}

void loop() {

}

The first time you read an analog input, it configures the ADC and this is probably glitching the output. I would agree with you there might be a better way to set it up so that this does not happen. That’s something we should look at. That said, if you leave the input floating, it’s going to give you strange readings. Your voltmeter is also a very hi impedance load, so it won’t load the input in any way.

Also for analogRead() you don’t need to set the pinMode() to INPUT. This is probably what’s glitching the pin.

The ADC input on the STM32 ARM is a common type used today, but different from the ADC input on the ATmega328p used in Arduino UNO. The ADC input is a capacitor that is switched to be connected to your circuit on the IO pin when you ask for a measurement. This capacitor is pre-charged to 3.3V divided by 2 since that increases the rate at which measurements can be made by roughly a factor of two. Your external circuit either charges or discharges this capacitor for a period to set the voltage and then the switch to your circuit opens and further internal processing happens to get the actual reading. At the end of that time, the cap is charged back up 3.3V/2 for the next measurement.

1 Like

thank you @bko and @BDub - that leaves me confused though - are you saying that the simple fix for me would be to not use pinmode?

The readings are very much different from what I get both hooking the TMP36 directly to a multimeter and to GND (then I get the correct reading) or the arduino - so I’m not sure what I’m doing that I shouldn’t be doing, or what I am not doing that I should be :smile:

Hi @TheNirEast

You have to use set the pin to input, no way around that. And when you start an analogRead() the internal ADC is connected to that pin, so no way around that.

You can try @BDub 's favorite 0.01uF capacitor from the analog input to the core to ground. This has helped some folks.

You can try adding an op-amp to buffer the sensor from the pin. Arduino has this type of buffer built-in but sometimes you need it and sometimes your don’t, so for Spark you can provide it externally.

In a few days a software change will make it into the webIDE build code that will allow you to slow down the ADC rate and improve the performance with this type of sensor. That is somewhat experimental right now, but I have high hopes.

I like digital temperature sensors such as the DS18B20 series.

You don’t actually have to use pinMode(A0,INPUT); you only need to do the analogRead(A0);

http://docs.spark.io/#/firmware/i-o-analogread

https://github.com/spark/core-firmware/blob/master/src/spark_wiring.cpp#L371-L484

1 Like

It sounds like you could also just use INPUT_PULLDOWN, to connect your pin to an internal pulldown resistor, or would that be silly?

If you have an input, with nothing connected to it except for a (very) high-impedance voltmeter, the input is “floating” and the “voltage” there is undefined (well, it is, of course, determined by the internal circuitry connected to it, but it really needs to have something connected to it – something that provides a valid analog or digital output). However, in the case of spark, be aware that the ADC inputs have impedance specifications, which are timing-dependent – too high of an impedance, and the voltage readings will be off.

1 Like

Yep, silly… :wink: cuz the analogRead() function sets the input to pinMode(pin, AN_INPUT); no matter what you had it set to prior (unless it’s an I2C, SPI or SERIAL pin then it just bails out).

1 Like

You just need a capacitor and the TMP36 then works fine. Much of the other discussion here is perhaps important but also perhaps moot for your purposes. 0.01uF between ground and signal, preferably close to the TMP36, fixed it for me. In setup() I also read the TMP36 and discard - the first reading is often wrong. I strongly suspect that the capacitor will remain a good idea even after everything suggested here is implemented in the new firmware or by yourself. I also don’t explicitly set the pin as input but that’s because I think usually less code is more, not because I know anything :slight_smile:

@psb777 - so if I understand this correctly the capacitor should be placed in parallel to the signal like so?

> Signal ----------> pin
>             |
>           capacitor
>             |
>            GND

What I don’t understand is WHY that would work, and also why that would be required when on an Arduino it isn’t. But I’m a CS guy, not a EE, so expect quite a lot of stupidity on my part when it comes to all things wiring-y :smile:

That is topologically correct but best, I am told, is to connect the capacitor as close to the TMP36 as possible. Three leads on the TMP36, left is to the 3.3* pin, middle is to the analogRead pin, right is to ground. Connect cap tween middle and right. I believe the reason is that the cap averages out noise and you don’t want any noise induced in the perhaps not very short leads tween TMP36 and the Core. For me it was good enough that it just worked with the cap, and it didn’t without. I also adjusted my code to set the ref voltage to 3.28 not 3.3 and that made my TMP36 accurate to within a degree. Before that it seemed water boiled and froze 1 deg warmer in my house than elsewhere. But that is to be expected - the TMP36 is only accurate to 2 degs by spec over much of its range. I know you say it isn’t required on an Arduino but the TMP36 spec sheets mention the capacitor.

Though the capacitor does filter out noise, its function is more about impedance (frequency or time-domain dependent resistance) than noise reduction. The A/D in the Core uses a small internal capacitor to charge with the analog input in order to step-wise calculate the input voltage. This process is called successive approximation. This is done at a fixed, settable frequency and thus has the effect of creating an impedance at the input pin. If the source of the voltage, in this case the TMP36, affects this impedance, the measurements will be off. So adding the external capacitor “matches” the impedance so that the A/D can function correctly. BDub did a lot of great work on this in another topic. :smile:

1 Like

In addition to what @peekay123 said, you should also place the cap closer to the A/D input and GND of the Spark Core, for better noise immunity AND lowering the impedance of the input.

1 Like

Well I stuck a 10nf capacitor between GND and signal (which I believe is 0.01uf as recommended) and sadly, that seemed to make very little difference (in fact, it raised the reading somewhat).

Core is measuring about 0.96v when a voltmeter is measuring about 0.76v (sounds about right from a temperature standpoint)- so there is a fairly consistent 0.2v offset.

Also tried a pulldown 10k ohm resistor to GND which did very little as well.

In my case the issue isn’t variability - but that the offest that the ADC reads is consistently higher than what a volt meter reads.

I placed the capacitor, as described above, directly between the GND and the middle pin of the TMP36.

Any other suggestions are welcome - I’m at a loss now :smile:

Well, if it helps, this code works for me. I do not set the pinMode - apparently one shouldn’t/needn’t for analogRead - and I have the cap positioned perhaps not ideally. But within a degree for me:

(void)analogRead(tempPin); //discard 1st reading
delay(50);
int tempReading = analogRead(tempPin);

// Spark.io ref voltage is 3.3V (I've used 3.28) and A2D is 12bit
float voltage = (float)tempReading * 3.28 / 4096.0;

// TMP36 device: Converting from 10 mv per degree with 500 mV offset
float temperatureC = (voltage - 0.5) * 100.0; // TMP36

@psb777 sadly, no dice ; put the cap between gnd and signal, read twice and still it’s above the voltage it should be.

The first read comes out closer (about 0.78v) but after that it’s all screwy.

Reading GND gets me a 0, reading 3.3v gets me 4095 as expected - reading what should be 0.75v gets me a value of 1194 which is - unless I have the mother of all brain farts - 0.97v