I read through 4-5 threads where people were connecting MLX90620 thermopile arrays to their arduino's. In one thread there was some sample code that used an external I2C library called I2CMaster. I'm very new to Arduino and had originally attempted to code this using the built-in Wire library. However my code doesn't seem to work and I think it might be because the Wire library doesn't support the type of communication I need.
The datasheet for the MLX90620 shows that the I2C communications for a read should go like this:
When I run the above, it runs as far as the last '.' but never prints the '!', indicating it is waiting on the Wire.available() call. Now I am suspecting that the Wire.requestFrom() call is not sending the second START signal. I think this because the I2CMaster code had a call to i2c_rep_start() which sounds like the repeated start signal in the middle of the sequence. Am I correct in assuming that? Or is the problem that the frequency is incorrect (I don't know if I2C negotiates speed, I doubt it does)
Wire.requestFrom returns the number of bytes obtained.
I am following what is documented at Wire - Arduino Reference which indicates that Wire.requestFrom() does not have a return value.
BTW 0x40 is not "40 sensors". It is 64. 0x40 is hex.
There are 64 pixels in this device, 4 rows of 16. So 0x40 is actually what I want. I'm well aware of Hex, thanks. I slipped in the comments. A cursory google for the MLX90620 indicates it is a 64 element array.
The Wire buffer is 32 bytes. It can never return 64 bytes.
I'll overlook that you used the word 'return' when you clearly meant 'buffered'. Since the Wire library only buffers 32 bytes I guess I am forced to make two calls to Wire.requestFrom(), each for half of my original request. (in fact, I believe each pixel actually is recorded as two bytes so I'll have to make 4 calls).
I will look into the link you left. I quickly scanned it and I see it has a shapshot from a logic analyzer. This will be useful as I managed to capture the conversation on an oscilloscope while I was at the lab. In the future, try to be a bit less hostile towards people who are new with respect to a technology (and don't assume they know nothing about programming). The 32 byte buffer is not documented on the Wire.requestFrom() documentation so anyone new to the library would have made that mistake.
I'm wondering if the 'restart' mentioned in the Wire.requestFrom() description is identical to the second 'start' signal specified in the datasheet for the MLX90620 on page 28 where the read conversation is illustrated. If so then I believe I should pass false as the optional parameter. I will run the Scanner program that you linked to later today to ensure my circuit setup is correct and then I will proceed to test my program, with alterations to adjust the call to Wire.requestFrom(false) and possibly another to remove the while(!Wire.available()) loop, despite it not really hurting if left in.
Vitus:
I am following what is documented at Wire - Arduino Reference which indicates that Wire.requestFrom() does not have a return value.
Thank you for pointing that out. I have raised an error report over this:
The Wire buffer is 32 bytes. It can never return 64 bytes.
I'll overlook that you used the word 'return' when you clearly meant 'buffered'.
Put it this way, Wire.requestFrom will never return 64.
Since the Wire library only buffers 32 bytes I guess I am forced to make two calls to Wire.requestFrom(), each for half of my original request. (in fact, I believe each pixel actually is recorded as two bytes so I'll have to make 4 calls).
That's probably wise, although you can edit two files and increase the buffer size. Be warned that whatever size you choose, it makes 5 of them. So a buffer of 32 already uses 160 bytes of your RAM.
The 32 byte buffer is not documented on the Wire.requestFrom() documentation so anyone new to the library would have made that mistake.
I wasn't trying to accuse you. I was pointing out things I found out for myself the hard way.
The limitation also applies to sending (beginTransmission ... endTransmission) as well. The documentation is incomplete in that respect. That applies to other things, like the size of the serial buffer.
Vitus:
... and possibly another to remove the while(!Wire.available()) loop, despite it not really hurting if left in.
It can hurt because, first it does nothing useful, and second, if nothing (zero) is returned by Wire.requestFrom (bus arbitration issue, device not on or something) then that loop will make your code hang forever, which presumably you don't want.
The correct test is to check the return value from Wire.requestFrom, and not to test for Wire.available.
I was looking through the datasheet for the MLX90620 and if I read it correctly it wants the I2C bus to run at 1Mhz. Now I'm not certain if that has to match the arduino exactly or not (I imagine it should). The arduino cannot run the I2C that fast, as if you do the TWBR calculation you get 0. Now the wikipedia for I2C says that devices can hold the clock line low as needed. With that in mind, will the arduino hold the clock and run it at 400 Mhz? Or will I have to find a way to change the MLX90620's preferred frequency.
Yesterday I built a level shifter using a CD4007UBE transistor package and some 4004 diodes. I hooked up the arduino and the thermopile array and I was not getting any useful results with the I2C Scanner. I varied the pull-up resistor values but I realized today that we did use low enough values (10K was what we had), so I'll go back today and try 2.2K.
Ok, I built and verified my level shifter using 10K pull up resistors. I followed the schematic exactly, except I left out the pull up resistors on the Arduino side because they are internal (If I left them in the voltage on SDA and SCL dropped to 1.5ish volts).
The results of running the I2C scanner example are that all odd numbered addresses from 1 to 0x77 are found to have devices on them. That seems odd, but I can't imagine why it would be so. Sadly I don't have any other I2C devices with which to test this besides the MLX90620.
Schematic: http://tinyurl.com/BiLvlShftr
Rp = 10K (removed on the 5V side)
Vdd1=2.5V (Aglient DC Power Supply)
Vdd2=5.0V (Aglient DC Power Supply)
The Arduino's GND is attached to the COM and GND on the Aglient DC Power Supply.
The address should be shifted right one, so although the datasheet says 0x60 for the IR data and 0x50 for the EEPROM, in your code you want 0x30 for the IR and 0x28 for the EEPROM.
The master is addressing the slave device by sending an 7-bit slave address after the START condition. The first seven bits are dedicated for the address and the 8th is Read/Write (R/W) bit. This bit indicates the direction of the transfer:
Read (HIGH) means that the master will read the data from the slave
Write (LOW) means that the master will send data to the slave Mlx90620 is responding to 2 different slave addresses:
OK, I guess I had changed the I2C Scanner code in some way (or my partner did when I wasn't looking). I recopied it from the site and the following address are occupied. So, on to step 2 - my own code. I will report back with results.
I2C Scanner
Scanning...
I2C device found at address 0x50 !
I2C device found at address 0x51 !
I2C device found at address 0x52 !
I2C device found at address 0x53 !
I2C device found at address 0x54 !
I2C device found at address 0x55 !
I2C device found at address 0x56 !
I2C device found at address 0x57 !
I2C device found at address 0x60 !
done
I don't see any functional difference between the scanner you linked to and the one at Arduino Playground - I2cScanner. If/when I transition to a different library (as this topic's title specifically mentions using the Wire library) I will keep the 7 vs. 8-bit addressing in mind. I understand there are some issues with the Wire library hanging. If it is unable to formulate messages in the manner I need or I experience hangs I transition to I2CMaster or another I2C library. Until then, I'd like to keep it simple and work with the built-in libraries , just to get my feet wet.
It looks like the Wire library will in no way work for communicating with this device because of the repeated start signal that Wire can't perform. I switched to using the I2C library located in the link below. I'm using revision 5 of that library. I have achieved the reading of raw values from the sensors, so now I just need to convert those into real temperatures. That will be a topic for a different thread. The final code I used is below.