gstreeter
Posts: 106
Joined: Sun Sep 02, 2012 11:11 am
Location: UK

Gertboard ADC with TMP036

Sat Feb 02, 2013 4:13 pm

or "Why Is My Gertboard Too Cold?"

As a starting project for my new Gertboard I thought I'd connect the on-board MCP3002 analogue to digital convertor to the TMP036 temperature sensor that came with my Arduino kit. Easy or so I thought as the TMP036 is 3.3v compatible and outputs a voltage that is directly proportional to the temperature at 10mV/C and a fixed offset of 500mV for 0C. Just connect the ground/power and then the output directly to one of the ADC inputs. A quick bit of maths and we have the temperature. All works ok except... it's consistently below the actual temperature as measured by several independent sensors. Faulty sensor? Low accuracy? No... it's a little more subtle.

Using a DVM I can see the TMP036 output at 720mV which is the expected value for the temperature of the room (22C). However as soon as the ADC starts a conversion the output falls to 680mV which gives a temperature of 18C, far too low. Once the conversion is over the output voltage rises again. This gave me an idea as to what's happening.

The ADC chip uses an internal capacitor to sample and hold the input voltage. As the ADC performs a conversion it connects an internal switch to allow the capacitor to charge up from the input source. The capacitor needs current to charge up and this is where the issue occurs. A check of the TMP036 data sheet shows it can only output a maximum of 50uA which is a pretty small current. Indeed it's so small that the TMP036 is overloaded by the current demand when the ADC connects the capacitor and this causes the TMP036 output voltage to drop giving the under-reading. It may also be that the sample period is too small to allow the capacitor to fully charge with the limited current.

The solution was to use an LM358 op-amp as a voltage follower to buffer the TMP036 output for the Gertboard ADC chip. By connecting the TMP036 output to the (+) input of the op-amp and the (-) input of the op-amp to the op-amp output it creates a unity gain amplifier that means the output voltage exactly follows the input voltage. The op-amp output is then connected to the Gertboard ADC input. Using this method the TMP036 output voltage stays at the correct value and so does the op-amp output sent to the ADC. I now have the correct temperature readings being returned.

The op-amp has a very high input impedance (resistance) and thus needs very little current from the TMP036 and does not therefore cause its voltage to drop. The op-amp can output 20mA and thus has more than enough current to charge the ADC sampling capacitor. If you need to use the Gertboard ADC with a low current source such as the TMP036 then this is the approach to take.

I've included a Fritzing diagram and the C code for the test based on the atod.c from the Gertboard sample library.

Code: Select all

#include <stdlib.h>
#include "gb_common.h"
#include "gb_spi.h"

// For A to D we only need the SPI bus and SPI chip select A
void setup_gpio()
{
   INP_GPIO(8);  SET_GPIO_ALT(8,0);
   INP_GPIO(9);  SET_GPIO_ALT(9,0);
   INP_GPIO(10); SET_GPIO_ALT(10,0);
   INP_GPIO(11); SET_GPIO_ALT(11,0);
} // setup_gpio


//
//  Read TMP036 temperature via ADC input 0/1
//
int main(int argc, char* argv[])
{
  int r, v;
  int chan = -1;
  double vref = 3.3;
  double temp = 0.0;
  double volts = 0.0;
  
  if (argc < 2 || argc > 3) {
    printf("usage: tmp036 channel [Vcc]\n");
    exit(-1);
  }

  chan = atoi(argv[1]);
  printf("Channel = %d\n", chan);

  if (chan < 0 || chan > 1) {
    printf("Channel must be 0 or 1\n");
    exit(1);
  }

  if (argc == 3) {
    vref = atof(argv[2]);
  }

  printf("Vref = %f\n", vref);

  // Map the I/O sections
  printf("Setup IO\n");
  setup_io();

  // activate SPI bus pins
  printf("Setup GPIO\n");
  setup_gpio();

  // Setup SPI bus
  printf("Setup SPI\n");
  setup_spi();

  for (r=0; r<100000; r++)
  {
    v = read_adc(chan);
    // V should be in range 0-1023

    volts = (vref * (double)v / 1023.0) * 1000.0;
    temp = ((vref * (double)v / 1023.0) - 0.5) * 100.0;  // TMP036 has 500mV offset

    printf("%04d\t", v);
    printf("%4.2f mV\t", volts);
    printf("%4.2f C", temp);

    putchar(0x0D); // go to start of the line
    short_wait();
  } // repeated read

  printf("\n");
  restore_io();
} // main
Attachments
tmp036-opamp_bb.png
tmp036-opamp_bb.png (61.41 KiB) Viewed 5808 times
Last edited by gstreeter on Wed Mar 06, 2013 12:59 pm, edited 3 times in total.

