Merge pull request #1062 from openmv/mlx_driver

Update MLX and FIR drivers.
This commit is contained in:
Ibrahim Abd Elkader 2020-12-28 20:21:46 +02:00 committed by GitHub
commit 6e0f5c5d67
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 1014 additions and 289 deletions

View File

@ -53,6 +53,7 @@ MICROPY_DIR=micropython
LEPTON_DIR=drivers/lepton
LSM6DS3_DIR=drivers/lsm6ds3
WINC1500_DIR=drivers/winc1500
MLX90621_DIR=drivers/mlx90621
MLX90640_DIR=drivers/mlx90640
LIBPDM_DIR=lib/libpdm
TENSORFLOW_DIR=lib/libtf

View File

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -0,0 +1,25 @@
# This file is part of the OpenMV project.
#
# Copyright (c) 2013-2019 Ibrahim Abdelkader <iabdalkader@openmv.io>
# Copyright (c) 2013-2019 Kwabena W. Agyeman <kwagyeman@openmv.io>
#
# This work is licensed under the MIT license, see the file LICENSE for details.
#
# MLX90621 Makefile
SRCS = $(wildcard src/*.c)
OBJS = $(addprefix $(BUILD)/, $(SRCS:.c=.o))
OBJ_DIRS = $(sort $(dir $(OBJS)))
all: | $(OBJ_DIRS) $(OBJS)
$(OBJ_DIRS):
$(MKDIR) -p $@
$(BUILD)/%.o : %.c
$(ECHO) "CC $<"
$(CC) $(CFLAGS) -c -o $@ $<
$(BUILD)/%.o : %.s
$(ECHO) "AS $<"
$(AS) $(AFLAGS) $< -o $@
-include $(OBJS:%.o=%.d)

View File

@ -0,0 +1,54 @@
/**
* @copyright (C) 2017 Melexis N.V.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifndef _MLX621_API_H_
#define _MLX621_API_H_
#define SCALEALPHA 0.000001
typedef struct
{
int16_t vTh25;
float kT1;
float kT2;
float tgc;
float KsTa;
float ksTo;
float alpha[64];
float ai[64];
float bi[64];
float cpAlpha;
float cpA;
float cpB;
uint16_t brokenPixels[5];
uint16_t outlierPixels[5];
} paramsMLX90621;
int MLX90621_DumpEE(uint8_t *eeData);
int MLX90621_GetFrameData(uint16_t *frameData);
int MLX90621_Configure(uint8_t *eeData);
int MLX90621_GetOscillatorTrim(uint16_t *oscTrim);
int MLX90621_GetConfiguration(uint16_t *cfgReg);
int MLX90621_ExtractParameters(uint8_t *eeData, paramsMLX90621 *mlx90621);
float MLX90621_GetTa(uint16_t *frameData, const paramsMLX90621 *params);
void MLX90621_GetImage(uint16_t *frameData, const paramsMLX90621 *params, float *result);
void MLX90621_CalculateTo(uint16_t *frameData, const paramsMLX90621 *params, float emissivity, float tr, float *result);
int MLX90621_SetResolution(uint8_t resolution);
int MLX90621_GetCurResolution();
int MLX90621_SetRefreshRate(uint8_t refreshRate);
int MLX90621_GetRefreshRate();
#endif

View File

@ -0,0 +1,25 @@
/**
* @copyright (C) 2017 Melexis N.V.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifndef _MLX90621_I2C_Driver_H_
#define _MLX90621_I2C_Driver_H_
#include <stdint.h>
void MLX90621_I2CInit(I2C_HandleTypeDef *i2c);
int MLX90621_I2CReadEEPROM(uint8_t slaveAddr, uint8_t startAddress, uint16_t nMemAddressRead, uint8_t *data);
int MLX90621_I2CRead(uint8_t slaveAddr, uint8_t command, uint8_t startAddress,
uint8_t addressStep, uint8_t nMemAddressRead, uint16_t *data);
int MLX90621_I2CWrite(uint8_t slaveAddr, uint8_t command, uint8_t checkValue, uint16_t data);
#endif

View File

@ -0,0 +1,476 @@
/**
* @copyright (C) 2017 Melexis N.V.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include STM32_HAL_H
#include <MLX90621_I2C_Driver.h>
#include <MLX90621_API.h>
#include <math.h>
#define pow(a,b) powf(a,b)
#define sqrt(x) sqrtf(x)
static void ExtractPTATParameters(uint8_t *eeData, paramsMLX90621 *mlx90621);
static void ExtractTgcParameters(uint8_t *eeData, paramsMLX90621 *mlx90621);
static void ExtractKsTaParameters(uint8_t *eeData, paramsMLX90621 *mlx90621);
static void ExtractKsToParameters(uint8_t *eeData, paramsMLX90621 *mlx90621);
static void ExtractAlphaParameters(uint8_t *eeData, paramsMLX90621 *mlx90621);
static void ExtractOffsetParameters(uint8_t *eeData, paramsMLX90621 *mlx90621);
int MLX90621_DumpEE(uint8_t *eeData)
{
return MLX90621_I2CReadEEPROM(0x50, 0, 256, eeData);
}
int MLX90621_GetFrameData(uint16_t *frameData)
{
int error = 1;
error = MLX90621_I2CRead(0x60, 0x02, 0, 1, 66, frameData);
return error;
}
int MLX90621_Configure(uint8_t *eeData)
{
int error = 1;
uint16_t value;
error = MLX90621_I2CWrite(0x60, 0x04, 0xAA, eeData[247]);
if (error != 0)
{
return error;
}
value = 256*eeData[246] + eeData[245];
value = value | 0x0400;
error = MLX90621_I2CWrite(0x60, 0x03, 0x55, value);
return error;
}
int MLX90621_GetOscillatorTrim(uint16_t *oscTrim)
{
int error = 1;
error = MLX90621_I2CRead(0x60, 0x02, 0x93, 0, 1, oscTrim);
return error;
}
int MLX90621_GetConfiguration(uint16_t *cfgReg)
{
int error = 1;
error = MLX90621_I2CRead(0x60, 0x02, 0x92, 0, 1, cfgReg);
return error;
}
int MLX90621_ExtractParameters(uint8_t *eeData, paramsMLX90621 *mlx90621)
{
int error = 0;
ExtractPTATParameters(eeData, mlx90621);
ExtractTgcParameters(eeData, mlx90621);
ExtractKsTaParameters(eeData, mlx90621);
ExtractKsToParameters(eeData, mlx90621);
ExtractAlphaParameters(eeData, mlx90621);
ExtractOffsetParameters(eeData, mlx90621);
return error;
}
//------------------------------------------------------------------------------
int MLX90621_SetResolution(uint8_t resolution)
{
uint16_t cfgReg;
int value;
int error;
value = (resolution & 0x03) << 4;
error = MLX90621_GetConfiguration(&cfgReg);
if(error == 0)
{
value = (cfgReg & 0xFFCF) | value;
error = MLX90621_I2CWrite(0x60, 0x03, 0x55, value);
}
return error;
}
//------------------------------------------------------------------------------
int MLX90621_GetCurResolution()
{
uint16_t cfgReg;
int resolution;
int error;
error = MLX90621_GetConfiguration(&cfgReg);
if(error != 0)
{
return error;
}
resolution = (cfgReg & 0x0030) >> 4;
return resolution;
}
//------------------------------------------------------------------------------
int MLX90621_SetRefreshRate(uint8_t refreshRate)
{
uint16_t cfgReg;
int value;
int error;
value = refreshRate & 0x0F;
error = MLX90621_GetConfiguration(&cfgReg);
if(error == 0)
{
value = (cfgReg & 0xFFF0) | value;
error = MLX90621_I2CWrite(0x60, 0x03, 0x55, value);
}
return error;
}
//------------------------------------------------------------------------------
int MLX90621_GetRefreshRate()
{
uint16_t cfgReg;
int rr;
int error;
error = MLX90621_GetConfiguration(&cfgReg);
if(error != 0)
{
return error;
}
rr = (cfgReg & 0x000F);
return rr;
}
//------------------------------------------------------------------------------
void MLX90621_CalculateTo(uint16_t *frameData, const paramsMLX90621 *params, float emissivity, float tr, float *result)
{
float ta;
float ta4;
float tr4;
float taTr;
float irDataCP;
float irData;
float alphaCompensated;
float Sx;
float To;
ta = MLX90621_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;
//------------------------- To calculation -------------------------------------
irDataCP = frameData[65];
if(irDataCP > 32767)
{
irDataCP = irDataCP - 65536;
}
irDataCP = irDataCP - (params->cpA + params->cpB * (ta - 25));
for( int pixelNumber = 0; pixelNumber < 64; pixelNumber++)
{
irData = frameData[pixelNumber];
if(irData > 32767)
{
irData = irData - 65536;
}
irData = irData - (params->ai[pixelNumber] + params->bi[pixelNumber] * (ta - 25));
irData = irData - params->tgc * irDataCP;
irData = irData / emissivity;
alphaCompensated = params->alpha[pixelNumber] - params->tgc * params->cpAlpha;
alphaCompensated = alphaCompensated *(1 + params->KsTa * (ta - 25));
Sx = alphaCompensated * alphaCompensated * alphaCompensated * (irData + alphaCompensated * taTr);
Sx = sqrt(sqrt(Sx)) * params->ksTo;
To = sqrt(sqrt(irData/(alphaCompensated * (1 - params->ksTo * 273.15) + Sx) + taTr)) - 273.15;
result[pixelNumber] = To;
}
}
//------------------------------------------------------------------------------
void MLX90621_GetImage(uint16_t *frameData, const paramsMLX90621 *params, float *result)
{
float ta;
float irDataCP;
float irData;
float alphaCompensated;
ta = MLX90621_GetTa(frameData, params);
//------------------------- Image calculation -------------------------------------
irDataCP = frameData[65];
if(irDataCP > 32767)
{
irDataCP = irDataCP - 65536;
}
irDataCP = irDataCP - (params->cpA + params->cpB * (ta - 25));
for( int pixelNumber = 0; pixelNumber < 64; pixelNumber++)
{
irData = frameData[pixelNumber];
if(irData > 32767)
{
irData = irData - 65536;
}
irData = irData - (params->ai[pixelNumber] + params->bi[pixelNumber] * (ta - 25));
irData = irData - params->tgc * irDataCP;
alphaCompensated = params->alpha[pixelNumber] - params->tgc * irDataCP;
alphaCompensated = alphaCompensated *(1 + params->KsTa * (ta - 25));
result[pixelNumber] = irData/alphaCompensated;
}
}
//------------------------------------------------------------------------------
float MLX90621_GetTa(uint16_t *frameData, const paramsMLX90621 *params)
{
float ptat;
float ta;
ptat = frameData[64];
if(ptat > 32767)
{
ptat = ptat - 65536;
}
ta = params->vTh25 - ptat;
ta = 4*params->kT2*ta;
ta = params->kT1*params->kT1 - ta;
ta = sqrt(ta)-params->kT1;
ta = ta / (2*params->kT2);
ta = ta + 25;
return ta;
}
//------------------------------------------------------------------------------
static void ExtractPTATParameters(uint8_t *eeData, paramsMLX90621 *mlx90621)
{
float kt1;
float kt2;
int16_t vth25;
int kt1Scale = 0;
int kt2Scale = 0;
int resolution = 3;
uint16_t data;
resolution = resolution - MLX90621_GetCurResolution();
kt1Scale = (eeData[210] & 0xF0) >> 4;
kt2Scale = eeData[210] & 0x0F;
kt2Scale = kt2Scale + 10;
kt1Scale = kt1Scale + resolution;
kt2Scale = kt2Scale + resolution;
data = (eeData[219]<<8) + eeData[218];
vth25 = data;
kt1 = (eeData[221]<<8) + eeData[220];
if (kt1 > 32767)
{
kt1 = kt1 - 65536;
}
kt1 = kt1 / (1<<kt1Scale);
kt2 = (eeData[223]<<8) + eeData[222];
if (kt2 > 32767)
{
kt2 = kt2 - 65536;
}
kt2 = kt2 / (1<<kt2Scale);
mlx90621->vTh25 = vth25;
mlx90621->kT1 = kt1;
mlx90621->kT2 = kt2;
}
//------------------------------------------------------------------------------
static void ExtractTgcParameters(uint8_t *eeData, paramsMLX90621 *mlx90621)
{
float tgc;
tgc = eeData[216]/32.0f;
mlx90621->tgc = tgc;
}
//------------------------------------------------------------------------------
static void ExtractKsTaParameters(uint8_t *eeData, paramsMLX90621 *mlx90621)
{
float KsTa;
KsTa = (eeData[231] << 8) + eeData[230];
if(KsTa > 32767)
{
KsTa = KsTa - 65536;
}
KsTa = KsTa / (1<<20);
mlx90621->KsTa = KsTa;
}
//------------------------------------------------------------------------------
static void ExtractKsToParameters(uint8_t *eeData, paramsMLX90621 *mlx90621)
{
int scale;
scale = eeData[192] & 0x0F;
scale = scale + 8;
mlx90621->ksTo = eeData[196];
if(mlx90621->ksTo > 127)
{
mlx90621->ksTo = mlx90621->ksTo - 256;
}
mlx90621->ksTo = mlx90621->ksTo / (1 << scale);
}
//------------------------------------------------------------------------------
static void ExtractAlphaParameters(uint8_t *eeData, paramsMLX90621 *mlx90621)
{
float alphaScale;
float deltaScale;
uint8_t resScale;
float alphaCom;
float alphaTemp;
float temp;
alphaScale = eeData[226];
deltaScale = eeData[227];
resScale = 3 - MLX90621_GetCurResolution();
alphaCom = (eeData[225]<<8) + eeData[224];
alphaScale = pow(2,alphaScale);
deltaScale = pow(2,deltaScale);
alphaCom = alphaCom / alphaScale;
for(int i = 0; i < 64; i++)
{
temp = eeData[128+i];
temp = temp / deltaScale;
alphaTemp = (alphaCom + temp)/(1<<resScale);
mlx90621->alpha[i] = alphaTemp;
}
alphaTemp = (eeData[215]<<8) + eeData[214];
alphaTemp = alphaTemp / alphaScale;
mlx90621->cpAlpha = alphaTemp / (1<<resScale);
}
//------------------------------------------------------------------------------
static void ExtractOffsetParameters(uint8_t *eeData, paramsMLX90621 *mlx90621)
{
uint8_t aScale;
float bScale;
uint8_t resScale;
int16_t aCom;
float aTemp;
float bTemp;
uint16_t data;
aScale = eeData[217]>>4;
bScale = eeData[217] & 0x0F;
resScale = 3 - MLX90621_GetCurResolution();
bScale = pow(2, (float)(bScale+resScale));
data = (eeData[209]<<8) + eeData[208];
aCom = data;
for(int i=0; i<64; i++)
{
aTemp = eeData[i]<<aScale;
bTemp = eeData[64+i];
if (bTemp > 127)
{
bTemp = bTemp - 256;
}
bTemp = bTemp / bScale;
mlx90621->ai[i] = (aCom + aTemp) / (1<<resScale);
mlx90621->bi[i] = bTemp;
}
aTemp = (eeData[212]<<8) + eeData[211];
if (aTemp > 32767)
{
aTemp = aTemp - 65536;
}
aTemp = aTemp / (1<<resScale);
bTemp = eeData[213];
if (bTemp > 127)
{
bTemp = bTemp - 256;
}
bTemp = bTemp / bScale;
mlx90621->cpA = aTemp;
mlx90621->cpB = bTemp;
}

View File

@ -0,0 +1,78 @@
/**
* @copyright (C) 2017 Melexis N.V.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include <stdio.h>
#include STM32_HAL_H
#include "cambus.h"
#include "MLX90621_I2C_Driver.h"
static I2C_HandleTypeDef *hi2c;
void MLX90621_I2CInit(I2C_HandleTypeDef *i2c)
{
hi2c = i2c;
}
int MLX90621_I2CReadEEPROM(uint8_t slaveAddr, uint8_t startAddress, uint16_t nMemAddressRead, uint8_t *data)
{
if (cambus_write_bytes_seq(hi2c, (slaveAddr << 1), &startAddress, 1, true) != 0) {
return -1;
}
if (cambus_read_bytes_seq(hi2c, (slaveAddr << 1), data, nMemAddressRead, false) != 0) {
return -1;
}
return 0;
}
int MLX90621_I2CRead(uint8_t slaveAddr,uint8_t command,
uint8_t startAddress, uint8_t addressStep, uint8_t nMemAddressRead, uint16_t *data)
{
uint8_t cmd[4] = {
command,
startAddress,
addressStep,
nMemAddressRead
};
if (cambus_write_bytes_seq(hi2c, (slaveAddr << 1), cmd, 4, true) != 0) {
return -1;
}
if (cambus_read_bytes_seq(hi2c, (slaveAddr << 1), (uint8_t *) data, nMemAddressRead * 2, false) != 0) {
return -1;
}
return 0;
}
int MLX90621_I2CWrite(uint8_t slaveAddr, uint8_t command, uint8_t checkValue, uint16_t data)
{
uint8_t cmd[5] = {
command,
(data & 0x00FF) - checkValue,
(data & 0x00FF),
(data >> 8) - checkValue,
(data >> 8)
};
if (cambus_write_bytes_seq(hi2c, (slaveAddr << 1), cmd, 5, false) != 0) {
return -1;
}
return 0;
}

View File

@ -10,8 +10,9 @@
*/
#include <stdbool.h>
#include <stddef.h>
#include "py/mphal.h"
#include STM32_HAL_H
#include "systick.h"
#include "omv_boardconfig.h"
#include "cambus.h"
#define I2C_TIMEOUT (1000)
@ -215,3 +216,56 @@ int cambus_writew_bytes(I2C_HandleTypeDef *i2c, uint8_t slv_addr, uint16_t reg_a
}
return 0;
}
int cambus_read_bytes_seq(I2C_HandleTypeDef *i2c, uint8_t slv_addr, uint8_t *buf, int len, bool nostop)
{
int ret = 0;
HAL_NVIC_EnableIRQ(I2C2_EV_IRQn);
HAL_NVIC_EnableIRQ(I2C2_ER_IRQn);
if (HAL_I2C_Master_Seq_Receive_IT(i2c, slv_addr, buf, len,
(nostop == true) ? I2C_FIRST_FRAME : I2C_FIRST_AND_LAST_FRAME) != HAL_OK) {
ret = -1;
goto i2c_error;
}
mp_uint_t tick_start = mp_hal_ticks_ms();
while (HAL_I2C_GetState(i2c) != HAL_I2C_STATE_READY) {
if ((mp_hal_ticks_ms() - tick_start) >= I2C_TIMEOUT) {
ret = -1;
}
__WFI();
}
i2c_error:
HAL_NVIC_DisableIRQ(I2C2_EV_IRQn);
HAL_NVIC_DisableIRQ(I2C2_ER_IRQn);
return ret;
}
int cambus_write_bytes_seq(I2C_HandleTypeDef *i2c, uint8_t slv_addr, uint8_t *buf, int len, bool nostop)
{
int ret = 0;
HAL_NVIC_EnableIRQ(I2C2_EV_IRQn);
HAL_NVIC_EnableIRQ(I2C2_ER_IRQn);
if (HAL_I2C_Master_Seq_Transmit_IT(i2c, slv_addr, buf, len,
(nostop == true) ? I2C_FIRST_FRAME : I2C_FIRST_AND_LAST_FRAME) != HAL_OK) {
ret = -1;
goto i2c_error;
}
mp_uint_t tick_start = mp_hal_ticks_ms();
while (HAL_I2C_GetState(i2c) != HAL_I2C_STATE_READY) {
if ((mp_hal_ticks_ms() - tick_start) >= I2C_TIMEOUT) {
ret = -1;
goto i2c_error;
}
__WFI();
}
i2c_error:
HAL_NVIC_DisableIRQ(I2C2_EV_IRQn);
HAL_NVIC_DisableIRQ(I2C2_ER_IRQn);
return ret;
}

