Go Down

Topic: Multiple Melexis MLX90614 on the same i2c, how to change addresses ?? (Read 11 times) previous topic - next topic

a spy

Hi,
I have two MLX90614 sensors and wanna connect both on the i2cbus. How can I change the address of one of these parts ? I use the i2cmaster from peter fleury (thx!) and have found a codepart in a forum. There is mentioned the address 0x2E for the address register, in the datasheet I have read the address 00Eh - what is correct ?? Does anybody have experiences (and a tested code) for this intention ??

// Now change address. First erase
i2cstartwait(dev+I2CWRITE);  //send start condition and write bit
i2cwrite(0x2E);  //send command for device to return address
i2cwrite(0x00);  // send low byte zero to erase
i2cwrite(0x00);  //send high byte zero to erase
i2cwrite(0x6F);  // send PEC
i2cstop();  //Release bus, end transaction
delay(100); // then wait 10ms

// Then write new address
i2cstartwait(dev+I2CWRITE);  //send start condition and write bit
i2cwrite(0x2E);  //send command for device to return address
i2cwrite(0x50);  // send low byte of address
i2cwrite(0x00);  //send high byte of address
i2cwrite(0x63); // send PEC
i2cstop(); //Release bus, end transaction
delay(100); // then wait 10ms

arduino newbie...

mk3

There's a pretty awesome example here:

http://bildr.org/2011/02/mlx90614-arduino/

