Kevin Braun / MLX9062x

Dependents:   KL25Z_MLX90620

MLX90620.cpp

Committer:
loopsva
Date:
2016-06-14
Revision:
0:8c2ddd9801ca
Child:
1:fd536ebc7eaf

File content as of revision 0:8c2ddd9801ca:

//NOTE:  "Step Measurement Mode" was removed from new MLX90620 data sheet, page 22 dated Sept 19 2012
//       which is used in this implementation

#include "mbed.h"
#include "MLX90620.h"

//these bufferes must reside in main.cpp
//extern char* MLXEEbuf;                         //256 uint8_ts, holds contents of EEPROM
//extern char* MLXRamBuf;                        //128 uint8_ts, 0x0 - 0x3f 'uint16_t', holds contents of RAM array
//extern char* MLXRamCmmd;                       //  8 uint8_ts, MLX90620 i2c command i/o buffer
/*
uint16_t Config = 0;                  //MLX90620 configuration register
uint16_t OscTrim = 0;                 //MLX90620 oscillator trim register
uint16_t PtatD = 0;                   //MLX90620 PTAT data register
int16_t VCP = 0;                              //VCP / TGC
int16_t Vth25X = 0;
float TaXX = 0.0;

//For To
int8_t AcpX = 0;
int8_t BcpX = 0;
float Kt1fX = 0.0;
float Kt2fX = 0.0;
int8_t TGCX = 0;
uint8_t BiScaleX = 0;
uint16_t theta0X = 0;
uint8_t theta0ScaleX = 0;
uint8_t deltaThetaScaleX = 0;
uint16_t elipsonX = 0;
int8_t AiPixelX = 0;                   //eeprom address range 0x00 - 0x3f
int8_t BiPixelX = 0;                   //eeprom address range 0x40 - 0x7f
uint8_t dThetaPixelX = 0;                      //eeprom address range 0x80 - 0xbf
int16_t VirPixelX = 0;
double TempPxlX = 0;
*/

//--------------------------------------------------------------------------------------------------------------------------------------//
// Constructor

MLX90620::MLX90620(PinName sda, PinName scl, const char* name) : _i2c(sda, scl){
    _i2c.frequency(400000);                             //set up i2c speed
    _i2c.stop();                                        //initialize with a stop
}

//--------------------------------------------------------------------------------------------------------------------------------------//
//copy contents of EEPROM inside the MLX90620 into a local buffer.  Data is used for lookup tables and parameters

#define MLX_EEP_EASY_LOAD        1

int MLX90620::LoadEEPROM(mlx_struct& Pntr) {
    
    //clear out buffer first
    for(int i = 0; i < 256; i++) {                      //option to clear out EEPROM buffer first
        Pntr.MLXEEbuf[i] = 0;
    }
    
    //load the entire EEPROM
    Pntr.MLXEEbuf[0] = 0;                                       //start at address 0 of EEPROM
    if(!_i2c.write(MLX_EEPADDR, Pntr.MLXEEbuf, 1, true)) {      //send command, 0 returned is ok

#ifdef MLX_EEP_EASY_LOAD
        _i2c.read((MLX_EEPADDR + 1), Pntr.MLXEEbuf, 256);             //**** this command does not work with the KL25Z anv v63 of mbed.lbr !!!!  //load contents of EEPROM
#else
        _i2c.start();
        _i2c.write(MLX_EEPADDR + 1);
        for(int i = 0; i < 256; i++) {
            Pntr.MLXEEbuf[i] = _i2c.read(1);
        }
        _i2c.stop();
#endif

    } else {
        _i2c.stop();                                    //don't read EEP if write is broken
        return(1);                                      //return with error
    }
    return(0);                                          //return with ok
}

//--------------------------------------------------------------------------------------------------------------------------------------//
//copy oscillator offset from MLXEEbuf to MLX90620 (MS byte = 0)

int MLX90620::SetOscTrimReg(mlx_struct& Pntr) { 
    Pntr.MLXRamCmmd[0] = 4;                                     //command
    Pntr.MLXRamCmmd[1] = Pntr.MLXEEbuf[MLX_EETRIM] - 0xaa;              //LS byte check
    Pntr.MLXRamCmmd[2] = Pntr.MLXEEbuf[MLX_EETRIM];                     //oscillator trim value
    Pntr.MLXRamCmmd[3] = 0x100 - 0xaa;                          //MS byte check
    Pntr.MLXRamCmmd[4] = 0;                                     //MS byte = 0
    int r = _i2c.write(MLX_RAMADDR, Pntr.MLXRamCmmd, 5, false); //send command
    return(r);                                          //return ok or error
}

