1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-01-17 04:52:59 +01:00

drivers/sht1x: Major refactoring

- Use RIOT's GPIO interface to access the sensor to increase portability
- Changed API to allow more than one sensor per board
- Added `sht1x_params.h` that specifies how the sensors is connected - each
  board can overwrite default settings by #defining SHT1X_PARAM_CLK and
  SHT1X_PARAM_DATA
- Changed arithmetic to use integer calculations only instead of floating point
  arithmetic
- Added support for checking the CRC sum
- Allow optional skipping of the CRC check to speed up measuring
- Added support for advanced features like reducing the resolution and skipping
  calibration to speed up measuring
- Allow specifying the supply voltage of sensor which heavily influences the
  temperature result (and use that information to calculate the correct
  temperature)
- Reset sensor on initialization to bring it in a well known state
- Support for the obscure heater feature. (Can be useful to check the
  temperature sensor?)
- Updated old SHT11 shell commands to the new driver interface, thus allowing
  more than one SHT10/11/15 sensor to be used
- Added new shell command to allow full configuration of all attached SHT1x
  sensors
- Removed old command for setting the SHT11 temperature offset, as this feature
  is implemented in the new configuration command
This commit is contained in:
Marian Buschsieweke 2018-06-13 09:17:29 +02:00
parent d208c224b0
commit de9b67bdc2
No known key found for this signature in database
GPG Key ID: 61F64C6599B1539F
23 changed files with 1268 additions and 464 deletions

View File

@ -1,5 +1,3 @@
MODULE = boards_common_msb-430
DIRS = drivers
include $(RIOTBASE)/Makefile.base

View File

@ -25,6 +25,3 @@ export DEBUGGER_FLAGS = --tui --ex="target remote localhost:2000" --ex "monitor
# export common msb-430 includes
export INCLUDES += -I$(RIOTBOARD)/common/msb-430/include
export INCLUDES += -I$(RIOTBOARD)/common/msb-430/drivers/include
USEMODULE += boards_common_msb-430-drivers

View File

@ -1,5 +0,0 @@
MODULE = boards_common_msb-430-drivers
include $(RIOTBOARD)/$(BOARD)/Makefile.include
include $(RIOTBASE)/Makefile.base

View File

@ -1,49 +0,0 @@
/*
* Copyright 2013, Freie Universitaet Berlin (FUB). 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.
*/
#ifndef SHT1X_BOARD_H
#define SHT1X_BOARD_H
/**
* @ingroup boards_common_msb-430
* @{
*/
/**
* @file
* @brief SHT11 Device Driver Configuration For MSB-430 Platform
*
* @author Freie Universität Berlin, Computer Systems & Telematics, RIOT
*
*/
#include <msp430x16x.h>
#include "bitarithm.h"
#ifdef __cplusplus
extern "C" {
#endif
/* SCK = P3B5
* DATA = P3B4
*/
#define SHT1X_SCK_LOW P3OUT &= ~(BIT5); /**< serial clock line low */
#define SHT1X_SCK_HIGH P3OUT |= BIT5; /**< serial clock line high */
#define SHT1X_DATA (P3IN & BIT5) /**< read serial I/O */
#define SHT1X_DATA_LOW P3OUT &= ~(BIT5); /**< serial I/O line low */
#define SHT1X_DATA_HIGH P3OUT |= BIT5; /**< serial I/O line high */
#define SHT1X_DATA_IN P3DIR &= ~(BIT5); /**< serial I/O as input */
#define SHT1X_DATA_OUT P3DIR |= BIT5; /**< serial I/O as output */
#define SHT1X_INIT P3DIR |= BIT5; /* FIO1DIR |= BIT25; PINSEL3 &= ~(BIT14|BIT15 | BIT16|BIT17); */
#ifdef __cplusplus
}
#endif
/** @} */
#endif /* SHT1X_BOARD_H */

View File

@ -1,5 +1,3 @@
MODULE = boards_common_msba2
DIRS = drivers
include $(RIOTBASE)/Makefile.base

View File

@ -27,8 +27,5 @@ endif
export FFLAGS = $(PORT) $(HEXFILE)
INCLUDES += -I$(RIOTBOARD)/common/msba2/include
INCLUDES += -I$(RIOTBOARD)/common/msba2/drivers/include
export UNDEF += $(BINDIR)/cpu/startup.o
USEMODULE += boards_common_msba2-drivers

View File

@ -1,3 +0,0 @@
MODULE = boards_common_msba2-drivers
include $(RIOTBASE)/Makefile.base

View File

@ -1,56 +0,0 @@
/*
* Copyright 2009, Freie Universitaet Berlin (FUB). 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.
*/
#ifndef SHT1X_BOARD_H
#define SHT1X_BOARD_H
/**
* @ingroup boards_common_msba2
* @{
*/
/**
* @file
* @brief LPC2387 SHT11 Device Driver
*
* @author Freie Universität Berlin, Computer Systems & Telematics, FeuerWhere project
* @version $Revision$
*
* @note $Id$
*/
#include "cpu.h"
#include "board.h"
#ifdef __cplusplus
extern "C" {
#endif
/* serial clock line low */
#define SHT1X_SCK_LOW FIO1CLR = BIT25;
/* serial clock line high */
#define SHT1X_SCK_HIGH FIO1SET = BIT25;
/* read serial I/O */
#define SHT1X_DATA ((FIO1PIN & BIT26) != 0)
/* serial I/O line low */
#define SHT1X_DATA_LOW (FIO1CLR = BIT26);
/* serial I/O line high */
#define SHT1X_DATA_HIGH (FIO1SET = BIT26);
/* serial I/O as input */
#define SHT1X_DATA_IN (FIO1DIR &= ~BIT26)
/* serial I/O as output */
#define SHT1X_DATA_OUT (FIO1DIR |= BIT26)
#define SHT1X_INIT FIO1DIR |= BIT25; PINSEL3 &= ~(BIT14|BIT15 | BIT16|BIT17);
#ifdef __cplusplus
}
#endif
/** @} */
#endif /* SHT1X_BOARD_H */

View File

@ -0,0 +1,3 @@
ifneq (,$(filter saul_default,$(USEMODULE)))
USEMODULE += sht11
endif

View File

