After reviewing the Firmware source files. It appears the ADC sampling time is set too fast, as I expected based on my testing observations.
Based on the datasheet:
The ADC_SAMPLING_TIME is set to Ts = 1.5 cycles and should probably be something more like 13.5 to 41.5. Looks like it was originally set to 239.5 but was found to take too long and was cranked full tilt in the opposite direction. https://github.com/spark/core-firmware/blob/master/inc/spark_wiring.h#L118
And because of this, any input impedance over 600 ohms is going to result in the ADC’s sample and hold capacitor not reaching a full charge. This should mean the readings always come in too low, but regardless it’s probably not a good idea to require such a low input impedance.
Most PIC uC’s have an input impedance requirement of max 10k ohms.
I would think 10k to 50k is probably a good range, lower would be faster conversion times. Higher would allow more flexibility at the expense of conversion time.
Thanks @BDub. Outstanding work. As always, we remain super appreciative! I’ve added this to our backlog. If anyone needs this immediately, pull requests are welcome!
@Hypnopompia I didn’t have the time, so I’m glad you tried this. There are actually a bunch of different parameters in the ADC setup to check. Especially the one that self calibrates the ADC the very first time analogRead() is called after reset. I don’t know anything about it, and the 100 page datasheet is pretty lacking on setup details… I’m hoping there is another super sized data sheet with all of that information, but I didn’t easily find it on ST’s website earlier.
I managed to get normal reading by putting a 10K resistor between pin A0 and GRD. It seems the TMP36 Vout (pin2) needs a small current to work. My voltage meter was enough to drop the value enough to “normal reading”. You can also try to keep the meter connected and see what the pin A0 results give you.
That’s really strange that it would need a 10k resistor, nowhere in the data sheet does it talk about that. It does say the TMP36’s output is low impedance, so it’s not like it’s floating around until terminated. It’s actively driven, but it’s not out of the question that it could potentially oscillate without a load… even linear voltage regulators can do that.
What happens if you put the 10k resistor from pin 2 of the TMP36 to GND? If your connection between pin 2 and A0 is a short jumper wire like in the spark example wiring image, don’t bother… but if it’s a long jumper wire it might have some effect. This is to see if the 10k is acting like a transmission line termination.
I’ve been using an analog thermistor instead of the TMP* series. I finally decided to try it on an Arduino Nano and am getting temperatures in the same range between both the Spark Core and Arduino Nano, so I think it’s just a margin-of-error sort of thing.
I did try to set my own ADC_SAMPLE_TIME (see this gist), but all it seemed to do was slow down the readings a little bit and make them fluctuate less.
When in doubt, sprinkle caps everywhere! One 0.1uF across the V+ and GND of the TMP36, and one directly from A0 to GND. In general, breadboards are pretty noisy for circuit prototyping. Tightening up the wiring on a perfboard should also help.
I really don’t think the readings should bounce around that much, especially in the case where you set up a reference voltage on A0 with a 10k/10k resistor divider.
It also might be worth a try to set up a low pass filter on the A0 input using a 10k ohm resistor between TMP36 pin 2 and A0 (instead of the jumper wire), and a 0.1uf capacitor between A0 and GND.
Figuring more data might be helpful here’s the results of my similar experimentation using the TMP36. As background, I have a 0.1uF decoupling cap across pins 1&3 of the TMP36 and have modified the sketch so I take 100 readings and average them before reporting them as a variable via the cloud. In all cases I’m monitoring the voltage of the 3.3v pin and it runs around 3.28v.
Case 1: Multimeter reading of the TMP36 output voltage without it being hooked to the Core – I get 0.718 volts which works out to be 21.8 degrees C, probably close to ambient in my dining room
Case 2: Multimeter reading of the TMP36 output voltage with it also being hooked to Core pin A0 – I still get 0.718 volts. So far, so good
Case 3: Analog reading from Core pin A0 via my sketch with the multimeter still connected to the TMP36 – The multimeter still says 0.718 volts but the sketch reports the average sensor reading to be 990, which works out to be .793 volts. Strange that the Core analog input sees a significantly higher voltage than the multimeter so something is awry. (I suppose it might be related to the sampling interval @BDub reported.)
Case 4: Analog reading from Core pin A0 via my sketch with the multimeter disconnected – The sketch reports the average sensor reading to be 1128, which works out to be .904 volts. This is much higher than the actual TMP36 output voltage and if converted to temperature would be just over 40 degrees C. Certainly not ambient temperature in my dining room. Alas, I can’t say what the TMP36 is actually reporting given the multimeter is disconnected in this case.
Clearly there are two problems here – the Core isn’t accurately reporting the TMP36 voltage in the case where I can compare it to the multimeter (Case 3), and without the multimeter the value is even more in error (Case 4).
Try putting a high value resistor between A0 and GND, then do some readings. Your DMM acts like a very high impedance path to ground, which is why the ADC is more accurate with it connected.
Was having the same issue of wildly swinging values reading TMP36 from A4. Fixed it with a 0.1uF cap.
See before and after images for data collected at A4 attached to TMP36. “Before” is without a 0.1uF cap from A4 to GND - values swinging wildly in a range of 19c to 27c. With a cap everything smooths out. The “before” picture reminds me of line noise seen on my scope, a common issue when building stuff on a breadboard.
Yep. Adding a .1uf cap between the analog input and GND produces the best results for me. Consistent, accurate readings from the TMP36 now. (Also @americanmcgee, I’m totally geeking out by your participation here. I’ve been a fan of your work for a long time.)
Reading Count: 360
A0 Reading
Current : 874
Average : 872
Min : 857
Max : 881
Delta : 24
Voltage
Current : 0.700V
Average : 0.698V
Min : 0.686V
Max : 0.706V
Delta : 0.02V
Temperature
Current : 20.00°C / 68.00°F
Average : 19.80°C / 67.64°F
Min : 18.60°C / 65.48°F
Max : 20.60°C / 69.08°F
Delta : 2°C / 3.6°F
Yep. Putting a 0.1uf cap between A0 and GND results in A0 readings that match what my voltmeter shows on pin 2 of the TMP36 and result in calculated temperature values that make sense (e.g., 70.2°F at my workbench). I’m already reporting the average reading across 100 points but will modify my sketch to track max/min as @Hypnopompia has done.
I generally use decoupling caps for power rails, will make it a point to start using them on analog voltage inputs too…
The TMP36 datasheet mentions a couple of interesting facts:
The max output current is 50uA. (In other words, a piddly amount.)
A load capacitance can cause the output to oscillate. While there is no max load cap specified, a “typical” supported value (no oscillation) appears to be 0.01uF. A 0.1uF cap might cause the output to oscillate (although it seems to work fine for some people, there’s no guarantee that this will work for everyone).
Without the cap, it’s not surprising that the ADC is getting screwy values. Looking at the TMP35 output voltage: glitch (Sorry, I appear to be too new to post inline images.) Picture with markers here.
Good catch on the 0.1uF. I guess we should push a value no higher than 0.01uF. I ordered one of these sensors last night just so I can play along
50uA max output current is sort of not really an issue though. While it’s not much drive, there is nothing to drive really. If you create a resistor divider to convert C to F in hardware, they seem to size it to draw about 31uA in the datasheet app note. Lots of other temp sensors have a weak output as well… but this can be affected by noise, EMI, ground bounce, etc… we are operating on a breadboard with a wifi transceiver right next to it! Going to need decoupling caps, and shielding with sensors … or get sensors that have more drive, like a 10k NTC thermistor in series with another 10k 1% resistor, and a cap on the analog input to ground. The resistors here won’t be the reason this helps though, read on.
The glitch is most likely the Wifi burst transmission coupling into the wiring. You can see the glitch occurring every 2.5ms or so. Not sure if that if that timing seems significant to the Spark Team or not. It doesn’t look like the Analog input is being turned into an high output for a cycle either (could maybe be a pull up for one cycle… maaaaybe). 10k ohm load to ground on the analog input still allows the voltage to spike up to 400mV, decaying to 0mV in about 1us. I’m also seeing a 200mV spike still with a 325 ohm load, albeit a much shorter decay. 0.1uF cap on A0 to GND seems to kill the glitch at both 10k and 325 ohm though.
I tried using the Spark.sleep(5); function to see if turning off wifi helped, and it does seem to make the glitch go away when it sleeps, but when it comes back online there is no glitch. However, the core does seem to be executing my code either… Serial1 stops, no D7 output toggling every 5 seconds. But I have a Cyan breathing light. I hacked up my Temperature Dilution Filter routine for this: http://pastebin.com/raw.php?i=VdeuE3nT so don’t look at this code too hard
While I’d certainly expect wifi coupling to be an issue, the shape of the glitch doesn’t look like what I’d expect that to be. However, I’m not familiar with wifi, and especially the shape of the transmission envelope.
The STM32F103 docs talk about effective max input resistance for the ADC (see section, “5.3.18 12-bit ADC characteristics”). However, I don’t have the time to figure out the ADC settings used by spark, and so I have no idea if the TMP36 meets the requirements for the settings. I wish I had something like a 741 laying around, because buffering the output of the TMP36 might be an interesting test.
However, the wifi theory is probably the likeliest.
If you have a Rigol DS1052E like me, it's only a 50MHz scope... and anything near 25MHz starts to get a little round. It doesn't come with the best probes in the world either. Wifi is up at 2.4GHz, so you're not going to see much of anything besides power capacitively coupling into your wiring. I could be wrong... it's a daily truth that I accept and learn from, but it's my best guess at this point.
For the ADC setup, please see a little analysis here from above. I don't believe I saw a hard spec of ADC has xx impedance like some micros... more like it has really high impedance 150k ohms or so, and you can set the effective impedance through the sample rate:
So I finally collected enough data to visualise and I’m still seeing massive variation on readings. The graph below shows readings over nearly 24 hours and whilst the trend is correct it’s measuring 2-3 degrees above what I’d expect (this is probably easily explained) however its’s the odd variations that are puzzling me…
Adding capacitance to the analog input is not the right answer because unless your also adding some significant resistor ahead of the cap to create a low pass filter in hardware… the cap is doing basically nothing except filtering some very high frequency (and low in power) noise that you wouldn’t see in your ADC reading anyways. 50uA drive current is fine using the highest sampling speed of the ADC as long as your aren’t adding additional resistance in the analog connection between the sensor and A0.
Having the RF couple back in to the analog circuit is possible… but unlikely to cause this much of a deviation in the reading. The coupling would have to be severe and there’s just not enough power there to make a difference.
The problem is most likely ground bounce when the CC3000 turns on its transmitter and starts drawing 150mA of current for a fraction of a second at the same time your sampling the analog value.
The spark core makes an attempt at providing a filtered VDDA, but does not isolate (filter) the digital ground from the analog ground. This is also highly dependent on how the board is layed out, where the high current path to and from the CC3000 is routed in relation to VSSA, etc - the schematic calls out no special handling for VSSA - its just tied to GND. (To be fair, I did not actually look at the gerbers to tell if analog ground routing was taken into consideration or not)
The decoupling capacitor on VDDA is also too large (C13), ST recommends a 10nF cap in addition to your bulk capacitance. Unless you are using a really expensive ultra low ESR 100nF cap for C13, I would change to the 10nF to improve your analog noise floor.
To test for ground bounce on VSSA, solder a jumper wire as close to VSSA is possible (STM32 Pin 8) and put on a scope probe with its GND reference connected near your temperature sensor. I bet you’ll find a 100mV or so bounce every so often with the wifi on.