Go Down

Topic: Melexis MLX90614 thermal sensor - default EEPROM? (Read 3414 times) previous topic - next topic

jay_ar

Dec 19, 2012, 10:25 pm Last Edit: Dec 24, 2012, 10:26 am by jay_ar Reason: 1
I asked this before but I did it in the wrong place (as a comment to an older thread).
Anyway... I'm trying to use a MLX90614 BCI with an Arduino Leonardo. I was able to use it, get measurements, etc. and life was good. But not great.

So I decided to change some of the registers as recommended at http://www.cheap-thermocam.tk/ , using the "configuration sketch" in that page. BIG mistake. That sketch was written for an Arduino Uno (and let's be honest, it's not the finest piece of code), and by the time you can connect to the Leonardo's serial port the information you are supposed to keep is already gone for good. AND... the code produced an error.

It looks like my sensor was flaky to begin with, and the code at that page didn't help much. Now my MLX is completely out of whack, and Melexis won't offer any support (among other things, because "Arduino is not an approved component"  :0 ).

I wonder if someone around here may help me reading the EEPROM from his/her MLX and sending the values to me. There are 32 positions, and although you are not supposed to mess with more than two or three, having the whole thing may help me identify what part of the EEPROM is bad.

I wrote a sketch that dumps EEPROM, RAM, Flags, etc., but I'm not that familiar with the Arduino and I won't feel comfortable asking you to run it on your devices, but if you can dump (or already did dump) your eeprom and send me the default values I would be very grateful. The code is here anyway...

Code: [Select]

// Configuration sketch for the MLX90614
// put together by jay_ar. Based on the
// "Configuration Sketch - Version 1.03"
// from www.cheap-thermocam.tk and some other
// examples

#include <i2cmaster.h>
extern volatile unsigned long timer0_millis;

int ledPin = 13;        // Onboard led
boolean ledOn = true;
unsigned long oldTime;

void setup() {
 pinMode(ledPin, HIGH);  // Output
 
 Serial.begin(9600);
 i2c_init();
 digitalWrite(ledPin, HIGH);   // sets the LED on
 oldTime=timer0_millis; // "now"  
}

//To Do: disable overwriting by default
void loop(){
 if (Serial.available() > 0) {  
     switch (Serial.read()) {
       case '1': readEEP(); break;
       case '2': readRAM(); break;
       case '3': measureTemp(); break;
       case '4': readStats(); break;
/* uncomment only if you know what you are doing!
       case '8': changeTmax(); break;
       case '9': changeTmin(); break;
       case '0': changeCtrl(); break;
*/
     }
 }
 if ((timer0_millis - oldTime)>1000){
   ledOn = !ledOn;
   digitalWrite(ledPin,ledOn);
   oldTime = timer0_millis;
   // led blinking = still alive!
 }
}

void readEEP(){
 Serial.println("EEPROM data");
 char S[32];  
 for (int i = 0; i <= (0x1F); i++) {
   unsigned int value = readAddress(0x00,0x20+i);
   sprintf (S,"%02X:\t%04X",i,value);
   Serial.println(S);
 }
}

void readRAM(){
 Serial.println("RAM data");
 char S[32];  
 for (int i = 0; i <= (0x1F); i++) {
   unsigned int value = readAddress(0x00,i);
   sprintf (S,"%02X:\t%04X",i,value);
   Serial.println(S);
 }
}

