Go Down

Topic: Problem with Reading/Writing to the EEPROM of a MLX90614 (Read 4822 times) previous topic - next topic

maxbot

Hello together,
I am stuck with the following problem and really need help from the community:
I have connected a Melexis MLX90614 Infrared Sensor to the Arduino to get temperature data.
Now i want to reduce the response time of the sensor by changing some values in the EEPROM.
According to this document http://www.melexis.com/Assets/Understanding-MLX90614-on-chip-digital-signal-filters-5272.aspx, I have to change bits 0-2 and 8-10 from a 16 bit column in the EEPROM ConfigRegister1. The other bits should not be changed, so the programm should read the register, make the alterations, then write the register value back, preserving the value in bits 3-7.

I found this sketch that modifies the emission rate of the MLX90614, i think this is very close to what I need:

Code: [Select]
/Simple program to read/write to the EEPROM (or read RAM) of the MLX90614 IR Sensor (in my case
//the MLX90614ESF-AAA). Example below erases the emissivity coefficient and then writes E = 1.
//Written be a total beginner, probably includes errors, and can definitely be
//improved on in many ways... /Lo-fi, 2011.

#include <i2cmaster.h>

void setup()
{
Serial.begin(9600);
Serial.println("----------Let's begin!----------");
i2c_init();                             //Initialise i2c bus
PORTC = (1 << PORTC4) | (1 << PORTC5);  //enable pullups
}

void loop()
{
int dev = 0x00; // I use the general address. If I specify the address
                //(0x05<<1), the code doesn't work, don't know why... yet.
unsigned int data_l = 0;
unsigned int data_h = 0;
int pec = 0;

float data_t = 0;
float emissivity = 0;

//READ EEPROM/RAM

Serial.println("*1: Read EEPROM address:");
i2c_start_wait(dev+I2C_WRITE);
i2c_write(0x24);  //0x004 and 0x04 etc reads the same address in the RAM,
                  //add 2(0) for EEPROM, eg. 0x24 (emissivity correction
                  //coefficient in EEPROM).

i2c_rep_start(dev+I2C_READ);
data_l = i2c_readAck(); //Read 1 byte and then send ack
data_h = i2c_readAck(); //Read 1 byte and then send ack
pec = i2c_readNak();
i2c_stop();

Serial.print("Data Low: ");
Serial.println(data_l);

Serial.print("Data High: ");
Serial.println(data_h);

Serial.print("Data combined: ");
data_t = (((data_h) << 8) + data_l);
Serial.println(data_t);

Serial.print("Emissivity: ");
emissivity = ((data_t) / 65535);
Serial.println(emissivity);

delay(5000);

//WRITE TO EEPROM, FIRST: ERASE OLD STUFF

i2c_start_wait(dev+I2C_WRITE);
i2c_write(0x24); //Register Address to write to

i2c_write(0x00); //Erase low byte (write 0)
i2c_write(0x00); //Erase high byte (write 0)
i2c_write(0xE8); //Send PEC
i2c_stop();

Serial.println("*2: Erasing old emissivity factor (writing 0).");
delay(5000);

//CHECK IF THE EEPROM VALUE HAS BEEN ERASED

Serial.println("*3: Check if the old emissivity coefficient was erased:");
i2c_start_wait(dev+I2C_WRITE);
i2c_write(0x24);  //See above comment.

i2c_rep_start(dev+I2C_READ);
data_l = i2c_readAck(); //Read 1 byte and then send ack
data_h = i2c_readAck(); //Read 1 byte and then send ack
pec = i2c_readNak();
i2c_stop();

Serial.print("Data Low: ");
Serial.println(data_l);

Serial.print("Data High: ");
Serial.println(data_h);

Serial.print("Data combined: ");
data_t = (((data_h) << 8) + data_l);
Serial.println(data_t);

Serial.print("Emissivity: ");
emissivity = ((data_t) / 65535);
Serial.println(emissivity);
delay(5000);

//WRITE TO EEPROM, THE NEW STUFF!

i2c_start_wait(dev+I2C_WRITE);
i2c_write(0x24); //Register Address to write to

i2c_write(0xFF); //New emissivity factor, Ef=1
i2c_write(0xFF); //New emissivity factor, Ef=1
i2c_write(0xCC); //Send PEC
i2c_stop();

Serial.println("*4: Write new E to EEPROM (E = 1.0).");
delay(5000);
Serial.println("----------The process starts over again----------");
delay(5000);
}


The only thing i know so far is that I have to change i2c_write(0x24);  to i2c_write(0x25); and that I need to send the following 16 Bits to this register:
1;0;0;R;R;R;R;R;1;0;0;R;R;R;R;R
R stands for read, so that the sketch first reads whats the existing value and then uses it.

Can anybody please help me with the adaption of the code ? Thanks a lot in advantage  :)

