drivers: sensor: STS4x Add driver
This adds support for Sensirion's STS4x temperature sensor. Signed-off-by: Jan Faeh <jan.faeh@sensirion.com>
This commit is contained in:
parent
5595f66851
commit
22945254ef
7 changed files with 216 additions and 0 deletions
|
@ -6,4 +6,5 @@ add_subdirectory_ifdef(CONFIG_SGP40 sgp40)
|
|||
add_subdirectory_ifdef(CONFIG_SHT3XD sht3xd)
|
||||
add_subdirectory_ifdef(CONFIG_SHT4X sht4x)
|
||||
add_subdirectory_ifdef(CONFIG_SHTCX shtcx)
|
||||
add_subdirectory_ifdef(CONFIG_STS4X sts4x)
|
||||
# zephyr-keep-sorted-stop
|
||||
|
|
|
@ -6,4 +6,5 @@ source "drivers/sensor/sensirion/sgp40/Kconfig"
|
|||
source "drivers/sensor/sensirion/sht3xd/Kconfig"
|
||||
source "drivers/sensor/sensirion/sht4x/Kconfig"
|
||||
source "drivers/sensor/sensirion/shtcx/Kconfig"
|
||||
source "drivers/sensor/sensirion/sts4x/Kconfig"
|
||||
# zephyr-keep-sorted-stop
|
||||
|
|
5
drivers/sensor/sensirion/sts4x/CMakeLists.txt
Normal file
5
drivers/sensor/sensirion/sts4x/CMakeLists.txt
Normal file
|
@ -0,0 +1,5 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
zephyr_library()
|
||||
|
||||
zephyr_library_sources(sts4x.c)
|
13
drivers/sensor/sensirion/sts4x/Kconfig
Normal file
13
drivers/sensor/sensirion/sts4x/Kconfig
Normal file
|
@ -0,0 +1,13 @@
|
|||
# Drivers configuration options for Sensirion STS4x
|
||||
|
||||
# Copyright (c) 2024 Jan Fäh
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config STS4X
|
||||
bool "STS4x Temperature Sensor"
|
||||
default y
|
||||
depends on DT_HAS_SENSIRION_STS4X_ENABLED
|
||||
select I2C
|
||||
select CRC
|
||||
help
|
||||
Enable driver for the Sensirion STS4x temperature sensors.
|
168
drivers/sensor/sensirion/sts4x/sts4x.c
Normal file
168
drivers/sensor/sensirion/sts4x/sts4x.c
Normal file
|
@ -0,0 +1,168 @@
|
|||
/*
|
||||
* Copyright (c) 2024 Jan Fäh
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT sensirion_sts4x
|
||||
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/drivers/sensor.h>
|
||||
#include <zephyr/drivers/i2c.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/sys/__assert.h>
|
||||
#include <zephyr/sys/byteorder.h>
|
||||
#include <zephyr/sys/crc.h>
|
||||
#include <zephyr/devicetree.h>
|
||||
|
||||
LOG_MODULE_REGISTER(STS4X, CONFIG_SENSOR_LOG_LEVEL);
|
||||
|
||||
#define STS4X_CMD_RESET 0x94
|
||||
|
||||
#define STS4X_RESET_TIME 1
|
||||
|
||||
#define STS4X_CRC_POLY 0x31
|
||||
#define STS4X_CRC_INIT 0xFF
|
||||
|
||||
#define STS4X_MAX_TEMP 175
|
||||
#define STS4X_MIN_TEMP -45
|
||||
|
||||
struct sts4x_config {
|
||||
struct i2c_dt_spec bus;
|
||||
uint8_t repeatability;
|
||||
};
|
||||
|
||||
struct sts4x_data {
|
||||
uint16_t temp_sample;
|
||||
};
|
||||
|
||||
static const uint8_t measure_cmds[3] = {0xE0, 0xF6, 0xFD};
|
||||
static const uint16_t measure_time_us[3] = {1600, 4500, 8300};
|
||||
|
||||
static int sts4x_crc_check(uint16_t value, uint8_t sensor_crc)
|
||||
{
|
||||
uint8_t buf[2];
|
||||
|
||||
sys_put_be16(value, buf);
|
||||
|
||||
uint8_t calculated_crc = crc8(buf, 2, STS4X_CRC_POLY, STS4X_CRC_INIT, false);
|
||||
|
||||
if (calculated_crc == sensor_crc) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static int sts4x_write_command(const struct device *dev, uint8_t cmd)
|
||||
{
|
||||
const struct sts4x_config *cfg = dev->config;
|
||||
uint8_t tx_buf = cmd;
|
||||
|
||||
return i2c_write_dt(&cfg->bus, &tx_buf, 1);
|
||||
}
|
||||
|
||||
static int sts4x_read_sample(const struct device *dev, uint16_t *temp_sample)
|
||||
{
|
||||
const struct sts4x_config *cfg = dev->config;
|
||||
uint8_t rx_buf[3];
|
||||
int ret;
|
||||
|
||||
ret = i2c_read_dt(&cfg->bus, rx_buf, sizeof(rx_buf));
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to read data.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
*temp_sample = sys_get_be16(rx_buf);
|
||||
ret = sts4x_crc_check(*temp_sample, rx_buf[2]);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Invalid CRC.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sts4x_sample_fetch(const struct device *dev, enum sensor_channel chan)
|
||||
{
|
||||
struct sts4x_data *data = dev->data;
|
||||
const struct sts4x_config *cfg = dev->config;
|
||||
int ret;
|
||||
|
||||
if (chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_AMBIENT_TEMP) {
|
||||
ret = sts4x_write_command(dev, measure_cmds[cfg->repeatability]);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to write measure command.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
k_usleep(measure_time_us[cfg->repeatability]);
|
||||
|
||||
ret = sts4x_read_sample(dev, &data->temp_sample);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to get temperature data.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
} else {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
}
|
||||
|
||||
static int sts4x_channel_get(const struct device *dev, enum sensor_channel chan,
|
||||
struct sensor_value *val)
|
||||
{
|
||||
const struct sts4x_data *data = dev->data;
|
||||
|
||||
if (chan == SENSOR_CHAN_AMBIENT_TEMP) {
|
||||
int64_t temp;
|
||||
|
||||
temp = data->temp_sample * STS4X_MAX_TEMP;
|
||||
val->val1 = (int32_t)(temp / 0xFFFF) + STS4X_MIN_TEMP;
|
||||
val->val2 = ((temp % 0xFFFF) * 1000000) / 0xFFFF;
|
||||
} else {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sts4x_init(const struct device *dev)
|
||||
{
|
||||
const struct sts4x_config *cfg = dev->config;
|
||||
int ret;
|
||||
|
||||
if (!i2c_is_ready_dt(&cfg->bus)) {
|
||||
LOG_ERR("Device not ready.");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = sts4x_write_command(dev, STS4X_CMD_RESET);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to reset the device.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
k_msleep(STS4X_RESET_TIME);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct sensor_driver_api sts4x_api_funcs = {
|
||||
.sample_fetch = sts4x_sample_fetch,
|
||||
.channel_get = sts4x_channel_get,
|
||||
};
|
||||
|
||||
#define STS4X_INIT(inst) \
|
||||
static struct sts4x_data sts4x_data_##inst; \
|
||||
static const struct sts4x_config sts4x_config_##inst = { \
|
||||
.bus = I2C_DT_SPEC_INST_GET(inst), \
|
||||
.repeatability = DT_INST_PROP(inst, repeatability), \
|
||||
}; \
|
||||
SENSOR_DEVICE_DT_INST_DEFINE(inst, sts4x_init, NULL, &sts4x_data_##inst, \
|
||||
&sts4x_config_##inst, POST_KERNEL, \
|
||||
CONFIG_SENSOR_INIT_PRIORITY, &sts4x_api_funcs);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(STS4X_INIT)
|
22
dts/bindings/sensor/sensirion,sts4x.yaml
Normal file
22
dts/bindings/sensor/sensirion,sts4x.yaml
Normal file
|
@ -0,0 +1,22 @@
|
|||
# Copyright (c) 2024, Jan Fäh
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
description: Sensirion STS4x temperature sensor
|
||||
|
||||
compatible: "sensirion,sts4x"
|
||||
|
||||
include: [sensor-device.yaml, i2c-device.yaml]
|
||||
|
||||
properties:
|
||||
repeatability:
|
||||
type: int
|
||||
required: true
|
||||
description: |
|
||||
Repeatability of the T Measurement
|
||||
0 = low -> 1.6 ms
|
||||
1 = med -> 4.5 ms
|
||||
2 = high -> 8.3 ms
|
||||
enum:
|
||||
- 0
|
||||
- 1
|
||||
- 2
|
|
@ -1125,3 +1125,9 @@ test_i2c_ilps22qs: ilps22qs@9c {
|
|||
avg = <LPS2xDF_DT_AVG_128_SAMPLES>;
|
||||
fs = <ILPS22QS_DT_FS_MODE_1_1260>;
|
||||
};
|
||||
|
||||
test_i2c_sts4x: sts4x@9d {
|
||||
compatible = "sensirion,sts4x";
|
||||
reg = <0x99>;
|
||||
repeatability = <2>;
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue