drivers: sensor: icp101xx: Add icp101xx support
Use official TDK Invensense driver for icp101xx sensor in tdk_hal module. Signed-off-by: Remi Buisson <remi.buisson@tdk.com>
This commit is contained in:
committed by
Benjamin Cabé
parent
fe796a7e22
commit
a4d863163b
@@ -5,7 +5,7 @@
|
||||
add_subdirectory_ifdef(CONFIG_ICM42605 icm42605)
|
||||
add_subdirectory_ifdef(CONFIG_ICM42670 icm42670)
|
||||
add_subdirectory_ifdef(CONFIG_ICM42688 icm42688)
|
||||
add_subdirectory_ifdef(CONFIG_ICP10125 icp10125)
|
||||
add_subdirectory_ifdef(CONFIG_ICP101XX icp101xx)
|
||||
add_subdirectory_ifdef(CONFIG_MPU6050 mpu6050)
|
||||
add_subdirectory_ifdef(CONFIG_MPU9250 mpu9250)
|
||||
# zephyr-keep-sorted-stop
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
source "drivers/sensor/tdk/icm42605/Kconfig"
|
||||
source "drivers/sensor/tdk/icm42670/Kconfig"
|
||||
source "drivers/sensor/tdk/icm42688/Kconfig"
|
||||
source "drivers/sensor/tdk/icp10125/Kconfig"
|
||||
source "drivers/sensor/tdk/icp101xx/Kconfig"
|
||||
source "drivers/sensor/tdk/mpu6050/Kconfig"
|
||||
source "drivers/sensor/tdk/mpu9250/Kconfig"
|
||||
# zephyr-keep-sorted-stop
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
# Copyright (c) 2022 Mizuki Agawa <agawa.mizuki@fujitsu.com>
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
zephyr_library()
|
||||
|
||||
zephyr_library_sources(icp10125.c)
|
||||
@@ -1,23 +0,0 @@
|
||||
# ICP10125 barometric pressure/temperature sensor configuration options
|
||||
|
||||
# Copyright (c) 2022 Mizuki Agawa <agawa.mizuki@fujitsu.com>
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
menuconfig ICP10125
|
||||
bool "ICP10125 Barometric Pressure & Temperature Sensor"
|
||||
default y
|
||||
depends on DT_HAS_INVENSENSE_ICP10125_ENABLED
|
||||
select I2C
|
||||
help
|
||||
Enable driver for ICP10125 barometric pressure/temperature sensor.
|
||||
|
||||
if ICP10125
|
||||
|
||||
config ICP10125_CHECK_CRC
|
||||
bool "Check the CRC of measument data"
|
||||
imply CRC
|
||||
default y
|
||||
help
|
||||
Verify the CRC checksum that appended to the measurement data.
|
||||
|
||||
endif # ICP10125
|
||||
@@ -1,321 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2022 Mizuki Agawa <agawa.mizuki@fujitsu.com>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT invensense_icp10125
|
||||
|
||||
#include <zephyr/drivers/i2c.h>
|
||||
#include <zephyr/drivers/sensor.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/sys/byteorder.h>
|
||||
|
||||
#ifdef CONFIG_ICP10125_CHECK_CRC
|
||||
#include <zephyr/sys/crc.h>
|
||||
#endif /* CONFIG_ICP10125_CHECK_CRC */
|
||||
|
||||
LOG_MODULE_REGISTER(ICP10125, CONFIG_SENSOR_LOG_LEVEL);
|
||||
|
||||
#define CRC_POLY 0x31
|
||||
#define SENSOR_DATA_SIZE 2
|
||||
|
||||
#define AMBIENT_TEMP_DATA_NUM 1
|
||||
#define PRESS_DATA_NUM 2
|
||||
#define PRESS_AND_AMBIENT_TEMP_DATA_NUM (AMBIENT_TEMP_DATA_NUM + PRESS_DATA_NUM)
|
||||
|
||||
enum {
|
||||
LOW_POWER,
|
||||
NORMAL,
|
||||
LOW_NOISE,
|
||||
ULTRA_LOW_NOISE,
|
||||
NUM_MEASURE_MODE
|
||||
};
|
||||
|
||||
struct icp10125_data {
|
||||
uint16_t raw_ambient_temp;
|
||||
uint32_t raw_press;
|
||||
float sensor_constants[4];
|
||||
};
|
||||
|
||||
struct icp10125_dev_config {
|
||||
struct i2c_dt_spec i2c;
|
||||
uint8_t ambient_temp_mode;
|
||||
uint8_t press_mode;
|
||||
};
|
||||
|
||||
struct icp10125_cmd {
|
||||
uint8_t data[2];
|
||||
};
|
||||
|
||||
struct icp10125_sensor_data {
|
||||
uint8_t data[2];
|
||||
uint8_t crc;
|
||||
};
|
||||
|
||||
struct icp10125_otp_read_setup {
|
||||
struct icp10125_cmd cmd;
|
||||
uint8_t data[3];
|
||||
} __packed __aligned(1);
|
||||
|
||||
/* ambient temperature measurement command for each mode.
|
||||
* (Section 5.2 MEASUREMENT COMMANDS in the Datasheet)
|
||||
*/
|
||||
static const struct icp10125_cmd ambient_temp_measurement_cmds[] = {
|
||||
{{0x60, 0x9C}}, {{0x68, 0x25}}, {{0x70, 0xDF}}, {{0x78, 0x66}}
|
||||
};
|
||||
|
||||
/* pressure measurement command for each mode.
|
||||
* (Section 5.2 MEASUREMENT COMMANDS in the Datasheet)
|
||||
*/
|
||||
static const struct icp10125_cmd press_measurement_cmds[] = {
|
||||
{{0x40, 0x1A}}, {{0x48, 0xA3}}, {{0x50, 0x59}}, {{0x59, 0xE0}}
|
||||
};
|
||||
|
||||
/* Request preparation for OTP data read. It should issue before data read request.
|
||||
* (Section 5.2 MEASUREMENT COMMANDS in the Datasheet)
|
||||
*/
|
||||
static const struct icp10125_otp_read_setup otp_read_setup = {
|
||||
.cmd = {{0xC5, 0x95}},
|
||||
.data = {0x00, 0x66, 0x9C}
|
||||
};
|
||||
|
||||
/* OTP data read request.
|
||||
* After issue this command 2byte x 4 sensor constant value can readable.
|
||||
*/
|
||||
static const struct icp10125_cmd otp_read_request_cmd = {{0xC7, 0xF7}};
|
||||
|
||||
/* The max conversion time for each modes.
|
||||
* (Section 2.2 OPERATION MODES in the Datasheet)
|
||||
*/
|
||||
static const uint32_t conv_time_max[] = {1800, 6300, 23800, 94500};
|
||||
|
||||
/* The typical conversion time for each modes.
|
||||
* (Section 2.2 OPERATION MODES in the Datasheet)
|
||||
*/
|
||||
static const uint32_t conv_time_typ[] = {1600, 5600, 20800, 83200};
|
||||
|
||||
/* The Datasheet has no mention of the constants and formulas.
|
||||
* Instead, it shows only how to use it in the sample code.
|
||||
* Since there is no detailed description in the ICP10125 product manual,
|
||||
* the calculation of the pressure implements is the same as shown in
|
||||
* the 5.11 SAMPLE CODE: EXAMPLE C SYNTAX
|
||||
*/
|
||||
|
||||
static void icp10125_calculate_conversion_constants(const float *p_LUT, float *A, float *B,
|
||||
float *C)
|
||||
{
|
||||
const float p_Pa[] = {45000.0, 80000.0, 105000.0};
|
||||
|
||||
*C = (p_LUT[0] * p_LUT[1] * (p_Pa[0] - p_Pa[1]) +
|
||||
p_LUT[1] * p_LUT[2] * (p_Pa[1] - p_Pa[2]) +
|
||||
p_LUT[2] * p_LUT[0] * (p_Pa[2] - p_Pa[0])) /
|
||||
(p_LUT[2] * (p_Pa[0] - p_Pa[1]) + p_LUT[0] * (p_Pa[1] - p_Pa[2]) +
|
||||
p_LUT[1] * (p_Pa[2] - p_Pa[0]));
|
||||
*A = (p_Pa[0] * p_LUT[0] - p_Pa[1] * p_LUT[1] - (p_Pa[1] - p_Pa[0]) * (*C)) /
|
||||
(p_LUT[0] - p_LUT[1]);
|
||||
*B = (p_Pa[0] - (*A)) * (p_LUT[0] + (*C));
|
||||
}
|
||||
|
||||
static float icp10125_calc_calibrated_ambient_temp(const struct icp10125_data *data)
|
||||
{
|
||||
return -45.f + 175.f / 65536.f * data->raw_ambient_temp;
|
||||
}
|
||||
|
||||
static float icp10125_calc_calibrated_press(const struct icp10125_data *data)
|
||||
{
|
||||
const float quadr_factor = 1 / 16777216.0;
|
||||
const float offst_factor = 2048.0;
|
||||
const float LUT_lower = 3.5 * (1 << 20);
|
||||
const float LUT_upper = 11.5 * (1 << 20);
|
||||
float t;
|
||||
float in[3];
|
||||
float A, B, C;
|
||||
|
||||
t = data->raw_ambient_temp - 32768.f;
|
||||
in[0] = LUT_lower + (data->sensor_constants[0] * t * t) * quadr_factor;
|
||||
in[1] = offst_factor * data->sensor_constants[3] +
|
||||
(data->sensor_constants[1] * t * t) * quadr_factor;
|
||||
in[2] = LUT_upper + (data->sensor_constants[2] * t * t) * quadr_factor;
|
||||
icp10125_calculate_conversion_constants(in, &A, &B, &C);
|
||||
|
||||
return A + B / (C + data->raw_press);
|
||||
}
|
||||
|
||||
/* End of porting the 5.11 SAMPLE CODE: EXAMPLE C SYNTAX */
|
||||
|
||||
static int icp10125_read_otp(const struct device *dev)
|
||||
{
|
||||
struct icp10125_data *data = dev->data;
|
||||
struct icp10125_sensor_data sensor_data;
|
||||
|
||||
const struct icp10125_dev_config *cfg = dev->config;
|
||||
int rc = 0;
|
||||
|
||||
rc = i2c_write_dt(&cfg->i2c, (uint8_t *)&otp_read_setup, sizeof(otp_read_setup));
|
||||
if (rc < 0) {
|
||||
LOG_ERR("Failed to write otp_read_setup.\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(data->sensor_constants); i++) {
|
||||
rc = i2c_write_dt(&cfg->i2c, (uint8_t *)&otp_read_request_cmd,
|
||||
sizeof(otp_read_request_cmd));
|
||||
if (rc < 0) {
|
||||
LOG_ERR("Failed to write otp_read_request.\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = i2c_read_dt(&cfg->i2c, (uint8_t *)&sensor_data, sizeof(sensor_data));
|
||||
if (rc < 0) {
|
||||
LOG_ERR("Failed to read otp_read_request.\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
data->sensor_constants[i] = sys_get_be16(sensor_data.data);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ICP10125_CHECK_CRC
|
||||
static int icp10125_check_crc(const uint8_t *data, const size_t len)
|
||||
{
|
||||
/* Details of CRC are described in Chapter 5 Section 8 of the product
|
||||
* specifications.
|
||||
*/
|
||||
return crc8(data, len, CRC_POLY, 0xFF, false);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int icp10125_measure(const struct i2c_dt_spec *i2c, const struct icp10125_cmd *cmds,
|
||||
const uint8_t mode, struct icp10125_sensor_data *sensor_data,
|
||||
const size_t data_num)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
rc = i2c_write_dt(i2c, (uint8_t *)&cmds[mode], sizeof(cmds[mode]));
|
||||
if (rc < 0) {
|
||||
LOG_ERR("Failed to start measurement.\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Wait for the sensor to become readable.
|
||||
* First wait for the typical time and then read.
|
||||
* If that fails, wait until the time to surely became readable.
|
||||
*/
|
||||
k_sleep(K_USEC(conv_time_typ[mode]));
|
||||
if (i2c_read_dt(i2c, (uint8_t *)sensor_data, sizeof(sensor_data[0]) * data_num) < 0) {
|
||||
k_sleep(K_USEC(conv_time_max[mode] - conv_time_typ[mode]));
|
||||
rc = i2c_read_dt(i2c, (uint8_t *)sensor_data, sizeof(sensor_data[0]) * data_num);
|
||||
if (rc < 0) {
|
||||
LOG_ERR("Failed to read measurement.\n");
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ICP10125_CHECK_CRC
|
||||
/* Calculate CRC from Chapter 5 Section 8 of ICP10125 Product manuals. */
|
||||
for (size_t i = 0; i < data_num; i++) {
|
||||
if (!icp10125_check_crc(sensor_data[i].data, SENSOR_DATA_SIZE)) {
|
||||
LOG_ERR("Sensor data has invalid CRC.\n");
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_ICP10125_CHECK_CRC */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int icp10125_sample_fetch(const struct device *dev, const enum sensor_channel chan)
|
||||
{
|
||||
struct icp10125_data *data = dev->data;
|
||||
const struct icp10125_dev_config *cfg = dev->config;
|
||||
uint8_t endian_conversion[3];
|
||||
struct icp10125_sensor_data sensor_data[PRESS_AND_AMBIENT_TEMP_DATA_NUM] = {0};
|
||||
int rc = 0;
|
||||
|
||||
if (!(chan == SENSOR_CHAN_AMBIENT_TEMP || chan == SENSOR_CHAN_PRESS ||
|
||||
chan == SENSOR_CHAN_ALL)) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (chan == SENSOR_CHAN_AMBIENT_TEMP) {
|
||||
rc = icp10125_measure(&cfg->i2c, ambient_temp_measurement_cmds,
|
||||
cfg->ambient_temp_mode, sensor_data, AMBIENT_TEMP_DATA_NUM);
|
||||
if (rc < 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
data->raw_ambient_temp = sys_get_be16(sensor_data[0].data);
|
||||
} else {
|
||||
rc = icp10125_measure(&cfg->i2c, press_measurement_cmds, cfg->press_mode,
|
||||
sensor_data, PRESS_AND_AMBIENT_TEMP_DATA_NUM);
|
||||
if (rc < 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
endian_conversion[0] = sensor_data[0].data[0];
|
||||
endian_conversion[1] = sensor_data[0].data[1];
|
||||
endian_conversion[2] = sensor_data[1].data[0];
|
||||
data->raw_press = sys_get_be24(endian_conversion);
|
||||
data->raw_ambient_temp = sys_get_be16(sensor_data[2].data);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void icp10125_convert_press_value(struct icp10125_data *data, struct sensor_value *val)
|
||||
{
|
||||
sensor_value_from_float(val, icp10125_calc_calibrated_press(data) / 1000.f);
|
||||
}
|
||||
|
||||
static void icp10125_convert_ambient_temp_value(struct icp10125_data *data,
|
||||
struct sensor_value *val)
|
||||
{
|
||||
sensor_value_from_float(val, icp10125_calc_calibrated_ambient_temp(data));
|
||||
}
|
||||
|
||||
static int icp10125_channel_get(const struct device *dev, enum sensor_channel chan,
|
||||
struct sensor_value *val)
|
||||
{
|
||||
struct icp10125_data *data = dev->data;
|
||||
|
||||
if (chan == SENSOR_CHAN_AMBIENT_TEMP) {
|
||||
icp10125_convert_ambient_temp_value(data, val);
|
||||
} else if (chan == SENSOR_CHAN_PRESS) {
|
||||
icp10125_convert_press_value(data, val);
|
||||
} else {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int icp10125_init(const struct device *dev)
|
||||
{
|
||||
int rc = icp10125_read_otp(dev);
|
||||
|
||||
if (rc < 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static DEVICE_API(sensor, icp10125_api_funcs) = {
|
||||
.sample_fetch = icp10125_sample_fetch,
|
||||
.channel_get = icp10125_channel_get,
|
||||
};
|
||||
|
||||
#define ICP10125_DEFINE(inst) \
|
||||
static struct icp10125_data icp10125_drv_##inst; \
|
||||
static const struct icp10125_dev_config icp10125_config_##inst = { \
|
||||
.i2c = I2C_DT_SPEC_INST_GET(inst), \
|
||||
.ambient_temp_mode = DT_INST_ENUM_IDX(inst, temperature_measurement_mode), \
|
||||
.press_mode = DT_INST_ENUM_IDX(inst, pressure_measurement_mode)}; \
|
||||
DEVICE_DT_INST_DEFINE(inst, icp10125_init, NULL, &icp10125_drv_##inst, \
|
||||
&icp10125_config_##inst, POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, \
|
||||
&icp10125_api_funcs);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(ICP10125_DEFINE)
|
||||
8
drivers/sensor/tdk/icp101xx/CMakeLists.txt
Normal file
8
drivers/sensor/tdk/icp101xx/CMakeLists.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
zephyr_library()
|
||||
|
||||
zephyr_compile_definitions_ifdef(CONFIG_CPU_HAS_FPU ICP101XX_DRV_USE_FLOATS)
|
||||
|
||||
zephyr_library_sources(icp101xx_drv.c)
|
||||
zephyr_library_include_directories(.)
|
||||
13
drivers/sensor/tdk/icp101xx/Kconfig
Normal file
13
drivers/sensor/tdk/icp101xx/Kconfig
Normal file
@@ -0,0 +1,13 @@
|
||||
# Copyright (c) 2024 TDK Invensense
|
||||
|
||||
# ICP101xx High Accuracy, Low Power, Barometric Pressure and Temperature Sensor option
|
||||
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
config ICP101XX
|
||||
bool "ICP101XX Barometric Pressure and Temperature Sensor"
|
||||
default y
|
||||
depends on DT_HAS_INVENSENSE_ICP101XX_ENABLED
|
||||
select I2C
|
||||
select USE_EMD_ICP101XX
|
||||
help
|
||||
Enable driver for ICP101XX barometric pressure/temperature sensors.
|
||||
259
drivers/sensor/tdk/icp101xx/icp101xx_drv.c
Normal file
259
drivers/sensor/tdk/icp101xx/icp101xx_drv.c
Normal file
@@ -0,0 +1,259 @@
|
||||
/*
|
||||
* Copyright (c) 2024 TDK Invensense
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT invensense_icp101xx
|
||||
|
||||
#include <math.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/drivers/sensor.h>
|
||||
#include <zephyr/init.h>
|
||||
#include <zephyr/drivers/gpio.h>
|
||||
#include <zephyr/pm/device.h>
|
||||
#include <zephyr/sys/byteorder.h>
|
||||
#include <zephyr/sys/__assert.h>
|
||||
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
#include "icp101xx_drv.h"
|
||||
|
||||
LOG_MODULE_REGISTER(ICP101XX, CONFIG_SENSOR_LOG_LEVEL);
|
||||
|
||||
#if DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 0
|
||||
#error "ICP101XX driver enabled without any compatible device in devicetree"
|
||||
#endif
|
||||
|
||||
inline void inv_icp101xx_sleep_us(int us)
|
||||
{
|
||||
k_sleep(K_USEC(us));
|
||||
}
|
||||
|
||||
static int inv_io_hal_read_reg(void *ctx, uint8_t reg, uint8_t *rbuffer, uint32_t rlen)
|
||||
{
|
||||
struct device *dev = (struct device *)ctx;
|
||||
const struct icp101xx_config *cfg = (const struct icp101xx_config *)dev->config;
|
||||
|
||||
return i2c_read_dt(&cfg->i2c, (uint8_t *)rbuffer, rlen);
|
||||
}
|
||||
|
||||
static int inv_io_hal_write_reg(void *ctx, uint8_t reg, const uint8_t *wbuffer, uint32_t wlen)
|
||||
{
|
||||
struct device *dev = (struct device *)ctx;
|
||||
const struct icp101xx_config *cfg = (const struct icp101xx_config *)dev->config;
|
||||
|
||||
return i2c_write_dt(&cfg->i2c, (uint8_t *)wbuffer, wlen);
|
||||
}
|
||||
|
||||
static uint8_t get_timeout_ms(enum icp101xx_meas mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case ICP101XX_MEAS_LOW_POWER_T_FIRST:
|
||||
case ICP101XX_MEAS_LOW_POWER_P_FIRST:
|
||||
return 2;
|
||||
case ICP101XX_MEAS_NORMAL_T_FIRST:
|
||||
case ICP101XX_MEAS_NORMAL_P_FIRST:
|
||||
return 7;
|
||||
case ICP101XX_MEAS_LOW_NOISE_T_FIRST:
|
||||
case ICP101XX_MEAS_LOW_NOISE_P_FIRST:
|
||||
return 24;
|
||||
default:
|
||||
case ICP101XX_MEAS_ULTRA_LOW_NOISE_T_FIRST:
|
||||
case ICP101XX_MEAS_ULTRA_LOW_NOISE_P_FIRST:
|
||||
return 95;
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t get_conversion_ms(enum icp101xx_meas mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case ICP101XX_MEAS_LOW_POWER_T_FIRST:
|
||||
case ICP101XX_MEAS_LOW_POWER_P_FIRST:
|
||||
return 1;
|
||||
case ICP101XX_MEAS_NORMAL_T_FIRST:
|
||||
case ICP101XX_MEAS_NORMAL_P_FIRST:
|
||||
return 5;
|
||||
case ICP101XX_MEAS_LOW_NOISE_T_FIRST:
|
||||
case ICP101XX_MEAS_LOW_NOISE_P_FIRST:
|
||||
return 20;
|
||||
default:
|
||||
case ICP101XX_MEAS_ULTRA_LOW_NOISE_T_FIRST:
|
||||
case ICP101XX_MEAS_ULTRA_LOW_NOISE_P_FIRST:
|
||||
return 80;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ICP101XX_DRV_USE_FLOATS
|
||||
#define ATMOSPHERICAL_PRESSURE_KPA ((float)101.325)
|
||||
#define TO_KELVIN(temp_C) ((float)273.15 + temp_C)
|
||||
/*
|
||||
* Constant in altitude formula:
|
||||
* M*g/R = (0,0289644 * 9,80665 / 8,31432)
|
||||
* with M the molar mass of air.
|
||||
* with g the gravitational force acceleration.
|
||||
* with R the universal gaz constant.
|
||||
*/
|
||||
#define HEIGHT_TO_PRESSURE_COEFF ((float)0.03424)
|
||||
|
||||
/*
|
||||
* Constant in altitude formula:
|
||||
* R / (M*g) = 8,31432 / (0,0289644 * 9,80665)
|
||||
* with M the molar mass of air.
|
||||
* with g the gravitational force acceleration.
|
||||
* with R the universal gaz constant.
|
||||
*/
|
||||
#define PRESSURE_TO_HEIGHT_COEFF ((float)29.27127)
|
||||
/*
|
||||
* Constant for altitude formula:
|
||||
* logarithm of pressure at 0m
|
||||
* ln(101.325)
|
||||
*/
|
||||
#define LOG_ATMOSPHERICAL_PRESSURE ((float)4.61833)
|
||||
|
||||
float convertToHeight(float pressure_kp, float temperature_C)
|
||||
{
|
||||
return PRESSURE_TO_HEIGHT_COEFF * TO_KELVIN(temperature_C) *
|
||||
(LOG_ATMOSPHERICAL_PRESSURE - logf(pressure_kp));
|
||||
}
|
||||
#endif
|
||||
|
||||
static int icp101xx_attr_set(const struct device *dev, enum sensor_channel chan,
|
||||
enum sensor_attribute attr, const struct sensor_value *val)
|
||||
{
|
||||
int err = 0;
|
||||
struct icp101xx_data *data = (struct icp101xx_data *)dev->data;
|
||||
|
||||
__ASSERT_NO_MSG(val != NULL);
|
||||
if (chan == SENSOR_CHAN_PRESS) {
|
||||
if (attr == SENSOR_ATTR_CONFIGURATION) {
|
||||
if ((val->val1 >= ICP101XX_MEAS_LOW_POWER_T_FIRST) &&
|
||||
(val->val1 <= ICP101XX_MEAS_ULTRA_LOW_NOISE_P_FIRST)) {
|
||||
data->icp_device.measurement_mode = val->val1;
|
||||
} else {
|
||||
LOG_ERR("Not supported ATTR value");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
} else {
|
||||
LOG_ERR("Not supported ATTR");
|
||||
return -EINVAL;
|
||||
}
|
||||
};
|
||||
return err;
|
||||
}
|
||||
|
||||
static int icp101xx_sample_fetch(const struct device *dev, const enum sensor_channel chan)
|
||||
{
|
||||
struct icp101xx_data *data = (struct icp101xx_data *)dev->data;
|
||||
int rc = 0;
|
||||
uint64_t timeout;
|
||||
|
||||
if (!((chan == SENSOR_CHAN_AMBIENT_TEMP) || (chan == SENSOR_CHAN_PRESS) ||
|
||||
(chan == SENSOR_CHAN_ALTITUDE) || (chan == SENSOR_CHAN_ALL))) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
rc = inv_icp101xx_enable_sensor(&data->icp_device, 1);
|
||||
/* Compute timeout for the measure */
|
||||
timeout = k_uptime_get() + get_timeout_ms(data->icp_device.measurement_mode);
|
||||
/* Initial sleep waiting the sensor proceeds with the measure */
|
||||
k_sleep(K_MSEC(get_conversion_ms(data->icp_device.measurement_mode)));
|
||||
do {
|
||||
k_sleep(K_USEC(200));
|
||||
rc = inv_icp101xx_get_data(&data->icp_device, &(data->raw_pressure),
|
||||
&(data->raw_temperature), &(data->pressure),
|
||||
&(data->temperature));
|
||||
} while ((rc != 0) && (k_uptime_get() <= timeout));
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int icp101xx_channel_get(const struct device *dev, enum sensor_channel chan,
|
||||
struct sensor_value *val)
|
||||
{
|
||||
|
||||
struct icp101xx_data *data = (struct icp101xx_data *)dev->data;
|
||||
|
||||
val->val1 = 0;
|
||||
val->val2 = 0;
|
||||
|
||||
if (!((chan == SENSOR_CHAN_AMBIENT_TEMP) || (chan == SENSOR_CHAN_PRESS) ||
|
||||
(chan == SENSOR_CHAN_ALTITUDE))) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
/* Zephyr expects kPa while ICP101xx returns Pa */
|
||||
if (chan == SENSOR_CHAN_AMBIENT_TEMP) {
|
||||
#ifdef ICP101XX_DRV_USE_FLOATS
|
||||
sensor_value_from_float(val, data->temperature);
|
||||
#else
|
||||
val->val1 = data->temperature >> 4;
|
||||
val->val2 = (data->temperature % 16) * 1000000 / 16;
|
||||
#endif
|
||||
} else if (chan == SENSOR_CHAN_PRESS) {
|
||||
#ifdef ICP101XX_DRV_USE_FLOATS
|
||||
sensor_value_from_float(val, data->pressure / 1000);
|
||||
#else
|
||||
val->val1 = data->pressure / 1000;
|
||||
val->val2 = (data->pressure % 1000) * 1000;
|
||||
#endif
|
||||
#ifdef ICP101XX_DRV_USE_FLOATS
|
||||
} else if (chan == SENSOR_CHAN_ALTITUDE) {
|
||||
float altitude = convertToHeight(data->pressure / 1000, data->temperature);
|
||||
|
||||
sensor_value_from_float(val, altitude);
|
||||
#endif
|
||||
} else {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int icp101xx_init(const struct device *dev)
|
||||
{
|
||||
int rc = 0;
|
||||
struct icp101xx_data *data = (struct icp101xx_data *)dev->data;
|
||||
const struct icp101xx_config *cfg = (const struct icp101xx_config *)dev->config;
|
||||
|
||||
memset(&(data->icp_device), 0, sizeof(data->icp_device));
|
||||
|
||||
data->icp_device.serif.context = (void *)dev;
|
||||
data->icp_device.serif.read_reg = inv_io_hal_read_reg;
|
||||
data->icp_device.serif.write_reg = inv_io_hal_write_reg;
|
||||
/* maximum number of bytes allowed per serial read */
|
||||
data->icp_device.serif.max_read = 2048;
|
||||
/* maximum number of bytes allowed per serial write */
|
||||
data->icp_device.serif.max_write = 2048;
|
||||
|
||||
rc = inv_icp101xx_soft_reset(&data->icp_device);
|
||||
if (rc != 0) {
|
||||
LOG_ERR("Soft reset error %d", rc);
|
||||
return rc;
|
||||
}
|
||||
inv_icp101xx_init(&data->icp_device);
|
||||
if (rc != 0) {
|
||||
LOG_ERR("Init error %d", rc);
|
||||
return rc;
|
||||
}
|
||||
data->icp_device.measurement_mode = cfg->mode;
|
||||
|
||||
/* successful init, return 0 */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static DEVICE_API(sensor, icp101xx_api_funcs) = {
|
||||
.sample_fetch = icp101xx_sample_fetch,
|
||||
.channel_get = icp101xx_channel_get,
|
||||
.attr_set = icp101xx_attr_set,
|
||||
};
|
||||
|
||||
#define ICP101XX_DEFINE(inst) \
|
||||
static struct icp101xx_data icp101xx_drv_##inst; \
|
||||
static const struct icp101xx_config icp101xx_config_##inst = { \
|
||||
.i2c = I2C_DT_SPEC_INST_GET(inst), \
|
||||
.mode = DT_INST_ENUM_IDX(inst, mode), \
|
||||
}; \
|
||||
SENSOR_DEVICE_DT_INST_DEFINE(inst, icp101xx_init, NULL, &icp101xx_drv_##inst, \
|
||||
&icp101xx_config_##inst, POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, \
|
||||
&icp101xx_api_funcs);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(ICP101XX_DEFINE)
|
||||
38
drivers/sensor/tdk/icp101xx/icp101xx_drv.h
Normal file
38
drivers/sensor/tdk/icp101xx/icp101xx_drv.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2023 TDK Invensense
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_DRIVERS_SENSOR_ICP101XXX_ICP101XXX_H_
|
||||
#define ZEPHYR_DRIVERS_SENSOR_ICP101XXX_ICP101XXX_H_
|
||||
|
||||
#include <zephyr/types.h>
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/devicetree.h>
|
||||
#include <zephyr/drivers/i2c.h>
|
||||
#include <zephyr/drivers/sensor.h>
|
||||
#include "Icp101xx.h"
|
||||
#include "Icp101xxSerif.h"
|
||||
|
||||
#define ICP101XX_BUS_I2C DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c)
|
||||
|
||||
struct icp101xx_data {
|
||||
int raw_pressure;
|
||||
int raw_temperature;
|
||||
#ifdef ICP101XX_DRV_USE_FLOATS
|
||||
float pressure;
|
||||
float temperature;
|
||||
#else
|
||||
int32_t pressure;
|
||||
int32_t temperature;
|
||||
#endif
|
||||
inv_icp101xx_t icp_device;
|
||||
};
|
||||
|
||||
struct icp101xx_config {
|
||||
struct i2c_dt_spec i2c;
|
||||
int mode;
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user