Driver for the Melexis MLX90620 infrared temperature sensor array. 64 pixels in a 16 x 4 format. Updated driver for KL25Z

Dependents:   lpc812_mlx90620

Melexis MLX90620 home page:

Note: I had to delete the original repository and start a new one due to issues I had with publishing. It should be at Rev 2, but it starts fresh at Rev 0. The reason for the new revision was basic ic2 command cleanup in order to work with the KL25Z board.

The datasheet for the MLX90620 can be found here: http://www.melexis.com/MLX90620

Note that the conversion-start process that is used in the mbed driver, the "Step" mode in section 9.3.2, is not longer in the datasheet. It was last described in the datasheet dated 20120620. Step mode was bit 6 of the Configuration Register 0x92, section 8.2.2.1, Table 10. Melexis claims that the temperature readings were not as accurate as the back-to-back-to-back "Normal" continous conversion method.

However, in my main.cpp code, I do start another conversion immediately after the current conversion completes and all of the sensor array RAM values have been read. Then, I perform all of the floating point math and update the display while the new conversion is taking place. At 4 conversions per second using the KL25Z board, there is about 110mS of idle time before the new conversion is ready to be read out. Reading bits 8 and 9 in the Configuration Register tell you when it is time to read the sensor array RAM values.

The datasheet says the the MLX90620 needs to operate at 2.6V for best performance (certain versions can operate up to 3.0V). Use an LDO from 3.3V to generate 2.6V. Though you could use a regular diode to drop 3.3V to 2.6V, it is not consistent from diode-to-diode and the voltage drop will vary with temperature. I highly recommend using an LDO. And don't forget to use bypass caps!!! BTW: Though the device VCC is limited to 2.6V, the i2c I/O pins can operate at 3.3V.

With an mbed1768, the MLX90620 operates with an i2c frequency of 400KHz and 4 feet of 4-wire cable. I have not tried 4 feet on the KL25Z, but it does work at 1 foot. The i2c pullup resistors are 2.2k.

In the overall program that I use for the MLX90620 (to be published), an mbed1768 can run with a USB Serial output of 921600 baud, whereas the KL25Z is limited to 115200 baud. Anything faster on the KL25Z, output characters get dropped.

...kevin

MLX90620.h

Committer:
loopsva
Date:
2013-07-29
Revision:
0:a86b8d0294ee

File content as of revision 0:a86b8d0294ee:

#ifndef MLX90620_H
#define MLX90620_H

#include "mbed.h"

/** Software routines to access the Melexis MLX90620 64 pixel (4 X 16) infrared sensor array
 *   The MLX90620's internal RAM has different i2c behavior than it's internal EEPROM
 *   As a result, the MLX90620's RAM uses more primitive mbed i2c commands than does the EEPROM.
 *
 * @code
 * #include "mbed.h"
 * #include "MLX90620.h" 
 *
 * char* EEbuf = new char[256];     //buffer for contents of EEPROM
 * char* RamCmmd = new char[8];     //holds / sends MLX90620 RAM commands
 * char* RamBuf = new char[128];    //0x3f words, values are 'unsigned short'
 *
 * Serial pc(USBTX, USBRX);
 * MLX90620 mlx(p9, p10, "mlx");
 * //MLX90620 mlx(PTE0, PTE1, "mlx");
 *
 * float Ta = 0.0;
 * float TempPxl = 0.0;
 *
 *
 * int main() {
 *     pc.baud(115200); 
 *     mlx.LoadEEPROM();         //if returns non 0, MLX90620 may not be unconnected to i2c bus
 *     mlx.SetOscTrimReg();      //if returns non 0, MLX90620 is having RAM access problems with i2c bus
 *     mlx.SetConfigReg();       //if returns non 0, WTF?? - shouldn't be any i2c problems at this point
 *     mlx.StartMeasurement();   //if returns non 0, WTF??
 *     wait(0.5);
 *     mlx.CalcTa_To();          //if returns non 0, WTF??
 *     Ta = mlx.GetDieTemp();
 *     pc.printf("\nTa = %f\n\n", Ta);
 *     //simplistic dump of pixel array. Any terminal character 
 *     //generates another acquisition cycle. 
 *     //allows the program to run at maximum refresh rate of 4Hz
 *     //In order to save time, mlx.StartMeasurement(); is done
 *     //just after mlx.GetMLXRam();. This way the CPU can process 
 *     //lots of floating math while the MLX90620 gets another round.
 *     while(1) {
 *         int config = mlx.GetConfigReg();
 *         int chk = config & 0x0300;
 *         if(chk == 0) {
 *             pc.printf("\nIR Array Capture\n");
 *             mlx.LoadMLXRam();         //if returns 0, WTF??
 *             mlx.StartMeasurement();   //if returns 0, WTF??
 *             for(int i = 0; i < 64; i++) {
 *                 TempPxl = mlx.CalcPixel(i);
 *                 pc.printf("Pix %2d   Temp %.3f\n", i, TempPxl);
 *             }
 *         } else {
 *             wait_ms(100);
 *         }
 *     }
 *}
 * @endcode
 */
