1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

Merge pull request #10750 from keestux/add-driver-sht2x

drivers: add support for SHT2x (I2C temp and humidity sensor)
This commit is contained in:
Peter Kietzmann 2019-02-06 17:25:50 +01:00 committed by GitHub
commit 56bf778156
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 1069 additions and 0 deletions

View File

@ -408,6 +408,11 @@ ifneq (,$(filter sht1%,$(USEMODULE)))
USEMODULE += xtimer
endif
ifneq (,$(filter sht2x,$(USEMODULE)))
USEMODULE += xtimer
FEATURES_REQUIRED += periph_i2c
endif
ifneq (,$(filter sht3x,$(USEMODULE)))
USEMODULE += xtimer
FEATURES_REQUIRED += periph_i2c

View File

@ -218,6 +218,10 @@ ifneq (,$(filter sdcard_spi,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/sdcard_spi/include
endif
ifneq (,$(filter sht2x,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/sht2x/include
endif
ifneq (,$(filter sht3x,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/sht3x/include
endif

197
drivers/include/sht2x.h Normal file
View File

@ -0,0 +1,197 @@
/*
* Copyright (C) 2016,2017,2018 Kees Bakker, SODAQ
* Copyright (C) 2017 George Psimenos
* Copyright (C) 2018 Steffen Robertz
*
* 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_sht2x SHT2X
* @ingroup drivers_sensors
* @brief Device driver interface for the SHT2X sensor
* @{
*
* @file
* @brief Device driver implementation for the SHT2x temperature and
* humidity sensor.
*
* @author Kees Bakker <kees@sodaq.com>
* @author George Psimenos <gp7g14@soton.ac.uk>
* @author Steffen Robertz <steffen.robertz@rwth-aachen.de>
*/
#ifndef SHT2X_H
#define SHT2X_H
#include <stdint.h>
#include <stdbool.h>
#include "periph/i2c.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Status and error return codes
*/
enum {
SHT2X_OK = 0, /**< everything was fine */
SHT2X_ERR_I2C = -1, /**< error initializing the I2C bus */
SHT2X_ERR_NODEV = -2, /**< did not detect SHT2x */
SHT2X_ERR_NOCAL = -3, /**< could not read calibration data */
SHT2X_ERR_I2C_READ = -4, /**< I2C read error */
SHT2X_ERR_TIMEDOUT = -5, /**< timed out */
SHT2X_ERR_CRC = -6, /**< CRC error */
SHT2X_ERR_USERREG = -7, /**< cannot write User Reg */
SHT2X_ERR_RES = -8, /**< invalid resolution */
SHT2X_ERR_OTHER = -999, /**< fatal error */
};
/**
* @brief Available resolutions
*
* @details The values represent bits 7 and 0 in the User Register
*/
typedef enum {
SHT2X_RES_12_14BIT = 0x00, /**< RH=12bit, T=14bit */
SHT2X_RES_8_12BIT = 0x01, /**< RH= 8bit, T=12bit */
SHT2X_RES_10_13BIT = 0x80, /**< RH=10bit, T=13bit */
SHT2X_RES_11_11BIT = 0x81, /**< RH=11bit, T=11bit */
} sht2x_res_t;
/**
* @brief Available Measuring modes
*/
typedef enum {
SHT2X_MEASURE_MODE_HOLD = 0, /**< trigger measurement, hold master */
SHT2X_MEASURE_MODE_NO_HOLD = 1 /**< trigger measurement, no hold master (i.e. poll) */
} sht2x_measure_mode_t;
/**
* @brief User register masks
* @details Notice that the values of @c sht2x_res_t must only have the
* bits in @c SHT2X_USER_RESOLUTION_MASK.
* @{
*/
#define SHT2X_USER_RESOLUTION_MASK 0x81
#define SHT2X_USER_EOB_MASK 0x40
#define SHT2X_USER_HEATER_MASK 0x04
#define SHT2X_USER_RESERVED_MASK 0x38
#define SHT2X_USER_OTP_MASK 0x02
/** @} */
/**
* @brief Device initialization parameters
*/
typedef struct {
i2c_t i2c_dev; /**< I2C device */
uint8_t i2c_addr; /**< I2C address */
sht2x_res_t resolution; /**< resolution bits RH/temp */
sht2x_measure_mode_t measure_mode; /**< measurement mode used */
bool is_crc_enabled; /**< do CRC or not */
} sht2x_params_t;
/**
* @brief Device descriptor for the SHT2X sensor
*/
typedef struct {
sht2x_params_t params; /**< Device Parameters */
} sht2x_t;
/**
* @brief Initialize the given SHT2X device
*
* @param[out] dev Initialized device descriptor of SHT2X device
* @param[in] params The parameters for the SHT2x device
*
* @return SHT2X_OK on success
* @return SHT2X_ERR_I2C if given I2C is not enabled in board config
* @return SHT2X_ERR_RES invalid resolution
* @return SHT2X_ERR_USERREG error writing User Register
* @return errors returned by sht2x_write_userreg or sht2x_read_userreg
*/
int sht2x_init(sht2x_t* dev, const sht2x_params_t* params);
/**
* @brief Reset the SHT2X device
*
* @param[in] dev Device descriptor of SHT2X device to read from
*
* @return SHT2X_OK on success
* @return SHT2X_ERR_I2C if given I2C is not enabled in board config
*/
int sht2x_reset(sht2x_t* dev);
/**
* @brief Read temperature value from the given SHT2X device, returned in
* centi °C
*
* @details Notice that this function will sleep (max 66 ms) when the
* @a measure_mode is set to @a SHT2X_MEASURE_MODE_NO_HOLD.
*
* @param[in] dev Device descriptor of SHT2X device to read from
*
* @returns The temperature in centi Celsius. In case of an error
* it returns INT16_MIN.
*/
int16_t sht2x_read_temperature(const sht2x_t* dev);
/**
* @brief Read humidity value from the given SHT2X device, returned in
* centi %RH
*
* @details Notice that this function will sleep (max 22 ms) when the
* @a measure_mode is set to @a SHT2X_MEASURE_MODE_NO_HOLD.
*
* @param[in] dev Device descriptor of SHT2X device to read from
*
* @returns Humidity in centi %RH (i.e. the percentage times 100).
* In case of an error it returns 0 (i.e. an unrealistic value).
*/
uint16_t sht2x_read_humidity(const sht2x_t *dev);
/**
* @brief Read identification code from the given SHT2X device
*
* @param[in] dev Device descriptor of SHT2X device to read from
* @param[out] buffer Buffer to write the identification code to
* @param[in] buflen The size of @p buffer
*
* @return >= 0 on success, number of bytes read
* @return SHT2X_ERR_CRC in case of a CRC mismatch
* @return <0 errors returned by i2c_read_regs
*/
int sht2x_read_ident(const sht2x_t *dev, uint8_t *buffer, size_t buflen);
/**
* @brief Read User Register from the given SHT2X device
*
* @param[in] dev Device descriptor of SHT2X device to read from
* @param[out] userreg The value of User Register
*
* @return SHT2X_OK on success
* @return SHT2X_ERR_I2C if given I2C is not enabled in board config
* @return SHT2X_ERR_OTHER if NULL pointer was given for @p buffer
*/
int sht2x_read_userreg(const sht2x_t *dev, uint8_t *userreg);
/**
* @brief Write User Register to the given SHT2X device
*
* @param[in] dev Device descriptor of SHT2X device to read from
* @param[in] userreg The value of User Register
*
* @return SHT2X_OK on success
* @return SHT2X_ERR_I2C if given I2C is not enabled in board config
*/
int sht2x_write_userreg(const sht2x_t *dev, uint8_t userreg);
#ifdef __cplusplus
}
#endif
#endif /* SHT2X_H */
/** @} */

1
drivers/sht2x/Makefile Normal file
View File

@ -0,0 +1 @@
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1,99 @@
/*
* Copyright (C) 2016,2017,2018 Kees Bakker, SODAQ
* Copyright (C) 2017 George Psimenos
* Copyright (C) 2018 Steffen Robertz
*
* 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_sht2x
*
* @{
* @file
* @brief Default configuration for SHT2X
*
* @author Kees Bakker <kees@sodaq.com>
* @author George Psimenos <gp7g14@soton.ac.uk>
* @author Steffen Robertz <steffen.robertz@rwth-aachen.de>
*/
#ifndef SHT2X_PARAMS_H
#define SHT2X_PARAMS_H
#include "sht2x.h"
#include "saul_reg.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Set default configuration parameters for the SHT2X
* @{
*/
#ifndef SHT2X_PARAM_I2C_DEV
#define SHT2X_PARAM_I2C_DEV (I2C_DEV(0))
#endif
#ifndef SHT2X_PARAM_I2C_ADDR
#define SHT2X_PARAM_I2C_ADDR (0x40)
#endif
#ifndef SHT2X_PARAM_RESOLUTION
#define SHT2X_PARAM_RESOLUTION (SHT2X_RES_12_14BIT)
#endif
#ifndef SHT2X_PARAM_MEASURE_MODE
#define SHT2X_PARAM_MEASURE_MODE (SHT2X_MEASURE_MODE_HOLD)
#endif
#ifndef SHT2X_PARAM_CRC_MODE
#define SHT2X_PARAM_CRC_MODE (1)
#endif
#define SHT2X_PARAMS_DEFAULT {.i2c_dev = SHT2X_PARAM_I2C_DEV, \
.i2c_addr = SHT2X_PARAM_I2C_ADDR, \
.resolution = SHT2X_PARAM_RESOLUTION, \
.measure_mode = SHT2X_PARAM_MEASURE_MODE, \
.is_crc_enabled = SHT2X_PARAM_CRC_MODE, \
}
#ifndef SHT2X_SAUL_INFO
#define SHT2X_SAUL_INFO { .name = "sht2x" }
#endif
/**@}*/
/**
* @brief Configure SHT2X
*/
static const sht2x_params_t sht2x_params[] =
{
#ifdef SHT2X_PARAMS_BOARD
SHT2X_PARAMS_BOARD,
#else
SHT2X_PARAMS_DEFAULT,
#endif
};
/**
* @brief Get the number of configured SHT2X devices
*/
#define SHT2X_NUMOF (sizeof(sht2x_params) / sizeof(sht2x_params[0]))
/**
* @brief Configuration details of SAUL registry entries
*
* This array contains static details of the sensors
* for each device. Please be aware that the indexes are used in
* auto_init_sht2x, so make sure the indexes match.
*/
static const saul_reg_info_t sht2x_saul_reg_info[SHT2X_NUMOF] =
{
SHT2X_SAUL_INFO
};
#ifdef __cplusplus
}
#endif
#endif /* SHT2X_PARAMS_H */
/** @} */

475
drivers/sht2x/sht2x.c Normal file
View File

@ -0,0 +1,475 @@
/*
* Copyright (C) 2016,2017,2018 Kees Bakker, SODAQ
* Copyright (C) 2017 George Psimenos
* Copyright (C) 2018 Steffen Robertz
*
* 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_sht2x
* @{
*
* @file
* @brief Device driver implementation for the SHT2x temperature and
* humidity sensor.
*
* @author Kees Bakker <kees@sodaq.com>
* @author George Psimenos <gp7g14@soton.ac.uk>
* @author Steffen Robertz <steffen.robertz@rwth-aachen.de>
*
* @}
*/
#include <math.h>
#include "log.h"
#include "sht2x.h"
#include "sht2x_params.h"
#include "periph/i2c.h"
#include "xtimer.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
/**
* @brief The number of retries when doing a polled measurement
*/
#define MAX_RETRIES 20
/**
* @brief A few helper macros
*/
#define _BUS (dev->params.i2c_dev)
#define _ADDR (dev->params.i2c_addr)
typedef enum {
temp_hold_cmd = 0xE3, /**< trigger temp measurement, hold master */
hum_hold_cmd = 0xE5, /**< trigger humidity measurement, hold master */
write_user_cmd = 0xE6, /**< write user register */
read_user_cmd = 0xE7, /**< read user register */
temp_no_hold_cmd = 0xF3, /**< trigger temp measurement, no hold master (poll) */
hum_no_hold_cmd = 0xF5, /**< trigger humidity measurement, no hold master (poll) */
soft_reset_cmd = 0xFE, /**< soft reset */
} cmd_t;
typedef enum {
SHT2X_MEASURE_TEMP,
SHT2X_MEASURE_RH,
} measure_type_t;
/**
* @brief Register addresses to read SHT2x Identification Code.
*/
static const uint16_t first_mem_addr = 0x0FFA;
static const uint16_t second_mem_addr = 0xC9FC;
static int read_sensor(const sht2x_t* dev, cmd_t command, uint16_t *val);
static int read_sensor_poll(const sht2x_t* dev, cmd_t command, uint16_t *val);
static uint8_t sht2x_checkcrc(uint8_t data[], uint8_t nbrOfBytes, uint8_t checksum);
static void sleep_during_temp_measurement(sht2x_res_t res);
static void sleep_during_hum_measurement(sht2x_res_t resolution);
/*---------------------------------------------------------------------------*
* SHT2x Core API *
*---------------------------------------------------------------------------*/
int sht2x_init(sht2x_t* dev, const sht2x_params_t* params)
{
int i2c_result;
dev->params = *params;
if (dev->params.resolution != SHT2X_RES_12_14BIT &&
dev->params.resolution != SHT2X_RES_8_12BIT &&
dev->params.resolution != SHT2X_RES_10_13BIT &&
dev->params.resolution != SHT2X_RES_11_11BIT) {
return SHT2X_ERR_RES;
}
i2c_result = sht2x_reset(dev);
if (i2c_result != SHT2X_OK) {
return SHT2X_ERR_I2C;
}
/* wait 15 ms for device to reset */
xtimer_usleep(15 * US_PER_MS);
uint8_t userreg;
uint8_t userreg2;
i2c_result = sht2x_read_userreg(dev, &userreg);
if (i2c_result != SHT2X_OK) {
return i2c_result;
}
DEBUG("[SHT2x] User Register=%02x\n", userreg);
if ((userreg & SHT2X_USER_RESOLUTION_MASK) != (uint8_t)dev->params.resolution) {
userreg &= ~SHT2X_USER_RESOLUTION_MASK;
userreg |= (uint8_t)dev->params.resolution;
i2c_result = sht2x_write_userreg(dev, userreg);
if (i2c_result != SHT2X_OK) {
return i2c_result;
}
i2c_result = sht2x_read_userreg(dev, &userreg2);
if (i2c_result != SHT2X_OK) {
return i2c_result;
}
DEBUG("[SHT2x] New User Register=%02x\n", userreg2);
if (userreg != userreg2) {
return SHT2X_ERR_USERREG;
}
}
return SHT2X_OK;
}
int sht2x_reset(sht2x_t* dev)
{
int i2c_result;
cmd_t command = soft_reset_cmd;
/* Acquire exclusive access */
i2c_acquire(_BUS);
DEBUG("[SHT2x] write command: addr=%02x cmd=%02x\n", _ADDR, (uint8_t)command);
i2c_result = i2c_write_byte(_BUS, _ADDR, (uint8_t)command, 0);
i2c_release(_BUS);
if (i2c_result != 0) {
return SHT2X_ERR_I2C;
}
return SHT2X_OK;
}
/*
* Returns temperature in centi DegC.
*/
int16_t sht2x_read_temperature(const sht2x_t* dev)
{
uint16_t raw_value;
int i2c_result;
if (dev->params.measure_mode == SHT2X_MEASURE_MODE_NO_HOLD) {
i2c_result = read_sensor_poll(dev, temp_no_hold_cmd, &raw_value);
} else {
i2c_result = read_sensor(dev, temp_hold_cmd, &raw_value);
}
if (i2c_result != SHT2X_OK) {
return INT16_MIN;
}
return (-46.85 + 175.72 / 65536.0 * raw_value) * 100;
}
/*
* Returns humidity in centi %RH (i.e. the percentage times 100).
*/
uint16_t sht2x_read_humidity(const sht2x_t *dev)
{
uint16_t raw_value;
int i2c_result;
if (dev->params.measure_mode == SHT2X_MEASURE_MODE_NO_HOLD) {
i2c_result = read_sensor_poll(dev, hum_no_hold_cmd, &raw_value);
} else {
i2c_result = read_sensor(dev, hum_hold_cmd, &raw_value);
}
if (i2c_result != SHT2X_OK) {
return 0;
}
return 100 * (-6.0 + 125.0 / 65536.0 * raw_value);
}
static size_t _sht2x_add_ident_byte(uint8_t * buffer, size_t buflen, uint8_t b, size_t ix)
{
if (ix < buflen) {
buffer[ix++] = b;
}
return ix;
}
int sht2x_read_ident(const sht2x_t *dev, uint8_t * buffer, size_t buflen)
{
uint8_t data1[8]; /* SNB_3, CRC, SNB_2, CRC, SNB_1, CRC, SNB_0, CRC */
uint8_t data2[6]; /* SNC_1, SNC_0, CRC, SNA_1, SNA_0, CRC */
size_t ix;
int res;
i2c_acquire(_BUS);
res = i2c_read_regs(_BUS, _ADDR,
first_mem_addr, data1, sizeof(data1), I2C_REG16);
i2c_release(_BUS);
if (res < 0) {
return res;
}
DEBUG("[SHT2x] ident (1): %02x %02x %02x %02x\n", data1[0], data1[1], data1[2], data1[3]);
DEBUG("[SHT2x] ident (1): %02x %02x %02x %02x\n", data1[4], data1[5], data1[6], data1[7]);
for (size_t ix = 0; ix < sizeof(data1); ix += 2) {
if (sht2x_checkcrc(&data1[ix], 1, data1[ix + 1]) != 0) {
DEBUG("[SHT2x] checksum error first (ix=%d)\n", ix);
return SHT2X_ERR_CRC;
}
}
i2c_acquire(_BUS);
res = i2c_read_regs(_BUS, _ADDR,
second_mem_addr, data2, sizeof(data2), I2C_REG16);
i2c_release(_BUS);
if (res < 0) {
return res;
}
DEBUG("[SHT2x] ident (2): %02x %02x %02x\n", data2[0], data2[1], data2[2]);
DEBUG("[SHT2x] ident (2): %02x %02x %02x\n", data2[3], data2[4], data2[5]);
for (size_t ix = 0; ix < sizeof(data2); ix += 3) {
if (sht2x_checkcrc(&data2[ix], 2, data2[ix + 2]) != 0) {
DEBUG("[SHT2x] checksum error, second (ix=%d)\n", ix);
return SHT2X_ERR_CRC;
}
}
/*
* See Sensirion document Electronic_Identification_Code_SHT2x_V1-1_C2
*
* first memory address:
* SNB_3, CRC, SNB_2, CRC, SNB_1, CRC, SNB_0, CRC,
* Second memory address:
* SNC_1, SNC_0, CRC, SNA_1, SNA_0, CRC
*
* To assemble the Identification code:
* SNA_1, SNA_0, SNB_3, SNB_2, SNB_1, SNB_0, SNC_1, SNC_0
*/
if (buffer == NULL) {
return 0;
}
ix = 0;
ix = _sht2x_add_ident_byte(buffer, buflen, data2[3], ix);
ix = _sht2x_add_ident_byte(buffer, buflen, data2[4], ix);
ix = _sht2x_add_ident_byte(buffer, buflen, data1[0], ix);
ix = _sht2x_add_ident_byte(buffer, buflen, data1[2], ix);
ix = _sht2x_add_ident_byte(buffer, buflen, data1[4], ix);
ix = _sht2x_add_ident_byte(buffer, buflen, data1[6], ix);
ix = _sht2x_add_ident_byte(buffer, buflen, data2[0], ix);
ix = _sht2x_add_ident_byte(buffer, buflen, data2[1], ix);
return ix;
}
int sht2x_read_userreg(const sht2x_t *dev, uint8_t * userreg)
{
cmd_t command = read_user_cmd;
if (userreg) {
int i2c_result;
DEBUG("[SHT2x] read command: addr=%02x cmd=%02x\n", _ADDR, (uint8_t)command);
i2c_acquire(_BUS);
i2c_result = i2c_read_reg(_BUS, _ADDR, (uint8_t)command, userreg, 0);
i2c_release(_BUS);
if (i2c_result != 0) {
return SHT2X_ERR_I2C_READ;
}
} else {
return SHT2X_ERR_OTHER;
}
return SHT2X_OK;
}
int sht2x_write_userreg(const sht2x_t *dev, uint8_t userreg)
{
cmd_t command = write_user_cmd;
int i2c_result;
DEBUG("[SHT2x] write command: addr=%02x cmd=%02x\n", _ADDR, (uint8_t)command);
i2c_acquire(_BUS);
i2c_result = i2c_write_reg(_BUS, _ADDR, (uint8_t)command, userreg, 0);
i2c_release(_BUS);
if (i2c_result != 0) {
return SHT2X_ERR_I2C;
}
return SHT2X_OK;
}
/******************************************************************************
* Local Functions
******************************************************************************/
/**
* @brief Read a sensor value from the given SHT2X device
*
* @param[in] dev Device descriptor of SHT2X device to read from
* @param[in] cmd The SHT2x command (hold mode only)
* @param[out] val The raw sensor value (only valid if no error)
*
* @return SHT2X_OK value is returned in @p val
* @return SHT2X_NODEV if sensor communication failed
* @return SHT2X_ERR_OTHER if parameters are invalid
* @return SHT2X_ERR_TIMEDOUT if sensor times out
* @return SHT2X_ERR_CRC if the checksum is wrong
*/
static int read_sensor(const sht2x_t* dev, cmd_t command, uint16_t *val)
{
uint8_t buffer[3];
int i2c_result;
/* Acquire exclusive access */
i2c_acquire(_BUS);
DEBUG("[SHT2x] write command: addr=%02x cmd=%02x\n", _ADDR, (uint8_t)command);
(void)i2c_write_byte(_BUS, _ADDR, (uint8_t)command, 0);
i2c_result = i2c_read_bytes(_BUS, _ADDR, buffer, sizeof(buffer), 0);
i2c_release(_BUS);
if (i2c_result != 0) {
DEBUG("[Error] Cannot read SHT2x sensor data.\n");
return SHT2X_ERR_I2C_READ;
}
DEBUG("[SHT2x] read: %02x %02x %02x\n", buffer[0], buffer[1], buffer[2]);
if (val) {
*val = (buffer[0] << 8) | buffer[1];
*val &= ~0x0003; /* clear two low bits (status bits) */
}
if (dev->params.is_crc_enabled) {
/* byte #3 is the checksum */
if (sht2x_checkcrc(buffer, 2, buffer[2]) != 0) {
return SHT2X_ERR_CRC;
}
}
return SHT2X_OK;
}
/**
* @brief Read a sensor value from the given SHT2X device, polling mode
*
* @param[in] dev Device descriptor of SHT2X device to read from
* @param[in] cmd The SHT2x command (hold mode only)
* @param[out] val The raw sensor value (only valid if no error)
*
* @return SHT2X_OK value is returned in @p val
* @return SHT2X_NODEV if sensor communication failed
* @return SHT2X_ERR_OTHER if parameters are invalid
* @return SHT2X_ERR_TIMEDOUT if sensor times out
* @return SHT2X_ERR_CRC if the checksum is wrong
*/
static int read_sensor_poll(const sht2x_t* dev, cmd_t command, uint16_t *val)
{
uint8_t buffer[3];
int i2c_result;
/* Acquire exclusive access */
i2c_acquire(_BUS);
DEBUG("[SHT2x] write command: addr=%02x cmd=%02x\n", _ADDR, (uint8_t)command);
(void)i2c_write_byte(_BUS, _ADDR, (uint8_t)command, 0);
if (command == temp_no_hold_cmd) {
sleep_during_temp_measurement(dev->params.resolution);
} else {
sleep_during_hum_measurement(dev->params.resolution);
}
uint8_t ix = 0;
for (; ix < MAX_RETRIES; ix++) {
i2c_result = i2c_read_bytes(_BUS, _ADDR, buffer, sizeof(buffer), 0);
if (i2c_result == 0) {
break;
}
}
i2c_release(_BUS);
if (i2c_result != 0) {
DEBUG("[Error] Cannot read SHT2x sensor data.\n");
return SHT2X_ERR_I2C_READ;
}
DEBUG("[SHT2x] read: %02x %02x %02x\n", buffer[0], buffer[1], buffer[2]);
if (val) {
*val = (buffer[0] << 8) | buffer[1];
*val &= ~0x0003; /* clear two low bits (status bits) */
}
/* byte #3 is the checksum */
if (dev->params.is_crc_enabled) {
if (sht2x_checkcrc(buffer, 2, buffer[2]) != 0) {
return SHT2X_ERR_CRC;
}
}
return SHT2X_OK;
}
static const uint16_t POLYNOMIAL = 0x131; /* P(x)=x^8+x^5+x^4+1 = 100110001 */
/**
* @brief Calculate 8-Bit checksum with given polynomial
*/
static uint8_t sht2x_checkcrc(uint8_t data[], uint8_t nbrOfBytes, uint8_t checksum)
{
uint8_t crc = 0;
uint8_t byteCtr;
for (byteCtr = 0; byteCtr < nbrOfBytes; ++byteCtr)
{
crc ^= (data[byteCtr]);
for (uint8_t bit = 8; bit > 0; --bit)
{
if ((crc & 0x80) != 0)
crc = (crc << 1) ^ POLYNOMIAL;
else
crc = (crc << 1);
}
}
if (crc != checksum)
return 1;
else
return 0;
}
/**
* @brief Initialize the given SHT2X device
*
* @param[in] res The resolution bits in the User Register
*
* @details Sleep for the typical time it takes to complete the measurement
* this depends on the resolution and is taken from the datasheet.
* Measurement time differs for temperature and humidity.
*/
static void sleep_during_temp_measurement(sht2x_res_t res)
{
uint32_t amount_ms = 0;
switch (res) {
case SHT2X_RES_12_14BIT:
amount_ms = 66;
break;
case SHT2X_RES_8_12BIT:
amount_ms = 17;
break;
case SHT2X_RES_10_13BIT:
amount_ms = 33;
break;
case SHT2X_RES_11_11BIT:
amount_ms = 9;
break;
}
xtimer_usleep(amount_ms * US_PER_MS);
}
static void sleep_during_hum_measurement(sht2x_res_t resolution)
{
uint32_t amount_ms = 0;
switch (resolution) {
case SHT2X_RES_12_14BIT:
amount_ms = 22;
break;
case SHT2X_RES_8_12BIT:
amount_ms = 3;
break;
case SHT2X_RES_10_13BIT:
amount_ms = 7;
break;
case SHT2X_RES_11_11BIT:
amount_ms = 12;
break;
}
xtimer_usleep(amount_ms * US_PER_MS);
}

View File

@ -0,0 +1,53 @@
/*
* Copyright (C) 2019 Kees Bakker, SODAQ
*
* 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_sht2x
* @{
*
* @file
* @brief SAUL adaption for Sensirion SHT20/SHT21/SHT25 devices
*
* @author Kees Bakker <kees@sodaq.com>
*
* @}
*/
#include "saul.h"
#include "sht2x.h"
static int read_temperature(const void *dev, phydat_t *res)
{
res->val[0] = sht2x_read_temperature((const sht2x_t *)dev);
res->unit = UNIT_TEMP_C;
res->scale = -2;
return 1;
}
static int read_relative_humidity(const void *dev, phydat_t *res)
{
res->val[0] = sht2x_read_humidity((const sht2x_t *)dev);
res->unit = UNIT_PERCENT;
res->scale = -2;
return 1;
}
const saul_driver_t sht2x_temperature_saul_driver = {
.read = read_temperature,
.write = saul_notsup,
.type = SAUL_SENSE_TEMP,
};
const saul_driver_t sht2x_relative_humidity_saul_driver = {
.read = read_relative_humidity,
.write = saul_notsup,
.type = SAUL_SENSE_HUM,
};

View File

@ -445,6 +445,10 @@ void auto_init(void)
extern void auto_init_pulse_counter(void);
auto_init_pulse_counter();
#endif
#ifdef MODULE_SHT2X
extern void auto_init_sht2x(void);
auto_init_sht2x();
#endif
#ifdef MODULE_SHT3X
extern void auto_init_sht3x(void);
auto_init_sht3x();

View File

@ -0,0 +1,77 @@
/*
* Copyright (C) 2019 Kees Bakker, SODAQ
*
* 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 SHT2X driver.
*
* @author Kees Bakker <kees@sodaq.com>
*
* @}
*/
#if defined(MODULE_SHT2X)
#include "log.h"
#include "saul_reg.h"
#include "sht2x_params.h"
#include "sht2x.h"
/**
* @brief Allocation of memory for device descriptors
*/
static sht2x_t sht2x_devs[SHT2X_NUMOF];
/**
* @brief Reference the driver structs.
* @{
*/
extern const saul_driver_t sht2x_temperature_saul_driver;
extern const saul_driver_t sht2x_relative_humidity_saul_driver;
/** @} */
/**
* @brief Memory for the SAUL registry entries
*/
#define SENSORS_NUMOF 2
static saul_reg_t saul_entries[SHT2X_NUMOF * SENSORS_NUMOF];
void auto_init_sht2x(void)
{
size_t se_ix = 0;
for (size_t i = 0; i < SHT2X_NUMOF; i++) {
LOG_DEBUG("[auto_init_saul] initializing SHT2X #%u\n", i);
int res = sht2x_init(&sht2x_devs[i], &sht2x_params[i]);
if (res < 0) {
LOG_ERROR("[auto_init_saul] error initializing SHT2X #%u\n", i);
continue;
}
/* temperature */
saul_entries[se_ix].dev = &sht2x_devs[i];
saul_entries[se_ix].name = sht2x_saul_reg_info[i].name;
saul_entries[se_ix].driver = &sht2x_temperature_saul_driver;
saul_reg_add(&saul_entries[se_ix]);
se_ix++;
/* relative humidity */
saul_entries[se_ix].dev = &sht2x_devs[i];
saul_entries[se_ix].name = sht2x_saul_reg_info[i].name;
saul_entries[se_ix].driver = &sht2x_relative_humidity_saul_driver;
saul_reg_add(&saul_entries[se_ix]);
se_ix++;
}
}
#else
typedef int dont_be_pedantic;
#endif /* MODULE_SHT2X */

View File

@ -0,0 +1,10 @@
APPLICATION = driver_sht2x
include ../Makefile.tests_common
FEATURES_REQUIRED = periph_i2c
USEMODULE += sht2x
USEMODULE += xtimer
USEMODULE += printf_float
include $(RIOTBASE)/Makefile.include

24
tests/driver_sht2x/README.md Executable file
View File

@ -0,0 +1,24 @@
# Sensirion SHT20/SHT21/SHT25 Humidity and Temperature Sensors
## About
This is a test application for the SHT2x humidity/temperature sensor
driver.
## Usage
This test application will initialize the SHT2x sensor with the following
parameters:
- default device type: SHT21
- 14-bit temperature resolution
- 12-bit humidity resolution
To change these parameters, you can override them by setting their
corresponding defines in your build environment, e.g.
```bash
CFLAGS=-DSHT2X_PARAM_RESOLUTION=SHT2x_RES_8_12BIT make ...
```
See `drivers/sht2x_params.h` for the default configuration.
After initialization, the sensor reads the temperature and humidity values
every one second and prints them to STDOUT. The chip-heater of the SHT2x
will be turned on in the beginning, so the temperature should rise over
time and the humidity should decrease.

120
tests/driver_sht2x/main.c Normal file
View File

@ -0,0 +1,120 @@
/*
* Copyright (C) 2016 Kees Bakker, SODAQ
*
* 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 SHT2x temperature and humidity sensor
*
* @author Kees Bakker <kees@sodaq.com>
*
* @}
*/
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include "sht2x_params.h"
#include "sht2x.h"
#include "xtimer.h"
#define SLEEP_2S (2 * 1000 * 1000u) /* 2 seconds delay between printf */
static void dump_buffer(const char* txt, uint8_t* buffer, size_t len);
int main(void)
{
sht2x_t dev;
uint8_t ident[8];
int result;
int ident_size;
memset(ident, 0, sizeof(ident));
puts("SHT2X test application\n");
printf("+------------Initializing------------+\n");
/* Use the first default parameter set */
result = sht2x_init(&dev, &sht2x_params[0]);
if (result != SHT2X_OK) {
puts("[Error] The given i2c is not enabled");
return 1;
}
else {
printf("Initialization successful\n\n");
}
printf("\n+--------Identifier--------+\n");
ident_size = sht2x_read_ident(&dev, ident, sizeof(ident));
if (ident_size > 0) {
dump_buffer("Identifier Code:", ident, ident_size);
}
printf("\n+--------Starting Measurements--------+\n");
while (1) {
int16_t temperature;
{
/* Print the identification every so often */
static int count = 0;
if (++count >= 100) {
ident_size = sht2x_read_ident(&dev, ident, sizeof(ident));
if (ident_size > 0) {
dump_buffer("Identifier Code:", ident, ident_size);
}
count = 0;
}
}
/* Get temperature in centi degrees celsius */
temperature = sht2x_read_temperature(&dev);
if (temperature == INT16_MIN) {
printf("\n+--------Soft Reset--------+\n");
sht2x_reset(&dev);
} else {
uint16_t humidity;
/* Get humidity in %RH */
humidity = sht2x_read_humidity(&dev);
printf("Temperature [°C]: %d.%d\n"
"Humidity [%%RH]: %u.%02u\n"
"\n+-------------------------------------+\n",
temperature / 100, (temperature % 100) / 10,
(unsigned int)(humidity / 100), (unsigned int)(humidity % 100)
);
}
xtimer_usleep(SLEEP_2S);
}
return 0;
}
static void dump_buffer(const char* txt, uint8_t* buffer, size_t len)
{
size_t ix;
printf("%s\n", txt);
for (ix = 0; ix < len; ++ix) {
if (ix > 0) {
if ((ix % 8) == 0) {
printf("\n");
}
else {
printf(" ");
}
}
printf("%02x", buffer[ix]);
}
if (len > 0) {
printf("\n");
}
}