kopia lustrzana https://github.com/pimoroni/pimoroni-pico
Merge pull request #225 from pimoroni/driver/mlx90640
Driver for the mlx90640 thermal camerapatch-pico-graphics-deps
commit
aab8f0be35
|
@ -22,3 +22,6 @@
|
||||||
path = drivers/vl53l5cx/src
|
path = drivers/vl53l5cx/src
|
||||||
url = https://github.com/ST-mirror/VL53L5CX_ULD_driver
|
url = https://github.com/ST-mirror/VL53L5CX_ULD_driver
|
||||||
branch = no-fw/lite/en
|
branch = no-fw/lite/en
|
||||||
|
[submodule "drivers/mlx90640/src"]
|
||||||
|
path = drivers/mlx90640/src
|
||||||
|
url = https://github.com/melexis/mlx90640-library
|
||||||
|
|
|
@ -42,4 +42,5 @@ add_subdirectory(sh1107)
|
||||||
add_subdirectory(st7567)
|
add_subdirectory(st7567)
|
||||||
add_subdirectory(psram_display)
|
add_subdirectory(psram_display)
|
||||||
add_subdirectory(inky73)
|
add_subdirectory(inky73)
|
||||||
add_subdirectory(shiftregister)
|
add_subdirectory(shiftregister)
|
||||||
|
add_subdirectory(mlx90640)
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
include(mlx90640.cmake)
|
|
@ -0,0 +1,50 @@
|
||||||
|
#include "src/headers/MLX90640_I2C_Driver.h"
|
||||||
|
#include "mlx90640.hpp"
|
||||||
|
|
||||||
|
#include "stdio.h"
|
||||||
|
|
||||||
|
|
||||||
|
static pimoroni::I2C *i2c;
|
||||||
|
|
||||||
|
void MLX90640_I2CConfigure(pimoroni::I2C *i2c_instance) {
|
||||||
|
i2c = i2c_instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MLX90640_I2CInit()
|
||||||
|
{
|
||||||
|
// i2c->init(); // Called in constructor
|
||||||
|
}
|
||||||
|
|
||||||
|
int MLX90640_I2CGeneralReset(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int MLX90640_I2CRead(uint8_t slaveAddr, uint16_t startAddress, uint16_t nMemAddressRead, uint16_t *data)
|
||||||
|
{
|
||||||
|
uint8_t cmd[2] = {(char)(startAddress >> 8), (char)(startAddress & 0xFF)};
|
||||||
|
|
||||||
|
// Set 16-bit register pointer
|
||||||
|
i2c->write_blocking(slaveAddr, cmd, sizeof(cmd), true);
|
||||||
|
// Read result
|
||||||
|
i2c->read_blocking(slaveAddr, (uint8_t*)data, nMemAddressRead * sizeof(uint16_t), false);
|
||||||
|
|
||||||
|
for(auto n = 0u; n < nMemAddressRead; n++) {
|
||||||
|
data[n] = __builtin_bswap16(data[n]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MLX90640_I2CFreqSet(int freq)
|
||||||
|
{
|
||||||
|
// We can't assume we own the I2C instance and can wiggle the baudrate ad-hoc
|
||||||
|
}
|
||||||
|
|
||||||
|
int MLX90640_I2CWrite(uint8_t slaveAddr, uint16_t writeAddress, uint16_t data)
|
||||||
|
{
|
||||||
|
uint8_t cmd[4] = {(char)(writeAddress >> 8), (char)(writeAddress & 0x00FF), (char)(data >> 8), (char)(data & 0x00FF)};
|
||||||
|
i2c->write_blocking(slaveAddr, cmd, sizeof(cmd), false);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
set(DRIVER_NAME mlx90640)
|
||||||
|
add_library(${DRIVER_NAME} INTERFACE)
|
||||||
|
|
||||||
|
target_sources(${DRIVER_NAME} INTERFACE
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/src/functions/MLX90640_API.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/MLX90640_RP2040_I2C_Driver.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/mlx90640.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(${DRIVER_NAME} INTERFACE pico_stdlib hardware_i2c pimoroni_i2c)
|
||||||
|
|
||||||
|
target_include_directories(${DRIVER_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR})
|
||||||
|
target_include_directories(${DRIVER_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR}/src/headers)
|
|
@ -0,0 +1,92 @@
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <cstring>
|
||||||
|
#include <fstream>
|
||||||
|
#include <chrono>
|
||||||
|
#include <thread>
|
||||||
|
#include <math.h>
|
||||||
|
#include "src/headers/MLX90640_API.h"
|
||||||
|
#include "mlx90640.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
namespace pimoroni {
|
||||||
|
MLX90640::MLX90640_Error MLX90640::setup(int fps){
|
||||||
|
MLX90640_I2CConfigure(i2c_instance);
|
||||||
|
//MLX90640_SetDeviceMode(i2c_address, 0);
|
||||||
|
//MLX90640_SetSubPageRepeat(i2c_address, 0);
|
||||||
|
|
||||||
|
switch(fps){
|
||||||
|
case 1:
|
||||||
|
MLX90640_SetRefreshRate(i2c_address, 0b001);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
MLX90640_SetRefreshRate(i2c_address, 0b010);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
MLX90640_SetRefreshRate(i2c_address, 0b011);
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
MLX90640_SetRefreshRate(i2c_address, 0b100);
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
MLX90640_SetRefreshRate(i2c_address, 0b101);
|
||||||
|
if(i2c_instance->get_baudrate() < 1000000) {
|
||||||
|
return INVALID_BAUDRATE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 32:
|
||||||
|
MLX90640_SetRefreshRate(i2c_address, 0b110);
|
||||||
|
if(i2c_instance->get_baudrate() < 1000000) {
|
||||||
|
return INVALID_BAUDRATE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 64:
|
||||||
|
MLX90640_SetRefreshRate(i2c_address, 0b111);
|
||||||
|
if(i2c_instance->get_baudrate() < 1000000) {
|
||||||
|
return INVALID_BAUDRATE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("Unsupported framerate: %d", fps);
|
||||||
|
#endif
|
||||||
|
return INVALID_FPS;
|
||||||
|
}
|
||||||
|
//MLX90640_SetChessMode(i2c_address);
|
||||||
|
MLX90640_SetInterleavedMode(i2c_address);
|
||||||
|
//MLX90640_SetResolution(i2c_address, 0);
|
||||||
|
MLX90640_DumpEE(i2c_address, eeMLX90640);
|
||||||
|
MLX90640_ExtractParameters(eeMLX90640, &mlx90640);
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int MLX90640::get_image(void){
|
||||||
|
MLX90640_I2CConfigure(i2c_instance);
|
||||||
|
|
||||||
|
MLX90640_GetFrameData(i2c_address, frame0);
|
||||||
|
sleep_us(1000);
|
||||||
|
MLX90640_GetFrameData(i2c_address, frame1);
|
||||||
|
|
||||||
|
MLX90640_GetImage(frame0, &mlx90640, mlx90640To);
|
||||||
|
MLX90640_GetImage(frame1, &mlx90640, mlx90640To);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int MLX90640::get_frame(void){
|
||||||
|
MLX90640_I2CConfigure(i2c_instance);
|
||||||
|
|
||||||
|
MLX90640_GetFrameData(i2c_address, frame0);
|
||||||
|
sleep_us(1000);
|
||||||
|
MLX90640_GetFrameData(i2c_address, frame1);
|
||||||
|
|
||||||
|
int tr0 = MLX90640_GetTa(frame0, &mlx90640) - reflected_temperature;
|
||||||
|
MLX90640_CalculateTo(frame0, &mlx90640, emissivity, tr0, mlx90640To);
|
||||||
|
int tr1 = MLX90640_GetTa(frame1, &mlx90640) - reflected_temperature;
|
||||||
|
MLX90640_CalculateTo(frame1, &mlx90640, emissivity, tr1, mlx90640To);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "src/headers/MLX90640_API.h"
|
||||||
|
#include "common/pimoroni_i2c.hpp"
|
||||||
|
|
||||||
|
void MLX90640_I2CConfigure(pimoroni::I2C *i2c_instance);
|
||||||
|
|
||||||
|
#define MLX90640_DEFAULT_I2C_ADDRESS 0x33
|
||||||
|
|
||||||
|
namespace pimoroni {
|
||||||
|
class MLX90640 {
|
||||||
|
public:
|
||||||
|
static const int WIDTH = 32;
|
||||||
|
static const int HEIGHT = 24;
|
||||||
|
|
||||||
|
enum MLX90640_Error {
|
||||||
|
OK = 0,
|
||||||
|
INVALID_BAUDRATE = 1,
|
||||||
|
INVALID_FPS = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
float mlx90640To[WIDTH * HEIGHT] = {0.0f};
|
||||||
|
float emissivity = 1.0f;
|
||||||
|
float reflected_temperature = 8.0f;
|
||||||
|
|
||||||
|
MLX90640(pimoroni::I2C *i2c_instance, uint i2c_address=MLX90640_DEFAULT_I2C_ADDRESS) : i2c_instance(i2c_instance), i2c_address(i2c_address) {};
|
||||||
|
MLX90640_Error setup(int fps);
|
||||||
|
int get_image(void);
|
||||||
|
int get_frame(void);
|
||||||
|
private:
|
||||||
|
pimoroni::I2C *i2c_instance;
|
||||||
|
uint i2c_address = MLX90640_DEFAULT_I2C_ADDRESS;
|
||||||
|
paramsMLX90640 mlx90640;
|
||||||
|
uint16_t eeMLX90640[832] = {0};
|
||||||
|
uint16_t frame0[834] = {0};
|
||||||
|
uint16_t frame1[834] = {0};
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 4dbbc56957b6cb7fce2f7ba2d6351c3f5446f0cb
|
|
@ -24,6 +24,7 @@ add_subdirectory(breakout_scd41)
|
||||||
add_subdirectory(breakout_vl53l5cx)
|
add_subdirectory(breakout_vl53l5cx)
|
||||||
add_subdirectory(breakout_pms5003)
|
add_subdirectory(breakout_pms5003)
|
||||||
add_subdirectory(breakout_oled_128x128)
|
add_subdirectory(breakout_oled_128x128)
|
||||||
|
add_subdirectory(breakout_mlx90640)
|
||||||
|
|
||||||
add_subdirectory(pico_display)
|
add_subdirectory(pico_display)
|
||||||
add_subdirectory(pico_display_2)
|
add_subdirectory(pico_display_2)
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
set(OUTPUT_NAME mlx90460_demo)
|
||||||
|
|
||||||
|
add_executable(
|
||||||
|
${OUTPUT_NAME}
|
||||||
|
demo.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
# Pull in pico libraries that we need
|
||||||
|
target_link_libraries(${OUTPUT_NAME} pico_stdlib mlx90640 hub75_legacy hardware_vreg)
|
||||||
|
|
||||||
|
# create map/bin/hex file etc.
|
||||||
|
pico_add_extra_outputs(${OUTPUT_NAME})
|
|
@ -0,0 +1,104 @@
|
||||||
|
#include "pico/stdlib.h"
|
||||||
|
#include "hardware/vreg.h"
|
||||||
|
#include "stdio.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
#include "mlx90640.hpp"
|
||||||
|
|
||||||
|
#include "hub75.hpp"
|
||||||
|
|
||||||
|
using namespace pimoroni;
|
||||||
|
|
||||||
|
// Display size in pixels
|
||||||
|
// Should be either 64x64 or 32x32 but perhaps 64x32 an other sizes will work.
|
||||||
|
// Note: this example uses only 5 address lines so it's limited to 32*2 pixels.
|
||||||
|
const uint8_t WIDTH = 32;
|
||||||
|
const uint8_t HEIGHT = 32;
|
||||||
|
|
||||||
|
// min and max temperature range (in degrees C) for scaling false colour
|
||||||
|
const float temp_min = 18.0f;
|
||||||
|
const float temp_max = 38.0f;
|
||||||
|
|
||||||
|
// colour brightness - crushes dynamic range so use wisely!
|
||||||
|
const float brightness = 0.5f;
|
||||||
|
|
||||||
|
Hub75 hub75(WIDTH, HEIGHT, nullptr);
|
||||||
|
|
||||||
|
// Dirty hack to overclock the Pico before class initialisation takes place
|
||||||
|
// since i2c uses the current clock frequency when determining baudrate.
|
||||||
|
class OC {
|
||||||
|
public:
|
||||||
|
OC(uint32_t freq_khz, vreg_voltage voltage) {
|
||||||
|
vreg_set_voltage(voltage);
|
||||||
|
sleep_us(100);
|
||||||
|
set_sys_clock_khz(freq_khz, true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
OC oc(266000, VREG_VOLTAGE_1_20);
|
||||||
|
|
||||||
|
// 1MHz i2c for higher framerates
|
||||||
|
I2C i2c(20, 21, 1000000UL);
|
||||||
|
|
||||||
|
MLX90640 mlx90640(&i2c);
|
||||||
|
|
||||||
|
void __isr dma_complete() {
|
||||||
|
hub75.dma_complete();
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_pixel_false_colour(int x, int y, float v) {
|
||||||
|
const int colours = 8;
|
||||||
|
static float color[colours][3] = {
|
||||||
|
{0, 0, 0},
|
||||||
|
{0, 0, 255.0f},
|
||||||
|
{0, 255.0f,255.0f},
|
||||||
|
{0, 255.0f,0},
|
||||||
|
{255.0f,255.0f,0},
|
||||||
|
{255.0f,0, 0},
|
||||||
|
{255.0f,0, 255.0f},
|
||||||
|
{255.0f,255.0f,255.0f}
|
||||||
|
};
|
||||||
|
int idx1, idx2;
|
||||||
|
float blend = 0.0f;
|
||||||
|
const float temp_range = temp_max - temp_min;
|
||||||
|
v -= temp_min;
|
||||||
|
v /= temp_range;
|
||||||
|
if(v <= 0) {idx1 = idx2 = 0;}
|
||||||
|
else if(v >= 1) {idx1 = idx2 = colours - 1;}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
v *= (colours - 1);
|
||||||
|
idx1 = std::floor(v);
|
||||||
|
idx2 = idx1 + 1;
|
||||||
|
blend = v - float(idx1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int r = (int)((((color[idx2][0] - color[idx1][0]) * blend) + color[idx1][0]) * brightness);
|
||||||
|
int g = (int)((((color[idx2][1] - color[idx1][1]) * blend) + color[idx1][1]) * brightness);
|
||||||
|
int b = (int)((((color[idx2][2] - color[idx1][2]) * blend) + color[idx1][2]) * brightness);
|
||||||
|
|
||||||
|
hub75.set_rgb(x, y, r, g, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
stdio_init_all();
|
||||||
|
hub75.start(dma_complete);
|
||||||
|
|
||||||
|
mlx90640.setup(32);
|
||||||
|
|
||||||
|
while(true) {
|
||||||
|
mlx90640.get_frame();
|
||||||
|
for(auto y = 0u; y < 24; y++) {
|
||||||
|
for(auto x = 0u; x < 32; x++) {
|
||||||
|
int offset = y * 32 + x;
|
||||||
|
float v = mlx90640.mlx90640To[offset]; // / 30000.0f;
|
||||||
|
set_pixel_false_colour(x, y, v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hub75.flip();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
add_library(usermod_mlx90640 INTERFACE)
|
||||||
|
|
||||||
|
target_sources(usermod_mlx90640 INTERFACE
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/mlx90640.c
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/mlx90640.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/../../../drivers/mlx90640/mlx90640.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/../../../drivers/mlx90640/src/functions/MLX90640_API.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/../../../drivers/mlx90640/MLX90640_RP2040_I2C_Driver.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(usermod_mlx90640 INTERFACE
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/../../../drivers/mlx90640/
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/../../../drivers/mlx90640/src/headers/
|
||||||
|
)
|
||||||
|
|
||||||
|
target_compile_definitions(usermod_mlx90640 INTERFACE
|
||||||
|
MODULE_MLX90640_ENABLED=1
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(usermod INTERFACE usermod_mlx90640)
|
|
@ -0,0 +1,45 @@
|
||||||
|
#include "mlx90640.h"
|
||||||
|
|
||||||
|
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_2(MLX90640_setup_obj, MLX90640_setup);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(MLX90640_get_frame_obj, MLX90640_get_frame);
|
||||||
|
|
||||||
|
STATIC const mp_rom_map_elem_t MLX90640_locals_dict_table[] = {
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_setup), MP_ROM_PTR(&MLX90640_setup_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_get_frame), MP_ROM_PTR(&MLX90640_get_frame_obj) },
|
||||||
|
};
|
||||||
|
STATIC MP_DEFINE_CONST_DICT(MLX90640_locals_dict, MLX90640_locals_dict_table);
|
||||||
|
|
||||||
|
#ifdef MP_DEFINE_CONST_OBJ_TYPE
|
||||||
|
MP_DEFINE_CONST_OBJ_TYPE(
|
||||||
|
MLX90640_MLX90640_type,
|
||||||
|
MP_QSTR_MLX90640,
|
||||||
|
MP_TYPE_FLAG_NONE,
|
||||||
|
make_new, MLX90640_make_new,
|
||||||
|
locals_dict, (mp_obj_dict_t*)&MLX90640_locals_dict
|
||||||
|
);
|
||||||
|
#else
|
||||||
|
const mp_obj_type_t MLX90640_MLX90640_type = {
|
||||||
|
{ &mp_type_type },
|
||||||
|
.name = MP_QSTR_MLX90640,
|
||||||
|
.make_new = MLX90640_make_new,
|
||||||
|
.locals_dict = (mp_obj_dict_t*)&MLX90640_locals_dict,
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
STATIC const mp_map_elem_t MLX90640_globals_table[] = {
|
||||||
|
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_msa301) },
|
||||||
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_MLX90640), (mp_obj_t)&MLX90640_type },
|
||||||
|
};
|
||||||
|
STATIC MP_DEFINE_CONST_DICT(mp_module_MLX90640_globals, MLX90640_globals_table);
|
||||||
|
|
||||||
|
const mp_obj_module_t MLX90640_user_cmodule = {
|
||||||
|
.base = { &mp_type_module },
|
||||||
|
.globals = (mp_obj_dict_t*)&mp_module_MLX90640_globals,
|
||||||
|
};
|
||||||
|
|
||||||
|
#if MICROPY_VERSION <= 70144
|
||||||
|
MP_REGISTER_MODULE(MP_QSTR_MLX90640, MLX90640_user_cmodule, MODULE_MLX90640_ENABLED);
|
||||||
|
#else
|
||||||
|
MP_REGISTER_MODULE(MP_QSTR_MLX90640, MLX90640_user_cmodule);
|
||||||
|
#endif
|
|
@ -0,0 +1,65 @@
|
||||||
|
#include "drivers/mlx90640/mlx90640.hpp"
|
||||||
|
|
||||||
|
#include "micropython/modules/util.hpp"
|
||||||
|
|
||||||
|
using namespace pimoroni;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "mlx90640.h"
|
||||||
|
#include "pimoroni_i2c.h"
|
||||||
|
|
||||||
|
typedef struct _ModMLX90640_obj_t {
|
||||||
|
mp_obj_base_t base;
|
||||||
|
MLX90640 *breakout;
|
||||||
|
_PimoroniI2C_obj_t *i2c;
|
||||||
|
int address;
|
||||||
|
} ModMLX90640_obj_t;
|
||||||
|
|
||||||
|
mp_obj_t MLX90640_setup(mp_obj_t self_in, mp_obj_t fps) {
|
||||||
|
_ModMLX90640_obj_t *self = MP_OBJ_TO_PTR2(self_in, _ModMLX90640_obj_t);
|
||||||
|
|
||||||
|
self->breakout->setup(mp_obj_get_int(fps));
|
||||||
|
|
||||||
|
return mp_const_none;
|
||||||
|
}
|
||||||
|
|
||||||
|
mp_obj_t MLX90640_get_frame(mp_obj_t self_in) {
|
||||||
|
_ModMLX90640_obj_t *self = MP_OBJ_TO_PTR2(self_in, _ModMLX90640_obj_t);
|
||||||
|
|
||||||
|
self->breakout->get_frame();
|
||||||
|
|
||||||
|
mp_obj_list_t *list = MP_OBJ_TO_PTR2(mp_obj_new_list(MLX90640::WIDTH * MLX90640::HEIGHT, NULL), mp_obj_list_t);
|
||||||
|
|
||||||
|
for(auto y = 0u; y < MLX90640::HEIGHT; y++) {
|
||||||
|
for(auto x = 0u; x < MLX90640::WIDTH; x++) {
|
||||||
|
int offset = y * MLX90640::WIDTH + x;
|
||||||
|
float v = self->breakout->mlx90640To[offset];
|
||||||
|
list->items[offset] = mp_obj_new_float(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
mp_obj_t MLX90640_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
|
||||||
|
enum { ARG_i2c, ARG_address };
|
||||||
|
static const mp_arg_t allowed_args[] = {
|
||||||
|
{ MP_QSTR_i2c, MP_ARG_OBJ, {.u_obj = nullptr} },
|
||||||
|
{ MP_QSTR_address, MP_ARG_INT, {.u_int = MLX90640_DEFAULT_I2C_ADDRESS}}
|
||||||
|
};
|
||||||
|
|
||||||
|
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||||
|
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||||
|
|
||||||
|
_ModMLX90640_obj_t *self = m_new_obj_with_finaliser(_ModMLX90640_obj_t);
|
||||||
|
self->base.type = &MLX90640_type;
|
||||||
|
|
||||||
|
self->i2c = PimoroniI2C_from_machine_i2c_or_native(args[ARG_i2c].u_obj);
|
||||||
|
self->address = args[ARG_address].u_int;
|
||||||
|
|
||||||
|
self->breakout = m_new_class(MLX90640, (pimoroni::I2C *)(self->i2c->i2c), self->address);
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
#include "py/runtime.h"
|
||||||
|
|
||||||
|
extern const mp_obj_type_t MLX90640_type;
|
||||||
|
|
||||||
|
extern mp_obj_t MLX90640_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args);
|
||||||
|
extern mp_obj_t MLX90640_get_frame(mp_obj_t self_in);
|
||||||
|
extern mp_obj_t MLX90640_setup(mp_obj_t self_in, mp_obj_t fps_in);
|
Ładowanie…
Reference in New Issue