Add MLX support.

This commit is contained in:
Kwabena W. Agyeman 2018-09-24 13:58:47 -07:00 committed by Ibrahim Abd Elkader
parent 25ce746b54
commit e97e0a2021
34 changed files with 2764 additions and 302 deletions

View File

@ -0,0 +1,20 @@
# AMG8833 Camera Demo
#
# This example shows off how to overlay a heatmap onto your OpenMV Cam's
# live video output from the main camera.
import image, time, fir
# Initialize the thermal sensor
fir.init(type=fir.FIR_AMG8833)
# FPS clock
clock = time.clock()
while (True):
clock.tick()
img = fir.snapshot(copy_to_fb=True)
# Print FPS.
print(clock.fps())

View File

@ -0,0 +1,25 @@
# AMG8833 Camera Demo
#
# This example shows off how to overlay a heatmap onto your OpenMV Cam's
# live video output from the main camera.
import image, time, fir, lcd
# Initialize the thermal sensor
fir.init(type=fir.FIR_AMG8833)
# Init the lcd.
lcd.init()
# FPS clock
clock = time.clock()
while (True):
clock.tick()
img = fir.snapshot(copy_to_fb=True)
lcd.display(img)
# Print FPS.
print(clock.fps())

View File

@ -0,0 +1,55 @@
# AMG8833 Overlay Demo
#
# This example shows off how to overlay a heatmap onto your OpenMV Cam's
# live video output from the main camera.
import sensor, image, time, fir
ALT_OVERLAY = False # Set to True to allocate a second ir image.
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QQVGA)
sensor.skip_frames(time = 2000)
# Initialize the thermal sensor
fir.init(type=fir.FIR_AMG8833)
# Allocate another frame buffer for smoother video.
extra_fb = sensor.alloc_extra_fb(sensor.width(), sensor.height(), sensor.RGB565)
# FPS clock
clock = time.clock()
while (True):
clock.tick()
# Capture an image
img = sensor.snapshot()
# Capture FIR data
# ta: Ambient temperature
# ir: Object temperatures (IR array)
# to_min: Minimum object temperature
# to_max: Maximum object temperature
ta, ir, to_min, to_max = fir.read_ir()
if not ALT_OVERLAY:
# Scale the image and belnd it with the framebuffer
fir.draw_ir(img, ir)
else:
# Create a secondary image and then blend into the frame buffer.
extra_fb.clear()
fir.draw_ir(extra_fb, ir, alpha=256)
img.blend(extra_fb, alpha=128)
# Draw ambient, min and max temperatures.
img.draw_string(8, 0, "Ta: %0.2f C" % ta, color = (255, 0, 0), mono_space = False)
img.draw_string(8, 8, "To min: %0.2f C" % to_min, color = (255, 0, 0), mono_space = False)
img.draw_string(8, 16, "To max: %0.2f C"% to_max, color = (255, 0, 0), mono_space = False)
# Force high quality streaming...
img.compress(quality=90)
# Print FPS.
print(clock.fps())

View File

@ -0,0 +1,59 @@
# AMG8833 Overlay Demo
#
# This example shows off how to overlay a heatmap onto your OpenMV Cam's
# live video output from the main camera.
import sensor, image, time, fir, lcd
ALT_OVERLAY = False # Set to True to allocate a second ir image.
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QQVGA2)
sensor.skip_frames(time = 2000)
# Initialize the thermal sensor
fir.init(type=fir.FIR_AMG8833)
# Init the lcd.
lcd.init()
# Allocate another frame buffer for smoother video.
extra_fb = sensor.alloc_extra_fb(sensor.width(), sensor.height(), sensor.RGB565)
# FPS clock
clock = time.clock()
while (True):
clock.tick()
# Capture an image
img = sensor.snapshot()
# Capture FIR data
# ta: Ambient temperature
# ir: Object temperatures (IR array)
# to_min: Minimum object temperature
# to_max: Maximum object temperature
ta, ir, to_min, to_max = fir.read_ir()
if not ALT_OVERLAY:
# Scale the image and belnd it with the framebuffer
fir.draw_ir(img, ir)
else:
# Create a secondary image and then blend into the frame buffer.
extra_fb.clear()
fir.draw_ir(extra_fb, ir, alpha=256)
img.blend(extra_fb, alpha=128)
# Draw ambient, min and max temperatures.
img.draw_string(8, 0, "Ta: %0.2f C" % ta, color = (255, 0, 0), mono_space = False)
img.draw_string(8, 8, "To min: %0.2f C" % to_min, color = (255, 0, 0), mono_space = False)
img.draw_string(8, 16, "To max: %0.2f C"% to_max, color = (255, 0, 0), mono_space = False)
lcd.display(img)
# Force high quality streaming...
img.compress(quality=90)
# Print FPS.
print(clock.fps())

View File

@ -0,0 +1,20 @@
# MLX90621 Camera Demo
#
# This example shows off how to overlay a heatmap onto your OpenMV Cam's
# live video output from the main camera.
import image, time, fir
# Initialize the thermal sensor
fir.init(type=fir.FIR_MLX90621)
# FPS clock
clock = time.clock()
while (True):
clock.tick()
img = fir.snapshot(copy_to_fb=True)
# Print FPS.
print(clock.fps())

View File

@ -0,0 +1,25 @@
# MLX90621 Camera Demo
#
# This example shows off how to overlay a heatmap onto your OpenMV Cam's
# live video output from the main camera.
import image, time, fir, lcd
# Initialize the thermal sensor
fir.init(type=fir.FIR_MLX90621)
# Init the lcd.
lcd.init()
# FPS clock
clock = time.clock()
while (True):
clock.tick()
img = fir.snapshot(copy_to_fb=True)
lcd.display(img)
# Print FPS.
print(clock.fps())

View File

@ -0,0 +1,55 @@
# MLX90621 Overlay Demo
#
# This example shows off how to overlay a heatmap onto your OpenMV Cam's
# live video output from the main camera.
import sensor, image, time, fir
ALT_OVERLAY = False # Set to True to allocate a second ir image.
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QQVGA)
sensor.skip_frames(time = 2000)
# Initialize the thermal sensor
fir.init(type=fir.FIR_MLX90621)
# Allocate another frame buffer for smoother video.
extra_fb = sensor.alloc_extra_fb(sensor.width(), sensor.height(), sensor.RGB565)
# FPS clock
clock = time.clock()
while (True):
clock.tick()
# Capture an image
img = sensor.snapshot()
# Capture FIR data
# ta: Ambient temperature
# ir: Object temperatures (IR array)
# to_min: Minimum object temperature
# to_max: Maximum object temperature
ta, ir, to_min, to_max = fir.read_ir()
if not ALT_OVERLAY:
# Scale the image and belnd it with the framebuffer
fir.draw_ir(img, ir)
else:
# Create a secondary image and then blend into the frame buffer.
extra_fb.clear()
fir.draw_ir(extra_fb, ir, alpha=256)
img.blend(extra_fb, alpha=128)
# Draw ambient, min and max temperatures.
img.draw_string(8, 0, "Ta: %0.2f C" % ta, color = (255, 0, 0), mono_space = False)
img.draw_string(8, 8, "To min: %0.2f C" % to_min, color = (255, 0, 0), mono_space = False)
img.draw_string(8, 16, "To max: %0.2f C"% to_max, color = (255, 0, 0), mono_space = False)
# Force high quality streaming...
img.compress(quality=90)
# Print FPS.
print(clock.fps())

View File

@ -0,0 +1,59 @@
# MLX90621 Overlay Demo
#
# This example shows off how to overlay a heatmap onto your OpenMV Cam's
# live video output from the main camera.
import sensor, image, time, fir, lcd
ALT_OVERLAY = False # Set to True to allocate a second ir image.
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QQVGA2)
sensor.skip_frames(time = 2000)
# Initialize the thermal sensor
fir.init(type=fir.FIR_MLX90621)
# Init the lcd.
lcd.init()
# Allocate another frame buffer for smoother video.
extra_fb = sensor.alloc_extra_fb(sensor.width(), sensor.height(), sensor.RGB565)
# FPS clock
clock = time.clock()
while (True):
clock.tick()
# Capture an image
img = sensor.snapshot()
# Capture FIR data
# ta: Ambient temperature
# ir: Object temperatures (IR array)
# to_min: Minimum object temperature
# to_max: Maximum object temperature
ta, ir, to_min, to_max = fir.read_ir()
if not ALT_OVERLAY:
# Scale the image and belnd it with the framebuffer
fir.draw_ir(img, ir)
else:
# Create a secondary image and then blend into the frame buffer.
extra_fb.clear()
fir.draw_ir(extra_fb, ir, alpha=256)
img.blend(extra_fb, alpha=128)
# Draw ambient, min and max temperatures.
img.draw_string(8, 0, "Ta: %0.2f C" % ta, color = (255, 0, 0), mono_space = False)
img.draw_string(8, 8, "To min: %0.2f C" % to_min, color = (255, 0, 0), mono_space = False)
img.draw_string(8, 16, "To max: %0.2f C"% to_max, color = (255, 0, 0), mono_space = False)
lcd.display(img)
# Force high quality streaming...
img.compress(quality=90)
# Print FPS.
print(clock.fps())

View File

@ -0,0 +1,20 @@
# MLX90640 Camera Demo
#
# This example shows off how to overlay a heatmap onto your OpenMV Cam's
# live video output from the main camera.
import image, time, fir
# Initialize the thermal sensor
fir.init(type=fir.FIR_MLX90640, refresh=16) # Hz (higher end OpenMV Cam's may be able to run faster)
# FPS clock
clock = time.clock()
while (True):
clock.tick()
img = fir.snapshot(copy_to_fb=True)
# Print FPS.
print(clock.fps())