johnwasser

Use 'bitwise AND" and "bitwise OR" operators to clear the fields you want to set and set the values.

Code: [Select]
/Simple program to read/write to the EEPROM (or read RAM) of the MLX90614 IR Sensor (in my case
i2c_start_wait(dev+I2C_WRITE);
i2c_write(0x24); 
i2c_rep_start(dev+I2C_READ);
unsigned int register = i2c_readAck(); //Read low byte and then send ack
register |= i2c_readAck() << 8; //Read high byte and then send ack
pec = i2c_readNak();
i2c_stop();

// Set the register to: 0b100xxxxx100xxxxx  (where 'x' means 'do not modify)
register &= 0b0001111100011111;  // Clear all bits in the fields to be modified.
register |= 0b1000000010000000;  //Set bits in those fields to 1 where needed


//WRITE TO EEPROM, THE NEW STUFF!

i2c_start_wait(dev+I2C_WRITE);
i2c_write(0x24); //Register Address to write to
i2c_write(register);
i2c_write(register >> 8);
i2c_write(0xCC); //Send PEC
i2c_stop();

Send Bitcoin tips to: 1L3CTDoTgrXNA5WyF77uWqt4gUdye9mezN
Send Litecoin tips to : LVtpaq6JgJAZwvnVq3ftVeHafWkcpmuR1e

maxbot


Use 'bitwise AND" and "bitwise OR" operators to clear the fields you want to set and set the values.

Code: [Select]
/Simple program to read/write to the EEPROM (or read RAM) of the MLX90614 IR Sensor (in my case
i2c_start_wait(dev+I2C_WRITE);
i2c_write(0x24); 
i2c_rep_start(dev+I2C_READ);
unsigned int register = i2c_readAck(); //Read low byte and then send ack
register |= i2c_readAck() << 8; //Read high byte and then send ack
pec = i2c_readNak();
i2c_stop();

// Set the register to: 0b100xxxxx100xxxxx  (where 'x' means 'do not modify)
register &= 0b0001111100011111;  // Clear all bits in the fields to be modified.
register |= 0b1000000010000000;  //Set bits in those fields to 1 where needed


//WRITE TO EEPROM, THE NEW STUFF!

i2c_start_wait(dev+I2C_WRITE);
i2c_write(0x24); //Register Address to write to
i2c_write(register);
i2c_write(register >> 8);
i2c_write(0xCC); //Send PEC
i2c_stop();




Thanks a lot for your work ! Unfortunately, it's not working correctly but I don't know whats the reason...
Heres the full code:
Code: [Select]
#include <i2cmaster.h>

void setup()
{
Serial.begin(9600);
i2c_init();                             //Initialise i2c bus
PORTC = (1 << PORTC4) | (1 << PORTC5);  //enable pullups

int dev = 0x5A<<1; // I use the general address. If I specify the address
                //(0x05<<1), the code doesn't work, don't know why... yet.
unsigned int value = 0;
int pec = 0;
i2c_start_wait(dev+I2C_WRITE);
i2c_write(0x25); 
i2c_rep_start(dev+I2C_READ);
value = i2c_readAck(); //Read low byte and then send ack
value |= i2c_readAck() << 8; //Read high byte and then send ack
pec = i2c_readNak();
i2c_stop();
// Set the register to: 0b100xxxxx100xxxxx  (where 'x' means 'do not modify)
wert &= 0b0001111100011111;  // Clear all bits in the fields to be modified.
wert |= 0b1000000010000000;  //Set bits in those fields to 1 where needed


//WRITE TO EEPROM, THE NEW STUFF!

i2c_start_wait(dev+I2C_WRITE);
i2c_write(0x25); //Register Address to write to
i2c_write(value);
i2c_write(value >> 8);
i2c_write(0xCC); //Send PEC
i2c_stop();
}

void loop()
{
}


Anybody finds a mistake ?

maxbot

I still haven't managed it to get the sketch above working :-(
can anybody pls help me ?

oh6kft

#4
Apr 24, 2011, 05:15 pm Last Edit: Apr 24, 2011, 05:17 pm by oh6kft Reason: 1
Hi,

I'm trying to build similar scanning IR-camera as your camera. I'm wondering if you have tried reading the chip also with PWM, to test if it would be faster ? As I read from the data-sheets, default output is PWM on the range of -20 - 120 C. As I don't yet have actual chip, I can't verify the code above. But as I get the chip (MLX90614ESF-BCF from Future Electronics), I'll try to reproduce the project and test the response time.

Another speedup would be to highlight the "interesting areas" from the web-cam picture before taking actual temperature-measurements. That way the area that needs to be scanned with the sensor would be much smaller - at least if there are only few interesting areas in the whole picture. That would be useful when scanning for wiring, connectors, IC-chips etc. Lot's of background that could be scanned only with limited resolution / faster and then focus on the most important areas in the picture.

But this all is still theory until they deliver my chip - hopefully soon.

With best regards from Finland,

Henkka

maxbot

I finally solved the problem, now everything is working:

Code: [Select]
#include <i2cmaster.h>

void setup()
{
Serial.begin(9600);
Serial.println("This program will change the EEPROM settings of");
Serial.println("your MLX90614-DCI sensor to work best with the");
Serial.println("Cheap-Thermocam. PRESS ANY KEY TO CONTINUE.");
Serial.println("");
Serial.println("Created by Max Ritter - www.cheap-thermocam.tk");
Serial.println("");
while (Serial.available() == 0) {
}
Serial.println("----------Let's begin!----------");
Serial.println("");
i2c_init();
PORTC = (1 << PORTC4) | (1 << PORTC5);

int dev = 0x00;
unsigned int data_l = 0;
unsigned int data_h = 0;
int pec = 0;
float data_t = 0;
float emissivity = 0;

//WRITE TO EEPROM, FIRST: ERASE OLD STUFF
Serial.println("*1: Erasing old EEPROM settings");
Serial.println("");
Serial.println("Erasing filter settings..");
i2c_start_wait(dev+I2C_WRITE);
i2c_write(0x25);
i2c_write(0x00); //Erase low byte (write 0)
i2c_write(0x00); //Erase high byte (write 0)
i2c_write(0x83); //Send PEC
//For PEC Calculation have a look at : http://smbus.org/faq/crc8Applet.htm
//In this case the PEC calculates from 250000 (=0x83)
i2c_stop();
delay(5000);

Serial.println("Erasing maximum temperature setting..");
i2c_start_wait(dev+I2C_WRITE);
i2c_write(0x20);
i2c_write(0x00);
i2c_write(0x00);
i2c_write(0x43);
i2c_stop();
delay(5000);

Serial.println("Erasing minimum temperature setting..");
i2c_start_wait(dev+I2C_WRITE);
i2c_write(0x21);
i2c_write(0x00);
i2c_write(0x00);
i2c_write(0x28);
i2c_stop();
delay(5000);

//WRITE TO EEPROM, THE NEW STUFF!
Serial.println("");
Serial.println("*2: Write new settings to EEPROM");
Serial.println("");
Serial.println("Writing new filter settings..");
i2c_start_wait(dev+I2C_WRITE);
i2c_write(0x25); //Register Address to write to
i2c_write(0x74); //New filter settings (B374)
i2c_write(0xB3);
i2c_write(0x65); //Send PEC
i2c_stop();
delay(5000);

Serial.println("Writing new maximum temperature setting..");
i2c_start_wait(dev+I2C_WRITE);
i2c_write(0x20);
i2c_write(0xFF);
i2c_write(0xFF);
i2c_write(0x67);
i2c_stop();
delay(5000);

Serial.println("Writing new minimum temperature setting..");
i2c_start_wait(dev+I2C_WRITE);
i2c_write(0x21);
i2c_write(0x5B);
i2c_write(0x4F);
i2c_write(0x59);
i2c_stop();

Serial.println("");
Serial.println("----------Finish!----------");
}
void loop()
{
}



The code changes the filter settings of the MLX90614-DCI to the minimum value of 49ms (100% FIR) and extends the standard temperature range from -20 - 120 degree to -70 - 370 °.

@ Henkka:
Great that you also try to build a IR camera. Limiting the scanning range to Ă­nteressting areas will be a possible soon. I will build a portable version of this cheap-thermocam which can be used standalone without any computer and in this step I will include the function. The latest information are always at www.cheap-thermocam.tk  ;)


Guido_Ov

Hello to all of you,

I'm new in Arduino projects and need your help.

I "played" a bit with MLX90614 to create a i2C bus with 6 MLX. I figured, that how to change the Address to have more than one MLX on the bus. That's clear so far. Because I need to ask each of them I Used tis directly, later on to get each specific temperature.

I Prepared a breadborad to change the Adresses. I pluged three of them, one by one, and reprogrammed them fine.

I used 5A, 5B, 5C, and all responsed temperature after reprogramming. Then I tried 5D, 5E and 5F and it won't work.

Then I tried soe other addresses and now I couldn't get any response. I there a kind of Adress scanner available which runs thourgh the range of adresses and find the one address which deliveres a response?

I used this INO for writing the new Addresses:


#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

 Serial.println("Wait 5sec...");
 delay(5000);                    // Wait to allow serial connection
 Serial.println("Read current Addr....");
 ReadAddr(0);                    // Read current address bytes
 Serial.println("Call ChangeAddr...");
 ChangeAddr(0x5A, 0x00);         // Change address to default value
 // Section I
 // ChangeAddr(0x5A, 0xBE);       // Change address to value 0x5A, 0xBE (90 , 190) Front Left
 // ChangeAddr(0x5B, 0x6F);       // Change address to value 0x5B, 0x6F (91 , 191)Front Mid
 // ChangeAddr(0x5C, 0xC0);       // Change address to value 0x5C, 0xC0 (92 , 192) Front Right
// Section II
 // ChangeAddr(0x5D, 0xC1);       // Change address to value 0x5D, 0xC1 (93 , 193) Rear Left
 // ChangeAddr(0x5E, 0xC2);       // Change address to value 0x5B, 0x6F (94 , 194)Rear Mid
 //ChangeAddr(0x5F, 0xC3);       // Change address to value 0x5C, 0xC0 (95 , 195) Rear Right
  ReadAddr(0);                    // Read new 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("> Changeing 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;
}