I hope it helps you instead of confusing you even more (I'm still a bit confused myself)

The Melexis data sheet lists the address in two different ways and places

on Page 11

8.3.3 EEPROM (32x16)

SMBus address 00Eh

Then on page 14

8.4.1 Functional Description

....write access to 9 EEPROM cells (at addresses .....0x2Eh....)

I am enough of a beginner that I think this could be something about memory addressing or Hex number format that I just don't understand.


one thing about your code, a spy, that seems off is the fact you are attempting to write a PEC to the device... I would guess there's no point to that.


Do you have the 3.3V version of the device?


mk3

after a bit more investigation, my money is on 00Eh as being the correct address for holding the address.

The bildr post led me to a Melexis PDF publication about changing the Emissivity of the sensor in which the address for Emissivity is described as 0x04.

this corresponds to the data from Page 11  and I'd say 2 of 3 wins.

I wish you success!

a spy

Thanks a lot, I will check it on the weekend... you will hear from me !!
arduino newbie...

vinegeek

Can someone please post full working code for changing addresses?  Or link to work code.  Huge thank you.  This code is confusing me (apparently along with others).  I really need to move on from this headache.

paulrd

Has anyone found a solution to this? I'm having the same problem! I've tried various combinations of addresses with CRCs from http://smbus.org/faq/crc8Applet.htm, but no luck yet.

paulrd

Ok I've solved it, as least as far as I need to. The code below rewrites the EEPROM location for the slave address and tries all possible CRC bytes until it finds the correct one. Be sure to cycle the power to the MLX after writing to it, or you get strange results.

I'm not sure what the second address config byte does, but for my purposes an address in the first location and a zero in the second seemed to work.

Code: [Select]
#include <i2cmaster.h>
// Pins: Standard: SDA:A4  SCL:A5
//       Mega:     SDA:D20 SCL:D21

byte MLXAddr = 0x5A<<1;           // Default address
//byte MLXAddr = 0;               // Universal address

void setup(){
 Serial.begin(9600);
 Serial.println("Setup...");
 
 i2c_init();                              //Initialise the i2c bus
 PORTC = (1 << PORTC4) | (1 << PORTC5);   //enable pullups
 
 delay(5000);                    // Wait to allow serial connection
 ReadAddr(0);                    // Read current address bytes
 ChangeAddr(0x55, 0x00);         // Change address to new value
 //ChangeAddr(0x5A, 0xBE);       // Change address to default value
 ReadAddr(0);                    // Read address bytes
 delay(5000);                    // Cycle power to MLX during this pause
 ReadTemp(0);                    // Read temperature using default address
 ReadTemp(MLXAddr);              // Read temperature using new address
}

void loop(){
   delay(1000); // wait a second
}

word ChangeAddr(byte NewAddr1, byte NewAddr2) {

 Serial.println("> Change address");

 i2c_start_wait(0 + I2C_WRITE);    //send start condition and write bit
 i2c_write(0x2E);                  //send command for device to return address
 i2c_write(0x00);                  // send low byte zero to erase
 i2c_write(0x00);                  //send high byte zero to erase
 if (i2c_write(0x6F) == 0) {
   i2c_stop();                     //Release bus, end transaction
   Serial.println("  Data erased.");
 }
 else {
   i2c_stop();                     //Release bus, end transaction
   Serial.println("  Failed to erase data");
   return -1;
 }

 Serial.print("  Writing data: ");
 Serial.print(NewAddr1, HEX);
 Serial.print(", ");
 Serial.println(NewAddr2, HEX);

 for (int a = 0; a != 256; a++) {
   i2c_start_wait(0 + I2C_WRITE);  //send start condition and write bit
   i2c_write(0x2E);                //send command for device to return address
   i2c_write(NewAddr1);            // send low byte zero to erase
   i2c_write(NewAddr2);            //send high byte zero to erase
   if (i2c_write(a) == 0) {
     i2c_stop();                   //Release bus, end transaction
     delay(100);                   // then wait 10ms
     Serial.print("Found correct CRC: 0x");
     Serial.println(a, HEX);
     return a;
   }
 }
 i2c_stop();                       //Release bus, end transaction
 Serial.println("Correct CRC not found");
 return -1;
}

void ReadAddr(byte Address) {

 Serial.println("> Read address");

 Serial.print("  MLX address: ");
 Serial.print(Address, HEX);
 Serial.print(", Data: ");

 i2c_start_wait(Address + I2C_WRITE);  //send start condition and write bit
 i2c_write(0x2E);                  //send command for device to return address
 i2c_rep_start(Address + I2C_READ);
 
 Serial.print(i2c_readAck(), HEX); //Read 1 byte and then send ack
 Serial.print(", ");
 Serial.print(i2c_readAck(), HEX); //Read 1 byte and then send ack
 Serial.print(", ");
 Serial.println(i2c_readNak(), HEX);
 i2c_stop();
}

float ReadTemp(byte Address) {
 int data_low = 0;
 int data_high = 0;
 int pec = 0;

 Serial.println("> Read temperature");

 Serial.print("  MLX address: ");
 Serial.print(Address, HEX);
 Serial.print(", ");

 i2c_start_wait(Address + I2C_WRITE);
 i2c_write(0x07);                  // Address of temp bytes
 
 // read
 i2c_rep_start(Address + I2C_READ);
 data_low = i2c_readAck();         //Read 1 byte and then send ack
 data_high = i2c_readAck();        //Read 1 byte and then send ack
 pec = i2c_readNak();
 i2c_stop();
 
 //This converts high and low bytes together and processes temperature, MSB is a error bit and is ignored for temps
 float Temperature = 0x0000;       // zero out the data
 
 // This masks off the error bit of the high byte, then moves it left 8 bits and adds the low byte.
 Temperature = (float)(((data_high & 0x007F) << 8) + data_low);
 Temperature = (Temperature * 0.02) - 273.16;
 
 Serial.print(Temperature);
 Serial.println(" C");
 return Temperature;
}

ginner159

#7
Jan 26, 2012, 06:09 pm Last Edit: Jan 26, 2012, 06:41 pm by ginner159 Reason: 1
hi
sorry to reopen an old thread but was wondering what values needed to be changed in the code if any? at a guess would it be on line 29
Code: [Select]
word ChangeAddr(byte NewAdd1, byte NewAddr2)
changing addr1+2 for the vales i require?

cheers in advance
and sorry again for digging this thread up :)

NEVER MIND!!!
I figured it out :)

ftosin

Hey,
How do I go back to the default address? I am getting funny values, which part of the code should I change to get a real value.
Thanks.
- Tosin

ftosin

Never mind, find the code the read the correct device address. After changing to the correct device address. Everything works well.
Thanks.

chris_flesher

#10
Apr 30, 2013, 11:42 pm Last Edit: Apr 30, 2013, 11:44 pm by chris_flesher Reason: 1
I couldn't find any existing code for how to calculate the PEC for the MLX90614... however was able to adapt some code written for a PICAXE to get it working. Haven't fully tested it but seems to work ok so far for writing to EEPROM.

Code: [Select]
byte calcCrc8(byte X, byte crc) {
 X = X ^ crc;
 for (byte i=0; i<8; i++) {
   if (X > 0x7F) {
     X <<= 1;
     X = X ^ 0x07;
   }
   else {
     X <<= 1;
   }
 }
 return X;
}