View File

@ -0,0 +1,25 @@
# MLX90640 Camera Demo
#
# This example shows off how to overlay a heatmap onto your OpenMV Cam's
# live video output from the main camera.
import image, time, fir, lcd
# Initialize the thermal sensor
fir.init(type=fir.FIR_MLX90640, refresh=16) # Hz (higher end OpenMV Cam's may be able to run faster)
# Init the lcd.
lcd.init()
# FPS clock
clock = time.clock()
while (True):
clock.tick()
img = fir.snapshot(copy_to_fb=True)
lcd.display(img)
# Print FPS.
print(clock.fps())

View File

@ -0,0 +1,55 @@
# MLX90640 Overlay Demo
#
# This example shows off how to overlay a heatmap onto your OpenMV Cam's
# live video output from the main camera.
import sensor, image, time, fir
ALT_OVERLAY = False # Set to True to allocate a second ir image.
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QQVGA)
sensor.skip_frames(time = 2000)
# Initialize the thermal sensor
fir.init(type=fir.FIR_MLX90640, refresh=16) # Hz (higher end OpenMV Cam's may be able to run faster)
# Allocate another frame buffer for smoother video.
extra_fb = sensor.alloc_extra_fb(sensor.width(), sensor.height(), sensor.RGB565)
# FPS clock
clock = time.clock()
while (True):
clock.tick()
# Capture an image
img = sensor.snapshot()
# Capture FIR data
# ta: Ambient temperature
# ir: Object temperatures (IR array)
# to_min: Minimum object temperature
# to_max: Maximum object temperature
ta, ir, to_min, to_max = fir.read_ir()
if not ALT_OVERLAY:
# Scale the image and belnd it with the framebuffer
fir.draw_ir(img, ir)
else:
# Create a secondary image and then blend into the frame buffer.
extra_fb.clear()
fir.draw_ir(extra_fb, ir, alpha=256)
img.blend(extra_fb, alpha=128)
# Draw ambient, min and max temperatures.
img.draw_string(8, 0, "Ta: %0.2f C" % ta, color = (255, 0, 0), mono_space = False)
img.draw_string(8, 8, "To min: %0.2f C" % to_min, color = (255, 0, 0), mono_space = False)
img.draw_string(8, 16, "To max: %0.2f C"% to_max, color = (255, 0, 0), mono_space = False)
# Force high quality streaming...
img.compress(quality=90)
# Print FPS.
print(clock.fps())

View File

@ -0,0 +1,59 @@
# MLX90640 Overlay Demo
#
# This example shows off how to overlay a heatmap onto your OpenMV Cam's
# live video output from the main camera.
import sensor, image, time, fir, lcd
ALT_OVERLAY = False # Set to True to allocate a second ir image.
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QQVGA2)
sensor.skip_frames(time = 2000)
# Initialize the thermal sensor
fir.init(type=fir.FIR_MLX90640, refresh=16) # Hz (higher end OpenMV Cam's may be able to run faster)
# Init the lcd.
lcd.init()
# Allocate another frame buffer for smoother video.
extra_fb = sensor.alloc_extra_fb(sensor.width(), sensor.height(), sensor.RGB565)
# FPS clock
clock = time.clock()
while (True):
clock.tick()
# Capture an image
img = sensor.snapshot()
# Capture FIR data
# ta: Ambient temperature
# ir: Object temperatures (IR array)
# to_min: Minimum object temperature
# to_max: Maximum object temperature
ta, ir, to_min, to_max = fir.read_ir()
if not ALT_OVERLAY:
# Scale the image and belnd it with the framebuffer
fir.draw_ir(img, ir)
else:
# Create a secondary image and then blend into the frame buffer.
extra_fb.clear()
fir.draw_ir(extra_fb, ir, alpha=256)
img.blend(extra_fb, alpha=128)
# Draw ambient, min and max temperatures.
img.draw_string(8, 0, "Ta: %0.2f C" % ta, color = (255, 0, 0), mono_space = False)
img.draw_string(8, 8, "To min: %0.2f C" % to_min, color = (255, 0, 0), mono_space = False)
img.draw_string(8, 16, "To max: %0.2f C"% to_max, color = (255, 0, 0), mono_space = False)
lcd.display(img)
# Force high quality streaming...
img.compress(quality=90)
# Print FPS.
print(clock.fps())

View File

@ -1,55 +0,0 @@
# Thermopile Shield Demo
#
# Note: To run this example you will need a Thermopile Shield for your OpenMV
# Cam. Also, please disable JPEG mode in the IDE.
#
# The Thermopile Shield allows your OpenMV Cam to see heat!
import sensor, image, time, fir
# Reset sensor
sensor.reset()
# Set sensor settings
sensor.set_contrast(1)
sensor.set_brightness(0)
sensor.set_saturation(2)
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QQVGA)
# The following registers fine-tune the image
# sensor window to align it with the FIR sensor.
if (sensor.get_id() == sensor.OV2640):
sensor.__write_reg(0xFF, 0x01) # switch to reg bank
sensor.__write_reg(0x17, 0x19) # set HSTART
sensor.__write_reg(0x18, 0x43) # set HSTOP
# Initialize the thermal sensor
fir.init()
# FPS clock
clock = time.clock()
while (True):
clock.tick()
# Capture an image
image = sensor.snapshot()
# Capture FIR data
# ta: Ambient temperature
# ir: Object temperatures (IR array)
# to_min: Minimum object temperature
# to_max: Maximum object temperature
ta, ir, to_min, to_max = fir.read_ir()
# Scale the image and belnd it with the framebuffer
fir.draw_ir(image, ir)
# Draw ambient, min and max temperatures.
image.draw_string(0, 0, "Ta: %0.2f"%ta, color = (0xFF, 0x00, 0x00))
image.draw_string(0, 8, "To min: %0.2f"%to_min, color = (0xFF, 0x00, 0x00))
image.draw_string(0, 16, "To max: %0.2f"%to_max, color = (0xFF, 0x00, 0x00))
# Print FPS.
print(clock.fps())

View File

@ -1,61 +0,0 @@
# Thermopile Shield Demo with LCD
#
# Note: To run this example you will need a Thermopile Shield for your OpenMV
# Cam and a LCD Shield. Also, please disable JPEG mode in the IDE.
#
# The Thermopile Shield allows your OpenMV Cam to see heat!
import sensor, image, time, fir, lcd
# Reset sensor
sensor.reset()
# Set sensor settings
sensor.set_contrast(1)
sensor.set_brightness(0)
sensor.set_saturation(2)
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QQVGA2)
# The following registers fine-tune the image
# sensor window to align it with the FIR sensor.
if (sensor.get_id() == sensor.OV2640):
sensor.__write_reg(0xFF, 0x01) # switch to reg bank
sensor.__write_reg(0x17, 0x19) # set HSTART
sensor.__write_reg(0x18, 0x43) # set HSTOP
# Initialize the thermal sensor
fir.init()
# Initialize the lcd sensor
lcd.init()
# FPS clock
clock = time.clock()
while(True):
clock.tick()
# Capture an image
image = sensor.snapshot()
# Capture FIR data
# ta: Ambient temperature
# ir: Object temperatures (IR array)
# to_min: Minimum object temperature
# to_max: Maximum object temperature
ta, ir, to_min, to_max = fir.read_ir()
# Draw IR data on the framebuffer
fir.draw_ir(image, ir)
# Draw ambient, min and max temperatures.
image.draw_string(0, 0, "Ta: %0.2f"%ta, color = (0xFF, 0x00, 0x00))
image.draw_string(0, 8, "To min: %0.2f"%to_min, color = (0xFF, 0x00, 0x00))
image.draw_string(0, 16, "To max: %0.2f"%to_max, color = (0xFF, 0x00, 0x00))
# Display image on LCD
lcd.display(image)
# Print FPS.
print(clock.fps())

View File

