Compare commits
4 commits
6250786c66
...
fc2f57e4cb
Author | SHA1 | Date | |
---|---|---|---|
|
fc2f57e4cb | ||
|
a5cd63a264 | ||
|
c7d9cb3fa8 | ||
|
2c53c45c4b |
19 changed files with 2312 additions and 10 deletions
|
@ -1,2 +1,4 @@
|
||||||
# Copyright (c) 2024 PM
|
# Copyright (c) 2024 PM
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
add_subdirectory(drivers)
|
||||||
|
|
2
Kconfig
2
Kconfig
|
@ -5,5 +5,5 @@
|
||||||
# as the module Kconfig entry point (see zephyr/module.yml). You can browse
|
# as the module Kconfig entry point (see zephyr/module.yml). You can browse
|
||||||
# module options by going to Zephyr -> Modules in Kconfig.
|
# module options by going to Zephyr -> Modules in Kconfig.
|
||||||
|
|
||||||
# rsource "drivers/Kconfig"
|
rsource "drivers/Kconfig"
|
||||||
# rsource "lib/Kconfig"
|
# rsource "lib/Kconfig"
|
|
@ -10,6 +10,9 @@ CONFIG_I2C_SHELL=y
|
||||||
CONFIG_INPUT_SHELL=y
|
CONFIG_INPUT_SHELL=y
|
||||||
CONFIG_LV_Z_SHELL=y
|
CONFIG_LV_Z_SHELL=y
|
||||||
|
|
||||||
|
CONFIG_SENSOR_SHELL=y
|
||||||
|
# CONFIG_SENSOR_SHELL_BATTERY=y
|
||||||
|
|
||||||
# LVGL
|
# LVGL
|
||||||
CONFIG_LVGL=y
|
CONFIG_LVGL=y
|
||||||
CONFIG_LV_COLOR_DEPTH_32=y
|
CONFIG_LV_COLOR_DEPTH_32=y
|
||||||
|
|
|
@ -12,11 +12,14 @@
|
||||||
#include <lvgl_input_device.h>
|
#include <lvgl_input_device.h>
|
||||||
|
|
||||||
#include <zephyr/drivers/display.h>
|
#include <zephyr/drivers/display.h>
|
||||||
|
#include <zephyr/drivers/sensor.h>
|
||||||
#include <zephyr/input/input.h>
|
#include <zephyr/input/input.h>
|
||||||
#include <zephyr/random/random.h>
|
#include <zephyr/random/random.h>
|
||||||
|
|
||||||
#include <zephyr/logging/log.h>
|
#include <zephyr/logging/log.h>
|
||||||
|
|
||||||
|
#include "../../drivers/sensor/mlx90640/mlx90640.h"
|
||||||
|
|
||||||
LOG_MODULE_REGISTER(main, CONFIG_APP_LOG_LEVEL);
|
LOG_MODULE_REGISTER(main, CONFIG_APP_LOG_LEVEL);
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
|
@ -26,6 +29,7 @@ int main(void)
|
||||||
|
|
||||||
char count_str[11] = {0};
|
char count_str[11] = {0};
|
||||||
const struct device *display_dev;
|
const struct device *display_dev;
|
||||||
|
const struct device *ir_dev;
|
||||||
|
|
||||||
display_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_display));
|
display_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_display));
|
||||||
if (!device_is_ready(display_dev))
|
if (!device_is_ready(display_dev))
|
||||||
|
@ -47,33 +51,64 @@ int main(void)
|
||||||
lv_obj_t *ir_image = lv_canvas_create(lv_scr_act());
|
lv_obj_t *ir_image = lv_canvas_create(lv_scr_act());
|
||||||
lv_canvas_set_buffer(ir_image, cbuf, 32, 24, LV_IMG_CF_TRUE_COLOR);
|
lv_canvas_set_buffer(ir_image, cbuf, 32, 24, LV_IMG_CF_TRUE_COLOR);
|
||||||
|
|
||||||
lv_canvas_fill_bg(ir_image, lv_color_make(0x40,0x40,0x40), LV_OPA_COVER);
|
lv_canvas_fill_bg(ir_image, lv_color_make(0x40, 0x40, 0x40), LV_OPA_COVER);
|
||||||
|
|
||||||
lv_obj_set_size(ir_image, 32, 24);
|
lv_obj_set_size(ir_image, 32, 24);
|
||||||
lv_obj_align(ir_image, LV_ALIGN_TOP_LEFT, 4, 4);
|
lv_obj_align(ir_image, LV_ALIGN_TOP_LEFT, 4, 4);
|
||||||
lv_img_set_pivot(ir_image, 0, 0);
|
lv_img_set_pivot(ir_image, 0, 0);
|
||||||
lv_img_set_zoom(ir_image, 256 * 8);
|
// lv_img_set_zoom(ir_image, 256 * 2);
|
||||||
|
lv_img_set_zoom(ir_image, 256 * 12);
|
||||||
lv_img_set_antialias(ir_image, false);
|
lv_img_set_antialias(ir_image, false);
|
||||||
|
|
||||||
lv_timer_handler();
|
lv_timer_handler();
|
||||||
display_blanking_off(display_dev);
|
display_blanking_off(display_dev);
|
||||||
|
|
||||||
|
ir_dev = DEVICE_DT_GET(DT_NODELABEL(mlx90640_mlx90640_elecrow_i2c));
|
||||||
|
if (!device_is_ready(ir_dev))
|
||||||
|
{
|
||||||
|
printf("Device %s not ready\n", ir_dev->name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
lv_color32_t color;
|
lv_color32_t color;
|
||||||
|
float *temps = ((struct mlx90640_data *)ir_dev->data)->temps;
|
||||||
|
int64_t reftime = k_uptime_get();
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
|
sensor_sample_fetch(ir_dev);
|
||||||
|
mlx90640_calculate_to(ir_dev, 0.8, ((struct mlx90640_data *)ir_dev->data)->ta - 8.0f); // Tr = Ta - 8.0 from PDF
|
||||||
|
|
||||||
for (int y = 0; y < 24; y++)
|
for (int y = 0; y < 24; y++)
|
||||||
{
|
{
|
||||||
for (int x = 0; x < 32; x++)
|
for (int x = 0; x < 32; x++)
|
||||||
{
|
{
|
||||||
color.ch.red = (color.ch.red + 11) % 255;
|
if (temps[y * 32 + x] < 0)
|
||||||
color.ch.green = (color.ch.green + 17) % 255;
|
{
|
||||||
color.ch.blue = (color.ch.blue + 13) % 255;
|
color = lv_color_black();
|
||||||
|
}
|
||||||
|
else if (temps[y * 32 + x] > 64)
|
||||||
|
{
|
||||||
|
color = lv_color_white();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
color.ch.red = (uint8_t)(temps[y * 32 + x] * 4);
|
||||||
|
color.ch.green = color.ch.red;
|
||||||
|
color.ch.blue = color.ch.red;
|
||||||
|
}
|
||||||
lv_canvas_set_px_color(ir_image, x, y, color);
|
lv_canvas_set_px_color(ir_image, x, y, color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int delay = lv_timer_handler_run_in_period(100);
|
lv_timer_handler();
|
||||||
k_msleep(delay);
|
|
||||||
|
int64_t elapsed = k_uptime_delta(&reftime);
|
||||||
|
printf("took %d ms", (uint32_t)elapsed);
|
||||||
|
|
||||||
|
if (elapsed < 100)
|
||||||
|
{
|
||||||
|
k_msleep(100 - elapsed);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
12
boards/shields/mlx90640_elecrow_i2c/Kconfig.defconfig
Normal file
12
boards/shields/mlx90640_elecrow_i2c/Kconfig.defconfig
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
# Copyright (c) 2024 PM
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
if SHIELD_MLX90640_ELECROW_I2C
|
||||||
|
|
||||||
|
config SENSOR
|
||||||
|
default y
|
||||||
|
|
||||||
|
config MLX90640
|
||||||
|
default y
|
||||||
|
|
||||||
|
endif # SHIELD_MLX90640_ELECROW_I2C
|
6
boards/shields/mlx90640_elecrow_i2c/Kconfig.shield
Normal file
6
boards/shields/mlx90640_elecrow_i2c/Kconfig.shield
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
# Copyright (c) 2024 PM
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
config SHIELD_MLX90640_ELECROW_I2C
|
||||||
|
def_bool $(shields_list_contains,mlx90640_elecrow_i2c)
|
|
@ -0,0 +1,15 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 PM
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
&i2c0 {
|
||||||
|
status = "okay";
|
||||||
|
|
||||||
|
mlx90640_mlx90640_elecrow_i2c: mlx90640@33 {
|
||||||
|
compatible = "melexis,mlx90640";
|
||||||
|
reg = <0x33>;
|
||||||
|
status = "okay";
|
||||||
|
};
|
||||||
|
};
|
|
@ -82,7 +82,7 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
&i2c0 {
|
&i2c0 {
|
||||||
clock-frequency = <I2C_BITRATE_STANDARD>;
|
clock-frequency = <I2C_BITRATE_FAST>;
|
||||||
pinctrl-0 = <&i2c0_default>;
|
pinctrl-0 = <&i2c0_default>;
|
||||||
pinctrl-names = "default";
|
pinctrl-names = "default";
|
||||||
status = "okay";
|
status = "okay";
|
||||||
|
|
|
@ -4,7 +4,8 @@
|
||||||
CONFIG_BOARD_ELECROW_ESP_TERMINAL=y
|
CONFIG_BOARD_ELECROW_ESP_TERMINAL=y
|
||||||
CONFIG_SOC_SERIES_ESP32S3=y
|
CONFIG_SOC_SERIES_ESP32S3=y
|
||||||
|
|
||||||
CONFIG_MAIN_STACK_SIZE=8192 # increased for LVGL
|
# increased for LVGL
|
||||||
|
CONFIG_MAIN_STACK_SIZE=8192
|
||||||
|
|
||||||
CONFIG_CONSOLE=y
|
CONFIG_CONSOLE=y
|
||||||
CONFIG_SERIAL=y
|
CONFIG_SERIAL=y
|
||||||
|
|
4
drivers/CMakeLists.txt
Normal file
4
drivers/CMakeLists.txt
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
# Copyright (c) 2024 PM
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
add_subdirectory_ifdef(CONFIG_SENSOR sensor)
|
6
drivers/Kconfig
Normal file
6
drivers/Kconfig
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
# Copyright (c) 2024 PM
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
menu "Drivers"
|
||||||
|
rsource "sensor/Kconfig"
|
||||||
|
endmenu
|
4
drivers/sensor/CMakeLists.txt
Normal file
4
drivers/sensor/CMakeLists.txt
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
# Copyright (c) 2024 PM
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
add_subdirectory_ifdef(CONFIG_MLX90640 mlx90640)
|
6
drivers/sensor/Kconfig
Normal file
6
drivers/sensor/Kconfig
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
# Copyright (c) 2024 PM
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
if SENSOR
|
||||||
|
rsource "mlx90640/Kconfig"
|
||||||
|
endif # SENSOR
|
7
drivers/sensor/mlx90640/CMakeLists.txt
Normal file
7
drivers/sensor/mlx90640/CMakeLists.txt
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
zephyr_library()
|
||||||
|
|
||||||
|
zephyr_library_sources(mlx90640.c)
|
||||||
|
# zephyr_library_sources_ifdef(CONFIG_MLX90640_TRIGGER mlx90640_trigger.c)
|
||||||
|
# zephyr_library_sources(vendor/functions/MLX90640.c)
|
55
drivers/sensor/mlx90640/Kconfig
Normal file
55
drivers/sensor/mlx90640/Kconfig
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
# MLX90640 infrared thermopile sensor configuration options
|
||||||
|
|
||||||
|
# Copyright (c) 2024 PM
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
# menuconfig MLX90640
|
||||||
|
config MLX90640
|
||||||
|
bool "MLX90640 Infrared Thermopile Sensor"
|
||||||
|
default y
|
||||||
|
depends on DT_HAS_MELEXIS_MLX90640_ENABLED
|
||||||
|
select I2C
|
||||||
|
help
|
||||||
|
Enable driver for MLX90640 infrared thermopile sensor.
|
||||||
|
|
||||||
|
# if MLX90640
|
||||||
|
|
||||||
|
# choice
|
||||||
|
# prompt "Trigger mode"
|
||||||
|
# default MLX90640_TRIGGER_NONE
|
||||||
|
# help
|
||||||
|
# Specify the type of triggering used by the driver.
|
||||||
|
|
||||||
|
# config MLX90640_TRIGGER_NONE
|
||||||
|
# bool "No trigger"
|
||||||
|
|
||||||
|
# config MLX90640_TRIGGER_GLOBAL_THREAD
|
||||||
|
# bool "Use global thread"
|
||||||
|
# depends on GPIO
|
||||||
|
# select MLX90640_TRIGGER
|
||||||
|
|
||||||
|
# config MLX90640_TRIGGER_OWN_THREAD
|
||||||
|
# bool "Use own thread"
|
||||||
|
# depends on GPIO
|
||||||
|
# select MLX90640_TRIGGER
|
||||||
|
|
||||||
|
# endchoice
|
||||||
|
|
||||||
|
# config MLX90640_TRIGGER
|
||||||
|
# bool
|
||||||
|
|
||||||
|
# config MLX90640_THREAD_PRIORITY
|
||||||
|
# int "Thread priority"
|
||||||
|
# depends on MLX90640_TRIGGER_OWN_THREAD
|
||||||
|
# default 10
|
||||||
|
# help
|
||||||
|
# Priority of thread used by the driver to handle interrupts.
|
||||||
|
|
||||||
|
# config MLX90640_THREAD_STACK_SIZE
|
||||||
|
# int "Thread stack size"
|
||||||
|
# depends on MLX90640_TRIGGER_OWN_THREAD
|
||||||
|
# default 1024
|
||||||
|
# help
|
||||||
|
# Stack size of thread used by the driver to handle interrupts.
|
||||||
|
|
||||||
|
# endif # MLX90640
|
1739
drivers/sensor/mlx90640/mlx90640.c
Normal file
1739
drivers/sensor/mlx90640/mlx90640.c
Normal file
File diff suppressed because it is too large
Load diff
146
drivers/sensor/mlx90640/mlx90640.h
Normal file
146
drivers/sensor/mlx90640/mlx90640.h
Normal file
|
@ -0,0 +1,146 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 PM
|
||||||
|
*
|
||||||
|
* using code from Melexis https://github.com/melexis/mlx90640-library,
|
||||||
|
* commit f6be7ca1d4a55146b705f3d347f84b773b29cc86 under Apache-2.0
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ZEPHYR_DRIVERS_SENSOR_MLX90640_MLX90640_H_
|
||||||
|
#define ZEPHYR_DRIVERS_SENSOR_MLX90640_MLX90640_H_
|
||||||
|
|
||||||
|
#include <zephyr/device.h>
|
||||||
|
#include <zephyr/drivers/gpio.h>
|
||||||
|
#include <zephyr/drivers/i2c.h>
|
||||||
|
#include <zephyr/sys/util.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[5];
|
||||||
|
int16_t ct[5];
|
||||||
|
uint16_t alpha[768];
|
||||||
|
uint8_t alphaScale;
|
||||||
|
int16_t offset[768];
|
||||||
|
int8_t kta[768];
|
||||||
|
uint8_t ktaScale;
|
||||||
|
int8_t kv[768];
|
||||||
|
uint8_t kvScale;
|
||||||
|
float cpAlpha[2];
|
||||||
|
int16_t cpOffset[2];
|
||||||
|
float ilChessC[3];
|
||||||
|
uint16_t brokenPixels[5];
|
||||||
|
uint16_t outlierPixels[5];
|
||||||
|
} mlx90640_params;
|
||||||
|
|
||||||
|
enum mlx90640_refresh_rate
|
||||||
|
{
|
||||||
|
MLX90640_REFRESH_0_5 = 0,
|
||||||
|
MLX90640_REFRESH_1 = 1,
|
||||||
|
MLX90640_REFRESH_2 = 2,
|
||||||
|
MLX90640_REFRESH_4 = 3,
|
||||||
|
MLX90640_REFRESH_8 = 4,
|
||||||
|
MLX90640_REFRESH_16 = 5,
|
||||||
|
MLX90640_REFRESH_32 = 6,
|
||||||
|
MLX90640_REFRESH_64 = 7,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum mlx90640_adc_resolution
|
||||||
|
{
|
||||||
|
MLX90640_ADC_RES_16 = 0,
|
||||||
|
MLX90640_ADC_RES_17 = 1,
|
||||||
|
MLX90640_ADC_RES_18 = 2,
|
||||||
|
MLX90640_ADC_RES_19 = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum mlx90640_reading_pattern
|
||||||
|
{
|
||||||
|
MLX90640_PATTERN_INTERLEAVED = 0,
|
||||||
|
MLX90640_PATTERN_CHESS = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mlx90640_config
|
||||||
|
{
|
||||||
|
const struct i2c_dt_spec i2c;
|
||||||
|
const enum mlx90640_refresh_rate refresh_rate;
|
||||||
|
const enum mlx90640_adc_resolution adc_resolution;
|
||||||
|
const enum mlx90640_reading_pattern reading_pattern;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mlx90640_data
|
||||||
|
{
|
||||||
|
float temps[768];
|
||||||
|
float vdd;
|
||||||
|
float ta;
|
||||||
|
uint16_t raw_data[833]; // 768 px + 64 metadata + 1 status
|
||||||
|
mlx90640_params params;
|
||||||
|
|
||||||
|
#ifdef CONFIG_MLX90640_TRIGGER
|
||||||
|
const struct device *dev;
|
||||||
|
struct gpio_callback gpio_cb;
|
||||||
|
|
||||||
|
sensor_trigger_handler_t drdy_handler;
|
||||||
|
const struct sensor_trigger *drdy_trigger;
|
||||||
|
|
||||||
|
sensor_trigger_handler_t th_handler;
|
||||||
|
const struct sensor_trigger *th_trigger;
|
||||||
|
|
||||||
|
#if defined(CONFIG_MLX90640_TRIGGER_OWN_THREAD)
|
||||||
|
K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_MLX90640_THREAD_STACK_SIZE);
|
||||||
|
struct k_sem gpio_sem;
|
||||||
|
struct k_thread thread;
|
||||||
|
#elif defined(CONFIG_MLX90640_TRIGGER_GLOBAL_THREAD)
|
||||||
|
struct k_work work;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* CONFIG_MLX90640_TRIGGER */
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_MLX90640_TRIGGER
|
||||||
|
int mlx90640_attr_set(const struct device *dev, enum sensor_channel chan, enum sensor_attribute attr,
|
||||||
|
const struct sensor_value *val);
|
||||||
|
|
||||||
|
int mlx90640_trigger_set(const struct device *dev, const struct sensor_trigger *trig, sensor_trigger_handler_t handler);
|
||||||
|
|
||||||
|
int mlx90640_init_interrupt(const struct device *dev);
|
||||||
|
#endif /* CONFIG_MLX90640_TRIGGER */
|
||||||
|
|
||||||
|
// data
|
||||||
|
int mlx90640_synch_frame(const struct device *dev);
|
||||||
|
int mlx90640_trigger_measurement(const struct device *dev);
|
||||||
|
int mlx90640_get_frame_data(const struct device *dev);
|
||||||
|
|
||||||
|
// process
|
||||||
|
float mlx90640_get_vdd(const struct device *dev);
|
||||||
|
float mlx90640_get_ta(const struct device *dev);
|
||||||
|
|
||||||
|
// void mlx90640_get_image(const struct device *dev);
|
||||||
|
// or!
|
||||||
|
void mlx90640_calculate_to(const struct device *dev, float emissivity, float tr);
|
||||||
|
|
||||||
|
// optional /
|
||||||
|
void mlx90640_bad_pixels_correction(const struct device *dev, int mode);
|
||||||
|
|
||||||
|
int mlx90640_set_adc_resolution(const struct device *dev, enum mlx90640_adc_resolution res);
|
||||||
|
enum mlx90640_adc_resolution mlx90640_get_adc_resolution(const struct device *dev);
|
||||||
|
|
||||||
|
int mlx90640_set_refresh_rate(const struct device *dev, enum mlx90640_refresh_rate res);
|
||||||
|
enum mlx90640_refresh_rate mlx90640_get_refresh_rate(const struct device *dev);
|
||||||
|
|
||||||
|
int mlx90640_set_reading_pattern(const struct device *dev, enum mlx90640_reading_pattern res);
|
||||||
|
enum mlx90640_reading_pattern mlx90640_get_reading_pattern(const struct device *dev);
|
||||||
|
|
||||||
|
#endif
|
213
drivers/sensor/mlx90640/mlx90640_trigger.c
Normal file
213
drivers/sensor/mlx90640/mlx90640_trigger.c
Normal file
|
@ -0,0 +1,213 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017-2019 Phytec Messtechnik GmbH
|
||||||
|
* Copyright (c) 2017 Benedict Ohl (Benedict-Ohl@web.de)
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <zephyr/device.h>
|
||||||
|
#include <zephyr/drivers/gpio.h>
|
||||||
|
#include <zephyr/drivers/i2c.h>
|
||||||
|
#include <zephyr/sys/util.h>
|
||||||
|
#include <zephyr/kernel.h>
|
||||||
|
#include <zephyr/drivers/sensor.h>
|
||||||
|
#include "amg88xx.h"
|
||||||
|
|
||||||
|
extern struct amg88xx_data amg88xx_driver;
|
||||||
|
|
||||||
|
#include <zephyr/logging/log.h>
|
||||||
|
LOG_MODULE_DECLARE(AMG88XX, CONFIG_SENSOR_LOG_LEVEL);
|
||||||
|
|
||||||
|
static inline void amg88xx_setup_int(const struct amg88xx_config *cfg,
|
||||||
|
bool enable)
|
||||||
|
{
|
||||||
|
unsigned int flags = enable
|
||||||
|
? GPIO_INT_EDGE_TO_ACTIVE
|
||||||
|
: GPIO_INT_DISABLE;
|
||||||
|
|
||||||
|
gpio_pin_interrupt_configure_dt(&cfg->int_gpio, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
int amg88xx_attr_set(const struct device *dev,
|
||||||
|
enum sensor_channel chan,
|
||||||
|
enum sensor_attribute attr,
|
||||||
|
const struct sensor_value *val)
|
||||||
|
{
|
||||||
|
const struct amg88xx_config *config = dev->config;
|
||||||
|
int16_t int_level = (val->val1 * 1000000 + val->val2) /
|
||||||
|
AMG88XX_TREG_LSB_SCALING;
|
||||||
|
uint8_t intl_reg;
|
||||||
|
uint8_t inth_reg;
|
||||||
|
|
||||||
|
if (!config->int_gpio.port) {
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chan != SENSOR_CHAN_AMBIENT_TEMP) {
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_DBG("set threshold to %d", int_level);
|
||||||
|
|
||||||
|
if (attr == SENSOR_ATTR_UPPER_THRESH) {
|
||||||
|
intl_reg = AMG88XX_INTHL;
|
||||||
|
inth_reg = AMG88XX_INTHH;
|
||||||
|
} else if (attr == SENSOR_ATTR_LOWER_THRESH) {
|
||||||
|
intl_reg = AMG88XX_INTLL;
|
||||||
|
inth_reg = AMG88XX_INTLH;
|
||||||
|
} else {
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i2c_reg_write_byte_dt(&config->i2c,
|
||||||
|
intl_reg, (uint8_t)int_level)) {
|
||||||
|
LOG_DBG("Failed to set INTxL attribute!");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i2c_reg_write_byte_dt(&config->i2c,
|
||||||
|
inth_reg, (uint8_t)(int_level >> 8))) {
|
||||||
|
LOG_DBG("Failed to set INTxH attribute!");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void amg88xx_gpio_callback(const struct device *dev,
|
||||||
|
struct gpio_callback *cb, uint32_t pins)
|
||||||
|
{
|
||||||
|
struct amg88xx_data *drv_data =
|
||||||
|
CONTAINER_OF(cb, struct amg88xx_data, gpio_cb);
|
||||||
|
const struct amg88xx_config *config = drv_data->dev->config;
|
||||||
|
|
||||||
|
amg88xx_setup_int(config, false);
|
||||||
|
|
||||||
|
#if defined(CONFIG_AMG88XX_TRIGGER_OWN_THREAD)
|
||||||
|
k_sem_give(&drv_data->gpio_sem);
|
||||||
|
#elif defined(CONFIG_AMG88XX_TRIGGER_GLOBAL_THREAD)
|
||||||
|
k_work_submit(&drv_data->work);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void amg88xx_thread_cb(const struct device *dev)
|
||||||
|
{
|
||||||
|
struct amg88xx_data *drv_data = dev->data;
|
||||||
|
const struct amg88xx_config *config = dev->config;
|
||||||
|
uint8_t status;
|
||||||
|
|
||||||
|
if (i2c_reg_read_byte_dt(&config->i2c,
|
||||||
|
AMG88XX_STAT, &status) < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (drv_data->drdy_handler != NULL) {
|
||||||
|
drv_data->drdy_handler(dev, drv_data->drdy_trigger);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (drv_data->th_handler != NULL) {
|
||||||
|
drv_data->th_handler(dev, drv_data->th_trigger);
|
||||||
|
}
|
||||||
|
|
||||||
|
amg88xx_setup_int(config, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_AMG88XX_TRIGGER_OWN_THREAD
|
||||||
|
static void amg88xx_thread(void *p1, void *p2, void *p3)
|
||||||
|
{
|
||||||
|
ARG_UNUSED(p2);
|
||||||
|
ARG_UNUSED(p3);
|
||||||
|
|
||||||
|
struct amg88xx_data *drv_data = p1;
|
||||||
|
|
||||||
|
while (42) {
|
||||||
|
k_sem_take(&drv_data->gpio_sem, K_FOREVER);
|
||||||
|
amg88xx_thread_cb(drv_data->dev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_AMG88XX_TRIGGER_GLOBAL_THREAD
|
||||||
|
static void amg88xx_work_cb(struct k_work *work)
|
||||||
|
{
|
||||||
|
struct amg88xx_data *drv_data =
|
||||||
|
CONTAINER_OF(work, struct amg88xx_data, work);
|
||||||
|
amg88xx_thread_cb(drv_data->dev);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int amg88xx_trigger_set(const struct device *dev,
|
||||||
|
const struct sensor_trigger *trig,
|
||||||
|
sensor_trigger_handler_t handler)
|
||||||
|
{
|
||||||
|
struct amg88xx_data *drv_data = dev->data;
|
||||||
|
const struct amg88xx_config *config = dev->config;
|
||||||
|
|
||||||
|
if (!config->int_gpio.port) {
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i2c_reg_write_byte_dt(&config->i2c,
|
||||||
|
AMG88XX_INTC, AMG88XX_INTC_DISABLED)) {
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
amg88xx_setup_int(config, false);
|
||||||
|
|
||||||
|
if (trig->type == SENSOR_TRIG_THRESHOLD) {
|
||||||
|
drv_data->th_handler = handler;
|
||||||
|
drv_data->th_trigger = trig;
|
||||||
|
} else {
|
||||||
|
LOG_ERR("Unsupported sensor trigger");
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
amg88xx_setup_int(config, true);
|
||||||
|
|
||||||
|
if (i2c_reg_write_byte_dt(&config->i2c,
|
||||||
|
AMG88XX_INTC, AMG88XX_INTC_ABS_MODE)) {
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int amg88xx_init_interrupt(const struct device *dev)
|
||||||
|
{
|
||||||
|
struct amg88xx_data *drv_data = dev->data;
|
||||||
|
const struct amg88xx_config *config = dev->config;
|
||||||
|
|
||||||
|
if (!gpio_is_ready_dt(&config->int_gpio)) {
|
||||||
|
LOG_ERR("%s: device %s is not ready", dev->name,
|
||||||
|
config->int_gpio.port->name);
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
gpio_pin_configure_dt(&config->int_gpio, GPIO_INPUT | config->int_gpio.dt_flags);
|
||||||
|
|
||||||
|
gpio_init_callback(&drv_data->gpio_cb,
|
||||||
|
amg88xx_gpio_callback,
|
||||||
|
BIT(config->int_gpio.pin));
|
||||||
|
|
||||||
|
if (gpio_add_callback(config->int_gpio.port, &drv_data->gpio_cb) < 0) {
|
||||||
|
LOG_DBG("Failed to set gpio callback!");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
drv_data->dev = dev;
|
||||||
|
|
||||||
|
#if defined(CONFIG_AMG88XX_TRIGGER_OWN_THREAD)
|
||||||
|
k_sem_init(&drv_data->gpio_sem, 0, K_SEM_MAX_LIMIT);
|
||||||
|
|
||||||
|
k_thread_create(&drv_data->thread, drv_data->thread_stack,
|
||||||
|
CONFIG_AMG88XX_THREAD_STACK_SIZE,
|
||||||
|
amg88xx_thread, drv_data,
|
||||||
|
NULL, NULL, K_PRIO_COOP(CONFIG_AMG88XX_THREAD_PRIORITY),
|
||||||
|
0, K_NO_WAIT);
|
||||||
|
#elif defined(CONFIG_AMG88XX_TRIGGER_GLOBAL_THREAD)
|
||||||
|
drv_data->work.handler = amg88xx_work_cb;
|
||||||
|
#endif
|
||||||
|
amg88xx_setup_int(config, true);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
48
dts/bindings/sensor/melexis,mlx90640.yaml
Normal file
48
dts/bindings/sensor/melexis,mlx90640.yaml
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
# Copyright (c) 2024 PM
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
description: Melexis MLX90640 32x24 (768) pixel infrared array sensor
|
||||||
|
|
||||||
|
compatible: "melexis,mlx90640"
|
||||||
|
|
||||||
|
include: [sensor-device.yaml, i2c-device.yaml]
|
||||||
|
|
||||||
|
properties:
|
||||||
|
refresh-rate:
|
||||||
|
type: int
|
||||||
|
default: 2
|
||||||
|
enum:
|
||||||
|
- 0 # 0.5HZ
|
||||||
|
- 1 # 1HZ
|
||||||
|
- 2 # 2HZ
|
||||||
|
- 3 # 4HZ
|
||||||
|
- 4 # 8HZ
|
||||||
|
- 5 # 16HZ
|
||||||
|
- 6 # 32HZ
|
||||||
|
- 7 # 64HZ
|
||||||
|
description:
|
||||||
|
Refresh rate of the sensor itself.
|
||||||
|
The I2C must be configured to keep up with the data flow.
|
||||||
|
This configures the rate for subfields, i.e. the full frame rate is half of this value.
|
||||||
|
|
||||||
|
adc-resolution:
|
||||||
|
type: int
|
||||||
|
default: 2
|
||||||
|
enum:
|
||||||
|
- 0 # 16BIT
|
||||||
|
- 1 # 17BIT
|
||||||
|
- 2 # 18BIT
|
||||||
|
- 3 # 19BIT
|
||||||
|
description:
|
||||||
|
ADC resolution.
|
||||||
|
|
||||||
|
reading-pattern:
|
||||||
|
type: int
|
||||||
|
default: 1
|
||||||
|
enum:
|
||||||
|
- 0 # CHESS
|
||||||
|
- 1 # INTERLEAVE
|
||||||
|
description:
|
||||||
|
Reading pattern.
|
||||||
|
The sensor can be read in either line-interleaved subfields (similar to a TV video)
|
||||||
|
or a pixel alternating "chess board" pattern.
|
Loading…
Reference in a new issue