User avatar
Gert van Loo
Posts: 2486
Joined: Tue Aug 02, 2011 7:27 am
Contact: Website

Re: Gertboard ADC with TMP036

Sat Feb 02, 2013 4:59 pm

Thee was a thread somewhere else about the same issue.
There I suggested a different (cheaper-but-not-as-good) solution as the user wanted to read the sensor only once every few seconds.
Add bigger capacitor to the output. The temperature sensor has 2-3 seconds to fill the big capacitor. Then when the ADC opens
its port 99% of the energy is draw from the big capacitor into the ADC input capacitor.
Result should be very good but I did not try it.

User avatar
alexeames
Forum Moderator
Forum Moderator
Posts: 2869
Joined: Sat Mar 03, 2012 11:57 am
Location: UK
Contact: Website

Re: Gertboard ADC with TMP036

Sat Feb 02, 2013 5:13 pm

I was just wondering if a capacitor on the sensor output would work too. :D
Alex Eames RasPi.TV, RasP.iO

gstreeter
Posts: 106
Joined: Sun Sep 02, 2012 11:11 am
Location: UK

Re: Gertboard ADC with TMP036

Sat Feb 02, 2013 5:15 pm

Hi Gert,

I had a look for TMP036 on the forum but must have missed the thread you have referred to. The LM358 is 38p per unit (dual amp chip too) from the supplier I use (Hobbytronics) so I classify this as a reasonably cheap solution too :-) Also got to use an op-amp for the first time after reading about them. I used to dismiss it as inaccuracy, Vcc drift etc.

Gary
Last edited by gstreeter on Wed Mar 06, 2013 1:00 pm, edited 1 time in total.

User avatar
alexeames
Forum Moderator
Forum Moderator
Posts: 2869
Joined: Sat Mar 03, 2012 11:57 am
Location: UK
Contact: Website

Re: Gertboard ADC with TMP036

Sat Feb 02, 2013 5:36 pm

gstreeter wrote:Hi Gert,

I had a look for TMP036 on the forum but must have missed the thread you have referred to. The LM358 is 38p per unit (dual amp chip too) from the supplier I use (Hobbytronics) so I classify this as a reasonably cheap solution too :-) Also got to use an op-amp for the first time after reading about them. Pity the Arduino kit from Sparkfun doesn't mention this issue in their TMP036 example as the same thing happens with the ATmega ADC and I used to dismiss it as inaccuracy, Vcc drift etc. An exercise for the reader!

Gary
I had put it down to inaccuracy too and compensated in software. An op-amp must surely give better overall accuracy. I don't know C, but it looks as if you're only waiting a "short wait" between readings. How long is that? Does the problem reduce if you wait a few seconds between readings or is it the same?
Alex Eames RasPi.TV, RasP.iO

gstreeter
Posts: 106
Joined: Sun Sep 02, 2012 11:11 am
Location: UK

Re: Gertboard ADC with TMP036

Sat Feb 02, 2013 6:40 pm

Hi Alex,

Away from home ATM but will try out the long delay and let you know the outcome when I get back.

Gary