@ -38,6 +38,7 @@ STUSB_DIR=stusb
MICROPY_DIR=micropython
OMV_DIR=omv
LEPTON_DIR=lepton
MLX_DIR=mlx
WINC1500_DIR=winc1500
BOOTLDR_DIR=bootloader
WEBCAM_DIR=webcam
@ -104,6 +105,7 @@ OMV_CFLAGS += -I$(TOP_DIR)/$(OMV_DIR)/nn/
OMV_CFLAGS += -I$(TOP_DIR)/$(OMV_DIR)/img/
OMV_CFLAGS += -I$(OMV_BOARD_CONFIG_DIR)
OMV_CFLAGS += -I$(TOP_DIR)/$(LEPTON_DIR)/include/
OMV_CFLAGS += -I$(TOP_DIR)/$(MLX_DIR)/include/
OMV_CFLAGS += -I$(TOP_DIR)/$(WINC1500_DIR)/include/
WEBCAM_CFLAGS = $(CFLAGS)
@ -147,6 +149,7 @@ FIRM_OBJ += $(wildcard $(BUILD)/$(CMSIS_DIR)/src/nn/SoftmaxFunctions/*.o)
#FIRM_OBJ += $(wildcard $(BUILD)/$(CMSIS_DIR)/src/dsp/TransformFunctions/*.o)
FIRM_OBJ += $(wildcard $(BUILD)/$(STHAL_DIR)/src/*.o)
FIRM_OBJ += $(wildcard $(BUILD)/$(LEPTON_DIR)/src/*.o)
FIRM_OBJ += $(wildcard $(BUILD)/$(MLX_DIR)/src/*.o)
FIRM_OBJ += $(wildcard $(BUILD)/$(WINC1500_DIR)/src/*.o)
#------------- OpenMV Objects ----------------#
@ -449,6 +452,7 @@ WEBCAM_OBJ += $(addprefix $(BUILD)/$(OMV_DIR)/img/,\
)
WEBCAM_OBJ += $(wildcard $(BUILD)/$(LEPTON_DIR)/src/*.o)
WEBCAM_OBJ += $(wildcard $(BUILD)/$(MLX_DIR)/src/*.o)
###################################################
#Export Variables
export Q
@ -484,6 +488,7 @@ FIRMWARE_OBJS:
$(MAKE) -C $(STHAL_DIR) BUILD=$(BUILD)/$(STHAL_DIR) CFLAGS="$(CFLAGS) -MMD"
$(MAKE) -C $(MICROPY_DIR)/ports/stm32 BUILD=$(BUILD)/$(MICROPY_DIR) BOARD=$(TARGET) QSTR_DEFS=$(OMV_QSTR_DEFS)
$(MAKE) -C $(LEPTON_DIR) BUILD=$(BUILD)/$(LEPTON_DIR) CFLAGS="$(CFLAGS) -MMD"
$(MAKE) -C $(MLX_DIR) BUILD=$(BUILD)/$(MLX_DIR) CFLAGS="$(CFLAGS) -MMD"
$(MAKE) -C $(WINC1500_DIR) BUILD=$(BUILD)/$(WINC1500_DIR) CFLAGS="$(CFLAGS) -MMD"
$(MAKE) -C $(OMV_DIR) BUILD=$(BUILD)/$(OMV_DIR) CFLAGS="$(CFLAGS) -MMD"

17
src/mlx/Makefile Normal file
View File

@ -0,0 +1,17 @@
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,64 @@
/**
* @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 _MLX640_API_H_
#define _MLX640_API_H_
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[4];
int16_t ct[4];
float alpha[768];
int16_t offset[768];
float kta[768];
float kv[768];
float cpAlpha[2];
int16_t cpOffset[2];
float ilChessC[3];
uint16_t brokenPixels[5];
uint16_t outlierPixels[5];
} paramsMLX90640;
int MLX90640_DumpEE(uint8_t slaveAddr, uint16_t *eeData);
int MLX90640_GetFrameData(uint8_t slaveAddr, uint16_t *frameData);
int MLX90640_ExtractParameters(uint16_t *eeData, paramsMLX90640 *mlx90640);
float MLX90640_GetVdd(uint16_t *frameData, const paramsMLX90640 *params);
float MLX90640_GetTa(uint16_t *frameData, const paramsMLX90640 *params);
void MLX90640_GetImage(uint16_t *frameData, const paramsMLX90640 *params, float *result);
void MLX90640_CalculateTo(uint16_t *frameData, const paramsMLX90640 *params, float emissivity, float tr, float *result);
int MLX90640_SetResolution(uint8_t slaveAddr, uint8_t resolution);
int MLX90640_GetCurResolution(uint8_t slaveAddr);
int MLX90640_SetRefreshRate(uint8_t slaveAddr, uint8_t refreshRate);
int MLX90640_GetRefreshRate(uint8_t slaveAddr);
int MLX90640_GetSubPageNumber(uint16_t *frameData);
int MLX90640_GetCurMode(uint8_t slaveAddr);
int MLX90640_SetInterleavedMode(uint8_t slaveAddr);
int MLX90640_SetChessMode(uint8_t slaveAddr);
#endif

View File

@ -0,0 +1,26 @@
/**
* @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 _MLX90640_I2C_Driver_H_
#define _MLX90640_I2C_Driver_H_
#include <stdint.h>
void MLX90640_I2CInit(void);
int MLX90640_I2CRead(uint8_t slaveAddr,uint16_t startAddress, uint16_t nMemAddressRead, uint16_t *data);
int MLX90640_I2CWrite(uint8_t slaveAddr,uint16_t writeAddress, uint16_t data);
void MLX90640_I2CFreqSet(int freq);
#endif

1187
src/mlx/src/MLX90640_API.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,107 @@
/**
* @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 "mbed.h"
#include "MLX90640_I2C_Driver.h"
I2C i2c(p9, p10);
void MLX90640_I2CInit()
{
i2c.stop();
}
int MLX90640_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;
p = data;
sa = (slaveAddr << 1);
cmd[0] = startAddress >> 8;
cmd[1] = startAddress & 0x00FF;
i2c.stop();
wait_us(5);
ack = i2c.write(sa, cmd, 2, 1);
if (ack != 0x00)
{
return -1;
}
sa = sa | 0x01;
ack = i2c.read(sa, i2cData, 2*nMemAddressRead, 0);
if (ack != 0x00)
{
return -1;
}
i2c.stop();
for(cnt=0; cnt < nMemAddressRead; cnt++)
{
i = cnt << 1;
*p++ = (uint16_t)i2cData[i]*256 + (uint16_t)i2cData[i+1];
}
return 0;
}
void MLX90640_I2CFreqSet(int freq)
{
i2c.frequency(1000*freq);
}
int MLX90640_I2CWrite(uint8_t slaveAddr, uint16_t writeAddress, uint16_t data)
{
uint8_t sa;
int ack = 0;
char cmd[4] = {0,0,0,0};
uint16_t dataCheck;
sa = (slaveAddr << 1);
cmd[0] = writeAddress >> 8;
cmd[1] = writeAddress & 0x00FF;
cmd[2] = data >> 8;
cmd[3] = data & 0x00FF;
i2c.stop();
wait_us(5);
ack = i2c.write(sa, cmd, 4, 0);
if (ack != 0x00)
{
return -1;
}
i2c.stop();
MLX90640_I2CRead(slaveAddr,writeAddress,1, &dataCheck);
if ( dataCheck != data)
{
return -2;
}
return 0;
}*/

View File

@ -0,0 +1,334 @@
/**
* @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.
*
*/
/**
* As the timings depend heavily on the MCU in use, it is recommended
* to make sure that the proper timings are achieved. For that purpose
* an oscilloscope might be needed to strobe the SCL and SDA signals.
* The Wait(int) function could be modified in order to better
* trim the frequency. For coarse setting of the frequency or
* dynamic frequency change using the default function implementation,
* freqCnt argument should be changed lower value results in
* higher frequency.
*/
//#include "mbed.h"
#include "MLX90640_I2C_Driver.h"
#include STM32_HAL_H
#include "omv_boardconfig.h"
//DigitalInOut sda(p9);
#define sda I2C_SIOD_READ()
//DigitalOut scl(p10);
#define LOW 0;
#define HIGH 1;
//#define SCL_HIGH scl = HIGH;
#define SCL_HIGH I2C_SIOC_H()
//#define SCL_LOW scl = LOW;
#define SCL_LOW I2C_SIOC_L()
//#define SDA_HIGH sda.input();
#define SDA_HIGH I2C_SIOD_H()
//#define SDA_LOW sda.output(); sda = LOW;
#define SDA_LOW I2C_SIOD_L()
int I2CSendByte(int8_t);
void I2CReadBytes(int, char *);
void I2CStart(void);
void I2CStop(void);
void I2CRepeatedStart(void);
void I2CSendACK(void);
void I2CSendNack(void);
int I2CReceiveAck(void);
void Wait(int);
static int freqCnt;
void MLX90640_I2CInit()
{
I2CStop();
}
int MLX90640_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;
p = data;
sa = (slaveAddr << 1);
cmd[0] = startAddress >> 8;
cmd[1] = startAddress & 0x00FF;
I2CStop();
Wait(freqCnt);
I2CStart();
Wait(freqCnt);
ack = I2CSendByte(sa)!=0;
if(ack != 0)
{
return -1;
}
ack = I2CSendByte(cmd[0])!=0;
if(ack != 0)
{
return -1;
}
ack = I2CSendByte(cmd[1])!=0;
if(ack != 0)
{
return -1;
}
I2CRepeatedStart();
sa = sa | 0x01;
ack = I2CSendByte(sa);
if(ack != 0)
{
return -1;
}
I2CReadBytes((nMemAddressRead << 1), i2cData);
I2CStop();
for(cnt=0; cnt < nMemAddressRead; cnt++)
{
i = cnt << 1;
*p++ = (int)i2cData[i]*256 + (int)i2cData[i+1];
}
return 0;
}
void MLX90640_I2CFreqSet(int freq)
{
freqCnt = freq>>1;
}
int MLX90640_I2CWrite(uint8_t slaveAddr, uint16_t writeAddress, uint16_t data)
{
uint8_t sa;
int ack = 0;
char cmd[4] = {0,0,0,0};
uint16_t dataCheck;
sa = (slaveAddr << 1);
cmd[0] = writeAddress >> 8;
cmd[1] = writeAddress & 0x00FF;
cmd[2] = data >> 8;
cmd[3] = data & 0x00FF;
I2CStop();
Wait(freqCnt);
I2CStart();
ack = I2CSendByte(sa);
if (ack != 0x00)
{
return 1;
}
for(int i = 0; i<4; i++)
{
ack = I2CSendByte(cmd[i]);
if (ack != 0x00)
{
return -1;
}
}
I2CStop();
MLX90640_I2CRead(slaveAddr,writeAddress,1, &dataCheck);
if ( dataCheck != data)
{
return -2;
}
return 0;
}
int I2CSendByte(int8_t data)
{
int ack = 1;
int8_t byte = data;
for(int i=0;i<8;i++)
{
Wait(freqCnt);
if(byte & 0x80)
{
SDA_HIGH;
}
else
{
SDA_LOW;
}
Wait(freqCnt);
SCL_HIGH;
Wait(freqCnt);
Wait(freqCnt);
SCL_LOW;
byte = byte<<1;
}
Wait(freqCnt);
ack = I2CReceiveAck();
return ack;
}
void I2CReadBytes(int nBytes, char *dataP)
{
char data;
for(int j=0;j<nBytes;j++)
{
Wait(freqCnt);
SDA_HIGH;
data = 0;
for(int i=0;i<8;i++){
Wait(freqCnt);
SCL_HIGH;
Wait(freqCnt);
data = data<<1;
if(sda == 1){
data = data+1;
}
Wait(freqCnt);
SCL_LOW;
Wait(freqCnt);
}
if(j == (nBytes-1))
{
I2CSendNack();
}
else
{
I2CSendACK();
}
*(dataP+j) = data;
}
}
void Wait(int freqCnt)
{
for(volatile int i = 0;i<freqCnt;i++);
}
void I2CStart(void)
{
SDA_HIGH;
SCL_HIGH;
Wait(freqCnt);
Wait(freqCnt);
SDA_LOW;
Wait(freqCnt);
SCL_LOW;
Wait(freqCnt);
}
void I2CStop(void)
{
SCL_LOW;
SDA_LOW;
Wait(freqCnt);
SCL_HIGH;
Wait(freqCnt);
SDA_HIGH;
Wait(freqCnt);
}
void I2CRepeatedStart(void)
{
SCL_LOW;
Wait(freqCnt);
SDA_HIGH;
Wait(freqCnt);
SCL_HIGH;
Wait(freqCnt);
SDA_LOW;
Wait(freqCnt);
SCL_LOW;
}
void I2CSendACK(void)
{
SDA_LOW;
Wait(freqCnt);
SCL_HIGH;
Wait(freqCnt);
Wait(freqCnt);
SCL_LOW;
Wait(freqCnt);
SDA_HIGH;
}
void I2CSendNack(void)
{
SDA_HIGH;
Wait(freqCnt);
SCL_HIGH;
Wait(freqCnt);
Wait(freqCnt);
SCL_LOW;
Wait(freqCnt);
SDA_HIGH;
}
int I2CReceiveAck(void)
{
int ack;
SDA_HIGH;
Wait(freqCnt);
SCL_HIGH;
Wait(freqCnt);
if(sda == 0)
{
ack = 0;
}
else
{
ack = 1;
}
Wait(freqCnt);
SCL_LOW;
SDA_LOW;
return ack;
}

