From 9781ea99ccf0d94cdaba54d390fb92119b7a1a32 Mon Sep 17 00:00:00 2001 From: Joakim Gebart Date: Thu, 2 Jul 2015 11:51:08 +0200 Subject: [PATCH 1/2] drivers/hih6310: Initial commit of HIH6310 driver Honeywell HumidIcon Digital Humidity/Temperature Sensors: HIH-6130/6131 Series Only basic humidity and temperature measurement support is implemented. Missing: - Alarm interrupts - Command mode (reconfigure i2c address, alarm levels, alarm polarity, custom ID) --- Makefile.dep | 4 ++ drivers/hih6130/Makefile | 3 + drivers/hih6130/hih6130.c | 140 ++++++++++++++++++++++++++++++++++++++ drivers/include/hih6130.h | 70 +++++++++++++++++++ 4 files changed, 217 insertions(+) create mode 100644 drivers/hih6130/Makefile create mode 100644 drivers/hih6130/hih6130.c create mode 100644 drivers/include/hih6130.h diff --git a/Makefile.dep b/Makefile.dep index 2a4721a645..cdf9a4744b 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -330,3 +330,7 @@ endif ifneq (,$(filter newlib,$(USEMODULE))) USEMODULE += uart_stdio endif + +ifneq (,$(filter hih6130,$(USEMODULE))) + USEMODULE += vtimer +endif diff --git a/drivers/hih6130/Makefile b/drivers/hih6130/Makefile new file mode 100644 index 0000000000..85e928e184 --- /dev/null +++ b/drivers/hih6130/Makefile @@ -0,0 +1,3 @@ +MODULE = hih6130 + +include $(RIOTBASE)/Makefile.base diff --git a/drivers/hih6130/hih6130.c b/drivers/hih6130/hih6130.c new file mode 100644 index 0000000000..8050e74305 --- /dev/null +++ b/drivers/hih6130/hih6130.c @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2015 Eistec AB + * + * 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 driver_hih6130 + * @{ + * + * @file + * @brief Device driver implementation for Honeywell HumidIcon Digital + * Humidity/Temperature Sensors: HIH-6130/6131 Series + * + * @author Joakim Gebart + * + * @} + */ + +#include +#include + +#include "hih6130.h" +#include "periph/i2c.h" +#include "timex.h" +#include "vtimer.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +/* Humidity is stored in the first 2 bytes of data */ +#define HIH6130_HUMIDITY_DATA_LENGTH (2) +/* Humidity + temperature data is 4 bytes long */ +#define HIH6130_FULL_DATA_LENGTH (4) +/* Bit mask for the status bits in the first byte transferred */ +#define HIH6130_STATUS_MASK (0xc0) +/* Bit mask for the humidity data */ +#define HIH6130_HUMIDITY_MASK (0x3fff) +/* Temperature data is left adjusted within the word */ +#define HIH6130_TEMPERATURE_SHIFT (2) + +enum { + HIH6130_STATUS_OK = 0x00, + /** + * stale data: data that has already been fetched since the last measurement + * cycle, or data fetched before the first measurement has been completed. + */ + HIH6130_STATUS_STALE_DATA = 0x40, + HIH6130_STATUS_COMMAND_MODE = 0x80, + HIH6130_STATUS_DIAGNOSTIC = 0xc0, +}; + +/** @brief Delay between requesting a measurement and data becoming ready */ +static const timex_t measurement_delay = { + .seconds = 0, .microseconds = 50 * MS_IN_USEC, }; + +/** @brief Trigger a new measurement on the sensor */ +static inline int hih6130_measurement_request(hih6130_t *dev) +{ + i2c_acquire(dev->i2c); + + /* An empty write request triggers a new measurement */ + if (i2c_write_bytes(dev->i2c, dev->addr, (char *)NULL, 0) < 0) { + i2c_release(dev->i2c); + return -1; + } + + i2c_release(dev->i2c); + + return 0; +} + +void hih6130_init(hih6130_t *dev, i2c_t i2c, uint8_t address) +{ + /* write device descriptor */ + dev->i2c = i2c; + dev->addr = address; +} + +static inline int hih6130_get_humidity_temperature_raw(hih6130_t *dev, uint16_t *humidity_raw, uint16_t *temperature_raw) +{ + int status; + uint8_t buf[HIH6130_FULL_DATA_LENGTH]; + + i2c_acquire(dev->i2c); + + if (i2c_read_bytes(dev->i2c, dev->addr, (char*)&buf[0], sizeof(buf)) != sizeof(buf)) { + i2c_release(dev->i2c); + return -1; + } + + i2c_release(dev->i2c); + + /* data is in big-endian format, with status bits in the first byte. */ + switch (buf[0] & HIH6130_STATUS_MASK) { + case HIH6130_STATUS_OK: + status = 0; + break; + case HIH6130_STATUS_STALE_DATA: + status = 1; + break; + default: + return -2; + } + + *humidity_raw = ((buf[0] << 8) | buf[1]) & HIH6130_HUMIDITY_MASK; + *temperature_raw = (((buf[2] << 8) | buf[3]) >> HIH6130_TEMPERATURE_SHIFT); + + return status; +} + +int hih6130_get_humidity_temperature_float(hih6130_t *dev, + float *relative_humidity_percent, float *temperature_celsius) +{ + uint16_t hum_raw, temp_raw; + int status; + + if (hih6130_measurement_request(dev) != 0) { + return -1; + } + + vtimer_sleep(measurement_delay); + + status = hih6130_get_humidity_temperature_raw(dev, &hum_raw, &temp_raw); + + if (status < 0) { + return -1; + } + + if (relative_humidity_percent != NULL) { + *relative_humidity_percent = hum_raw * (100.f / 16383.f); + } + if (temperature_celsius != NULL) { + *temperature_celsius = temp_raw * (165.f / 16383.f) - 40.f; + } + + return status; +} diff --git a/drivers/include/hih6130.h b/drivers/include/hih6130.h new file mode 100644 index 0000000000..92c7780f03 --- /dev/null +++ b/drivers/include/hih6130.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2015 Eistec AB + * + * 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 driver_hih6130 HIH6130 humidity and temperature sensor + * @ingroup drivers + * @brief Device driver for Honeywell HumidIcon Digital + * Humidity/Temperature Sensors: HIH-6130/6131 Series + * @{ + * + * @file + * @brief Device driver for Honeywell HumidIcon Digital + * Humidity/Temperature Sensors: HIH-6130/6131 Series + * + * @author Joakim Gebart + */ + +#ifndef HIH6130_H_ +#define HIH6130_H_ + +#include + +#include "periph/i2c.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Device descriptor for HIH6130/HIH6131 sensors + */ +typedef struct { + i2c_t i2c; /**< I2C device the sensor is connected to */ + uint8_t addr; /**< the slave address of the sensor on the I2C bus */ +} hih6130_t; + +/** + * @brief Initialize a sensor + * + * @param[out] dev device descriptor of sensor to initialize + * @param[in] i2c I2C bus the sensor is connected to + * @param[in] address I2C slave address of the sensor + */ +void hih6130_init(hih6130_t *dev, i2c_t i2c, uint8_t address); + +/** + * @brief Read humidity and temperature from sensor and convert to floating-point + * + * @param[in] dev Sensor device descriptor + * @param[out] relative_humidity_percent Measured relative humidity in percent + * @param[out] temperature_celsius Measured temperature in degrees Celsius + * + * @return 0 on success + * @return -1 on error + * @return 1 if data is stale + */ +int hih6130_get_humidity_temperature_float(hih6130_t *dev, + float *relative_humidity_percent, float *temperature_celsius); + +#ifdef __cplusplus +} +#endif + +#endif /* HIH6130_H_ */ +/** @} */ From d34af3cb0e0313157b782615c1e2b89be063d948 Mon Sep 17 00:00:00 2001 From: Joakim Gebart Date: Thu, 2 Jul 2015 12:09:16 +0200 Subject: [PATCH 2/2] tests/driver_hih6130: test application for drivers/hih6130 --- tests/driver_hih6130/Makefile | 22 +++++++++ tests/driver_hih6130/README.md | 7 +++ tests/driver_hih6130/main.c | 81 ++++++++++++++++++++++++++++++++++ 3 files changed, 110 insertions(+) create mode 100644 tests/driver_hih6130/Makefile create mode 100644 tests/driver_hih6130/README.md create mode 100644 tests/driver_hih6130/main.c diff --git a/tests/driver_hih6130/Makefile b/tests/driver_hih6130/Makefile new file mode 100644 index 0000000000..eecfc85e9c --- /dev/null +++ b/tests/driver_hih6130/Makefile @@ -0,0 +1,22 @@ +APPLICATION = driver_hih6130 +include ../Makefile.tests_common + +FEATURES_REQUIRED = periph_i2c + +USEMODULE += hih6130 +USEMODULE += vtimer + +ifneq (,$(TEST_HIH6130_I2C)) + CFLAGS += -DTEST_HIH6130_I2C=$(TEST_HIH6130_I2C) +else + # set arbitrary default + CFLAGS += -DTEST_HIH6130_I2C=I2C_0 +endif +ifneq (,$(TEST_HIH6130_ADDR)) + CFLAGS += -DTEST_HIH6130_ADDR=$(TEST_HIH6130_ADDR) +else + # factory default address + CFLAGS += -DTEST_HIH6130_ADDR=0x27 +endif + +include $(RIOTBASE)/Makefile.include diff --git a/tests/driver_hih6130/README.md b/tests/driver_hih6130/README.md new file mode 100644 index 0000000000..fc81bd9124 --- /dev/null +++ b/tests/driver_hih6130/README.md @@ -0,0 +1,7 @@ +# About +This is a manual test application for the HIH6130 humidity and temperature sensor. + +# Usage + +After initialization, the sensor reads the measurement values every 100ms +and prints them to the STDOUT. diff --git a/tests/driver_hih6130/main.c b/tests/driver_hih6130/main.c new file mode 100644 index 0000000000..7585ab21b1 --- /dev/null +++ b/tests/driver_hih6130/main.c @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2015 Eistec AB + * + * 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 HIH6130 sensor driver + * + * @author Joakim Gebart + * + * @} + */ + +#ifndef TEST_HIH6130_I2C +#error "TEST_HIH6130_I2C not defined" +#endif +#ifndef TEST_HIH6130_ADDR +#error "TEST_HIH6130_ADDR not defined" +#endif + +#include +#include +#include + +#include "vtimer.h" +#include "hih6130.h" + +#define SLEEP (100 * 1000U) + +int main(void) +{ + hih6130_t dev; + + puts("HIH6130 sensor driver test application\n"); + printf("Initializing I2C_%i... ", TEST_HIH6130_I2C); + if (i2c_init_master(TEST_HIH6130_I2C, I2C_SPEED_FAST) < 0) { + puts("[Failed]"); + return -1; + } + puts("[OK]"); + + printf("Initializing HIH6130 sensor at I2C_%i, address 0x%02x... ", + TEST_HIH6130_I2C, TEST_HIH6130_ADDR); + hih6130_init(&dev, TEST_HIH6130_I2C, TEST_HIH6130_ADDR); + puts("[OK]"); + + while (1) { + float hum = 0.f; + float temp = 0.f; + int status; + float integral = 0.f; + float fractional; + + vtimer_usleep(SLEEP); + + status = hih6130_get_humidity_temperature_float(&dev, &hum, &temp); + if (status < 0) { + printf("Communication error: %d\n", status); + continue; + } else if (status == 1) { + puts("Stale values"); + } + /* Several platforms usually build with nano.specs, (without float printf) */ + /* Split value into two integer parts for printing. */ + fractional = modff(hum, &integral); + printf("humidity: %4d.%04u %%", + (int)integral, (unsigned int)abs(fractional * 10000.f)); + fractional = modff(temp, &integral); + printf(" temperature: %4d.%04u C\n", + (int)integral, (unsigned int)abs(fractional * 10000.f)); + } + + return 0; +}