TSD305 thermopile - changing i2c address

Hi all,

I wonder if anybody could help me decipher what I'm finding to be quite a cryptic datasheet. I have a TSD305-1C55 thermopile with default i2c address of 0x00. I would like to change this to 0x01, so I can use two in a project.

The i2c address resides in EEPROM address 0x02. I can read this out just fine.

Page 7 of the datasheet below I think indicates that to change the address you have to:
-Write the command 0x42 to select EEPROM address 0x02
-It doesn't explicitly state this but I assume you then write your desired address, e.g. 0x01
-Write the command 0x90 to 'calculate and write the memory checksum'
-Power cycle to activate the new address

So I'm trying the following, with no success. I'm not sure if I need to insert delays between commands or whether I'm approaching this in completely the wrong way:

Wire.beginTransmission((uint8_t)TSD305_ADDR); //TSD305_ADDR being the 0x00 default
Wire.write(0x42); //select EEPROM address 0x02 for writing
Wire.write(0x01); //write the new address
Wire.write(0x90); //send the command for memory checksum
Wire.endTransmission();
//Then power cycle to see if device has picked up the new address

TSD305-1C55 datasheet

Lightbulb TSD304 arduino library

Any pointers would be gratefully received!

My reading of the data sheet indicates that data transfers to and from EEPROM are 16 bits per address, each way. Beware endian -- looks like high byte first.

1 Like

Thanks! I've got a step further with your help.

The following simple code has allowed me to set the address to 0x01, as confirmed by some generic arduino i2c scanner code run afterwards. The example lightbulb TSD305 code at the link above picks up the new sensor with address 0x01, however, the status byte returns 0x04 which means memory integrity error. The example also returns zero values for temperature. This leads me to think I have to write the CRC value after sending command 0x90.

I'm assuming this has to be a two byte CRC16 value calculated from my 0x00 0x01 values written. The datasheet doesn't go into specifics but I can't see it being anything else. Would this make sense?

Wire.beginTransmission(0x00);//0x00 is the default address for the sensor
Wire.write(0x42); //select address 0x02 in write mode (the register that contains the sensor address)
Wire.write(0x00); //write high byte of new address
Wire.write(0x01); //write low byte of new address. i.e. new address is 0x01
Wire.write(0x90); //write command for recalculation of memory checksum
Wire.endTransmission();
//power cycle sensor 

The data sheet indicates that the command 0x90 recalculates and writes the CRC value.

Try this: run the I2C scanner program to see what slave address is now recognized. Then, using that address, run a program that just sends the 0x90 command, delays a bit, then reads the status byte. Power down and repeat.

When all else fails, consult the manufacturer.

1 Like

Champion! Great advice thank you very much. It worked on the first write of a standalone 0x90 command. I think it doesn't like the address being changed and sending of the 0x90 command without a delay between.

Steps I took to change the address for anybody else wanting to do the same thing. Obviously could be made a lot neater, but this was my amateurish approach to get it working:

In tsd305.h, comment out the 'private:' line, allowing you to call the read_EE_coeff function from your code. Added a new 'write_EE_coeff' function as shown below

//private:
	/**
   * \brief Reads the tsd305 EEPROM coefficient stored at address provided.
   *
   * \param[in] uint8_t : Address of coefficient in EEPROM
   * \param[out] uint16_t* : Value read in EEPROM
   *
   * \return tsd305_status : status of TSD305
   *       - tsd305_status_ok : I2C transfer completed successfully
   *       - tsd305_status_i2c_transfer_error : Problem with i2c transfer
   *       - tsd305_status_busy : Sensor is busy
   *       - tsd305_status_memory_error : Sensor EEPROM memory error
   */
	enum tsd305_status read_EE_coeff(uint8_t address, uint16_t *coeff);
   /**	
   * \brief Reads the tsd305 EEPROM coefficient stored at address provided.
   *
   * \param[in] uint8_t : Address of coefficient in EEPROM
   * \param[out] float* : IEEE-745 Value read in EEPROM
   *
   * \return tsd305_status : status of TSD305
   *       - tsd305_status_ok : I2C transfer completed successfully
   *       - tsd305_status_i2c_transfer_error : Problem with i2c transfer
   *       - tsd305_status_busy : Sensor is busy
   *       - tsd305_status_memory_error : Sensor EEPROM memory error
   */
   //new one I added here:
  	enum tsd305_status write_EE_coeff(uint8_t address, uint16_t *coeff);