View File

@ -9,6 +9,12 @@
#ifndef __IMLIB_CONFIG_H__
#define __IMLIB_CONFIG_H__
// Enable binary ops
//#define IMLIB_ENABLE_BINARY_OPS
// Enable math ops
//#define IMLIB_ENABLE_MATH_OPS
// Enable flood_fill()
//#define IMLIB_ENABLE_FLOOD_FILL

View File

@ -161,4 +161,19 @@
#define WINC_CS_LOW() HAL_GPIO_WritePin(WINC_CS_PORT, WINC_CS_PIN, GPIO_PIN_RESET)
#define WINC_CS_HIGH() HAL_GPIO_WritePin(WINC_CS_PORT, WINC_CS_PIN, GPIO_PIN_SET)
#define I2C_PORT GPIOB
#define I2C_SIOC_PIN GPIO_PIN_10
#define I2C_SIOD_PIN GPIO_PIN_11
#define I2C_SIOC_H() HAL_GPIO_WritePin(I2C_PORT, I2C_SIOC_PIN, GPIO_PIN_SET)
#define I2C_SIOC_L() HAL_GPIO_WritePin(I2C_PORT, I2C_SIOC_PIN, GPIO_PIN_RESET)
#define I2C_SIOD_H() HAL_GPIO_WritePin(I2C_PORT, I2C_SIOD_PIN, GPIO_PIN_SET)
#define I2C_SIOD_L() HAL_GPIO_WritePin(I2C_PORT, I2C_SIOD_PIN, GPIO_PIN_RESET)
#define I2C_SIOD_READ() HAL_GPIO_ReadPin(I2C_PORT, I2C_SIOD_PIN)
#define I2C_SIOD_WRITE(bit) HAL_GPIO_WritePin(I2C_PORT, I2C_SIOD_PIN, bit);
#define I2C_SPIN_DELAY 16
#endif //__OMV_BOARDCONFIG_H__

View File

@ -9,6 +9,9 @@
#ifndef __IMLIB_CONFIG_H__
#define __IMLIB_CONFIG_H__
// Enable binary ops
#define IMLIB_ENABLE_BINARY_OPS
// Enable math ops
#define IMLIB_ENABLE_MATH_OPS

View File

@ -159,4 +159,19 @@
#define WINC_CS_LOW() HAL_GPIO_WritePin(WINC_CS_PORT, WINC_CS_PIN, GPIO_PIN_RESET)
#define WINC_CS_HIGH() HAL_GPIO_WritePin(WINC_CS_PORT, WINC_CS_PIN, GPIO_PIN_SET)
#define I2C_PORT GPIOB
#define I2C_SIOC_PIN GPIO_PIN_10
#define I2C_SIOD_PIN GPIO_PIN_11
#define I2C_SIOC_H() HAL_GPIO_WritePin(I2C_PORT, I2C_SIOC_PIN, GPIO_PIN_SET)
#define I2C_SIOC_L() HAL_GPIO_WritePin(I2C_PORT, I2C_SIOC_PIN, GPIO_PIN_RESET)
#define I2C_SIOD_H() HAL_GPIO_WritePin(I2C_PORT, I2C_SIOD_PIN, GPIO_PIN_SET)
#define I2C_SIOD_L() HAL_GPIO_WritePin(I2C_PORT, I2C_SIOD_PIN, GPIO_PIN_RESET)
#define I2C_SIOD_READ() HAL_GPIO_ReadPin(I2C_PORT, I2C_SIOD_PIN)
#define I2C_SIOD_WRITE(bit) HAL_GPIO_WritePin(I2C_PORT, I2C_SIOD_PIN, bit);
#define I2C_SPIN_DELAY 24
#endif //__OMV_BOARDCONFIG_H__

View File

@ -9,6 +9,9 @@
#ifndef __IMLIB_CONFIG_H__
#define __IMLIB_CONFIG_H__
// Enable binary ops
#define IMLIB_ENABLE_BINARY_OPS
// Enable math ops
#define IMLIB_ENABLE_MATH_OPS

View File

@ -183,6 +183,21 @@
#define WINC_CS_LOW() HAL_GPIO_WritePin(WINC_CS_PORT, WINC_CS_PIN, GPIO_PIN_RESET)
#define WINC_CS_HIGH() HAL_GPIO_WritePin(WINC_CS_PORT, WINC_CS_PIN, GPIO_PIN_SET)
#define I2C_PORT GPIOB
#define I2C_SIOC_PIN GPIO_PIN_10
#define I2C_SIOD_PIN GPIO_PIN_11
#define I2C_SIOC_H() HAL_GPIO_WritePin(I2C_PORT, I2C_SIOC_PIN, GPIO_PIN_SET)
#define I2C_SIOC_L() HAL_GPIO_WritePin(I2C_PORT, I2C_SIOC_PIN, GPIO_PIN_RESET)
#define I2C_SIOD_H() HAL_GPIO_WritePin(I2C_PORT, I2C_SIOD_PIN, GPIO_PIN_SET)
#define I2C_SIOD_L() HAL_GPIO_WritePin(I2C_PORT, I2C_SIOD_PIN, GPIO_PIN_RESET)
#define I2C_SIOD_READ() HAL_GPIO_ReadPin(I2C_PORT, I2C_SIOD_PIN)
#define I2C_SIOD_WRITE(bit) HAL_GPIO_WritePin(I2C_PORT, I2C_SIOD_PIN, bit);
#define I2C_SPIN_DELAY 32
// SPI1/2/3 clock source is PLL2 (160MHz/8 == 20MHz).
#define LEPTON_SPI_PRESCALER (SPI_BAUDRATEPRESCALER_8)
#endif //__OMV_BOARDCONFIG_H__

View File