/* MLX90620 controller class
 */
class MLX90620 {

public:

    /** Create a MLX90620 object using the specified I2C object
     *
     * @param constructor, - the I2C object to communicate with
     */
    MLX90620(PinName sda, PinName scl, const char* name);

    
    /** Copy the contents of the MLX90620 EEPROM into local buffer for later use
     *    Returns '1' if i2c error, '0' if ok.
     *  Only done at initialization.  MUST be the first thing you do in MAIN.
     * 
     * @param NONE, - loads all 256 bytes from EEPROM into local buffer
     */
    int LoadEEPROM();

    
    /** Initialize the MLX90620's Oscillator Trim Register 
     *    Data is derived from values received from the EEPROM
     *    Returns '1' if i2c error, '0' if ok.
     *  Register is only set once during initialization
     *
     * @param NONE, - 7 lsb bits from 16 bit value, set by EEPROM value at initialization
     */
    int SetOscTrimReg();

    
    /** Get the MLX90620's Oscillator Trim Register
     *    Returns the Oscillator Trim Register value
     * 
     * @param NONE, - 7 lsb bits from 16 bit value, Read from MLX RAM
     */
    unsigned short GetOscTrimReg();

    
    /** Set the MLX90620's Configuration Register
     *    Returns '0' if i2c error, '1' if ok.
     *  Register is set only during initialization. Inital setup:
     *  1. ADC low reference
     *  2. Ta Ref Rate 8Hz
     *  3. I2C FM+ mode enabled
     *  4. MD / Brownout bit set
     *  5. Normal Operation (non-Sleep) mode
     *  6. Step(Melexis reserved) mode. (removed from later datasheets, but used in this code)
     *  7. IR refresh rate 4Hz
     *  
     * @param NONE, - 16 bit value set by code at initialization
     */
    int SetConfigReg();

    
    /** Get the MLX90620's Configuration Register 
     *    Returns the Configuration Register value
     *  periodic check for Ta ready, IR Array ready and brownout conditions
     *
     * @param returns unsigned short, - 16 bit value, Read from MLX RAM
     */
    unsigned short GetConfigReg();

    
    /** Get the MLX90620's PTAT register. Register read at every Ta cycle
     *    Returns the Proportional To Ambient Temperature Register value
     *
     * @param returns unsigned short, - 16 bit value, PTAT sensor, Read from MLX RAM
     */
    unsigned short GetPTATReg();

    
    /** Get the MLX90620's TGC register
     *    Returns the Temperature Gradient Coefficient Register value
     *
     * @param returns short, - 16 bit value, TGC, Read from MLX RAM
     */
    short GetTGCReg();

    
    /** Get the MLX90620's IR pixel array and dump into local buffer
     *    Returns nothing
     *
     * @param NONE, - loads IR Pixel array into buffer (0x7F bytes, 0x3f Pixels), Read from MLX RAM
     */
    void LoadMLXRam();

    
    /** Start a Ta and IR array conversion update cycle
     *    Returns '1' if i2c error, '0' if ok.
     *  Also calls GetPTATReg() and GetTGCReg()
     *
     * @param NONE, - MLX90620 starts aquiring data, takes about 250mS /w 4Hz refresh rate
     */
    int StartMeasurement();

    
    /** Get the MLX90620's die temperature in degC
     *    Returns MLX90620 die temperature
     *  Needs to be performed before every array update calculation
     *
     * @param returns, - float of die temperature of MLX90620 in degC
     */
    float GetDieTemp(); 

    
    /** Calculate initial MLX90620 offsets. Performed only at initialization
     *    Returns nothing
     *
     * @param NONE, - sets the MLX90620 with die correcting factors at initialization
     */
    void CalcTa_To();

    
    /** Calculate temperature of any pixel within the array (0 - 63)
     *  after an IR array dump into local buffer, 
     *
     * @param set int(0-63) of pixel to convert, returns double of temperature in degC of pixel
     */
    double CalcPixel(int Pixel);
    
private:
    I2C _i2c;                   //local i2c communication interface instance
    unsigned short Config;
    unsigned short OscTrim;
    unsigned short PtatD;
    short VCP;
    short Vth25X;
    signed char AcpX;
    signed char BcpX;
    float Kt1fX;
    float Kt2fX;
    float TaXX;
    signed char TGCX;
    char BiScaleX;
    unsigned short theta0X;
    char theta0ScaleX;
    char deltaThetaScaleX;
    unsigned short elipsonX;
    signed char AiPixelX;
    signed char BiPixelX;
    char dThetaPixelX;
    short VirPixelX;
    double TempPxlX;

}; 
 
#endif