Note that the address of the sensor is stored in tsd305.cpp. The default is 0x00 NOT 0x1E. Once you update the address, this has to be changed to suit here.

//TSD305 device address
#define TSD305_ADDR 0x00
//NOT 1E!

If you want to change the address to 0x01. include the following in your new 'write_EE_coeff' function

  enum tsd305_status tsd305::write_EE_coeff(uint8_t address, uint16_t *coeff) {
 	Wire.beginTransmission((uint8_t)TSD305_ADDR);//the default for the TSD304 is 0x00
 	Wire.write(address);//this is 0x42 to write into EEPROM address 0x02
	Wire.write(0x00);// write high byte
	Wire.write(0x01);//write low byte. Setting to address 0x01
 	Wire.endTransmission();
 	delay(1);
 }

My main arduino code below writes the new address to 0x42, corresponding to EEPROM address 0x02, calling our new function above. I connected the power pin of the sensor to pin 4, so I can turn it on and off easily.

#include <tsd305.h>

tsd305 m_tsd305;

void setup() {
  uint16_t test;//variable to store contents of address returned from sensor
  bool connected;//1 if sensor connected, 0 if not
  tsd305_status status;//store contents of status byte returned from sensor
  
  pinMode(4, OUTPUT);//TSD305 power pin
  digitalWrite(4, HIGH);//turn on sensor
  delay(2000);//some time for sensor to turn on
    
  Serial.begin(9600);//setup serial

  Serial.println(F("==== TE Connectivity ===="));//standard printout from lightbulb example
  Serial.println(F("==== TSD305 ====="));
  Serial.println(F("==== Measure ===="));

  m_tsd305.begin();
  
  connected = m_tsd305.is_connected();//check if sensor connected
  if ( connected ) {//if so do this
    m_tsd305.write_EE_coeff(0x42, (uint16_t *)&test );//Write to 0x42 to write a new address to EEPROM address 0x02. If writing address succeeds, sensor won't respond below as has new address
    //change to 0x90 command to reset memory bit
    Serial.println("written to 0x90!");//ignore this, should be 0x42
  }
  
  Serial.println("turning off sensor!");
  digitalWrite(4, LOW);//turn off sensor
  delay(2000);//delay to power off sensor
  
  digitalWrite(4, HIGH);//turn on sensor
  Serial.println("turning on sensor!");
  delay(2000);//some time for sensor to turn on

  connected = m_tsd305.is_connected();//check if sensor connected
  if ( connected ) {//if so do this
    status = m_tsd305.read_EE_coeff(0x02, (uint16_t *)&test );//read address two containing the sensor address
    Serial.println("read address 0x02! Contents are:");
    Serial.println(test);//print the contents of the address
    Serial.println("status byte is:");
    Serial.println(status, HEX);//print the status byte. 4 = memory error. 0 = fine. Returns 0!
  }
}

Note that if successful, the last part of this code won't work, as we changed the address to 0x01.

Go back into tsd305.cpp and set the address to 0x01

//TSD305 device address
#define TSD305_ADDR 0x01

Change our new write_EE_coeff function in tsd305.cpp to the following:

  enum tsd305_status tsd305::write_EE_coeff(uint8_t address, uint16_t *coeff) {
 	Wire.beginTransmission((uint8_t)TSD305_ADDR);//the default for the TSD304 is 0x00
 	Wire.write(address);//this is 0x42 to write into EEPROM address 0x02
//note that we will now pass in the command/address 0x90 from the main code
	//Wire.write(0x00);// write high byte
	//Wire.write(0x01);//write low byte. Setting to address 0x01
 	Wire.endTransmission();
 	delay(1);
 }

Change this section of the code below in our main arduino function to this to write the 0x90 command. Running the whole program will auto power cycle the sensor and then read the address 0x02, which should give you the result 0x01 and give you a status byte result of 0. A result of 4 means it hasn't worked. Until this gives you 0, the lightbulb library TSD305 temperature result gives you non sensical readings. This worked for me on the first try.

  connected = m_tsd305.is_connected();//check if sensor connected
  if ( connected ) {//if so do this
    m_tsd305.write_EE_coeff(0x90, (uint16_t *)&test );//Write 0x90 command which resets memory bit
    Serial.println("written to 0x90!");
  }

Good luck if you are trying the same thing!

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.