TMP102 and I2C

Hi,

I’m new to Electric Imp and I2C so this is probably a stupid question. I’m trying to build a temperature logger with a TMP102 module from SparkFun and based on some Arduino examples I guessed it might be as simple as:

`
hardware.configure(I2C_12);
hardware.i2c12.configure(CLOCK_SPEED_100_KHZ);
local i2c = hardware.i2c12;

imp.configure(“Temperature sensor”, [], []);

function readTemp()
{
local result = i2c.read(0x48, “”, 2);
server.show(result);
imp.wakeup(2, readTemp);
}

readTemp();
`

Apparently it’s not as the code outputs null. Any help would be greatly appreciated.

Well, printing the raw bytes may not be what you want, but if it’s showing null then it’s likely the i2c read isn’t working.

It could be the i2c address. The imp quotes these as 8 bit, whereas most datasheets show them as 7 bit. Try replacing 0x48 with (0x48<<1)?

Also, try replacing server.show with:

if (result != null) { server.show(format("%02x %02x", result[0], result[1]); }

…also make sure you have pullups on SCL and SDA!

Unfortunately it’s still returning null. In some examples I noticed that people first write “” to the device first to “wake” it up (I tried it as well). Is this necessary? Is the i2c.read equal to Arduino function Wire.requestFrom? Also in some examples the read/write bit seems to be included in the address.

I’ve tried adresses 0x48, 0x48<<1 and 0x90 as well as all the addresses between 0x00 and 0xff. The pull-up resistors for the SCL and SDA are included in the SparkFun TMP102 breakout.

On many sensors, the procedure is a bit more like this:

  1. Write a control word to the sensor to tell it to start a reading
  2. Wait some amount of time for the conversion to complete
  3. Read the result from the sensor

What’s the part number for the sensor you’re using?

I would tie ADD0 to ground and try again. That reliably sets the lower two I2C address bits to 00 .

Jane uses a TMP112 which appears to be similar to the TMP102; the jane example code writes the pointer register when reading the temperature like this:

` local result = i2c.read(0x90, “\x00”, 2);

if (result == null) {
    server.log("I2C Read Fail: Result == Null");
    return -1;
}else if(result[0] == null){
    server.log("I2C Read Fail: Result[0] == Null");
    return -1;
}else if(result[1] == null){
    server.log("I2C Read Fail: Result[1] == Null");
    return -1;
}

local t = ((result[0] << 4) + (result[1] >> 4)) * 0.0625;

`

Thanks for all the answers. The pointer register points to the temperature register (00) by default so writing shouldn’t be necessary nor has it helped. The SparkFun part number is SEN-09418. I’m sorry I forgot to mention that the ADDR0 is already tied to ground. I’ve also checked that SCL is connected to pin 1 and SDA to pin 2 and the solder joints seem good, but maybe I should check them once more. I noticed the Jane example and tried reading “\x00” as well, but it didn’t help either. The ATmega328 example on the SparkFun product page uses 0x92 for writing and 0x93 for reading (ADDR0 tied to VCC), but in my case reading 0x91 didn’t help.

The low bit of the i2c address in the API should always be zero. The imp will set the low bit for a read transaction.

The only thing I can think of is re-checking the SDA and SCL connections are the right way round?

I just got it working with the following code and pin1=SCL and pin2=SDA. In the arduino world, the Vcc is 5V, here I use 3.3V (from the arduino)
Code:
`// LM75 (CN75) Temperature Monitor using I2C
hardware.configure(I2C_12);
local i2c = hardware.i2c12;

local out_temp = OutputPort(“Temperature”);
imp.configure(“Temperature LM75”, [],[out_temp]);

function getsample() {
imp.wakeup(1.0, getsample.bindenv(this));
// Start conversion
i2c.write(0x90, “”);
i2c.write(0x90, “0”);

// Wait at least 36ms
imp.sleep(0.05);

local a = 0.0;
local temperature = 0.0;
a = i2c.read(0x90, "\\x00", 2);

if (a==null){
    temperature=999;
} else {
    if (a[0]>127){
        temperature = (a[0]-127)*-1.0; // values above 127 are negative degrees
        if (a[1]==128) temperature -= 0.5;
    } else {
        temperature = a[0];
        if (a[1]==128) temperature += 0.5;
    }
}

// log and print
server.log(format("temperature %.2f C ",temperature));
server.show(format("%.2f C", temperature));

//Send data to server
out_temp.set(temperature);

}

getsample();

`

Thanks Gaston. The code seems to work (at least from time to time, probably something wrong with my wiring).

Although the code below is in Processing, it may give you an idea for help in debugging your I2C wiring etc.
`// --------------------------------------
//
//
// This sketch tests the standard 7-bit addresses from 0 to 127.
// Devices with higher bit address might not be seen properly.
//
// Ric Batty
// September 2012
// version 121014-2307
//
// Using Arduino IDE 1.0.1
//

#include <Wire.h>

byte return_code;
byte I2C_address;

int count_Devices;
int count_Scans;
int scan_Index;
int total_Scans = 1; // You can bump this up or just hit reset for another scan

#define settle_time 10 // Time delay bewteen the Wire.beginTransmission and Wire.endTransmission
#define scan_period 1000 // Scan period, nominally 1 scan per second
//
//
//------------------------------------------------------------
//
void setup()
{
Serial.begin(9600);
Serial.println(“
I2C Address Scanner v121014-2307
”);
count_Devices = 0;
count_Scans = 0;
scan_Index = 1;
Wire.begin();
}

//------------------------------------------------------------
//
void loop()
{

while(scan_Index <= total_Scans) {
count_Scans += 1;
Serial.print("-Scan “);
Serial.print(count_Scans, DEC);
Serial.println(” start ");

count_Devices = 0;

for(I2C_address = 0; I2C_address <= 127; I2C_address++ )   {
  Wire.beginTransmission(I2C_address);
  delay(settle_time);
  return_code = Wire.endTransmission();
  /*
  
   Returns
   byte, which indicates the status of the transmission:
   0:success
   1:data too long to fit in transmit buffer
   2:received NACK on transmit of address
   3:received NACK on transmit of data
   4:other error
   
   */

  if (return_code == 0) {
    // Return code of 0 means the Wire begin and end were recognized
    Serial.print("   I2C device found at address ");
    Serial.print(format2Hex(I2C_address)); 
    Serial.println(" !");
    count_Devices++;
  }
  else if (return_code==4) {
    Serial.print("   Unknown error at I2C_address ");
    Serial.print(format2Hex(I2C_address));  
    Serial.println(" ***");
  } 
  else {
    // Do nothing
  }  
}
if (count_Devices == 0) {
  Serial.println("   **** No I2C devices found  **** ");
}
else {
  Serial.print(format2Dec(count_Devices));
  Serial.println(" I2C device(s) found");
} 

Serial.println("-Scan end\

");

delay(scan_period);           // wait for next scan

scan_Index++;

}
}

String format2Hex(byte I2C_Address) {
String tempS;
tempS = String(I2C_Address,HEX);
tempS.toUpperCase();
if (I2C_Address < 0x10) {
tempS = “0” + tempS;
}
tempS = “0x” + tempS;
return tempS;
}

String format2Dec(int input) {
String tempS;
tempS = String(input,DEC);
if (input < 10) {
tempS = " " + tempS;
}
return tempS;
}
`

This is my take on it, a class that wraps TMP102. Works great and gives fractional values. Also note what documentations says about i2c:

The I2C bit rate is currently fixed at 100kHz, however a future firmware revision is expected to allow for configuration of this. Note also that external pull-ups are required, it is not possible to enable the internal pull-ups when pins are used for I2C.

I’m not using any pull-ups though and it works just fine.

/Per


//
// TMP102 Temperature Reader
// Uses i2c on pins 8, 9
//
class TemperatureReader {
    i2c = null;
    
    // Constructor
    constructor() {
        hardware.i2c89.configure(CLOCK_SPEED_100_KHZ);
        i2c = hardware.i2c89;
    }
    
    function readData() {
        // Start conversion
        i2c.write(0x90, "");
        i2c.write(0x90, "0");
 
        // Wait for conversion to finish
        imp.sleep(0.05);
 
        // Read msb and lsb
        local a = i2c.read(0x90, "\\x00", 2);
        
        if (a == null){
            return 999; // Dang...
        }
        
        // Calculate no of steps. Each step is 0.0625 degrees centigrades.
        local temp = ((((a[0] & 0x7f) << 8) + a[1]) >> 4) * 0.0625;
        
        // Is negative value?
        if (a[0] & 0x80) {
            temp *= -1;
        }
        return temp;
    }
}

Thanks for pointing that incorrect note in the docs out! I2C clock has been configurable for a while now (50/100/400kHz). You still need pullups as the internal ones aren’t strong enough even for 50kHz.

Ah, now I get why my setup is so stable. The breakout board I have for the TMP102 has 1k pull-ups on it. They are just so tiny that I didn’t notice until now. :slight_smile:

Here’s another example of a class and end-to-end code for reading temperature from the TMP102. (attached)

Nice code, thanks - you can, however, remove the hardware.configure(I2C_12); type lines - this is legacy and deprecated.

thanks, very well documented

Hey,

Hope somebody can help me out because I’m really stuck…

Trying to read one of these click with my Imp @ i2c12, but not getting anything other than ‘null’ when doing the i2c read command.

Everything is wired OK (double-checked with multi-meter, 3V3 is there @ Vcc, both SDA & SCL are held High by breakout resistors) and I’ve tried all of the classes listed in this thread to no avail (they’re pretty much identical, but I tried them all just to be sure…)

Any ideas what could be causing this?

I recall that someone mentioned the first two pins on the Sparkfun Imp breakout misbehaving - could this be it? Should I try with i2c89?

Thanks in advance!

Anybody?

maybe you should show us your setup/breadboard.