Melexis MLX90620 and MLX90621, non-contact, 16x4 infrared array temperature sensor device driver.
MLX90620.cpp
- Committer:
- loopsva
- Date:
- 2016-07-26
- Revision:
- 2:82782c73251e
- Parent:
- 1:fd536ebc7eaf
File content as of revision 2:82782c73251e:
//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 //the following code addition of a 1 byte I2C fetch is due to a bug in the F746NG which can only transfer 255 bytes at a time. grrr!!!.... #if defined(TARGET_DISCO_F746NG) #warning "TARGET_DISCO_F746NG i2c bug, 255 byte limit!!!" Pntr.MLXEEbuf[0] = 255; if(!_i2c.write(MLX_EEPADDR, Pntr.MLXEEbuf, 1, true)) { _i2c.read((MLX_EEPADDR + 1), Pntr.MLXEEbuf, 1, false); Pntr.MLXEEbuf[255] = Pntr.MLXEEbuf[0]; Pntr.MLXEEbuf[0] = 0; _i2c.write(MLX_EEPADDR, Pntr.MLXEEbuf, 1, true); _i2c.read((MLX_EEPADDR + 1), Pntr.MLXEEbuf, 255, false); //s/b 256 if F746NG bug wasn't there #else if(!_i2c.write(MLX_EEPADDR, Pntr.MLXEEbuf, 1, true)) { //send command, 0 returned is ok _i2c.read((MLX_EEPADDR + 1), Pntr.MLXEEbuf, 256, false); #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); }