byte calcPec(byte slaveAddr, byte memAddr, byte loByte, byte hiByte) {
 byte crc = 0x00;
 byte slaveAddr2 = slaveAddr << 1;
 crc = calcCrc8(slaveAddr2, crc);
 crc = calcCrc8(memAddr, crc);
 crc = calcCrc8(slaveAddr2+1, crc);
 crc = calcCrc8(loByte, crc);
 crc = calcCrc8(hiByte, crc);
 crc = calcCrc8(0x19, crc);
 return crc;
}

void setup(){
 Serial.begin(9600);
 byte pec = calcPec(0x00, 0x2E, 0x00, 0x55);
}

void loop(){
}

rrvik

Hi guys,

I've tried this code over and over with alot of changes, but I still can't get it working. Anybody having a solution?

Im going to use 4 sensors on the same inputs, but I still can't change the name on them..

Thanks in advance!

ginner159

Rrvik use the code posted by paulrd but make sure to only have one connected at once
And where it states this
Code: [Select]

.....
delay(5000);                    // Wait to allow serial connection
  ReadAddr(0);                    // Read current address bytes
  ChangeAddr(0x55, 0x00);         // Change address to new value
  //ChangeAddr(0x5A, 0xBE);       // Change address to default value
  ReadAddr(0);                    // Read address bytes
  delay(5000);                    // Cycle power to MLX during this pause
  ReadTemp(0);                    // Read temperature using default address
  ReadTemp(MLXAddr);              // Read temperature using new address
...

Comment out the first ChangeAddr to reset to default or change it to a new address. Also if I remover correctly (nearly a year since I last used this code) look for a CRC checker as it will make sure you have the correct checking bytes so that the device will respond as expected. I will update if I can find the one I used I think I still have it.

Hope this helps
Reply if you need more help

rrvik

Hi,

Thanks alot for your help.

I'm using the code right of, with no changes.
All I'm getting on the monitor is:


Setup...
> Read address
  MLX address: 0, Data: 55, 0, 2C
> Change address
  Data erased.
  Writing data: 55, 0
Found correct CRC: 0x22
> Read address
  MLX address: 0, Data: 55, 0, 0
> Read temperature
  MLX address: 0, 23.62 C
> Read temperature
  MLX address: B4,


And B4, as I am sure you know, is the same as 5A<<1.
And it only replies to that address even after running it with this program..

ginner159

found the crc check i was using
http://smbus.org/faq/crc8Applet.htm

as for your problem, did you power cycle the device during the address change stage?

Try using this code i used to check the devices had changed the address (made by me :D)
Code: [Select]

/*****************************************************************************************
*
*   Title:         I2C Device Scanner
*   Author:        Matthew Dinsdale <mdinsdale159@gmail.com>
*   Date:          Sunday, February 20th, 2012
*   Availability:  e-mail, or with consent from LJMU FSEA Team.
*   Compiled Size: 3858 bytes.
*
*****************************************************************************************
*
*   The included library and detailed info of each command can be found at
*   http://dsscircuits.com/articles/arduino-i2c-master-library.html
*
*   Sketch was coded using Version 5 of the library.
*
******************************************************************************************/

#include <I2C.h>

void setup()
{
  Serial.begin(115200);    //Enable serial output at 115200Baud
  Serial.println("Initialising I2C Scanner...");
  Serial.println();

  PORTC = (1 << PORTC4) | (1 << PORTC5);
  // Pins: Standard: SDA:A4  SCL:A5
  //       Mega:     SDA:D20 SCL:D21

  // Start Read cycle.
  int x = 0;
  int y = 3;     // Run for 'y' times. Change if you feel more is needed.
  while(x < y){
    ++x;

    I2c.begin();   // Starts I2C Protocol.
    delay(1000);   // Wait 1 second to allow all devices to initialise.
    I2c.scan();    // Scans and prints found address. A delay is built into this function.
    I2c.end();     // Stops I2C data.
    Serial.println();
    if (x == y){   // Stops loop once run through 'Y' amount of times.
      break;
    }
  }
  // End of Read cycle.

  // End of program info.
  Serial.println();
  Serial.print("Scanner ran ");
  Serial.print(x); // Prints the ammount of times the device bus was read.
  Serial.println(" times and was able to find the above device names.");
  Serial.println("To restart, Power Cycle or Push Reset button.");
  // Tell user that the script has finished and how to re-run.
  Serial.println("Program complete");
  Serial.println();
}

void loop()
{
  // Not used.
}


It runs 3 times just to make sure that a device wasnt sleeping during the first run time. Wish i could remember some more on what i did to get them working. I can post the code i used to read 4 devices. Hell if i can remember i may make a video!

Go Up