Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

drivers/shtc1: Initial support for the SHTC1 temperature and humidity sensor #7866

Closed
wants to merge 14 commits into from
Closed
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions drivers/Makefile.include
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,10 @@ ifneq (,$(filter sdcard_spi,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/sdcard_spi/include
endif

ifneq (,$(filter shtc1,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/shtc1/include
endif

ifneq (,$(filter si114x,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/si114x/include
endif
Expand Down
127 changes: 127 additions & 0 deletions drivers/include/shtc1.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
/*
* 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
* @ingroup drivers_sensors
* @name Device driver interface for the SHTC1 Temperature and humidity sensor
* @{
*
* @file
* @brief Device driver interface for the SHTC1 Temperature and humidity sensor
*
* @author Steffen Robertz <[email protected]>
* @author Josua Arndt <[email protected]>
*/

#ifndef SHTC1_H
#define SHTC1_H

#include <stdint.h>
#include "periph/i2c.h"

#ifdef __cplusplus
extern "C" {
#endif

typedef enum {
CRC_DISABLED = 0,
CRC_ENABLED
} shtc1_crc_type_t;

/**
* @brief value struct, where all results obtained from the sensor will be saved.
* @{
*/
typedef struct {
float temp; /**< Temperature after an according call to the measurement function. */
float rel_humidity; /**< Relative humidity after an according call to the measuerment funtion. */
unsigned int id; /**< ID read from the sensor, only available after shtc1_id() was called. */
} shtc1_values_t;
/** @} */

/**
* @brief settings struct with all relevant parameters
* @{
*/
typedef struct {
i2c_t bus; /**< I2C bus descriptor. */
uint8_t addr; /**< I2C address of the sensor. */
shtc1_crc_type_t crc; /**< crc check enabled or disabled (CRC_ENABLED/CRC_DISABLED). */
} shtc1_params_t;
/** @} */

/**
* @brief device descriptor for the SHTC1
* @{
*/
typedef struct {
shtc1_values_t values; /**< Values struct, where all read data will be stored. */
shtc1_params_t params; /**< Paramteres struct with all settings set. */
} shtc1_t;
/** @} */

enum {
SHTC1_OK = 0,
SHTC1_ERROR = -1
};

/**
* @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 on error.
*/
int8_t shtc1_init(shtc1_t* const dev, const shtc1_params_t* params);

/**
* @brief Reads temperature and humidity values.
* @details The values will be saved in the device descriptor (values struct).
* The temperature is in °C and the humidity in %.
*
* @param[in] dev The I2C device descriptor.
*
* @return SHTC1_OK if a measurement completed. The values will be stored
* in the values struct. Temperature in °C and humidity in %.
* @return SHTC1_ERROR on checksum error.
*/
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please reduce line width of the doc

int8_t shtc1_measure(shtc1_t* const dev);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it be nice to have a function that directly returns the data instead of fiddling around with the device struct? Furthermore, I expected some intentions to cache sensor data when you introduced shtc1_values_t. If this was the case, wouldn't you need a distinction between triggering a new read and getting cached data?

Copy link
Contributor

@Josar Josar Nov 8, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shtc1_values_t are used in the device struckt shtc1_t.

Just passing the struckt instead of dev, temp, hum pointer is much more convinient. IMHO.
We could discuss to add raw and processed data to the shtc1_values_t. What do you think.


/**
* @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.
*
* @return SHTC1_OK on everything done.
* @return SHTC1_ERROR on error.
*/
int8_t shtc1_id(shtc1_t* const dev);

/**
* @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 on error.
*/
int8_t shtc1_reset(const shtc1_t* const dev);

#ifdef __cplusplus
}
#endif

#endif /* SHTC1_H */
/** @} */
1 change: 1 addition & 0 deletions drivers/shtc1/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include $(RIOTBASE)/Makefile.base
66 changes: 66 additions & 0 deletions drivers/shtc1/include/shtc1_params.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* 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
* @name Default parameters for the SHTC1 Temperature and humidity sensor
* @{
*
* @file
* @brief Default parameters for the SHTC1 Temperature and humidity sensor
*
* @author Steffen Robertz <[email protected]>
* @author Josua Arndt <[email protected]>
*/

#ifndef SHTC1_PARAMS_H
#define SHTC1_PARAMS_H

#include "board.h"
#include "shtc1.h"

#ifdef __cplusplus
extern "C" {
#endif

/**
* @brief Default configuration parameters for SHTC1 sensors
* @{
*/
#ifndef SHTC1_PARAM_I2C
#define SHTC1_PARAM_I2C (I2C_DEV(0))
#endif
#ifndef SHTC1_PARAM_ADDR
#define SHTC1_PARAM_ADDR (0x70)
#endif
#ifndef SHTC1_PARAM_CRC
#define SHTC1_PARAM_CRC CRC_ENABLED
#endif

#ifndef SHTC1_PARAMS
#define SHTC1_PARAMS { .bus = SHTC1_PARAM_I2C, \
.addr = SHTC1_PARAM_ADDR, \
.crc = SHTC1_PARAM_CRC }
#endif
/** @} */

/**
* @brief Allocation of SHTC1 configuration
*/
static const shtc1_params_t shtc1_params[] = {
#ifdef SHTC1_PARAMS_BOARD
SHTC1_PARAMS_BOARD
#else
SHTC1_PARAMS
#endif
};
#ifdef __cplusplus
}
#endif
#endif /* SHTC1_PARAMS_H */
/** @} */
41 changes: 41 additions & 0 deletions drivers/shtc1/include/shtc1_regs.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* 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
* @name Register definition for the SHTC1 Temperature and humidity sensor
* @{
*
* @file
* @brief Register definition for the SHTC1 Temperature and humidity sensor
*
* @author Steffen Robertz <[email protected]>
* @author Josua Arndt <[email protected]>
*/

#ifndef SHTC1_REGS_H
#define SHTC1_REGS_H

#ifdef __cplusplus
extern "C" {
#endif

#define SHTC1_CRC (0x31) /* crc polynomial */
#define SHTC1_MEASURE_CLOCK_STRETCHING_TEMP_HIGH (0x7C)
#define SHTC1_MEASURE_CLOCK_STRETCHING_TEMP_LOW (0xA2)
#define SHTC1_COMMAND_RESET_HIGH (0x80)
#define SHTC1_COMMAND_RESET_LOW (0x5D)
#define SHTC1_COMMAND_ID_HIGH (0xEF)
#define SHTC1_COMMAND_ID_LOW (0xC8)
#define SHTC1_ID (0x07) /* ID Mask */

#ifdef __cplusplus
}
#endif
#endif /* SHTC1_REGS_H */
/** @} */
136 changes: 136 additions & 0 deletions drivers/shtc1/shtc1.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
/*
* Copyright 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.
*/

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add doxygen header and author field in the following form:

/**
 * @ingroup     drivers_XXX
 * @{
 *
 * @file
 * @brief       Device driver implementation for the XXX
 *
 * @author      XXX XXX <[email protected]>
 *
 * @}
 */

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Obviously this belongs to the group you defined above.

/**
* @ingroup drivers_shtc1
* @{
*
* @file
* @brief Device driver implementation for the Sensirion SHTC1 temperature and humidity sensor
*
* @author Steffen Robertz <[email protected]>
* @author Josua Arndt <[email protected]>
* @}
*/

#include "shtc1.h"
#include "shtc1_regs.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
#include "assert.h"


/*
* does a crc check and returns 0 for passed and -1 for failed
* 2 bytes will be checked for the checksum, rec_value is pointer
* to first value
*/
static int8_t _check_crc(uint8_t *rec_values, uint8_t right_crc)
{
uint8_t crc = 0xFF;
uint8_t current_byte;
uint8_t bit;

for (current_byte = 0; current_byte < 2; current_byte++) {
crc ^= (rec_values[current_byte]);
for (bit = 8; bit > 0; bit--) {
if (crc & 0x80) {
crc = (crc << 1) ^ SHTC1_CRC;
}
else {
crc = (crc << 1);
}
}
}
return !(crc == right_crc);
}

int8_t shtc1_init(shtc1_t *const dev, const shtc1_params_t *params)
{
/* 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) != SHTC1_OK || ((dev->values.id & 0x3F) != SHTC1_ID)) {
return SHTC1_ERROR;
}
return SHTC1_OK;
}

int8_t shtc1_measure(shtc1_t *const dev)
{
/* 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.bus);
if (i2c_write_bytes(dev->params.bus, dev->params.addr, cmd, 2, 0)) {
return SHTC1_ERROR;
}
/* Receive the measurement */
/* 16 bit Temperature
* 8 bit CRC temp
* 16 Bit Absolute Humidity
* 8 bit CRC Hum
*/
uint8_t received[6];
if(i2c_read_bytes(dev->params.bus, dev->params.addr, received, 6, 0)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe spend a comment about the format (upper 8bit, lower 8bit, crc)

return SHTC1_ERROR;
}
i2c_release(dev->params.bus);
/* get 16bit values and check crc */
uint16_t temp_f = ((received[0] << 8) | received[1]);
uint16_t abs_humidity = ((received[3] << 8) | received[4]);
if (dev->params.crc) {
if (!((_check_crc(&received[0], received[2]) == 0) && (_check_crc(&received[3], received[5]) == 0))) {
/* crc check failed */
DEBUG("CRC Error");
return SHTC1_ERROR;
}
DEBUG("CRC Passed! \n");
}
/* calculate the relative humidity and convert the temperature to °C */
dev->values.temp = (175.0 * temp_f / 65536) - 45;
dev->values.rel_humidity = 100 * (abs_humidity / 65536.0);

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Usually we abstain from extra divisions and normalization operations to represent a value in persent or something. Do you think we can simplify here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe that a conversion of the temperature to °C is neccessary. The raw values does not hold a lot of information to a user.
The relative humidity can be changed back to the absolute one as this should be clear.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return SHTC1_OK;
}

int8_t shtc1_id(shtc1_t *const dev)
{
/* Build and send measurement command */
uint8_t data[] = { SHTC1_COMMAND_ID_HIGH, SHTC1_COMMAND_ID_LOW };
int8_t check = 0;

i2c_acquire(dev->params.bus);
check = i2c_write_bytes(dev->params.bus, dev->params.addr, data, 2, 0);
/* receive ID and check if the send and receive commands were successfull */
check += i2c_read_bytes(dev->params.bus, dev->params.addr, data, 2, 0);
i2c_release(dev->params.bus);
if (check != 0) {
/* error occured */
return SHTC1_ERROR;
}
/* Save ID in device descriptor */
dev->values.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.bus);
if (i2c_write_bytes(dev->params.bus, dev->params.addr, data, 2, 0)) {
i2c_release(dev->params.bus);
return SHTC1_ERROR;
}
i2c_release(dev->params.bus);
return SHTC1_OK;
}
9 changes: 9 additions & 0 deletions tests/driver_shtc1/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
APPLICATION = driver_shtc1
include ../Makefile.tests_common

FEATURES_REQUIRED = periph_i2c

USEMODULE += shtc1
USEMODULE += xtimer

include $(RIOTBASE)/Makefile.include
Loading