void measureTemp(){
 unsigned int data_l = 0;
 unsigned int data_h = 0;
 int pec = 0;
 
 i2c_start_wait(0x00+I2C_WRITE);
 i2c_write(0x07);
 i2c_rep_start(0x00+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();  

 double tempFactor = 0.02;
 double temp = 0x0000;

 temp = (double)(((data_h & 0x007F) << 8) + data_l);
 temp = (temp * tempFactor)-0.01-273.15;

 char S[32];
 long int temp_i=round(100*temp);
 sprintf(S,"Temp: %s%li.%02li",(temp_i < 0 ? "-" : ""), abs(temp_i / 100), abs(temp_i % 100));
 Serial.println(S);    
}

void readStats(){
 unsigned int data_l = 0;
 
 i2c_start_wait(0x00+I2C_WRITE);
 i2c_write(0xF0);
 data_l = i2c_readAck(); //Read 1 byte and then send ack
 i2c_stop();

 char S[32];
 sprintf(S,"Flags: 0x%02X",data_l);
 Serial.println(S);
}

// This part of the code may brick your MLX!!!
// Use it (uncomment cases 8..0 above) at your own risk
// To do: keep non-relevant bits from 0x05

void changeTmax(){
 Serial.println("Erasing max temp settings...");
 writeAddress(0x00,0x20,0x00,0x00,0x43);
 delay(100);
 Serial.println("Writing new max temp settings...");
 writeAddress(0x00,0x20,0x23,0xFF,0x21);
 cycleMLX(0x00);
 delay(1000);

 char S[32];  
 unsigned int value = readAddress(0x00,0x20+0x00);
 sprintf (S,"Read:\t%04X",value);
 Serial.println(S);  
}

void changeTmin(){
 Serial.println("Erasing min temp settings...");
 writeAddress(0x00,0x21,0x00,0x00,0x28);  // <- Corrected
 delay(100);
 Serial.println("Writing new min temp settings...");
 writeAddress(0x00,0x21,0x5B,0x4F,0x59);
 cycleMLX(0x00);
 delay(1000);

 char S[32];  
 unsigned int value = readAddress(0x00,0x20+0x01);
 sprintf (S,"Read:\t%04X",value);
 Serial.println(S);  
}

void changeCtrl(){
 Serial.println("Erasing filter settings...");
 writeAddress(0x00,0x25,0x00,0x00,0x83);
 delay(100);
 Serial.println("Writing new filter settings...");
 writeAddress(0x00,0x25,0x74,0xB6,0x7E);
 cycleMLX(0x00);
 delay(1000);

 char S[32];  
 unsigned int value = readAddress(0x00,0x20+0x05);
 sprintf (S,"Read:\t%04X",value);
 Serial.println(S);  
}

unsigned int readAddress (int dev, int address){
 unsigned int data_l = 0;
 unsigned int data_h = 0;
 int pec = 0;
 unsigned int data_t = 0;

 i2c_start_wait(dev+I2C_WRITE);
 i2c_write(address);
 i2c_rep_start(dev+I2C_READ);
 data_l = i2c_readAck();
 data_h = i2c_readAck();
 pec = i2c_readNak();
 i2c_stop();
 data_t = (((data_h) << 8) + data_l);
 return data_t;
}

void writeAddress (int dev, int address, int LB, int HB, int pec){
 i2c_start_wait(dev+I2C_WRITE);
 i2c_write(address); // Should have 0x20 added beforehand!
 i2c_write(LB);  // LSB
 i2c_write(HB);  // MSB
 i2c_write(pec); // Checksum
 i2c_stop();
 delay(5);
}

void cycleMLX(int dev){
 i2c_start_wait(dev+I2C_WRITE);
 i2c_write(0xFF);  // Sleep command
 i2c_write(0xF3); // <- Checksum, corrected
 i2c_stop();
 delay(5);
}


[EDIT 12-24] Corrected two bad CRCs

pylon

I only have the DCI version of the sensor. Do you know if they have the same EEPROM content?

jay_ar

Hello Pylon,

I have no idea, but I think they just have very slight differences. In any case, I ended up buying a new MLX, and the first thing I plan to do is dump all the EEPROM positions. I guess it's Ok to post those numbers here so, if you upload yours, we can know the answer to your question. And help the next person who tries to use the "configuration sketch" with an Arduino Leonardo and/or doesn't write down the numbers :)

BTW: even if someone decide to use the configuration sketch with an Arduino Uno, there's something somewhat non kosher with the code. Namely, the sketch overwrites 100% of register 0x05, including some bits that MLX recommends not to touch. The correct way to do this would be to read 0x05, and use bitwise AND/OR to set/clear just the bits we need without changing the others. If I decide to change those bits in my new sensor that's what I'll do, anyway.

jay_ar

#3
Dec 24, 2012, 10:22 am Last Edit: Dec 24, 2012, 10:28 am by jay_ar Reason: 1
Ok... the new MLX90614ESF-BCI is in, and the EEPROM dump is done. Here are the relevant registers (the positions that can be written by the user):
00: 9993 -> ToMax
01: 62E3 -> ToMin
02: 0201 -> PWMCTRL
03: F71C -> Ta Range
04: FFFF -> Emissivity
05: 9F75 -> Config register
0E: BE5A -> SMBus address (LSB only)
0F: 0800 -> Melexis reserved
09: D15A -> ????

