Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
MLX90620.cpp
- Committer:
- loopsva
- Date:
- 2016-07-21
- Revision:
- 1:fd536ebc7eaf
- Parent:
- 0:8c2ddd9801ca
- Child:
- 2:82782c73251e
File content as of revision 1:fd536ebc7eaf:
//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"
//for debugging purposes (uncomment)
//#define MLXTEST_621b 1
//--------------------------------------------------------------------------------------------------------------------------------------//
// Original Constructor
MLX9062x::MLX9062x(PinName sda, PinName scl, const char* name) : _i2c(sda, scl){
_i2c.frequency(400000); //set up i2c speed
_i2c.stop(); //initialize with a stop
mlxDev = mlx90620; //default device is MLX90620
}
//--------------------------------------------------------------------------------------------------------------------------------------//
// Additional Constructor for selecting the MLX device
MLX9062x::MLX9062x(PinName sda, PinName scl, MLXdevice MLXtype, const char* name) : _i2c(sda, scl){
_i2c.frequency(400000); //set up i2c speed
_i2c.stop(); //initialize with a stop
mlxDev = MLXtype; //user select device 620 or 621
}
//--------------------------------------------------------------------------------------------------------------------------------------//
//copy contents of EEPROM inside the MLX9062x into a local buffer. Data is used for lookup tables and parameters
#define MLX_EEP_EASY_LOAD 1
int MLX9062x::LoadEEPROM(mlx_struct& Pntr) {
Pntr.mlx621IDhi = 0;
Pntr.mlx621IDlo = 0;
Pntr.mlxDevice = mlxDev; //make strurcture device same as local device
//clear out buffer first
for(int i = 0; i < 256; i++) Pntr.MLXEEbuf[i] = 0; //clear out entire EEMPROM buffer
//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 and v63 of mbed.lbr !!!!
#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
}
if(Pntr.mlxDevice == mlx90621) {
Pntr.mlx621IDhi = (Pntr.MLXEEbuf[MLX621_EE_ID_BASE + 7] << 24) | (Pntr.MLXEEbuf[MLX621_EE_ID_BASE + 6] << 16) |
(Pntr.MLXEEbuf[MLX621_EE_ID_BASE + 5] << 8) | Pntr.MLXEEbuf[MLX621_EE_ID_BASE + 4];
Pntr.mlx621IDlo = (Pntr.MLXEEbuf[MLX621_EE_ID_BASE + 3] << 24) | (Pntr.MLXEEbuf[MLX621_EE_ID_BASE + 2] << 16) |
(Pntr.MLXEEbuf[MLX621_EE_ID_BASE + 1] << 8) | Pntr.MLXEEbuf[MLX621_EE_ID_BASE + 0];
}
return(0); //return with ok
}
//--------------------------------------------------------------------------------------------------------------------------------------//
//copy oscillator offset from MLXEEbuf to MLX9062x (MS byte on 620 always = 0)
int MLX9062x::SetOscTrimReg(mlx_struct& Pntr) {
Pntr.MLXRamCmmd[0] = 4; //command
Pntr.MLXRamCmmd[1] = Pntr.MLXEEbuf[MLX620_EETRIM] - 0xaa; //LS byte check
Pntr.MLXRamCmmd[2] = Pntr.MLXEEbuf[MLX620_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
//printf("OscTrim-W: %02x %02x %02x %02x %02x\r\n", Pntr.MLXRamCmmd[0], Pntr.MLXRamCmmd[1], Pntr.MLXRamCmmd[2], Pntr.MLXRamCmmd[3], Pntr.MLXRamCmmd[4]);
return(r); //return ok or error
}
//--------------------------------------------------------------------------------------------------------------------------------------//
//get oscillator offset register from MLX9062x
uint16_t MLX9062x::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, false); //get 16 bit register
Pntr.OscTrim = (Pntr.MLXRamCmmd[1] << 8) + Pntr.MLXRamCmmd[0]; //store register
//printf("OscTrim-R: %02x %02x\r\n", Pntr.MLXRamCmmd[0], Pntr.MLXRamCmmd[1]);
return(Pntr.OscTrim); //return value
}
//--------------------------------------------------------------------------------------------------------------------------------------//
//initialize the configuration register
//******* NOTE: Step measurement mode was removed from new data sheet dated Sept 19 2012
int MLX9062x::SetConfigReg(mlx_struct& Pntr) {
Pntr.MLXRamCmmd[0] = 3; //command
if(Pntr.mlxDevice == mlx90621) {
Pntr.MLXRamCmmd[2] = Pntr.MLXEEbuf[MLX621_CONFIG_LO]; //LS byte
Pntr.MLXRamCmmd[4] = Pntr.MLXEEbuf[MLX621_CONFIG_HI]; //MS byte
//here you can manipulate the Config Register contents from the default EEPROM values of 0x463e
Pntr.MLXRamCmmd[2] = (Pntr.MLXRamCmmd[2] & ~MLX621_CONF_ADC_MASK) | MLX621_CONF_ADC18;
Pntr.MLXRamCmmd[4] = Pntr.MLXRamCmmd[4] | (MLX621_CONF_MD_1 >> 8);
Pntr.MLXRamCmmd[1] = Pntr.MLXRamCmmd[2] - 0x55; //LS byte check
Pntr.MLXRamCmmd[3] = Pntr.MLXRamCmmd[4] - 0x55; //MS byte check
} else {
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);
//printf("Command-W: %02x %02x %02x %02x %02x\r\n", Pntr.MLXRamCmmd[0], Pntr.MLXRamCmmd[1], Pntr.MLXRamCmmd[2], Pntr.MLXRamCmmd[3], Pntr.MLXRamCmmd[4]);
return(r);
}
//--------------------------------------------------------------------------------------------------------------------------------------//
//get configuration register from MLX9062x
uint16_t MLX9062x::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 MLX9062x
uint16_t MLX9062x::GetPTATReg(mlx_struct& Pntr) {
Pntr.MLXRamCmmd[0] = 2; //command
Pntr.MLXRamCmmd[1] = MLX620_PTATSENS; //address of register
if(Pntr.mlxDevice == mlx90621) Pntr.MLXRamCmmd[1] = MLX621_PTATSENS;
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];
#ifdef MLXTEST_621b
if(Pntr.mlxDevice == mlx90620) {
Pntr.PtatD = 0x1ac0;
} else {
if(ConfigReg54 == 0) {
Pntr.PtatD = 0x0cfb;
} else
if(ConfigReg54 == 1) {
Pntr.PtatD = 0x19f7;
} else
if(ConfigReg54 == 2) {
Pntr.PtatD = 0x33ef;
} else
if(ConfigReg54 == 3) {
Pntr.PtatD = 0x67de;
} else {
Pntr.PtatD = 0;
}
}
#endif
return(Pntr.PtatD);
}
//--------------------------------------------------------------------------------------------------------------------------------------//
//get VCP / TGC register from MLX9062x
int16_t MLX9062x::GetTGCReg(mlx_struct& Pntr) {
Pntr.MLXRamCmmd[0] = 2; //command
Pntr.MLXRamCmmd[1] = MLX620_TGCSENS; //address of register
if(Pntr.mlxDevice == mlx90621) Pntr.MLXRamCmmd[1] = MLX621_TGCSENS;
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);
int16_t VCP = (Pntr.MLXRamCmmd[1] << 8) + Pntr.MLXRamCmmd[0];
#ifdef MLXTEST_621b
VCP = 0xffdc;
#endif
Pntr.VCP = VCP;
return(VCP);
}
//--------------------------------------------------------------------------------------------------------------------------------------//
//get RAM dump from MLX9062x
void MLX9062x::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 = MLX9062x::GetPTATReg(Pntr);
Pntr.VCP = MLX9062x::GetTGCReg(Pntr);
}
//--------------------------------------------------------------------------------------------------------------------------------------//
//start measurement MLX9062x
int MLX9062x::StartMeasurement(mlx_struct& Pntr) {
if(Pntr.mlxDevice == mlx90621) return(0); //there is no start_meas in the 90621
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);
}
//--------------------------------------------------------------------------------------------------------------------------------------//
// Only a test to set up values in EEPROM and RAM buffers to debug math.
//Note: must be performed after reading the EEPROM and RAM data
void MLX9062x::DSSetup(mlx_struct& Pntr, int Pixel) {
#ifdef MLXTEST_621b
#warning "MLX90620 test mode B"
if(Pntr.mlxDevice == mlx90620) {
Pntr.MLXEEbuf[0xda] = 0x78;
Pntr.MLXEEbuf[0xdb] = 0x1a;
Pntr.MLXEEbuf[0xdc] = 0x33;
Pntr.MLXEEbuf[0xdd] = 0x5b;
Pntr.MLXEEbuf[0xde] = 0xcc;
Pntr.MLXEEbuf[0xdf] = 0xed;
} else {
//7.3.2 for Ta Calculations
Pntr.MLXEEbuf[0xda] = 0x20;
Pntr.MLXEEbuf[0xdb] = 0x64;
Pntr.MLXEEbuf[0xdc] = 0x89;
Pntr.MLXEEbuf[0xdd] = 0x55;
Pntr.MLXEEbuf[0xde] = 0x7e;
Pntr.MLXEEbuf[0xdf] = 0x5e;
Pntr.MLXEEbuf[0xd2] = 0x8b;
//7.3.4 for To Calculations (pixel 11)
Pntr.MLXEEbuf[0x00 + Pixel] = 0x21;
Pntr.MLXEEbuf[0x40 + Pixel] = 0xbc;
Pntr.MLXEEbuf[0x80 + Pixel] = 0xcd;
Pntr.MLXEEbuf[0xc0] = 0x99;
Pntr.MLXEEbuf[0xc4] = 0x9e;
Pntr.MLXEEbuf[0xd0] = 0x8a;
Pntr.MLXEEbuf[0xd1] = 0xff;
Pntr.MLXEEbuf[0xd3] = 0x9d;
Pntr.MLXEEbuf[0xd4] = 0xff;
Pntr.MLXEEbuf[0xd5] = 0xa2;
Pntr.MLXEEbuf[0xd6] = 0xa8;
Pntr.MLXEEbuf[0xd7] = 0x0f;
Pntr.MLXEEbuf[0xd8] = 0x18;
Pntr.MLXEEbuf[0xd9] = 0x07;
Pntr.MLXEEbuf[0xe0] = 0xae;
Pntr.MLXEEbuf[0xe1] = 0x4e;
Pntr.MLXEEbuf[0xe2] = 0x26;
Pntr.MLXEEbuf[0xe3] = 0x1f;
Pntr.MLXEEbuf[0xe4] = 0x00;
Pntr.MLXEEbuf[0xe5] = 0x80;
Pntr.MLXEEbuf[0xe6] = 0x0c;
Pntr.MLXEEbuf[0xe7] = 0x02;
VirPix = 0x01b7;
}
#endif
}
//--------------------------------------------------------------------------------------------------------------------------------------//
// Initial Calculations for Ta and To
//#define MLXTEST_621 1
double MLX9062x::GetDieTemp(mlx_struct& Pntr) {
Pntr.PtatD = MLX9062x::GetPTATReg(Pntr);
//Note: There seems to be a scaling error in the following routine
//MLX621_CONF_ADC18 = +26.891C
//MLX621_CONF_ADC17 = +25.934C
//MLX621_CONF_ADC16 = +25.467C
//MLX621_CONF_ADC15 = +25.187C
double TaX = (-Kt1_f + sqrt(pow(Kt1_f, 2.0) - 4.0 * Kt2_f * (((Vth25 - (double)Pntr.PtatD)/ScaleCR54))))/(2.0 * Kt2_f) + 25.0;
Pntr.DieTemp = TaX;
return(TaX);
}
//--------------------------------------------------------------------------------------------------------------------------------------//
// Display internal PIXEL registers for debugging math
void MLX9062x::DumpPixRegs(mlx_struct& Pntr, int Pixel) {
#ifdef MLXTEST_621b
if(Pntr.mlxDevice == mlx90620) {
/*
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("VirPix_off_comp = %f\r\n", VirPix_off_comp);
printf("VirPix = %d\r\n", VirPix);
printf("AiPix = %d\r\n", AiPix);
printf("BiPix = %d\r\n", BiPix);
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", (Ta - 25.0f));
printf("BiPix/2^BiScale = %f\r\n", (BiPix / powf(2.0,BiScaleX)));
printf("AiP+BiP/2^BiScale)*(Ta-25= %f\r\n", (AiPix + BiPix / powf(2.0,BiScaleX) * (Ta - 25.0f)));
printf("VirPix_off_comp again = %f\r\n", (VirPix - (AiPix + BiPix / powf(2.0,BiScaleX) * (Ta - 25.0f))));
printf("VirPix_off_comp2 step = %f\r\n", VirPix_off_comp2);
printf("VirPix_tgc_comp = %f\r\n", VirPix_tgc_comp);
printf("elipsonf = %f\r\n", elipsonf);
printf("VirPix_comp = %f\r\n", VirPix_comp);
printf("theta28 = %f << double print problem\r\n", (theta28 * 100000000.0)); //<<< can't print a double
printf("TempPxl = %f\r\n", TempPxl);
*/
} else {
printf("Pixel,%2d\r\n", Pixel);
//DSSetup(Pntr, Pixel);
printf("VirPix,%d,%x\r\n", VirPix, VirPix);
printf("VCP,%d\r\n", Pntr.VCP);
printf("Ta,%.3f\r\n\r\n", Ta);
printf("Acommon_mod,%d\r\n", Acommon);
printf("AiPix,%d\r\n", AiPix);
printf("Ai_ij_f,%.16f\r\n", Ai_ij);
printf("BiPix_mod,%d\r\n", BiPix);
printf("Bi_ij_f,%.16f\r\n", Bi_ij);
printf("VirOffComp,%.16f\r\n", VirOffComp);
printf("ACP_ee_mod,%d\r\n", ACP_ee);
int8_t bCPx = Pntr.MLXEEbuf[MLX621_BCP];
if(bCPx > 127) bCPx -= 256;
printf("bCP_ee_mod,%d\r\n", bCPx);
printf("bCP,%.16f\r\n", bCP);
printf("VcpCPOffComp,%.16f\r\n", VcpCPOffComp);
printf("TempTCG_mod,%d\r\n\r\n", TempTCG);
printf("Tgc621 mod,%.16f\r\n", Tgc621);
printf("Emiss mod,%d\r\n", Emiss);
printf("VirTGCComp,%.16f\r\n", VirTGCComp);
printf("VirComp,%.16f\r\n", VirComp);
printf("KsTa,%d\r\n", KsTa);
printf("KsTaF,%.16f\r\n", KsTaF);
printf("ThPix,%.16f\r\n", ThPix);
printf("ThetaCP,%.16f\r\n", ThetaCP);
printf("ThetaCompPix,%.16f\r\n", ThetaCompPix);
printf("Ks4_ee,%d\r\n", Ks4_ee);
printf("Ks4_scale,%d,%x\r\n", Pntr.MLXEEbuf[MLX621_KS_SCALE], Pntr.MLXEEbuf[MLX621_KS_SCALE]);
printf("Ks4,%.16f\r\n", Ks4);
printf("TaK4,%.2f\r\n", TaK4);
printf("Sx,%.16f\r\n", Sx);
/*
printf("BiPix,%d,%x\r\n", Pntr.MLXEEbuf[Pixel + 0x40], Pntr.MLXEEbuf[Pixel + 0x40]);
printf("d_Th_Pix,%d,%x\r\n", d_Th_Pix, d_Th_Pix);
//printf("VirOff_(Ta - 25.0f),%.16f\r\n", (Ta - 25.0f));
//printf("VirOff_Bi_ij * (Ta - 25.0f),%.16f\r\n", Bi_ij * (Ta - 25.0f));
//printf("VirOff_(Ai_ij + Bi_ij * (Ta - 25.0f)),%.16f\r\n", (Ai_ij + Bi_ij * (Ta - 25.0f)));
printf("VircpTgcComp,%.16f\r\n", VircpTgcComp);
printf("VirTGCComp,%.16f\r\n", VirTGCComp);
printf("DELTA_TH_SCALE,%d,%.0f\r\n", Pntr.MLXEEbuf[MLX621_DELTA_TH_SCALE], (double) powf(2.0,Pntr.MLXEEbuf[MLX621_DELTA_TH_SCALE]));
printf("THETA0_SCALE,%d,%.0f\r\n", Pntr.MLXEEbuf[MLX621_THETA0_SCALE], (double) powf(2.0,Pntr.MLXEEbuf[MLX621_THETA0_SCALE]));
//printf("Alpha_ij_raw,%d,%04x\r\n", (Pntr.MLXEEbuf[MLX621_THETA0_HI] << 8) + Pntr.MLXEEbuf[MLX621_THETA0_LO], (Pntr.MLXEEbuf[MLX621_THETA0_HI] << 8) + Pntr.MLXEEbuf[MLX621_THETA0_LO]);
//printf("Alpha_ij_f,%.16f\r\n", Alpha_ij);
//printf("VirNorm,%.16f\r\n", VirNorm);
printf("VirComp,%.16f\r\n", VirComp);
printf("TempPxl,%.16f\r\n", TempPxl);
//printf("TempPxl_a,%.16f\r\n", powf((Ta + 273.15), 4.0));
//printf("TempPxl_b,%.16f\r\n", log10((VirComp + powf((Ta + 273.15), 4.0)) / 4.0));
//printf("TempPxl_c,%.16f\r\n", exp((log10((VirComp + powf((Ta + 273.15), 4.0)) / 4.0))));
//printf("TempPxl_d,%.16f\r\n", powf((Ta + 273.15), 1.0));
//printf("TempPxl_e,%.16f\r\n", Ta + 273.15);
//printf("TempPxl_f,%.16f\r\n", Ta + 273.15);
printf("Th_0 ,%.16f\r\n", (double)Th_0 / pow(2.0,(double)Th_0_sc));
//printf("d_Th_Pix,%d,%x\r\n", d_Th_Pix, d_Th_Pix);
//printf("d_Th_Pix_raw,%d,%3.20f\r\n", Pntr.MLXEEbuf[Pixel + 0x80], (double)Pntr.MLXEEbuf[Pixel + 0x80]);
//printf("ThDeltaZ,%3.20f\r\n", (double)d_Th_Pix); // !!!!! coverting 205 to 34!!
//d_Th_Pix = Pntr.MLXEEbuf[Pixel + 0x80];
//printf("ThDelta1,%.16f\r\n", (double)d_Th_Pix);
//printf("ThDelta2,%.16f\r\n", (double)Th_0 / pow(2.0,(double)Th_0_sc));
//printf("ThDelta3,%.16f\r\n", (double)d_Th_Pix / pow(2.0,(double)d_Th_sc));
//printf("ThDelta4,%.16f\r\n", (double)Th_0 / pow(2.0,(double)Th_0_sc) + (double)d_Th_Pix / pow(2.0,(double)d_Th_sc));
//printf("ThDelta5,%.16f\r\n", (double)d_Th_Pix / pow(2.0,(double)d_Th_sc));
//ThPix = (((double)Th_0 / pow(2.0,(double)Th_0_sc) + ((double)d_Th_Pix / pow(2.0,(double)d_Th_sc)))) / ScaleCR54;
printf("ThPix,%.16f\r\n", ThPix);
printf("ThetaCP,%.16f\r\n", ThetaCP);
printf("ThetaCompPix,%.16f\r\n", ThetaCompPix);
//printf("SxGuts1,%.32f\r\n", pow(ThetaCompPix, 3.0));
//printf("SxGuts2,%.32f\r\n", pow(ThetaCompPix, 3.0) * VirComp);
//printf("SxGuts3,%.32f\r\n", pow(ThetaCompPix, 4.0));
//printf("SxGuts4,%.32f\r\n", pow(ThetaCompPix, 4.0) * TaK4);
//printf("SxGuts5,%.32f\r\n", pow(ThetaCompPix, 3.0) * VirComp + (pow(ThetaCompPix, 4.0) * TaK4));
printf("SxGuts,%.32f\r\n", SxGuts);
printf("Sx,%.16f\r\n", Sx);
*/
printf("TempPxl,%.16f\r\n", TempPxl);
printf("\r\n");
}
#endif
}
//--------------------------------------------------------------------------------------------------------------------------------------//
// Display internal registers for debugging math
void MLX9062x::DumpRawRegs(mlx_struct& Pntr) {
#ifdef MLXTEST_621b
if(Pntr.mlxDevice == mlx90620) {
printf("\r\n\r\nMLX90620 Ta_T0 regs:\r\n");
//printf("ConfigReg54 = %d\r\n", ConfigReg54);
//printf("ScaleCR54 = %d\r\n", ScaleCR54);
//printf("Ktbits = %02x\r\n",Pntr.MLXEEbuf[MLX621_KT12_SCALE]);
printf("Kt1,%d,%x\r\n", Kt1, Kt1);
//printf("Kt1_0xd2 = %d\r\n", 1 << ((Pntr.MLXEEbuf[MLX621_KT12_SCALE] & MLX621_KT1SCALE_BITS) >> 4));
printf("Kt2,%d,%x\r\n", Kt2, Kt2);
//printf("Kt2_0xd2 = %d %x\r\n", 1 << (Pntr.MLXEEbuf[MLX621_KT12_SCALE] & MLX621_KT2SCALE_BITS), 1 << (Pntr.MLXEEbuf[MLX621_KT12_SCALE] & MLX621_KT2SCALE_BITS));
//printf("Kt2_0xd2 2 = %d %x\r\n", 1 << 10 << (Pntr.MLXEEbuf[MLX621_KT12_SCALE] & MLX621_KT2SCALE_BITS), 1 << 10 << (Pntr.MLXEEbuf[MLX621_KT12_SCALE] & MLX621_KT2SCALE_BITS));
printf("Vth25,%d,%x\r\n", Vth25, Vth25);
printf("Kt1_f,%f\r\n", Kt1_f);
printf("Kt2_f,%f\r\n", Kt2_f);
printf("Pntr.PtatD,%d,%x\r\n", Pntr.PtatD, Pntr.PtatD);
printf("Ta,%f\r\n", Ta);
//printf("Tak4 = %f\r\n", Tak4);
//printf("MLX621_KS4_EE = %d\r\n", Pntr.MLXEEbuf[MLX621_KS4_EE]);
//printf("MLX621_KS_SCALE = %d\r\n", Pntr.MLXEEbuf[MLX621_KS_SCALE]);
//printf("ks4 = %d\r\n", ks4);
//printf("Acommon = %d\r\n", Acommon);
//printf("deltaAi621 = %d\r\n", deltaAi621);
//printf("deltaAiScale621 = %d\r\n", deltaAiScale621);
//printf("Ai_ij = %d\r\n", Ai_ij);
//printf("BiScale621 = %d\r\n", BiScale621);
//printf("Bi_ijEEP = %d **\r\n", Bi_ijEEP);
//printf("Bi_ij = %d\r\n", Bi_ij);
//printf("ACP_ee = %d **\r\n", ACP_ee);
//printf("aCP = %d\r\n", aCP); //was 8 bit, now 16
//printf("Vth(25) = %6d 0x%x\nTa1 = %6d 0x%x\nTa2 = %6d 0x%x\n", Vth25, Vth25, Kt1, Kt1, Kt2, Kt2);
//printf("Kt1_f = %f\nKt2_f = %f\nTa = %f\n\n", Kt1_f, Kt2_f, Ta);
//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);
} else {
printf("\r\n\r\nMLX90621 Ta_T0 regs:\r\n");
printf("ConfigReg54,%d,%02x\r\n", (Pntr.Config & MLX621_RESOLUTION) >> 4, (Pntr.Config & MLX621_RESOLUTION) >> 4);
printf("Pntr.PtatD,%d,%x\r\n", Pntr.PtatD, Pntr.PtatD);
printf("Vth25 mod,%d,%x\r\n", Vth25, Vth25);
printf("Kt1_f,%.16f\r\n", Kt1_f);
printf("Kt2_f,%.16f\r\n", Kt2_f);
printf("Ta,%.16f\r\n\r\n", Ta);
printf("ScaleCR54,%d,%x\r\n", 1 << (3 - ((Pntr.Config & MLX621_RESOLUTION) >> 4)), 1 << (3 - ((Pntr.Config & MLX621_RESOLUTION) >> 4)));
printf("Ktbits,%02x\r\n",Pntr.MLXEEbuf[MLX621_KT12_SCALE]);
printf("Kt1,%d,%x\r\n", (int16_t)(Pntr.MLXEEbuf[MLX621_KT1_HI] << 8) | Pntr.MLXEEbuf[MLX621_KT1_LO], (Pntr.MLXEEbuf[MLX621_KT1_HI] << 8) | Pntr.MLXEEbuf[MLX621_KT1_LO]);
printf("Kt1_0xd2,%d\r\n", 1 << ((Pntr.MLXEEbuf[MLX621_KT12_SCALE] & MLX621_KT1SCALE_BITS) >> 4));
printf("Kt1 mod,%d,%x\r\n", Kt1, Kt1);
printf("Kt2,%d,%x\r\n", (int16_t)((Pntr.MLXEEbuf[MLX621_KT2_HI] << 8) | Pntr.MLXEEbuf[MLX621_KT2_LO]), ((Pntr.MLXEEbuf[MLX621_KT2_HI] << 8) | Pntr.MLXEEbuf[MLX621_KT2_LO]));
printf("Kt2_0xd2,%d,%x\r\n", 1 << (Pntr.MLXEEbuf[MLX621_KT12_SCALE] & MLX621_KT2SCALE_BITS), 1 << (Pntr.MLXEEbuf[MLX621_KT12_SCALE] & MLX621_KT2SCALE_BITS));
printf("Kt2_0xd2_2,%d,%x\r\n", 1 << 10 << (Pntr.MLXEEbuf[MLX621_KT12_SCALE] & MLX621_KT2SCALE_BITS), 1 << 10 << (Pntr.MLXEEbuf[MLX621_KT12_SCALE] & MLX621_KT2SCALE_BITS));
printf("Kt2 mod,%d,%x\r\n", Kt2, Kt2);
printf("Vth25,%d,%x\r\n", (int16_t)(((Pntr.MLXEEbuf[MLX621_VTH25_HI] << 8) | Pntr.MLXEEbuf[MLX621_VTH25_LO])), (((Pntr.MLXEEbuf[MLX621_VTH25_HI] << 8) | Pntr.MLXEEbuf[MLX621_VTH25_LO])));
printf("Kt1_f^2,%12f\r\n", pow(Kt1_f, 2.0));
printf("Vth25-PtatD,%12f\r\n", (Vth25 - (double)Pntr.PtatD));
printf("4*Kt2_f,%12f\r\n", 4.0 * Kt2_f);
printf("4*Kt2_f*(Vth25 - Pntr.PtatD),%12f\r\n", 4.0 * Kt2_f * (Vth25 - (double)Pntr.PtatD));
printf("TopBeforesqrt,%12f\r\n", -pow(Kt1_f, 2.0) - 4.0 * Kt2_f * (Vth25 - (double)Pntr.PtatD));
printf("\r\n");
printf("Acommon,%d,%x\r\n", (int16_t)(Pntr.MLXEEbuf[MLX621_A_COMMON_HI] << 8) + Pntr.MLXEEbuf[MLX621_A_COMMON_LO], (Pntr.MLXEEbuf[MLX621_A_COMMON_HI] << 8) + Pntr.MLXEEbuf[MLX621_A_COMMON_LO]);
printf("Acommon mod,%d,%x\r\n", Acommon, Acommon);
printf("Emiss,%d,%x\r\n", (uint16_t)((Pntr.MLXEEbuf[MLX621_A_EMMIS_HI] << 8) + Pntr.MLXEEbuf[MLX621_A_EMMIS_LO]), ((Pntr.MLXEEbuf[MLX621_A_EMMIS_HI] << 8) + Pntr.MLXEEbuf[MLX621_A_EMMIS_LO]));
printf("Emiss mod,%d,%x\r\n", Emiss, Emiss);
printf("ACP_ee,%d,%x\r\n", (int16_t)(Pntr.MLXEEbuf[MLX621_ACP_HI] << 8) + Pntr.MLXEEbuf[MLX621_ACP_LO], (Pntr.MLXEEbuf[MLX621_ACP_HI] << 8) + Pntr.MLXEEbuf[MLX621_ACP_LO]);
printf("ACP_ee mod,%d,%x\r\n", ACP_ee, ACP_ee);
printf("AlphaCP,%d,%x\r\n", (int16_t)((Pntr.MLXEEbuf[MLX621_ALPHACP_HI] << 8) + Pntr.MLXEEbuf[MLX621_ALPHACP_LO]), ((Pntr.MLXEEbuf[MLX621_ALPHACP_HI] << 8) + Pntr.MLXEEbuf[MLX621_ALPHACP_LO]));
printf("AlphaCP mod,%d,%x\r\n", AlphaCP, AlphaCP);
printf("aCP,%.16f\r\n", aCP);
printf("AiScale621,%d,%x\r\n", (int16_t)(Pntr.MLXEEbuf[MLX621_DELTA_ABI_SCALE] & MLX621_DAISCALE_BITS) >> 4, (Pntr.MLXEEbuf[MLX621_DELTA_ABI_SCALE] & MLX621_DAISCALE_BITS) >> 4);
printf("BiScale621,%d,%x\r\n", (int16_t)(Pntr.MLXEEbuf[MLX621_DELTA_ABI_SCALE] & MLX621_DBISCALE_BITS), (Pntr.MLXEEbuf[MLX621_DELTA_ABI_SCALE] & MLX621_DBISCALE_BITS));
printf("bCP,%d,%x\r\n", (int8_t)Pntr.MLXEEbuf[MLX621_BCP], Pntr.MLXEEbuf[MLX621_BCP]);
printf("bCP mod,%.16f\r\n", bCP);
printf("TempTCG,%d,%x\r\n", (int8_t)Pntr.MLXEEbuf[MLX621_TGC], Pntr.MLXEEbuf[MLX621_TGC]);
printf("TempTCG mod,%d,%x\r\n", TempTCG, TempTCG);
printf("Tgc621 mod,%.16f\r\n", Tgc621);
//printf("TGCReg,%d,%x\r\n", (int16_t)TGCReg, TGCReg);
printf("VCP,%d,%x\r\n", (int16_t)Pntr.VCP, Pntr.VCP);
printf("VcpCPOffComp,%.16f\r\n", VcpCPOffComp);
printf("KsTa,%d,%x\r\n", (int16_t)KsTa, KsTa);
printf("KsTaF,%.16f\r\n", KsTaF);
printf("Ks4_ee,%d,%x\r\n", (int16_t)Ks4_ee, Ks4_ee);
printf("Ks4_scale,%d,%x\r\n", Pntr.MLXEEbuf[MLX621_KS_SCALE], Pntr.MLXEEbuf[MLX621_KS_SCALE]);
printf("Ks4,%.16f\r\n", Ks4);
printf("TaK4,%.16f\r\n", TaK4);
printf("Th_0,%d,%x\r\n", (int16_t)Th_0, Th_0);
printf("Th_0_sc,%d,%x\r\n", (int16_t)Th_0_sc, Th_0_sc);
printf("d_Th_sc,%d,%x\r\n", (int16_t)d_Th_sc, d_Th_sc);
printf("\r\n");
}
#endif
}
//--------------------------------------------------------------------------------------------------------------------------------------//
// Initial Calculations for Ta and To
void MLX9062x::CalcTa_To(mlx_struct& Pntr) {
#ifdef MLXTEST_621b
DSSetup(Pntr, 11);
#endif
if(Pntr.mlxDevice == mlx90620) {
//Calculate Ta first
Vth25 = (Pntr.MLXEEbuf[MLX_TAINDEX + 1] << 8) + Pntr.MLXEEbuf[MLX_TAINDEX + 0];
Kt1 = (Pntr.MLXEEbuf[MLX_TAINDEX + 3] << 8) + Pntr.MLXEEbuf[MLX_TAINDEX + 2];
Kt2 = (Pntr.MLXEEbuf[MLX_TAINDEX + 5] << 8) + Pntr.MLXEEbuf[MLX_TAINDEX + 4];
if(Vth25 > 32767) Vth25 -= 65536;
if(Kt1 > 32767) Kt1 -= 65536;
if(Kt2 > 32767) Kt2 -= 65536;
Kt1_f = (double)Kt1 / 1024.0f;
Kt2_f = (double)Kt2 / 1048576.0f;
ScaleCR54 = 1;
Ta = MLX9062x::GetDieTemp(Pntr);
//Calculate To
AcpX = Pntr.MLXEEbuf[MLX621_A_COMMON_LO]; //[MLX_TOINDEX + 0];
BcpX = Pntr.MLXEEbuf[MLX621_A_COMMON_HI]; //[MLX_TOINDEX + 1];
//uint16_t thetaCPX = (EEbuf[MLX_TOINDEX + 3] << 8) + MLXEEbuf[MLX_TOINDEX + 2];
TGCX = Pntr.MLXEEbuf[MLX_TGCX_REG]; //[MLX_TOINDEX + 4];
BiScaleX = Pntr.MLXEEbuf[MLX621_DELTA_ABI_SCALE]; //[MLX_TOINDEX + 5];
theta0X = (Pntr.MLXEEbuf[MLX_THETA0_REG_HI] << 8) + Pntr.MLXEEbuf[MLX_THETA0_REG_LO]; //[MLX_TOINDEX + 13] << 8) + Pntr.MLXEEbuf[MLX_TOINDEX + 12];
theta0ScaleX = Pntr.MLXEEbuf[MLX_THETA0_SCALE_REG]; //[MLX_TOINDEX + 14];
deltaThetaScaleX = Pntr.MLXEEbuf[MLX_DELTA_TH_SCALE_REG]; //[MLX_TOINDEX + 15];
elipsonX = (Pntr.MLXEEbuf[MLX_EPSILON_REG_HI] << 8) + Pntr.MLXEEbuf[MLX_EPSILON_REG_LO]; //[MLX_TOINDEX + 17] << 8) + Pntr.MLXEEbuf[MLX_TOINDEX + 16];
} else {
ConfigReg54 = (Pntr.Config & MLX621_RESOLUTION) >> 4;
ScaleCR54 = 1 << (3 - ((Pntr.Config & MLX621_RESOLUTION) >> 4)); //1 << (3 - ConfigReg54);
Kt1 = (int16_t)((Pntr.MLXEEbuf[MLX621_KT1_HI] << 8) | Pntr.MLXEEbuf[MLX621_KT1_LO]);
Kt2 = (int16_t)((Pntr.MLXEEbuf[MLX621_KT2_HI] << 8) | Pntr.MLXEEbuf[MLX621_KT2_LO]);
Vth25 = (int16_t)(((Pntr.MLXEEbuf[MLX621_VTH25_HI] << 8) | Pntr.MLXEEbuf[MLX621_VTH25_LO]));
#ifdef MLXTEST_621
#warning "MLX90620 test mode"
//for testing only
ConfigReg54 = 0;
ScaleCR54 = 1 << (3 - ConfigReg54);
Vth25 = 0x6420;
Kt1 = 0x5589;
Kt2 = 0x5e7e;
#endif
if(Kt1 > 32767) Kt1 -= 65536;
if(Kt2 > 32767) Kt2 -= 65536;
if(Vth25 > 32767) Vth25 -= 65536;
Vth25 /= ScaleCR54;
Kt1_f = (double)Kt1 / ((1 << ((Pntr.MLXEEbuf[MLX621_KT12_SCALE] & MLX621_KT1SCALE_BITS) >> 4)) * ScaleCR54);
Kt2_f = (double)Kt2 / ((1 << 10 << (Pntr.MLXEEbuf[MLX621_KT12_SCALE] & MLX621_KT2SCALE_BITS)) * ScaleCR54);
Ta = MLX9062x::GetDieTemp(Pntr);
//double Tak4 = pow(Ta + 273.15, 4.0);
Acommon = (int16_t)(Pntr.MLXEEbuf[MLX621_A_COMMON_HI] << 8) + Pntr.MLXEEbuf[MLX621_A_COMMON_LO];
Emiss = (uint16_t)((Pntr.MLXEEbuf[MLX621_A_EMMIS_HI] << 8) + Pntr.MLXEEbuf[MLX621_A_EMMIS_LO]) / 32768;
ACP_ee = (int16_t)(Pntr.MLXEEbuf[MLX621_ACP_HI] << 8) + Pntr.MLXEEbuf[MLX621_ACP_LO];
AlphaCP = (int16_t)((Pntr.MLXEEbuf[MLX621_ALPHACP_HI] << 8) + Pntr.MLXEEbuf[MLX621_ALPHACP_LO]) / ScaleCR54;
if(Acommon > 32767) Acommon -= 65536;
//if(Emiss > 32767) Emiss -= 65536;
if(ACP_ee > 32767) ACP_ee -= 65536;
aCP = (float)(ACP_ee / ScaleCR54);
AiScale621 = (int16_t)(Pntr.MLXEEbuf[MLX621_DELTA_ABI_SCALE] & MLX621_DAISCALE_BITS) >> 4;
BiScale621 = (int16_t)(Pntr.MLXEEbuf[MLX621_DELTA_ABI_SCALE] & MLX621_DBISCALE_BITS);
bCP = (float)Pntr.MLXEEbuf[MLX621_BCP];
if(bCP > 127.0f) bCP -= 256.0f;
bCP /= (pow(2.0f, (float)BiScale621) * (float)ScaleCR54);
TempTCG = Pntr.MLXEEbuf[MLX621_TGC];
if(TempTCG > 127) TempTCG -= 256;
Tgc621 = (float)TempTCG / 32.0f;
TGCReg = GetTGCReg(Pntr);
if(Pntr.VCP > 32767) Pntr.VCP -= 65536;
VcpCPOffComp = (double)Pntr.VCP - ((double)aCP + bCP * (Ta - 25.0));
KsTa = (Pntr.MLXEEbuf[MLX621_KSTA_HI] << 8) + Pntr.MLXEEbuf[MLX621_KSTA_LO];
if(KsTa > 32767) KsTa -= 65536;
KsTaF = (double)KsTa / pow(2.0, 20);
Ks4_ee = Pntr.MLXEEbuf[MLX621_KS4_EE];
if(Ks4_ee > 127) Ks4_ee -= 256;
Ks4 = (double)Ks4_ee / pow(2.0, (double)((Pntr.MLXEEbuf[MLX621_KS_SCALE] & 15) + 8.0));
TaK4 = pow((Ta + 273.15), 4.0);
Th_0 = (Pntr.MLXEEbuf[MLX621_THETA0_HI] << 8) + Pntr.MLXEEbuf[MLX621_THETA0_LO];
Th_0_sc = Pntr.MLXEEbuf[MLX621_THETA0_SCALE];
d_Th_sc = Pntr.MLXEEbuf[MLX621_DELTA_TH_SCALE];
}
DumpRawRegs(Pntr);
}
//--------------------------------------------------------------------------------------------------------------------------------------//
// Pixel Temperature Calculation
double MLX9062x::CalcPixel(mlx_struct& Pntr, int Pixel) {
if(Pntr.mlxDevice == mlx90620) {
AiPix = Pntr.MLXEEbuf[Pixel]; //eeprom address range 0x00 - 0x3f
BiPix = Pntr.MLXEEbuf[Pixel + 0x40]; //eeprom address range 0x40 - 0x7f
d_Th_Pix = Pntr.MLXEEbuf[Pixel + 0x80]; //eeprom address range 0x08 - 0xbf
VirPix = (Pntr.MLXRamBuf[Pixel * 2 + 1] << 8) + Pntr.MLXRamBuf[Pixel * 2]; //ram address range 0x000 - 0x08f, 16b
float Vcp_off_comp = Pntr.VCP - (AcpX + BcpX / powf(2.0f,BiScaleX) * (Ta - 25.0f));
float VirPix_off_comp = VirPix - (AiPix + BiPix / powf(2.0f,BiScaleX) * (Ta - 25.0f));
float VirPix_off_comp2 = (float(AiPix) + float(BiPix) / float(1 << BiScaleX) * (Ta - 25.0f));
VirPix_off_comp2 = VirPix - VirPix_off_comp2;
float VirPix_tgc_comp = VirPix_off_comp - TGCX / 32.0 * Vcp_off_comp;
float elipsonf = elipsonX / 32768.0;
float VirPix_comp = VirPix_tgc_comp / elipsonf;
double theta28 = theta0X / powf(2.0, theta0ScaleX) + d_Th_Pix / powf(2.0, deltaThetaScaleX);
TempPxl = powf((VirPix_comp / theta28 + powf((Ta + 273.15f), 4.0f)), (1.0f / 4.0f)) - 273.15f;
} else {
AiPix = Pntr.MLXEEbuf[Pixel]; //eeprom address range 0x00 - 0x3f
BiPix = Pntr.MLXEEbuf[Pixel + 0x40]; //eeprom address range 0x40 - 0x7f
d_Th_Pix = Pntr.MLXEEbuf[Pixel + 0x80]; //eeprom address range 0x08 - 0xbf
VirPix = (Pntr.MLXRamBuf[Pixel * 2 + 1] << 8) + Pntr.MLXRamBuf[Pixel * 2]; //ram address range 0x000 - 0x08f, 16b
#ifdef MLXTEST_621b
VirPix = 0x01b7;
#endif
if(VirPix > 32767) VirPix -= 65536;
if(BiPix > 127) BiPix -= 256;
Ai_ij = (float)(Acommon + AiPix * pow(2.0, AiScale621)) / (float)ScaleCR54;
Bi_ij = (float)BiPix / (float)((1 << BiScale621) * ScaleCR54);
VirOffComp = (float)VirPix - (Ai_ij + Bi_ij * (Ta - 25.0f));
VirTGCComp = VirOffComp - Tgc621 * VcpCPOffComp;
VirComp = VirTGCComp / Emiss;
ThPix = (((double)Th_0 / pow(2.0,(double)Th_0_sc) + ((double)d_Th_Pix / pow(2.0,(double)d_Th_sc)))) / ScaleCR54;
ThetaCP = (double)AlphaCP / (pow(2.0, (double)Th_0_sc) * ScaleCR54);
ThetaCompPix = (1.0 + KsTaF * (Ta - 25.0)) * (ThPix - Tgc621 * ThetaCP);
SxGuts = pow(ThetaCompPix, 3.0) * VirComp + (pow(ThetaCompPix, 4.0) * TaK4);
Sx = sqrt(SxGuts);
Sx = Ks4 * sqrt(Sx);
TempPxl = ThetaCompPix * (1.0 - (Ks4 * 273.15)) + Sx;
TempPxl = (VirComp / TempPxl) + TaK4;
TempPxl = sqrt(TempPxl);
TempPxl = sqrt(TempPxl) - 273.15;
}
DumpPixRegs(Pntr, Pixel);
return(TempPxl);
}