From 55cda8d8abc090d6305184777fa946d23932bc17 Mon Sep 17 00:00:00 2001 From: smlng Date: Thu, 16 Nov 2017 20:15:38 +0100 Subject: [PATCH] drivers: add hts221 temperature and humidity sensor --- drivers/Makefile.dep | 4 + drivers/Makefile.include | 3 + drivers/hts221/Makefile | 1 + drivers/hts221/hts221.c | 388 +++++++++++++++++++++++++ drivers/hts221/include/hts221_params.h | 69 +++++ drivers/hts221/include/hts221_regs.h | 153 ++++++++++ drivers/include/hts221.h | 168 +++++++++++ 7 files changed, 786 insertions(+) create mode 100644 drivers/hts221/Makefile create mode 100644 drivers/hts221/hts221.c create mode 100644 drivers/hts221/include/hts221_params.h create mode 100644 drivers/hts221/include/hts221_regs.h create mode 100644 drivers/include/hts221.h diff --git a/drivers/Makefile.dep b/drivers/Makefile.dep index 05fcf57a2f..c6c6919a91 100644 --- a/drivers/Makefile.dep +++ b/drivers/Makefile.dep @@ -115,6 +115,10 @@ ifneq (,$(filter hih6130,$(USEMODULE))) USEMODULE += xtimer endif +ifneq (,$(filter hts221,$(USEMODULE))) + FEATURES_REQUIRED += periph_i2c +endif + ifneq (,$(filter io1_xplained,$(USEMODULE))) FEATURES_REQUIRED += periph_gpio USEMODULE += at30tse75x diff --git a/drivers/Makefile.include b/drivers/Makefile.include index b6cd4e40af..ff5dac66bf 100644 --- a/drivers/Makefile.include +++ b/drivers/Makefile.include @@ -148,3 +148,6 @@ endif ifneq (,$(filter apa102,$(USEMODULE))) USEMODULE_INCLUDES += $(RIOTBASE)/drivers/apa102/include endif +ifneq (,$(filter hts221,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/hts221/include +endif diff --git a/drivers/hts221/Makefile b/drivers/hts221/Makefile new file mode 100644 index 0000000000..48422e909a --- /dev/null +++ b/drivers/hts221/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/drivers/hts221/hts221.c b/drivers/hts221/hts221.c new file mode 100644 index 0000000000..8d53bd5b06 --- /dev/null +++ b/drivers/hts221/hts221.c @@ -0,0 +1,388 @@ +/* + * Copyright (C) 2017 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_hts221 + * @{ + * + * @file + * @brief Driver for the ST HTS221 digital Humidity Sensor + * + * @author Sebastian Meiling + * + * @} + */ + +#include +#include + +#include "assert.h" +#include "hts221.h" +#include "periph/i2c.h" +#include "xtimer.h" + +#define ENABLE_DEBUG (1) +#include "debug.h" + +#define I2C_SPEED I2C_SPEED_FAST +#define BUS (dev->p.i2c) +#define ADDR (dev->p.addr) + +static int _set_power(const hts221_t *dev, const bool active); + +/** + * @brief Read calibration parameters for humidity calculation + * + * @note This function does not acquire or release the I2C bus, must be done + * in calling function! + * + * @param[in|out] dev device descriptor of sensor + * + * @returns HTS221_OK on success, or error otherwise + */ +int _humidity_calibration(hts221_t *dev) +{ + uint8_t buf[2]; + uint8_t reg = HTS221_REGS_H0_RH_X2 | 0x80; + /* 1. read h0_rh and h1_rh coefficients */ + if (i2c_read_regs(BUS, ADDR, reg, &buf[0], 2) != 2) { + i2c_release(BUS); + DEBUG("%s: i2c_read_regs failed!\n", DEBUG_FUNC); + return -HTS221_NOBUS; + } + DEBUG("%s: buf[0]=%u buf[1]=%u\n", DEBUG_FUNC, buf[0], buf[1]); + dev->h0_rh = buf[0] >> 1; + dev->h1_rh = buf[1] >> 1; + DEBUG("%s: h0_rh %" PRIi16 ", h1_rh %" PRIi16 "\n", + DEBUG_FUNC, dev->h0_rh, dev->h1_rh); + /* 2. read h0_t0_out */ + reg = HTS221_REGS_H0_T0_OUT_L | 0x80; + if (i2c_read_regs(BUS, ADDR, reg, &buf[0], 2) != 2) { + i2c_release(BUS); + DEBUG("%s: i2c_read_regs failed!\n", DEBUG_FUNC); + return -HTS221_NOBUS; + } + DEBUG("%s: buf[0]=%u buf[1]=%u\n", DEBUG_FUNC, buf[0], buf[1]); + dev->h0_t0_out = ((uint16_t)buf[1] << 8) | buf[0]; + /* 3. read h1_t0_out */ + reg = HTS221_REGS_H1_T0_OUT_L | 0x80; + if (i2c_read_regs(BUS, ADDR, reg, &buf[0], 2) != 2) { + i2c_release(BUS); + DEBUG("%s: i2c_read_regs failed!\n", DEBUG_FUNC); + return -HTS221_NOBUS; + } + DEBUG("%s: buf[0]=%u buf[1]=%u\n", DEBUG_FUNC, buf[0], buf[1]); + dev->h1_t0_out = ((uint16_t)buf[1] << 8) | buf[0]; + DEBUG("%s: h0_t0_out %" PRIi16 ", h1_t0_out %" PRIi16 "\n", + DEBUG_FUNC, dev->h0_t0_out, dev->h1_t0_out); + + return HTS221_OK; +} + +/** + * @brief Read calibration parameters for temperature calculation + * + * @note This function does not acquire or release the I2C bus, must be done + * in calling function! + * + * @param[in|out] dev device descriptor of sensor + * + * @returns HTS221_OK on success, or error otherwise + */ +int _temperature_calibration(hts221_t *dev) +{ + uint8_t buf[2]; + uint8_t tmp; + /* 1. read t0_degc and t1_degc coefficients */ + uint8_t reg = HTS221_REGS_T0_DEGC_X8 | 0x80; + if (i2c_read_regs(BUS, ADDR, reg, &buf[0], 2) != 2) { + i2c_release(BUS); + DEBUG("%s: i2c_read_regs failed!\n", DEBUG_FUNC); + return -HTS221_NOBUS; + } + DEBUG("%s: buf[0]=%u buf[1]=%u\n", DEBUG_FUNC, buf[0], buf[1]); + /* 2. read t1_t0_msb */ + if (i2c_read_reg(BUS, ADDR, HTS221_REGS_T1_T0_MSB, &tmp) != 1) { + i2c_release(BUS); + DEBUG("%s: i2c_read_regs failed!\n", DEBUG_FUNC); + return -HTS221_NOBUS; + } + /* 3. calc values */ + int16_t t0_degc_x8_u16 = (((uint16_t)(tmp & 0x03)) << 8) | buf[0]; + int16_t t1_degc_x8_u16 = (((uint16_t)(tmp & 0x0C)) << 6) | buf[1]; + dev->t0_degc = t0_degc_x8_u16 >> 3; + dev->t1_degc = t1_degc_x8_u16 >> 3; + DEBUG("%s: t0_degc %" PRIi16 ", t1_degc %" PRIi16 "\n", + DEBUG_FUNC, dev->t0_degc, dev->t1_degc); + /* 4. read t0_out */ + reg = HTS221_REGS_T0_OUT_L | 0x80; + if (i2c_read_regs(BUS, ADDR, reg, &buf[0], 2) != 2) { + i2c_release(BUS); + DEBUG("%s: i2c_read_regs failed!\n", DEBUG_FUNC); + return -HTS221_NOBUS; + } + DEBUG("%s: buf[0]=%u buf[1]=%u\n", DEBUG_FUNC, buf[0], buf[1]); + dev->t0_out = ((uint16_t)buf[1] << 8) | buf[0]; + /* 5. read t1_out */ + reg = HTS221_REGS_T1_OUT_L | 0x80; + if (i2c_read_regs(BUS, ADDR, reg, &buf[0], 2) != 2) { + i2c_release(BUS); + DEBUG("%s: i2c_read_regs failed!\n", DEBUG_FUNC); + return -HTS221_NOBUS; + } + DEBUG("%s: buf[0]=%u buf[1]=%u\n", DEBUG_FUNC, buf[0], buf[1]); + dev->t1_out = ((uint16_t)buf[1] << 8) | buf[0]; + DEBUG("%s: t0_out %" PRIi16 ", t1_out %" PRIi16 "\n", + DEBUG_FUNC, dev->t0_out, dev->t1_out); + + return HTS221_OK; +} + +int hts221_init(hts221_t *dev, const hts221_params_t *params) +{ + uint8_t reg; + + memcpy(&dev->p, params, sizeof(hts221_params_t)); + /* initialize the I2C bus */ + i2c_acquire(BUS); + if (i2c_init_master(BUS, I2C_SPEED) < 0) { + i2c_release(BUS); + DEBUG("%s: i2c_init_master failed!\n", DEBUG_FUNC); + return -HTS221_NOBUS; + } + + /* try if we can interact with the device by reading its manufacturer ID */ + if (i2c_read_reg(BUS, ADDR, HTS221_REGS_WHO_AM_I, ®) != 1) { + i2c_release(BUS); + DEBUG("%s: i2c_read_regs HTS221_REGS_WHO_AM_I failed!\n", DEBUG_FUNC); + return -HTS221_NOBUS; + } + if (reg != HTS221_DEVICE_ID) { + i2c_release(BUS); + DEBUG("%s: invalid HTS221_DEVICE_ID!\n", DEBUG_FUNC); + return -HTS221_NODEV; + } + i2c_release(BUS); + /* reboot device before usage */ + if (hts221_reboot(dev) != HTS221_OK) { + return -HTS221_NOBUS; + } + + i2c_acquire(BUS); + if (i2c_write_reg(BUS, ADDR, HTS221_REGS_AV_CONF, dev->p.avgx) != 1) { + i2c_release(BUS); + DEBUG("%s: i2c_write_regs HTS221_REGS_AV_CONF failed!\n", DEBUG_FUNC); + return -HTS221_NOBUS; + } + reg = 0; + if (i2c_write_reg(BUS, ADDR, HTS221_REGS_CTRL_REG1, reg) != 1) { + i2c_release(BUS); + DEBUG("%s: i2c_write_reg HTS221_REGS_CTRL_REG1 failed!\n", DEBUG_FUNC); + return -HTS221_NOBUS; + } + i2c_release(BUS); + + i2c_acquire(BUS); + if ((_humidity_calibration(dev) != HTS221_OK) || + (_temperature_calibration(dev) != HTS221_OK)) { + i2c_release(BUS); + DEBUG("%s: read calibration parameters failed!\n", DEBUG_FUNC); + return HTS221_ERROR; + } + i2c_release(BUS); + DEBUG("%s: DONE!\n", DEBUG_FUNC); + + return HTS221_OK; +} + +int hts221_one_shot(const hts221_t *dev) +{ + uint8_t reg = HTS221_REGS_CTRL_REG1_ODR_ONE_SHOT; + + /* first, disable any continuous measurement, enter one short mode */ + if (hts221_set_rate(dev, reg) != HTS221_OK) { + return -HTS221_NOBUS; + } + + i2c_acquire(BUS); + /* second, read current settings */ + if (i2c_read_reg(BUS, ADDR, HTS221_REGS_CTRL_REG2, ®) != 1) { + i2c_release(BUS); + DEBUG("%s: i2c_read_regs HTS221_REGS_CTRL_REG1 failed!\n", DEBUG_FUNC); + return -HTS221_NOBUS; + } + /* third, enable one-shot */ + reg |= HTS221_REGS_CTRL_REG2_OS_EN; + if (i2c_write_reg(BUS, ADDR, HTS221_REGS_CTRL_REG2, reg) != 1) { + i2c_release(BUS); + return -HTS221_NOBUS; + } + i2c_release(BUS); + + return HTS221_OK; +} + +int hts221_set_rate(const hts221_t *dev, const uint8_t rate) +{ + uint8_t reg; + + i2c_acquire(BUS); + if (i2c_read_reg(BUS, ADDR, HTS221_REGS_CTRL_REG1, ®) != 1) { + i2c_release(BUS); + DEBUG("%s: i2c_read_reg HTS221_REGS_CTRL_REG1 failed!\n", DEBUG_FUNC); + return -HTS221_NOBUS; + } + reg |= rate; + DEBUG("hts221_set_rate: %u\n", reg); + if (i2c_write_reg(BUS, ADDR, HTS221_REGS_CTRL_REG1, reg) != 1) { + i2c_release(BUS); + DEBUG("%s: i2c_write_reg HTS221_REGS_CTRL_REG1 failed!\n", DEBUG_FUNC); + return -HTS221_NOBUS; + } + i2c_release(BUS); + + return HTS221_OK; +} + +int hts221_reboot(const hts221_t *dev) +{ + uint8_t reg; + + i2c_acquire(BUS); + reg = HTS221_REGS_CTRL_REG2_BOOT; + if (i2c_write_reg(BUS, ADDR, HTS221_REGS_CTRL_REG2, reg) != 1) { + i2c_release(BUS); + DEBUG("%s: i2c_write_reg HTS221_REGS_CTRL_REG2 failed!\n", DEBUG_FUNC); + return -HTS221_NOBUS; + } + /* loop until HTS221_REGS_CTRL_REG2_BOOT == 0 */ + do { + i2c_read_reg(BUS, ADDR, HTS221_REGS_CTRL_REG2, ®); + } while (reg & HTS221_REGS_CTRL_REG2_BOOT); + i2c_release(BUS); + + return HTS221_OK; +} + +static int _set_power(const hts221_t *dev, const bool active) +{ + uint8_t reg; + + i2c_acquire(BUS); + if (i2c_read_reg(BUS, ADDR, HTS221_REGS_CTRL_REG1, ®) != 1) { + i2c_release(BUS); + DEBUG("%s: i2c_read_reg HTS221_REGS_CTRL_REG1 failed!\n", DEBUG_FUNC); + return -HTS221_NOBUS; + } + if (active) { + reg |= HTS221_REGS_CTRL_REG1_PD_ACTIVE; + } + else { + reg &= ~HTS221_REGS_CTRL_REG1_PD_ACTIVE; + } + if (i2c_write_reg(BUS, ADDR, HTS221_REGS_CTRL_REG1, reg) != 1) { + i2c_release(BUS); + DEBUG("%s: i2c_write_reg HTS221_REGS_CTRL_REG1 failed!\n", DEBUG_FUNC); + return -HTS221_NOBUS; + } + i2c_release(BUS); + + return HTS221_OK; +} + +int hts221_power_on(const hts221_t *dev) +{ + return _set_power(dev, true); +} + +int hts221_power_off(const hts221_t *dev) +{ + return _set_power(dev, false); +} + +int hts221_get_state(const hts221_t *dev) +{ + uint8_t reg; + + i2c_acquire(BUS); + if (i2c_read_reg(BUS, ADDR, HTS221_REGS_STATUS_REG, ®) != 1) { + i2c_release(BUS); + DEBUG("%s: i2c_read_regs failed!\n", DEBUG_FUNC); + return -HTS221_NOBUS; + } + i2c_release(BUS); + + return (int)reg; +} + +int hts221_read_humidity(const hts221_t *dev, uint16_t *val) +{ + uint8_t buf[2]; + + if (!(hts221_get_state(dev) & HTS221_REGS_STATUS_REG_HDA)) { + DEBUG("%s: waiting for data ...\n", DEBUG_FUNC); + while (!(hts221_get_state(dev) & HTS221_REGS_STATUS_REG_HDA)) {} + } + + /* read raw humidity */ + i2c_acquire(BUS); + uint8_t reg = HTS221_REGS_HUMIDITY_OUT_L | 0x80; + if (i2c_read_regs(BUS, ADDR, reg, &buf[0], 2) != 2) { + i2c_release(BUS); + DEBUG("%s: i2c_read_regs failed!\n", DEBUG_FUNC); + return -HTS221_NOBUS; + } + i2c_release(BUS); + DEBUG("%s: buf[0]=%u buf[1]=%u\n", DEBUG_FUNC, buf[0], buf[1]); + int16_t h_t_out = ((uint16_t)buf[1] << 8) | buf[0]; + DEBUG("%s, h_t_out: %" PRIi16 "\n", DEBUG_FUNC, h_t_out); + + /* compute RH [%] value by linear interpolation */ + int32_t tmp32 = (h_t_out - dev->h0_t0_out) * (dev->h1_rh - dev->h0_rh) * 10; + DEBUG("%s, tmp32: %" PRIi32 "\n", DEBUG_FUNC, tmp32); + *val = (tmp32 / (dev->h1_t0_out - dev->h0_t0_out)) + (dev->h0_rh * 10); + /* cut of humidty at 100% */ + if (*val > 1000) { + *val = 1000; + } + DEBUG("%s, val: %" PRIu16 "\n", DEBUG_FUNC, *val); + + return HTS221_OK; +} + +int hts221_read_temperature(const hts221_t *dev, int16_t *val) +{ + uint8_t buf[2]; + + if (!(hts221_get_state(dev) & HTS221_REGS_STATUS_REG_TDA)) { + DEBUG("%s: waiting for data ...\n", DEBUG_FUNC); + while (!(hts221_get_state(dev) & HTS221_REGS_STATUS_REG_TDA)) {} + } + + /* read raw t_out */ + i2c_acquire(BUS); + uint8_t reg = HTS221_REGS_TEMP_OUT_L | 0x80; + if (i2c_read_regs(BUS, ADDR, reg, &buf[0], 2) != 2) { + i2c_release(BUS); + DEBUG("%s: i2c_read_regs failed!\n", DEBUG_FUNC); + return -HTS221_NOBUS; + } + i2c_release(BUS); + DEBUG("%s: buf[0]=%u buf[1]=%u\n", DEBUG_FUNC, buf[0], buf[1]); + int16_t t_out = ((uint16_t)buf[1] << 8) | buf[0]; + DEBUG("%s, t_out: %" PRIi16 "\n", DEBUG_FUNC, t_out); + + /* calculate actual temperature */ + int32_t tmp32 = (t_out - dev->t0_out) * (dev->t1_degc - dev->t0_degc) * 10; + DEBUG("%s, tmp32: %" PRIi32 "\n", DEBUG_FUNC, tmp32); + *val = (tmp32 / (dev->t1_out - dev->t0_out)) + (dev->t0_degc * 10); + DEBUG("%s, val: %" PRIi16 "\n", DEBUG_FUNC, *val); + + return HTS221_OK; +} diff --git a/drivers/hts221/include/hts221_params.h b/drivers/hts221/include/hts221_params.h new file mode 100644 index 0000000000..127a659f9b --- /dev/null +++ b/drivers/hts221/include/hts221_params.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2017 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_hts221 + * + * @{ + * @file + * @brief Default configuration for ST HTS221 devices + * + * @author Sebastian Meiling + */ + +#ifndef HTS221_PARAMS_H +#define HTS221_PARAMS_H + +#include "board.h" +#include "hts221.h" +#include "hts221_regs.h" +#include "saul_reg.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @name Set default configuration parameters for the HTS221 driver + * @{ + */ +#ifndef HTS221_PARAM_I2C +#define HTS221_PARAM_I2C I2C_DEV(0) +#endif +#ifndef HTS221_PARAM_ADDR +#define HTS221_PARAM_ADDR (HTS221_I2C_ADDRESS) +#endif +#ifndef HTS221_PARAM_AVGX +#define HTS221_PARAM_AVGX ((HTS221_REGS_AVGT_16 << HTS221_REGS_AVGT_SHIFT) | \ + HTS221_REGS_AVGH_32) +#endif +#ifndef HTS221_PARAM_RATE +#define HTS221_PARAM_RATE (HTS221_REGS_CTRL_REG1_ODR_12HZ) +#endif +#ifndef HTS221_PARAMS +#define HTS221_PARAMS { .i2c = HTS221_PARAM_I2C, \ + .addr = HTS221_PARAM_ADDR, \ + .avgx = HTS221_PARAM_AVGX, \ + .rate = HTS221_PARAM_RATE } +#endif /* HTS221_PARAMS */ +/**@}*/ + +/** + * @brief HTS221 configuration + */ +static const hts221_params_t hts221_params[] = +{ + HTS221_PARAMS, +}; + +#ifdef __cplusplus +} +#endif + +#endif /* HTS221_PARAMS_H */ +/** @} */ diff --git a/drivers/hts221/include/hts221_regs.h b/drivers/hts221/include/hts221_regs.h new file mode 100644 index 0000000000..d3717892a0 --- /dev/null +++ b/drivers/hts221/include/hts221_regs.h @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2017 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_hts221 + * + * @{ + * @file + * @brief Register definitions for ST HTS221 devices + * + * @author Sebastian Meiling + */ + +#ifndef HTS221_REGS_H +#define HTS221_REGS_H + +#include "board.h" +#include "hts221.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define HTS221_DEVICE_ID (0xBC) +/** + * @name Register Map + * @{ + */ +#define HTS221_REGS_WHO_AM_I (0x0F) +#define HTS221_REGS_AV_CONF (0x10) +#define HTS221_REGS_CTRL_REG1 (0x20) +#define HTS221_REGS_CTRL_REG2 (0x21) +#define HTS221_REGS_CTRL_REG3 (0x22) /**< data ready output signal */ +#define HTS221_REGS_STATUS_REG (0x27) +#define HTS221_REGS_HUMIDITY_OUT_L (0x28) +#define HTS221_REGS_HUMIDITY_OUT_H (0x29) +#define HTS221_REGS_TEMP_OUT_L (0x2A) +#define HTS221_REGS_TEMP_OUT_H (0x2B) +/** @} */ + +/** + * @name Calibration Register Map + * @{ + */ +#define HTS221_REGS_H0_RH_X2 (0x30) +#define HTS221_REGS_H1_RH_X2 (0x31) +#define HTS221_REGS_T0_DEGC_X8 (0x32) +#define HTS221_REGS_T1_DEGC_X8 (0x33) +#define HTS221_REGS_T1_T0_MSB (0x35) +#define HTS221_REGS_H0_T0_OUT_L (0x36) +#define HTS221_REGS_H0_T0_OUT_H (0x37) +#define HTS221_REGS_H1_T0_OUT_L (0x3A) +#define HTS221_REGS_H1_T0_OUT_H (0x3B) +#define HTS221_REGS_T0_OUT_L (0x3C) +#define HTS221_REGS_T0_OUT_H (0x3D) +#define HTS221_REGS_T1_OUT_L (0x3E) +#define HTS221_REGS_T1_OUT_H (0x3F) +/** @} */ + +/** + * @brief Shift for AVG oftemperature configuration set in HTS221_REGS_AV_CONF + * + * Register HTS221_REGS_AV_CONF= [7:6] reserved, [5:3] AVGT2-0, [2:0] AVGH2-0 + */ +#define HTS221_REGS_AVGT_SHIFT (3U) + +/** + * @name Humidity average over number of samples 4 to 512 + * @{ + */ +enum { + HTS221_REGS_AVGH_4 = 0, + HTS221_REGS_AVGH_8, + HTS221_REGS_AVGH_16, + HTS221_REGS_AVGH_32, + HTS221_REGS_AVGH_64, + HTS221_REGS_AVGH_128, + HTS221_REGS_AVGH_256, + HTS221_REGS_AVGH_512 +}; +/** @} */ + +/** + * @name Temperature average over number of samples 2 to 256 + * @{ + */ +enum { + HTS221_REGS_AVGT_2 = 0, + HTS221_REGS_AVGT_4, + HTS221_REGS_AVGT_8, + HTS221_REGS_AVGT_16, + HTS221_REGS_AVGT_32, + HTS221_REGS_AVGT_64, + HTS221_REGS_AVGT_128, + HTS221_REGS_AVGT_256 +}; +/** @} */ + +/** + * @name Config bits of HTS221_REGS_CTRL_REG1 + * @{ + */ +#define HTS221_REGS_CTRL_REG1_PD_ACTIVE (1 << 7) /**< power-down control, set active mode */ +#define HTS221_REGS_CTRL_REG1_BDU (1 << 2) /**< Block data update */ +/** @} */ + +/** + * @brief Output data rate settings, HTS221_REGS_CTRL_REG1[1:0] + */ +enum { + HTS221_REGS_CTRL_REG1_ODR_ONE_SHOT = 0, + HTS221_REGS_CTRL_REG1_ODR_1HZ, + HTS221_REGS_CTRL_REG1_ODR_7HZ, + HTS221_REGS_CTRL_REG1_ODR_12HZ +}; + +/** + * @name Config bits of HTS221_REGS_CTRL_REG2 + * @{ + */ +#define HTS221_REGS_CTRL_REG2_BOOT (1 << 7) /**< Reboot memory content */ +#define HTS221_REGS_CTRL_REG2_HEATER (1 << 1) /**< Heater ON */ +#define HTS221_REGS_CTRL_REG2_OS_EN (1 << 2) /**< One-shot enable, start new dataset */ +/** @} */ + +/** + * @name Data ready config bits of HTS221_REGS_CTRL_REG3 + * @{ + */ +#define HTS221_REGS_CTRL_REG3_DRDY_HL (1 << 7) /**< Data Ready output signal active high, low */ +#define HTS221_REGS_CTRL_REG3_PP_OD (1 << 6) /**< Push-pull / Open Drain selection on pin 3 */ +#define HTS221_REGS_CTRL_REG3_DRDY_EN (1 << 2) /**< Data Ready enable */ +/** @} */ + +/** + * @name Status bits to check data availability, HTS221_REGS_STATUS_REG[1:0] + * @{ + */ +#define HTS221_REGS_STATUS_REG_TDA (1 << 0) /**< temperature data available */ +#define HTS221_REGS_STATUS_REG_HDA (1 << 1) /**< humidity data available */ +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* HTS221_REGS_H */ +/** @} */ diff --git a/drivers/include/hts221.h b/drivers/include/hts221.h new file mode 100644 index 0000000000..5bb2c5fd6d --- /dev/null +++ b/drivers/include/hts221.h @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2017 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. + */ + +/** + * @defgroup drivers_hts221 ST HTS221 digital Humidity Sensor + * @ingroup drivers_sensors + * @brief Driver for the ST HTS221 digital Humidity Sensor + * + * @{ + * @file + * @brief Interface definition for the ST HTS221 driver + * + * @author Sebastian Meiling + */ + +#ifndef HTS221_H +#define HTS221_H + +#include + +#include "periph/i2c.h" +#include "hts221_regs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Default I2C bus address (7 Bit) of HTS221 devices + */ +#ifndef HTS221_I2C_ADDRESS +#define HTS221_I2C_ADDRESS (0x5F) +#endif + +/** + * @brief Parameters needed for device initialization + */ +typedef struct { + i2c_t i2c; /**< bus the device is connected to */ + uint8_t addr; /**< address on that bus */ + uint8_t avgx; /**< average sampling of humidity and temperature */ + uint8_t rate; /**< output data rate */ +} hts221_params_t; + +/** + * @brief Return values and error codes + */ +enum { + HTS221_OK = 0, + HTS221_ERROR, + HTS221_NOBUS, + HTS221_NODEV, +}; + +/** + * @brief Device descriptor for HTS221 sensors + */ +typedef struct { + hts221_params_t p; /**< Configuration parameters */ + int16_t h0_rh; /**< lower humitidy reference */ + int16_t h1_rh; /**< upper humitidy reference */ + int16_t h0_t0_out; /**< lower humitidy to temperature reference */ + int16_t h1_t0_out; /**< upper humitidy to temperature reference */ + int16_t t0_degc; /**< lower temperature reference in degC */ + int16_t t1_degc; /**< upper temperature reference in degC */ + int16_t t0_out; /**< lower temperature reference raw value */ + int16_t t1_out; /**< upper temperature reference raw value */ +} hts221_t; + +/** + * @brief Initialize the given HTS221 device + * + * @param[out] dev device descriptor of sensor to initialize + * @param[in] params configuration parameters + * + * @return HTS221_OK on success + * @return HTS221_NOBUS if initialization of I2C bus fails + * @return HTS221_NODEV if no HTS221 device found on bus + */ +int hts221_init(hts221_t *dev, const hts221_params_t *params); + +/** + * @brief Reboot device and reload base configuration + * + * @param[in] dev device descriptor of sensor + * + * @return 0 on success, or error otherwise + */ +int hts221_reboot(const hts221_t *dev); + +/** + * @brief Set device to continues measurements + * + * @param[in] dev device descriptor of sensor + * + * @return 0 on success, or error otherwise + */ +int hts221_one_shot(const hts221_t *dev); + +/** + * @brief Set device to continues measurements + * + * @param[in] dev device descriptor of sensor + * @param[in] rate conversion rate for continues mode + * + * @return 0 on success, or error otherwise + */ +int hts221_set_rate(const hts221_t *dev, const uint8_t rate); + +/** + * @brief Set device to active + * + * @param[in] dev device descriptor of sensor + * + * @return 0 on success, or error otherwise + */ +int hts221_power_on(const hts221_t *dev); + +/** + * @brief Set device to power down + * + * @param[in] dev device descriptor of sensor + * + * @return 0 on success, or error otherwise + */ +int hts221_power_off(const hts221_t *dev); + +/** + * @brief Set device to power down + * + * @param[in] dev device descriptor of sensor + * + * @return >=0 on success + * @return -HTS221_NOBUS on error + */ +int hts221_get_state(const hts221_t *dev); + +/** + * @brief Reading humidity and temperature + * + * @param[in] dev device descriptor of sensor + * @param[out] val humidity [in 10 * percent relative] + * + * @return 0 on success, or error otherwise + */ +int hts221_read_humidity(const hts221_t *dev, uint16_t *val); + +/** + * @brief Reading humidity and temperature + * + * @param[in] dev device descriptor of sensor + * @param[out] val temperature [in 100 * degree centigrade] + * + * @return 0 on success, or error otherwise + */ +int hts221_read_temperature(const hts221_t *dev, int16_t *val); + +#ifdef __cplusplus +} +#endif + +#endif /* HTS221_H */ +/** @} */