I appreciate your support and your suggestions to get the Address issue fixed.

Does have any one a list of available Addresses?

Sorry for my poor english. Hope you understand my problem.

Best regards and thank you in advance

Guido

banff

Hello everybody!

I also have some trouble to read and write the EEPROM of the MLX90614. I'm using the DCI version if the MLX90614, so to set a new emissivity I need to change the values in two EEPROM cells, 0x04 and 0x0F, according to the Melexis sheet I attached. However, I'm not familiar with the wire or i2cmaster library and don't want to destroy my sensor. For now, I simply miltiplied the result with my emissivity factor, as it is just a factor.. Does it make any difference?

There are some examples with the i2cmaster library but I really don't get the point what I need to use of it. Moreover I cannot find the i2cmaster library to download..

I want the new emissivity to be 0.95. In hex it would be 0xF332. To calculate the new value for cell 0x0F it is necessary to read the old content the EEPROM addresses 0x04 and 0x0F and to make some calculations, as shown in the Melexis sheet for changing the emissivity. So the current values must be read out to include them into the calculations.

Would anyone mind helping me with the code to change the emissivity on the DCI?

Thanks a lot in advance!
Regards, banff


Go Up
 


Please enter a valid email to subscribe

Confirm your email address

We need to confirm your email address.
To complete the subscription, please click the link in the email we just sent you.

Thank you for subscribing!

Arduino
via Egeo 16
Torino, 10131
Italy