diff --git a/drivers/sensors/Kconfig b/drivers/sensors/Kconfig index 487e98d9b86..e9ae6a01140 100644 --- a/drivers/sensors/Kconfig +++ b/drivers/sensors/Kconfig @@ -92,6 +92,21 @@ config SENSORS_SX9373_BUFFER_NUMBER The number of the circular buffer used. If the value equal to zero, indicates that the circular buffer is disabled. +config SENSORS_CT7117 + bool "Sensylink CT7117 Temperature Sensor" + default n + select I2C + ---help--- + Enable driver for CT7117 Temperature Sensor. + +config SENSORS_CT7117_BUFFER_NUMBER + int "The nunmber of circular buffer for sensor CT7117" + default 1 + depends on SENSORS_CT7117 + ---help--- + The number of the circular buffer used. If the value equal to zero, + indicates that the circular buffer is disabled. + config SENSORS_AS5048B bool "AMS AS5048B Magnetic Rotary Encoder support" default n diff --git a/drivers/sensors/Make.defs b/drivers/sensors/Make.defs index b5a9a881f7e..b73e0377475 100644 --- a/drivers/sensors/Make.defs +++ b/drivers/sensors/Make.defs @@ -64,6 +64,10 @@ ifeq ($(CONFIG_SENSORS_SX9373),y) CSRCS += sx9373.c endif +ifeq ($(CONFIG_SENSORS_CT7117),y) + CSRCS += ct7117.c +endif + ifeq ($(CONFIG_SENSORS_AS5048B),y) CSRCS += as5048b.c endif diff --git a/drivers/sensors/ct7117.c b/drivers/sensors/ct7117.c new file mode 100644 index 00000000000..7ca5336c437 --- /dev/null +++ b/drivers/sensors/ct7117.c @@ -0,0 +1,805 @@ +/**************************************************************************** + * drivers/sensors/ct7117.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define CT7117_DEVID 0x59 /* Device id. */ + +/* Temperature resolution. */ + +#define CT7117_RESOLUTION 0.0078125f /* degC. */ + +/* default ODR */ + +#define CT7117_DEFAULT_ODR 4000000 /* default 4s. */ + +/* Register address. */ + +#define CT7117_REG_DATA 0x00 /* Temperature data. */ +#define CT7117_REG_CONF 0x01 /* Config information. */ +#define CT7117_REG_WIA 0x07 /* Manufacture id. */ + +/* Conversion time bit. */ + +#define CT7117_CONVERSION_0p25HZ 0x00 /* Conversion Rate Selection 0.25Hz. */ +#define CT7117_CONVERSION_1HZ 0x01 /* Conversion Rate Selection 1.0Hz. */ +#define CT7117_CONVERSION_4HZ 0x02 /* Conversion Rate Selection 4.0Hz. */ +#define CT7117_CONVERSION_8HZ 0x03 /* Conversion Rate Selection 8.0Hz. */ + +/* Mode Control bit. */ + +#define CT7117_SHOTDOWN_MODE 0x01 /* Control device in shotdown mode. */ +#define CT7117_NORMAL_MODE 0x00 /* Control device in normal mode. */ + +#define CT7117_MAKE_S16(u8h, u8l) \ + (int16_t)(((uint16_t)(u8h) << 8) | (uint16_t)(u8l)) + +/**************************************************************************** + * Private Type Definitions + ****************************************************************************/ + +/* Device Register Bit. */ + +union ct7117_control_u +{ + uint16_t ctrl_w; + struct + { + uint16_t os : 1; /* One shot action enable bit. */ + uint16_t cr : 2; /* Conversion rate selection bits. */ + uint16_t pec : 1; /* Packet error checking bit. */ + uint16_t to : 1; /* Time-out enable bit. */ + uint16_t re : 2; /* Resolution selection bits. */ + uint16_t em : 1; /* Extended mode bit. */ + uint16_t sd : 1; /* Shutdown bit. */ + uint16_t altm : 1; /* Over temperature alert mode selection bit. */ + uint16_t res1 : 1; /* Reserved. */ + uint16_t fq : 2; /* Fault queue bits. */ + uint16_t res2 : 2; /* Reserved. */ + uint16_t ots : 1; /* Over temperature ALERT status bit. */ + } ctrl_b; +}; + +typedef union ct7117_control_u ct7117_control_t; + +/* Structure for ct7117 odr. */ + +struct ct7117_odr_s +{ + uint8_t regval; /* the data of register. */ + unsigned int odr; /* the unit is us. */ +}; + +/* Structure for ct7117 device. */ + +struct ct7117_dev_s +{ + struct sensor_lowerhalf_s lower; /* The struct of lower half driver. */ + FAR struct ct7117_config_s *config; /* The board config function. */ + uint64_t start_timestamp; /* Start timestamp(us). */ + uint64_t sample_count; /* The count of sampling */ + bool activated; /* Sensor working state. */ + unsigned int interval; /* Sensor acquisition interval. */ + struct work_s work; /* Work queue for reading data. */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* I2C functions. */ + +static int ct7117_i2c_write(FAR struct ct7117_dev_s *priv, + uint8_t regaddr, FAR uint8_t *regval); +static int ct7117_i2c_read(FAR struct ct7117_dev_s *priv, + uint8_t regaddr, FAR uint8_t *regval, + uint32_t cnt); +static int ct7117_i2c_readcfg(FAR struct ct7117_dev_s *priv, + FAR ct7117_control_t *ctrl); +static int ct7117_i2c_writecfg(FAR struct ct7117_dev_s *priv, + FAR ct7117_control_t *ctrl); + +/* Sensor handle functions. */ + +static int ct7117_enable(FAR struct ct7117_dev_s *priv, bool enable); +static int ct7117_checkid(FAR struct ct7117_dev_s *priv); +static int ct7117_setmode(FAR struct ct7117_dev_s *priv, uint8_t mode); +static int ct7117_readtemp(FAR struct ct7117_dev_s *priv, + FAR struct sensor_event_temp *data); +static int ct7117_findodr(FAR unsigned int *expect_period_us); + +/* Sensor ops functions. */ + +static int ct7117_activate(FAR struct sensor_lowerhalf_s *lower, + bool enable); +static int ct7117_set_interval(FAR struct sensor_lowerhalf_s *lower, + FAR unsigned int *interval_us); + +/* Sensor poll functions. */ + +static void ct7117_worker(FAR void *arg); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct ct7117_odr_s g_ct7117_odr[] = +{ + {CT7117_CONVERSION_8HZ, 125000}, /* Sampling interval is 1.25s. */ + {CT7117_CONVERSION_4HZ, 250000}, /* Sampling interval is 2.5s. */ + {CT7117_CONVERSION_1HZ, 1000000}, /* Sampling interval is 1s. */ + {CT7117_CONVERSION_0p25HZ, 4000000}, /* Sampling interval is 4s. */ +}; + +static const struct sensor_ops_s g_ct7117_ops = +{ + .activate = ct7117_activate, /* Enable/disable snesor. */ + .set_interval = ct7117_set_interval /* Set output data period. */ +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/* I2C functions */ + +/**************************************************************************** + * Name: ct7117_i2c_read + * + * Description: + * Read register data + * + * Input Parameters + * priv -Device struct + * regaddr -Register address + * regval -Register value + * cnt -Data number + * + * Returned Value + * Return 0 if the driver was success; A negated errno + * value is returned on any failure; + * + * Assumptions/Limitations: + * none. + * + ****************************************************************************/ + +static int ct7117_i2c_read(FAR struct ct7117_dev_s *priv, + uint8_t regaddr, FAR uint8_t *regval, + uint32_t cnt) +{ + struct i2c_msg_s msg[2]; + int ret; + + msg[0].frequency = priv->config->freq; + msg[0].addr = priv->config->addr; + msg[0].flags = 0; + msg[0].buffer = ®addr; + msg[0].length = 1; + + msg[1].frequency = priv->config->freq; + msg[1].addr = priv->config->addr; + msg[1].flags = I2C_M_READ; + msg[1].buffer = regval; + msg[1].length = cnt; + + ret = I2C_TRANSFER(priv->config->i2c, msg, 2); + if (ret < 0) + { + snerr("I2C_TRANSFER failed: %d\n", ret); + } + + return ret; +} + +/**************************************************************************** + * Name: ct7117_i2c_write + * + * Description: + * Write ct7117 register + * + * Input Parameters + * priv -Device struct + * regaddr -Register address + * regval -To be write value + * + * Returned Value + * Return 0 if the driver was success; A negated errno + * value is returned on any failure; + * + * Assumptions/Limitations: + * none. + * + ****************************************************************************/ + +static int ct7117_i2c_write(FAR struct ct7117_dev_s *priv, + uint8_t regaddr, FAR uint8_t *regval) +{ + struct i2c_msg_s msg; + uint8_t w_buf[3]; + int ret; + + w_buf[0] = regaddr; + w_buf[1] = regval[0]; + w_buf[2] = regval[1]; + + msg.frequency = priv->config->freq; + msg.addr = priv->config->addr; + msg.flags = 0; + msg.buffer = w_buf; + msg.length = 3; + + ret = I2C_TRANSFER(priv->config->i2c, &msg, 1); + if (ret < 0) + { + snerr("I2C_TRANSFER failed: %d\n", ret); + } + + return ret; +} + +/**************************************************************************** + * Name: ct7117_i2c_readcfg + * + * Description: + * Read config regsiter + * + * Input Parameters + * priv -Device struct + * ctrl -ctrl value + * + * Returned Value + * Return 0 if the driver was success; A negated errno + * value is returned on any failure; + * + * Assumptions/Limitations: + * none. + * + ****************************************************************************/ + +static int ct7117_i2c_readcfg(FAR struct ct7117_dev_s *priv, + FAR ct7117_control_t *ctrl) +{ + int ret; + uint8_t r_buf[2]; + + ret = ct7117_i2c_read(priv, CT7117_REG_CONF, r_buf, 2); + if (ret < 0) + { + snerr("Fail to read config register: %d\n", ret); + } + else + { + ctrl->ctrl_w = (uint16_t)((r_buf[0] << 8) | (r_buf[1])); + } + + return ret; +} + +/**************************************************************************** + * Name: ct7117_i2c_writecfg + * + * Description: + * Write ct7117 config register + * + * Input Parameters + * priv -Device struct + * ctrl -ctrl value + * + * Returned Value + * Return 0 if the driver was success; A negated errno + * value is returned on any failure; + * + * Assumptions/Limitations: + * none. + * + ****************************************************************************/ + +static int ct7117_i2c_writecfg(FAR struct ct7117_dev_s *priv, + FAR ct7117_control_t *ctrl) +{ + int ret; + uint8_t w_buf[2]; + + w_buf[0] = (uint8_t)((ctrl->ctrl_w) >> 8); + w_buf[1] = (uint8_t)(ctrl->ctrl_w); + + ret = ct7117_i2c_write(priv, CT7117_REG_CONF, w_buf); + if (ret < 0) + { + snerr("Fail to write config register: %d\n", ret); + } + + return ret; +} + +/* Sensor handle functions */ + +/**************************************************************************** + * Name: ct7117_setmode + * + * Description: + * Set work mode for CT7117 + * + * Input Parameters + * priv -Device struct + * mode -Work mode + * + * Returned Value + * Return 0 if the driver was success; A negated errno + * value is returned on any failure; + * + * Assumptions/Limitations: + * none. + * + ****************************************************************************/ + +static int ct7117_setmode(FAR struct ct7117_dev_s *priv, + uint8_t mode) +{ + ct7117_control_t ctrl; + int ret; + + ret = ct7117_i2c_readcfg(priv, &ctrl); + if (ret < 0) + { + snerr("Failed to read config register: %d\n", ret); + return ret; + } + + if (mode == CT7117_NORMAL_MODE) + { + ctrl.ctrl_b.sd = CT7117_NORMAL_MODE; + } + else + { + ctrl.ctrl_b.sd = CT7117_SHOTDOWN_MODE; + } + + ret = ct7117_i2c_writecfg(priv, &ctrl); + if (ret < 0) + { + snerr("Failed to set work mode: %d\n", ret); + } + + return ret; +} + +/**************************************************************************** + * Name: ct7117_readtemp + * + * Description: + * Read temperature data + * + * Input Parameters + * priv -Device struct + * data -temperature data buffer + * + * Returned Value + * Return 0 if the driver was success; A negated errno + * value is returned on any failure; + * + * Assumptions/Limitations: + * none. + * + ****************************************************************************/ + +static int ct7117_readtemp(FAR struct ct7117_dev_s *priv, + FAR struct sensor_event_temp *data) +{ + int ret; + uint8_t buffer[2]; + + ret = ct7117_i2c_read(priv, CT7117_REG_DATA, buffer, 2); + if (ret < 0) + { + snerr("Failed to read temperature: %d\n", ret); + return ret; + } + + data->temperature = CT7117_RESOLUTION * + CT7117_MAKE_S16(buffer[0], buffer[1]); + + return ret; +} + +/**************************************************************************** + * Name: ct7117_checkid + * + * Description: + * Read and verify the CT7117 chip ID + * + * Input Parameters + * priv -Device struct + * + * Returned Value + * Return 0 if the driver was success; A negated errno + * value is returned on any failure; + * + * Assumptions/Limitations: + * none. + * + ****************************************************************************/ + +static int ct7117_checkid(FAR struct ct7117_dev_s *priv) +{ + int ret; + uint8_t devid; + + ret = ct7117_i2c_read(priv, CT7117_REG_WIA, &devid, 1); + if (ret < 0 || devid != CT7117_DEVID) + { + snerr("Wrong Device ID! %02x\n", devid); + ret = -ENODEV; + } + + return ret; +} + +/**************************************************************************** + * Name: ct7117_enable + * + * Description: + * CT7117 control on/off + * + * Input Parameters + * priv -Device struct + * + * Returned Value + * Return 0 if the driver was success; A negated errno + * value is returned on any failure; + * + * Assumptions/Limitations: + * none. + * + ****************************************************************************/ + +static int ct7117_enable(FAR struct ct7117_dev_s *priv, bool enable) +{ + int ret; + + if (enable) + { + /* Set normal mode. */ + + ret = ct7117_setmode(priv, CT7117_NORMAL_MODE); + if (ret < 0) + { + snerr("Failed to set normal mode: %d\n", ret); + return ret; + } + } + else + { + /* Set shotdown mode. */ + + ret = ct7117_setmode(priv, CT7117_SHOTDOWN_MODE); + if (ret < 0) + { + snerr("Failed to set shotdown mode: %d\n", ret); + return ret; + } + } + + return ret; +} + +/**************************************************************************** + * Name: ct7117_findodr + * + * Description: + * Find the period that matches best. + * + * Input Parameters + * expect_period_us -the time(expext) between report data, in us. + * + * Returned Value + * index of odr param. + * + * Assumptions/Limitations: + * none. + * + ****************************************************************************/ + +static int ct7117_findodr(FAR unsigned int *expect_period_us) +{ + int i; + int len = sizeof(g_ct7117_odr) / sizeof(struct ct7117_odr_s); + + for (i = 0; i < len; i++) + { + if (*expect_period_us <= g_ct7117_odr[i].odr) + { + return i; + } + } + + return len - 1; +} + +/* Sensor ops functions */ + +/**************************************************************************** + * Name: ct7117_set_interval + * + * Description: + * Set ODR + * + * Input Parameters + * lower -The instance of lower half sensor driver + * interval_us -Sample interval + * + * Returned Value + * Return 0 if the driver was success; A negated errno + * value is returned on any failure; + * + * Assumptions/Limitations: + * none. + * + ****************************************************************************/ + +static int ct7117_set_interval(FAR struct sensor_lowerhalf_s *lower, + FAR unsigned int *interval_us) +{ + FAR struct ct7117_dev_s *priv = (FAR struct ct7117_dev_s *)lower; + ct7117_control_t ctrl; + int ret = 0; + int idx; + + DEBUGASSERT(priv != NULL); + + /* Find the period that matches best. */ + + idx = ct7117_findodr(interval_us); + if (priv->interval != g_ct7117_odr[idx].odr) + { + ret = ct7117_i2c_readcfg(priv, &ctrl); + if (ret < 0) + { + snerr("Failed to read config register: %d\n", ret); + return ret; + } + + ctrl.ctrl_b.cr = g_ct7117_odr[idx].regval; + ret = ct7117_i2c_writecfg(priv, &ctrl); + if (ret < 0) + { + snerr("Failed to set interval: %d\n", ret); + } + else + { + priv->interval = g_ct7117_odr[idx].odr; + } + } + + return ret; +} + +/**************************************************************************** + * Name: ct7117_activate + * + * Description: + * Enable or disable sensor device + * + * Input Parameters + * lower -The instance of lower half sensor driver + * enable -true(enable) and false(disable) + * + * Returned Value + * Return 0 if the driver was success; A negated errno + * value is returned on any failure; + * + * Assumptions/Limitations: + * none. + * + ****************************************************************************/ + +static int ct7117_activate(FAR struct sensor_lowerhalf_s *lower, + bool enable) +{ + FAR struct ct7117_dev_s *priv = (FAR struct ct7117_dev_s *)lower; + int ret; + + if (lower->type != SENSOR_TYPE_AMBIENT_TEMPERATURE) + { + snerr("Failed to match sensor type.\n"); + return -EINVAL; + } + + if (priv->activated != enable) + { + ret = ct7117_enable(priv, enable); + if (ret < 0) + { + snerr("Failed to enable temperature sensor: %d\n", ret); + return ret; + } + + priv->activated = enable; + + if (enable) + { + priv->start_timestamp = sensor_get_timestamp(); + priv->sample_count = 1; + + work_queue(LPWORK, &priv->work, + ct7117_worker, priv, + priv->interval / USEC_PER_TICK); + } + else + { + work_cancel(LPWORK, &priv->work); + } + } + + return OK; +} + +/**************************************************************************** + * Name: ct7117_worker + * + * Description: + * Reading data according to the sampling time + * + * Input Parameters + * + * Returned Value + * Return 0 if the driver was success; A negated errno + * value is returned on any failure; + * + * Assumptions/Limitations: + * none. + * + ****************************************************************************/ + +static void ct7117_worker(FAR void *arg) +{ + struct sensor_event_temp tmp; + FAR struct ct7117_dev_s *priv = arg; + int interval; + + DEBUGASSERT(priv != NULL); + + /* Get the timestamp. */ + + tmp.timestamp = sensor_get_timestamp(); + + /* Update the number of sampling points. */ + + priv->sample_count++; + + /* Get fixed interval. */ + + interval = priv->start_timestamp + + priv->sample_count * priv->interval - + tmp.timestamp; + + /* If it is negative, need to start immediately to compensate the time. */ + + if (interval < 0) + { + interval = 0; + } + + work_queue(LPWORK, &priv->work, ct7117_worker, + priv, interval / USEC_PER_TICK); + + if (ct7117_readtemp(priv, &tmp) >= 0) + { + priv->lower.push_event(priv->lower.priv, &tmp, + sizeof(struct sensor_event_temp)); + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ct7117_register + * + * Description: + * Register the CT7117 character device as 'devpath'. + * + * Input Parameters: + * devno - The device number, used to build the device path + * as /dev/sensor/tempN + * config - configuration for the temperature driver. + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int ct7117_register(int devno, FAR const struct ct7117_config_s *config) +{ + FAR struct ct7117_dev_s *priv; + int ret; + + /* Sanity check. */ + + DEBUGASSERT(config != NULL); + + /* Initialize the CT7117 device structure. */ + + priv = kmm_zalloc(sizeof(struct ct7117_dev_s)); + if (priv == NULL) + { + snerr("Failed to allocate instance\n"); + return -ENOMEM; + } + + priv->config = config; + priv->lower.type = SENSOR_TYPE_AMBIENT_TEMPERATURE; + priv->lower.buffer_number = CONFIG_SENSORS_CT7117_BUFFER_NUMBER; + priv->lower.ops = &g_ct7117_ops; + priv->interval = CT7117_DEFAULT_ODR; + + /* Check Device ID. */ + + ret = ct7117_checkid(priv); + if (ret < 0) + { + snerr("Failed to register driver: %d\n", ret); + goto err; + } + + /* Enter shotdown mode. */ + + ret = ct7117_enable(priv, false); + if (ret < 0) + { + snerr("Failed to enter shotdown mode : %d\n", ret); + goto err; + } + + /* Register the sensor driver. */ + + ret = sensor_register(&priv->lower, devno); + if (ret < 0) + { + snerr("Failed to register driver:%d\n", ret); + goto err; + } + + return ret; + +err: + kmm_free(priv); + return ret; +} diff --git a/include/nuttx/sensors/ct7117.h b/include/nuttx/sensors/ct7117.h new file mode 100644 index 00000000000..4bfc5d7ef3b --- /dev/null +++ b/include/nuttx/sensors/ct7117.h @@ -0,0 +1,85 @@ +/**************************************************************************** + * include/nuttx/sensors/ct7117.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __INCLUDE_NUTTX_SENSORS_CT7117_H +#define __INCLUDE_NUTTX_SENSORS_CT7117_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ +#include +#include + +#if defined(CONFIG_I2C) && defined(CONFIG_SENSORS_CT7117) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +struct ct7117_config_s +{ + uint8_t addr; /* I2C address. */ + int freq; /* I2C frequency. */ + FAR struct i2c_master_s *i2c; /* I2C interface. */ +}; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Name: ct7117_register + * + * Description: + * Register the CT7117 character device as 'devpath'. + * + * Input Parameters: + * devno - The device number, used to build the device path + * as /dev/sensor/tempN. + * i2c - An I2C driver instance. + * config - configuration for the CT7117 driver. For details see + * description above. + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int ct7117_register(int devno, FAR const struct ct7117_config_s *config); + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* CONFIG_I2C && CONFIG_CT7117 */ +#endif /* __INCLUDE_NUTTX_SENSORS_CT7117_H */