gstreeter
Posts: 106
Joined: Sun Sep 02, 2012 11:11 am
Location: UK

Re: Gertboard ADC with TMP036

Sun Feb 03, 2013 7:39 pm

I tried the sampling at maximum speed with no delay and then with several seconds between samples using the direct TMP036 to ADC connection. The result was the same under-reading no matter the sample period. I tried Gert's solution with a capacitor and even a 0.1uF decoupling capacitor brought the value up to the expected reading.

I've attached the updated code that loops continously until ctrl-C is used to halt it. The program takes 3 parameters:

sudo ./tmp036 channel [delay] [vcc]
  • channel: ADC channel 0/1
    delay: optional delay between samples in seconds, accepts decimals e.g. 0.5. Defaults to 1s.
    vcc: optional positive voltage rail level of your Gertboard provided to your ADC which is used as the reference for comparision. Defaults to 3.3v.
My Vcc is sightly higher than 3.3v at 3.325v and this makes a difference to the TMP036 reading as it's sensitive to small differences in the voltage as it's calibrated at 10mV/C.

e.g. to sample channel 0 every 1/2 second with a 3.325v reference use: sudo ./tmp036 0 0.5 3.325

Code: Select all

#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include "gb_common.h"
#include "gb_spi.h"

// For A to D we only need the SPI bus and SPI chip select A
void setup_gpio()
{
   INP_GPIO(8);  SET_GPIO_ALT(8,0);
   INP_GPIO(9);  SET_GPIO_ALT(9,0);
   INP_GPIO(10); SET_GPIO_ALT(10,0);
   INP_GPIO(11); SET_GPIO_ALT(11,0);
} // setup_gpio

// Catch ctrl-c to kill program but run restore_io() first
void int_handler(int sig) {
  restore_io;
  printf("Restore IO\n");
  exit(0);
}

//
//  Read TMP036 temperature via ADC input 0 
//
int main(int argc, char* argv[])
{
  int r, v;
  int chan = -1;
  int delay = 1000000;
  double vref = 3.3;
  double temp = 0.0;
  double volts = 0.0;

  signal(SIGINT, int_handler); // Handler for ctrl-C
  
  if (argc < 2 || argc > 4) {
    printf("usage: tmp036 channel [delay] [Vcc]\n");
    exit(-1);
  }

  chan = atoi(argv[1]);
  printf("Channel = %d\n", chan);

  if (chan < 0 || chan > 1) {
    printf("Channel must be 0 or 1\n");
    exit(1);
  }

  if (argc > 2) {
    delay = 1000000.0 * atof(argv[2]);
  }

  printf("Delay = %fs\n", (double)delay / 1000000.0);

  if (argc > 3) {
    vref = atof(argv[3]);
  }

  printf("Vref = %f\n", vref);

  // Map the I/O sections
  printf("Setup IO\n");
  setup_io();

  // activate SPI bus pins
  printf("Setup GPIO\n");
  setup_gpio();

  // Setup SPI bus
  printf("Setup SPI\n");
  setup_spi();

  for (;1;)
  {
    v = read_adc(chan);

    volts = (vref * (double)v / 1023.0) * 1000.0;
    temp = ((vref * (double)v / 1023.0) - 0.5) * 100.0;  // TMP036 has 500mV offset

    printf("%04d\t", v);
    printf("%4.2f mV\t", volts);
    printf("%4.2f C", temp);
    printf("\n");
    fflush(stdout);
 
    usleep(delay);
  } // repeated read

  printf("\n");
  restore_io();
} // main

User avatar
alexeames
Forum Moderator
Forum Moderator
Posts: 2869
Joined: Sat Mar 03, 2012 11:57 am
Location: UK
Contact: Website

Re: Gertboard ADC with TMP036

Sun Feb 03, 2013 9:41 pm

Excellent, thanks Gary. I have a bunch of 1 uF and 0.1 uF, so I'll give this a go.

