drivers: sensor: SCD4x Add driver
This adds support for Sensirion's SCD4x co2 sensor. Signed-off-by: Jan Faeh <jan.faeh@sensirion.com>
This commit is contained in:
parent
428db04fd5
commit
2efc8598e3
10 changed files with 1143 additions and 0 deletions
|
@ -2,6 +2,7 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# zephyr-keep-sorted-start
|
||||
add_subdirectory_ifdef(CONFIG_SCD4X scd4x)
|
||||
add_subdirectory_ifdef(CONFIG_SGP40 sgp40)
|
||||
add_subdirectory_ifdef(CONFIG_SHT3XD sht3xd)
|
||||
add_subdirectory_ifdef(CONFIG_SHT4X sht4x)
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# zephyr-keep-sorted-start
|
||||
source "drivers/sensor/sensirion/scd4x/Kconfig"
|
||||
source "drivers/sensor/sensirion/sgp40/Kconfig"
|
||||
source "drivers/sensor/sensirion/sht3xd/Kconfig"
|
||||
source "drivers/sensor/sensirion/sht4x/Kconfig"
|
||||
|
|
5
drivers/sensor/sensirion/scd4x/CMakeLists.txt
Normal file
5
drivers/sensor/sensirion/scd4x/CMakeLists.txt
Normal file
|
@ -0,0 +1,5 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
zephyr_library()
|
||||
|
||||
zephyr_library_sources(scd4x.c)
|
13
drivers/sensor/sensirion/scd4x/Kconfig
Normal file
13
drivers/sensor/sensirion/scd4x/Kconfig
Normal file
|
@ -0,0 +1,13 @@
|
|||
# Drivers configuration options for Sensirion SCD4x
|
||||
|
||||
# Copyright (c) 2024 Jan Fäh
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config SCD4X
|
||||
bool "SCD4x Carbon Dioxide Sensor"
|
||||
default y
|
||||
depends on DT_HAS_SENSIRION_SCD41_ENABLED || DT_HAS_SENSIRION_SCD40_ENABLED
|
||||
select I2C
|
||||
select CRC
|
||||
help
|
||||
Enable driver for the Sensirion SCD4x carbon dioxide sensors.
|
908
drivers/sensor/sensirion/scd4x/scd4x.c
Normal file
908
drivers/sensor/sensirion/scd4x/scd4x.c
Normal file
|
@ -0,0 +1,908 @@
|
|||
/*
|
||||
* Copyright (c) 2024 Jan Fäh
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#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>
|
||||
|
||||
#include <zephyr/drivers/sensor/scd4x.h>
|
||||
#include "scd4x.h"
|
||||
|
||||
LOG_MODULE_REGISTER(SCD4X, CONFIG_SENSOR_LOG_LEVEL);
|
||||
|
||||
static uint8_t scd4x_calc_crc(uint16_t value)
|
||||
{
|
||||
uint8_t buf[2];
|
||||
|
||||
sys_put_be16(value, buf);
|
||||
|
||||
return crc8(buf, 2, SCD4X_CRC_POLY, SCD4X_CRC_INIT, false);
|
||||
}
|
||||
|
||||
static int scd4x_write_command(const struct device *dev, uint8_t cmd)
|
||||
{
|
||||
const struct scd4x_config *cfg = dev->config;
|
||||
uint8_t tx_buf[2];
|
||||
int ret;
|
||||
|
||||
sys_put_be16(scd4x_cmds[cmd].cmd, tx_buf);
|
||||
|
||||
ret = i2c_write_dt(&cfg->bus, tx_buf, sizeof(tx_buf));
|
||||
|
||||
if (scd4x_cmds[cmd].cmd_duration_ms) {
|
||||
k_msleep(scd4x_cmds[cmd].cmd_duration_ms);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int scd4x_read_reg(const struct device *dev, uint8_t *rx_buf, uint8_t rx_buf_size)
|
||||
{
|
||||
const struct scd4x_config *cfg = dev->config;
|
||||
int ret;
|
||||
|
||||
ret = i2c_read_dt(&cfg->bus, rx_buf, rx_buf_size);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to read i2c data.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < (rx_buf_size / 3); i++) {
|
||||
ret = scd4x_calc_crc(sys_get_be16(&rx_buf[i * 3]));
|
||||
if (ret != rx_buf[(i * 3) + 2]) {
|
||||
LOG_ERR("Invalid CRC.");
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int scd4x_write_reg(const struct device *dev, uint8_t cmd, uint16_t *data, uint8_t data_size)
|
||||
{
|
||||
const struct scd4x_config *cfg = dev->config;
|
||||
int ret;
|
||||
uint8_t tx_buf[((data_size * 3) + 2)];
|
||||
|
||||
sys_put_be16(scd4x_cmds[cmd].cmd, tx_buf);
|
||||
|
||||
uint8_t tx_buf_pos = 2;
|
||||
|
||||
for (uint8_t i = 0; i < data_size; i++) {
|
||||
sys_put_be16(data[i], &tx_buf[tx_buf_pos]);
|
||||
tx_buf_pos += 2;
|
||||
tx_buf[tx_buf_pos++] = scd4x_calc_crc(data[i]);
|
||||
}
|
||||
|
||||
ret = i2c_write_dt(&cfg->bus, tx_buf, sizeof(tx_buf));
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to write i2c data.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (scd4x_cmds[cmd].cmd_duration_ms) {
|
||||
k_msleep(scd4x_cmds[cmd].cmd_duration_ms);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int scd4x_data_ready(const struct device *dev, bool *is_data_ready)
|
||||
{
|
||||
uint8_t rx_data[3];
|
||||
int ret;
|
||||
*is_data_ready = false;
|
||||
|
||||
ret = scd4x_write_command(dev, SCD4X_CMD_GET_DATA_READY_STATUS);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to write get_data_ready_status command.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = scd4x_read_reg(dev, rx_data, sizeof(rx_data));
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to read get_data_ready_status register.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint16_t word = sys_get_be16(rx_data);
|
||||
/* Least significant 11 bits = 0 --> data not ready */
|
||||
if ((word & 0x07FF) > 0) {
|
||||
*is_data_ready = true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int scd4x_read_sample(const struct device *dev)
|
||||
{
|
||||
struct scd4x_data *data = dev->data;
|
||||
uint8_t rx_data[9];
|
||||
int ret;
|
||||
|
||||
ret = scd4x_write_command(dev, SCD4X_CMD_READ_MEASUREMENT);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to write read_measurement command.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = scd4x_read_reg(dev, rx_data, sizeof(rx_data));
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to read read_measurement register.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
data->co2_sample = sys_get_be16(rx_data);
|
||||
data->temp_sample = sys_get_be16(&rx_data[3]);
|
||||
data->humi_sample = sys_get_be16(&rx_data[6]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int scd4x_setup_measurement(const struct device *dev)
|
||||
{
|
||||
const struct scd4x_config *cfg = dev->config;
|
||||
int ret;
|
||||
|
||||
switch ((enum scd4x_mode_t)cfg->mode) {
|
||||
case SCD4X_MODE_NORMAL:
|
||||
ret = scd4x_write_command(dev, SCD4X_CMD_START_PERIODIC_MEASUREMENT);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to write start_periodic_measurement command.");
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
case SCD4X_MODE_LOW_POWER:
|
||||
ret = scd4x_write_command(dev, SCD4X_CMD_LOW_POWER_PERIODIC_MEASUREMENT);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to write start_low_power_periodic_measurement command.");
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
case SCD4X_MODE_SINGLE_SHOT:
|
||||
ret = scd4x_write_command(dev, SCD4X_CMD_POWER_DOWN);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to write power_down command.");
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int scd4x_set_idle_mode(const struct device *dev)
|
||||
{
|
||||
const struct scd4x_config *cfg = dev->config;
|
||||
int ret;
|
||||
|
||||
if (cfg->mode == SCD4X_MODE_SINGLE_SHOT) {
|
||||
/*send wake up command twice because of an expected nack return in power down mode*/
|
||||
scd4x_write_command(dev, SCD4X_CMD_WAKE_UP);
|
||||
ret = scd4x_write_command(dev, SCD4X_CMD_WAKE_UP);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed write wake_up command.");
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
ret = scd4x_write_command(dev, SCD4X_CMD_STOP_PERIODIC_MEASUREMENT);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to write stop_periodic_measurement command.");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int scd4x_set_temperature_offset(const struct device *dev, const struct sensor_value *val)
|
||||
{
|
||||
int ret;
|
||||
/*Calculation from Datasheet*/
|
||||
uint16_t offset_temp =
|
||||
(float)(val->val1 + (val->val2 / 1000000.0)) * 0xFFFF / SCD4X_MAX_TEMP;
|
||||
|
||||
ret = scd4x_write_reg(dev, SCD4X_CMD_SET_TEMPERATURE_OFFSET, &offset_temp, 1);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to write set_temperature_offset register.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int scd4x_set_sensor_altitude(const struct device *dev, const struct sensor_value *val)
|
||||
{
|
||||
int ret;
|
||||
uint16_t altitude = val->val1;
|
||||
|
||||
ret = scd4x_write_reg(dev, SCD4X_CMD_SET_SENSOR_ALTITUDE, &altitude, 1);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to write set_sensor_altitude register.");
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int scd4x_set_ambient_pressure(const struct device *dev, const struct sensor_value *val)
|
||||
{
|
||||
int ret;
|
||||
|
||||
uint16_t ambient_pressure = val->val1;
|
||||
|
||||
ret = scd4x_write_reg(dev, SCD4X_CMD_SET_AMBIENT_PRESSURE, &ambient_pressure, 1);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to write set_ambient_pressure register.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int scd4x_set_automatic_calib_enable(const struct device *dev,
|
||||
const struct sensor_value *val)
|
||||
{
|
||||
int ret;
|
||||
uint16_t automatic_calib_enable = val->val1;
|
||||
|
||||
ret = scd4x_write_reg(dev, SCD4X_CMD_SET_AUTOMATIC_CALIB_ENABLE, &automatic_calib_enable,
|
||||
1);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to write set_automatic_calibration_enable register.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int scd4x_set_self_calib_initial_period(const struct device *dev,
|
||||
const struct sensor_value *val)
|
||||
{
|
||||
int ret;
|
||||
uint16_t initial_period = val->val1;
|
||||
|
||||
ret = scd4x_write_reg(dev, SCD4X_CMD_SET_SELF_CALIB_INITIAL_PERIOD, &initial_period, 1);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to write set_automatic_self_calibration_initial_period register.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int scd4x_set_self_calib_standard_period(const struct device *dev,
|
||||
const struct sensor_value *val)
|
||||
{
|
||||
int ret;
|
||||
uint16_t standard_period = val->val1;
|
||||
|
||||
ret = scd4x_write_reg(dev, SCD4X_CMD_SET_SELF_CALIB_STANDARD_PERIOD, &standard_period, 1);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to write set_automatic_self_calibration_standard_period register.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int scd4x_get_temperature_offset(const struct device *dev, struct sensor_value *val)
|
||||
{
|
||||
int ret;
|
||||
uint8_t rx_buf[3];
|
||||
|
||||
ret = scd4x_write_command(dev, SCD4X_CMD_GET_TEMPERATURE_OFFSET);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to write get_temperature_offset command.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = scd4x_read_reg(dev, rx_buf, sizeof(rx_buf));
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to read get_temperature_offset register.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
int32_t temp;
|
||||
|
||||
/*Calculation from Datasheet*/
|
||||
temp = sys_get_be16(rx_buf) * SCD4X_MAX_TEMP;
|
||||
val->val1 = (int32_t)(temp / 0xFFFF);
|
||||
val->val2 = ((temp % 0xFFFF) * 1000000) / 0xFFFF;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int scd4x_get_sensor_altitude(const struct device *dev, struct sensor_value *val)
|
||||
{
|
||||
int ret;
|
||||
uint8_t rx_buf[3];
|
||||
|
||||
ret = scd4x_write_command(dev, SCD4X_CMD_GET_SENSOR_ALTITUDE);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to write get_sensor_altitude command.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = scd4x_read_reg(dev, rx_buf, sizeof(rx_buf));
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to read get_sensor_altitude register.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
val->val1 = sys_get_be16(rx_buf);
|
||||
val->val2 = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int scd4x_get_ambient_pressure(const struct device *dev, struct sensor_value *val)
|
||||
{
|
||||
int ret;
|
||||
uint8_t rx_buf[3];
|
||||
|
||||
ret = scd4x_write_command(dev, SCD4X_CMD_GET_AMBIENT_PRESSURE);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to write get_ambient_pressure command.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = scd4x_read_reg(dev, rx_buf, sizeof(rx_buf));
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to read get_ambient_pressure register.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
val->val1 = sys_get_be16(rx_buf);
|
||||
val->val2 = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int scd4x_get_automatic_calib_enable(const struct device *dev, struct sensor_value *val)
|
||||
{
|
||||
int ret;
|
||||
uint8_t rx_buf[3];
|
||||
|
||||
ret = scd4x_write_command(dev, SCD4X_CMD_GET_AUTOMATIC_CALIB_ENABLE);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to write get_automatic_calibration_enable command.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = scd4x_read_reg(dev, rx_buf, sizeof(rx_buf));
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to read get_automatic_calibration_enabled register.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
val->val1 = sys_get_be16(rx_buf);
|
||||
val->val2 = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int scd4x_get_self_calib_initial_period(const struct device *dev, struct sensor_value *val)
|
||||
{
|
||||
int ret;
|
||||
uint8_t rx_buf[3];
|
||||
|
||||
ret = scd4x_write_command(dev, SCD4X_CMD_GET_SELF_CALIB_INITIAL_PERIOD);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to write get_automati_calibration_initial_period command.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = scd4x_read_reg(dev, rx_buf, sizeof(rx_buf));
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to read get_automatic_calibration_initial_period register.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
val->val1 = sys_get_be16(rx_buf);
|
||||
val->val2 = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int scd4x_get_self_calib_standard_period(const struct device *dev, struct sensor_value *val)
|
||||
{
|
||||
int ret;
|
||||
uint8_t rx_buf[3];
|
||||
|
||||
ret = scd4x_write_command(dev, SCD4X_CMD_GET_SELF_CALIB_STANDARD_PERIOD);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to write get_automatic_self_calibration_standard_period command.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = scd4x_read_reg(dev, rx_buf, sizeof(rx_buf));
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to read get_automatic_self_calibration_standard_period register.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
val->val1 = sys_get_be16(rx_buf);
|
||||
val->val2 = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int scd4x_forced_recalibration(const struct device *dev, uint16_t target_concentration,
|
||||
uint16_t *frc_correction)
|
||||
{
|
||||
uint8_t rx_buf[3];
|
||||
int ret;
|
||||
|
||||
ret = scd4x_set_idle_mode(dev);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to set idle mode.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = scd4x_write_reg(dev, SCD4X_CMD_FORCED_RECALIB, &target_concentration, 1);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to write perform_forced_recalibration register.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = scd4x_read_reg(dev, rx_buf, sizeof(rx_buf));
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to read perform_forced_recalibration register.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
*frc_correction = sys_get_be16(rx_buf);
|
||||
|
||||
/*from datasheet*/
|
||||
if (*frc_correction == 0xFFFF) {
|
||||
LOG_ERR("FRC failed. Returned 0xFFFF.");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
*frc_correction -= 0x8000;
|
||||
|
||||
ret = scd4x_setup_measurement(dev);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to setup measurement.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int scd4x_self_test(const struct device *dev)
|
||||
{
|
||||
int ret;
|
||||
uint8_t rx_buf[3];
|
||||
|
||||
ret = scd4x_set_idle_mode(dev);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to set idle mode.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = scd4x_write_command(dev, SCD4X_CMD_SELF_TEST);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to write perform_self_test command.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = scd4x_read_reg(dev, rx_buf, sizeof(rx_buf));
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to read perform_self_test register.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint16_t is_malfunction = sys_get_be16(rx_buf);
|
||||
|
||||
if (is_malfunction) {
|
||||
LOG_ERR("malfunction detected.");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
ret = scd4x_setup_measurement(dev);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to setup measurement.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int scd4x_persist_settings(const struct device *dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = scd4x_set_idle_mode(dev);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to set idle mode.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = scd4x_write_command(dev, SCD4X_CMD_PERSIST_SETTINGS);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to write persist_settings command.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = scd4x_setup_measurement(dev);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to setup measurement.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int scd4x_factory_reset(const struct device *dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = scd4x_set_idle_mode(dev);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to set idle mode.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = scd4x_write_command(dev, SCD4X_CMD_FACTORY_RESET);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to write perfom_factory_reset command.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = scd4x_setup_measurement(dev);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to setup measurement.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int scd4x_sample_fetch(const struct device *dev, enum sensor_channel chan)
|
||||
{
|
||||
const struct scd4x_config *cfg = dev->config;
|
||||
bool is_data_ready;
|
||||
int ret;
|
||||
|
||||
if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_AMBIENT_TEMP &&
|
||||
chan != SENSOR_CHAN_HUMIDITY && chan != SENSOR_CHAN_CO2) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (cfg->mode == SCD4X_MODE_SINGLE_SHOT) {
|
||||
ret = scd4x_set_idle_mode(dev);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to set idle mode.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (chan == SENSOR_CHAN_HUMIDITY || chan == SENSOR_CHAN_AMBIENT_TEMP) {
|
||||
ret = scd4x_write_command(dev, SCD4X_CMD_MEASURE_SINGLE_SHOT_RHT);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to write measure_single_shot_rht_only command.");
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
ret = scd4x_write_command(dev, SCD4X_CMD_MEASURE_SINGLE_SHOT);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to write measure_single_shot command.");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ret = scd4x_data_ready(dev, &is_data_ready);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to check data ready.");
|
||||
return ret;
|
||||
}
|
||||
if (!is_data_ready) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
ret = scd4x_read_sample(dev);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to get sample data.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (cfg->mode == SCD4X_MODE_SINGLE_SHOT) {
|
||||
ret = scd4x_setup_measurement(dev);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to setup measurement.");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int scd4x_channel_get(const struct device *dev, enum sensor_channel chan,
|
||||
struct sensor_value *val)
|
||||
{
|
||||
const struct scd4x_data *data = dev->data;
|
||||
int32_t tmp_val;
|
||||
|
||||
switch ((enum sensor_channel)chan) {
|
||||
case SENSOR_CHAN_AMBIENT_TEMP:
|
||||
/*Calculation from Datasheet*/
|
||||
tmp_val = data->temp_sample * SCD4X_MAX_TEMP;
|
||||
val->val1 = (int32_t)(tmp_val / 0xFFFF) + SCD4X_MIN_TEMP;
|
||||
val->val2 = ((tmp_val % 0xFFFF) * 1000000) / 0xFFFF;
|
||||
break;
|
||||
case SENSOR_CHAN_HUMIDITY:
|
||||
/*Calculation from Datasheet*/
|
||||
tmp_val = data->humi_sample * 100;
|
||||
val->val1 = (int32_t)(tmp_val / 0xFFFF);
|
||||
val->val2 = ((tmp_val % 0xFFFF) * 1000000) / 0xFFFF;
|
||||
break;
|
||||
case SENSOR_CHAN_CO2:
|
||||
val->val1 = data->co2_sample;
|
||||
val->val2 = 0;
|
||||
break;
|
||||
default:
|
||||
return -ENOTSUP;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int scd4x_attr_set(const struct device *dev, enum sensor_channel chan, enum sensor_attribute attr,
|
||||
const struct sensor_value *val)
|
||||
{
|
||||
const struct scd4x_config *cfg = dev->config;
|
||||
int ret;
|
||||
|
||||
if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_AMBIENT_TEMP &&
|
||||
chan != SENSOR_CHAN_HUMIDITY && chan != SENSOR_CHAN_CO2) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if ((enum sensor_attribute_scd4x)attr != SENSOR_ATTR_SCD4X_AMBIENT_PRESSURE) {
|
||||
ret = scd4x_set_idle_mode(dev);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to set idle mode.");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (val->val1 < 0 || val->val2 < 0) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch ((enum sensor_attribute_scd4x)attr) {
|
||||
case SENSOR_ATTR_SCD4X_TEMPERATURE_OFFSET:
|
||||
if (val->val1 > SCD4X_TEMPERATURE_OFFSET_IDX_MAX) {
|
||||
return -EINVAL;
|
||||
}
|
||||
ret = scd4x_set_temperature_offset(dev, val);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to set temperature offset.");
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
case SENSOR_ATTR_SCD4X_SENSOR_ALTITUDE:
|
||||
if (val->val1 > SCD4X_SENSOR_ALTITUDE_IDX_MAX) {
|
||||
return -EINVAL;
|
||||
}
|
||||
ret = scd4x_set_sensor_altitude(dev, val);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to set sensor altitude.");
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
case SENSOR_ATTR_SCD4X_AMBIENT_PRESSURE:
|
||||
if (val->val1 > SCD4X_AMBIENT_PRESSURE_IDX_MAX || val->val1 < 700) {
|
||||
return -EINVAL;
|
||||
}
|
||||
ret = scd4x_set_ambient_pressure(dev, val);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to set ambient pressure.");
|
||||
return ret;
|
||||
}
|
||||
/* return 0 to not call scd4x_start_measurement */
|
||||
return 0;
|
||||
case SENSOR_ATTR_SCD4X_AUTOMATIC_CALIB_ENABLE:
|
||||
if (val->val1 > SCD4X_BOOL_IDX_MAX) {
|
||||
return -EINVAL;
|
||||
}
|
||||
ret = scd4x_set_automatic_calib_enable(dev, val);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to set automatic calib enable.");
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
case SENSOR_ATTR_SCD4X_SELF_CALIB_INITIAL_PERIOD:
|
||||
if (val->val1 % 4) {
|
||||
return -EINVAL;
|
||||
}
|
||||
if (cfg->model == SCD4X_MODEL_SCD40) {
|
||||
LOG_ERR("SELF_CALIB_INITIAL_PERIOD not available for SCD40.");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
ret = scd4x_set_self_calib_initial_period(dev, val);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to set self calib initial period.");
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
case SENSOR_ATTR_SCD4X_SELF_CALIB_STANDARD_PERIOD:
|
||||
if (val->val1 % 4) {
|
||||
return -EINVAL;
|
||||
}
|
||||
if (cfg->model == SCD4X_MODEL_SCD40) {
|
||||
LOG_ERR("SELF_CALIB_STANDARD_PERIOD not available for SCD40.");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
ret = scd4x_set_self_calib_standard_period(dev, val);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to set self calib standard period.");
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
ret = scd4x_setup_measurement(dev);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to setup measurement.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int scd4x_attr_get(const struct device *dev, enum sensor_channel chan,
|
||||
enum sensor_attribute attr, struct sensor_value *val)
|
||||
{
|
||||
const struct scd4x_config *cfg = dev->config;
|
||||
int ret;
|
||||
|
||||
if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_AMBIENT_TEMP &&
|
||||
chan != SENSOR_CHAN_HUMIDITY && chan != SENSOR_CHAN_CO2) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if ((enum sensor_attribute_scd4x)attr != SENSOR_ATTR_SCD4X_AMBIENT_PRESSURE ||
|
||||
cfg->mode == SCD4X_MODE_SINGLE_SHOT) {
|
||||
ret = scd4x_set_idle_mode(dev);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to set idle mode.");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
switch ((enum sensor_attribute_scd4x)attr) {
|
||||
case SENSOR_ATTR_SCD4X_TEMPERATURE_OFFSET:
|
||||
ret = scd4x_get_temperature_offset(dev, val);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to get temperature offset.");
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
case SENSOR_ATTR_SCD4X_SENSOR_ALTITUDE:
|
||||
ret = scd4x_get_sensor_altitude(dev, val);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to get sensor altitude.");
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
case SENSOR_ATTR_SCD4X_AMBIENT_PRESSURE:
|
||||
ret = scd4x_get_ambient_pressure(dev, val);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to get ambient pressure.");
|
||||
return ret;
|
||||
}
|
||||
/* return 0 to not call scd4x_setup_measurement */
|
||||
return 0;
|
||||
case SENSOR_ATTR_SCD4X_AUTOMATIC_CALIB_ENABLE:
|
||||
ret = scd4x_get_automatic_calib_enable(dev, val);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to get automatic calib.");
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
case SENSOR_ATTR_SCD4X_SELF_CALIB_INITIAL_PERIOD:
|
||||
if (cfg->model == SCD4X_MODEL_SCD40) {
|
||||
LOG_ERR("SELF_CALIB_INITIAL_PERIOD not available for SCD40.");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
ret = scd4x_get_self_calib_initial_period(dev, val);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to set get self calib initial period.");
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
case SENSOR_ATTR_SCD4X_SELF_CALIB_STANDARD_PERIOD:
|
||||
if (cfg->model == SCD4X_MODEL_SCD40) {
|
||||
LOG_ERR("SELF_CALIB_STANDARD_PERIOD not available for SCD40.");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
ret = scd4x_get_self_calib_standard_period(dev, val);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to set get self calib standard period.");
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
ret = scd4x_setup_measurement(dev);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to setup measurement.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int scd4x_init(const struct device *dev)
|
||||
{
|
||||
const struct scd4x_config *cfg = dev->config;
|
||||
int ret;
|
||||
|
||||
if (!i2c_is_ready_dt(&cfg->bus)) {
|
||||
LOG_ERR("Device not ready.");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = scd4x_write_command(dev, SCD4X_CMD_STOP_PERIODIC_MEASUREMENT);
|
||||
if (ret < 0) {
|
||||
/*send wake up command twice because of an expected nack return in power down mode*/
|
||||
scd4x_write_command(dev, SCD4X_CMD_WAKE_UP);
|
||||
ret = scd4x_write_command(dev, SCD4X_CMD_WAKE_UP);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to put the device in idle mode.");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = scd4x_write_command(dev, SCD4X_CMD_REINIT);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to reset the device.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = scd4x_setup_measurement(dev);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to setup measurement.");
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct sensor_driver_api scd4x_api_funcs = {
|
||||
.sample_fetch = scd4x_sample_fetch,
|
||||
.channel_get = scd4x_channel_get,
|
||||
.attr_set = scd4x_attr_set,
|
||||
.attr_get = scd4x_attr_get,
|
||||
};
|
||||
|
||||
#define SCD4X_INIT(inst, scd4x_model) \
|
||||
static struct scd4x_data scd4x_data_##inst; \
|
||||
static const struct scd4x_config scd4x_config_##inst = { \
|
||||
.bus = I2C_DT_SPEC_INST_GET(inst), \
|
||||
.model = scd4x_model, \
|
||||
.mode = DT_INST_ENUM_IDX_OR(inst, mode, SCD4X_MODE_NORMAL), \
|
||||
}; \
|
||||
SENSOR_DEVICE_DT_INST_DEFINE(inst, scd4x_init, NULL, &scd4x_data_##inst, \
|
||||
&scd4x_config_##inst, POST_KERNEL, \
|
||||
CONFIG_SENSOR_INIT_PRIORITY, &scd4x_api_funcs);
|
||||
|
||||
#define DT_DRV_COMPAT sensirion_scd40
|
||||
DT_INST_FOREACH_STATUS_OKAY_VARGS(SCD4X_INIT, SCD4X_MODEL_SCD40)
|
||||
#undef DT_DRV_COMPAT
|
||||
|
||||
#define DT_DRV_COMPAT sensirion_scd41
|
||||
DT_INST_FOREACH_STATUS_OKAY_VARGS(SCD4X_INIT, SCD4X_MODEL_SCD41)
|
||||
#undef DT_DRV_COMPAT
|
88
drivers/sensor/sensirion/scd4x/scd4x.h
Normal file
88
drivers/sensor/sensirion/scd4x/scd4x.h
Normal file
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* Copyright (c) 2024 Jan Fäh
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_DRIVERS_SENSOR_SCD4X_SCD4X_H_
|
||||
#define ZEPHYR_DRIVERS_SENSOR_SCD4X_SCD4X_H_
|
||||
|
||||
#include <zephyr/device.h>
|
||||
|
||||
#define SCD4X_CMD_REINIT 0
|
||||
#define SCD4X_CMD_START_PERIODIC_MEASUREMENT 1
|
||||
#define SCD4X_CMD_STOP_PERIODIC_MEASUREMENT 2
|
||||
#define SCD4X_CMD_READ_MEASUREMENT 3
|
||||
#define SCD4X_CMD_SET_TEMPERATURE_OFFSET 4
|
||||
#define SCD4X_CMD_GET_TEMPERATURE_OFFSET 5
|
||||
#define SCD4X_CMD_SET_SENSOR_ALTITUDE 6
|
||||
#define SCD4X_CMD_GET_SENSOR_ALTITUDE 7
|
||||
#define SCD4X_CMD_SET_AMBIENT_PRESSURE 8
|
||||
#define SCD4X_CMD_GET_AMBIENT_PRESSURE 9
|
||||
#define SCD4X_CMD_FORCED_RECALIB 10
|
||||
#define SCD4X_CMD_SET_AUTOMATIC_CALIB_ENABLE 11
|
||||
#define SCD4X_CMD_GET_AUTOMATIC_CALIB_ENABLE 12
|
||||
#define SCD4X_CMD_LOW_POWER_PERIODIC_MEASUREMENT 13
|
||||
#define SCD4X_CMD_GET_DATA_READY_STATUS 14
|
||||
#define SCD4X_CMD_PERSIST_SETTINGS 15
|
||||
#define SCD4X_CMD_SELF_TEST 16
|
||||
#define SCD4X_CMD_FACTORY_RESET 17
|
||||
#define SCD4X_CMD_MEASURE_SINGLE_SHOT 18
|
||||
#define SCD4X_CMD_MEASURE_SINGLE_SHOT_RHT 19
|
||||
#define SCD4X_CMD_POWER_DOWN 10
|
||||
#define SCD4X_CMD_WAKE_UP 21
|
||||
#define SCD4X_CMD_SET_SELF_CALIB_INITIAL_PERIOD 22
|
||||
#define SCD4X_CMD_GET_SELF_CALIB_INITIAL_PERIOD 23
|
||||
#define SCD4X_CMD_SET_SELF_CALIB_STANDARD_PERIOD 24
|
||||
#define SCD4X_CMD_GET_SELF_CALIB_STANDARD_PERIOD 25
|
||||
|
||||
#define SCD4X_CRC_POLY 0x31
|
||||
#define SCD4X_CRC_INIT 0xFF
|
||||
|
||||
#define SCD4X_STARTUP_TIME_MS 30
|
||||
|
||||
#define SCD4X_TEMPERATURE_OFFSET_IDX_MAX 20
|
||||
#define SCD4X_SENSOR_ALTITUDE_IDX_MAX 3000
|
||||
#define SCD4X_AMBIENT_PRESSURE_IDX_MAX 1200
|
||||
#define SCD4X_BOOL_IDX_MAX 1
|
||||
|
||||
#define SCD4X_MAX_TEMP 175
|
||||
#define SCD4X_MIN_TEMP -45
|
||||
|
||||
enum scd4x_model_t {
|
||||
SCD4X_MODEL_SCD40,
|
||||
SCD4X_MODEL_SCD41,
|
||||
};
|
||||
|
||||
enum scd4x_mode_t {
|
||||
SCD4X_MODE_NORMAL,
|
||||
SCD4X_MODE_LOW_POWER,
|
||||
SCD4X_MODE_SINGLE_SHOT,
|
||||
};
|
||||
|
||||
struct scd4x_config {
|
||||
struct i2c_dt_spec bus;
|
||||
enum scd4x_model_t model;
|
||||
enum scd4x_mode_t mode;
|
||||
};
|
||||
|
||||
struct scd4x_data {
|
||||
uint16_t temp_sample;
|
||||
uint16_t humi_sample;
|
||||
uint16_t co2_sample;
|
||||
};
|
||||
|
||||
struct cmds_t {
|
||||
uint16_t cmd;
|
||||
uint16_t cmd_duration_ms;
|
||||
};
|
||||
|
||||
const struct cmds_t scd4x_cmds[] = {
|
||||
{0x3646, 30}, {0x21B1, 0}, {0x3F86, 500}, {0xEC05, 1}, {0x241D, 1}, {0x2318, 1},
|
||||
{0x2427, 1}, {0x2322, 1}, {0xE000, 1}, {0xE000, 1}, {0x362F, 400}, {0x2416, 1},
|
||||
{0x2313, 1}, {0x21AC, 0}, {0xE4B8, 1}, {0x3615, 800}, {0x3639, 10000}, {0x3632, 1200},
|
||||
{0x219D, 5000}, {0x2196, 50}, {0x36E0, 1}, {0x36F6, 30}, {0x2445, 1}, {0x2340, 1},
|
||||
{0x244E, 1}, {0x234B, 1},
|
||||
};
|
||||
|
||||
#endif /* ZEPHYR_DRIVERS_SENSOR_SCD4X_SCD4X_H_ */
|
8
dts/bindings/sensor/sensirion,scd40.yaml
Normal file
8
dts/bindings/sensor/sensirion,scd40.yaml
Normal file
|
@ -0,0 +1,8 @@
|
|||
# Copyright (c) 2024, Jan Fäh
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
description: Sensirion SCD4x temperature sensor
|
||||
|
||||
compatible: "sensirion,scd40"
|
||||
|
||||
include: [sensor-device.yaml, i2c-device.yaml]
|
21
dts/bindings/sensor/sensirion,scd41.yaml
Normal file
21
dts/bindings/sensor/sensirion,scd41.yaml
Normal file
|
@ -0,0 +1,21 @@
|
|||
# Copyright (c) 2024, Jan Fäh
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
description: Sensirion SCD4x temperature sensor
|
||||
|
||||
compatible: "sensirion,scd41"
|
||||
|
||||
include: [sensor-device.yaml, i2c-device.yaml]
|
||||
|
||||
properties:
|
||||
mode:
|
||||
type: int
|
||||
required: true
|
||||
description: |
|
||||
- 0: Normal periodic measurement. Default interval of 5sec
|
||||
- 1: Low power periodic measurement. Interval of 30sec
|
||||
- 2: Singleshot measurement for low power usage.
|
||||
enum:
|
||||
- 0
|
||||
- 1
|
||||
- 2
|
92
include/zephyr/drivers/sensor/scd4x.h
Normal file
92
include/zephyr/drivers/sensor/scd4x.h
Normal file
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* Copyright (c) 2024 Jan Fäh
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_INCLUDE_DRIVERS_SENSOR_SCD4X_H_
|
||||
#define ZEPHYR_INCLUDE_DRIVERS_SENSOR_SCD4X_H_
|
||||
|
||||
#include <zephyr/drivers/sensor.h>
|
||||
|
||||
enum sensor_attribute_scd4x {
|
||||
/* Offset temperature: Toffset_actual = Tscd4x – Treference + Toffset_previous
|
||||
* 0 - 20°C
|
||||
*/
|
||||
SENSOR_ATTR_SCD4X_TEMPERATURE_OFFSET = SENSOR_ATTR_PRIV_START,
|
||||
/* Altidude of the sensor;
|
||||
* 0 - 3000m
|
||||
*/
|
||||
SENSOR_ATTR_SCD4X_SENSOR_ALTITUDE,
|
||||
/* Ambient pressure in hPa
|
||||
* 700 - 1200hPa
|
||||
*/
|
||||
SENSOR_ATTR_SCD4X_AMBIENT_PRESSURE,
|
||||
/* Set the current state (enabled: 1 / disabled: 0).
|
||||
* Default: enabled.
|
||||
*/
|
||||
SENSOR_ATTR_SCD4X_AUTOMATIC_CALIB_ENABLE,
|
||||
/* Set the initial period for automatic self calibration correction in hours. Allowed values
|
||||
* are integer multiples of 4 hours.
|
||||
* Default: 44
|
||||
*/
|
||||
SENSOR_ATTR_SCD4X_SELF_CALIB_INITIAL_PERIOD,
|
||||
/* Set the standard period for automatic self calibration correction in hours. Allowed
|
||||
* values are integer multiples of 4 hours. Default: 156
|
||||
*/
|
||||
SENSOR_ATTR_SCD4X_SELF_CALIB_STANDARD_PERIOD,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Performs a forced recalibration.
|
||||
*
|
||||
* Operate the SCD4x in the operation mode for at least 3 minutes in an environment with a
|
||||
* homogeneous and constant CO2 concentration. Otherwise the recalibratioin will fail. The sensor
|
||||
* must be operated at the voltage desired for the application when performing the FRC sequence.
|
||||
*
|
||||
* @param dev Pointer to the sensor device
|
||||
* @param target_concentration Reference CO2 concentration.
|
||||
* @param frc_correction Previous differences from the target concentration
|
||||
*
|
||||
* @return 0 if successful, negative errno code if failure.
|
||||
*/
|
||||
int scd4x_forced_recalibration(const struct device *dev, uint16_t target_concentration,
|
||||
uint16_t *frc_correction);
|
||||
|
||||
/**
|
||||
* @brief Performs a self test.
|
||||
*
|
||||
* The self_test command can be used as an end-of-line test to check the sensor functionality
|
||||
*
|
||||
* @param dev Pointer to the sensor device
|
||||
*
|
||||
* @return 0 if successful, negative errno code if failure.
|
||||
*/
|
||||
int scd4x_self_test(const struct device *dev);
|
||||
|
||||
/**
|
||||
* @brief Performs a self test.
|
||||
*
|
||||
* The persist_settings command can be used to save the actual configuration. This command
|
||||
* should only be sent when persistence is required and if actual changes to the configuration have
|
||||
* been made. The EEPROM is guaranteed to withstand at least 2000 write cycles
|
||||
*
|
||||
* @param dev Pointer to the sensor device
|
||||
*
|
||||
* @return 0 if successful, negative errno code if failure.
|
||||
*/
|
||||
int scd4x_persist_settings(const struct device *dev);
|
||||
|
||||
/**
|
||||
* @brief Performs a factory reset.
|
||||
*
|
||||
* The perform_factory_reset command resets all configuration settings stored in the EEPROM and
|
||||
* erases the FRC and ASC algorithm history.
|
||||
*
|
||||
* @param dev Pointer to the sensor device
|
||||
*
|
||||
* @return 0 if successful, negative errno code if failure.
|
||||
*/
|
||||
int scd4x_factory_reset(const struct device *dev);
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_DRIVERS_SENSOR_SCD4X_H_ */
|
|
@ -1131,3 +1131,9 @@ test_i2c_sts4x: sts4x@9d {
|
|||
reg = <0x99>;
|
||||
repeatability = <2>;
|
||||
};
|
||||
|
||||
test_i2c_scd4x: scd4x@9e {
|
||||
compatible = "sensirion,scd41";
|
||||
reg = <0x9e>;
|
||||
mode = <0>;
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue