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 MICROPY_DIR=micropython
OMV_DIR=omv OMV_DIR=omv
LEPTON_DIR=lepton LEPTON_DIR=lepton
MLX_DIR=mlx
WINC1500_DIR=winc1500 WINC1500_DIR=winc1500
BOOTLDR_DIR=bootloader BOOTLDR_DIR=bootloader
WEBCAM_DIR=webcam 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$(TOP_DIR)/$(OMV_DIR)/img/
OMV_CFLAGS += -I$(OMV_BOARD_CONFIG_DIR) OMV_CFLAGS += -I$(OMV_BOARD_CONFIG_DIR)
OMV_CFLAGS += -I$(TOP_DIR)/$(LEPTON_DIR)/include/ OMV_CFLAGS += -I$(TOP_DIR)/$(LEPTON_DIR)/include/
OMV_CFLAGS += -I$(TOP_DIR)/$(MLX_DIR)/include/
OMV_CFLAGS += -I$(TOP_DIR)/$(WINC1500_DIR)/include/ OMV_CFLAGS += -I$(TOP_DIR)/$(WINC1500_DIR)/include/
WEBCAM_CFLAGS = $(CFLAGS) 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)/$(CMSIS_DIR)/src/dsp/TransformFunctions/*.o)
FIRM_OBJ += $(wildcard $(BUILD)/$(STHAL_DIR)/src/*.o) FIRM_OBJ += $(wildcard $(BUILD)/$(STHAL_DIR)/src/*.o)
FIRM_OBJ += $(wildcard $(BUILD)/$(LEPTON_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) FIRM_OBJ += $(wildcard $(BUILD)/$(WINC1500_DIR)/src/*.o)
#------------- OpenMV Objects ----------------# #------------- 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)/$(LEPTON_DIR)/src/*.o)
WEBCAM_OBJ += $(wildcard $(BUILD)/$(MLX_DIR)/src/*.o)
################################################### ###################################################
#Export Variables #Export Variables
export Q export Q
@ -484,6 +488,7 @@ FIRMWARE_OBJS:
$(MAKE) -C $(STHAL_DIR) BUILD=$(BUILD)/$(STHAL_DIR) CFLAGS="$(CFLAGS) -MMD" $(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 $(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 $(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 $(WINC1500_DIR) BUILD=$(BUILD)/$(WINC1500_DIR) CFLAGS="$(CFLAGS) -MMD"
$(MAKE) -C $(OMV_DIR) BUILD=$(BUILD)/$(OMV_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__ #ifndef __IMLIB_CONFIG_H__
#define __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() // Enable flood_fill()
//#define IMLIB_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_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 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__ #endif //__OMV_BOARDCONFIG_H__

View File

@ -9,6 +9,9 @@
#ifndef __IMLIB_CONFIG_H__ #ifndef __IMLIB_CONFIG_H__
#define __IMLIB_CONFIG_H__ #define __IMLIB_CONFIG_H__
// Enable binary ops
#define IMLIB_ENABLE_BINARY_OPS
// Enable math ops // Enable math ops
#define IMLIB_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_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 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__ #endif //__OMV_BOARDCONFIG_H__

View File

@ -9,6 +9,9 @@
#ifndef __IMLIB_CONFIG_H__ #ifndef __IMLIB_CONFIG_H__
#define __IMLIB_CONFIG_H__ #define __IMLIB_CONFIG_H__
// Enable binary ops
#define IMLIB_ENABLE_BINARY_OPS
// Enable math ops // Enable math ops
#define IMLIB_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_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 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). // SPI1/2/3 clock source is PLL2 (160MHz/8 == 20MHz).
#define LEPTON_SPI_PRESCALER (SPI_BAUDRATEPRESCALER_8) #define LEPTON_SPI_PRESCALER (SPI_BAUDRATEPRESCALER_8)
#endif //__OMV_BOARDCONFIG_H__ #endif //__OMV_BOARDCONFIG_H__

View File

@ -5,6 +5,7 @@
#include "imlib.h" #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) 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)) { 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); imlib_difference(img, NULL, &temp, 0, mask);
fb_free(); fb_free();
} }
#endif

View File

@ -11,6 +11,7 @@
#include <string.h> #include <string.h>
#include "imlib.h" #include "imlib.h"
#include "fb_alloc.h" #include "fb_alloc.h"
#ifdef IMLIB_ENABLE_BINARY_OPS
typedef struct gvec { typedef struct gvec {
uint16_t t; 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(); fb_free();
} }
#endif

View File

@ -3,18 +3,18 @@
* Copyright (c) 2013/2014 Ibrahim Abdelkader <i.abdalkader@gmail.com> * Copyright (c) 2013/2014 Ibrahim Abdelkader <i.abdalkader@gmail.com>
* This work is licensed under the MIT license, see the file LICENSE for details. * This work is licensed under the MIT license, see the file LICENSE for details.
* *
* MLX90621 Python module. * MLX Python module.
* *
*/ */
#include <mp.h> #include <stdbool.h>
#include <math.h>
#include <float.h>
#include "soft_i2c.h" #include "soft_i2c.h"
#include "fb_alloc.h" #include "MLX90640_I2C_Driver.h"
#include "xalloc.h" #include "MLX90640_API.h"
#include "py_assert.h" #include "omv_boardconfig.h"
#include "py_image.h" #include "framebuffer.h"
#include "sensor.h"
#include "py_helper.h" #include "py_helper.h"
#include "py_image.h"
#include "py_fir.h" #include "py_fir.h"
#define FIR_EEPROM_ADDR 0xA0 #define FIR_EEPROM_ADDR 0xA0
@ -71,6 +71,10 @@
#define CAL_BCP 0xD5 #define CAL_BCP 0xD5
#define MLX90640_ADDR 0x33
#define AMG8833_ADDR 0xD2
#define MAP(OldValue, OldMin, OldMax, NewMin, NewMax) \ #define MAP(OldValue, OldMin, OldMax, NewMin, NewMax) \
({ __typeof__ (OldValue) _OldValue = (OldValue); \ ({ __typeof__ (OldValue) _OldValue = (OldValue); \
__typeof__ (OldMin) _OldMin = (OldMin); \ __typeof__ (OldMin) _OldMin = (OldMin); \
@ -89,73 +93,77 @@ static float *b_ij = NULL;
static float *alpha_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 float v_th, k_t1, k_t2, tgc, emissivity, ksta, alpha_cp, ks4, a_cp, b_cp;
static int width = 0; static uint8_t width = 0;
static int height = 0; static uint8_t height = 0;
static enum { FIR_NONE, FIR_SHIELD } type = FIR_NONE; 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 static float calculate_Ta() // ambient temp
{ {
// Code to handle dealing with brown-out conditions. // Code to handle dealing with brown-out conditions.
{ {
uint16_t config_reg; uint16_t config_reg;
soft_i2c_write_bytes(FIR_MODULE_ADDR, test_ack(soft_i2c_write_bytes(FIR_MODULE_ADDR,
(uint8_t [4]) {FIR_READ_CMD, 0x92, 0x00, 0x01}, 4, false); (uint8_t [4]) {FIR_READ_CMD, 0x92, 0x00, 0x01}, 4, false));
soft_i2c_read_bytes(FIR_MODULE_ADDR, test_ack(soft_i2c_read_bytes(FIR_MODULE_ADDR,
(uint8_t*) &config_reg, 2, true); (uint8_t*) &config_reg, 2, true));
if (!(config_reg & 0x0400)) { // brown out if (!(config_reg & 0x0400)) { // brown out
uint8_t eeprom; uint8_t eeprom;
// Read the eeprom. // Read the eeprom.
soft_i2c_write_bytes(FIR_EEPROM_ADDR, test_ack(soft_i2c_write_bytes(FIR_EEPROM_ADDR,
(uint8_t [1]){CAL_OSC_TRIM}, 1, false); (uint8_t [1]){CAL_OSC_TRIM}, 1, false));
soft_i2c_read_bytes(FIR_EEPROM_ADDR, test_ack(soft_i2c_read_bytes(FIR_EEPROM_ADDR,
&eeprom, 1, true); &eeprom, 1, true));
// Write oscillator trimming value. // Write oscillator trimming value.
soft_i2c_write_bytes(FIR_MODULE_ADDR, soft_i2c_write_bytes(FIR_MODULE_ADDR,
(uint8_t [5]){FIR_WR_TRIM_CMD, (uint8_t [5]){FIR_WR_TRIM_CMD,
(uint8_t)(eeprom-0xAA), eeprom, (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. // 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; uint8_t lsb = (ADC_resolution << 4) | IR_refresh_rate;
// Normal Operation Mode - Continuous Measurment Mode // Normal Operation Mode - Continuous Measurment Mode
// ADC set to 18 bit resolution - IR Refresh rate = 64 Hz
uint8_t msb = 0x44; uint8_t msb = 0x44;
// ADC low reference enabled - EEPROM enabled // ADC low reference enabled - EEPROM enabled
// I2C FM+ 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 [5]){FIR_WR_CFG_REG,
(uint8_t)(lsb-0x55), lsb, (uint8_t)(lsb-0x55), lsb,
(uint8_t)(msb-0x55), msb}, 5, true); (uint8_t)(msb-0x55), msb}, 5, true));
} }
} }
uint16_t ptat; uint16_t ptat;
soft_i2c_write_bytes(FIR_MODULE_ADDR, test_ack(soft_i2c_write_bytes(FIR_MODULE_ADDR,
(uint8_t [4]) {FIR_READ_CMD, 0x40, 0x00, 0x01}, 4, false); (uint8_t [4]) {FIR_READ_CMD, 0x40, 0x00, 0x01}, 4, false));
soft_i2c_read_bytes(FIR_MODULE_ADDR, test_ack(soft_i2c_read_bytes(FIR_MODULE_ADDR,
(uint8_t*) &ptat, 2, true); (uint8_t*) &ptat, 2, true));
return (((-k_t1)+fast_sqrtf((k_t1*k_t1)-(4*k_t2*(v_th-ptat))))/(2*k_t2))+25; 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) 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 // Read IR sensor result
soft_i2c_write_bytes(FIR_MODULE_ADDR, test_ack(soft_i2c_write_bytes(FIR_MODULE_ADDR,
(uint8_t [4]){FIR_READ_CMD, 0x00, 0x01, 0x40}, 4, false); (uint8_t [4]){FIR_READ_CMD, 0x00, 0x01, 0x40}, 4, false));
soft_i2c_read_bytes(FIR_MODULE_ADDR, test_ack(soft_i2c_read_bytes(FIR_MODULE_ADDR,
(uint8_t*) v_ir, 128, true); (uint8_t*) v_ir, 128, true));
int16_t v_cp; int16_t v_cp;
// Read compensation pixel result // Read compensation pixel result
soft_i2c_write_bytes(FIR_MODULE_ADDR, test_ack(soft_i2c_write_bytes(FIR_MODULE_ADDR,
(uint8_t [4]){FIR_READ_CMD, 0x41, 0x00, 0x01}, 4, false); (uint8_t [4]){FIR_READ_CMD, 0x41, 0x00, 0x01}, 4, false));
soft_i2c_read_bytes(FIR_MODULE_ADDR, test_ack(soft_i2c_read_bytes(FIR_MODULE_ADDR,
(uint8_t*) &v_cp, 2, true); (uint8_t*) &v_cp, 2, true));
// Calculate Thermal Gradien Compensation (TGC) // Calculate Thermal Gradien Compensation (TGC)
float v_ir_cp_off_comp = v_cp-(a_cp+(b_cp*(Ta-25))); 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*(1-(ks4*273.15f)))+sx))+Ta4))-273.15f;
To[i] = sqrtf(sqrtf((v_ir_comp/alpha_comp_ij)+Tak4))-273.15f; To[i] = sqrtf(sqrtf((v_ir_comp/alpha_comp_ij)+Tak4))-273.15f;
} }
fb_free();
} }
static mp_obj_t py_fir_deinit() static mp_obj_t py_fir_deinit()
@ -189,11 +198,14 @@ static mp_obj_t py_fir_deinit()
case FIR_NONE: case FIR_NONE:
return mp_const_none; return mp_const_none;
case FIR_SHIELD: case FIR_SHIELD:
case FIR_MLX90640:
case FIR_AMG8833:
soft_i2c_deinit(); soft_i2c_deinit();
width = 0; width = 0;
height = 0; height = 0;
type = FIR_NONE; type = FIR_NONE;
IR_refresh_rate = 0;
ADC_resolution = 0;
if (a_ij) { if (a_ij) {
a_ij = NULL; a_ij = NULL;
} }
@ -207,6 +219,7 @@ static mp_obj_t py_fir_deinit()
} }
return mp_const_none; 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) 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(); py_fir_deinit();
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), FIR_SHIELD)) {
case FIR_NONE: case FIR_NONE:
{
return mp_const_none; return mp_const_none;
}
case FIR_SHIELD: case FIR_SHIELD:
{ {
width = 16; 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; type = FIR_SHIELD;
soft_i2c_init(); soft_i2c_init();
// pasre refresh rate and ADC resolution // parse 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 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 ADC_resolution = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_resolution), 18); // 18-bits
// sanitize values // sanitize values
ADC_resolution = ((ADC_resolution > 18)? 18:(ADC_resolution < 15)? 15:ADC_resolution) - 15; 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)); 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)); a_ij = xalloc(64 * sizeof(*a_ij));
b_ij = xalloc(64 * sizeof(*b_ij)); b_ij = xalloc(64 * sizeof(*b_ij));
alpha_ij = xalloc(64 * sizeof(*alpha_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. // Read the whole eeprom.
soft_i2c_write_bytes(FIR_EEPROM_ADDR, test_ack(soft_i2c_write_bytes(FIR_EEPROM_ADDR,
(uint8_t [1]){0x00}, 1, false); (uint8_t [1]){0x00}, 1, false));
soft_i2c_read_bytes(FIR_EEPROM_ADDR, test_ack(soft_i2c_read_bytes(FIR_EEPROM_ADDR,
eeprom, 256, true); eeprom, 256, true));
// Write oscillator trimming value. // Write oscillator trimming value.
soft_i2c_write_bytes(FIR_MODULE_ADDR, soft_i2c_write_bytes(FIR_MODULE_ADDR,
(uint8_t [5]){FIR_WR_TRIM_CMD, (uint8_t [5]){FIR_WR_TRIM_CMD,
(uint8_t)(eeprom[CAL_OSC_TRIM]-0xAA), eeprom[CAL_OSC_TRIM], (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. // Write device configuration value.
// assignment of IR_refresh_rate and ADC_resolution now done above // assignment of IR_refresh_rate and ADC_resolution now done above
uint8_t lsb = (ADC_resolution << 4) | IR_refresh_rate; uint8_t lsb = (ADC_resolution << 4) | IR_refresh_rate;
// Normal Operation Mode - Continuous Measurment Mode // Normal Operation Mode - Continuous Measurment Mode
// ADC set to 18 bit resolution - IR Refresh rate = 64 Hz
uint8_t msb = 0x44; uint8_t msb = 0x44;
// ADC low reference enabled - EEPROM enabled // ADC low reference enabled - EEPROM enabled
// I2C FM+ 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 [5]){FIR_WR_CFG_REG,
(uint8_t)(lsb-0x55), lsb, (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])) / v_th = ((int16_t)((eeprom[CAL_VTH_H]<<8)|eeprom[CAL_VTH_L])) /
powf(2,3-ADC_resolution); powf(2,3-ADC_resolution);
@ -321,43 +335,140 @@ 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]) / b_cp = ((int8_t)eeprom[CAL_BCP]) /
powf(2,b_i_scale+(3-ADC_resolution)); 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;
} }
} }
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() static mp_obj_t py_fir_width()
{ {
if (type == FIR_NONE) return mp_const_none; if (type == FIR_NONE) return mp_const_none;
return mp_obj_new_int(width); 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() static mp_obj_t py_fir_height()
{ {
if (type == FIR_NONE) return mp_const_none; if (type == FIR_NONE) return mp_const_none;
return mp_obj_new_int(height); 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() static mp_obj_t py_fir_type()
{ {
if (type == FIR_NONE) return mp_const_none; if (type == FIR_NONE) return mp_const_none;
return mp_obj_new_int(type); 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() mp_obj_t py_fir_read_ta()
{ {
if (type == FIR_NONE) return mp_const_none; switch(type) {
return mp_obj_new_float(calculate_Ta()); 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() mp_obj_t py_fir_read_ir()
{ {
if (type == FIR_NONE) { switch(type) {
return mp_const_none; case FIR_NONE: return mp_const_none;
} case FIR_SHIELD:
{
float To[64], To_rot[64]; float *To = fb_alloc(64 * sizeof(float)), *To_rot = fb_alloc(64 * sizeof(float));
float Ta = calculate_Ta(); float Ta = calculate_Ta();
float min = FLT_MAX, max = FLT_MIN; float min = FLT_MAX, max = FLT_MIN;
@ -382,20 +493,95 @@ mp_obj_t py_fir_read_ir()
for (int i=0; i<64; i++) { for (int i=0; i<64; i++) {
mp_obj_list_append(tuple[1], mp_obj_new_float(To[i])); mp_obj_list_append(tuple[1], mp_obj_new_float(To[i]));
} }
fb_free();
fb_free();
return mp_obj_new_tuple(4, tuple); 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);
}
}
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) 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; if (type == FIR_NONE) return mp_const_none;
image_t *arg_img = py_image_cobj(args[0]); image_t *arg_img = py_helper_arg_to_image_mutable(args[0]);
PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported.");
float Ta = mp_obj_get_float(args[1]); float Ta = mp_obj_get_float(args[1]);
float min = -17.7778, max = 37.7778; // 0F to 100F 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, int alpha = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_alpha), 128);
MP_OBJ_NEW_QSTR(MP_QSTR_alpha), 128), 0), 256); 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)); MP_OBJ_NEW_QSTR(MP_QSTR_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); 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 r_ta = COLOR_RGB565_TO_R5(rainbow_table[gs_ta]);
uint16_t g_ta = IM_G565(rainbow_table[gs_ta]); uint16_t g_ta = COLOR_RGB565_TO_G6(rainbow_table[gs_ta]);
uint16_t b_ta = IM_B565(rainbow_table[gs_ta]); uint16_t b_ta = COLOR_RGB565_TO_B5(rainbow_table[gs_ta]);
uint32_t va = __PKHBT((256-alpha), alpha, 16); uint32_t va = __PKHBT((256-alpha), alpha, 16);
for (int y=0; y<arg_img->h; y++) { for (int y=0; y<arg_img->h; y++) {
for (int x=0; x<arg_img->w; x++) { for (int x=0; x<arg_img->w; x++) {
if (IM_IS_GS(arg_img)) { switch (arg_img->bpp) {
uint8_t pixel = IM_GET_GS_PIXEL(arg_img, x, y); 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 vgs = __PKHBT(pixel, gs_ta, 16);
uint32_t gs = __SMUAD(va, vgs)>>8; uint32_t gs = __SMUAD(va, vgs)>>8;
IM_SET_GS_PIXEL(arg_img, x, y, gs); IMAGE_PUT_BINARY_PIXEL(arg_img, x, y, COLOR_GRAYSCALE_TO_BINARY(gs));
} else { break;
uint16_t pixel = IM_GET_RGB565_PIXEL(arg_img, x, y); }
uint32_t vr = __PKHBT(IM_R565(pixel), r_ta, 16); case IMAGE_BPP_GRAYSCALE:
uint32_t vg = __PKHBT(IM_G565(pixel), g_ta, 16); {
uint32_t vb = __PKHBT(IM_B565(pixel), b_ta, 16); 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 r = __SMUAD(va, vr)>>8;
uint32_t g = __SMUAD(va, vg)>>8; uint32_t g = __SMUAD(va, vg)>>8;
uint32_t b = __SMUAD(va, vb)>>8; uint32_t b = __SMUAD(va, vb)>>8;
IM_SET_RGB565_PIXEL(arg_img, x, y, IM_RGB565(r, g, b)); IMAGE_PUT_RGB565_PIXEL(arg_img, x, y, COLOR_R5_G6_B5_TO_RGB565(r, g, b));
break;
}
default: break;
} }
} }
} }
return mp_const_none; 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) 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; if (type == FIR_NONE) return mp_const_none;
image_t *arg_img = py_image_cobj(args[0]); image_t *arg_img = py_helper_arg_to_image_mutable(args[0]);
PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported.");
mp_obj_t *arg_To; 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; float *To = fb_alloc(width*height * sizeof(float)), min = FLT_MAX, max = FLT_MIN;
for (int i=0; i<64; i++) { for (int i=0; i<width*height; i++) {
float temp = To[i] = mp_obj_get_float(arg_To[i]); float temp = To[i] = mp_obj_get_float(arg_To[i]);
min = IM_MIN(min, temp); min = IM_MIN(min, temp);
max = IM_MAX(max, temp); max = IM_MAX(max, temp);
} }
int alpha = IM_MIN(IM_MAX(py_helper_keyword_int(n_args, args, 2, kw_args, int alpha = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_alpha), 128);
MP_OBJ_NEW_QSTR(MP_QSTR_alpha), 128), 0), 256); 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)); 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]); max = mp_obj_get_float(arg_scale[1]);
} }
int x_scale = arg_img->w / width; int x_scale = arg_img->w / width, y_scale = arg_img->h / height;
int x_offset = (arg_img->w - (width * x_scale)) / 2; int scale = IM_MIN(x_scale, y_scale);
int y_scale = x_scale; // keep aspect ratio int x_offset = (arg_img->w - (width * scale)) / 2;
int y_offset = (arg_img->h - (height * y_scale)) / 2; int y_offset = (arg_img->h - (height * scale)) / 2;
uint32_t va = __PKHBT((256-alpha), alpha, 16); uint32_t va = __PKHBT((256-alpha), alpha, 16);
for (int y=y_offset; y<y_offset+(height*y_scale); y++) { for (int y=y_offset; y<y_offset+(height*scale); y++) {
for (int x=x_offset; x<x_offset+(width*x_scale); x++) { for (int x=x_offset; x<x_offset+(width*scale); x++) {
int index = (((y-y_offset)/y_scale)*width)+((x-x_offset)/x_scale); 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); 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 r_to = COLOR_RGB565_TO_R5(rainbow_table[gs_to]);
uint16_t g_to = IM_G565(rainbow_table[gs_to]); uint16_t g_to = COLOR_RGB565_TO_G6(rainbow_table[gs_to]);
uint16_t b_to = IM_B565(rainbow_table[gs_to]); uint16_t b_to = COLOR_RGB565_TO_B5(rainbow_table[gs_to]);
if (IM_IS_GS(arg_img)) { switch (arg_img->bpp) {
uint8_t pixel = IM_GET_GS_PIXEL(arg_img, x, y); 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 vgs = __PKHBT(pixel, gs_to, 16);
uint32_t gs = __SMUAD(va, vgs)>>8; uint32_t gs = __SMUAD(va, vgs)>>8;
IM_SET_GS_PIXEL(arg_img, x, y, gs); IMAGE_PUT_BINARY_PIXEL(arg_img, x, y, COLOR_GRAYSCALE_TO_BINARY(gs));
} else { break;
uint16_t pixel = IM_GET_RGB565_PIXEL(arg_img, x, y); }
uint32_t vr = __PKHBT(IM_R565(pixel), r_to, 16); case IMAGE_BPP_GRAYSCALE:
uint32_t vg = __PKHBT(IM_G565(pixel), g_to, 16); {
uint32_t vb = __PKHBT(IM_B565(pixel), b_to, 16); 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 r = __SMUAD(va, vr)>>8;
uint32_t g = __SMUAD(va, vg)>>8; uint32_t g = __SMUAD(va, vg)>>8;
uint32_t b = __SMUAD(va, vb)>>8; uint32_t b = __SMUAD(va, vb)>>8;
IM_SET_RGB565_PIXEL(arg_img, x, y, IM_RGB565(r, g, b)); 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; 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 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_t py_fir_snapshot(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{ 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 }, if (type == FIR_NONE) return mp_const_none;
{ MP_OBJ_NEW_QSTR(MP_QSTR_width), (mp_obj_t)&py_fir_width_obj }, mp_obj_t ir = py_fir_read_ir();
{ MP_OBJ_NEW_QSTR(MP_QSTR_height), (mp_obj_t)&py_fir_height_obj }, size_t len;
{ MP_OBJ_NEW_QSTR(MP_QSTR_type), (mp_obj_t)&py_fir_type_obj }, mp_obj_t *items;
{ MP_OBJ_NEW_QSTR(MP_QSTR_read_ta), (mp_obj_t)&py_fir_read_ta_obj }, mp_obj_tuple_get(ir, &len, &items);
{ 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 }, int pixformat = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_pixformat), PIXFORMAT_RGB565);
{ MP_OBJ_NEW_QSTR(MP_QSTR_draw_ir), (mp_obj_t)&py_fir_draw_ir_obj }, PY_ASSERT_TRUE_MSG((pixformat == PIXFORMAT_GRAYSCALE) || (pixformat == PIXFORMAT_RGB565), "Invalid Pixformat!");
{ NULL, NULL },
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); STATIC MP_DEFINE_CONST_DICT(globals_dict, globals_dict_table);
const mp_obj_module_t fir_module = { const mp_obj_module_t fir_module = {
.base = { &mp_type_module }, .base = { &mp_type_module },
.globals = (mp_obj_t)&globals_dict, .globals = (mp_obj_t) &globals_dict,
}; };
void py_fir_init0() void py_fir_init0()

View File

@ -3,7 +3,7 @@
* Copyright (c) 2013/2014 Ibrahim Abdelkader <i.abdalkader@gmail.com> * Copyright (c) 2013/2014 Ibrahim Abdelkader <i.abdalkader@gmail.com>
* This work is licensed under the MIT license, see the file LICENSE for details. * This work is licensed under the MIT license, see the file LICENSE for details.
* *
* MLX90621 Python module. * MLX Python module.
* *
*/ */
#ifndef __PY_FIR_H__ #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); STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_flood_fill_obj, 2, py_image_flood_fill);
#endif // IMLIB_ENABLE_FLOOD_FILL #endif // IMLIB_ENABLE_FLOOD_FILL
#ifdef IMLIB_ENABLE_BINARY_OPS
///////////////// /////////////////
// Binary Methods // 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]; return args[0];
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_close_obj, 2, py_image_close); 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 #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); 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) 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]); 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]; return args[0];
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_edges_obj, 2, py_image_find_edges); STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_edges_obj, 2, py_image_find_edges);
#endif
#ifdef IMLIB_ENABLE_HOG #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) 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 #endif
{MP_ROM_QSTR(MP_QSTR_draw_keypoints), MP_ROM_PTR(&py_image_draw_keypoints_obj)}, {MP_ROM_QSTR(MP_QSTR_draw_keypoints), MP_ROM_PTR(&py_image_draw_keypoints_obj)},
/* Binary Methods */ /* 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_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_invert), MP_ROM_PTR(&py_image_invert_obj)},
{MP_ROM_QSTR(MP_QSTR_and), MP_ROM_PTR(&py_image_b_and_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_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_open), MP_ROM_PTR(&py_image_open_obj)},
{MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&py_image_close_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 #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_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)}, {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_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_lbp), MP_ROM_PTR(&py_image_find_lbp_obj)},
{MP_ROM_QSTR(MP_QSTR_find_keypoints), MP_ROM_PTR(&py_image_find_keypoints_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)}, {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 #ifdef IMLIB_ENABLE_HOG
{MP_ROM_QSTR(MP_QSTR_find_hog), MP_ROM_PTR(&py_image_find_hog_obj)}, {MP_ROM_QSTR(MP_QSTR_find_hog), MP_ROM_PTR(&py_image_find_hog_obj)},
#else #else

View File

@ -79,17 +79,6 @@ Q(get_backlight)
Q(display) Q(display)
Q(clear) 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 // Gif module
Q(gif) Q(gif)
Q(Gif) Q(Gif)
@ -412,7 +401,7 @@ Q(draw_circle)
// Draw String // Draw String
Q(draw_string) Q(draw_string)
// duplicate Q(color) // duplicate Q(color)
// duplicate Q(scale) Q(scale)
Q(x_spacing) Q(x_spacing)
Q(y_spacing) Q(y_spacing)
Q(mono_space) Q(mono_space)
@ -564,7 +553,7 @@ Q(difference)
// Blend // Blend
Q(blend) Q(blend)
// duplicate Q(alpha) Q(alpha)
// duplicate Q(mask) // duplicate Q(mask)
// Histogram Equalization // Histogram Equalization
@ -1006,3 +995,32 @@ Q(next_frame)
// duplicate Q(copy_to_fb) // duplicate Q(copy_to_fb)
// duplicate Q(loop) // duplicate Q(loop)
// duplicate Q(close) // 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 <mp.h>
#include "soft_i2c.h" #include "soft_i2c.h"
#include "omv_boardconfig.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);
#define ACK 0 #define ACK 0
#define NACK 1 #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) 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(); i2c_start();
ret |= i2c_write_byte(slv_addr | 1); ret |= i2c_write_byte(slv_addr | 1);
for(int i=0; i<len; i++) { 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) { if (stop) {
i2c_stop(); i2c_stop();