@ -5,6 +5,7 @@
#include "imlib.h"
#ifdef IMLIB_ENABLE_BINARY_OPS
void imlib_binary(image_t *out, image_t *img, list_t *thresholds, bool invert, bool zero, image_t *mask)
{
for (list_lnk_t *it = iterator_start_from_head(thresholds); it; it = iterator_next(it)) {
@ -839,3 +840,4 @@ void imlib_black_hat(image_t *img, int ksize, int threshold, image_t *mask)
imlib_difference(img, NULL, &temp, 0, mask);
fb_free();
}
#endif

View File

@ -11,6 +11,7 @@
#include <string.h>
#include "imlib.h"
#include "fb_alloc.h"
#ifdef IMLIB_ENABLE_BINARY_OPS
typedef struct gvec {
uint16_t t;
@ -151,3 +152,4 @@ void imlib_edge_canny(image_t *src, rectangle_t *roi, int low_thresh, int high_t
fb_free();
}
#endif

View File

@ -3,18 +3,18 @@
* Copyright (c) 2013/2014 Ibrahim Abdelkader <i.abdalkader@gmail.com>
* This work is licensed under the MIT license, see the file LICENSE for details.
*
* MLX90621 Python module.
* MLX Python module.
*
*/
#include <mp.h>
#include <math.h>
#include <float.h>
#include <stdbool.h>
#include "soft_i2c.h"
#include "fb_alloc.h"
#include "xalloc.h"
#include "py_assert.h"
#include "py_image.h"
#include "MLX90640_I2C_Driver.h"
#include "MLX90640_API.h"
#include "omv_boardconfig.h"
#include "framebuffer.h"
#include "sensor.h"
#include "py_helper.h"
#include "py_image.h"
#include "py_fir.h"
#define FIR_EEPROM_ADDR 0xA0
@ -71,6 +71,10 @@
#define CAL_BCP 0xD5
#define MLX90640_ADDR 0x33
#define AMG8833_ADDR 0xD2
#define MAP(OldValue, OldMin, OldMax, NewMin, NewMax) \
({ __typeof__ (OldValue) _OldValue = (OldValue); \
__typeof__ (OldMin) _OldMin = (OldMin); \
@ -89,73 +93,77 @@ 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 int width = 0;
static int height = 0;
static enum { FIR_NONE, FIR_SHIELD } type = FIR_NONE;
static uint8_t width = 0;
static uint8_t height = 0;
static enum { FIR_NONE, FIR_SHIELD, FIR_MLX90640, FIR_AMG8833 } type = FIR_NONE;
static uint8_t IR_refresh_rate = 0;
static uint8_t ADC_resolution = 0;
static void test_ack(int ret)
{
PY_ASSERT_TRUE_MSG(ret == 0, "I2C Bus communication error - missing ACK!");
}
static float calculate_Ta() // ambient temp
{
// Code to handle dealing with brown-out conditions.
{
uint16_t config_reg;
soft_i2c_write_bytes(FIR_MODULE_ADDR,
(uint8_t [4]) {FIR_READ_CMD, 0x92, 0x00, 0x01}, 4, false);
soft_i2c_read_bytes(FIR_MODULE_ADDR,
(uint8_t*) &config_reg, 2, true);
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.
soft_i2c_write_bytes(FIR_EEPROM_ADDR,
(uint8_t [1]){CAL_OSC_TRIM}, 1, false);
soft_i2c_read_bytes(FIR_EEPROM_ADDR,
&eeprom, 1, true);
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);
(uint8_t)(0x00-0xAA), 0x00}, 5, true); // no ack here
// Write device configuration value.
uint8_t IR_refresh_rate = 0x8; // 64 Hz
uint8_t ADC_resolution = 0x3; // 18-bits
uint8_t lsb = (ADC_resolution << 4) | IR_refresh_rate;
// Normal Operation Mode - Continuous Measurment Mode
// ADC set to 18 bit resolution - IR Refresh rate = 64 Hz
uint8_t msb = 0x44;
// ADC low reference enabled - EEPROM enabled
// I2C FM+ enabled
soft_i2c_write_bytes(FIR_MODULE_ADDR,
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);
(uint8_t)(msb-0x55), msb}, 5, true));
}
}
uint16_t ptat;
soft_i2c_write_bytes(FIR_MODULE_ADDR,
(uint8_t [4]) {FIR_READ_CMD, 0x40, 0x00, 0x01}, 4, false);
soft_i2c_read_bytes(FIR_MODULE_ADDR,
(uint8_t*) &ptat, 2, true);
return (((-k_t1)+fast_sqrtf((k_t1*k_t1)-(4*k_t2*(v_th-ptat))))/(2*k_t2))+25;
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)
{
int16_t v_ir[64];
int16_t *v_ir = fb_alloc(64 * sizeof(int16_t));
// Read IR sensor result
soft_i2c_write_bytes(FIR_MODULE_ADDR,
(uint8_t [4]){FIR_READ_CMD, 0x00, 0x01, 0x40}, 4, false);
soft_i2c_read_bytes(FIR_MODULE_ADDR,
(uint8_t*) v_ir, 128, true);
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
soft_i2c_write_bytes(FIR_MODULE_ADDR,
(uint8_t [4]){FIR_READ_CMD, 0x41, 0x00, 0x01}, 4, false);
soft_i2c_read_bytes(FIR_MODULE_ADDR,
(uint8_t*) &v_cp, 2, true);
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)));
@ -181,6 +189,7 @@ static void calculate_To(float Ta, float *To)
// 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_free();
}
static mp_obj_t py_fir_deinit()
@ -189,11 +198,14 @@ static mp_obj_t py_fir_deinit()
case FIR_NONE:
return mp_const_none;
case FIR_SHIELD:
case FIR_MLX90640:
case FIR_AMG8833:
soft_i2c_deinit();
width = 0;
height = 0;
type = FIR_NONE;
IR_refresh_rate = 0;
ADC_resolution = 0;
if (a_ij) {
a_ij = NULL;
}
@ -207,6 +219,7 @@ static mp_obj_t py_fir_deinit()
}
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_fir_deinit_obj, py_fir_deinit);
/*
Allows the refresh rate to be set in the range 1Hz and 512Hz, in powers of 2. (64Hz default)
@ -225,7 +238,9 @@ mp_obj_t py_fir_init(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
py_fir_deinit();
switch (py_helper_keyword_int(n_args, args, 0, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_type), FIR_SHIELD)) {
case FIR_NONE:
{
return mp_const_none;
}
case FIR_SHIELD:
{
width = 16;
@ -233,43 +248,42 @@ mp_obj_t py_fir_init(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
type = FIR_SHIELD;
soft_i2c_init();
// pasre refresh rate and ADC resolution
uint32_t IR_refresh_rate = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_refresh), 64); // 64Hz
uint32_t ADC_resolution = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_resolution), 18); // 18-bits
// 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
ADC_resolution = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_resolution), 18); // 18-bits
// sanitize values
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));
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));
uint8_t eeprom[256];
uint8_t *eeprom = fb_alloc(256 * sizeof(uint8_t));
// Read the whole eeprom.
soft_i2c_write_bytes(FIR_EEPROM_ADDR,
(uint8_t [1]){0x00}, 1, false);
soft_i2c_read_bytes(FIR_EEPROM_ADDR,
eeprom, 256, true);
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));
// 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);
(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
// ADC set to 18 bit resolution - IR Refresh rate = 64 Hz
uint8_t msb = 0x44;
// ADC low reference enabled - EEPROM enabled
// I2C FM+ enabled
soft_i2c_write_bytes(FIR_MODULE_ADDR,
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);
(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);
@ -321,83 +335,255 @@ mp_obj_t py_fir_init(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
b_cp = ((int8_t)eeprom[CAL_BCP]) /
powf(2,b_i_scale+(3-ADC_resolution));
fb_free();
return mp_const_none;
}
case FIR_MLX90640:
{
width = 32;
height = 24;
type = FIR_MLX90640;
soft_i2c_init();
// 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), 32); // 32Hz
ADC_resolution = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_resolution), 19); // 19-bits
// sanitize values
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));
MLX90640_I2CFreqSet(I2C_SPIN_DELAY);
MLX90640_I2CInit();
int error = 0;
error |= MLX90640_SetResolution(MLX90640_ADDR, ADC_resolution);
error |= MLX90640_SetRefreshRate(MLX90640_ADDR, IR_refresh_rate);
uint16_t *eeprom = fb_alloc(832 * sizeof(uint16_t));
error |= MLX90640_DumpEE(MLX90640_ADDR, eeprom);
error |= MLX90640_ExtractParameters(eeprom, (paramsMLX90640 *) alpha_ij);
PY_ASSERT_TRUE_MSG(error == 0, "Failed to init the MLX90640!");
fb_free();
return mp_const_none;
}
case FIR_AMG8833:
{
width = 8;
height = 8;
type = FIR_AMG8833;
soft_i2c_init();
IR_refresh_rate = 10;
ADC_resolution = 12;
test_ack(soft_i2c_write_bytes(AMG8833_ADDR, (uint8_t [2]){0x01, 0x3F}, 2, true));
return mp_const_none;
}
}
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_fir_init_obj, 0, py_fir_init);
static mp_obj_t py_fir_width()
{
if (type == FIR_NONE) return mp_const_none;
return mp_obj_new_int(width);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_fir_width_obj, py_fir_width);
static mp_obj_t py_fir_height()
{
if (type == FIR_NONE) return mp_const_none;
return mp_obj_new_int(height);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_fir_height_obj, py_fir_height);
static mp_obj_t py_fir_type()
{
if (type == FIR_NONE) return mp_const_none;
return mp_obj_new_int(type);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_fir_type_obj, py_fir_type);
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 (type == FIR_NONE) return mp_const_none;
if (type == FIR_SHIELD) return mp_obj_new_int(mlx_90621_refresh_rates[IR_refresh_rate]);
if (type == FIR_MLX90640) return mp_obj_new_int(mlx_90640_refresh_rates[IR_refresh_rate]);
if (type == FIR_AMG8833) return mp_obj_new_int(IR_refresh_rate);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_fir_refresh_obj, py_fir_refresh);
static mp_obj_t py_fir_resolution()
{
if (type == FIR_NONE) return mp_const_none;
if (type == FIR_SHIELD) return mp_obj_new_int(ADC_resolution + 15);
if (type == FIR_MLX90640) return mp_obj_new_int(ADC_resolution + 16);
if (type == FIR_AMG8833) return mp_obj_new_int(ADC_resolution);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_fir_resolution_obj, py_fir_resolution);
mp_obj_t py_fir_read_ta()
{
if (type == FIR_NONE) return mp_const_none;
return mp_obj_new_float(calculate_Ta());
switch(type) {
case FIR_NONE: return mp_const_none;
case FIR_SHIELD: return mp_obj_new_float(calculate_Ta());
case FIR_MLX90640:
{
uint16_t *data = fb_alloc(834 * sizeof(uint16_t));
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));
fb_free();
return result;
}
case FIR_AMG8833:
{
test_ack(soft_i2c_write_bytes(AMG8833_ADDR, (uint8_t [1]){0x0E}, 1, true));
int16_t temp;
test_ack(soft_i2c_read_bytes(AMG8833_ADDR, (uint8_t *) &temp, 2, true));
if ((temp >> 11) & 1) temp |= 1 << 15;
temp &= 0x87FF;
return mp_obj_new_float(temp * 0.0625);
}
}
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_fir_read_ta_obj, py_fir_read_ta);
mp_obj_t py_fir_read_ir()
{
if (type == FIR_NONE) {
return mp_const_none;
}
switch(type) {
case FIR_NONE: return mp_const_none;
case FIR_SHIELD:
{
float *To = fb_alloc(64 * sizeof(float)), *To_rot = fb_alloc(64 * sizeof(float));
float Ta = calculate_Ta();
float min = FLT_MAX, max = FLT_MIN;
float To[64], To_rot[64];
float Ta = calculate_Ta();
float min = FLT_MAX, max = FLT_MIN;
// Calculate object temperatures
calculate_To(Ta, To_rot);
// 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);
}
}
// 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);
mp_obj_t tuple[4];
tuple[0] = mp_obj_new_float(Ta);
tuple[1] = mp_obj_new_list(0, NULL);
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]));
}
fb_free();
fb_free();
return mp_obj_new_tuple(4, tuple);
}
case FIR_MLX90640:
{
uint16_t *data = fb_alloc(834 * sizeof(uint16_t));
// 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 *To = fb_alloc0(768 * sizeof(float));
MLX90640_CalculateTo(data, (paramsMLX90640 *) alpha_ij, 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);
float min = FLT_MAX, max = FLT_MIN;
for (int i=0; i<768; i++) {
min = IM_MIN(min, To[i]);
max = IM_MAX(max, To[i]);
}
mp_obj_t tuple[4];
tuple[0] = mp_obj_new_float(Ta);
tuple[1] = mp_obj_new_list(0, NULL);
tuple[2] = mp_obj_new_float(min);
tuple[3] = mp_obj_new_float(max);
for (int i=0; i<768; i++) {
mp_obj_list_append(tuple[1], mp_obj_new_float(To[i]));
}
fb_free();
fb_free();
return mp_obj_new_tuple(4, tuple);
}
case FIR_AMG8833:
{
test_ack(soft_i2c_write_bytes(AMG8833_ADDR, (uint8_t [1]){0x0E}, 1, true));
int16_t temp;
test_ack(soft_i2c_read_bytes(AMG8833_ADDR, (uint8_t *) &temp, 2, true));
if ((temp >> 11) & 1) temp |= 1 << 15;
temp &= 0x87FF;
float Ta = temp * 0.0625;
test_ack(soft_i2c_write_bytes(AMG8833_ADDR, (uint8_t [1]){0x80}, 1, true));
int16_t *data = fb_alloc(64 * sizeof(int16_t));
test_ack(soft_i2c_read_bytes(AMG8833_ADDR, (uint8_t *) data, 128, true));
float To[64], min = FLT_MAX, max = FLT_MIN;
for (int i = 0; i < 64; i++) {
if ((data[i] >> 11) & 1) data[i] |= 1 << 15;
data[i] &= 0x87FF;
To[i] = data[i] * 0.25;
min = IM_MIN(min, To[i]);
max = IM_MAX(max, To[i]);
}
mp_obj_t tuple[4];
tuple[0] = mp_obj_new_float(Ta);
tuple[1] = mp_obj_new_list(0, NULL);
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]));
}
fb_free();
return mp_obj_new_tuple(4, tuple);
}
}
mp_obj_t tuple[4];
tuple[0] = mp_obj_new_float(Ta);
tuple[1] = mp_obj_new_list(0, NULL);
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]));
}
return mp_obj_new_tuple(4, tuple);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_fir_read_ir_obj, py_fir_read_ir);
mp_obj_t py_fir_draw_ta(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
if (type == FIR_NONE) return mp_const_none;
image_t *arg_img = py_image_cobj(args[0]);
PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported.");
image_t *arg_img = py_helper_arg_to_image_mutable(args[0]);
float Ta = mp_obj_get_float(args[1]);
float min = -17.7778, max = 37.7778; // 0F to 100F
int alpha = IM_MIN(IM_MAX(py_helper_keyword_int(n_args, args, 2, kw_args,
MP_OBJ_NEW_QSTR(MP_QSTR_alpha), 128), 0), 256);
int alpha = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_alpha), 128);
PY_ASSERT_TRUE_MSG((0 <= alpha) && (alpha <= 256), "Error: 0 <= alpha <= 256!");
mp_obj_t scale_obj = py_helper_keyword_object(n_args, args, 3, kw_args,
mp_obj_t scale_obj = py_helper_keyword_object(n_args, args, 3, kw_args,
MP_OBJ_NEW_QSTR(MP_QSTR_scale));
if (scale_obj) {
mp_obj_t *arg_scale;
@ -407,50 +593,65 @@ mp_obj_t py_fir_draw_ta(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
}
uint8_t gs_ta = IM_MIN(IM_MAX(MAP(Ta, min, max, 0, 255), 0), 255);
uint16_t r_ta = IM_R565(rainbow_table[gs_ta]);
uint16_t g_ta = IM_G565(rainbow_table[gs_ta]);
uint16_t b_ta = IM_B565(rainbow_table[gs_ta]);
uint16_t r_ta = COLOR_RGB565_TO_R5(rainbow_table[gs_ta]);
uint16_t g_ta = COLOR_RGB565_TO_G6(rainbow_table[gs_ta]);
uint16_t b_ta = COLOR_RGB565_TO_B5(rainbow_table[gs_ta]);
uint32_t va = __PKHBT((256-alpha), alpha, 16);
for (int y=0; y<arg_img->h; y++) {
for (int x=0; x<arg_img->w; x++) {
if (IM_IS_GS(arg_img)) {
uint8_t pixel = IM_GET_GS_PIXEL(arg_img, x, y);
uint32_t vgs = __PKHBT(pixel, gs_ta, 16);
uint32_t gs = __SMUAD(va, vgs)>>8;
IM_SET_GS_PIXEL(arg_img, x, y, gs);
} else {
uint16_t pixel = IM_GET_RGB565_PIXEL(arg_img, x, y);
uint32_t vr = __PKHBT(IM_R565(pixel), r_ta, 16);
uint32_t vg = __PKHBT(IM_G565(pixel), g_ta, 16);
uint32_t vb = __PKHBT(IM_B565(pixel), b_ta, 16);
uint32_t r = __SMUAD(va, vr)>>8;
uint32_t g = __SMUAD(va, vg)>>8;
uint32_t b = __SMUAD(va, vb)>>8;
IM_SET_RGB565_PIXEL(arg_img, x, y, IM_RGB565(r, g, b));
switch (arg_img->bpp) {
case IMAGE_BPP_BINARY:
{
uint8_t pixel = COLOR_BINARY_TO_GRAYSCALE(IMAGE_GET_BINARY_PIXEL(arg_img, x, y));
uint32_t vgs = __PKHBT(pixel, gs_ta, 16);
uint32_t gs = __SMUAD(va, vgs)>>8;
IMAGE_PUT_BINARY_PIXEL(arg_img, x, y, COLOR_GRAYSCALE_TO_BINARY(gs));
break;
}
case IMAGE_BPP_GRAYSCALE:
{
uint8_t pixel = IMAGE_GET_GRAYSCALE_PIXEL(arg_img, x, y);
uint32_t vgs = __PKHBT(pixel, gs_ta, 16);
uint32_t gs = __SMUAD(va, vgs)>>8;
IMAGE_PUT_GRAYSCALE_PIXEL(arg_img, x, y, gs);
break;
}
case IMAGE_BPP_RGB565: {
uint16_t pixel = IMAGE_GET_RGB565_PIXEL(arg_img, x, y);
uint32_t vr = __PKHBT(COLOR_RGB565_TO_R5(pixel), r_ta, 16);
uint32_t vg = __PKHBT(COLOR_RGB565_TO_G6(pixel), g_ta, 16);
uint32_t vb = __PKHBT(COLOR_RGB565_TO_B5(pixel), b_ta, 16);
uint32_t r = __SMUAD(va, vr)>>8;
uint32_t g = __SMUAD(va, vg)>>8;
uint32_t b = __SMUAD(va, vb)>>8;
IMAGE_PUT_RGB565_PIXEL(arg_img, x, y, COLOR_R5_G6_B5_TO_RGB565(r, g, b));
break;
}
default: break;
}
}
}
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_fir_draw_ta_obj, 2, py_fir_draw_ta);
mp_obj_t py_fir_draw_ir(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
if (type == FIR_NONE) return mp_const_none;
image_t *arg_img = py_image_cobj(args[0]);
PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported.");
image_t *arg_img = py_helper_arg_to_image_mutable(args[0]);
mp_obj_t *arg_To;
mp_obj_get_array_fixed_n(args[1], 64, &arg_To);
mp_obj_get_array_fixed_n(args[1], width*height, &arg_To);
float To[64], min = FLT_MAX, max = FLT_MIN;
for (int i=0; i<64; i++) {
float *To = fb_alloc(width*height * sizeof(float)), min = FLT_MAX, max = FLT_MIN;
for (int i=0; i<width*height; i++) {
float temp = To[i] = mp_obj_get_float(arg_To[i]);
min = IM_MIN(min, temp);
max = IM_MAX(max, temp);
}
int alpha = IM_MIN(IM_MAX(py_helper_keyword_int(n_args, args, 2, kw_args,
MP_OBJ_NEW_QSTR(MP_QSTR_alpha), 128), 0), 256);
int alpha = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_alpha), 128);
PY_ASSERT_TRUE_MSG((0 <= alpha) && (alpha <= 256), "Error: 0 <= alpha <= 256!");
mp_obj_t scale_obj = py_helper_keyword_object(n_args, args, 3, kw_args,
MP_OBJ_NEW_QSTR(MP_QSTR_scale));
@ -461,65 +662,129 @@ mp_obj_t py_fir_draw_ir(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
max = mp_obj_get_float(arg_scale[1]);
}
int x_scale = arg_img->w / width;
int x_offset = (arg_img->w - (width * x_scale)) / 2;
int y_scale = x_scale; // keep aspect ratio
int y_offset = (arg_img->h - (height * y_scale)) / 2;
int x_scale = arg_img->w / width, y_scale = arg_img->h / height;
int scale = IM_MIN(x_scale, y_scale);
int x_offset = (arg_img->w - (width * scale)) / 2;
int y_offset = (arg_img->h - (height * scale)) / 2;
uint32_t va = __PKHBT((256-alpha), alpha, 16);
for (int y=y_offset; y<y_offset+(height*y_scale); y++) {
for (int x=x_offset; x<x_offset+(width*x_scale); x++) {
int index = (((y-y_offset)/y_scale)*width)+((x-x_offset)/x_scale);
for (int y=y_offset; y<y_offset+(height*scale); y++) {
for (int x=x_offset; x<x_offset+(width*scale); x++) {
int index = (((y-y_offset)/scale)*width)+((x-x_offset)/scale);
uint8_t gs_to = IM_MIN(IM_MAX(MAP(To[index], min, max, 0, 255), 0), 255);
uint16_t r_to = IM_R565(rainbow_table[gs_to]);
uint16_t g_to = IM_G565(rainbow_table[gs_to]);
uint16_t b_to = IM_B565(rainbow_table[gs_to]);
if (IM_IS_GS(arg_img)) {
uint8_t pixel = IM_GET_GS_PIXEL(arg_img, x, y);
uint32_t vgs = __PKHBT(pixel, gs_to, 16);
uint32_t gs = __SMUAD(va, vgs)>>8;
IM_SET_GS_PIXEL(arg_img, x, y, gs);
} else {
uint16_t pixel = IM_GET_RGB565_PIXEL(arg_img, x, y);
uint32_t vr = __PKHBT(IM_R565(pixel), r_to, 16);
uint32_t vg = __PKHBT(IM_G565(pixel), g_to, 16);
uint32_t vb = __PKHBT(IM_B565(pixel), b_to, 16);
uint32_t r = __SMUAD(va, vr)>>8;
uint32_t g = __SMUAD(va, vg)>>8;
uint32_t b = __SMUAD(va, vb)>>8;
IM_SET_RGB565_PIXEL(arg_img, x, y, IM_RGB565(r, g, b));
uint16_t r_to = COLOR_RGB565_TO_R5(rainbow_table[gs_to]);
uint16_t g_to = COLOR_RGB565_TO_G6(rainbow_table[gs_to]);
uint16_t b_to = COLOR_RGB565_TO_B5(rainbow_table[gs_to]);
switch (arg_img->bpp) {
case IMAGE_BPP_BINARY:
{
uint8_t pixel = COLOR_BINARY_TO_GRAYSCALE(IMAGE_GET_BINARY_PIXEL(arg_img, x, y));
uint32_t vgs = __PKHBT(pixel, gs_to, 16);
uint32_t gs = __SMUAD(va, vgs)>>8;
IMAGE_PUT_BINARY_PIXEL(arg_img, x, y, COLOR_GRAYSCALE_TO_BINARY(gs));
break;
}
case IMAGE_BPP_GRAYSCALE:
{
uint8_t pixel = IMAGE_GET_GRAYSCALE_PIXEL(arg_img, x, y);
uint32_t vgs = __PKHBT(pixel, gs_to, 16);
uint32_t gs = __SMUAD(va, vgs)>>8;
IMAGE_PUT_GRAYSCALE_PIXEL(arg_img, x, y, gs);
break;
}
case IMAGE_BPP_RGB565: {
uint16_t pixel = IMAGE_GET_RGB565_PIXEL(arg_img, x, y);
uint32_t vr = __PKHBT(COLOR_RGB565_TO_R5(pixel), r_to, 16);
uint32_t vg = __PKHBT(COLOR_RGB565_TO_G6(pixel), g_to, 16);
uint32_t vb = __PKHBT(COLOR_RGB565_TO_B5(pixel), b_to, 16);
uint32_t r = __SMUAD(va, vr)>>8;
uint32_t g = __SMUAD(va, vg)>>8;
uint32_t b = __SMUAD(va, vb)>>8;
IMAGE_PUT_RGB565_PIXEL(arg_img, x, y, COLOR_R5_G6_B5_TO_RGB565(r, g, b));
break;
}
default: break;
}
}
}
fb_free();
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_fir_init_obj, 0, py_fir_init);
STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_fir_deinit_obj, py_fir_deinit);
STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_fir_width_obj, py_fir_width);
STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_fir_height_obj, py_fir_height);
STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_fir_type_obj, py_fir_type);
STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_fir_read_ta_obj, py_fir_read_ta);
STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_fir_read_ir_obj, py_fir_read_ir);
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_fir_draw_ta_obj, 2, py_fir_draw_ta);
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_fir_draw_ir_obj, 2, py_fir_draw_ir);
static const mp_map_elem_t globals_dict_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_fir) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&py_fir_init_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_deinit), (mp_obj_t)&py_fir_deinit_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_width), (mp_obj_t)&py_fir_width_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_height), (mp_obj_t)&py_fir_height_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_type), (mp_obj_t)&py_fir_type_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_read_ta), (mp_obj_t)&py_fir_read_ta_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_read_ir), (mp_obj_t)&py_fir_read_ir_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_draw_ta), (mp_obj_t)&py_fir_draw_ta_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_draw_ir), (mp_obj_t)&py_fir_draw_ir_obj },
{ NULL, NULL },
mp_obj_t py_fir_snapshot(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
if (type == FIR_NONE) return mp_const_none;
mp_obj_t ir = py_fir_read_ir();
size_t len;
mp_obj_t *items;
mp_obj_tuple_get(ir, &len, &items);
int pixformat = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_pixformat), PIXFORMAT_RGB565);
PY_ASSERT_TRUE_MSG((pixformat == PIXFORMAT_GRAYSCALE) || (pixformat == PIXFORMAT_RGB565), "Invalid Pixformat!");
bool copy_to_fb = py_helper_keyword_int(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_copy_to_fb), false);
if (copy_to_fb) fb_update_jpeg_buffer();
image_t image;
image.w = width;
image.h = height;
image.bpp = (pixformat == PIXFORMAT_RGB565) ? IMAGE_BPP_RGB565 : IMAGE_BPP_GRAYSCALE;
image.data = NULL;
if (copy_to_fb) {
PY_ASSERT_TRUE_MSG((image_size(&image) <= OMV_RAW_BUF_SIZE), "FB Overflow!");
MAIN_FB()->w = image.w;
MAIN_FB()->h = image.h;
MAIN_FB()->bpp = image.bpp;
image.data = MAIN_FB()->pixels;
} else {
image.data = xalloc(image_size(&image));
}
mp_obj_t snapshot = py_image_from_struct(&image);
mp_obj_t *new_args = xalloc((2 + n_args) * sizeof(mp_obj_t));
new_args[0] = snapshot;
new_args[1] = items[1]; // ir array
for (uint i = 0; i < n_args; i++) {
new_args[2+i] = args[i];
}
py_fir_draw_ir(2 + n_args, new_args, kw_args);
gc_collect();
return snapshot;
}
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_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) },
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&py_fir_deinit_obj) },
{ MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&py_fir_width_obj) },
{ MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&py_fir_height_obj) },
{ MP_ROM_QSTR(MP_QSTR_type), MP_ROM_PTR(&py_fir_type_obj) },
{ MP_ROM_QSTR(MP_QSTR_refresh), MP_ROM_PTR(&py_fir_refresh_obj) },
{ MP_ROM_QSTR(MP_QSTR_resolution), MP_ROM_PTR(&py_fir_resolution_obj) },
{ MP_ROM_QSTR(MP_QSTR_read_ta), MP_ROM_PTR(&py_fir_read_ta_obj) },
{ MP_ROM_QSTR(MP_QSTR_read_ir), MP_ROM_PTR(&py_fir_read_ir_obj) },
{ MP_ROM_QSTR(MP_QSTR_draw_ta), MP_ROM_PTR(&py_fir_draw_ta_obj) },
{ MP_ROM_QSTR(MP_QSTR_draw_ir), MP_ROM_PTR(&py_fir_draw_ir_obj) },
{ MP_ROM_QSTR(MP_QSTR_snapshot), MP_ROM_PTR(&py_fir_snapshot_obj) }
};
STATIC MP_DEFINE_CONST_DICT(globals_dict, globals_dict_table);
const mp_obj_module_t fir_module = {
.base = { &mp_type_module },
.globals = (mp_obj_t)&globals_dict,
.globals = (mp_obj_t) &globals_dict,
};
void py_fir_init0()

View File

@ -3,7 +3,7 @@
* Copyright (c) 2013/2014 Ibrahim Abdelkader <i.abdalkader@gmail.com>
* This work is licensed under the MIT license, see the file LICENSE for details.
*
* MLX90621 Python module.
* MLX Python module.
*
*/
#ifndef __PY_FIR_H__