//--------------------------------------------------------------------------------------------------------------------------------------//
//get oscillator offset register from MLX90620

uint16_t MLX90620::GetOscTrimReg(mlx_struct& Pntr) { 
    Pntr.MLXRamCmmd[0] = 2;                                     //command
    Pntr.MLXRamCmmd[1] = MLX_TRIM;                              //address of register
    Pntr.MLXRamCmmd[2] = 0;                                     //address step
    Pntr.MLXRamCmmd[3] = 1;                                     //# of reads
    _i2c.write(MLX_RAMADDR, Pntr.MLXRamCmmd, 4, true);          //send command  
    _i2c.read(MLX_RAMADDR, Pntr.MLXRamCmmd, 2);                 //get 16 bit register
    Pntr.OscTrim = (Pntr.MLXRamCmmd[1] << 8) + Pntr.MLXRamCmmd[0];           //store register
    return(Pntr.OscTrim);                                    //return value
}

//--------------------------------------------------------------------------------------------------------------------------------------//
//initialize the configuration register
//******* NOTE: Step measurement mode was removed from new data sheet dated   Sept 19 2012

int MLX90620::SetConfigReg(mlx_struct& Pntr) {   
    Pntr.MLXRamCmmd[0] = 3;                                     //command
    //old mode
    //MLXRamCmmd[1] = 0x14c - 0x55;                          //LS byte check
    //MLXRamCmmd[2] = 0x4c;                                  //LS config value, step meas mode, 4Hz array  *******
    Pntr.MLXRamCmmd[1] = 0x10c - 0x55;                          //LS byte check
    Pntr.MLXRamCmmd[2] = 0x0c;                                  //LS config value, normal mode, 4Hz array  *******
    Pntr.MLXRamCmmd[3] = 0x5c - 0x55;                           //MS byte check
    Pntr.MLXRamCmmd[4] = 0x5c;                                  //MS config value, 8Hz Ta, 400k i2c
    int r = _i2c.write(MLX_RAMADDR, Pntr.MLXRamCmmd, 5, false);
    return(r);
}

//--------------------------------------------------------------------------------------------------------------------------------------//
//get configuration register from MLX90620

uint16_t MLX90620::GetConfigReg(mlx_struct& Pntr) { 
    Pntr.MLXRamCmmd[0] = 2;                                     //command
    Pntr.MLXRamCmmd[1] = MLX_CONFIG;                            //address of register
    Pntr.MLXRamCmmd[2] = 0;                                     //address step
    Pntr.MLXRamCmmd[3] = 1;                                     //# of reads
    _i2c.write(MLX_RAMADDR, Pntr.MLXRamCmmd, 4, true); 
    _i2c.read(MLX_RAMADDR, Pntr.MLXRamCmmd, 2);
    Pntr.Config = (Pntr.MLXRamCmmd[1] << 8) + Pntr.MLXRamCmmd[0];
    return(Pntr.Config);
}

//--------------------------------------------------------------------------------------------------------------------------------------//
//get PTAT register from MLX90620

uint16_t MLX90620::GetPTATReg(mlx_struct& Pntr) { 
    Pntr.MLXRamCmmd[0] = 2;                                     //command
    Pntr.MLXRamCmmd[1] = MLX_PTATSENS;                          //address of register
    Pntr.MLXRamCmmd[2] = 0;                                     //address step
    Pntr.MLXRamCmmd[3] = 1;                                     //# of reads
    _i2c.write(MLX_RAMADDR, Pntr.MLXRamCmmd, 4, true); 
    _i2c.read(MLX_RAMADDR, Pntr.MLXRamCmmd, 2);
    Pntr.PtatD = (Pntr.MLXRamCmmd[1] << 8) + Pntr.MLXRamCmmd[0];
    return(Pntr.PtatD);
}

//--------------------------------------------------------------------------------------------------------------------------------------//
//get VCP / TGC register from MLX90620

int16_t MLX90620::GetTGCReg(mlx_struct& Pntr) { 
    Pntr.MLXRamCmmd[0] = 2;                                     //command
    Pntr.MLXRamCmmd[1] = MLX_TGCSENS;                           //address of register
    Pntr.MLXRamCmmd[2] = 0;                                     //address step
    Pntr.MLXRamCmmd[3] = 1;                                     //# of reads
    _i2c.write(MLX_RAMADDR, Pntr.MLXRamCmmd, 4, true);
    _i2c.read(MLX_RAMADDR, Pntr.MLXRamCmmd, 2); 
    VCP = (Pntr.MLXRamCmmd[1] << 8) + Pntr.MLXRamCmmd[0];
    return(VCP);
}