Almost all of these registers are the same between the two sensors. The only exception at this point is 0x09 (undocumented), where I think the calibration is stored somehow. Which is relevant because once I fed these new numbers into my older sensor it's sort-of-working again... except now the temperature is just 3~4°C off. I can live with that (the important thing for me is the difference between measured temperatures, not the absolute temperature of any particular point), but correcting it would be nice.

Anyway... if anyone decides to post his/her numbers it would be interesting.

I found why one particular memory position wasn't being written. I checked the new values time and time again, including the CRC, and everything looked fine, so I didn't know what was going on. Well... before anything gets written to any register, that register must be zeroed... and that process ALSO has a CRC, which for one particular register (0x01) was not correct in my code. That made the zero-ing to fail, which in turn prevented the new value from being written. After changing the CRC (and another one on the cycling) everything seems to be working fine.

PD: be VERY careful when messing with register 0x05... from the literature changing bit #3 makes the factory calibration to get out of whack



Chrisprols

Hi jay_ar !

I found the project http://www.cheap-thermocam.tk/ a few days ago and planning to do it.
I got an arduino uno and a MLX90614ESF-DCI coming.

First thing, if you have any input on the following post, that would be very much appreciated :
http://arduino.cc/forum/index.php/topic,141280.0.html

Secondly, you are saying the configuration code (and maybe the main sketch as well) is not well written (and maybe even not working).
Would you have another code I can run ?
What is the difference between a code you can run on your due and on I could run on my uno ?
Could you share the code to dump a complete EEPROM configuration and the one to reload it ?
By curiosity : what project are you working on ?

Many thanks !!

pylon

Quote
I found the project http://www.cheap-thermocam.tk/ a few days ago and planning to do it.
I got an arduino uno and a MLX90614ESF-DCI coming.


Great, I've done that project too and it runs perfectly.

Quote
First thing, if you have any input on the following post, that would be very much appreciated


What's your problem with that post? The original poster there wasn't sure about libraries to be used. But this isn't a problem if you rebuild a project and use the available code.

Quote
Secondly, you are saying the configuration code (and maybe the main sketch as well) is not well written (and maybe even not working).


It's not badly written, it's just not that pretty code. But it works OK if you do the same thing as the original author. If you change a component you either should know what that means to your project or you better ask in the forum.

Quote
Would you have another code I can run ?


That's not necessary, the code runs OK on the specified hardware and the described wiring.

Quote
What is the difference between a code you can run on your due and on I could run on my uno ?


jay_ar wasn't running it on a Due but on a Leonardo. The Leonardo hasn't the hardware I2C wired to pins A4 and A5 as the UNO has, that was his error. If you're using an UNO you could follow the description on the website.



Chrisprols

Hi !

Thanks for your answer.
As you advised, I ordered pretty much all the same parts. Now I'm just waiting for them to arrive. Then I'll try that project.

I didn't know about the differences between Uno, Due and Leonardo.

Thanks and have a great day,

jay_ar

Hello people :)

I'm writing a (dreadly late) reply just to clarify something:

As Pylon says, I used a different Arduino (a Leonardo) to put together the circuit. However, my error was not having the I2C pins wired incorrectly, but rather the fact that the code (written for the Uno) assumes the serial connection with the PC stays on the whole time during the boot sequence. Alas, on the Leonardo this is NOT true, and as a consequence you miss that nice warning saying "please store these values because you can messup things big time". By the time the serial connection between the board and the arduino was reestablished the damage was already done (the overwriting of the parameters had failed and I didn't have the original values anywhere to restore them). I just added a "wait until serial is established" at the beginning of the code to make sure I didn't miss anything being sent to the PC... and then changed a lot of other things on the code, if just to know what was going on :) "My" code is the one listed in the original post (compare it against the original one and you'll see some minor differences).

As mentioned before, the original configuration code has a few quirks. Again, as Pylon says, the "problem" is that the coding is not the nicest one. Specifically, Melexis says not to overwrite some of the bits in one of the registers, and the codes overwrite them without making any attempt to read what was there originally. This may be Ok as long as the bits on your sensor are the same as the ones on the sensor the author had, but nothing guarantees that. Please note I did NOT correct this, because I didn't find a way to implement the CRC computation inside the arduino.

I found some other issues with the sequence the code uses to overwrite the registers, but I think it's just cosmetic.

Go Up