Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,6 @@
path = drivers/vl53l5cx/src
url = https://github.com/ST-mirror/VL53L5CX_ULD_driver
branch = no-fw/lite/en
[submodule "drivers/mlx90640/src"]
path = drivers/mlx90640/src
url = https://github.com/melexis/mlx90640-library
1 change: 1 addition & 0 deletions drivers/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,4 @@ add_subdirectory(vl53l5cx)
add_subdirectory(pcf85063a)
add_subdirectory(pms5003)
add_subdirectory(sh1107)
add_subdirectory(mlx90640)
1 change: 1 addition & 0 deletions drivers/mlx90640/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include(mlx90640.cmake)
50 changes: 50 additions & 0 deletions drivers/mlx90640/MLX90640_RP2040_I2C_Driver.cpp
Original file line number Diff line number Diff line change
@@ -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;
}

13 changes: 13 additions & 0 deletions drivers/mlx90640/mlx90640.cmake
Original file line number Diff line number Diff line change
@@ -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)
92 changes: 92 additions & 0 deletions drivers/mlx90640/mlx90640.cpp
Original file line number Diff line number Diff line change
@@ -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;
}
}
37 changes: 37 additions & 0 deletions drivers/mlx90640/mlx90640.hpp
Original file line number Diff line number Diff line change
@@ -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};
};
}
1 change: 1 addition & 0 deletions drivers/mlx90640/src
Submodule src added at 4dbbc5
1 change: 1 addition & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ add_subdirectory(breakout_scd41)
add_subdirectory(breakout_vl53l5cx)
add_subdirectory(breakout_pms5003)
add_subdirectory(breakout_oled_128x128)
add_subdirectory(breakout_mlx90640)

add_subdirectory(pico_display)
add_subdirectory(pico_display_2)
Expand Down
2 changes: 2 additions & 0 deletions examples/breakout_mlx90640/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
include(mlx90640_rgbmatrix.cmake)
include(mlx90640_st7789.cmake)
12 changes: 12 additions & 0 deletions examples/breakout_mlx90640/mlx90640_rgbmatrix.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
set(OUTPUT_NAME mlx90640_rgbmatrix)

add_executable(
${OUTPUT_NAME}
mlx90640_rgbmatrix.cpp
)

# Pull in pico libraries that we need
target_link_libraries(${OUTPUT_NAME} pico_stdlib mlx90640 hub75 hardware_vreg)

# create map/bin/hex file etc.
pico_add_extra_outputs(${OUTPUT_NAME})
104 changes: 104 additions & 0 deletions examples/breakout_mlx90640/mlx90640_rgbmatrix.cpp
Original file line number Diff line number Diff line change
@@ -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;
}
13 changes: 13 additions & 0 deletions examples/breakout_mlx90640/mlx90640_st7789.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
set(OUTPUT_NAME mlx90640_st7789)

add_executable(
${OUTPUT_NAME}
mlx90640_st7789.cpp
)

# Pull in pico libraries that we need
pico_enable_stdio_usb(${OUTPUT_NAME} 1)
target_link_libraries(${OUTPUT_NAME} pico_stdlib pico_stdio mlx90640 pico_graphics st7789)

# create map/bin/hex file etc.
pico_add_extra_outputs(${OUTPUT_NAME})
Loading