@ -59,6 +59,14 @@ extern "C" {
#define MSP430_HAS_EXTERNAL_CRYSTAL 0
/** @} */
/**
* @name Configure on-board SHT11 device
* @{
*/
#define SHT1X_PARAM_CLK (GPIO_PIN(3, 5))
#define SHT1X_PARAM_DATA (GPIO_PIN(3, 4))
/** @} */
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,3 @@
ifneq (,$(filter saul_default,$(USEMODULE)))
USEMODULE += sht11
endif

View File

@ -47,6 +47,14 @@ extern "C" {
#define MSP430_HAS_EXTERNAL_CRYSTAL 1
/** @} */
/**
* @name Configure on-board SHT11 device
* @{
*/
#define SHT1X_PARAM_CLK (GPIO_PIN(3, 5))
#define SHT1X_PARAM_DATA (GPIO_PIN(3, 4))
/** @} */
#ifdef __cplusplus
}
#endif

View File

@ -3,3 +3,7 @@ include $(RIOTBOARD)/common/msba2/Makefile.dep
ifneq (,$(filter netdev_default gnrc_netdev_default,$(USEMODULE)))
USEMODULE += cc110x
endif
ifneq (,$(filter saul_default,$(USEMODULE)))
USEMODULE += sht11
endif

View File

@ -304,6 +304,7 @@ endif
ifneq (,$(filter sht1%,$(USEMODULE)))
USEMODULE += sht1x
FEATURES_REQUIRED += periph_gpio
USEMODULE += xtimer
endif

View File

@ -50,6 +50,10 @@ ifneq (,$(filter dht,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/dht/include
endif
ifneq (,$(filter sht1x,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/sht1x/include
endif
ifneq (,$(filter ds1307,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/ds1307/include
endif

View File

@ -1,5 +1,6 @@
/*
* Copyright 2009, Freie Universitaet Berlin (FUB). All rights reserved.
* Copyright 2009 Freie Universitaet Berlin (FUB)
* 2018 Otto-von-Guericke-Universität Magdeburg
*
* 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
@ -16,90 +17,168 @@
* @file
* @brief SHT10/SHT11/SHT15 Device Driver
*
* @author Freie Universität Berlin, Computer Systems & Telematics
* @author Marian Buschsieweke <marian.buschsieweke@ovgu.de>
*/
#ifndef SHT1X_H
#define SHT1X_H
#include <stdint.h>
#include <periph/gpio.h>
#ifdef __cplusplus
extern "C" {
#endif
#define SHT1X_NO_ACK (0) /**< don't ack read in `read_byte` */
#define SHT1X_ACK (1) /**< do acknowledge read in `read_byte` */
/* adr command r/w */
#define SHT1X_STATUS_REG_W (0x06) /**< will write to status register */
#define SHT1X_STATUS_REG_R (0x07) /**< will read from status register */
#define SHT1X_MEASURE_TEMP (0x03) /**< tell sensor to measure temperature */
#define SHT1X_MEASURE_HUMI (0x05) /**< tell sensor to measure humidity */
#define SHT1X_RESET (0x1E) /**< reset the sensor */
/** time to wait after toggling the data line */
#define SHT1X_DATA_WAIT (1)
/** time to wait after toggling the clock line */
#define SHT1X_CLK_WAIT (1)
/** set measurement timeout to 1 second */
#define SHT1X_MEASURE_TIMEOUT (1000)
/**
* @brief sht11 measureable data
*/
typedef struct {
float temperature; /**< temperature value */
float relhum; /**< linear relative humidity */
float relhum_temp; /**< temperature compensated relative humidity */
} sht1x_val_t;
/**
* @brief SHT11 modes that can be measured
* @brief Possible configuration (=status byte) values of the SHT10/11/15
*
* These values can be or'ed together to get the configuration.
*/
typedef enum {
TEMPERATURE = 1,
HUMIDITY = 2
} sht1x_mode_t;
/** Use 8/12 bit resolution instead of 12/14 bit for temp/hum */
SHT1X_CONF_LOW_RESOLUTION = 0x01,
/** Don't upload calibration data to register to safe 10 millisec */
SHT1X_CONF_SKIP_CALIBRATION = 0x02,
/** Waste 8mA at 5V to increase the sensor temperature up to 10°C */
SHT1X_CONF_ENABLE_HEATER = 0x04,
/** Skip the CRC check (and reading the CRC byte) to safe time */
SHT1X_CONF_SKIP_CRC = 0x08,
} sht1x_conf_t;
/**
* @brief Initialize SHT11 ports
* @brief Possible values for Vdd (measured temperature depends on it)
*/
void sht1x_init(void);
typedef enum {
SHT1X_VDD_5_0V = 0,
SHT1X_VDD_4_0V = 1,
SHT1X_VDD_3_5V = 2,
SHT1X_VDD_3_0V = 3,
SHT1X_VDD_2_5V = 4,
} sht1x_vdd_t;
/**
* @brief Read sensor
*
* @param value The struct to be filled with measured values
* @param mode Specifies type of data to be read
*
* @return 1 on success, 0 otherwise
*
* Example:
* \code sht1x_val sht11;
* sht1x_read_sensor(&sht11, HUMIDITY|TEMPERATURE);
* printf("%-6.2f °C %5.2f %% %5.2f %%\n", sht11.temperature, sht11.relhum, sht11.relhum_temp); \endcode
* @brief SHT10/11/15 temperature humidity sensor
*/
uint8_t sht1x_read_sensor(sht1x_val_t *value, sht1x_mode_t mode);
typedef struct {
gpio_t clk; /**< GPIO connected to the clock pin of the SHT1X */
gpio_t data; /**< GPIO connected to the data pin of the SHT1X */
int16_t temp_off; /**< Offset to add to the measured temperature */
int16_t hum_off; /**< Offset to add to the measured humidity */
uint8_t conf; /**< Status byte (containing configuration) of the SHT1X */
uint8_t vdd; /**< Supply voltage of the SHT1X (as sht1x_vdd_t) */
} sht1x_dev_t;
/**
* @brief Write status register
*
* @param p_value The value to write
*
* @return 1 on success, 0 otherwise
* @brief Parameters required to set up the SHT10/11/15 device driver
*/
uint8_t sht1x_write_status(uint8_t *p_value);
typedef struct {
gpio_t clk; /**< GPIO connected to the clock pin of the SHT1X */
gpio_t data; /**< GPIO connected to the data pin of the SHT1X */
sht1x_vdd_t vdd; /**< The supply voltage of the SHT1X */
} sht1x_params_t;
/**
* @brief Read status register with checksum
* @brief Initialize the SHT10/11/15 sensor
*
* @param p_value The read value
* @param p_checksum The received checksum
* @param dev SHT1X sensor to initialize
* @param params Information on how the SHT1X is connected to the board
*
* return 1 on success, 0 otherwise
* @retval 0 Success
* @retval -EIO IO failure (`gpio_init()` failed)
* @retval -EPROTO Sensor did not acknowledge reset command
*/
uint8_t sht1x_read_status(uint8_t *p_value, uint8_t *p_checksum);
int sht1x_init(sht1x_dev_t *dev, const sht1x_params_t *params);
/**
* @brief Calculate the temperature from the raw input
* @note This internal function is exposed for unit tests
*
* @param dev Device from which the raw value was received
* @param raw The raw (unprocessed) temperature value
*
* @return The correct temperature in E-02 °C
* @retval INT16_MIN Passed `NULL` for parameter `dev` or `dev->vdd`
*/
int16_t sht1x_temperature(const sht1x_dev_t *dev, uint16_t raw);
/**
* @brief Calculate the relative humidity from the raw input
* @note This internal function is exposed for unit tests
*
* @param dev Device from which the raw value was received
* @param raw The raw (unprocessed) temperature value
* @param temp The temperature at which the humidity was measure in
* E-02 °C
*
* @return The correct temperature in E-02 %
* @retval -1 Passed `NULL` for parameter `dev`
*/
int16_t sht1x_humidity(const sht1x_dev_t *dev, uint16_t raw, int16_t temp);
/**
* @brief Read the current temperature
*
* @param dev SHT1X sensor to read
* @param temp Store the measured temperature in E-02 °C here
* @param hum Store the measured relative humidity in E-02 % here
*
* @retval 0 Success
* @retval -EIO IO failure (`gpio_init()` failed)
* @retval -EBADMSG CRC-8 checksum didn't match (--> Retry)
* @retval -EINVAL Passed `NULL` for dev or for both `temp` and `hum`
* @retval -EBADMSG CRC checksum didn't match
* @retval -ECANCELED Measurement timed out
* @retval -EPROTO Sensor did not acknowledge command
*
* For either `temp` or `hum` `NULL` can be passed, if only one value is of
* interest. Passing `NULL` for `hum` speeds up the communication, but
* passing `NULL` for `temp` does not. The temperature value is required to
* calculate the relative humidity from the raw input. So the temperature is
* measured in any case, it is just not returned if `temp` is `NULL`.
*/
int sht1x_read(const sht1x_dev_t *dev, int16_t *temp, int16_t *hum);
/**
* @brief Apply the given configuration (= status byte) to
*
* @param dev SHT1X device to configure
* @param conf Configuration to apply
*
* @retval 0 Configuration applied
* @retval -EINVAL Called with `dev == NULL`
* @retval -EIO I/O error (`gpio_init()` failed)
* @retval -EPROTO Sensor did not acknowledge command
* @retval -ECANCELED Sensor did not apply configuration
* @retval -EBADMSG CRC checksum error while verifying uploaded configuration
*/
int sht1x_configure(sht1x_dev_t *dev, sht1x_conf_t conf);
/**
* @brief Read the status byte of an SHT1X sensor
*
* @param dev SHT1X device to receive the status from
* @param status Store the received status byte here
*
* @retval 0 Configuration applied
* @retval -EINVAL Called with `dev == NULL`
* @retval -EIO I/O error (`gpio_init()` failed)
* @retval -EPROTO Sensor did not acknowledge command
* @retval -EBADMSG CRC checksum didn't match
*/
int sht1x_read_status(sht1x_dev_t *dev, uint8_t *status);
/**
* @brief Reset the sensor's configuration to default values
*
* @param dev SHT1X device to reset
*
* @retval 0 Reset successful
* @retval -EINVAL Called with `dev == NULL`
* @retval -EIO I/O error (`gpio_init()` failed)
* @retval -EPROTO Sensor did not acknowledge reset command
*/
int sht1x_reset(sht1x_dev_t *dev);
#ifdef __cplusplus
}

View File

@ -0,0 +1,72 @@
/*
* Copyright 2009 Freie Universitaet Berlin (FUB)
* 2018 Otto-von-Guericke-Universität Magdeburg
*
* 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_sht1x
* @{
*
* @file
* @brief Internal defines required by the SHT10/SHT11/SHT15 driver
*
* @author Marian Buschsieweke <marian.buschsieweke@ovgu.de>
*/
#ifndef SHT1X_DEFINES_H
#define SHT1X_DEFINES_H
#include <stdint.h>
#include <periph/gpio.h>
#include <mutex.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @name Possible values to pass as `ack` parameter to `write_byte`
* @see write_byte
* @{
*/
#define SHT1X_NO_ACK (1) /**< don't ack read in `read_byte` */
#define SHT1X_ACK (0) /**< do acknowledge read in `read_byte` */
/** @} */
/**
* @name Commands that can be sent to the SHT1X driver
* @{
*/
#define SHT1X_STATUS_REG_W (0x06) /**< will write to status register */
#define SHT1X_STATUS_REG_R (0x07) /**< will read from status register */
#define SHT1X_MEASURE_TEMP (0x03) /**< tell sensor to measure temperature */
#define SHT1X_MEASURE_HUM (0x05) /**< tell sensor to measure humidity */
#define SHT1X_RESET (0x1E) /**< reset the sensor */
/** @} */
/**
* @name Timing parameters for the SHT10/SHT1X/SHT15
* @{
*/
#define SHT1X_HALF_CLOCK (1) /**< Half clock length in µsec */
#define SHT1X_MEASURE_TIMEOUT (1000) /**< Timeout for the SHT1x to complete
the measurement (in millisec) */
#define SHT1X_RESET_WAIT (11000) /**< Wait 11ms after soft reset */
/** @} */
#define SHT1X_CONF_MASK (0x07) /**< Bitmask to get writable bits of the
status byte */
#define SHT1X_SAUL_RETRIES (3) /**< How often reading the sensor should
be retried in case of communication
failures */
#ifdef __cplusplus
}
#endif
#endif /* SHT1X_DEFINES_H */
/** @} */

View File

@ -0,0 +1,63 @@
/*
* Copyright (C) 2018 Otto-von-Guericke-Universität Magdeburg
*
* 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_sht1x
*
* @{
* @file
* @brief Default configuration for SHT10/SHT11/SHT15 devices
*
* @author Marian Buschsieweke <marian.buschsieweke@ovgu.de>
*/
#ifndef SHT1X_PARAMS_H
#define SHT1X_PARAMS_H
#include "board.h"
#include "sht1x.h"
#include "saul_reg.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @name Set default configuration parameters for the SHT1X devices
* @{
*/
#ifndef SHT1X_PARAM_CLK
#define SHT1X_PARAM_CLK (GPIO_PIN(1, 25))
#endif
#ifndef SHT1X_PARAM_DATA
#define SHT1X_PARAM_DATA (GPIO_PIN(1, 26))
#endif
#ifndef SHT1X_PARAM_VDD
#define SHT1X_PARAM_VDD (SHT1X_VDD_3_5V)
#endif
#ifndef SHT1X_PARAMS
#define SHT1X_PARAMS { .clk = SHT1X_PARAM_CLK, \
.data = SHT1X_PARAM_DATA, \
.vdd = SHT1X_PARAM_VDD }
#endif
/**@}*/
/**
* @brief Configure SHT1X devices
*/
static const sht1x_params_t sht1x_params[] =
{
SHT1X_PARAMS
};
#ifdef __cplusplus
}
#endif
#endif /* SHT1X_PARAMS_H */
/** @} */

View File

@ -1,5 +1,6 @@
/*
* Copyright 2009, Freie Universitaet Berlin (FUB). All rights reserved.
* Copyright 2009 Freie Universitaet Berlin (FUB)
* 2018 Otto-von-Guericke-Universität Magdeburg
*
* 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
@ -8,343 +9,686 @@
/**
* @ingroup drivers_sht1x
* @brief Driver for the Sensirion SHT11 humidity and temperature sensor
* @brief Driver for the Sensirion SHT10/SHT11/SHT15 humidity and
* temperature sensor
* @{
*
* @file
* @brief SHT11 Device Driver
* @brief SHT10/SHT11/SHT15 Device Driver
* @author Marian Buschsieweke <marian.buschsieweke@ovgu.de>
*
* @version $Revision: 2396 $
*
* @note $Id: sht1x.c 2396 2010-07-06 15:12:35Z ziegert $
* @}
*/
#include <stdio.h>
#include <errno.h>
#include <stdint.h>
#include "xtimer.h"
#include "mutex.h"
#include "sht1x.h"
#include "sht1x-board.h"
#include "sht1x_defines.h"
#include "bitarithm.h"
float sht1x_temperature_offset;
#define ENABLE_DEBUG (0)
#include "debug.h"
/**
* @brief Perform measurement
* @brief Perform measurement
*
* @param p_value Measured value (14 or 12 bit -> 2 bytes)
* @param p_checksum Checksum of measurement
* @param mode The requestested measurement mode: temperature or humidity
* @param dev SHT1X device to use
* @param value Measured value
* @param mode The requested measurement mode: temperature or humidity
*
* @return 1 on success, 0 otherwise
* @retval 0 Success
* @retval -EIO I/O failure (`gpio_init()` failed)
* @retval -EBADMSG CRC-8 checksum didn't match
* @retval -EPROTO SHT1x did not acknowledge command
* @retval -ECANCELED Measurement timed out
*/
static uint8_t measure(uint8_t *p_value, uint8_t *p_checksum, uint8_t mode);
static int measure(const sht1x_dev_t *dev, uint16_t *value, uint8_t mode);
/**
* @brief Write one byte
* @brief Write one byte
*
* @param value The value to write
* @param dev SHT1X device to send the byte to
* @param value The value to write
*
* @return 1 for acknowledged write, 0 otherwise
* @retval 1 Write was acknowledged
* @retval 0 Write was *NOT* acknowledged (communication failure)
* @retval -EIO I/O failure (`gpio_init()` failed)
*/
static uint8_t write_byte(uint8_t value);
static int write_byte(const sht1x_dev_t *dev, uint8_t value);
/**
* @brief Read ony byte
* @brief Read one byte
*
* @param ack Set if the data read should be acknowledged
* @param dev SHT1X device to receive the byte from
* @param dest Store the received byte here
* @param ack `SHT1X_ACK` to acknowledge byte, `SHT1X_NO_ACK` otherwise
*
* @return The read byte
* @retval 0 Success
* @retval -EIO I/O failure (`gpio_init()` failed)
*/
static uint8_t read_byte(uint8_t ack);
static int read_byte(const sht1x_dev_t *dev, uint8_t *dest, int ack);
/**
* @brief Communication reset
* @brief Communication reset
*
* @param dev SHT1X device to reset the connection to
*
* @retval 0 Success
* @retval -EIO I/O failure (`gpio_init()` failed)
*/
static void connection_reset(void);
static int connection_reset(const sht1x_dev_t *dev);
/**
* @brief Send start of transmision sequence
* @brief Send start of transmission sequence
*
* @param dev SHT1X device to send the transmission start sequence to
*
* @retval 0 Success
* @retval -EIO I/O failure (`gpio_init()` failed)
*/
static void transmission_start(void);
static int transmission_start(const sht1x_dev_t *dev);
/**
* @brief Toggle the clock line
* @brief Toggle the clock line
*
* @param dev SHT1X device to send one clock signal to
*/
static inline void clk_signal(void);
static inline void clk_signal(const sht1x_dev_t *dev);
/* mutex for exclusive measurement operation */
mutex_t sht1x_mutex = MUTEX_INIT;
/**
* @brief Calculate the initial value of the CRC-8 checksum
*
* @param status The current sensor status
*
* @return The initial value of the CRC-8 checksum
*/
static inline uint8_t crc_initial_value(uint8_t status);
/**
* @brief Reverse the order of bits in a byte (needed for CRC)
*
* @param value The byte to reverse the bits of
*
* @return The reversed input
*/
static inline uint8_t reverse_byte(uint8_t value);
/**
* @brief Look up table required for CRC-8 calculation
*
* Values taken from the Application Note PDF of Sensirion (December 2011)
*/
static const uint8_t crc_lookup_table[] = {
0x00, 0x31, 0x62, 0x53, 0xc4, 0xf5, 0xa6, 0x97,
0xb9, 0x88, 0xdb, 0xea, 0x7d, 0x4c, 0x1f, 0x2e,
0x43, 0x72, 0x21, 0x10, 0x87, 0xb6, 0xe5, 0xd4,
0xfa, 0xcb, 0x98, 0xa9, 0x3e, 0x0f, 0x5c, 0x6d,
0x86, 0xb7, 0xe4, 0xd5, 0x42, 0x73, 0x20, 0x11,
0x3f, 0x0e, 0x5d, 0x6c, 0xfb, 0xca, 0x99, 0xa8,
0xc5, 0xf4, 0xa7, 0x96, 0x01, 0x30, 0x63, 0x52,
0x7c, 0x4d, 0x1e, 0x2f, 0xb8, 0x89, 0xda, 0xeb,
0x3d, 0x0c, 0x5f, 0x6e, 0xf9, 0xc8, 0x9b, 0xaa,
0x84, 0xb5, 0xe6, 0xd7, 0x40, 0x71, 0x22, 0x13,
0x7e, 0x4f, 0x1c, 0x2d, 0xba, 0x8b, 0xd8, 0xe9,
0xc7, 0xf6, 0xa5, 0x94, 0x03, 0x32, 0x61, 0x50,
0xbb, 0x8a, 0xd9, 0xe8, 0x7f, 0x4e, 0x1d, 0x2c,
0x02, 0x33, 0x60, 0x51, 0xc6, 0xf7, 0xa4, 0x95,
0xf8, 0xc9, 0x9a, 0xab, 0x3c, 0x0d, 0x5e, 0x6f,
0x41, 0x70, 0x23, 0x12, 0x85, 0xb4, 0xe7, 0xd6,
0x7a, 0x4b, 0x18, 0x29, 0xbe, 0x8f, 0xdc, 0xed,
0xc3, 0xf2, 0xa1, 0x90, 0x07, 0x36, 0x65, 0x54,
0x39, 0x08, 0x5b, 0x6a, 0xfd, 0xcc, 0x9f, 0xae,
0x80, 0xb1, 0xe2, 0xd3, 0x44, 0x75, 0x26, 0x17,
0xfc, 0xcd, 0x9e, 0xaf, 0x38, 0x09, 0x5a, 0x6b,
0x45, 0x74, 0x27, 0x16, 0x81, 0xb0, 0xe3, 0xd2,
0xbf, 0x8e, 0xdd, 0xec, 0x7b, 0x4a, 0x19, 0x28,
0x06, 0x37, 0x64, 0x55, 0xc2, 0xf3, 0xa0, 0x91,
0x47, 0x76, 0x25, 0x14, 0x83, 0xb2, 0xe1, 0xd0,
0xfe, 0xcf, 0x9c, 0xad, 0x3a, 0x0b, 0x58, 0x69,
0x04, 0x35, 0x66, 0x57, 0xc0, 0xf1, 0xa2, 0x93,
0xbd, 0x8c, 0xdf, 0xee, 0x79, 0x48, 0x1b, 0x2a,
0xc1, 0xf0, 0xa3, 0x92, 0x05, 0x34, 0x67, 0x56,
0x78, 0x49, 0x1a, 0x2b, 0xbc, 0x8d, 0xde, 0xef,
0x82, 0xb3, 0xe0, 0xd1, 0x46, 0x77, 0x24, 0x15,
0x3b, 0x0a, 0x59, 0x68, 0xff, 0xce, 0x9d, 0xac,
};
/** @brief Lookuptable for d1 parameter depending on supply voltage */
static const int16_t sht1x_d1[] = { -4010, -3980, -3970, -3960, -3940 };
/*---------------------------------------------------------------------------*/
static inline void clk_signal(void)
static inline void clk_signal(const sht1x_dev_t *dev)
{
SHT1X_SCK_HIGH;
xtimer_usleep(SHT1X_CLK_WAIT);
SHT1X_SCK_LOW;
xtimer_usleep(SHT1X_CLK_WAIT);
gpio_set(dev->clk);
xtimer_usleep(SHT1X_HALF_CLOCK);
gpio_clear(dev->clk);
xtimer_usleep(SHT1X_HALF_CLOCK);
}
/*---------------------------------------------------------------------------*/
static uint8_t write_byte(uint8_t value)
static int write_byte(const sht1x_dev_t *dev, uint8_t value)
{
uint8_t i;
uint8_t ack;
int ack;
SHT1X_DATA_OUT;
if (gpio_init(dev->data, GPIO_OUT) == -1) {
return -EIO;
}
/* send value bit by bit to sht11 */
for (i = 0; i < 8; i++) {
/* send value bit by bit to sht1x */
for (int i = 0; i < 8; i++) {
if (value & BIT7) {
SHT1X_DATA_HIGH;
xtimer_usleep(SHT1X_DATA_WAIT);
gpio_set(dev->data);
}
else {
SHT1X_DATA_LOW;
xtimer_usleep(SHT1X_DATA_WAIT);
gpio_clear(dev->data);
}
xtimer_usleep(SHT1X_HALF_CLOCK);
/* trigger clock signal */
clk_signal();
clk_signal(dev);
/* shift value to write next bit */
value = value << 1;
value <<= 1;
}
/* wait for ack */
SHT1X_DATA_IN;
xtimer_usleep(SHT1X_CLK_WAIT);
ack = SHT1X_DATA;
if (gpio_init(dev->data, GPIO_IN) == -1) {
return -EIO;
}
xtimer_usleep(SHT1X_HALF_CLOCK);
ack = gpio_read(dev->data);
clk_signal();
clk_signal(dev);
return ack;
}
/*---------------------------------------------------------------------------*/
static uint8_t read_byte(uint8_t ack)
static int read_byte(const sht1x_dev_t *dev, uint8_t *dest, int ack)
{
uint8_t i;
uint8_t value = 0;
SHT1X_DATA_IN;
xtimer_usleep(SHT1X_DATA_WAIT);
xtimer_usleep(SHT1X_HALF_CLOCK);
/* read value bit by bit */
for (i = 0; i < 8; i++) {
value = value << 1;
SHT1X_SCK_HIGH;
xtimer_usleep(SHT1X_CLK_WAIT);
for (int i = 0; i < 8; i++) {
value <<= 1;
gpio_set(dev->clk);
xtimer_usleep(SHT1X_HALF_CLOCK);
if (SHT1X_DATA) {
/* increase data by one when DATA is high */
value++;
if (gpio_read(dev->data)) {
/* set bit when DATA is high */
value |= 0x01;
}
SHT1X_SCK_LOW;
xtimer_usleep(SHT1X_CLK_WAIT);
gpio_clear(dev->clk);
xtimer_usleep(SHT1X_HALF_CLOCK);
}
/* send ack if necessary */
SHT1X_DATA_OUT;
if (ack) {
SHT1X_DATA_LOW;
xtimer_usleep(SHT1X_DATA_WAIT);
}
else {
SHT1X_DATA_HIGH;
xtimer_usleep(SHT1X_DATA_WAIT);
if (gpio_init(dev->data, GPIO_OUT) == -1) {
return -EIO;
}
clk_signal();
gpio_write(dev->data, ack);
xtimer_usleep(SHT1X_HALF_CLOCK);
clk_signal(dev);
/* release data line */
SHT1X_DATA_IN;
if (gpio_init(dev->data, GPIO_IN) == -1) {
return -EIO;
}
return value;
*dest = value;
return 0;
}
/*---------------------------------------------------------------------------*/
static void transmission_start(void)
static int transmission_start(const sht1x_dev_t *dev)
{
/* _____ ________
DATA: |_______|
___ ___
SCK : ___| |___| |______
*/
SHT1X_DATA_OUT;
*/
if (gpio_init(dev->data, GPIO_OUT) == -1) {
return -EIO;
}
/* set initial state */
SHT1X_DATA_HIGH;
xtimer_usleep(SHT1X_DATA_WAIT);
SHT1X_SCK_LOW;
xtimer_usleep(SHT1X_CLK_WAIT);
gpio_set(dev->data);
xtimer_usleep(SHT1X_HALF_CLOCK);
gpio_clear(dev->clk);
xtimer_usleep(SHT1X_HALF_CLOCK);
SHT1X_SCK_HIGH;
xtimer_usleep(SHT1X_CLK_WAIT);
gpio_set(dev->clk);
xtimer_usleep(SHT1X_HALF_CLOCK);
SHT1X_DATA_LOW;
xtimer_usleep(SHT1X_DATA_WAIT);
gpio_clear(dev->data);
xtimer_usleep(SHT1X_HALF_CLOCK);
SHT1X_SCK_LOW;
xtimer_usleep(SHT1X_CLK_WAIT);
gpio_clear(dev->clk);
xtimer_usleep(SHT1X_HALF_CLOCK);
SHT1X_SCK_HIGH;
xtimer_usleep(SHT1X_CLK_WAIT);
gpio_set(dev->clk);
xtimer_usleep(SHT1X_HALF_CLOCK);
SHT1X_DATA_HIGH;
xtimer_usleep(SHT1X_DATA_WAIT);
gpio_set(dev->data);
xtimer_usleep(SHT1X_HALF_CLOCK);
SHT1X_SCK_LOW;
xtimer_usleep(SHT1X_CLK_WAIT);
gpio_clear(dev->clk);
xtimer_usleep(SHT1X_HALF_CLOCK);
if (gpio_init(dev->data, GPIO_IN) == -1) {
return -EIO;
}
return 0;
}
/*---------------------------------------------------------------------------*/
static void connection_reset(void)
static int connection_reset(const sht1x_dev_t *dev)
{
/* _____________________________________________________ ____
DATA: |_______|
_ _ _ _ _ _ _ _ _ ___ ___
SCK : __| |__| |__| |__| |__| |__| |__| |__| |__| |______| |___| |__
*/
uint8_t i;
SHT1X_DATA_HIGH;
xtimer_usleep(SHT1X_DATA_WAIT);
SHT1X_SCK_LOW;
xtimer_usleep(SHT1X_CLK_WAIT);
for (i = 0; i < 9; i++) {
clk_signal();
*/
if (gpio_init(dev->data, GPIO_OUT) == -1) {
return -EIO;
}
transmission_start();
gpio_set(dev->data);
xtimer_usleep(SHT1X_HALF_CLOCK);
gpio_clear(dev->clk);
xtimer_usleep(SHT1X_HALF_CLOCK);
for (int i = 0; i < 9; i++) {
clk_signal(dev);
}
return transmission_start(dev);
}
/*---------------------------------------------------------------------------*/
static uint8_t measure(uint8_t *p_value, uint8_t *p_checksum, uint8_t mode)
static inline uint8_t crc_initial_value(uint8_t status)
{
uint8_t error = 0;
uint8_t ack = 1;
uint16_t i;
status &= 0x07;
transmission_start();
error = write_byte(mode);
return (
((0x01 & status) << 7) |
((0x02 & status) << 5) |
((0x04 & status) << 3)
);
}
xtimer_usleep(1000);
/*---------------------------------------------------------------------------*/
static inline uint8_t reverse_byte(uint8_t value)
{
uint8_t result = (value & 0x01) << 7;
/* wait untile sensor has finished measurement or timeout */
for (i = 0; (i < SHT1X_MEASURE_TIMEOUT) && (!error); i++) {
ack = SHT1X_DATA;
result |= (value & 0x02) << 5;
result |= (value & 0x04) << 3;
result |= (value & 0x08) << 1;
result |= (value & 0x10) >> 1;
result |= (value & 0x20) >> 3;
result |= (value & 0x40) >> 5;
result |= (value & 0x80) >> 7;
if (!ack) {
break;
}
return result;
}
xtimer_usleep(1000);
/*---------------------------------------------------------------------------*/
static int measure(const sht1x_dev_t *dev, uint16_t *value, uint8_t mode)
{
uint8_t data[2] = { 0, 0 };
int retval;
retval = transmission_start(dev);
if (retval != 0) {
return retval;
}
error += ack;
switch (write_byte(dev, mode)) {
case -EIO:
return -EIO;
case 0:
break;
default:
case 1:
return -EPROTO;
}
/* wait until sensor has finished measurement or timeout */
{
int ack = 1;
for (int i = 0; ack != 0; i++) {
if (i > SHT1X_MEASURE_TIMEOUT) {
return -ECANCELED;
}
xtimer_usleep(1000);
ack = gpio_read(dev->data);
}
}
/* read MSB */
*(p_value + 1) = read_byte(SHT1X_ACK);
/* read LSB */
*(p_value) = read_byte(SHT1X_ACK);
/* read checksum */
*p_checksum = read_byte(SHT1X_NO_ACK);
return (!error);
}
/*---------------------------------------------------------------------------*/
void sht1x_init(void)
{
sht1x_temperature_offset = 0;
SHT1X_INIT;
xtimer_usleep(11 * 1000);
}
/*---------------------------------------------------------------------------*/
uint8_t sht1x_read_status(uint8_t *p_value, uint8_t *p_checksum)
{
uint8_t error = 0;
transmission_start();
error |= write_byte(SHT1X_STATUS_REG_R);
*p_value = read_byte(SHT1X_ACK);
*p_checksum = read_byte(SHT1X_NO_ACK);
return (!error);
}
/*---------------------------------------------------------------------------*/
uint8_t sht1x_write_status(uint8_t *p_value)
{
uint8_t error = 0;
transmission_start();
error += write_byte(SHT1X_STATUS_REG_W);
error += write_byte(*p_value);
return (!error);
}
/*---------------------------------------------------------------------------*/
uint8_t sht1x_read_sensor(sht1x_val_t *value, sht1x_mode_t mode)
{
uint8_t error = 0;
uint8_t checksum;
uint16_t humi_int, temp_int;
/* Temperature arithmetic where S0(T) is read value
* T = D1 + D2 * S0(T) */
const float D1 = -39.6;
const float D2 = 0.01;
/* Arithmetic for linear humdity where S0(RH) is read value
* HL = C1 + C2 * S0(RH) + C3 * SO(RH)^2 */
const float C1 = -4.0;
const float C2 = +0.0405;
const float C3 = -0.0000028;
/* Arithmetic for temperature compesated relative humdity
* HT = (T-25) * ( T1 + T2 * SO(RH) ) + HL */
const float T1 = +0.01;
const float T2 = +0.00008;
/* check for valid buffer */
if (value == NULL) {
return 0;
retval = read_byte(dev, &data[0], SHT1X_ACK);
if (retval != 0) {
return retval;
}
value->temperature = 0;
value->relhum = 0;
value->relhum_temp = 0;
mutex_lock(&sht1x_mutex);
connection_reset();
/* measure humidity */
if (mode & HUMIDITY) {
error += (!measure((uint8_t *) &humi_int, &checksum, SHT1X_MEASURE_HUMI));
/* read LSB, send ACK only if CRC checking is enabled */
retval = (dev->conf & SHT1X_CONF_SKIP_CRC) ? SHT1X_NO_ACK : SHT1X_ACK;
retval = read_byte(dev, &data[1], retval);
if (retval != 0) {
return retval;
}
/* measure temperature */
if (mode & TEMPERATURE) {
error += (!measure((uint8_t *) &temp_int, &checksum, SHT1X_MEASURE_TEMP));
}
if (!(dev->conf & SHT1X_CONF_SKIP_CRC)) {
uint8_t crc;
uint8_t expected;
/* break on error */
if (error != 0) {
connection_reset();
mutex_unlock(&sht1x_mutex);
return 0;
}
retval = read_byte(dev, &crc, SHT1X_NO_ACK);
if (retval != 0) {
return retval;
}
if (mode & TEMPERATURE) {
value->temperature = D1 + (D2 * ((float) temp_int)) + sht1x_temperature_offset;
}
if (mode & HUMIDITY) {
value->relhum = C1 + (C2 * ((float) humi_int)) + (C3 * ((float) humi_int) * ((float) humi_int));
if (mode & TEMPERATURE) {
value->relhum_temp = (value->temperature - 25) * (T1 + (T2 * (float) humi_int)) + value->relhum;
expected = crc_initial_value(dev->conf);
expected = crc_lookup_table[expected ^ mode];
expected = crc_lookup_table[expected ^ data[0]];
expected = crc_lookup_table[expected ^ data[1]];
expected = reverse_byte(expected);
if (expected != crc) {
DEBUG("[sht1x] CRC expected: 0x%02x, got: 0x%02x\n"
" CRC0: 0x%02x, CMD: 0x%02x, data: {0x%02x, 0x%02x}\n",
(int)expected, (int)crc,
(int)crc_initial_value(dev->conf), mode,
(int)data[0], (int)data[1]);
return -EBADMSG;
}
}
mutex_unlock(&sht1x_mutex);
return 1;
*value = (((uint16_t)data[0]) << 8) | (uint16_t)data[1];
return 0;
}
/*---------------------------------------------------------------------------*/
int sht1x_init(sht1x_dev_t *dev, const sht1x_params_t *params)
{
if (
!dev ||
!params ||
(((uint8_t)params->vdd) >= sizeof(sht1x_d1) / sizeof(sht1x_d1[0]))
) {
return -EINVAL;
}
dev->clk = params->clk;
dev->data = params->data;
if (gpio_init(dev->clk, GPIO_OUT) || gpio_init(dev->data, GPIO_IN)) {
return -EIO;
}
dev->temp_off = 0;
dev->hum_off = 0;
dev->conf = 0;
dev->vdd = (uint8_t)params->vdd;
return sht1x_reset(dev);
}
/*---------------------------------------------------------------------------*/
int16_t sht1x_temperature(const sht1x_dev_t *dev, uint16_t raw)
{
if (!dev || (dev->vdd >= sizeof(sht1x_d1) / sizeof(sht1x_d1[0]))) {
return INT16_MIN;
}
int16_t d1 = sht1x_d1[dev->vdd];
int16_t d2 = (dev->conf & SHT1X_CONF_LOW_RESOLUTION) ? 4 : 1;
return d1 + d2 * ((int16_t)raw);
}
/*---------------------------------------------------------------------------*/
int16_t sht1x_humidity(const sht1x_dev_t *dev, uint16_t raw, int16_t temp)
{
if (!dev) {
return -1;
}
static const int32_t c1 = -20468;
static const int32_t t1 = 1;
int32_t c2, c3, c4, t2;
if (dev->conf & SHT1X_CONF_LOW_RESOLUTION) {
c2 = 5872;
c3 = 494801;
c4 = 1000000;
t2 = 781;
}
else {
c2 = 367;
c3 = 791684;
c4 = 100000;
t2 = 12500;
}
/*
* Calculate linear humidity, but slightly different. Original formula:
*
* hum_lin = c1 + c2 * raw + c3 * (raw * raw)
*
* But we use:
*
* hum_lin = c1 + c2 * raw - (c4 * raw / c3') * (c4 * raw / c3')
*
* where: c3' = 1 / (sqrt(-c3) / c4)
*
* (This better fits for integer calculation)
*/
int32_t res = ((int32_t)raw * c4) / c3;
res = c1 + c2 * (int32_t)raw - (res * res);
/*
* Perform temperature compensation, again slightly different.
* Original formula:
*
* hum_true = (temp - 25) * (t1 + t2 * raw) + hum_lin
*
* But we use:
*
* hum_true = (temp - 25) * t1 + (temp - 25) * raw / t2') + hum_lin
*
* where t2' = 1/t2
*/
int32_t temp_diff = temp - 2500;
res = temp_diff * t1 + (temp_diff * (int32_t)raw * 100) / t2 + res;
return (int16_t)(res / 100);
}
/*---------------------------------------------------------------------------*/
int sht1x_read(const sht1x_dev_t *dev, int16_t *temp, int16_t *rel_hum)
{
uint16_t temp_raw;
int16_t t;
uint16_t hum_raw;
int retval;
if (
!dev ||
(dev->vdd >= sizeof(sht1x_d1) / sizeof(sht1x_d1[0])) ||
(!temp && !rel_hum)
) {
return -EINVAL;
}
retval = measure(dev, &temp_raw, SHT1X_MEASURE_TEMP);
if (retval != 0) {
connection_reset(dev);
return retval;
}
t = sht1x_temperature(dev, temp_raw) + dev->temp_off;
if (temp != NULL) {
*temp = t;
}
if (rel_hum != NULL) {
retval = measure(dev, &hum_raw, SHT1X_MEASURE_HUM);
if (retval != 0) {
connection_reset(dev);
return retval;
}
*rel_hum = sht1x_humidity(dev, hum_raw, t) + dev->hum_off;
}
return 0;
}
/*---------------------------------------------------------------------------*/
int sht1x_configure(sht1x_dev_t *dev, sht1x_conf_t conf)
{
if (!dev) {
return -EINVAL;
}
/* Apply config that is not stored on the sensor */
dev->conf &= SHT1X_CONF_MASK;
dev->conf |= conf & (~(SHT1X_CONF_MASK));
/* Send new status byte to sensor, if on-device config was changed */
if ((conf & SHT1X_CONF_MASK) != (dev->conf & SHT1X_CONF_MASK)) {
int retval = transmission_start(dev);
if (retval != 0) {
return retval;
}
switch (write_byte(dev, SHT1X_STATUS_REG_W)) {
case -EIO:
return -EIO;
case 0:
break;
default:
case 1:
return -EPROTO;
}
switch (write_byte(dev, conf & SHT1X_CONF_MASK)) {
case -EIO:
return -EIO;
case 0:
break;
default:
case 1:
return -EPROTO;
}
/* Read back uploaded configuration to verify that sensor applied it */
uint8_t status;
retval = sht1x_read_status(dev, &status);
if (retval != 0) {
return retval;
}
if (dev->conf != conf) {
/* Configuration was not applied by sensor */
return -ECANCELED;
}
}
return 0;
}
/*---------------------------------------------------------------------------*/
int sht1x_read_status(sht1x_dev_t *dev, uint8_t *status)
{
int retval;
if (!dev || !status) {
return -EINVAL;
}
retval = transmission_start(dev);
if (retval != 0) {
return retval;
}
switch (write_byte(dev, SHT1X_STATUS_REG_R)) {
case -EIO:
return -EIO;
case 0:
break;
default:
case 1:
return -EPROTO;
}
retval = read_byte(dev, status, SHT1X_ACK);
if (retval != 0) {
return retval;
}
{
uint8_t crc;
uint8_t expected;
/* read checksum */
retval = read_byte(dev, &crc, SHT1X_NO_ACK);
if (retval != 0) {
return retval;
}
expected = crc_initial_value(*status);
expected = crc_lookup_table[expected ^ SHT1X_STATUS_REG_R];
expected = crc_lookup_table[expected ^ *status];
expected = reverse_byte(expected);
if (expected != crc) {
DEBUG("[sht1x] CRC expected: 0x%02x, got: 0x%02x\n"
" CRC0: 0x%02x, CMD: 0x%02x, data: {0x%02x}\n",
(int)expected, (int)crc,
(int)crc_initial_value(*status), SHT1X_STATUS_REG_R,
(int)*status);
return -EBADMSG;
}
}
/* Extract config from status and store it after CRC check passed */
dev->conf &= ~(SHT1X_CONF_MASK);
dev->conf |= *status & SHT1X_CONF_MASK;
return 0;
}
/*---------------------------------------------------------------------------*/
int sht1x_reset(sht1x_dev_t *dev)
{
int retval;
if (!dev) {
return -EINVAL;
}
retval = transmission_start(dev);
if (retval != 0) {
return retval;
}
switch (write_byte(dev, SHT1X_RESET)) {
case -EIO:
return -EIO;
case 0:
break;
default:
case 1:
return -EPROTO;
}
dev->conf = 0;
xtimer_usleep(SHT1X_RESET_WAIT);
return 0;
}

View File

@ -20,10 +20,6 @@
#include "auto_init.h"
#ifdef MODULE_SHT1X
#include "sht1x.h"
#endif
#ifdef MODULE_MCI
#include "diskio.h"
#endif
@ -101,10 +97,6 @@ void auto_init(void)
DEBUG("Auto init xtimer module.\n");
xtimer_init();
#endif
#ifdef MODULE_SHT1X
DEBUG("Auto init SHT1X module.\n");
sht1x_init();
#endif
#ifdef MODULE_MCI
DEBUG("Auto init mci module.\n");
mci_initialize();
@ -275,6 +267,12 @@ void auto_init(void)
#endif
/* initialize sensors and actuators */
#ifdef MODULE_SHT1X
DEBUG("Auto init SHT1X module (SHT10/SHT11/SHT15 sensor driver).\n");
extern void auto_init_sht1x(void);
auto_init_sht1x();
#endif
#ifdef MODULE_AUTO_INIT_SAUL
DEBUG("auto_init SAUL\n");

View File

@ -0,0 +1,74 @@
/*
* Copyright 2018 Otto-von-Guericke-Universität Magdeburg
*
* 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
* @{
*
* @file
* @brief Auto initialization for SHT1X temperature/humidity sensors
*
* @author Marian Buschsieweke <marian.buschsieweke@ovgu.de>
*
* @}
*/
#ifdef MODULE_SHT1X
#include "log.h"
#include "sht1x_params.h"
#include "sht1x.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
/**
* @brief Define the number of configured sensors
*/
#define SHT1X_NUM (sizeof(sht1x_params) / sizeof(sht1x_params[0]))
/**
* @brief Allocate memory for the device descriptors
*/
sht1x_dev_t sht1x_devs[SHT1X_NUM];
static void sht1x_error(unsigned int num, const char *reason)
{
LOG_ERROR("[auto_init] error initializing SHT10/SHT11/SHT15 sensor "
"#%u: %s\n", num, reason);
}
void auto_init_sht1x(void)
{
for (unsigned int i = 0; i < SHT1X_NUM; i++) {
DEBUG("[auto_init_sht1x] Initializing SHT1X sensor #%u\n", i);
switch (sht1x_init(&sht1x_devs[i], &sht1x_params[i])) {
case 0:
break;
case -EIO:
sht1x_error(i, "Failed to initialize GPIOs");
continue;
case -EINVAL:
sht1x_error(i, "Invalid configuration for VDD");
continue;
case -EPROTO:
sht1x_error(i, "Reset command not acknowledged");
continue;
default:
/* Should not happen, but better safe than sorry */
sht1x_error(i, "?");
continue;
}
}
}
#else
typedef int dont_be_pedantic;
#endif /* MODULE_SHT1X */

View File

@ -1,5 +1,6 @@
/*
* Copyright (C) 2013 INRIA.
* Copyright (C) 2013 INRIA
* 2018 Otto-von-Guericke-Universität Magdeburg
*
* 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
@ -11,102 +12,367 @@
* @{
*
* @file
* @brief Provides shell commands to poll sht11 sensor
* @brief Provides shell commands to access SHT10/SHT11/SHT15 sensors
*
* @author Oliver Hahm <oliver.hahm@inria.fr>
* @author Marian Buschsieweke <marian.buschsieweke@ovgu.de>
*
* @}
*/
#ifdef MODULE_SHT1X
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "sht1x.h"
#include "sht1x_params.h"
#ifdef MODULE_SHT1X
#define SHT1X_NUM (sizeof(sht1x_params) / sizeof(sht1x_params[0]))
extern float sht1x_temperature_offset;
extern sht1x_dev_t sht1x_devs[SHT1X_NUM];
static sht1x_dev_t *get_dev(int argc, char **argv)
{
switch (argc) {
case 1:
return &sht1x_devs[0];
case 2:
{
int pos = atoi(argv[1]);
if ((pos < 0) || (pos >= (int)SHT1X_NUM)) {
printf("No SHT10/SHT11/SHT15 device with number %i\n", pos);
return NULL;
}
return &sht1x_devs[pos];
}
default:
break;
}
printf("Usage: %s [DEVICE_NUMBER]\n", argv[0]);
return NULL;
}
static void error_msg(const char *msg)
{
printf("[sht1x] Operation failed: %s\n", msg);
}
static int read_sensor(int16_t *temp, int16_t *hum, int argc, char **argv)
{
const sht1x_dev_t *dev = get_dev(argc, argv);
if (!dev) {
return -1;
}
switch (sht1x_read(dev, temp, hum)) {
case 0:
break;
case -EIO:
error_msg("gpio_init() failed");
return -1;
case -EBADMSG:
error_msg("CRC checksum error");
return -1;
case -ECANCELED:
error_msg("Measurement timed out");
return -1;
case -EPROTO:
error_msg("Sensor did not acknowledge command");
return -1;
default:
/* Should never happen, but better safe the sorry */
error_msg("Unknown error");
return -1;
}
return 0;
}
int _get_humidity_handler(int argc, char **argv)
{
(void) argc;
(void) argv;
int16_t hum;
uint8_t success;
sht1x_val_t sht1x_val;
success = sht1x_read_sensor(&sht1x_val, HUMIDITY | TEMPERATURE);
if (!success) {
printf("Error reading SHT11\n");
return 1;
if (read_sensor(NULL, &hum, argc, argv)) {
return -1;
}
else {
printf("Relative humidity: %5.2f%% / Temperature compensated humidity; %5.2f%%\n",
(double) sht1x_val.relhum, (double) sht1x_val.relhum_temp);
return 0;
}
printf("Relative humidity: %i.%02i%%\n", (int)hum / 100, (int)hum % 100);
return 0;
}
int _get_temperature_handler(int argc, char **argv)
{
(void) argc;
(void) argv;
int16_t temp;
uint8_t success;
sht1x_val_t sht1x_val;
success = sht1x_read_sensor(&sht1x_val, TEMPERATURE);
if (!success) {
printf("Error reading SHT11\n");
return 1;
if (read_sensor(&temp, NULL, argc, argv)) {
return -1;
}
else {
printf("Temperature: %-6.2f°C\n", (double) sht1x_val.temperature);
return 0;
}
printf("Temperature: %i.%02i°C\n", (int)temp / 100, (int)temp % 100);
return 0;
}
int _get_weather_handler(int argc, char **argv)
{
(void) argc;
(void) argv;
int16_t hum;
int16_t temp;
uint8_t success;
sht1x_val_t sht1x_val;
success = sht1x_read_sensor(&sht1x_val, HUMIDITY | TEMPERATURE);
if (!success) {
printf("Error reading SHT11\n");
return 1;
if (read_sensor(&temp, &hum, argc, argv)) {
return -1;
}
else {
printf("Relative humidity: %5.2f%% / Temperature compensated humidity; %5.2f%% ",
(double) sht1x_val.relhum, (double) sht1x_val.relhum_temp);
printf("Temperature: %-6.2f°C\n", (double) sht1x_val.temperature);
return 0;
}
printf("Relative humidity: %i.%02i%%\n", (int)hum / 100, (int)hum % 100);
printf("Temperature: %i.%02i°C\n", (int)temp / 100, (int)temp % 100);
return 0;
}
int _set_offset_handler(int argc, char **argv)
static void print_config(const sht1x_dev_t *dev)
{
if (argc != 2) {
printf("Usage: %s <OFFSET>\n", argv[0]);
const char *vdds[] = { "5.0", "4.0", "3.5", "3.0", "2.5" };
return 1;
}
else {
sht1x_temperature_offset = atoi(argv[1]);
printf("Temperature offset set to %f\n", (double) sht1x_temperature_offset);
printf("Sensor VDD = %s\n", vdds[dev->vdd]);
printf("Temperature offset [-t]: %i\n", (int)dev->temp_off);
printf("Humidity offset [-h]: %i\n", (int)dev->hum_off);
printf("Resolution [-r]: %s\n",
(dev->conf & SHT1X_CONF_LOW_RESOLUTION) ? "low" : "high");
printf("Skip calibration (faster reading) [-c]: %s\n",
(dev->conf & SHT1X_CONF_SKIP_CALIBRATION) ? "yes" : "no");
printf("Heater [-H]: %s\n",
(dev->conf & SHT1X_CONF_ENABLE_HEATER) ? "on" : "off");
printf("CRC checking [-C]: %s\n",
(dev->conf & SHT1X_CONF_SKIP_CRC) ? "off" : "on");
}
static void unknown_parameter(int index, char **argv)
{
printf("Unknown parameter \"%s\"\n"
"Usage: \"%s [PARAMS]\", run \"%s --help\" for help\n",
argv[index], argv[0], argv[0]);
}
static void missing_argument(int index, char **argv)
{
printf("Missing argument for parameter \"%s\"\n"
"Usage: \"%s [%s <ARG>][PARAMS]\", run \"%s --help\" for help\n",
argv[index], argv[0], argv[index], argv[0]);
}
static void invalid_argument(int index, char **argv, const char *valid)
{
printf("Invalid argument \"%s\" for parameter \"%s\"\n"
"Valid arguments are: \"%s\", run \"%s --help\" for help\n",
argv[index + 1], argv[index], valid, argv[0]);
}
int _sht_config_handler(int argc, char **argv)
{
uint8_t set_conf = 0;
uint8_t unset_conf = 0;
int16_t temp_off = INT16_MAX;
int16_t hum_off = INT16_MAX;
int dev_num = 0;
if ((argc == 2) && (strcmp("--help", argv[1]) == 0)) {
printf("Usage: \"%s [PARMS]\n"
"\n"
"Supported parameters:\n"
" -d <NUM>\n"
" Use SHT10/11/15 sensor number <NUM>. Default: 0\n"
"\n"
" -t <OFFSET>\n"
" Add <OFFSET> (in e-2°C) to all temperature measurements\n"
"\n"
" -h <OFFSET>\n"
" Add <OFFSET> (in e-2%%) to all humidity measurements\n"
"\n"
" -r l/h\n"
" Set resolution to low/high. Low resolution trades "
"presicion for speed\n"
"\n"
" -H y/n\n"
" Turns heater on/off. Can increase temperature by up to "
"10°C\n"
"\n"
" -C y/n\n"
" Turns on/off CRC checking. No checking trades robustness "
"for speed\n",
argv[0]);
return 0;
}
for (int i = 1; i < argc; i++) {
if ((argv[i][0] != '-') || (!argv[i][1]) || (argv[i][2])) {
unknown_parameter(i, argv);
return -1;
}
switch (argv[i][1]) {
case 'd':
if (++i >= argc) {
missing_argument(i - 1, argv);
return -1;
}
dev_num = atoi(argv[i]);
if ((dev_num < 0) || (dev_num >= (int)SHT1X_NUM)) {
printf("No SHT10/11/15 sensor with number %i\n", dev_num);
return -1;
}
break;
case 't':
if (++i >= argc) {
missing_argument(i - 1, argv);
return -1;
}
temp_off = (int16_t)atoi(argv[i]);
break;
case 'h':
if (++i >= argc) {
missing_argument(i - 1, argv);
return -1;
}
hum_off = (int16_t)atoi(argv[i]);
break;
case 'r':
if (++i >= argc) {
missing_argument(i - 1, argv);
return -1;
}
if ((!argv[i][0]) || (argv[i][1])) {
invalid_argument(i - 1, argv, "l, h");
return -1;
}
switch (argv[i][0]) {
case 'l':
set_conf |= SHT1X_CONF_LOW_RESOLUTION;
break;
case 'h':
unset_conf |= SHT1X_CONF_LOW_RESOLUTION;
break;
default:
invalid_argument(i - 1, argv, "l, h");
return -1;
}
break;
case 'c':
if (++i >= argc) {
missing_argument(i - 1, argv);
return -1;
}
if ((!argv[i][0]) || (argv[i][1])) {
invalid_argument(i - 1, argv, "y, n");
return -1;
}
switch (argv[i][0]) {
case 'y':
set_conf |= SHT1X_CONF_SKIP_CALIBRATION;
break;
case 'n':
unset_conf |= SHT1X_CONF_SKIP_CALIBRATION;
break;
default:
invalid_argument(i - 1, argv, "y, n");
return -1;
}
break;
case 'H':
if (++i >= argc) {
missing_argument(i - 1, argv);
return -1;
}
if ((!argv[i][0]) || (argv[i][1])) {
invalid_argument(i - 1, argv, "y, n");
return -1;
}
switch (argv[i][0]) {
case 'y':
set_conf |= SHT1X_CONF_ENABLE_HEATER;
break;
case 'n':
unset_conf |= SHT1X_CONF_ENABLE_HEATER;
break;
default:
invalid_argument(i - 1, argv, "y, n");
return -1;
}
break;
case 'C':
if (++i >= argc) {
missing_argument(i - 1, argv);
return -1;
}
if ((!argv[i][0]) || (argv[i][1])) {
invalid_argument(i - 1, argv, "y, n");
return -1;
}
switch (argv[i][0]) {
case 'y':
unset_conf |= SHT1X_CONF_SKIP_CRC;
break;
case 'n':
set_conf |= SHT1X_CONF_SKIP_CRC;
break;
default:
invalid_argument(i - 1, argv, "y, n");
return -1;
}
break;
default:
unknown_parameter(i, argv);
return -1;
}
}
if ((set_conf) || (unset_conf)) {
/* Apply new configuration */
uint8_t new_conf = sht1x_devs[dev_num].conf;
new_conf &= ~(unset_conf);
new_conf |= set_conf;
switch (sht1x_configure(&sht1x_devs[dev_num], new_conf)) {
case 0:
break;
case -EIO:
error_msg("gpio_init() failed");
return -1;
case -EBADMSG:
error_msg("CRC checksum error");
return -1;
case -ECANCELED:
error_msg("Sensor did not apply configuration");
return -1;
case -EPROTO:
error_msg("Sensor did not acknowledge command");
return -1;
default:
/* Should never happen, but better safe the sorry */
error_msg("Unknown error");
return -1;
}
}
if (temp_off != INT16_MAX) {
if ((temp_off > 2000) || (temp_off < -2000)) {
printf("A temperature offset of %i.%02i°C is unreasonable\n",
(int)temp_off / 100, (int)temp_off % 100);
return -1;
}
sht1x_devs[dev_num].temp_off = temp_off;
}
if (hum_off != INT16_MAX) {
if ((hum_off > 1000) || (hum_off < -1000)) {
printf("A humidity offset of %i.%02i%% is unreasonable\n",
(int)hum_off / 100, (int)hum_off % 100);
return -1;
}
sht1x_devs[dev_num].hum_off = hum_off;
}
print_config(&sht1x_devs[dev_num]);
return 0;
}
#endif

View File

@ -41,7 +41,7 @@ extern int _ps_handler(int argc, char **argv);
extern int _get_temperature_handler(int argc, char **argv);
extern int _get_humidity_handler(int argc, char **argv);
extern int _get_weather_handler(int argc, char **argv);
extern int _set_offset_handler(int argc, char **argv);
extern int _sht_config_handler(int argc, char **argv);
#endif
#ifdef MODULE_LTC4150
@ -157,7 +157,7 @@ const shell_command_t _shell_command_list[] = {
{"temp", "Prints measured temperature.", _get_temperature_handler},
{"hum", "Prints measured humidity.", _get_humidity_handler},
{"weather", "Prints measured humidity and temperature.", _get_weather_handler},
{"offset", "Set temperature offset.", _set_offset_handler},
{"sht-config", "Get/set SHT10/11/15 sensor configuration.", _sht_config_handler},
#endif
#ifdef MODULE_LTC4150
{"cur", "Prints current and average power consumption.", _get_current_handler},