//--------------------------------------------------------------------------------------------------------------------------------------//
//get RAM dump from MLX90620
bool firstDump = false;

void MLX90620::LoadMLXRam(mlx_struct& Pntr) { 
    Pntr.MLXRamCmmd[0] = 2;                                     //command
    Pntr.MLXRamCmmd[1] = 0;                                     //start address
    Pntr.MLXRamCmmd[2] = 1;                                     //address step
    Pntr.MLXRamCmmd[3] = 0x40;                                  //# of reads
    _i2c.write(MLX_RAMADDR, Pntr.MLXRamCmmd, 4, true);
    _i2c.read(MLX_RAMADDR, Pntr.MLXRamBuf, 0x80); 
    Pntr.PtatD = MLX90620::GetPTATReg(Pntr);
    VCP = MLX90620::GetTGCReg(Pntr);
}

//--------------------------------------------------------------------------------------------------------------------------------------//
//start measurement MLX90620

int MLX90620::StartMeasurement(mlx_struct& Pntr) {   
    Pntr.MLXRamCmmd[0] = 1;                                     //command
    Pntr.MLXRamCmmd[1] = 8;                                     //address of config register
    int r = _i2c.write(MLX_RAMADDR, Pntr.MLXRamCmmd, 2, false);
    return(r);
}

//--------------------------------------------------------------------------------------------------------------------------------------//
// Initial Calculations for Ta and To

float MLX90620::GetDieTemp(mlx_struct& Pntr) {
    Pntr.PtatD = MLX90620::GetPTATReg(Pntr);
    float TaX = (-Kt1fX + sqrt(pow(Kt1fX, 2.0f) - 4.0f * Kt2fX * ((float)(Vth25X - Pntr.PtatD))))/(2.0f * Kt2fX) + 25.0f;
    return(TaX);
}

//--------------------------------------------------------------------------------------------------------------------------------------//
// Initial Calculations for Ta and To

void MLX90620::CalcTa_To(mlx_struct& Pntr) {
    //Calculate Ta first
    Vth25X =      (Pntr.MLXEEbuf[MLX_TAINDEX +  1] << 8) + Pntr.MLXEEbuf[MLX_TAINDEX +  0];
    int16_t Kt1 = (Pntr.MLXEEbuf[MLX_TAINDEX +  3] << 8) + Pntr.MLXEEbuf[MLX_TAINDEX +  2];
    int16_t Kt2 = (Pntr.MLXEEbuf[MLX_TAINDEX +  5] << 8) + Pntr.MLXEEbuf[MLX_TAINDEX +  4];
    Kt1fX = Kt1 / 1024.0;
    Kt2fX = Kt2 / 1048576.0;
    TaXX = MLX90620::GetDieTemp(Pntr);
    
    //Calculate To
    AcpX =              Pntr.MLXEEbuf[MLX_TOINDEX +  0];
    BcpX =              Pntr.MLXEEbuf[MLX_TOINDEX +  1];
//    uint16_t thetaCPX = (EEbuf[MLX_TOINDEX + 3] << 8) + MLXEEbuf[MLX_TOINDEX + 2];
    TGCX =              Pntr.MLXEEbuf[MLX_TOINDEX +  4];
    BiScaleX =          Pntr.MLXEEbuf[MLX_TOINDEX +  5];
    theta0X =          (Pntr.MLXEEbuf[MLX_TOINDEX + 13] << 8) + Pntr.MLXEEbuf[MLX_TOINDEX + 12];
    theta0ScaleX =      Pntr.MLXEEbuf[MLX_TOINDEX + 14];
    deltaThetaScaleX =  Pntr.MLXEEbuf[MLX_TOINDEX + 15];
    elipsonX =         (Pntr.MLXEEbuf[MLX_TOINDEX + 17] << 8) + Pntr.MLXEEbuf[MLX_TOINDEX + 16];
/*
        printf("Vth(25) = %6d 0x%x\nTa1     = %6d 0x%x\nTa2     = %6d 0x%x\n", Vth25X, Vth25X, Kt1, Kt1, Kt2, Kt2);
        printf("Kt1fX   = %f\nKt2fX   = %f\nTaXX    = %f\n\n", Kt1fX, Kt2fX, TaXX);
        printf("Acp     = %6d 0x%x\nBcp     = %6d 0x%x\nThCP    = %6d 0x%x\n", AcpX, AcpX, BcpX, BcpX, thetaCPX, thetaCPX); 
        printf("TGC     = %6d 0x%x\nBiS     = %6d 0x%x\nTh0     = %6d 0x%x\n", TGCX, TGCX, BiScaleX, BiScaleX, theta0X, theta0X);   
        printf("T0s     = %6d 0x%x\nDts     = %6d 0x%x\nelip    = %6d 0x%x\n\n", theta0ScaleX, theta0ScaleX, deltaThetaScaleX, deltaThetaScaleX, elipsonX, elipsonX);   
*/
}

