-
Notifications
You must be signed in to change notification settings - Fork 500
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
MLX90640: Driver and 32x32 LED matrix example
- Loading branch information
Showing
11 changed files
with
311 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
include(mlx90640.cmake) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
#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: | ||
enum MLX90640_Error { | ||
OK = 0, | ||
INVALID_BAUDRATE = 1, | ||
INVALID_FPS = 2, | ||
}; | ||
|
||
float mlx90640To[768] = {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}; | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 hardware_vreg) | ||
|
||
# create map/bin/hex file etc. | ||
pico_add_extra_outputs(${OUTPUT_NAME}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} |