View File

@ -11,6 +11,7 @@
#ifndef __CAMBUS_H__
#define __CAMBUS_H__
#include <stdint.h>
#include <stdbool.h>
#include STM32_HAL_H
#if defined(STM32F4)
#define I2C_TIMING_STANDARD (100000U)
@ -46,4 +47,6 @@ int cambus_read_bytes(I2C_HandleTypeDef *i2c, uint8_t slv_addr, uint8_t reg_addr
int cambus_write_bytes(I2C_HandleTypeDef *i2c, uint8_t slv_addr, uint8_t reg_addr, uint8_t *buf, int len);
int cambus_readw_bytes(I2C_HandleTypeDef *i2c, uint8_t slv_addr, uint16_t reg_addr, uint8_t *buf, int len);
int cambus_writew_bytes(I2C_HandleTypeDef *i2c, uint8_t slv_addr, uint16_t reg_addr, uint8_t *buf, int len);
int cambus_read_bytes_seq(I2C_HandleTypeDef *i2c, uint8_t slv_addr, uint8_t *buf, int len, bool nostop);
int cambus_write_bytes_seq(I2C_HandleTypeDef *i2c, uint8_t slv_addr, uint8_t *buf, int len, bool nostop);
#endif // __CAMBUS_H__

View File

@ -15,10 +15,13 @@
#include "py/mphal.h"
#include "systick.h"
#include "soft_i2c.h"
#include "cambus.h"
#include "MLX90640_I2C_Driver.h"
#include "MLX90640_API.h"
#include "MLX90640_I2C_Driver.h"
#include "MLX90621_API.h"
#include "MLX90621_I2C_Driver.h"
#include "omv_boardconfig.h"
#include "framebuffer.h"
#include "sensor.h"
@ -27,80 +30,27 @@
#include "py_image.h"
#include "py_fir.h"
#define FIR_EEPROM_ADDR 0xA0
#define FIR_MODULE_ADDR 0xC0
#define FIR_READ_CMD 0x02
#define FIR_WR_CFG_REG 0x03
#define FIR_WR_TRIM_CMD 0x04
#define CAL_OSC_TRIM 0xF7
#define CAL_VTH_L 0xDA
#define CAL_VTH_H 0xDB
#define CAL_KT1_L 0xDC
#define CAL_KT1_H 0xDD
#define CAL_K_T1_SCALE 0xD2
#define CAL_KT2_L 0xDE
#define CAL_KT2_H 0xDF
#define CAL_K_T2_SCALE 0xD2
#define CAL_ACOMMON_L 0xD0
#define CAL_ACOMMON_H 0xD1
#define CAL_AI_SCALE 0xD9
#define CAL_AI_OFFSET 0x00
#define CAL_BI_SCALE 0xD9
#define CAL_BI_OFFSET 0x40
#define CAL_TGC 0xD8
#define CAL_EMISS_L 0xE4
#define CAL_EMISS_H 0xE5
#define CAL_KSTA_L 0xE6
#define CAL_KSTA_H 0xE7
#define CAL_A0_L 0xE0
#define CAL_A0_H 0xE1
#define CAL_A0_SCALE 0xE2
#define CAL_D_A_SCALE 0xE3
#define CAL_A_CP_OFFSET 0x80
#define CAL_ALPHA_CP_L 0xD6
#define CAL_ALPHA_CP_H 0xD7
#define CAL_KS_SCALE 0xC0
#define CAL_KS4_EE 0xC4
#define CAL_ACP_L 0xD3
#define CAL_ACP_H 0xD4
#define CAL_BCP 0xD5
#define MLX90640_ADDR 0x33
#define AMG8833_ADDR 0xD2
// MLX variables
static float *a_ij = NULL;
static float *b_ij = NULL;
static float *alpha_ij = NULL;
static float v_th, k_t1, k_t2, tgc, emissivity, ksta, alpha_cp, ks4, a_cp, b_cp;
static uint8_t width = 0;
static uint8_t height = 0;
static uint8_t IR_refresh_rate = 0;
static uint8_t ADC_resolution = 0;
static void *mlx_data= NULL;
static I2C_HandleTypeDef fir_i2c = {0}; // FIR/I2C bus.
// TODO temporary hack.
#ifdef PORTENTA
extern I2C_HandleTypeDef I2CHandle3; // FIR/I2C bus.
#define fir_i2c (I2CHandle3)
#else
extern I2C_HandleTypeDef I2CHandle2; // FIR/I2C bus.
#define fir_i2c (I2CHandle2)
#endif
static enum {
FIR_NONE,
FIR_SHIELD,
MLX90621,
FIR_MLX90640,
FIR_AMG8833
} fir_sensor = FIR_NONE;
@ -136,95 +86,6 @@ static void generate_scl_train()
debug_printf("reset stuck i2c device\n");
}
static float calculate_Ta() // ambient temp
{
// Code to handle dealing with brown-out conditions.
{
uint16_t config_reg;
test_ack(soft_i2c_write_bytes(FIR_MODULE_ADDR,
(uint8_t [4]) {FIR_READ_CMD, 0x92, 0x00, 0x01}, 4, false));
test_ack(soft_i2c_read_bytes(FIR_MODULE_ADDR,
(uint8_t*) &config_reg, 2, true));
if (!(config_reg & 0x0400)) { // brown out
uint8_t eeprom;
// Read the eeprom.
test_ack(soft_i2c_write_bytes(FIR_EEPROM_ADDR,
(uint8_t [1]){CAL_OSC_TRIM}, 1, false));
test_ack(soft_i2c_read_bytes(FIR_EEPROM_ADDR,
&eeprom, 1, true));
// Write oscillator trimming value.
soft_i2c_write_bytes(FIR_MODULE_ADDR,
(uint8_t [5]){FIR_WR_TRIM_CMD,
(uint8_t)(eeprom-0xAA), eeprom,
(uint8_t)(0x00-0xAA), 0x00}, 5, true); // no ack here
// Write device configuration value.
uint8_t lsb = (ADC_resolution << 4) | IR_refresh_rate;
// Normal Operation Mode - Continuous Measurment Mode
uint8_t msb = 0x44;
// ADC low reference enabled - EEPROM enabled
// I2C FM+ enabled
test_ack(soft_i2c_write_bytes(FIR_MODULE_ADDR,
(uint8_t [5]){FIR_WR_CFG_REG,
(uint8_t)(lsb-0x55), lsb,
(uint8_t)(msb-0x55), msb}, 5, true));
}
}
uint16_t ptat;
test_ack(soft_i2c_write_bytes(FIR_MODULE_ADDR,
(uint8_t [4]) {FIR_READ_CMD, 0x40, 0x00, 0x01}, 4, false));
test_ack(soft_i2c_read_bytes(FIR_MODULE_ADDR,
(uint8_t*) &ptat, 2, true));
return (((-k_t1)+sqrtf((k_t1*k_t1)-(4*k_t2*(v_th-ptat))))/(2*k_t2))+25;
}
static void calculate_To(float Ta, float *To)
{
fb_alloc_mark();
int16_t *v_ir = fb_alloc(64 * sizeof(int16_t), FB_ALLOC_NO_HINT);
// Read IR sensor result
test_ack(soft_i2c_write_bytes(FIR_MODULE_ADDR,
(uint8_t [4]){FIR_READ_CMD, 0x00, 0x01, 0x40}, 4, false));
test_ack(soft_i2c_read_bytes(FIR_MODULE_ADDR,
(uint8_t*) v_ir, 128, true));
int16_t v_cp;
// Read compensation pixel result
test_ack(soft_i2c_write_bytes(FIR_MODULE_ADDR,
(uint8_t [4]){FIR_READ_CMD, 0x41, 0x00, 0x01}, 4, false));
test_ack(soft_i2c_read_bytes(FIR_MODULE_ADDR,
(uint8_t*) &v_cp, 2, true));
// Calculate Thermal Gradien Compensation (TGC)
float v_ir_cp_off_comp = v_cp-(a_cp+(b_cp*(Ta-25)));
// (Ta+273.15f)^4
float Tak4 = (Ta+273.15f)*(Ta+273.15f)*(Ta+273.15f)*(Ta+273.15f);
for (int i=0; i<64; i++) {
// #1: Calculate Offset Compensation
float v_ir_off_comp = v_ir[i]-(a_ij[i]+(b_ij[i]*(Ta-25)));
// #2: Calculate Thermal Gradien Compensation (TGC)
float v_ir_tgc_comp = v_ir_off_comp-(tgc*v_ir_cp_off_comp);
// #3: Calculate Emissivity Compensation
float v_ir_comp = v_ir_tgc_comp/emissivity;
// #4: Calculate Sensitivity Compensation
float alpha_comp_ij = (1+(ksta*(Ta-25)))*(alpha_ij[i]-(tgc*alpha_cp));
// Ks4=0 for BAB and BAD sensors.
// float sx = ks4*sqrtf(sqrtf((powf(alpha_comp_ij,3)*v_ir_comp)+(powf(alpha_comp_ij,4)*Ta4)));
// To[i] = sqrtf(sqrtf((v_ir_comp/((alpha_comp_ij*(1-(ks4*273.15f)))+sx))+Ta4))-273.15f;
To[i] = sqrtf(sqrtf((v_ir_comp/alpha_comp_ij)+Tak4))-273.15f;
}
fb_alloc_free_till_mark();
}
// img->w == data_w && img->h == data_h && img->bpp == IMAGE_BPP_GRAYSCALE
static void fir_fill_image_float_obj(image_t *img, mp_obj_t *data, float min, float max)
{
@ -255,28 +116,13 @@ static mp_obj_t py_fir_deinit()
height = 0;
ADC_resolution = 0;
IR_refresh_rate = 0;
if (a_ij) {
a_ij = NULL;
if (mlx_data != NULL) {
mlx_data = NULL;
}
if (b_ij) {
b_ij = NULL;
if (fir_sensor != FIR_NONE) {
fir_sensor = FIR_NONE;
cambus_deinit(&fir_i2c);
}
if (alpha_ij) {
alpha_ij = NULL;
}
switch (fir_sensor) {
case FIR_NONE:
break;
case FIR_SHIELD:
soft_i2c_deinit();
break;
case FIR_MLX90640:
case FIR_AMG8833:
cambus_deinit(&fir_i2c);
break;
}
fir_sensor = FIR_NONE;
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_fir_deinit_obj, py_fir_deinit);
@ -297,16 +143,19 @@ mp_obj_t py_fir_init(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
py_fir_deinit();
bool first_init = true;
switch (py_helper_keyword_int(n_args, args, 0, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_type), FIR_SHIELD)) {
switch (py_helper_keyword_int(n_args, args, 0, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_type), MLX90621)) {
case FIR_NONE: {
return mp_const_none;
}
case FIR_SHIELD: {
case MLX90621: {
FIR_MLX90621:
width = 16;
height = 4;
fir_sensor = FIR_SHIELD;
soft_i2c_init();
fir_sensor = MLX90621;
MLX90621_I2CInit(&fir_i2c);
// The EEPROM must be read at <= 400KHz.
cambus_init(&fir_i2c, FIR_I2C, I2C_TIMING_FULL);
// parse refresh rate and ADC resolution
IR_refresh_rate = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_refresh), 64); // 64Hz
@ -316,85 +165,31 @@ mp_obj_t py_fir_init(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
ADC_resolution = ((ADC_resolution > 18) ? 18 : (ADC_resolution < 15) ? 15 : ADC_resolution) - 15;
IR_refresh_rate = 14 - __CLZ(__RBIT((IR_refresh_rate > 512) ? 512 : (IR_refresh_rate < 1) ? 1 : IR_refresh_rate));
a_ij = xalloc(64 * sizeof(*a_ij));
b_ij = xalloc(64 * sizeof(*b_ij));
alpha_ij = xalloc(64 * sizeof(*alpha_ij));
mlx_data = xalloc(sizeof(paramsMLX90621));
fb_alloc_mark();
uint8_t *eeprom = fb_alloc(256 * sizeof(uint8_t), FB_ALLOC_NO_HINT);
// Read the whole eeprom.
test_ack(soft_i2c_write_bytes(FIR_EEPROM_ADDR, (uint8_t [1]){0x00}, 1, false));
test_ack(soft_i2c_read_bytes(FIR_EEPROM_ADDR, eeprom, 256, true));
uint8_t *eeprom = fb_alloc0(256 * sizeof(uint8_t), FB_ALLOC_NO_HINT);
int error = 0;
error |= MLX90621_DumpEE(eeprom);
error |= MLX90621_Configure(eeprom);
error |= MLX90621_SetResolution(ADC_resolution);
error |= MLX90621_SetRefreshRate(IR_refresh_rate);
error |= MLX90621_ExtractParameters(eeprom, mlx_data);
fb_alloc_free_till_mark();
// Write oscillator trimming value.
soft_i2c_write_bytes(FIR_MODULE_ADDR,
(uint8_t [5]){FIR_WR_TRIM_CMD,
(uint8_t)(eeprom[CAL_OSC_TRIM]-0xAA), eeprom[CAL_OSC_TRIM],
(uint8_t)(0x00-0xAA), 0x00}, 5, true); // no ack here
// Write device configuration value.
// assignment of IR_refresh_rate and ADC_resolution now done above
uint8_t lsb = (ADC_resolution << 4) | IR_refresh_rate;
// Normal Operation Mode - Continuous Measurment Mode
uint8_t msb = 0x44;
// ADC low reference enabled - EEPROM enabled
// I2C FM+ enabled
test_ack(soft_i2c_write_bytes(FIR_MODULE_ADDR,
(uint8_t [5]){FIR_WR_CFG_REG,
(uint8_t)(lsb-0x55), lsb,
(uint8_t)(msb-0x55), msb}, 5, true));
v_th = ((int16_t)((eeprom[CAL_VTH_H]<<8)|eeprom[CAL_VTH_L])) /
powf(2,3-ADC_resolution);
uint8_t k_t1_scale = (uint8_t)((eeprom[CAL_K_T1_SCALE]&0xF0)>>4);
k_t1 = ((int16_t)((eeprom[CAL_KT1_H]<<8)|eeprom[CAL_KT1_L])) /
powf(2,k_t1_scale+(3-ADC_resolution));
uint8_t k_t2_scale = (uint8_t)(eeprom[CAL_K_T2_SCALE]&0x0F);
k_t2 = ((int16_t)((eeprom[CAL_KT2_H]<<8)|eeprom[CAL_KT2_L])) /
powf(2,k_t2_scale+10+(3-ADC_resolution));
int16_t a_common = (int16_t)((eeprom[CAL_ACOMMON_H]<<8)|eeprom[CAL_ACOMMON_L]);
uint8_t a_i_scale = (uint8_t)((eeprom[CAL_AI_SCALE]&0xF0)>>4);
uint8_t b_i_scale = (uint8_t)(eeprom[CAL_BI_SCALE]&0x0F);
uint16_t alpha_0 = (uint16_t)((eeprom[CAL_A0_H]<<8)|eeprom[CAL_A0_L]);
uint8_t alpha_0_scale = (uint8_t)eeprom[CAL_A0_SCALE];
uint8_t delta_a_scale = (uint8_t)eeprom[CAL_D_A_SCALE];
for (int i=0; i<64; i++) {
// Pixel offset
a_ij[i] = (a_common+(((uint8_t)eeprom[CAL_AI_OFFSET+i])*powf(2,a_i_scale))) /
powf(2,3-ADC_resolution);
// Slope coefficient
b_ij[i] = ((int8_t)eeprom[CAL_BI_OFFSET+i]) /
powf(2,b_i_scale+(3-ADC_resolution));
// Sensitivity coefficient
float t0 = alpha_0/powf(2,alpha_0_scale);
float t1 = ((uint8_t)eeprom[CAL_A_CP_OFFSET+i])/powf(2,delta_a_scale);
alpha_ij[i] = (t0+t1) /
powf(2,3-ADC_resolution);
if (error != 0 && first_init == true) {
first_init = false;
generate_scl_train();
xfree(mlx_data);
mlx_data = NULL;
goto FIR_MLX90621;
}
tgc = ((int8_t)eeprom[CAL_TGC]) /
32.0f;
emissivity = ((uint16_t)((eeprom[CAL_EMISS_H]<<8)|eeprom[CAL_EMISS_L])) /
32768.0f;
ksta = ((int16_t)((eeprom[CAL_KSTA_H]<<8)|eeprom[CAL_KSTA_L])) /
1048576.0f;
alpha_cp = ((uint16_t)((eeprom[CAL_ALPHA_CP_H]<<8)|eeprom[CAL_ALPHA_CP_L])) /
powf(2,alpha_0_scale+(3-ADC_resolution));
// Switch to FAST speed
cambus_deinit(&fir_i2c);
cambus_init(&fir_i2c, FIR_I2C, I2C_TIMING_FAST);
uint8_t ks_scale = (uint8_t)(eeprom[CAL_KS_SCALE]&0x0F);
ks4 = ((int8_t)eeprom[CAL_KS4_EE]) /
powf(2,ks_scale+8);
a_cp = ((int16_t)((eeprom[CAL_ACP_H]<<8)|eeprom[CAL_ACP_L])) /
powf(2,3-ADC_resolution);
b_cp = ((int8_t)eeprom[CAL_BCP]) /
powf(2,b_i_scale+(3-ADC_resolution));
fb_alloc_free_till_mark();
PY_ASSERT_TRUE_MSG(error == 0, "Failed to init the MLX90621!");
return mp_const_none;
}
@ -415,7 +210,7 @@ mp_obj_t py_fir_init(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
ADC_resolution = ((ADC_resolution > 19) ? 19 : (ADC_resolution < 16) ? 16 : ADC_resolution) - 16;
IR_refresh_rate = __CLZ(__RBIT((IR_refresh_rate > 64) ? 64 : (IR_refresh_rate < 1) ? 1 : IR_refresh_rate)) + 1;
alpha_ij = xalloc(sizeof(paramsMLX90640));
mlx_data = xalloc(sizeof(paramsMLX90640));
int error = 0;
error |= MLX90640_SetResolution(MLX90640_ADDR, ADC_resolution);
@ -424,14 +219,14 @@ mp_obj_t py_fir_init(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
fb_alloc_mark();
uint16_t *eeprom = fb_alloc(832 * sizeof(uint16_t), FB_ALLOC_NO_HINT);
error |= MLX90640_DumpEE(MLX90640_ADDR, eeprom);
error |= MLX90640_ExtractParameters(eeprom, (paramsMLX90640 *) alpha_ij);
error |= MLX90640_ExtractParameters(eeprom, mlx_data);
fb_alloc_free_till_mark();
if (error != 0 && first_init == true) {
first_init = false;
generate_scl_train();
xfree(alpha_ij);
alpha_ij = NULL;
xfree(mlx_data);
mlx_data = NULL;
goto FIR_MLX90640;
}
@ -494,7 +289,7 @@ static mp_obj_t py_fir_refresh()
const int mlx_90621_refresh_rates[16] = {512, 512, 512, 512, 512, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1, 0};
const int mlx_90640_refresh_rates[8] = {0, 1, 2, 4, 8, 16, 32, 64};
if (fir_sensor == FIR_NONE) return mp_const_none;
if (fir_sensor == FIR_SHIELD) return mp_obj_new_int(mlx_90621_refresh_rates[IR_refresh_rate]);
if (fir_sensor == MLX90621) return mp_obj_new_int(mlx_90621_refresh_rates[IR_refresh_rate]);
if (fir_sensor == FIR_MLX90640) return mp_obj_new_int(mlx_90640_refresh_rates[IR_refresh_rate]);
if (fir_sensor == FIR_AMG8833) return mp_obj_new_int(IR_refresh_rate);
return mp_const_none;
@ -504,7 +299,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_fir_refresh_obj, py_fir_refresh);
static mp_obj_t py_fir_resolution()
{
if (fir_sensor == FIR_NONE) return mp_const_none;
if (fir_sensor == FIR_SHIELD) return mp_obj_new_int(ADC_resolution + 15);
if (fir_sensor == MLX90621) return mp_obj_new_int(ADC_resolution + 15);
if (fir_sensor == FIR_MLX90640) return mp_obj_new_int(ADC_resolution + 16);
if (fir_sensor == FIR_AMG8833) return mp_obj_new_int(ADC_resolution);
return mp_const_none;
@ -514,20 +309,30 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_fir_resolution_obj, py_fir_resolution);
mp_obj_t py_fir_read_ta()
{
switch(fir_sensor) {
case FIR_NONE: return mp_const_none;
case FIR_SHIELD: return mp_obj_new_float(calculate_Ta());
case FIR_NONE:
return mp_const_none;
case MLX90621: {
fb_alloc_mark();
uint16_t *data = fb_alloc0(66 * sizeof(uint16_t), FB_ALLOC_NO_HINT);
PY_ASSERT_TRUE_MSG(MLX90621_GetFrameData(data) >= 0,
"Failed to read the MLX90640 sensor data!");
mp_obj_t result = mp_obj_new_float(MLX90621_GetTa(data, mlx_data));
fb_alloc_free_till_mark();
return result;
}
case FIR_MLX90640: {
fb_alloc_mark();
uint16_t *data = fb_alloc(834 * sizeof(uint16_t), FB_ALLOC_NO_HINT);
PY_ASSERT_TRUE_MSG(MLX90640_GetFrameData(MLX90640_ADDR, data) >= 0,
"Failed to read the MLX90640 sensor data!");
mp_obj_t result = mp_obj_new_float(MLX90640_GetTa(data, (paramsMLX90640 *) alpha_ij));
mp_obj_t result = mp_obj_new_float(MLX90640_GetTa(data, mlx_data));
fb_alloc_free_till_mark();
return result;
}
case FIR_AMG8833: {
int16_t temp;
int16_t temp=0;
test_ack(cambus_read_bytes(&fir_i2c, AMG8833_ADDR, 0x0E, (uint8_t *) &temp, 2));
if ((temp >> 11) & 1) temp |= 1 << 15;
temp &= 0x87FF;
@ -545,22 +350,19 @@ mp_obj_t py_fir_read_ir()
return mp_const_none;
}
case FIR_SHIELD: {
case MLX90621: {
fb_alloc_mark();
float *To = fb_alloc(64 * sizeof(float), FB_ALLOC_NO_HINT), *To_rot = fb_alloc(64 * sizeof(float), FB_ALLOC_NO_HINT);
float Ta = calculate_Ta();
uint16_t *data = fb_alloc0(66 * sizeof(uint16_t), FB_ALLOC_NO_HINT);
PY_ASSERT_TRUE_MSG(MLX90621_GetFrameData(data) >= 0,
"Failed to read the MLX90621 sensor data!");
float Ta = MLX90621_GetTa(data, mlx_data);
float *To = fb_alloc0(64 * sizeof(float), FB_ALLOC_NO_HINT);
MLX90621_CalculateTo(data, mlx_data, 0.95, Ta - 8, To);
float min = FLT_MAX, max = FLT_MIN;
// Calculate object temperatures
calculate_To(Ta, To_rot);
// Rotate temperatures array (sensor memory is read column wise).
for (int x=15, r=0; x>=0; x--) {
for (int y=0; y<4; y++) {
float temp = To[y*16 + x] = To_rot[r++];
min = IM_MIN(min, temp);
max = IM_MAX(max, temp);
}
for (int i=0; i<64; i++) {
min = IM_MIN(min, To[i]);
max = IM_MAX(max, To[i]);
}
mp_obj_t tuple[4];
@ -569,8 +371,10 @@ mp_obj_t py_fir_read_ir()
tuple[2] = mp_obj_new_float(min);
tuple[3] = mp_obj_new_float(max);
for (int i=0; i<64; i++) {
mp_obj_list_append(tuple[1], mp_obj_new_float(To[i]));
for (int i=0; i<4; i++) {
for (int j=0; j<16; j++) {
mp_obj_list_append(tuple[1], mp_obj_new_float(To[((15-j)*4)+i]));
}
}
fb_alloc_free_till_mark();
@ -583,14 +387,14 @@ mp_obj_t py_fir_read_ir()
// Calculate 1st sub-frame...
PY_ASSERT_TRUE_MSG(MLX90640_GetFrameData(MLX90640_ADDR, data) >= 0,
"Failed to read the MLX90640 sensor data!");
float Ta = MLX90640_GetTa(data, (paramsMLX90640 *) alpha_ij);
float Ta = MLX90640_GetTa(data, mlx_data);
float *To = fb_alloc0(768 * sizeof(float), FB_ALLOC_NO_HINT);
MLX90640_CalculateTo(data, (paramsMLX90640 *) alpha_ij, 0.95, Ta - 8, To);
MLX90640_CalculateTo(data, mlx_data, 0.95, Ta - 8, To);
// Calculate 2nd sub-frame...
PY_ASSERT_TRUE_MSG(MLX90640_GetFrameData(MLX90640_ADDR, data) >= 0,
"Failed to read the MLX90640 sensor data!");
Ta = MLX90640_GetTa(data, (paramsMLX90640 *) alpha_ij);
MLX90640_CalculateTo(data, (paramsMLX90640 *) alpha_ij, 0.95, Ta - 8, To);
Ta = MLX90640_GetTa(data, mlx_data);
MLX90640_CalculateTo(data, mlx_data, 0.95, Ta - 8, To);
float min = FLT_MAX, max = FLT_MIN;
for (int i=0; i<768; i++) {
@ -881,9 +685,9 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_fir_snapshot_obj, 0, py_fir_snapshot);
STATIC const mp_rom_map_elem_t globals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_fir) },
{ MP_ROM_QSTR(MP_QSTR_FIR_NONE), MP_ROM_INT(FIR_NONE) },
{ MP_ROM_QSTR(MP_QSTR_FIR_SHIELD), MP_ROM_INT(FIR_SHIELD) },
{ MP_ROM_QSTR(MP_QSTR_FIR_MLX90620), MP_ROM_INT(FIR_SHIELD) }, // == FIR_SHIELD
{ MP_ROM_QSTR(MP_QSTR_FIR_MLX90621), MP_ROM_INT(FIR_SHIELD) }, // == FIR_SHIELD
{ MP_ROM_QSTR(MP_QSTR_FIR_SHIELD), MP_ROM_INT(MLX90621) },
{ MP_ROM_QSTR(MP_QSTR_FIR_MLX90620), MP_ROM_INT(MLX90621) },
{ MP_ROM_QSTR(MP_QSTR_FIR_MLX90621), MP_ROM_INT(MLX90621) },
{ MP_ROM_QSTR(MP_QSTR_FIR_MLX90640), MP_ROM_INT(FIR_MLX90640) },
{ MP_ROM_QSTR(MP_QSTR_FIR_AMG8833), MP_ROM_INT(FIR_AMG8833) },
{ MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&py_fir_init_obj) },

View File

@ -39,10 +39,11 @@ OMV_CFLAGS += -I$(TOP_DIR)/$(OMV_DIR)/ports/$(PORT)/
OMV_CFLAGS += -I$(TOP_DIR)/$(OMV_DIR)/ports/$(PORT)/modules/
OMV_CFLAGS += -I$(TOP_DIR)/$(LEPTON_DIR)/include/
OMV_CFLAGS += -I$(TOP_DIR)/$(MLX90640_DIR)/include/
OMV_CFLAGS += -I$(TOP_DIR)/$(LSM6DS3_DIR)/include/
OMV_CFLAGS += -I$(TOP_DIR)/$(TENSORFLOW_DIR)/$(CPU)/
OMV_CFLAGS += -I$(TOP_DIR)/$(WINC1500_DIR)/include/
OMV_CFLAGS += -I$(TOP_DIR)/$(MLX90621_DIR)/include/
OMV_CFLAGS += -I$(TOP_DIR)/$(MLX90640_DIR)/include/
OMV_CFLAGS += -I$(TOP_DIR)/$(TENSORFLOW_DIR)/$(CPU)/
OMV_CFLAGS += -I$(TOP_DIR)/$(LIBPDM_DIR)/
ifeq ($(OMV_ENABLE_BL), 1)
@ -92,13 +93,14 @@ endif
FIRM_OBJ += $(wildcard $(BUILD)/$(HAL_DIR)/src/*.o)
FIRM_OBJ += $(wildcard $(BUILD)/$(LEPTON_DIR)/src/*.o)
FIRM_OBJ += $(wildcard $(BUILD)/$(MLX90640_DIR)/src/*.o)
ifeq ($(MICROPY_PY_IMU), 1)
FIRM_OBJ += $(wildcard $(BUILD)/$(LSM6DS3_DIR)/src/*.o)
endif
ifeq ($(MICROPY_PY_WINC1500), 1)
FIRM_OBJ += $(wildcard $(BUILD)/$(WINC1500_DIR)/src/*.o)
endif
FIRM_OBJ += $(wildcard $(BUILD)/$(MLX90621_DIR)/src/*.o)
FIRM_OBJ += $(wildcard $(BUILD)/$(MLX90640_DIR)/src/*.o)
#------------- OpenMV Objects ----------------#
FIRM_OBJ += $(addprefix $(BUILD)/$(CMSIS_DIR)/src/, \
@ -481,10 +483,11 @@ UVC_OBJ += $(addprefix $(BUILD)/$(OMV_DIR)/ports/stm32/,\
)
UVC_OBJ += $(wildcard $(BUILD)/$(LEPTON_DIR)/src/*.o)
UVC_OBJ += $(wildcard $(BUILD)/$(MLX90640_DIR)/src/*.o)
ifeq ($(MICROPY_PY_IMU), 1)
UVC_OBJ += $(wildcard $(BUILD)/$(LSM6DS3_DIR)/src/*.o)
endif
UVC_OBJ += $(wildcard $(BUILD)/$(MLX90621_DIR)/src/*.o)
UVC_OBJ += $(wildcard $(BUILD)/$(MLX90640_DIR)/src/*.o)
endif
###################################################
@ -522,13 +525,14 @@ FIRMWARE_OBJS: | $(BUILD) $(FW_DIR)
$(MAKE) -C $(MICROPY_DIR)/ports/$(PORT) BUILD=$(BUILD)/$(MICROPY_DIR) $(MICROPY_ARGS)
$(MAKE) -C $(HAL_DIR) BUILD=$(BUILD)/$(HAL_DIR) CFLAGS="$(CFLAGS) -MMD"
$(MAKE) -C $(LEPTON_DIR) BUILD=$(BUILD)/$(LEPTON_DIR) CFLAGS="$(CFLAGS) -MMD"
$(MAKE) -C $(MLX90640_DIR) BUILD=$(BUILD)/$(MLX90640_DIR) CFLAGS="$(CFLAGS) -MMD"
ifeq ($(MICROPY_PY_IMU), 1)
$(MAKE) -C $(LSM6DS3_DIR) BUILD=$(BUILD)/$(LSM6DS3_DIR) CFLAGS="$(CFLAGS) -MMD"
endif
ifeq ($(MICROPY_PY_WINC1500), 1)
$(MAKE) -C $(WINC1500_DIR) BUILD=$(BUILD)/$(WINC1500_DIR) CFLAGS="$(CFLAGS) -MMD"
endif
$(MAKE) -C $(MLX90621_DIR) BUILD=$(BUILD)/$(MLX90621_DIR) CFLAGS="$(CFLAGS) -MMD"
$(MAKE) -C $(MLX90640_DIR) BUILD=$(BUILD)/$(MLX90640_DIR) CFLAGS="$(CFLAGS) -MMD"
$(MAKE) -C $(OMV_DIR) BUILD=$(BUILD)/$(OMV_DIR) CFLAGS="$(CFLAGS) -MMD"
ifeq ($(CUBEAI), 1)
$(MAKE) -C $(CUBEAI_DIR) BUILD=$(BUILD)/$(CUBEAI_DIR) CFLAGS="$(CFLAGS) -fno-strict-aliasing -MMD"