//--------------------------------------------------------------------------------------------------------------------------------------//
// Pixel Temperature Calculation

double MLX90620::CalcPixel(mlx_struct& Pntr, int Pixel) {
    AiPixelX = Pntr.MLXEEbuf[Pixel];                                        //eeprom address range 0x00 - 0x3f
    BiPixelX = Pntr.MLXEEbuf[Pixel + 0x40];                                 //eeprom address range 0x40 - 0x7f
    dThetaPixelX = Pntr.MLXEEbuf[Pixel + 0x80];                             //eeprom address range 0x08 - 0xbf
    VirPixelX = (Pntr.MLXRamBuf[Pixel * 2 + 1] << 8) + Pntr.MLXRamBuf[Pixel * 2];   //ram address range 0x000 - 0x08f, 16b
    float Vcp_off_comp = VCP - (AcpX + BcpX / powf(2.0f,BiScaleX) * (TaXX - 25.0f));
    float VirPixel_off_comp = VirPixelX - (AiPixelX + BiPixelX / powf(2.0f,BiScaleX) * (TaXX - 25.0f));
    float VirPixel_off_comp2 = (float(AiPixelX) + float(BiPixelX) / float(1 << BiScaleX) * (TaXX - 25.0f));
    VirPixel_off_comp2 = VirPixelX - VirPixel_off_comp2;
    float VirPixel_tgc_comp = VirPixel_off_comp - TGCX / 32.0 * Vcp_off_comp;
    float elipsonf = elipsonX / 32768.0;
    float VirPixel_comp = VirPixel_tgc_comp / elipsonf;
    double theta28 = theta0X / powf(2.0, theta0ScaleX) + dThetaPixelX / powf(2.0, deltaThetaScaleX);
    double TempPxl = powf((VirPixel_comp / theta28 + powf((TaXX + 273.15f), 4.0f)), (1.0f / 4.0f)) - 273.15f;
/*
        printf("\r\n\r\npixel = %d\r\n", Pixel);
        printf("Acp   = %d\r\nBcp   = %d\r\nBiS   = %d\r\n", AcpX, BcpX, BiScaleX);
        printf("Vcp   = %d\r\neps   = %d\r\nTGC   = %d\r\n", VCP, elipsonX, TGCX);
        printf("Vcp_off_comp             = %f\r\n", Vcp_off_comp);
        printf("VirPixel_off_comp        = %f\r\n", VirPixel_off_comp);
        printf("VirPixel                 = %d\r\n", VirPixelX);
        printf("AiPixel                  = %d\r\n", AiPixelX);
        printf("BiPixel                  = %d\r\n", BiPixelX);
        printf("BiScale                  = %d\r\n", BiScaleX);
        printf("2^BiScale                = %f\r\n", (powf(2.0,BiScaleX)));
        printf("1 << BiScale             = %d\r\n", (1 << BiScaleX));
        printf("Ta-25.0                  = %f\r\n", (TaXX - 25.0f));
        printf("BiPix/2^BiScale          = %f\r\n", (BiPixelX / powf(2.0,BiScaleX)));
        printf("AiP+BiP/2^BiScale)*(Ta-25= %f\r\n", (AiPixelX + BiPixelX / powf(2.0,BiScaleX) * (TaXX - 25.0f)));
        printf("VirPixel_off_comp again  = %f\r\n", (VirPixelX - (AiPixelX + BiPixelX / powf(2.0,BiScaleX) * (TaXX - 25.0f))));
        printf("VirPixel_off_comp2 step  = %f\r\n", VirPixel_off_comp2);
        printf("VirPixel_tgc_comp        = %f\r\n", VirPixel_tgc_comp);
        printf("elipsonf                 = %f\r\n", elipsonf);
        printf("VirPixel_comp            = %f\r\n", VirPixel_comp);
        printf("theta28                  = %f  << double print problem\r\n", (theta28 * 100000000.0));  //<<< can't print a double
        printf("TempPxl                  = %f\r\n",  TempPxl);
*/
    return(TempPxl);
}