Q for Gert. Is this a design defect in the ADC, the temperature sensor, or our circuit design (i.e. should we have been able to predict this from diligent perusal of the data sheets?)
Alex Eames RasPi.TV, RasP.iO

User avatar
Gert van Loo
Posts: 2486
Joined: Tue Aug 02, 2011 7:27 am
Contact: Website

Re: Gertboard ADC with TMP036

Mon Feb 04, 2013 11:08 am

alexeames wrote:Excellent, thanks Gary. I have a bunch of 1 uF and 0.1 uF, so I'll give this a go.

Q for Gert. Is this a design defect in the ADC, the temperature sensor, or our circuit design (i.e. should we have been able to predict this from diligent perusal of the data sheets?)
Good question so it deserves a long answer.

The data sheet of the tmp36 says it has a short-circuit current of 250uA and a supply current of 50uA. But it does not tell you if it still works with a shorted output or at what load the accuracy is lost.
I think the TMP36 data sheet is misleading as it claim an output drive of 10.000pF. I scanned (not read!) it but could not find any warning about not loading the output suddenly.
I think that is wrong as the standard way of reading it would be with a ADC. Most ADCs, have a sampling capacitor (See under sample-and-hold) which needs to be charged.
From what many users have tried I conclude the load on the temperature sensor output must be minimal. An OP-AMP is the normally preferred solution but can distort the result if it is not exactly 1:1.
The extra capacitor is a nice trick as it also gets rid of noise. But it makes that the result is slow. I would recommended this only for temperature measurements as the temperature of objects
rarely changes rapidly. (Read the data sheet: the package alone causes a delay of 3 seconds even when dipped in oil).

The MCP has a sampling capacitor of 20pF. You have added 100nF bulk capacitor. So when the gates opens the external capacitor is 200x bigger then the internal one which means your error is ~0.5%.
I have had a quick look at the AVR datasheet but could not spot a capacitor value in there.

Maths:
Normal operating current is 50uA. Assume you can draw 10uA for the output (arbitrary number I choose!). Time constant to load a 20pF capacitor to 3V3 is
(3.3 * 20e-12)/10e-6 = 6.6 micro seconds. I think you can program the sampling time in the AVR for that. If my chosen number is off (e.g. you can draw only 1uA) the time becomes 66 micro seconds. etc.
The bigger capacitor makes things a lot more difficult to calculate as the voltage will not go from 0 to max each time. After the initial period you only need to keep it topped-up.

User avatar
alexeames
Forum Moderator
Forum Moderator
Posts: 2869
Joined: Sat Mar 03, 2012 11:57 am
Location: UK
Contact: Website

Re: Gertboard ADC with TMP036

Mon Feb 04, 2013 12:19 pm

Thanks Gert :) I think I'll be adding small caps to the outputs of my TMP36s in circuits where I don't want an extra op-amp chip.
Alex Eames RasPi.TV, RasP.iO

EmergencyFunding
Posts: 2
Joined: Thu Apr 04, 2013 10:24 am

Re: Gertboard ADC with TMP036

Thu Apr 04, 2013 10:42 am

Hello

I am hoping to follow the solution suggested here to sort out a low temperature reading. I am going to order an LM358. Looking here...

http://cpc.farnell.com/jsp/search/brows ... tid=178836

... I see two possible variants - the LM358AN and the LM358N. Does it make any difference which one I get?

Thanks.

gstreeter
Posts: 106
Joined: Sun Sep 02, 2012 11:11 am
Location: UK

Re: Gertboard ADC with TMP036

Thu Apr 04, 2013 2:00 pm

The "A" version is an improved specification over the original LM358, e.g. lower input bias current etc. For the use described in this post it makes no difference as such.

EmergencyFunding
Posts: 2
Joined: Thu Apr 04, 2013 10:24 am

Re: Gertboard ADC with TMP036

Thu Apr 04, 2013 2:21 pm

Thanks for the info. Cheers.

Return to “HATs and other add-ons”