diff --git a/drivers/Makefile.dep b/drivers/Makefile.dep index 9dc64efe57..873bfc36c1 100644 --- a/drivers/Makefile.dep +++ b/drivers/Makefile.dep @@ -542,6 +542,12 @@ ifneq (,$(filter sht3x,$(USEMODULE))) FEATURES_REQUIRED += periph_i2c endif +ifneq (,$(filter shtc1,$(USEMODULE))) + FEATURES_REQUIRED += periph_i2c + USEMODULE += xtimer + USEMODULE += checksum +endif + ifneq (,$(filter si114%,$(USEMODULE))) USEMODULE += xtimer FEATURES_REQUIRED += periph_i2c diff --git a/drivers/Makefile.include b/drivers/Makefile.include index 9000e6b417..d51ff35bd2 100644 --- a/drivers/Makefile.include +++ b/drivers/Makefile.include @@ -278,6 +278,10 @@ ifneq (,$(filter sht3x,$(USEMODULE))) USEMODULE_INCLUDES += $(RIOTBASE)/drivers/sht3x/include endif +ifneq (,$(filter shtc1,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/shtc1/include +endif + ifneq (,$(filter si114x,$(USEMODULE))) USEMODULE_INCLUDES += $(RIOTBASE)/drivers/si114x/include endif diff --git a/drivers/include/shtc1.h b/drivers/include/shtc1.h new file mode 100644 index 0000000000..6d9da30bda --- /dev/null +++ b/drivers/include/shtc1.h @@ -0,0 +1,124 @@ +/* + * Copyright 2017, RWTH Aachen. All rights reserved. + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @defgroup drivers_shtc1 SHTC1 Temperature and humidity sensor + * @ingroup drivers_sensors + * @ingroup drivers_saul + * @brief Driver for the Sensirion SHTC1 sensor. + * + * @file + * @brief Device driver interface for the SHTC1 Temperature and humidity sensor + * + * @author Steffen Robertz + * @author Josua Arndt + */ + +#ifndef SHTC1_H +#define SHTC1_H + +#include +#include "saul.h" + +#include "periph/i2c.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief SHTC1 Default Address + * + */ +#ifndef SHTC1_I2C_ADDRESS +#define SHTC1_I2C_ADDRESS (0x70) +#endif + +/** + * @brief settings struct with all relevant parameters + * @{ + */ +typedef struct { + i2c_t i2c_dev; /**< I2C bus descriptor. */ + uint8_t i2c_addr; /**< I2C address of the sensor. */ +} shtc1_params_t; +/** @} */ + +/** + * @brief device descriptor for the SHTC1 + * @{ + */ +typedef struct { + shtc1_params_t params; /**< Parameters struct with all settings set. */ +} shtc1_t; +/** @} */ + +enum { + SHTC1_OK, /**< Success, no error */ + SHTC1_ERROR_BUS, /**< I2C bus error */ + SHTC1_ERROR_CRC, /**< CRC error */ + SHTC1_ERROR /**< General error */ +}; + +/** + * @brief Initializes the sensor and I2C. + * + * @param[in] dev I2C device descriptor. + * @param[in] params SHTC1 parameters to be used. + * + * @return SHTC1_OK on a working initialization. + * @return SHTC1_ERROR_BUS Reading I2C failed. + * @return SHTC1_ERROR_CRC Wrong ID. + */ +int8_t shtc1_init(shtc1_t* const dev, const shtc1_params_t* params); + +/** + * @brief Reads all register values from the device. + * @details The values as raw data will be saved into reveived. + * + * @param[in] dev The I2C device descriptor. + * @param[in] rel_humidity Humidity in centi %. + * @param[in] temperature Temperature in centi °C. + * + * @return SHTC1_OK if a measurement completed. + * @return SHTC1_ERROR_BUS reading I2C failed. + * @return SHTC1_ERROR_CRC on checksum error. + */ +int8_t shtc1_read(const shtc1_t *dev, uint16_t *rel_humidity, int16_t *temperature); + +/** + * @brief Reads the ID and saves it in the device descriptor + * + * @details When working correctly ID should equal xxxx'xxxx'xx00'0111 where x is unspecified. + * + * @param[in] dev The I2C device descriptor. + * @param[in] id ID of the device. + * + * @return SHTC1_OK on everything done. + * @return SHTC1_ERROR_BUS on error. + */ +int8_t shtc1_id(const shtc1_t *dev, uint16_t *id); + +/** + * @brief Resets sensor + * + * This will reset all internal state machines and reload calibration data from the memory. + * + * @param[in] dev The I2C device descriptor. + * + * @return SHTC1_OK on everything done. + * @return SHTC1_ERROR_BUS on error. + */ +int8_t shtc1_reset(const shtc1_t *dev); + +#ifdef __cplusplus +} +#endif + +#endif /* SHTC1_H */ +/** @} */ diff --git a/drivers/shtc1/Makefile b/drivers/shtc1/Makefile new file mode 100644 index 0000000000..2ff6b1f8f1 --- /dev/null +++ b/drivers/shtc1/Makefile @@ -0,0 +1,3 @@ +MODULE = shtc1 + +include $(RIOTBASE)/Makefile.base diff --git a/drivers/shtc1/include/shtc1_params.h b/drivers/shtc1/include/shtc1_params.h new file mode 100644 index 0000000000..e21aa1c89d --- /dev/null +++ b/drivers/shtc1/include/shtc1_params.h @@ -0,0 +1,74 @@ +/* + * Copyright 2017, RWTH Aachen. All rights reserved. + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_shtc1 + * + * @{ + * + * @file + * @brief Default parameters for the SHTC1 Temperature and humidity sensor + * + * @author Steffen Robertz + * @author Josua Arndt + */ + +#ifndef SHTC1_PARAMS_H +#define SHTC1_PARAMS_H + +#include "board.h" +#include "shtc1.h" +#include "shtc1_regs.h" +#include "saul_reg.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @name Default configuration parameters for SHTC1 sensors + * @{ + */ +#ifndef SHTC1_PARAM_I2C_DEV +#define SHTC1_PARAM_I2C_DEV (I2C_DEV(0)) +#endif +#ifndef SHTC1_PARAM_I2C_ADDR +#define SHTC1_PARAM_I2C_ADDR SHTC1_I2C_ADDRESS +#endif + +#ifndef SHTC1_PARAMS +#define SHTC1_PARAMS { .i2c_dev = SHTC1_PARAM_I2C_DEV, \ + .i2c_addr = SHTC1_PARAM_I2C_ADDR } +#endif +#ifndef SHTC1_SAUL_INFO +#define SHTC1_SAUL_INFO { .name = "shtc1 temperature" }, \ + { .name = "shtc1 humidity" } +#endif +/** @} */ + +/** + * @brief Allocation of SHTC1 configuration + */ +static const shtc1_params_t shtc1_params[] = +{ + SHTC1_PARAMS +}; + +/** + * @brief Configure SAUL registry entries + */ +static const saul_reg_info_t shtc1_saul_info[] = +{ + SHTC1_SAUL_INFO +}; +#ifdef __cplusplus +} +#endif + +#endif /* SHTC1_PARAMS_H */ +/** @} */ diff --git a/drivers/shtc1/include/shtc1_regs.h b/drivers/shtc1/include/shtc1_regs.h new file mode 100644 index 0000000000..4c8d750ce4 --- /dev/null +++ b/drivers/shtc1/include/shtc1_regs.h @@ -0,0 +1,49 @@ +/* + * Copyright 2017, RWTH Aachen. All rights reserved. + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_shtc1 + * + * @{ + * @file + * @brief Register definitions for SHTC1 devices + * + * @author Steffen Robertz + * @author Josua Arndt + */ + +#ifndef SHTC1_REGS_H +#define SHTC1_REGS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** +* @name SHTC1 registers +* @{ +*/ +#define SHTC1_CRC (0x31) /**< crc polynomial */ +#define SHTC1_MEASURE_CLOCK_STRETCHING_TEMP_HIGH (0x7C) /**< Clock stretching enable high*/ +#define SHTC1_MEASURE_CLOCK_STRETCHING_TEMP_LOW (0xA2) /**< Clock stretching disable high*/ +#define SHTC1_COMMAND_RESET_HIGH (0x80) /**< Reset command high*/ +#define SHTC1_COMMAND_RESET_LOW (0x5D) /**< Reset command low*/ +#define SHTC1_COMMAND_ID_HIGH (0xEF) /**< Get ID command low*/ +#define SHTC1_COMMAND_ID_LOW (0xC8) /**< Get ID command low*/ +/** @} */ + +/** +* @brief SHTC1 default ID +*/ +#define SHTC1_ID (0x07) /* ID Mask */ + +#ifdef __cplusplus +} +#endif +#endif /* SHTC1_REGS_H */ +/** @} */ diff --git a/drivers/shtc1/shtc1.c b/drivers/shtc1/shtc1.c new file mode 100644 index 0000000000..af5aeb6e2d --- /dev/null +++ b/drivers/shtc1/shtc1.c @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2017 RWTH-Aachen + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_shtc1 + * @{ + * + * @file + * @brief Device driver implementation for the Sensirion SHTC1 temperature + * and humidity sensor. + * + * @author Steffen Robertz + * @author Josua Arndt + * @} + */ +#include +#include + +#include "log.h" +#include "assert.h" +#include "checksum/crc8.h" +#include "shtc1.h" +#include "shtc1_regs.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +int8_t shtc1_init(shtc1_t *const dev, const shtc1_params_t *params) +{ + uint16_t id; + + /* check for a valid device descriptor and parameters */ + assert(dev && params); + /* copy settings into the device descriptor */ + dev->params = *params; + /* Verify the connection by reading the SHTC1's ID and checking its value */ + if (shtc1_id(dev, &id) != SHTC1_OK) { + return SHTC1_ERROR_BUS; + } + else if ((id & 0x3F) != SHTC1_ID) { + return SHTC1_ERROR_CRC; + } + else { + return SHTC1_OK; + } +} + +int8_t shtc1_read(const shtc1_t *dev, uint16_t *rel_humidity, + int16_t *temperature) +{ + uint8_t received[6]; + /* Build and issue the measurement command */ + uint8_t cmd[] = + { SHTC1_MEASURE_CLOCK_STRETCHING_TEMP_HIGH, + SHTC1_MEASURE_CLOCK_STRETCHING_TEMP_LOW }; + + i2c_acquire(dev->params.i2c_dev); + + if (i2c_write_bytes(dev->params.i2c_dev, dev->params.i2c_addr, cmd, 2, 0)) { + return SHTC1_ERROR_BUS; + } + /* Receive the measurement */ + /* 16 bit Temperature + * 8 bit CRC temp + * 16 Bit Absolute Humidity + * 8 bit CRC Hum + */ + if (i2c_read_bytes(dev->params.i2c_dev, dev->params.i2c_addr, received, 6, + 0)) { + return SHTC1_ERROR_BUS; + } + i2c_release(dev->params.i2c_dev); + + if (rel_humidity != NULL) { + uint32_t abs_humidity = ((received[3] << 8) | received[4]); + /* 10000 * ( abs_humidity /65536) */ + *rel_humidity = (10000 * abs_humidity) >> 16; + } + + if (temperature != NULL) { + uint16_t temp_f = ((received[0] << 8) | received[1]); + /* calculate the relative humidity and convert the temperature to centi °C */ + /* (175.0 * 100 * temp_f / 65536) - 45 ; */ + *temperature = ((17500 * (uint32_t)temp_f) >> 16) - 4500; + } + + if (!((crc8(&received[0], 2, SHTC1_CRC, 0xFF) == received[2]) && + (crc8(&received[3], 2, SHTC1_CRC, 0xFF) == received[5]))) { + /* crc check failed */ + DEBUG("CRC Error\n"); + return SHTC1_ERROR_CRC; + } + DEBUG("CRC Passed! \n"); + return SHTC1_OK; +} + +int8_t shtc1_id(const shtc1_t *dev, uint16_t *id) +{ + /* Build and send measurement command */ + uint8_t data[] = { SHTC1_COMMAND_ID_HIGH, SHTC1_COMMAND_ID_LOW }; + + i2c_acquire(dev->params.i2c_dev); + if (i2c_write_bytes(dev->params.i2c_dev, dev->params.i2c_addr, data, 2, + 0)) { + return SHTC1_ERROR_BUS; + } + /* receive ID and check if the send and receive commands were successful */ + if (i2c_read_bytes(dev->params.i2c_dev, dev->params.i2c_addr, data, 2, 0)) { + return SHTC1_ERROR_BUS; + } + i2c_release(dev->params.i2c_dev); + + /* Save ID in device descriptor */ + *id = (data[0] << 8) | data[1]; + return SHTC1_OK; +} + +int8_t shtc1_reset(const shtc1_t *const dev) +{ + /* Build and issue the reset command */ + uint8_t data[] = { SHTC1_COMMAND_RESET_HIGH, SHTC1_COMMAND_RESET_LOW }; + + i2c_acquire(dev->params.i2c_dev); + if (i2c_write_bytes(dev->params.i2c_dev, dev->params.i2c_addr, data, 2, + 0)) { + return SHTC1_ERROR_BUS; + } + i2c_release(dev->params.i2c_dev); + return SHTC1_OK; +} diff --git a/drivers/shtc1/shtc1_saul.c b/drivers/shtc1/shtc1_saul.c new file mode 100644 index 0000000000..ad12396ba3 --- /dev/null +++ b/drivers/shtc1/shtc1_saul.c @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2019 HAW Hamburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_shtc1 + * @{ + * + * @file + * @brief SHTC1 adaption to the RIOT actuator/sensor interface + * + * @author Michel Gerlach + * + * @} + */ + +#include "saul.h" +#include "shtc1.h" + +static int read_temperature(const void *dev, phydat_t *res) +{ + if (shtc1_read((shtc1_t *)dev, NULL, &res->val[0]) != SHTC1_OK) { + return -ECANCELED; + } + res->unit = UNIT_TEMP_C; + res->scale = -2; + + return 1; +} + +static int read_relative_humidity(const void *dev, phydat_t *res) +{ + if (shtc1_read((shtc1_t *)dev, (uint16_t *)&res->val[0], NULL) != SHTC1_OK) { + return -ECANCELED; + } + res->unit = UNIT_PERCENT; + res->scale = -2; + + return 1; +} + +const saul_driver_t shtc1_temperature_saul_driver = { + .read = read_temperature, + .write = saul_notsup, + .type = SAUL_SENSE_TEMP, +}; + +const saul_driver_t shtc1_relative_humidity_saul_driver = { + .read = read_relative_humidity, + .write = saul_notsup, + .type = SAUL_SENSE_HUM, +}; diff --git a/sys/auto_init/auto_init.c b/sys/auto_init/auto_init.c index 5d3e152f24..b72b856875 100644 --- a/sys/auto_init/auto_init.c +++ b/sys/auto_init/auto_init.c @@ -539,6 +539,10 @@ void auto_init(void) extern void auto_init_sht3x(void); auto_init_sht3x(); #endif +#ifdef MODULE_SHTC1 + extern void auto_init_shtc1(void); + auto_init_shtc1(); +#endif #ifdef MODULE_SDS011 extern void auto_init_sds011(void); auto_init_sds011(); diff --git a/sys/auto_init/saul/auto_init_shtc1.c b/sys/auto_init/saul/auto_init_shtc1.c new file mode 100644 index 0000000000..7d38c0616f --- /dev/null +++ b/sys/auto_init/saul/auto_init_shtc1.c @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2019 HAW Hamburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + * + */ + +/** + * @ingroup sys_auto_init_saul + * @{ + * + * @file + * @brief Auto initialization of shtc1 Digital Humidity Sensor + * + * @author Michel Gerlach + * + * @} + */ + + #ifdef MODULE_SHTC1 + + #include "assert.h" + #include "log.h" + #include "saul_reg.h" + + #include "shtc1.h" + #include "shtc1_params.h" + + /** + * @brief Define the number of configured sensors + */ + #define SHTC1_NUM ARRAY_SIZE(shtc1_params) + + /** + * @brief Allocate memory for the device descriptors + */ + static shtc1_t shtc1_devs[SHTC1_NUM]; + + /** + * @brief Memory for the SAUL registry entries + */ + static saul_reg_t saul_entries[SHTC1_NUM * 2]; + + /** + * @brief Define the number of saul info + */ + #define SHTC1_INFO_NUM ARRAY_SIZE(shtc1_saul_info) + + /** + * @brief Reference the driver struct + */ + extern const saul_driver_t shtc1_temperature_saul_driver; + extern const saul_driver_t shtc1_relative_humidity_saul_driver; + + void auto_init_shtc1(void) + { + assert(SHTC1_NUM == SHTC1_INFO_NUM); + + for (unsigned i = 0; i < SHTC1_NUM; i++) { + LOG_DEBUG("[auto_init_saul] initializing shtc1 #%u\n", i); + + if (shtc1_init(&shtc1_devs[i], &shtc1_params[i]) != SHTC1_OK) { + LOG_ERROR("[auto_init_saul] error initializing shtc1 #%u\n", i); + continue; + } + /* temperature */ + saul_entries[(i * 2)].dev = &(shtc1_devs[i]); + saul_entries[(i * 2)].name = shtc1_saul_info[i].name; + saul_entries[(i * 2)].driver = &shtc1_temperature_saul_driver; + + /* Humidity */ + saul_entries[(i * 2)+1].dev = &(shtc1_devs[i]); + saul_entries[(i * 2)+1].name = shtc1_saul_info[i].name; + saul_entries[(i * 2)+1].driver = &shtc1_relative_humidity_saul_driver; + + saul_reg_add(&(saul_entries[(i * 2)])); + saul_reg_add(&(saul_entries[(i * 2)+1])); + } + } + + #else + typedef int dont_be_pedantic; + #endif /* MODULE_SHTC1 */ diff --git a/tests/driver_shtc1/Makefile b/tests/driver_shtc1/Makefile new file mode 100644 index 0000000000..9ece2699c7 --- /dev/null +++ b/tests/driver_shtc1/Makefile @@ -0,0 +1,8 @@ +include ../Makefile.tests_common + +DRIVER ?= shtc1 + +USEMODULE += fmt +USEMODULE += $(DRIVER) + +include $(RIOTBASE)/Makefile.include diff --git a/tests/driver_shtc1/README.md b/tests/driver_shtc1/README.md new file mode 100644 index 0000000000..6bc4ab1698 --- /dev/null +++ b/tests/driver_shtc1/README.md @@ -0,0 +1,4 @@ +#About +Testing application for the SHTC1 temperature and humidity sensor +#Usage +Just build it using the `make BOARD=??? flash` command in the `tests/driver_shtc1` folder. Temperature and humidity values should be printed in the terminal every 2s diff --git a/tests/driver_shtc1/main.c b/tests/driver_shtc1/main.c new file mode 100644 index 0000000000..0c079d7d42 --- /dev/null +++ b/tests/driver_shtc1/main.c @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2017 RWTH Aachen, Steffen Robertz, Josua Arndt + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ +/** + * @ingroup tests + * @{ + * + * @file + * @brief Test application for the SHTC1 temperature and humidity sensor + * + * @author Steffen Robertz + * @author Josua Arndt + * @author Michel Gerlach + * + * @} + */ +#include +#include + +#include "shtc1.h" +#include "shtc1_params.h" +#include "xtimer.h" +#include "fmt.h" + +int main(void) +{ + shtc1_t dev; + int16_t temp; + uint16_t hum; + + char str_temp[8]; + char str_hum[8]; + size_t len; + + puts("SHTC1 test application\n"); + + if ((shtc1_init(&dev, &shtc1_params[0])) != SHTC1_OK) { + puts("can't initialize the sensor"); + return -1; + } + puts("SHTC1 initialized\n"); + while (1) { + if (shtc1_read(&dev, &hum, &temp) == SHTC1_OK) { + len = fmt_s16_dfp(str_temp, temp, -2); + str_temp[len] = '\0'; + + len = fmt_s16_dfp(str_hum, hum, -2); + str_hum[len] = '\0'; + } + /* print values to STDIO */ + printf("Temperature [°C]: %s\n", str_temp); + printf(" Humidity [%%rH]: %s\n", str_hum); + + xtimer_sleep(2); + } + return 0; +}