人体测温 melexis迈来芯 linux 平台mlx90614/mlx90621/mlx90641驱动调试
2020年的春节因为疫情的原因一直出不了门,听说melexis测温头价格从40块涨到400块,并且还买不到货;正好有同事要求调到驱动:mlx测温模块驱动,基于android平台:
3. app:
这个客户已经做好了,并且提供的应用接口,我只要在jni里实现接口就行了;
2. JNI 接口的封装:
open()
read()
write()
close()
1. 驱动调试:
由于规格书上说mlx使用smbus接口,本人用硬件i2c驱动来调试时遇到了麻烦,搞了两天都通讯不成功,不得已放弃了;于是只能改用io,用io来模拟i2c,这种方式很好用。
#if 8 // 888
static void SMBus_Delay(u16 time);
static void SMBus_StartBit(void);
static void SMBus_StopBit(void);
static void SMBus_SendBit(u8);
static u8 SMBus_SendByte(u8);
static u8 SMBus_ReceiveBit(void);
static u8 SMBus_ReceiveByte(u8);
static void SMBus_Delay(u16);
static int SMBus_Init(void);
static u16 SMBus_ReadMemory(u8, u8);
static u8 PEC_Calculation(u8*);
static unsigned long SMBus_ReadTemp(void); //?????
static void SMBus_DisplayTemperature(void); //?LCD?5,6?????
static int SMBus_Write(u8 slaveAddress, u8 command, u8 dataL,u8 dataH);
static unsigned long int mlx90616_value;
static char smbus_io_first = 1;
static void mlx90616_main(void)
{
unsigned long int DATA;
if(smbus_io_first == 1){
smbus_io_first = 0;
SMBus_Init();//rk_gpio_init();
}
mlx90616_value = SMBus_ReadTemp();
}
//#include "myiic.h"
//#include "delay.h"
#define ACK 0
#define NACK 1
#define SA 0x00 //????,??MLX90614????0x00,????????0x5a
#define RAM_ACCESS 0x00 //RAM access command
#define EEPROM_ACCESS 0x20 //EEPROM access command
#define RAM_TOBJ1 0x07 //To1 address in the eeprom
//#define SMBUS_PORT GPIOB
#define SMBUS_SCK 113 //251 //GPIO_Pin_6
#define SMBUS_SDA 8 //237 //GPIO_Pin_7
#define RCC_APB2Periph_SMBUS_PORT RCC_APB2Periph_GPIOB
#define SMBUS_SCK_H() gpio_direction_output(SMBUS_SCK, 1) //SMBUS_PORT->BSRR = SMBUS_SCK
#define SMBUS_SCK_L() gpio_direction_output(SMBUS_SCK, 0) //SMBUS_PORT->BRR = SMBUS_SCK
#define SMBUS_SDA_H() gpio_direction_output(SMBUS_SDA, 1) //SMBUS_PORT->BSRR = SMBUS_SDA
#define SMBUS_SDA_L() gpio_direction_output(SMBUS_SDA, 0) //SMBUS_PORT->BRR = SMBUS_SDA
//#define SMBUS_SDA_PIN() SMBUS_PORT->IDR & SMBUS_SDA //??????
static int SMBUS_SDA_PIN(void)
{
int ret = 0;
gpio_direction_input(SMBUS_SDA);
ret = gpio_get_value(SMBUS_SDA);
return ret;
}
/*******************************************************************************
* ???: SMBus_StartBit
* ?? : ?????
* Input : None
* Output : None
* Return : None
*******************************************************************************/
static void SMBus_StartBit(void)
{
if(smbus_io_first == 1){
smbus_io_first = 0;
if(0 != SMBus_Init()) {
smbus_io_first =0xff; // io init failed
}
}
SMBUS_SDA_H(); // Set SDA line
SMBus_Delay(5); // Wait a few microseconds
SMBUS_SCK_H(); // Set SCL line
SMBus_Delay(5); // Generate bus free time between Stop
SMBUS_SDA_L(); // Clear SDA line
SMBus_Delay(5); // Hold time after (Repeated) Start
// Condition. After this period, the first clock is generated.
//(Thd:sta=4.0us min)
SMBUS_SCK_L(); // Clear SCL line
SMBus_Delay(5); // Wait a few microseconds
}
/*******************************************************************************
* ???: SMBus_StopBit
* ??: Generate STOP condition on SMBus
* Input : None
* Output : None
* Return : None
*******************************************************************************/
static void SMBus_StopBit(void)
{
if(smbus_io_first == 1){
smbus_io_first = 0;
if(0 != SMBus_Init()) {
smbus_io_first =0xff; // io init failed
}
}
SMBUS_SCK_L(); // Clear SCL line
SMBus_Delay(5); // Wait a few microseconds
SMBUS_SDA_L(); // Clear SDA line
SMBus_Delay(5); // Wait a few microseconds
SMBUS_SCK_H(); // Set SCL line
SMBus_Delay(5); // Stop condition setup time(Tsu:sto=4.0us min)
SMBUS_SDA_H(); // Set SDA line
}
/*******************************************************************************
* ???: SMBus_SendByte
* ??: Send a byte on SMBus
* Input : Tx_buffer
* Output : None
* Return : None
*******************************************************************************/
static u8 SMBus_SendByte(u8 Tx_buffer)
{
u8 Bit_counter;
u8 Ack_bit;
u8 bit_out;
for(Bit_counter=8; Bit_counter; Bit_counter--)
{
if (Tx_buffer&0x80)
{
bit_out=1; // If the current bit of Tx_buffer is 1 set bit_out
}
else
{
bit_out=0; // else clear bit_out
}
SMBus_SendBit(bit_out); // Send the current bit on SDA
Tx_buffer<<=1; // Get next bit for checking
}
Ack_bit=SMBus_ReceiveBit(); // Get acknowledgment bit
return Ack_bit;
}
/*******************************************************************************
* ???: SMBus_SendBit
* ??: Send a bit on SMBus 82.5kHz
* Input : bit_out
* Output : None
* Return : None
*******************************************************************************/
static void SMBus_SendBit(u8 bit_out)
{
if(bit_out==0)
{
SMBUS_SDA_L();
}
else
{
SMBUS_SDA_H();
}
SMBus_Delay(2); // Tsu:dat = 250ns minimum
SMBUS_SCK_H(); // Set SCL line
SMBus_Delay(6); // High Level of Clock Pulse
SMBUS_SCK_L(); // Clear SCL line
SMBus_Delay(3); // Low Level of Clock Pulse
// SMBUS_SDA_H(); // Master release SDA line ,
return;
}
/*******************************************************************************
* Function Name : SMBus_ReceiveBit
* Description : Receive a bit on SMBus
* Input : None
* Output : None
* Return : Ack_bit
*******************************************************************************/
static u8 SMBus_ReceiveBit(void)
{
u8 Ack_bit;
SMBUS_SDA_H(); //?????????,????
SMBus_Delay(2); // High Level of Clock Pulse
SMBUS_SCK_H(); // Set SCL line
SMBus_Delay(5); // High Level of Clock Pulse
if (SMBUS_SDA_PIN())
{
Ack_bit=1;
}
else
{
Ack_bit=0;
}
SMBUS_SCK_L(); // Clear SCL line
SMBus_Delay(3); // Low Level of Clock Pulse
return Ack_bit;
}
/*******************************************************************************
* ???: SMBus_ReceiveByte
* ??: Receive a byte on SMBus
* Input : ack_nack
* Output : None
* Return : RX_buffer
*******************************************************************************/
static u8 SMBus_ReceiveByte(u8 ack_nack)
{
u8 RX_buffer;
u8 Bit_Counter;
for(Bit_Counter=8; Bit_Counter; Bit_Counter--)
{
if(SMBus_ReceiveBit()) // Get a bit from the SDA line
{
RX_buffer <<= 1; // If the bit is HIGH save 1 in RX_buffer
RX_buffer |=0x01;
}
else
{
RX_buffer <<= 1; // If the bit is LOW save 0 in RX_buffer
RX_buffer &=0xfe;
}
}
SMBus_SendBit(ack_nack); // Sends acknowledgment bit
return RX_buffer;
}
/*******************************************************************************
* ???: SMBus_Delay
* ??: ?? ?????1us
* Input : time
* Output : None
* Return : None
*******************************************************************************/
static void SMBus_Delay(u16 time)
{
u16 i, j;
for (i=0; i<5; i++)
{
udelay(time);//for (j=0; j<time; j++);
}
}
/*******************************************************************************
* ???: SMBus_Init
* ??: SMBus???
* Input : None
* Output : None
* Return : None
*******************************************************************************/
static int SMBus_Init()
{
#if 0
GPIO_InitTypeDef GPIO_InitStructure;
/* Enable SMBUS_PORT clocks */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SMBUS_PORT, ENABLE);
/*??SMBUS_SCK?SMBUS_SDA????????*/
GPIO_InitStructure.GPIO_Pin = SMBUS_SDA;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(SMBUS_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = SMBUS_SCK ;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(SMBUS_PORT, &GPIO_InitStructure);
SMBUS_SCK_H();
SMBUS_SDA_H();
#else
int err;
err = gpio_request(SMBUS_SDA,"RK_GPIO_SDA");
if(err){
printk("Cannot Request the gpio of %d\n", SMBUS_SDA);
return -1;
}
err = gpio_direction_output(SMBUS_SDA, 1);
if (err < 0) {
printk("Cannot set SMBUS_SDA output mode. \n");
gpio_free(SMBUS_SDA);
return -1;
}
//gpio_set_value(RK_GPIO_SDA, 1);
radio_dbg("liuxd SMBUS_SDA init ok\n");
err = gpio_request(SMBUS_SCK,"RK_GPIO_SCL");
if(err){
printk("Cannot Request SMBUS_SCK %d\n", SMBUS_SCK);
return -1;
}
err = gpio_direction_output(SMBUS_SCK, 1);
if (err < 0) {
printk("Cannot set SMBUS_SCK output mode. \n");
gpio_free(SMBUS_SCK);
return -1;
}
//gpio_set_value(SMBUS_SCK, 1);
radio_dbg("liuxd RK_GPIO_SCL init ok\n");
SMBUS_SCK_H();
SMBUS_SDA_H();
return 0;
#endif
}
/*******************************************************************************
* ???: SMBus_ReadMemory
* ??: READ DATA FROM RAM/EEPROM
* Input : slaveAddress, command
* Return : Data
*******************************************************************************/
static u16 SMBus_ReadMemory(u8 slaveAddress, u8 command)
{
u16 data; // Data storage (DataH:DataL)
u8 Pec; // PEC byte storage
u8 DataL=0; // Low data byte storage
u8 DataH=0; // High data byte storage
u8 arr[6]; // Buffer for the sent bytes
u8 PecReg; // Calculated PEC byte storage
u8 ErrorCounter; // Defines the number of the attempts for communication with MLX90614
ErrorCounter=0x00; // Initialising of ErrorCounter
slaveAddress <<= 1; //2-7???????
do
{
repeat:
SMBus_StopBit(); //If slave send NACK stop comunication
--ErrorCounter; //Pre-decrement ErrorCounter
if(!ErrorCounter) //ErrorCounter=0?
{
break; //Yes,go out from do-while{}
}
SMBus_StartBit(); //Start condition
if(SMBus_SendByte(slaveAddress))//Send SlaveAddress ???Wr=0????????
{
goto repeat; //Repeat comunication again
}
if(SMBus_SendByte(command)) //Send command
{
goto repeat; //Repeat comunication again
}
SMBus_StartBit(); //Repeated Start condition
if(SMBus_SendByte(slaveAddress+1)) //Send SlaveAddress ???Rd=1????????
{
goto repeat; //Repeat comunication again
}
DataL = SMBus_ReceiveByte(ACK); //Read low data,master must send ACK
DataH = SMBus_ReceiveByte(ACK); //Read high data,master must send ACK
Pec = SMBus_ReceiveByte(NACK); //Read PEC byte, master must send NACK
SMBus_StopBit(); //Stop condition
arr[5] = slaveAddress; //
arr[4] = command; //
arr[3] = slaveAddress+1; //Load array arr
arr[2] = DataL; //
arr[1] = DataH; //
arr[0] = 0; //
PecReg=PEC_Calculation(arr);//Calculate CRC
}
while(PecReg != Pec); //If received and calculated CRC are equal go out from do-while{}
data = (DataH<<8) | DataL; //data=DataH:DataL
return data;
}
/*******************************************************************************
* ???: PEC_calculation
* ?? : ????
* Input : pec[]
* Output : None
* Return : pec[0]-this byte contains calculated crc value
*******************************************************************************/
static u8 PEC_Calculation(u8 pec[])
{
u8 crc[6];
u8 BitPosition=47;
u8 shift;
u8 i;
u8 j;
u8 temp;
do
{
/*Load pattern value 0x000000000107*/
crc[5]=0;
crc[4]=0;
crc[3]=0;
crc[2]=0;
crc[1]=0x01;
crc[0]=0x07;
/*Set maximum bit position at 47 ( six bytes byte5...byte0,MSbit=47)*/
BitPosition=47;
/*Set shift position at 0*/
shift=0;
/*Find first "1" in the transmited message beginning from the MSByte byte5*/
i=5;
j=0;
while((pec[i]&(0x80>>j))==0 && i>0)
{
BitPosition--;
if(j<7)
{
j++;
}
else
{
j=0x00;
i--;
}
}/*End of while */
/*Get shift value for pattern value*/
shift=BitPosition-8;
/*Shift pattern value */
while(shift)
{
for(i=5; i<0xFF; i--)
{
if((crc[i-1]&0x80) && (i>0))
{
temp=1;
}
else
{
temp=0;
}
crc[i]<<=1;
crc[i]+=temp;
}/*End of for*/
shift--;
}/*End of while*/
/*Exclusive OR between pec and crc*/
for(i=0; i<=5; i++)
{
pec[i] ^=crc[i];
}/*End of for*/
}
while(BitPosition>8); /*End of do-while*/
return pec[0];
}
/*******************************************************************************
* ???: SMBus_ReadTemp
* ??: ????????
* Return : SMBus_ReadMemory(0x00, 0x07)*0.02-273.15
*******************************************************************************/
static unsigned long SMBus_ReadTemp(void)
{
//return SMBus_ReadMemory(SA, RAM_ACCESS|RAM_TOBJ1)*0.02-273.15;
unsigned long tmp = SMBus_ReadMemory(SA, RAM_ACCESS|RAM_TOBJ1);
tmp = abs(tmp*2-27315);
//radio_dbg("liuxd tmp=%d\n",tmp);
return tmp;
}
/****
*
*/
static int SMBus_Write(u8 slaveAddress, u8 command, u8 dataL,u8 dataH)
{
int err = -1; // result: 0 is ok;
u8 ErrorCounter; // Defines the number of the attempts for communication with MLX90614
u8 arr[6],Pecreg;
ErrorCounter=0x00; // Initialising of ErrorCounter
slaveAddress <<= 1; //2-7???????
arr[5] = 0;
arr[4] = slaveAddress;
arr[3] = command;
arr[2] = dataL;
arr[1] = dataH;
arr[0] = 0;
Pecreg = PEC_Calculation(arr);
do
{
repeat:
SMBus_StopBit(); //If slave send NACK stop comunication
--ErrorCounter; //Pre-decrement ErrorCounter
if(!ErrorCounter) //ErrorCounter=0?
{
break; //Yes,go out from do-while{}
}
SMBus_StartBit(); //Start condition
if(SMBus_SendByte(slaveAddress))//Send SlaveAddress ???Wr=0????????
{
goto repeat; //Repeat comunication again
}
//radio_dbg("liuxd step111\n");
if(SMBus_SendByte(command)) //Send command
{
goto repeat; //Repeat comunication again
}
//radio_dbg("liuxd step222\n");
if(SMBus_SendByte(dataL)) //Send data
{
goto repeat; //Repeat comunication again
}
//radio_dbg("liuxd step333\n");
if(SMBus_SendByte(dataH)) //Send data
{
goto repeat; //Repeat comunication again
}
//radio_dbg("liuxd step444\n");
if(SMBus_SendByte(Pecreg)) //Send data
{
goto repeat; //Repeat comunication again
}
SMBus_StopBit(); //Stop condition
//radio_dbg("liuxd step555\n");
err = 0;
break;
}
while(err); //If received and calculated CRC are equal go out from do-while{}
return err;
}
#endif
#if 1
//#define SLA_8BIT 1
#define MAX_TIMES 3
static int MLX90641_I2CRead(uint8_t slaveAddr, uint16_t startAddress,uint16_t nMemAddressRead, uint16_t *data)
{
uint8_t sa;
int ack = 0;
int cnt = 0;
int i = 0;
char cmd[2] = {0,0};
char i2cData[1664] = {0};
uint16_t *p;
u8 ErrorCounter;
u8 flag = 1;
int no;
char * ptr;
p = data;
ptr = i2cData;
sa = (slaveAddr << 1);
cmd[0] = startAddress >> 8;
cmd[1] = startAddress & 0x00FF;
ErrorCounter=MAX_TIMES;
no = nMemAddressRead<<1;
do
{
repeat:
SMBus_StopBit(); //If slave send NACK stop comunication
if(smbus_io_first == 0xff){
printk("io alloc failed,MLX90641_I2CRead abort!\n");
return -1;
}
--ErrorCounter; //Pre-decrement ErrorCounter
if(!ErrorCounter) //ErrorCounter=0?
{
return -1; //Yes,go out from do-while{}
}
SMBus_StartBit(); //Start condition
if(SMBus_SendByte(sa))//Send SlaveAddress ???Wr=0????????
{
goto repeat; //Repeat comunication again
}
if(SMBus_SendByte(cmd[0])) //Send command
{
goto repeat; //Repeat comunication again
}
if(SMBus_SendByte(cmd[1]))
{
goto repeat;
}
SMBus_StartBit(); //Repeated Start condition
if(SMBus_SendByte(sa+1)) //Send SlaveAddress ???Rd=1????????
{
goto repeat; //Repeat comunication again
}
for(i=0;i<no-1;i++){
*ptr = SMBus_ReceiveByte(ACK);
ptr++;
}
*ptr = SMBus_ReceiveByte(NACK); //Read PEC byte, master must send NACK
SMBus_StopBit(); //Stop condition
flag = 0;
//dump_raw(s,no);
}
while(flag); //If received and calculated CRC are equal go out from do-while{}
for(cnt=0; cnt < nMemAddressRead; cnt++)
{
i = cnt << 1;
*p++ = (int)i2cData[i]*256 + (int)i2cData[i+1];
}
return 0;
}
static void MLX90641_I2CFreqSet(int freq)
{
//freqCnt = freq>>1;
}
static int MLX90641_I2CWrite(uint8_t slaveAddr, uint16_t writeAddress, uint16_t data)
{
uint8_t sa;
int ack = 0,i;
char cmd[4] = {0,0,0,0};
static uint16_t dataCheck;
u8 ErrorCounter,err =1;
ErrorCounter=MAX_TIMES;
sa = (slaveAddr << 1);
cmd[0] = writeAddress >> 8;
cmd[1] = writeAddress & 0x00FF;
cmd[2] = data >> 8;
cmd[3] = data & 0x00FF;
do
{
repeat:
SMBus_StopBit(); //If slave send NACK stop comunication
if(smbus_io_first == 0xff){
printk("io alloc failed,MLX90641_I2CRead abort!\n");
return -1;
}
--ErrorCounter; //Pre-decrement ErrorCounter
if(!ErrorCounter) //ErrorCounter=0?
{
return -1; //Yes,go out from do-while{}
}
SMBus_StartBit(); //Start condition
if(SMBus_SendByte(sa))//Send SlaveAddress ???Wr=0????????
{
goto repeat; //Repeat comunication again
}
//if(SMBus_SendByte(cmd)) //Send command
//{
// goto repeat; //Repeat comunication again
//}
for(i=0;i<4;i++){
if(SMBus_SendByte(cmd[i])) //Send data
{
goto repeat; //Repeat comunication again
}
}
SMBus_StopBit(); //Stop condition
err = 0;
break;
}
while(err);
MLX90641_I2CRead(slaveAddr,writeAddress,1, &dataCheck);
if ( dataCheck != data)
{
return -2;
}
return 0;
}
static float fabs(float a)
{
if(a > 0.000001)
return a;
else
return -a;
}
static float pow(float x,double y)
{
if(y>0)
return(x*pow(x,y-1));
else
return 1;
}
#define DBL_EPSILON 0.0000001
static double sqrt(double A)
{
double x0 = A + 0.25, x1, xx = x0;
int second = 0;
if(A<=DBL_EPSILON){
x1 = DBL_EPSILON;
//printk("sqrt < DBL_EPSILON\n");
return x1;
}
for(;;) {
x1 = (x0*x0 + A) / (2*x0);
if(fabs(x1 - x0) <= DBL_EPSILON) break;
if(xx == x1) break; // to break two value cycle.
if(second++ > 32) {printk("sqrt > 32\n");break;}
xx = x0;
x0 = x1;
}
return x1;
}
#define SCALEALPHA 0.000001
typedef struct
{
int16_t kVdd;
int16_t vdd25;
float KvPTAT;
float KtPTAT;
uint16_t vPTAT25;
float alphaPTAT;
int16_t gainEE;
float tgc;
float cpKv;
float cpKta;
uint8_t resolutionEE;
uint8_t calibrationModeEE;
float KsTa;
float ksTo[8];
int16_t ct[8];
uint16_t alpha[192];
uint8_t alphaScale;
int16_t offset[2][192];
int8_t kta[192];
uint8_t ktaScale;
int8_t kv[192];
uint8_t kvScale;
float cpAlpha;
int16_t cpOffset;
float emissivityEE;
uint16_t brokenPixels[2];
} paramsMLX90641;
static int MLX90641_DumpEE(uint8_t slaveAddr, uint16_t *eeData);
static int MLX90641_GetFrameData(uint8_t slaveAddr, uint16_t *frameData);
static int MLX90641_ExtractParameters(uint16_t *eeData, paramsMLX90641 *mlx90641);
static float MLX90641_GetVdd(uint16_t *frameData, const paramsMLX90641 *params);
static float MLX90641_GetTa(uint16_t *frameData, const paramsMLX90641 *params);
static void MLX90641_GetImage(uint16_t *frameData, const paramsMLX90641 *params, float *result);
static void MLX90641_CalculateTo(uint16_t *frameData, const paramsMLX90641 *params, float emissivity, float tr, float *result);
static int MLX90641_SetResolution(uint8_t slaveAddr, uint8_t resolution);
static int MLX90641_GetCurResolution(uint8_t slaveAddr);
static int MLX90641_SetRefreshRate(uint8_t slaveAddr, uint8_t refreshRate);
static int MLX90641_GetRefreshRate(uint8_t slaveAddr);
static int MLX90641_GetSubPageNumber(uint16_t *frameData);
static float MLX90641_GetEmissivity(const paramsMLX90641 *mlx90641);
static void MLX90641_BadPixelsCorrection(uint16_t *pixels, float *to, paramsMLX90641 *params);
static void ExtractVDDParameters(uint16_t *eeData, paramsMLX90641 *mlx90641);
static void ExtractPTATParameters(uint16_t *eeData, paramsMLX90641 *mlx90641);
static void ExtractGainParameters(uint16_t *eeData, paramsMLX90641 *mlx90641);
static void ExtractTgcParameters(uint16_t *eeData, paramsMLX90641 *mlx90641);
static void ExtractEmissivityParameters(uint16_t *eeData, paramsMLX90641 *mlx90641);
static void ExtractResolutionParameters(uint16_t *eeData, paramsMLX90641 *mlx90641);
static void ExtractKsTaParameters(uint16_t *eeData, paramsMLX90641 *mlx90641);
static void ExtractKsToParameters(uint16_t *eeData, paramsMLX90641 *mlx90641);
static void ExtractAlphaParameters(uint16_t *eeData, paramsMLX90641 *mlx90641);
static void ExtractOffsetParameters(uint16_t *eeData, paramsMLX90641 *mlx90641);
static void ExtractKtaPixelParameters(uint16_t *eeData, paramsMLX90641 *mlx90641);
static void ExtractKvPixelParameters(uint16_t *eeData, paramsMLX90641 *mlx90641);
static void ExtractCPParameters(uint16_t *eeData, paramsMLX90641 *mlx90641);
static int ExtractDeviatingPixels(uint16_t *eeData, paramsMLX90641 *mlx90641);
static int CheckEEPROMValid(uint16_t *eeData);
static int HammingDecode(uint16_t *eeData);
//------------------------------------------------------------------------------
static int MLX90641_DumpEE(uint8_t slaveAddr, uint16_t *eeData)
{
int error = 1;
#if 1 // org
error = MLX90641_I2CRead(slaveAddr, 0x2400, 832, eeData);
#else
error = 0 ;//MLX90641_I2CRead(slaveAddr, 0x2400, 32, eeData);
#endif
if (error == 0)
{
error = HammingDecode(eeData);
//printk("liuxd MLX90641_DumpEE ok\n");
}else {
printk("liuxd MLX90641_DumpEE ng\n");
}
return error;
}
//------------------------------------------------------------------------------
static int HammingDecode(uint16_t *eeData)
{
int error = 0;
int16_t parity[5];
int8_t D[16];
int16_t check;
uint16_t data;
uint16_t mask;
int addr,i;
for ( addr=16; addr<832; addr++)
{
parity[0] = -1;
parity[1] = -1;
parity[2] = -1;
parity[3] = -1;
parity[4] = -1;
data = eeData[addr];
mask = 1;
for( i = 0; i < 16; i++)
{
D[i] = (data & mask) >> i;
mask = mask << 1;
}
parity[0] = D[0]^D[1]^D[3]^D[4]^D[6]^D[8]^D[10]^D[11];
parity[1] = D[0]^D[2]^D[3]^D[5]^D[6]^D[9]^D[10]^D[12];
parity[2] = D[1]^D[2]^D[3]^D[7]^D[8]^D[9]^D[10]^D[13];
parity[3] = D[4]^D[5]^D[6]^D[7]^D[8]^D[9]^D[10]^D[14];
parity[4] = D[0]^D[1]^D[2]^D[3]^D[4]^D[5]^D[6]^D[7]^D[8]^D[9]^D[10]^D[11]^D[12]^D[13]^D[14]^D[15];
if ((parity[0]!=0) || (parity[1]!=0) || (parity[2]!=0) || (parity[3]!=0) || (parity[4]!=0))
{
check = (parity[0]<<0) + (parity[1]<<1) + (parity[2]<<2) + (parity[3]<<3) + (parity[4]<<4);
if ((check > 15)&&(check < 32))
{
switch (check)
{
case 16:
D[15] = 1 - D[15];
break;
case 24:
D[14] = 1 - D[14];
break;
case 20:
D[13] = 1 - D[13];
break;
case 18:
D[12] = 1 - D[12];
break;
case 17:
D[11] = 1 - D[11];
break;
case 31:
D[10] = 1 - D[10];
break;
case 30:
D[9] = 1 - D[9];
break;
case 29:
D[8] = 1 - D[8];
break;
case 28:
D[7] = 1 - D[7];
break;
case 27:
D[6] = 1 - D[6];
break;
case 26:
D[5] = 1 - D[5];
break;
case 25:
D[4] = 1 - D[4];
break;
case 23:
D[3] = 1 - D[3];
break;
case 22:
D[2] = 1 - D[2];
break;
case 21:
D[1] = 1 - D[1];
break;
case 19:
D[0] = 1 - D[0];
break;
}
if(error == 0)
{
error = -9;
}
data = 0;
mask = 1;
for( i = 0; i < 16; i++)
{
data = data + D[i]*mask;
mask = mask << 1;
}
}
else
{
error = -10;
}
}
eeData[addr] = data & 0x07FF;
}
return error;
}
//------------------------------------------------------------------------------
static int MLX90641_GetFrameData(uint8_t slaveAddr, uint16_t *frameData)
{
uint16_t dataReady = 1;
uint16_t controlRegister1;
uint16_t statusRegister;
int error = 1;
uint8_t cnt = 0;
uint8_t subPage = 0;
dataReady = 0;
while(dataReady == 0)
{
error = MLX90641_I2CRead(slaveAddr, 0x8000, 1, &statusRegister);
if(error != 0)
{
return error;
}
dataReady = statusRegister & 0x0008;
}
subPage = statusRegister & 0x0001;
while(dataReady != 0 && cnt < 5)
{
error = MLX90641_I2CWrite(slaveAddr, 0x8000, 0x0030);
if(error == -1)
{
return error;
}
if(subPage == 0)
{
error = MLX90641_I2CRead(slaveAddr, 0x0400, 32, frameData);
if(error != 0)
{
return error;
}
error = MLX90641_I2CRead(slaveAddr, 0x0440, 32, frameData+32);
if(error != 0)
{
return error;
}
error = MLX90641_I2CRead(slaveAddr, 0x0480, 32, frameData+64);
if(error != 0)
{
return error;
}
error = MLX90641_I2CRead(slaveAddr, 0x04C0, 32, frameData+96);
if(error != 0)
{
return error;
}
error = MLX90641_I2CRead(slaveAddr, 0x0500, 32, frameData+128);
if(error != 0)
{
return error;
}
error = MLX90641_I2CRead(slaveAddr, 0x0540, 32, frameData+160);
if(error != 0)
{
return error;
}
}
else
{
error = MLX90641_I2CRead(slaveAddr, 0x0420, 32, frameData);
if(error != 0)
{
return error;
}
error = MLX90641_I2CRead(slaveAddr, 0x0460, 32, frameData+32);
if(error != 0)
{
return error;
}
error = MLX90641_I2CRead(slaveAddr, 0x04A0, 32, frameData+64);
if(error != 0)
{
return error;
}
error = MLX90641_I2CRead(slaveAddr, 0x04E0, 32, frameData+96);
if(error != 0)
{
return error;
}
error = MLX90641_I2CRead(slaveAddr, 0x0520, 32, frameData+128);
if(error != 0)
{
return error;
}
error = MLX90641_I2CRead(slaveAddr, 0x0560, 32, frameData+160);
if(error != 0)
{
return error;
}
}
error = MLX90641_I2CRead(slaveAddr, 0x0580, 48, frameData+192);
if(error != 0)
{
return error;
}
error = MLX90641_I2CRead(slaveAddr, 0x8000, 1, &statusRegister);
if(error != 0)
{
return error;
}
dataReady = statusRegister & 0x0008;
subPage = statusRegister & 0x0001;
cnt = cnt + 1;
}
if(cnt > 4)
{
return -8;
}
error = MLX90641_I2CRead(slaveAddr, 0x800D, 1, &controlRegister1);
frameData[240] = controlRegister1;
frameData[241] = statusRegister & 0x0001;
if(error != 0)
{
return error;
}
return frameData[241];
}
//------------------------------------------------------------------------------
static int MLX90641_ExtractParameters(uint16_t *eeData, paramsMLX90641 *mlx90641)
{
int error = CheckEEPROMValid(eeData);
if(error == 0)
{
ExtractVDDParameters(eeData, mlx90641);
ExtractPTATParameters(eeData, mlx90641);
ExtractGainParameters(eeData, mlx90641);
ExtractTgcParameters(eeData, mlx90641);
ExtractEmissivityParameters(eeData, mlx90641);
ExtractResolutionParameters(eeData, mlx90641);
ExtractKsTaParameters(eeData, mlx90641);
ExtractKsToParameters(eeData, mlx90641);
ExtractAlphaParameters(eeData, mlx90641);
ExtractOffsetParameters(eeData, mlx90641);
ExtractKtaPixelParameters(eeData, mlx90641);
ExtractKvPixelParameters(eeData, mlx90641);
ExtractCPParameters(eeData, mlx90641);
error = ExtractDeviatingPixels(eeData, mlx90641);
}
return error;
}
//------------------------------------------------------------------------------
static int MLX90641_SetResolution(uint8_t slaveAddr, uint8_t resolution)
{
uint16_t controlRegister1;
int value;
int error;
value = (resolution & 0x03) << 10;
error = MLX90641_I2CRead(slaveAddr, 0x800D, 1, &controlRegister1);
if(error == 0)
{
value = (controlRegister1 & 0xF3FF) | value;
error = MLX90641_I2CWrite(slaveAddr, 0x800D, value);
}
return error;
}
//------------------------------------------------------------------------------
static int MLX90641_GetCurResolution(uint8_t slaveAddr)
{
uint16_t controlRegister1;
int resolutionRAM;
int error;
error = MLX90641_I2CRead(slaveAddr, 0x800D, 1, &controlRegister1);
if(error != 0)
{
return error;
}
resolutionRAM = (controlRegister1 & 0x0C00) >> 10;
return resolutionRAM;
}
//------------------------------------------------------------------------------
static int MLX90641_SetRefreshRate(uint8_t slaveAddr, uint8_t refreshRate)
{
uint16_t controlRegister1;
int value;
int error;
value = (refreshRate & 0x07)<<7;
error = MLX90641_I2CRead(slaveAddr, 0x800D, 1, &controlRegister1);
if(error == 0)
{
value = (controlRegister1 & 0xFC7F) | value;
error = MLX90641_I2CWrite(slaveAddr, 0x800D, value);
}
return error;
}
//------------------------------------------------------------------------------
static int MLX90641_GetRefreshRate(uint8_t slaveAddr)
{
uint16_t controlRegister1;
int refreshRate;
int error;
error = MLX90641_I2CRead(slaveAddr, 0x800D, 1, &controlRegister1);
if(error != 0)
{
return error;
}
refreshRate = (controlRegister1 & 0x0380) >> 7;
return refreshRate;
}
//------------------------------------------------------------------------------
static void MLX90641_CalculateTo(uint16_t *frameData, const paramsMLX90641 *params, float emissivity, float tr, float *result)
{
float vdd;
float ta;
float ta4;
float tr4;
float taTr;
float gain;
float irDataCP;
float irData;
float alphaCompensated;
float Sx;
float To;
float alphaCorrR[8];
int8_t range;
uint16_t subPage;
float ktaScale;
float kvScale;
float alphaScale;
float kta;
float kv;
int pixelNumber;
subPage = frameData[241];
vdd = MLX90641_GetVdd(frameData, params);
ta = MLX90641_GetTa(frameData, params);
ta4 = (ta + 273.15);
ta4 = ta4 * ta4;
ta4 = ta4 * ta4;
tr4 = (tr + 273.15);
tr4 = tr4 * tr4;
tr4 = tr4 * tr4;
taTr = tr4 - (tr4-ta4)/emissivity;
ktaScale = pow(2,(double)params->ktaScale);
kvScale = pow(2,(double)params->kvScale);
alphaScale = pow(2,(double)params->alphaScale);
alphaCorrR[1] = 1 / (1 + params->ksTo[1] * 20);
alphaCorrR[0] = alphaCorrR[1] / (1 + params->ksTo[0] * 20);
alphaCorrR[2] = 1 ;
alphaCorrR[3] = (1 + params->ksTo[2] * params->ct[3]);
alphaCorrR[4] = alphaCorrR[3] * (1 + params->ksTo[3] * (params->ct[4] - params->ct[3]));
alphaCorrR[5] = alphaCorrR[4] * (1 + params->ksTo[4] * (params->ct[5] - params->ct[4]));
alphaCorrR[6] = alphaCorrR[5] * (1 + params->ksTo[5] * (params->ct[6] - params->ct[5]));
alphaCorrR[7] = alphaCorrR[6] * (1 + params->ksTo[6] * (params->ct[7] - params->ct[6]));
//------------------------- Gain calculation -----------------------------------
gain = frameData[202];
if(gain > 32767)
{
gain = gain - 65536;
}
gain = params->gainEE / gain;
//------------------------- To calculation -------------------------------------
irDataCP = frameData[200];
if(irDataCP > 32767)
{
irDataCP = irDataCP - 65536;
}
irDataCP = irDataCP * gain;
irDataCP = irDataCP - params->cpOffset * (1 + params->cpKta * (ta - 25)) * (1 + params->cpKv * (vdd - 3.3));
for( pixelNumber = 0; pixelNumber < 192; pixelNumber++)
{
irData = frameData[pixelNumber];
if(irData > 32767)
{
irData = irData - 65536;
}
irData = irData * gain;
kta = (float)params->kta[pixelNumber]/ktaScale;
kv = (float)params->kv[pixelNumber]/kvScale;
irData = irData - params->offset[subPage][pixelNumber]*(1 + kta*(ta - 25))*(1 + kv*(vdd - 3.3));
irData = irData - params->tgc * irDataCP;
irData = irData / emissivity;
alphaCompensated = SCALEALPHA*alphaScale/params->alpha[pixelNumber];
alphaCompensated = alphaCompensated*(1 + params->KsTa * (ta - 25));
Sx = alphaCompensated * alphaCompensated * alphaCompensated * (irData + alphaCompensated * taTr);
Sx = sqrt(sqrt(Sx)) * params->ksTo[2];
To = sqrt(sqrt(irData/(alphaCompensated * (1 - params->ksTo[2] * 273.15) + Sx) + taTr)) - 273.15;
if(To < params->ct[1])
{
range = 0;
}
else if(To < params->ct[2])
{
range = 1;
}
else if(To < params->ct[3])
{
range = 2;
}
else if(To < params->ct[4])
{
range = 3;
}
else if(To < params->ct[5])
{
range = 4;
}
else if(To < params->ct[6])
{
range = 5;
}
else if(To < params->ct[7])
{
range = 6;
}
else
{
range = 7;
}
To = sqrt(sqrt(irData / (alphaCompensated * alphaCorrR[range] * (1 + params->ksTo[range] * (To - params->ct[range]))) + taTr)) - 273.15;
result[pixelNumber] = To;
}
}
//------------------------------------------------------------------------------
static void MLX90641_GetImage(uint16_t *frameData, const paramsMLX90641 *params, float *result)
{
float vdd;
float ta;
float gain;
float irDataCP;
float irData;
float alphaCompensated;
float image;
uint16_t subPage;
int pixelNumber;
subPage = frameData[241];
vdd = MLX90641_GetVdd(frameData, params);
ta = MLX90641_GetTa(frameData, params);
//------------------------- Gain calculation -----------------------------------
gain = frameData[202];
if(gain > 32767)
{
gain = gain - 65536;
}
gain = params->gainEE / gain;
//------------------------- Image calculation -------------------------------------
irDataCP = frameData[200];
if(irDataCP > 32767)
{
irDataCP = irDataCP - 65536;
}
irDataCP = irDataCP * gain;
irDataCP = irDataCP - params->cpOffset * (1 + params->cpKta * (ta - 25)) * (1 + params->cpKv * (vdd - 3.3));
for( pixelNumber = 0; pixelNumber < 192; pixelNumber++)
{
irData = frameData[pixelNumber];
if(irData > 32767)
{
irData = irData - 65536;
}
irData = irData * gain;
irData = irData - params->offset[subPage][pixelNumber]*(1 + params->kta[pixelNumber]*(ta - 25))*(1 + params->kv[pixelNumber]*(vdd - 3.3));
irData = irData - params->tgc * irDataCP;
alphaCompensated = (params->alpha[pixelNumber] - params->tgc * params->cpAlpha);
image = irData*alphaCompensated;
result[pixelNumber] = image;
}
}
//------------------------------------------------------------------------------
static float MLX90641_GetVdd(uint16_t *frameData, const paramsMLX90641 *params)
{
float vdd;
float resolutionCorrection;
int resolutionRAM;
vdd = frameData[234];
if(vdd > 32767)
{
vdd = vdd - 65536;
}
resolutionRAM = (frameData[240] & 0x0C00) >> 10;
resolutionCorrection = pow(2, (double)params->resolutionEE) / pow(2, (double)resolutionRAM);
vdd = (resolutionCorrection * vdd - params->vdd25) / params->kVdd + 3.3;
return vdd;
}
//------------------------------------------------------------------------------
static float MLX90641_GetTa(uint16_t *frameData, const paramsMLX90641 *params)
{
float ptat;
float ptatArt;
float vdd;
float ta;
vdd = MLX90641_GetVdd(frameData, params);
ptat = frameData[224];
if(ptat > 32767)
{
ptat = ptat - 65536;
}
ptatArt = frameData[192];
if(ptatArt > 32767)
{
ptatArt = ptatArt - 65536;
}
ptatArt = (ptat / (ptat * params->alphaPTAT + ptatArt)) * pow(2, (double)18);
ta = (ptatArt / (1 + params->KvPTAT * (vdd - 3.3)) - params->vPTAT25);
ta = ta / params->KtPTAT + 25;
return ta;
}
//------------------------------------------------------------------------------
static int MLX90641_GetSubPageNumber(uint16_t *frameData)
{
return frameData[241];
}
//------------------------------------------------------------------------------
static void MLX90641_BadPixelsCorrection(uint16_t *pixels, float *to, paramsMLX90641 *params)
{
float ap[2];
uint8_t pix;
uint8_t line;
uint8_t column;
pix = 0;
while(pixels[pix]< 65535)
{
line = pixels[pix]>>5;
column = pixels[pix] - (line<<5);
if(column == 0)
{
to[pixels[pix]] = to[pixels[pix]+1];
}
else if(column == 1 || column == 14)
{
to[pixels[pix]] = (to[pixels[pix]-1]+to[pixels[pix]+1])/2.0;
}
else if(column == 15)
{
to[pixels[pix]] = to[pixels[pix]-1];
}
else
{
ap[0] = to[pixels[pix]+1] - to[pixels[pix]+2];
ap[1] = to[pixels[pix]-1] - to[pixels[pix]-2];
if(fabs(ap[0]) > fabs(ap[1]))
{
to[pixels[pix]] = to[pixels[pix]-1] + ap[1];
}
else
{
to[pixels[pix]] = to[pixels[pix]+1] + ap[0];
}
}
pix = pix + 1;
}
}
//------------------------------------------------------------------------------
static void ExtractVDDParameters(uint16_t *eeData, paramsMLX90641 *mlx90641)
{
int16_t kVdd;
int16_t vdd25;
kVdd = eeData[39];
if(kVdd > 1023)
{
kVdd = kVdd - 2048;
}
kVdd = 32 * kVdd;
vdd25 = eeData[38];
if(vdd25 > 1023)
{
vdd25 = vdd25 - 2048;
}
vdd25 = 32 * vdd25;
mlx90641->kVdd = kVdd;
mlx90641->vdd25 = vdd25;
}
//------------------------------------------------------------------------------
static void ExtractPTATParameters(uint16_t *eeData, paramsMLX90641 *mlx90641)
{
float KvPTAT;
float KtPTAT;
int16_t vPTAT25;
float alphaPTAT;
KvPTAT = eeData[43];
if(KvPTAT > 1023)
{
KvPTAT = KvPTAT - 2048;
}
KvPTAT = KvPTAT/4096;
KtPTAT = eeData[42];
if(KtPTAT > 1023)
{
KtPTAT = KtPTAT - 2048;
}
KtPTAT = KtPTAT/8;
vPTAT25 = 32 * eeData[40] + eeData[41];
alphaPTAT = eeData[44] / 128.0f;
mlx90641->KvPTAT = KvPTAT;
mlx90641->KtPTAT = KtPTAT;
mlx90641->vPTAT25 = vPTAT25;
mlx90641->alphaPTAT = alphaPTAT;
}
//------------------------------------------------------------------------------
static void ExtractGainParameters(uint16_t *eeData, paramsMLX90641 *mlx90641)
{
int16_t gainEE;
gainEE = 32 * eeData[36] + eeData[37];
mlx90641->gainEE = gainEE;
}
//------------------------------------------------------------------------------
static void ExtractTgcParameters(uint16_t *eeData, paramsMLX90641 *mlx90641)
{
float tgc;
tgc = eeData[51] & 0x01FF;
if(tgc > 255)
{
tgc = tgc - 512;
}
tgc = tgc / 64.0f;
mlx90641->tgc = tgc;
}
//------------------------------------------------------------------------------
static void ExtractEmissivityParameters(uint16_t *eeData, paramsMLX90641 *mlx90641)
{
float emissivity;
emissivity = eeData[35];
if(emissivity > 1023)
{
emissivity = emissivity - 2048;
}
emissivity = emissivity/512;
mlx90641->emissivityEE = emissivity;
}
//------------------------------------------------------------------------------
static void ExtractResolutionParameters(uint16_t *eeData, paramsMLX90641 *mlx90641)
{
uint8_t resolutionEE;
resolutionEE = (eeData[51] & 0x0600) >> 9;
mlx90641->resolutionEE = resolutionEE;
}
//------------------------------------------------------------------------------
static void ExtractKsTaParameters(uint16_t *eeData, paramsMLX90641 *mlx90641)
{
float KsTa;
KsTa = eeData[34];
if(KsTa > 1023)
{
KsTa = KsTa - 2048;
}
KsTa = KsTa / 32768.0f;
mlx90641->KsTa = KsTa;
}
//------------------------------------------------------------------------------
static void ExtractKsToParameters(uint16_t *eeData, paramsMLX90641 *mlx90641)
{
int KsToScale;
int i;
mlx90641->ct[0] = -40;
mlx90641->ct[1] = -20;
mlx90641->ct[2] = 0;
mlx90641->ct[3] = 80;
mlx90641->ct[4] = 120;
mlx90641->ct[5] = eeData[58];
mlx90641->ct[6] = eeData[60];
mlx90641->ct[7] = eeData[62];
KsToScale = eeData[52];
KsToScale = 1 << KsToScale;
mlx90641->ksTo[0] = eeData[53];
mlx90641->ksTo[1] = eeData[54];
mlx90641->ksTo[2] = eeData[55];
mlx90641->ksTo[3] = eeData[56];
mlx90641->ksTo[4] = eeData[57];
mlx90641->ksTo[5] = eeData[59];
mlx90641->ksTo[6] = eeData[61];
mlx90641->ksTo[7] = eeData[63];
for( i = 0; i < 8; i++)
{
if(mlx90641->ksTo[i] > 1023)
{
mlx90641->ksTo[i] = mlx90641->ksTo[i] - 2048;
}
mlx90641->ksTo[i] = mlx90641->ksTo[i] / KsToScale;
}
}
//------------------------------------------------------------------------------
static void ExtractAlphaParameters(uint16_t *eeData, paramsMLX90641 *mlx90641)
{
float rowMaxAlphaNorm[6];
uint16_t scaleRowAlpha[6];
uint8_t alphaScale;
float alphaTemp[192];
float temp;
int p = 0;
int i,j;
scaleRowAlpha[0] = (eeData[25] >> 5) + 20;
scaleRowAlpha[1] = (eeData[25] & 0x001F) + 20;
scaleRowAlpha[2] = (eeData[26] >> 5) + 20;
scaleRowAlpha[3] = (eeData[26] & 0x001F) + 20;
scaleRowAlpha[4] = (eeData[27] >> 5) + 20;
scaleRowAlpha[5] = (eeData[27] & 0x001F) + 20;
for( i = 0; i < 6; i++)
{
rowMaxAlphaNorm[i] = eeData[28 + i] / pow(2,(double)scaleRowAlpha[i]);
rowMaxAlphaNorm[i] = rowMaxAlphaNorm[i] / 2047.0f;
}
for( i = 0; i < 6; i++)
{
for( j = 0; j < 32; j ++)
{
p = 32 * i +j;
alphaTemp[p] = eeData[256 + p] * rowMaxAlphaNorm[i];
alphaTemp[p] = alphaTemp[p] - mlx90641->tgc * mlx90641->cpAlpha;
alphaTemp[p] = SCALEALPHA/alphaTemp[p];
}
}
temp = alphaTemp[0];
for( i = 1; i < 192; i++)
{
if (alphaTemp[i] > temp)
{
temp = alphaTemp[i];
}
}
alphaScale = 0;
while(temp < 32768)
{
temp = temp*2;
alphaScale = alphaScale + 1;
}
for( i = 0; i < 192; i++)
{
temp = alphaTemp[i] * pow(2,(double)alphaScale);
mlx90641->alpha[i] = (temp + 0.5);
}
mlx90641->alphaScale = alphaScale;
}
//------------------------------------------------------------------------------
static void ExtractOffsetParameters(uint16_t *eeData, paramsMLX90641 *mlx90641)
{
int scaleOffset;
int16_t offsetRef;
int16_t tempOffset;
int i;
scaleOffset = eeData[16] >> 5;
scaleOffset = 1 << scaleOffset;
offsetRef = 32 * eeData[17] + eeData[18];
if (offsetRef > 32767)
{
offsetRef = offsetRef - 65536;
}
for( i = 0; i < 192; i++)
{
tempOffset = eeData[64 + i];
if(tempOffset > 1023)
{
tempOffset = eeData[64 + i] - 2048;
}
mlx90641->offset[0][i] = tempOffset * scaleOffset + offsetRef;
tempOffset = eeData[640 + i];
if(tempOffset > 1023)
{
tempOffset = eeData[640 + i] - 2048;
}
mlx90641->offset[1][i] = tempOffset * scaleOffset + offsetRef;
}
}
//------------------------------------------------------------------------------
static void ExtractKtaPixelParameters(uint16_t *eeData, paramsMLX90641 *mlx90641)
{
uint8_t ktaScale1;
uint8_t ktaScale2;
int16_t ktaAvg;
int16_t tempKta;
float ktaTemp[192];
float temp;
int i;
ktaAvg = eeData[21];
if (ktaAvg > 1023)
{
ktaAvg = ktaAvg - 2048;
}
ktaScale1 = eeData[22] >> 5;
ktaScale2 = eeData[22] & 0x001F;
for( i = 0; i < 192; i++)
{
tempKta = (eeData[448 + i] >> 5);
if (tempKta > 31)
{
tempKta = tempKta - 64;
}
ktaTemp[i] = tempKta * pow(2,(double)ktaScale2);
ktaTemp[i] = ktaTemp[i] + ktaAvg;
ktaTemp[i] = ktaTemp[i] / pow(2,(double)ktaScale1);
}
temp = fabs(ktaTemp[0]);
for( i = 1; i < 192; i++)
{
if (fabs(ktaTemp[i]) > temp)
{
temp = fabs(ktaTemp[i]);
}
}
ktaScale1 = 0;
while(temp < 64)
{
temp = temp*2;
ktaScale1 = ktaScale1 + 1;
}
for( i = 0; i < 192; i++)
{
temp = ktaTemp[i] * pow(2,(double)ktaScale1);
if (temp < 0)
{
mlx90641->kta[i] = (temp - 0.5);
}
else
{
mlx90641->kta[i] = (temp + 0.5);
}
}
mlx90641->ktaScale = ktaScale1;
}
//------------------------------------------------------------------------------
static void ExtractKvPixelParameters(uint16_t *eeData, paramsMLX90641 *mlx90641)
{
uint8_t kvScale1;
uint8_t kvScale2;
int16_t kvAvg;
int16_t tempKv;
float kvTemp[192];
float temp;
int i;
kvAvg = eeData[23];
if (kvAvg > 1023)
{
kvAvg = kvAvg - 2048;
}
kvScale1 = eeData[24] >> 5;
kvScale2 = eeData[24] & 0x001F;
for( i = 0; i < 192; i++)
{
tempKv = (eeData[448 + i] & 0x001F);
if (tempKv > 15)
{
tempKv = tempKv - 32;
}
kvTemp[i] = tempKv * pow(2,(double)kvScale2);
kvTemp[i] = kvTemp[i] + kvAvg;
kvTemp[i] = kvTemp[i] / pow(2,(double)kvScale1);
}
temp = fabs(kvTemp[0]);
for( i = 1; i < 192; i++)
{
if (fabs(kvTemp[i]) > temp)
{
temp = fabs(kvTemp[i]);
}
}
kvScale1 = 0;
while(temp < 64)
{
temp = temp*2;
kvScale1 = kvScale1 + 1;
}
for( i = 0; i < 192; i++)
{
temp = kvTemp[i] * pow(2,(double)kvScale1);
if (temp < 0)
{
mlx90641->kv[i] = (temp - 0.5);
}
else
{
mlx90641->kv[i] = (temp + 0.5);
}
}
mlx90641->kvScale = kvScale1;
}
//------------------------------------------------------------------------------
static void ExtractCPParameters(uint16_t *eeData, paramsMLX90641 *mlx90641)
{
float alphaCP;
int16_t offsetCP;
float cpKv;
float cpKta;
uint8_t alphaScale;
uint8_t ktaScale1;
uint8_t kvScale;
alphaScale = eeData[46];
offsetCP = 32 * eeData[47] + eeData[48];
if (offsetCP > 32767)
{
offsetCP = offsetCP - 65536;
}
alphaCP = eeData[45];
if (alphaCP > 1023)
{
alphaCP = alphaCP - 2048;
}
alphaCP = alphaCP / pow(2,(double)alphaScale);
cpKta = eeData[49] & 0x001F;
if (cpKta > 31)
{
cpKta = cpKta - 64;
}
ktaScale1 = eeData[49] >> 6;
mlx90641->cpKta = cpKta / pow(2,(double)ktaScale1);
cpKv = eeData[50] & 0x001F;
if (cpKv > 31)
{
cpKv = cpKv - 64;
}
kvScale = eeData[50] >> 6;
mlx90641->cpKv = cpKv / pow(2,(double)kvScale);
mlx90641->cpAlpha = alphaCP;
mlx90641->cpOffset = offsetCP;
}
//------------------------------------------------------------------------------
static float MLX90641_GetEmissivity(const paramsMLX90641 *mlx90641)
{
return mlx90641->emissivityEE;
}
//------------------------------------------------------------------------------
static int ExtractDeviatingPixels(uint16_t *eeData, paramsMLX90641 *mlx90641)
{
uint16_t pixCnt = 0;
uint16_t brokenPixCnt = 0;
int warn = 0;
for(pixCnt = 0; pixCnt<3; pixCnt++)
{
mlx90641->brokenPixels[pixCnt] = 0xFFFF;
}
pixCnt = 0;
while (pixCnt < 192 && brokenPixCnt < 3)
{
if((eeData[pixCnt+64] == 0) && (eeData[pixCnt+256] == 0) && (eeData[pixCnt+448] == 0) && (eeData[pixCnt+640] == 0))
{
mlx90641->brokenPixels[brokenPixCnt] = pixCnt;
brokenPixCnt = brokenPixCnt + 1;
}
pixCnt = pixCnt + 1;
}
if(brokenPixCnt > 1)
{
warn = -3;
}
return warn;
}
//------------------------------------------------------------------------------
static int CheckEEPROMValid(uint16_t *eeData)
{
int deviceSelect;
deviceSelect = eeData[10] & 0x0040;
if(deviceSelect != 0)
{
return 0;
}
return -7;
}
static int mlx90641_ta = 0;
static unsigned char slaveAddress;
static int eeMLX90641[832];
static int mlx90641Frame[242];
static paramsMLX90641 mlx90641;
static float emissivity = 0.95;
static float tr = 23.15;
static float mlx90641To[192];
//int MLX90641_ExtractParameters(uint16_t *eeData, paramsMLX90641 *mlx90641)
//void MLX90641_CalculateTo(uint16_t *frameData, const paramsMLX90641 *params, float emissivity, float tr, float *result)
//int MLX90641_DumpEE(uint8_t slaveAddr, uint16_t *eeData);
//int MLX90641_GetFrameData(uint8_t slaveAddr, uint16_t *frameData);
//float MLX90641_GetTa(uint16_t *frameData, const paramsMLX90641 *params)
static void mlx90641_main_ta(void)
{
slaveAddress = 0x33;
#if 1
MLX90641_DumpEE(slaveAddress, eeMLX90641);
MLX90641_ExtractParameters(eeMLX90641, &mlx90641);
MLX90641_GetFrameData(0x33, mlx90641Frame);
mlx90641_ta = (int)MLX90641_GetTa(mlx90641Frame,&mlx90641);
#else
#endif
printk("mlx90641_ta=%d\n",mlx90641_ta);
}
static void mlx90641_main_to(void)
{
slaveAddress = 0x33;
MLX90641_DumpEE(slaveAddress, eeMLX90641);
MLX90641_ExtractParameters(eeMLX90641, &mlx90641);
MLX90641_GetFrameData(0x33, mlx90641Frame);
MLX90641_CalculateTo(mlx90641Frame,&mlx90641,emissivity,tr,mlx90641To);
printk("mlx90641_to0=%d\n",(int)mlx90641To[0]);
printk("mlx90641_to1=%d\n",(int)mlx90641To[1]);
printk("mlx90641_to2=%d\n",(int)mlx90641To[2]);
printk("mlx90641_to3=%d\n",(int)mlx90641To[3]);
mlx90641_ta = mlx90641To[0];
}
#endif
人体测温 melexis迈来芯 linux 平台mlx90614/mlx90621/mlx90641驱动调试相关推荐
- 基于红外热成像人体测温系统解决方案的组成
概述 当前,各行各业已基本实现复工复产,但新冠肺炎疫情防控仍处在关键阶段.疫情期间,车站.机场.写字楼等公共场所人流聚集,该如何监控异常体温,成为一大难题.如何更高效地监测人员体温信息,且避免人员发生 ...
- 基于红外传感器人体测温系统设计(STC89C51单片机)
目 录 摘 要 I ABSTRACT II 目 录 III 1绪论 1 1.1选题背景及依据 1 1.2国内外研究现状 1 1.3研究内容 3 2 红外传感器人体测温系统原理及方案设计 4 2.1温度 ...
- [C#] 折腾海康威视的人体测温 模组
单位的项目需要测温,同事买了个海康威视的人体测温机芯,型号位:TB-4117-3/S,给了一份pdf的说明书. 按说明书把设备连接设置好,从官网下载vb.net教程了sdk,我的个乖乖,压缩包就有70 ...
- 红外测温仪人体测温解决方案
红外人体测温仪是一种利用红外线照射的测温仪器,在此之前,红外测温都是作为工厂生产的用的,用来检测产品的温度,和监测设备的运行发热状态.逐渐的人们突发奇想,转变用于人体测温,来规避人员之间身体直接接触( ...
- 智能无感人体测温系统解决方案
中国已全面进入"全民战疫"的非常状态.随着春运返程高峰的到来,全国各大城市的防疫形势更加严峻,防控进入关键时期.6108方案凭借自身在AIoT领域的技术优势,推出了一套智能无感人体 ...
- [linux kernel] 内核下ksz8081驱动调试
系统版本:Ubuntu18.04-64 编译器版本:gcc version 7.4.0 (Ubuntu/Linaro 7.4.0-1ubuntu1~18.04.1) uboot版本:2018.07 - ...
- STM32 + CT1711超级准的人体测温方案
一.前言 做一个手腕式检测设备玩玩,其中设计到人体温度检测,就测试手腕温度皮肤表面温度,采用ct1711温度传感器,该传感器是可以直接与人体接触的,其参数如下: CT1711 的典型静态电流仅为10n ...
- Linux平台Segmentation fault(段错误)调试方法
1. 段错误是什么 一句话来说,段错误是指访问的内存超出了系统给这个程序所设定的内存空间,例如访问了不存在的内存地址.访问了系统保护的内存地址.访问了只读的内存地址等等情况. 2. 段错误的原因 段错 ...
- bcm4360 蓝牙 linux,Android BCM4330 蓝牙BT驱动调试记录
网上关于BT的驱动很少,所以我在开发过程中把其中的步骤记录下来.供大家相互学习讨论. 一.关于BT driver的移植: 1. Enablebluetootch in BoadConfig.mk BO ...
最新文章
- Flask学习之路(一)--初识flask
- sed替换ip地址为网关
- 通过ngrok在内网捕获meterpreter反弹
- 对弈程序基本技术---最小-最大搜索
- 如果给你一个亿,你想去干嘛?各专业的科研狗是这样回答的……
- python编写自制编译器_编译器构造-编译Python
- Spring精华问答 | 什么是YAML?
- 铃木uy125最高时速_五菱宏光mini EV月销三万辆,铃木是否后悔退出中国?
- 老兵的十年职场之路(一)
- 4999元起!华为Mate 30 5G系列今日预售:支持SA及NSA 5G双模
- 05_DecisionTree_统计学习方法
- mapper mysl实现批量插入 更新
- 高德地图基于阿里云MaxCompute的最佳实践
- couldn't create PTY
- 伺服电机编码器为什么要调零或校正
- 【?】【9908】守望者的逃离
- MRR@K P@K R@K意义阐述与对比
- 2021亚太杯A|B|C题全网最全解题思路+数据分享
- java compiler类_利用 JavaCompiler 编译 Java 类文件
- 面经分享 | 2年经验,1个月拿下阿里P6 Offer
热门文章
- line怎么添加好友?
- QT应用程序-获取Application-获取主窗口指针-QT内嵌浏览器-QT菜单动作
- 实验室服务器使用指南:pytorch、tensorflow安装问题、visdom安装问题本地远程调用服务器jupyter问题、本地pycharm远程连接服务器
- 海康网络摄像头android,海康网络摄像头的Android端Demo
- 边缘检测算子性能评价Matlab实现之——MSE,PSNR,FOM(品质因数)
- 2018.11.3 Nescafe18 T2 太鼓达人
- Java 浏览器下载文件及文件预览
- SAP 物料主数据BP主数据同步第三方系统
- 北京八维计算机学校分数线,廊坊 中专 排名
- Enlight官方第三届“金融帝国杯”玩家游戏视频邀请赛《竞赛规则》(2022.12.23修订)