View File

@ -1489,6 +1489,7 @@ STATIC mp_obj_t py_image_flood_fill(uint n_args, const mp_obj_t *args, mp_map_t
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_flood_fill_obj, 2, py_image_flood_fill);
#endif // IMLIB_ENABLE_FLOOD_FILL
#ifdef IMLIB_ENABLE_BINARY_OPS
/////////////////
// Binary Methods
/////////////////
@ -1758,6 +1759,7 @@ STATIC mp_obj_t py_image_close(uint n_args, const mp_obj_t *args, mp_map_t *kw_a
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_close_obj, 2, py_image_close);
#endif // IMLIB_ENABLE_BINARY_OPS
#ifdef IMLIB_ENABLE_MATH_OPS
///////////////
@ -5157,6 +5159,7 @@ static mp_obj_t py_image_find_keypoints(uint n_args, const mp_obj_t *args, mp_ma
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_keypoints_obj, 1, py_image_find_keypoints);
#ifdef IMLIB_ENABLE_BINARY_OPS
static mp_obj_t py_image_find_edges(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
image_t *arg_img = py_helper_arg_to_image_grayscale(args[0]);
@ -5190,6 +5193,7 @@ static mp_obj_t py_image_find_edges(uint n_args, const mp_obj_t *args, mp_map_t
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_edges_obj, 2, py_image_find_edges);
#endif
#ifdef IMLIB_ENABLE_HOG
static mp_obj_t py_image_find_hog(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
@ -5276,6 +5280,7 @@ static const mp_rom_map_elem_t locals_dict_table[] = {
#endif
{MP_ROM_QSTR(MP_QSTR_draw_keypoints), MP_ROM_PTR(&py_image_draw_keypoints_obj)},
/* Binary Methods */
#ifdef IMLIB_ENABLE_BINARY_OPS
{MP_ROM_QSTR(MP_QSTR_binary), MP_ROM_PTR(&py_image_binary_obj)},
{MP_ROM_QSTR(MP_QSTR_invert), MP_ROM_PTR(&py_image_invert_obj)},
{MP_ROM_QSTR(MP_QSTR_and), MP_ROM_PTR(&py_image_b_and_obj)},
@ -5294,6 +5299,26 @@ static const mp_rom_map_elem_t locals_dict_table[] = {
{MP_ROM_QSTR(MP_QSTR_dilate), MP_ROM_PTR(&py_image_dilate_obj)},
{MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&py_image_open_obj)},
{MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&py_image_close_obj)},
#else
{MP_ROM_QSTR(MP_QSTR_binary), MP_ROM_PTR(&py_func_unavailable_obj)},
{MP_ROM_QSTR(MP_QSTR_invert), MP_ROM_PTR(&py_func_unavailable_obj)},
{MP_ROM_QSTR(MP_QSTR_and), MP_ROM_PTR(&py_func_unavailable_obj)},
{MP_ROM_QSTR(MP_QSTR_b_and), MP_ROM_PTR(&py_func_unavailable_obj)},
{MP_ROM_QSTR(MP_QSTR_nand), MP_ROM_PTR(&py_func_unavailable_obj)},
{MP_ROM_QSTR(MP_QSTR_b_nand), MP_ROM_PTR(&py_func_unavailable_obj)},
{MP_ROM_QSTR(MP_QSTR_or), MP_ROM_PTR(&py_func_unavailable_obj)},
{MP_ROM_QSTR(MP_QSTR_b_or), MP_ROM_PTR(&py_func_unavailable_obj)},
{MP_ROM_QSTR(MP_QSTR_nor), MP_ROM_PTR(&py_func_unavailable_obj)},
{MP_ROM_QSTR(MP_QSTR_b_nor), MP_ROM_PTR(&py_func_unavailable_obj)},
{MP_ROM_QSTR(MP_QSTR_xor), MP_ROM_PTR(&py_func_unavailable_obj)},
{MP_ROM_QSTR(MP_QSTR_b_xor), MP_ROM_PTR(&py_func_unavailable_obj)},
{MP_ROM_QSTR(MP_QSTR_xnor), MP_ROM_PTR(&py_func_unavailable_obj)},
{MP_ROM_QSTR(MP_QSTR_b_xnor), MP_ROM_PTR(&py_func_unavailable_obj)},
{MP_ROM_QSTR(MP_QSTR_erode), MP_ROM_PTR(&py_func_unavailable_obj)},
{MP_ROM_QSTR(MP_QSTR_dilate), MP_ROM_PTR(&py_func_unavailable_obj)},
{MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&py_func_unavailable_obj)},
{MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&py_func_unavailable_obj)},
#endif
#ifdef IMLIB_ENABLE_MATH_OPS
{MP_ROM_QSTR(MP_QSTR_top_hat), MP_ROM_PTR(&py_image_top_hat_obj)},
{MP_ROM_QSTR(MP_QSTR_black_hat), MP_ROM_PTR(&py_image_black_hat_obj)},
@ -5471,7 +5496,11 @@ static const mp_rom_map_elem_t locals_dict_table[] = {
{MP_ROM_QSTR(MP_QSTR_find_eye), MP_ROM_PTR(&py_image_find_eye_obj)},
{MP_ROM_QSTR(MP_QSTR_find_lbp), MP_ROM_PTR(&py_image_find_lbp_obj)},
{MP_ROM_QSTR(MP_QSTR_find_keypoints), MP_ROM_PTR(&py_image_find_keypoints_obj)},
#ifdef IMLIB_ENABLE_BINARY_OPS
{MP_ROM_QSTR(MP_QSTR_find_edges), MP_ROM_PTR(&py_image_find_edges_obj)},
#else
{MP_ROM_QSTR(MP_QSTR_find_edges), MP_ROM_PTR(&py_func_unavailable_obj)},
#endif
#ifdef IMLIB_ENABLE_HOG
{MP_ROM_QSTR(MP_QSTR_find_hog), MP_ROM_PTR(&py_image_find_hog_obj)},
#else

View File

@ -79,17 +79,6 @@ Q(get_backlight)
Q(display)
Q(clear)
// FIR Module
Q(fir)
Q(read_ta)
Q(read_ir)
Q(draw_ta)
Q(draw_ir)
Q(alpha)
Q(scale)
Q(refresh)
Q(resolution)
// Gif module
Q(gif)
Q(Gif)
@ -412,7 +401,7 @@ Q(draw_circle)
// Draw String
Q(draw_string)
// duplicate Q(color)
// duplicate Q(scale)
Q(scale)
Q(x_spacing)
Q(y_spacing)
Q(mono_space)
@ -564,7 +553,7 @@ Q(difference)
// Blend
Q(blend)
// duplicate Q(alpha)
Q(alpha)
// duplicate Q(mask)
// Histogram Equalization
@ -1006,3 +995,32 @@ Q(next_frame)
// duplicate Q(copy_to_fb)
// duplicate Q(loop)
// duplicate Q(close)
// FIR Module
Q(fir)
// duplicate Q(init)
Q(FIR_NONE)
Q(FIR_SHIELD)
Q(FIR_MLX90620)
Q(FIR_MLX90621)
Q(FIR_MLX90640)
Q(FIR_AMG8833)
Q(refresh)
Q(resolution)
// duplicate Q(deinit)
// duplicate Q(width)
// duplicate Q(height)
// duplicate Q(type)
Q(read_ta)
Q(read_ir)
Q(draw_ta)
// duplicate Q(alpha)
// duplicate Q(scale)
Q(draw_ir)
// duplicate Q(alpha)
// duplicate Q(scale)
// duplicate Q(snapshot)
// duplicate Q(alpha)
// duplicate Q(scale)
Q(pixformat)
// duplciate Q(copy_to_fb)

View File

@ -8,26 +8,14 @@
*/
#include <mp.h>
#include "soft_i2c.h"
#define I2C_PORT GPIOB
#define I2C_SIOC_PIN GPIO_PIN_10
#define I2C_SIOD_PIN GPIO_PIN_11
#define I2C_SIOC_H() HAL_GPIO_WritePin(I2C_PORT, I2C_SIOC_PIN, GPIO_PIN_SET)
#define I2C_SIOC_L() HAL_GPIO_WritePin(I2C_PORT, I2C_SIOC_PIN, GPIO_PIN_RESET)
#define I2C_SIOD_H() HAL_GPIO_WritePin(I2C_PORT, I2C_SIOD_PIN, GPIO_PIN_SET)
#define I2C_SIOD_L() HAL_GPIO_WritePin(I2C_PORT, I2C_SIOD_PIN, GPIO_PIN_RESET)
#define I2C_SIOD_READ() HAL_GPIO_ReadPin(I2C_PORT, I2C_SIOD_PIN)
#define I2C_SIOD_WRITE(bit) HAL_GPIO_WritePin(I2C_PORT, I2C_SIOD_PIN, bit);
#include "omv_boardconfig.h"
#define ACK 0
#define NACK 1
static void delay(void) // TODO: Update with clock speed knowledge for M7.
static void delay(void)
{
for(volatile int i=0; i<16; i++);
for(volatile int i=0; i<I2C_SPIN_DELAY; i++);
}
static void i2c_start(void)
@ -119,7 +107,7 @@ int soft_i2c_read_bytes(uint8_t slv_addr, uint8_t *buf, int len, bool stop)
i2c_start();
ret |= i2c_write_byte(slv_addr | 1);
for(int i=0; i<len; i++) {
buf[i] = i2c_read_byte(ACK);
buf[i] = i2c_read_byte((i != (len-1)) ? ACK : NACK);
}
if (stop) {
i2c_stop();