From d208c224b06561915183f6acddf5e6a69a356ab5 Mon Sep 17 00:00:00 2001 From: Marian Buschsieweke Date: Wed, 13 Jun 2018 08:26:30 +0200 Subject: [PATCH 1/5] drivers: Renamed module sht11 to sht1x The sensor family SHT10, SHT11 and SHT15 only differ in their accuracy (as in calibration, not as in resolution). Thus, the same driver can be used for all. The new driver name better reflects this fact. --- .../include/{sht11-board.h => sht1x-board.h} | 22 +-- .../include/{sht11-board.h => sht1x-board.h} | 22 +-- drivers/Makefile.dep | 3 +- drivers/include/{sht11.h => sht1x.h} | 49 +++--- drivers/{sht11 => sht1x}/Makefile | 0 drivers/{sht11/sht11.c => sht1x/sht1x.c} | 146 +++++++++--------- makefiles/pseudomodules.inc.mk | 5 + sys/auto_init/auto_init.c | 10 +- sys/shell/commands/Makefile | 4 +- sys/shell/commands/{sc_sht11.c => sc_sht1x.c} | 30 ++-- sys/shell/commands/shell_commands.c | 4 +- 11 files changed, 151 insertions(+), 144 deletions(-) rename boards/common/msb-430/drivers/include/{sht11-board.h => sht1x-board.h} (56%) rename boards/common/msba2/drivers/include/{sht11-board.h => sht1x-board.h} (65%) rename drivers/include/{sht11.h => sht1x.h} (60%) rename drivers/{sht11 => sht1x}/Makefile (100%) rename drivers/{sht11/sht11.c => sht1x/sht1x.c} (72%) rename sys/shell/commands/{sc_sht11.c => sc_sht1x.c} (69%) diff --git a/boards/common/msb-430/drivers/include/sht11-board.h b/boards/common/msb-430/drivers/include/sht1x-board.h similarity index 56% rename from boards/common/msb-430/drivers/include/sht11-board.h rename to boards/common/msb-430/drivers/include/sht1x-board.h index a79fe22b4d..873504d47c 100644 --- a/boards/common/msb-430/drivers/include/sht11-board.h +++ b/boards/common/msb-430/drivers/include/sht1x-board.h @@ -6,8 +6,8 @@ * directory for more details. */ -#ifndef SHT11_BOARD_H -#define SHT11_BOARD_H +#ifndef SHT1X_BOARD_H +#define SHT1X_BOARD_H /** * @ingroup boards_common_msb-430 @@ -32,18 +32,18 @@ extern "C" { * DATA = P3B4 */ -#define SHT11_SCK_LOW P3OUT &= ~(BIT5); /**< serial clock line low */ -#define SHT11_SCK_HIGH P3OUT |= BIT5; /**< serial clock line high */ -#define SHT11_DATA (P3IN & BIT5) /**< read serial I/O */ -#define SHT11_DATA_LOW P3OUT &= ~(BIT5); /**< serial I/O line low */ -#define SHT11_DATA_HIGH P3OUT |= BIT5; /**< serial I/O line high */ -#define SHT11_DATA_IN P3DIR &= ~(BIT5); /**< serial I/O as input */ -#define SHT11_DATA_OUT P3DIR |= BIT5; /**< serial I/O as output */ -#define SHT11_INIT P3DIR |= BIT5; /* FIO1DIR |= BIT25; PINSEL3 &= ~(BIT14|BIT15 | BIT16|BIT17); */ +#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 /* SHT11_BOARD_H */ +#endif /* SHT1X_BOARD_H */ diff --git a/boards/common/msba2/drivers/include/sht11-board.h b/boards/common/msba2/drivers/include/sht1x-board.h similarity index 65% rename from boards/common/msba2/drivers/include/sht11-board.h rename to boards/common/msba2/drivers/include/sht1x-board.h index 7ee0009965..a70589b9ab 100644 --- a/boards/common/msba2/drivers/include/sht11-board.h +++ b/boards/common/msba2/drivers/include/sht1x-board.h @@ -6,8 +6,8 @@ * directory for more details. */ -#ifndef SHT11_BOARD_H -#define SHT11_BOARD_H +#ifndef SHT1X_BOARD_H +#define SHT1X_BOARD_H /** * @ingroup boards_common_msba2 @@ -32,25 +32,25 @@ extern "C" { #endif /* serial clock line low */ -#define SHT11_SCK_LOW FIO1CLR = BIT25; +#define SHT1X_SCK_LOW FIO1CLR = BIT25; /* serial clock line high */ -#define SHT11_SCK_HIGH FIO1SET = BIT25; +#define SHT1X_SCK_HIGH FIO1SET = BIT25; /* read serial I/O */ -#define SHT11_DATA ((FIO1PIN & BIT26) != 0) +#define SHT1X_DATA ((FIO1PIN & BIT26) != 0) /* serial I/O line low */ -#define SHT11_DATA_LOW (FIO1CLR = BIT26); +#define SHT1X_DATA_LOW (FIO1CLR = BIT26); /* serial I/O line high */ -#define SHT11_DATA_HIGH (FIO1SET = BIT26); +#define SHT1X_DATA_HIGH (FIO1SET = BIT26); /* serial I/O as input */ -#define SHT11_DATA_IN (FIO1DIR &= ~BIT26) +#define SHT1X_DATA_IN (FIO1DIR &= ~BIT26) /* serial I/O as output */ -#define SHT11_DATA_OUT (FIO1DIR |= BIT26) +#define SHT1X_DATA_OUT (FIO1DIR |= BIT26) -#define SHT11_INIT FIO1DIR |= BIT25; PINSEL3 &= ~(BIT14|BIT15 | BIT16|BIT17); +#define SHT1X_INIT FIO1DIR |= BIT25; PINSEL3 &= ~(BIT14|BIT15 | BIT16|BIT17); #ifdef __cplusplus } #endif /** @} */ -#endif /* SHT11_BOARD_H */ +#endif /* SHT1X_BOARD_H */ diff --git a/drivers/Makefile.dep b/drivers/Makefile.dep index d9bed242d2..4a95122c30 100644 --- a/drivers/Makefile.dep +++ b/drivers/Makefile.dep @@ -302,7 +302,8 @@ ifneq (,$(filter servo,$(USEMODULE))) FEATURES_REQUIRED += periph_pwm endif -ifneq (,$(filter sht11,$(USEMODULE))) +ifneq (,$(filter sht1%,$(USEMODULE))) + USEMODULE += sht1x USEMODULE += xtimer endif diff --git a/drivers/include/sht11.h b/drivers/include/sht1x.h similarity index 60% rename from drivers/include/sht11.h rename to drivers/include/sht1x.h index 2378ca8c1b..447aa74a1f 100644 --- a/drivers/include/sht11.h +++ b/drivers/include/sht1x.h @@ -7,19 +7,20 @@ */ /** - * @defgroup drivers_sht11 SHT11 Humidity and Temperature Sensor + * @defgroup drivers_sht1x SHT10/SHT11/SHT15 Humidity and Temperature Sensor * @ingroup drivers_sensors - * @brief Driver for Sensirion SHT11 Humidity and Temperature Sensor + * @brief Driver for Sensirion SHT10/SHT11/SHT15 Humidity and Temperature + Sensor * @{ * * @file - * @brief SHT11 Device Driver + * @brief SHT10/SHT11/SHT15 Device Driver * * @author Freie Universität Berlin, Computer Systems & Telematics */ -#ifndef SHT11_H -#define SHT11_H +#ifndef SHT1X_H +#define SHT1X_H #include @@ -27,22 +28,22 @@ extern "C" { #endif -#define SHT11_NO_ACK (0) /**< don't ack read in `read_byte` */ -#define SHT11_ACK (1) /**< do acknowledge read in `read_byte` */ +#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 SHT11_STATUS_REG_W (0x06) /**< will write to status register */ -#define SHT11_STATUS_REG_R (0x07) /**< will read from status register */ -#define SHT11_MEASURE_TEMP (0x03) /**< tell sensor to measure temperature */ -#define SHT11_MEASURE_HUMI (0x05) /**< tell sensor to measure humidity */ -#define SHT11_RESET (0x1E) /**< reset the sensor */ +#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 SHT11_DATA_WAIT (1) +#define SHT1X_DATA_WAIT (1) /** time to wait after toggling the clock line */ -#define SHT11_CLK_WAIT (1) +#define SHT1X_CLK_WAIT (1) /** set measurement timeout to 1 second */ -#define SHT11_MEASURE_TIMEOUT (1000) +#define SHT1X_MEASURE_TIMEOUT (1000) /** * @brief sht11 measureable data @@ -51,7 +52,7 @@ typedef struct { float temperature; /**< temperature value */ float relhum; /**< linear relative humidity */ float relhum_temp; /**< temperature compensated relative humidity */ -} sht11_val_t; +} sht1x_val_t; /** * @brief SHT11 modes that can be measured @@ -59,12 +60,12 @@ typedef struct { typedef enum { TEMPERATURE = 1, HUMIDITY = 2 -} sht11_mode_t; +} sht1x_mode_t; /** * @brief Initialize SHT11 ports */ -void sht11_init(void); +void sht1x_init(void); /** * @brief Read sensor @@ -75,11 +76,11 @@ void sht11_init(void); * @return 1 on success, 0 otherwise * * Example: - * \code sht11_val sht11; - * sht11_read_sensor(&sht11, HUMIDITY|TEMPERATURE); + * \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 */ -uint8_t sht11_read_sensor(sht11_val_t *value, sht11_mode_t mode); +uint8_t sht1x_read_sensor(sht1x_val_t *value, sht1x_mode_t mode); /** * @brief Write status register @@ -88,7 +89,7 @@ uint8_t sht11_read_sensor(sht11_val_t *value, sht11_mode_t mode); * * @return 1 on success, 0 otherwise */ -uint8_t sht11_write_status(uint8_t *p_value); +uint8_t sht1x_write_status(uint8_t *p_value); /** * @brief Read status register with checksum @@ -98,11 +99,11 @@ uint8_t sht11_write_status(uint8_t *p_value); * * return 1 on success, 0 otherwise */ -uint8_t sht11_read_status(uint8_t *p_value, uint8_t *p_checksum); +uint8_t sht1x_read_status(uint8_t *p_value, uint8_t *p_checksum); #ifdef __cplusplus } #endif -#endif /* SHT11_H */ +#endif /* SHT1X_H */ /** @} */ diff --git a/drivers/sht11/Makefile b/drivers/sht1x/Makefile similarity index 100% rename from drivers/sht11/Makefile rename to drivers/sht1x/Makefile diff --git a/drivers/sht11/sht11.c b/drivers/sht1x/sht1x.c similarity index 72% rename from drivers/sht11/sht11.c rename to drivers/sht1x/sht1x.c index e92b15013b..c48d03a177 100644 --- a/drivers/sht11/sht11.c +++ b/drivers/sht1x/sht1x.c @@ -7,7 +7,7 @@ */ /** - * @ingroup drivers_sht11 + * @ingroup drivers_sht1x * @brief Driver for the Sensirion SHT11 humidity and temperature sensor * @{ * @@ -16,7 +16,7 @@ * * @version $Revision: 2396 $ * - * @note $Id: sht11.c 2396 2010-07-06 15:12:35Z ziegert $ + * @note $Id: sht1x.c 2396 2010-07-06 15:12:35Z ziegert $ * @} */ @@ -25,11 +25,11 @@ #include "xtimer.h" #include "mutex.h" -#include "sht11.h" -#include "sht11-board.h" +#include "sht1x.h" +#include "sht1x-board.h" #include "bitarithm.h" -float sht11_temperature_offset; +float sht1x_temperature_offset; /** * @brief Perform measurement @@ -76,15 +76,15 @@ static void transmission_start(void); static inline void clk_signal(void); /* mutex for exclusive measurement operation */ -mutex_t sht11_mutex = MUTEX_INIT; +mutex_t sht1x_mutex = MUTEX_INIT; /*---------------------------------------------------------------------------*/ static inline void clk_signal(void) { - SHT11_SCK_HIGH; - xtimer_usleep(SHT11_CLK_WAIT); - SHT11_SCK_LOW; - xtimer_usleep(SHT11_CLK_WAIT); + SHT1X_SCK_HIGH; + xtimer_usleep(SHT1X_CLK_WAIT); + SHT1X_SCK_LOW; + xtimer_usleep(SHT1X_CLK_WAIT); } /*---------------------------------------------------------------------------*/ @@ -93,17 +93,17 @@ static uint8_t write_byte(uint8_t value) uint8_t i; uint8_t ack; - SHT11_DATA_OUT; + SHT1X_DATA_OUT; /* send value bit by bit to sht11 */ for (i = 0; i < 8; i++) { if (value & BIT7) { - SHT11_DATA_HIGH; - xtimer_usleep(SHT11_DATA_WAIT); + SHT1X_DATA_HIGH; + xtimer_usleep(SHT1X_DATA_WAIT); } else { - SHT11_DATA_LOW; - xtimer_usleep(SHT11_DATA_WAIT); + SHT1X_DATA_LOW; + xtimer_usleep(SHT1X_DATA_WAIT); } /* trigger clock signal */ @@ -114,9 +114,9 @@ static uint8_t write_byte(uint8_t value) } /* wait for ack */ - SHT11_DATA_IN; - xtimer_usleep(SHT11_CLK_WAIT); - ack = SHT11_DATA; + SHT1X_DATA_IN; + xtimer_usleep(SHT1X_CLK_WAIT); + ack = SHT1X_DATA; clk_signal(); @@ -128,40 +128,40 @@ static uint8_t read_byte(uint8_t ack) uint8_t i; uint8_t value = 0; - SHT11_DATA_IN; - xtimer_usleep(SHT11_DATA_WAIT); + SHT1X_DATA_IN; + xtimer_usleep(SHT1X_DATA_WAIT); /* read value bit by bit */ for (i = 0; i < 8; i++) { value = value << 1; - SHT11_SCK_HIGH; - xtimer_usleep(SHT11_CLK_WAIT); + SHT1X_SCK_HIGH; + xtimer_usleep(SHT1X_CLK_WAIT); - if (SHT11_DATA) { + if (SHT1X_DATA) { /* increase data by one when DATA is high */ value++; } - SHT11_SCK_LOW; - xtimer_usleep(SHT11_CLK_WAIT); + SHT1X_SCK_LOW; + xtimer_usleep(SHT1X_CLK_WAIT); } /* send ack if necessary */ - SHT11_DATA_OUT; + SHT1X_DATA_OUT; if (ack) { - SHT11_DATA_LOW; - xtimer_usleep(SHT11_DATA_WAIT); + SHT1X_DATA_LOW; + xtimer_usleep(SHT1X_DATA_WAIT); } else { - SHT11_DATA_HIGH; - xtimer_usleep(SHT11_DATA_WAIT); + SHT1X_DATA_HIGH; + xtimer_usleep(SHT1X_DATA_WAIT); } clk_signal(); /* release data line */ - SHT11_DATA_IN; + SHT1X_DATA_IN; return value; } @@ -173,31 +173,31 @@ static void transmission_start(void) ___ ___ SCK : ___| |___| |______ */ - SHT11_DATA_OUT; + SHT1X_DATA_OUT; /* set initial state */ - SHT11_DATA_HIGH; - xtimer_usleep(SHT11_DATA_WAIT); - SHT11_SCK_LOW; - xtimer_usleep(SHT11_CLK_WAIT); + SHT1X_DATA_HIGH; + xtimer_usleep(SHT1X_DATA_WAIT); + SHT1X_SCK_LOW; + xtimer_usleep(SHT1X_CLK_WAIT); - SHT11_SCK_HIGH; - xtimer_usleep(SHT11_CLK_WAIT); + SHT1X_SCK_HIGH; + xtimer_usleep(SHT1X_CLK_WAIT); - SHT11_DATA_LOW; - xtimer_usleep(SHT11_DATA_WAIT); + SHT1X_DATA_LOW; + xtimer_usleep(SHT1X_DATA_WAIT); - SHT11_SCK_LOW; - xtimer_usleep(SHT11_CLK_WAIT); + SHT1X_SCK_LOW; + xtimer_usleep(SHT1X_CLK_WAIT); - SHT11_SCK_HIGH; - xtimer_usleep(SHT11_CLK_WAIT); + SHT1X_SCK_HIGH; + xtimer_usleep(SHT1X_CLK_WAIT); - SHT11_DATA_HIGH; - xtimer_usleep(SHT11_DATA_WAIT); + SHT1X_DATA_HIGH; + xtimer_usleep(SHT1X_DATA_WAIT); - SHT11_SCK_LOW; - xtimer_usleep(SHT11_CLK_WAIT); + SHT1X_SCK_LOW; + xtimer_usleep(SHT1X_CLK_WAIT); } /*---------------------------------------------------------------------------*/ static void connection_reset(void) @@ -208,10 +208,10 @@ static void connection_reset(void) SCK : __| |__| |__| |__| |__| |__| |__| |__| |__| |______| |___| |__ */ uint8_t i; - SHT11_DATA_HIGH; - xtimer_usleep(SHT11_DATA_WAIT); - SHT11_SCK_LOW; - xtimer_usleep(SHT11_CLK_WAIT); + SHT1X_DATA_HIGH; + xtimer_usleep(SHT1X_DATA_WAIT); + SHT1X_SCK_LOW; + xtimer_usleep(SHT1X_CLK_WAIT); for (i = 0; i < 9; i++) { clk_signal(); @@ -232,8 +232,8 @@ static uint8_t measure(uint8_t *p_value, uint8_t *p_checksum, uint8_t mode) xtimer_usleep(1000); /* wait untile sensor has finished measurement or timeout */ - for (i = 0; (i < SHT11_MEASURE_TIMEOUT) && (!error); i++) { - ack = SHT11_DATA; + for (i = 0; (i < SHT1X_MEASURE_TIMEOUT) && (!error); i++) { + ack = SHT1X_DATA; if (!ack) { break; @@ -245,44 +245,44 @@ static uint8_t measure(uint8_t *p_value, uint8_t *p_checksum, uint8_t mode) error += ack; /* read MSB */ - *(p_value + 1) = read_byte(SHT11_ACK); + *(p_value + 1) = read_byte(SHT1X_ACK); /* read LSB */ - *(p_value) = read_byte(SHT11_ACK); + *(p_value) = read_byte(SHT1X_ACK); /* read checksum */ - *p_checksum = read_byte(SHT11_NO_ACK); + *p_checksum = read_byte(SHT1X_NO_ACK); return (!error); } /*---------------------------------------------------------------------------*/ -void sht11_init(void) +void sht1x_init(void) { - sht11_temperature_offset = 0; - SHT11_INIT; + sht1x_temperature_offset = 0; + SHT1X_INIT; xtimer_usleep(11 * 1000); } /*---------------------------------------------------------------------------*/ -uint8_t sht11_read_status(uint8_t *p_value, uint8_t *p_checksum) +uint8_t sht1x_read_status(uint8_t *p_value, uint8_t *p_checksum) { uint8_t error = 0; transmission_start(); - error |= write_byte(SHT11_STATUS_REG_R); - *p_value = read_byte(SHT11_ACK); - *p_checksum = read_byte(SHT11_NO_ACK); + error |= write_byte(SHT1X_STATUS_REG_R); + *p_value = read_byte(SHT1X_ACK); + *p_checksum = read_byte(SHT1X_NO_ACK); return (!error); } /*---------------------------------------------------------------------------*/ -uint8_t sht11_write_status(uint8_t *p_value) +uint8_t sht1x_write_status(uint8_t *p_value) { uint8_t error = 0; transmission_start(); - error += write_byte(SHT11_STATUS_REG_W); + error += write_byte(SHT1X_STATUS_REG_W); error += write_byte(*p_value); return (!error); } /*---------------------------------------------------------------------------*/ -uint8_t sht11_read_sensor(sht11_val_t *value, sht11_mode_t mode) +uint8_t sht1x_read_sensor(sht1x_val_t *value, sht1x_mode_t mode) { uint8_t error = 0; uint8_t checksum; @@ -313,28 +313,28 @@ uint8_t sht11_read_sensor(sht11_val_t *value, sht11_mode_t mode) value->relhum = 0; value->relhum_temp = 0; - mutex_lock(&sht11_mutex); + mutex_lock(&sht1x_mutex); connection_reset(); /* measure humidity */ if (mode & HUMIDITY) { - error += (!measure((uint8_t *) &humi_int, &checksum, SHT11_MEASURE_HUMI)); + error += (!measure((uint8_t *) &humi_int, &checksum, SHT1X_MEASURE_HUMI)); } /* measure temperature */ if (mode & TEMPERATURE) { - error += (!measure((uint8_t *) &temp_int, &checksum, SHT11_MEASURE_TEMP)); + error += (!measure((uint8_t *) &temp_int, &checksum, SHT1X_MEASURE_TEMP)); } /* break on error */ if (error != 0) { connection_reset(); - mutex_unlock(&sht11_mutex); + mutex_unlock(&sht1x_mutex); return 0; } if (mode & TEMPERATURE) { - value->temperature = D1 + (D2 * ((float) temp_int)) + sht11_temperature_offset; + value->temperature = D1 + (D2 * ((float) temp_int)) + sht1x_temperature_offset; } if (mode & HUMIDITY) { @@ -345,6 +345,6 @@ uint8_t sht11_read_sensor(sht11_val_t *value, sht11_mode_t mode) } } - mutex_unlock(&sht11_mutex); + mutex_unlock(&sht1x_mutex); return 1; } diff --git a/makefiles/pseudomodules.inc.mk b/makefiles/pseudomodules.inc.mk index 1e3d319898..0d04d3cec7 100644 --- a/makefiles/pseudomodules.inc.mk +++ b/makefiles/pseudomodules.inc.mk @@ -95,6 +95,11 @@ PSEUDOMODULES += adc121c PSEUDOMODULES += sx1272 PSEUDOMODULES += sx1276 +# include variants of SHT1X drivers as pseudo modules +PSEUDOMODULES += sht10 +PSEUDOMODULES += sht11 +PSEUDOMODULES += sht15 + # include variants of Si114x drivers as pseudo modules PSEUDOMODULES += si1145 PSEUDOMODULES += si1146 diff --git a/sys/auto_init/auto_init.c b/sys/auto_init/auto_init.c index 067b367e85..617a073523 100644 --- a/sys/auto_init/auto_init.c +++ b/sys/auto_init/auto_init.c @@ -20,8 +20,8 @@ #include "auto_init.h" -#ifdef MODULE_SHT11 -#include "sht11.h" +#ifdef MODULE_SHT1X +#include "sht1x.h" #endif #ifdef MODULE_MCI @@ -101,9 +101,9 @@ void auto_init(void) DEBUG("Auto init xtimer module.\n"); xtimer_init(); #endif -#ifdef MODULE_SHT11 - DEBUG("Auto init SHT11 module.\n"); - sht11_init(); +#ifdef MODULE_SHT1X + DEBUG("Auto init SHT1X module.\n"); + sht1x_init(); #endif #ifdef MODULE_MCI DEBUG("Auto init mci module.\n"); diff --git a/sys/shell/commands/Makefile b/sys/shell/commands/Makefile index 8e8e56e3d9..5d1908f2d1 100644 --- a/sys/shell/commands/Makefile +++ b/sys/shell/commands/Makefile @@ -8,8 +8,8 @@ endif ifneq (,$(filter ps,$(USEMODULE))) SRC += sc_ps.c endif -ifneq (,$(filter sht11,$(USEMODULE))) - SRC += sc_sht11.c +ifneq (,$(filter sht1x,$(USEMODULE))) + SRC += sc_sht1x.c endif ifneq (,$(filter lpc2387,$(USEMODULE))) SRC += sc_heap.c diff --git a/sys/shell/commands/sc_sht11.c b/sys/shell/commands/sc_sht1x.c similarity index 69% rename from sys/shell/commands/sc_sht11.c rename to sys/shell/commands/sc_sht1x.c index 6722626125..2a379def5c 100644 --- a/sys/shell/commands/sc_sht11.c +++ b/sys/shell/commands/sc_sht1x.c @@ -22,11 +22,11 @@ #include #include #include -#include "sht11.h" +#include "sht1x.h" -#ifdef MODULE_SHT11 +#ifdef MODULE_SHT1X -extern float sht11_temperature_offset; +extern float sht1x_temperature_offset; int _get_humidity_handler(int argc, char **argv) { @@ -34,8 +34,8 @@ int _get_humidity_handler(int argc, char **argv) (void) argv; uint8_t success; - sht11_val_t sht11_val; - success = sht11_read_sensor(&sht11_val, HUMIDITY | TEMPERATURE); + sht1x_val_t sht1x_val; + success = sht1x_read_sensor(&sht1x_val, HUMIDITY | TEMPERATURE); if (!success) { printf("Error reading SHT11\n"); @@ -44,7 +44,7 @@ int _get_humidity_handler(int argc, char **argv) } else { printf("Relative humidity: %5.2f%% / Temperature compensated humidity; %5.2f%%\n", - (double) sht11_val.relhum, (double) sht11_val.relhum_temp); + (double) sht1x_val.relhum, (double) sht1x_val.relhum_temp); return 0; } @@ -56,8 +56,8 @@ int _get_temperature_handler(int argc, char **argv) (void) argv; uint8_t success; - sht11_val_t sht11_val; - success = sht11_read_sensor(&sht11_val, TEMPERATURE); + sht1x_val_t sht1x_val; + success = sht1x_read_sensor(&sht1x_val, TEMPERATURE); if (!success) { printf("Error reading SHT11\n"); @@ -65,7 +65,7 @@ int _get_temperature_handler(int argc, char **argv) return 1; } else { - printf("Temperature: %-6.2f°C\n", (double) sht11_val.temperature); + printf("Temperature: %-6.2f°C\n", (double) sht1x_val.temperature); return 0; } @@ -77,8 +77,8 @@ int _get_weather_handler(int argc, char **argv) (void) argv; uint8_t success; - sht11_val_t sht11_val; - success = sht11_read_sensor(&sht11_val, HUMIDITY | TEMPERATURE); + sht1x_val_t sht1x_val; + success = sht1x_read_sensor(&sht1x_val, HUMIDITY | TEMPERATURE); if (!success) { printf("Error reading SHT11\n"); @@ -87,8 +87,8 @@ int _get_weather_handler(int argc, char **argv) } else { printf("Relative humidity: %5.2f%% / Temperature compensated humidity; %5.2f%% ", - (double) sht11_val.relhum, (double) sht11_val.relhum_temp); - printf("Temperature: %-6.2f°C\n", (double) sht11_val.temperature); + (double) sht1x_val.relhum, (double) sht1x_val.relhum_temp); + printf("Temperature: %-6.2f°C\n", (double) sht1x_val.temperature); return 0; } @@ -102,8 +102,8 @@ int _set_offset_handler(int argc, char **argv) return 1; } else { - sht11_temperature_offset = atoi(argv[1]); - printf("Temperature offset set to %f\n", (double) sht11_temperature_offset); + sht1x_temperature_offset = atoi(argv[1]); + printf("Temperature offset set to %f\n", (double) sht1x_temperature_offset); return 0; } diff --git a/sys/shell/commands/shell_commands.c b/sys/shell/commands/shell_commands.c index 6ab2937dc2..ce73861323 100644 --- a/sys/shell/commands/shell_commands.c +++ b/sys/shell/commands/shell_commands.c @@ -37,7 +37,7 @@ extern int _heap_handler(int argc, char **argv); extern int _ps_handler(int argc, char **argv); #endif -#ifdef MODULE_SHT11 +#ifdef MODULE_SHT1X 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); @@ -153,7 +153,7 @@ const shell_command_t _shell_command_list[] = { #ifdef MODULE_PS {"ps", "Prints information about running threads.", _ps_handler}, #endif -#ifdef MODULE_SHT11 +#ifdef MODULE_SHT1X {"temp", "Prints measured temperature.", _get_temperature_handler}, {"hum", "Prints measured humidity.", _get_humidity_handler}, {"weather", "Prints measured humidity and temperature.", _get_weather_handler}, From de9b67bdc25ab1b7b359e0584b60f51544850089 Mon Sep 17 00:00:00 2001 From: Marian Buschsieweke Date: Wed, 13 Jun 2018 09:17:29 +0200 Subject: [PATCH 2/5] 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 --- boards/common/msb-430/Makefile | 2 - boards/common/msb-430/Makefile.include | 3 - boards/common/msb-430/drivers/Makefile | 5 - .../msb-430/drivers/include/sht1x-board.h | 49 -- boards/common/msba2/Makefile | 2 - boards/common/msba2/Makefile.include | 3 - boards/common/msba2/drivers/Makefile | 3 - .../msba2/drivers/include/sht1x-board.h | 56 -- boards/msb-430/Makefile.dep | 3 + boards/msb-430/include/board.h | 8 + boards/msb-430h/Makefile.dep | 3 + boards/msb-430h/include/board.h | 8 + boards/msba2/Makefile.dep | 4 + drivers/Makefile.dep | 1 + drivers/Makefile.include | 4 + drivers/include/sht1x.h | 193 +++-- drivers/sht1x/include/sht1x_defines.h | 72 ++ drivers/sht1x/include/sht1x_params.h | 63 ++ drivers/sht1x/sht1x.c | 778 +++++++++++++----- sys/auto_init/auto_init.c | 14 +- sys/auto_init/auto_init_sht1x.c | 74 ++ sys/shell/commands/sc_sht1x.c | 380 +++++++-- sys/shell/commands/shell_commands.c | 4 +- 23 files changed, 1268 insertions(+), 464 deletions(-) delete mode 100644 boards/common/msb-430/drivers/Makefile delete mode 100644 boards/common/msb-430/drivers/include/sht1x-board.h delete mode 100644 boards/common/msba2/drivers/Makefile delete mode 100644 boards/common/msba2/drivers/include/sht1x-board.h create mode 100644 boards/msb-430/Makefile.dep create mode 100644 boards/msb-430h/Makefile.dep create mode 100644 drivers/sht1x/include/sht1x_defines.h create mode 100644 drivers/sht1x/include/sht1x_params.h create mode 100644 sys/auto_init/auto_init_sht1x.c diff --git a/boards/common/msb-430/Makefile b/boards/common/msb-430/Makefile index baa55d8731..4695a0f761 100644 --- a/boards/common/msb-430/Makefile +++ b/boards/common/msb-430/Makefile @@ -1,5 +1,3 @@ MODULE = boards_common_msb-430 -DIRS = drivers - include $(RIOTBASE)/Makefile.base diff --git a/boards/common/msb-430/Makefile.include b/boards/common/msb-430/Makefile.include index 3125ba0715..5c054c4c66 100644 --- a/boards/common/msb-430/Makefile.include +++ b/boards/common/msb-430/Makefile.include @@ -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 diff --git a/boards/common/msb-430/drivers/Makefile b/boards/common/msb-430/drivers/Makefile deleted file mode 100644 index ed11f0ae34..0000000000 --- a/boards/common/msb-430/drivers/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -MODULE = boards_common_msb-430-drivers - -include $(RIOTBOARD)/$(BOARD)/Makefile.include - -include $(RIOTBASE)/Makefile.base diff --git a/boards/common/msb-430/drivers/include/sht1x-board.h b/boards/common/msb-430/drivers/include/sht1x-board.h deleted file mode 100644 index 873504d47c..0000000000 --- a/boards/common/msb-430/drivers/include/sht1x-board.h +++ /dev/null @@ -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 -#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 */ diff --git a/boards/common/msba2/Makefile b/boards/common/msba2/Makefile index a8c0997289..ccf58a0844 100644 --- a/boards/common/msba2/Makefile +++ b/boards/common/msba2/Makefile @@ -1,5 +1,3 @@ MODULE = boards_common_msba2 -DIRS = drivers - include $(RIOTBASE)/Makefile.base diff --git a/boards/common/msba2/Makefile.include b/boards/common/msba2/Makefile.include index 5ba3b3d01c..00260c0623 100644 --- a/boards/common/msba2/Makefile.include +++ b/boards/common/msba2/Makefile.include @@ -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 diff --git a/boards/common/msba2/drivers/Makefile b/boards/common/msba2/drivers/Makefile deleted file mode 100644 index 26dd1f4f5d..0000000000 --- a/boards/common/msba2/drivers/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -MODULE = boards_common_msba2-drivers - -include $(RIOTBASE)/Makefile.base diff --git a/boards/common/msba2/drivers/include/sht1x-board.h b/boards/common/msba2/drivers/include/sht1x-board.h deleted file mode 100644 index a70589b9ab..0000000000 --- a/boards/common/msba2/drivers/include/sht1x-board.h +++ /dev/null @@ -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 */ diff --git a/boards/msb-430/Makefile.dep b/boards/msb-430/Makefile.dep new file mode 100644 index 0000000000..f512457554 --- /dev/null +++ b/boards/msb-430/Makefile.dep @@ -0,0 +1,3 @@ +ifneq (,$(filter saul_default,$(USEMODULE))) + USEMODULE += sht11 +endif diff --git a/boards/msb-430/include/board.h b/boards/msb-430/include/board.h index a053c327f3..7baa71f1aa 100644 --- a/boards/msb-430/include/board.h +++ b/boards/msb-430/include/board.h @@ -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 diff --git a/boards/msb-430h/Makefile.dep b/boards/msb-430h/Makefile.dep new file mode 100644 index 0000000000..f512457554 --- /dev/null +++ b/boards/msb-430h/Makefile.dep @@ -0,0 +1,3 @@ +ifneq (,$(filter saul_default,$(USEMODULE))) + USEMODULE += sht11 +endif diff --git a/boards/msb-430h/include/board.h b/boards/msb-430h/include/board.h index 8fc284faa1..ae744f1b5f 100644 --- a/boards/msb-430h/include/board.h +++ b/boards/msb-430h/include/board.h @@ -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 diff --git a/boards/msba2/Makefile.dep b/boards/msba2/Makefile.dep index e5d94f2d25..d7230f86c2 100644 --- a/boards/msba2/Makefile.dep +++ b/boards/msba2/Makefile.dep @@ -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 diff --git a/drivers/Makefile.dep b/drivers/Makefile.dep index 4a95122c30..75e0bdb4d4 100644 --- a/drivers/Makefile.dep +++ b/drivers/Makefile.dep @@ -304,6 +304,7 @@ endif ifneq (,$(filter sht1%,$(USEMODULE))) USEMODULE += sht1x + FEATURES_REQUIRED += periph_gpio USEMODULE += xtimer endif diff --git a/drivers/Makefile.include b/drivers/Makefile.include index 8c7a1c4482..3832016dd3 100644 --- a/drivers/Makefile.include +++ b/drivers/Makefile.include @@ -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 diff --git a/drivers/include/sht1x.h b/drivers/include/sht1x.h index 447aa74a1f..b8c7bd8719 100644 --- a/drivers/include/sht1x.h +++ b/drivers/include/sht1x.h @@ -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 */ #ifndef SHT1X_H #define SHT1X_H #include +#include #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 } diff --git a/drivers/sht1x/include/sht1x_defines.h b/drivers/sht1x/include/sht1x_defines.h new file mode 100644 index 0000000000..0327387ab0 --- /dev/null +++ b/drivers/sht1x/include/sht1x_defines.h @@ -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 + */ + +#ifndef SHT1X_DEFINES_H +#define SHT1X_DEFINES_H + +#include +#include +#include + +#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 */ +/** @} */ diff --git a/drivers/sht1x/include/sht1x_params.h b/drivers/sht1x/include/sht1x_params.h new file mode 100644 index 0000000000..f7cd54f8a7 --- /dev/null +++ b/drivers/sht1x/include/sht1x_params.h @@ -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 + */ + +#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 */ +/** @} */ diff --git a/drivers/sht1x/sht1x.c b/drivers/sht1x/sht1x.c index c48d03a177..f2a55cc013 100644 --- a/drivers/sht1x/sht1x.c +++ b/drivers/sht1x/sht1x.c @@ -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 * - * @version $Revision: 2396 $ - * - * @note $Id: sht1x.c 2396 2010-07-06 15:12:35Z ziegert $ * @} */ - -#include +#include #include #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; } diff --git a/sys/auto_init/auto_init.c b/sys/auto_init/auto_init.c index 617a073523..bdfda5229b 100644 --- a/sys/auto_init/auto_init.c +++ b/sys/auto_init/auto_init.c @@ -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"); diff --git a/sys/auto_init/auto_init_sht1x.c b/sys/auto_init/auto_init_sht1x.c new file mode 100644 index 0000000000..49d9e6f5c9 --- /dev/null +++ b/sys/auto_init/auto_init_sht1x.c @@ -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 + * + * @} + */ + +#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 */ diff --git a/sys/shell/commands/sc_sht1x.c b/sys/shell/commands/sc_sht1x.c index 2a379def5c..c814ccff48 100644 --- a/sys/shell/commands/sc_sht1x.c +++ b/sys/shell/commands/sc_sht1x.c @@ -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 + * @author Marian Buschsieweke * * @} */ +#ifdef MODULE_SHT1X + #include #include #include #include #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 \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 ][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 \n" + " Use SHT10/11/15 sensor number . Default: 0\n" + "\n" + " -t \n" + " Add (in e-2°C) to all temperature measurements\n" + "\n" + " -h \n" + " Add (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 diff --git a/sys/shell/commands/shell_commands.c b/sys/shell/commands/shell_commands.c index ce73861323..a9871517d3 100644 --- a/sys/shell/commands/shell_commands.c +++ b/sys/shell/commands/shell_commands.c @@ -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}, From 2bff79ef5626a2f969bece8e2901c3600b1b1c6e Mon Sep 17 00:00:00 2001 From: Marian Buschsieweke Date: Mon, 11 Jun 2018 22:25:28 +0200 Subject: [PATCH 3/5] tests/unittests: Added unit tests for sht1x MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Added unit tests for new integer only arithmetic - Temperature conversion differs at most 0.01°C from double arithmetic - Humidity conversions differs at most 0.1% from double arithmetic --- tests/unittests/tests-sht1x/Makefile | 1 + tests/unittests/tests-sht1x/Makefile.include | 1 + tests/unittests/tests-sht1x/tests-sht1x.c | 110 +++++++++++++++++++ tests/unittests/tests-sht1x/tests-sht1x.h | 36 ++++++ 4 files changed, 148 insertions(+) create mode 100644 tests/unittests/tests-sht1x/Makefile create mode 100644 tests/unittests/tests-sht1x/Makefile.include create mode 100644 tests/unittests/tests-sht1x/tests-sht1x.c create mode 100644 tests/unittests/tests-sht1x/tests-sht1x.h diff --git a/tests/unittests/tests-sht1x/Makefile b/tests/unittests/tests-sht1x/Makefile new file mode 100644 index 0000000000..48422e909a --- /dev/null +++ b/tests/unittests/tests-sht1x/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/tests/unittests/tests-sht1x/Makefile.include b/tests/unittests/tests-sht1x/Makefile.include new file mode 100644 index 0000000000..4ccfa29f72 --- /dev/null +++ b/tests/unittests/tests-sht1x/Makefile.include @@ -0,0 +1 @@ +USEMODULE += sht1x diff --git a/tests/unittests/tests-sht1x/tests-sht1x.c b/tests/unittests/tests-sht1x/tests-sht1x.c new file mode 100644 index 0000000000..3991db589c --- /dev/null +++ b/tests/unittests/tests-sht1x/tests-sht1x.c @@ -0,0 +1,110 @@ +/* + * 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. + */ + +#include +#include +#include "embUnit/embUnit.h" +#include "tests-sht1x.h" + +/** @brief Maximum difference from correct temperature value [in e-02 °C] */ +static const int16_t max_diff_temp = 1; +/** @brief Maximum difference from correct humidity value [in e-02 %] */ +static const int16_t max_diff_hum = 10; + +static int16_t expected_temp(const sht1x_dev_t *dev, uint16_t _raw) +{ + static const double d1_table[] = { -40.1, -39.8, -39.7, -39.6, -39.4 }; + double d1 = d1_table[dev->vdd]; + double d2 = (dev->conf & SHT1X_CONF_LOW_RESOLUTION) ? 0.04 : 0.01; + double raw = (double)_raw; + double temp = d1 + d2 * raw; + + return (int16_t)(temp * 100.0); +} + +static int16_t expected_hum(const sht1x_dev_t *dev, uint16_t _raw, int16_t _temp) +{ + static const double c1 = -2.0468; + static const double t1 = 0.01; + double temp = ((double)_temp) / 100.0; + double raw = (double)_raw; + double c2, c3, t2, hum_linear, hum_real; + + if (dev->conf & SHT1X_CONF_LOW_RESOLUTION) { + c2 = 0.5872; + c3 = -4.0845e-04; + t2 = 0.00128; + } + else { + c2 = 0.0367; + c3 = -1.5955e-06; + t2 = 0.00008; + } + + hum_linear = c1 + c2 * raw + c3 * (raw * raw); + hum_real = (temp - 25.0) * (t1 + t2 * raw) + hum_linear; + return (int16_t)(hum_real * 100.0); +} + +static void test_sht1x_conversion(void) +{ + const uint8_t vdds[] = { + SHT1X_VDD_5_0V, SHT1X_VDD_4_0V, SHT1X_VDD_3_5V, SHT1X_VDD_3_0V, + SHT1X_VDD_2_5V, + }; + const uint8_t confs[] = { SHT1X_CONF_LOW_RESOLUTION, 0 }; + const uint16_t max_raw_temps[] = { 0xfff, 0x3fff }; + const uint16_t max_raw_hums[] = { 0xff, 0xfff }; + sht1x_dev_t dev = { .conf = 0 }; + + for (size_t i_res = 0; i_res < sizeof(confs) / sizeof(confs[0]); i_res++) { + dev.conf = confs[i_res]; + uint16_t max_raw_temp = max_raw_temps[i_res]; + uint16_t max_raw_hum = max_raw_hums[i_res]; + for (size_t i_vdd = 0; i_vdd < sizeof(vdds) / sizeof(vdds[0]); i_vdd++) { + dev.vdd = vdds[i_vdd]; + for (uint16_t raw_temp = 0; raw_temp <= max_raw_temp; raw_temp++) { + int16_t got_temp = sht1x_temperature(&dev, raw_temp); + int16_t exp_temp = expected_temp(&dev, raw_temp); + + TEST_ASSERT(((got_temp - max_diff_temp) <= exp_temp) && + ((got_temp + max_diff_temp) >= exp_temp)); + } + } + + /* Testing for temperatures in -10.00°C and 65.00°C in steps of 0.13°C */ + for (int16_t temp = -1000; temp < 6500; temp += 13) { + for (uint16_t raw_hum = 0; raw_hum <= max_raw_hum; raw_hum++) { + int16_t exp_hum = expected_hum(&dev, raw_hum, temp); + if ((exp_hum < 0) || (exp_hum > 10000)) { + /* Result out of range, ignore it */ + continue; + } + int16_t got_hum = sht1x_humidity(&dev, raw_hum, temp); + TEST_ASSERT(((got_hum - max_diff_hum) <= exp_hum) && + ((got_hum + max_diff_hum) >= exp_hum)); + } + } + } +} + +Test *tests_sht1x_tests(void) +{ + EMB_UNIT_TESTFIXTURES(fixtures) { + new_TestFixture(test_sht1x_conversion), + }; + + EMB_UNIT_TESTCALLER(sht1x_tests, NULL, NULL, fixtures); + + return (Test *)&sht1x_tests; +} + +void tests_sht1x(void) +{ + TESTS_RUN(tests_sht1x_tests()); +} diff --git a/tests/unittests/tests-sht1x/tests-sht1x.h b/tests/unittests/tests-sht1x/tests-sht1x.h new file mode 100644 index 0000000000..0619efc654 --- /dev/null +++ b/tests/unittests/tests-sht1x/tests-sht1x.h @@ -0,0 +1,36 @@ +/* + * 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. + */ + +/** + * @addtogroup unittests + * @{ + * + * @file + * @brief Unittests for the conversions used in the sht1x driver + * + * @author Marian Buschsieweke + */ +#ifndef TESTS_SHT1X_H +#define TESTS_SHT1X_H + +#include "embUnit.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief The entry point of this test suite. + */ +void tests_sht1x(void); + +#ifdef __cplusplus +} +#endif +#endif /* TESTS_SHT1X_H */ +/** @} */ From b91359b05bd6e398a9b772c7f87729033da2ac0b Mon Sep 17 00:00:00 2001 From: Marian Buschsieweke Date: Wed, 13 Jun 2018 13:14:29 +0200 Subject: [PATCH 4/5] drivers/sht1x: Added SAUL integration --- drivers/sht1x/include/sht1x_params.h | 30 ++++++++++ drivers/sht1x/sht1x_saul.c | 87 ++++++++++++++++++++++++++++ sys/auto_init/auto_init_sht1x.c | 28 +++++++++ 3 files changed, 145 insertions(+) create mode 100644 drivers/sht1x/sht1x_saul.c diff --git a/drivers/sht1x/include/sht1x_params.h b/drivers/sht1x/include/sht1x_params.h index f7cd54f8a7..02b94c784d 100644 --- a/drivers/sht1x/include/sht1x_params.h +++ b/drivers/sht1x/include/sht1x_params.h @@ -47,6 +47,28 @@ extern "C" { #endif /**@}*/ +/** + * @name Set default SAUL info text depending on used pseudo module + * @{ + */ +#ifndef SHT1X_SAULINFO +#ifdef MODULE_SHT15 +#define SHT1X_SAULINFO { .name = "SHT15 temperature" }, \ + { .name = "SHT15 humidity" } +#else +#ifdef MODULE_SHT10 +#define SHT1X_SAULINFO { .name = "SHT10 temperature" }, \ + { .name = "SHT10 humidity" } +#else +/* SHT11 is the most commonly used, so use that as default */ +#define SHT1X_SAULINFO { .name = "SHT11 temperature" }, \ + { .name = "SHT11 humidity" } +#endif /* MODULE_SHT10 */ +#endif /* MODULE_SHT15 */ +#endif /* SHT1X_SAULINFO */ + +/**@}*/ + /** * @brief Configure SHT1X devices */ @@ -55,6 +77,14 @@ static const sht1x_params_t sht1x_params[] = SHT1X_PARAMS }; +/** + * @brief Allocate and configure entries to the SAUL registry + */ +static const saul_reg_info_t sht1x_saul_info[] = +{ + SHT1X_SAULINFO +}; + #ifdef __cplusplus } #endif diff --git a/drivers/sht1x/sht1x_saul.c b/drivers/sht1x/sht1x_saul.c new file mode 100644 index 0000000000..7c0abd9255 --- /dev/null +++ b/drivers/sht1x/sht1x_saul.c @@ -0,0 +1,87 @@ +/* + * 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 drivers_sht1x + * @{ + * + * @file + * @brief SAUL adaption for SHT10/SHT11/SHT15 devices + * + * @author Marian Buschsieweke + * + * @} + */ + +#include +#include +#include + +#include "phydat.h" +#include "saul.h" +#include "sht1x_defines.h" +#include "sht1x.h" + +static int read(const sht1x_dev_t *dev, int16_t *temp, int16_t *hum) +{ + for (int retries = 0; retries < SHT1X_SAUL_RETRIES; retries++) { + switch (sht1x_read(dev, temp, hum)) { + case 0: + return 0; + case -EBADMSG: + puts("[sht1x] CRC"); + continue; + case -EPROTO: + puts("[sht1x] Sensor did not acknowledge measurement command"); + continue; + case -ECANCELED: + puts("[sht1x] Measurement times out"); + default: + /* Other failure, cannot recover so giving up */ + return -1; + } + } + + printf("[sht1x] Giving up after %i tries\n", SHT1X_SAUL_RETRIES); + + return -1; +} + +static int read_temp(const void *dev, phydat_t *res) +{ + if (read(dev, &res->val[0], NULL) == 0) { + res->unit = UNIT_TEMP_C; + res->scale = -2; + return 1; + } + + return -ECANCELED; +} + +static int read_hum(const void *dev, phydat_t *res) +{ + if (read(dev, NULL, &res->val[0]) == 0) { + res->unit = UNIT_PERCENT; + res->scale = -2; + return 1; + } + + return -ECANCELED; +} + +const saul_driver_t sht1x_saul_temp_driver = { + .read = read_temp, + .write = saul_notsup, + .type = SAUL_SENSE_TEMP +}; + +const saul_driver_t sht1x_saul_hum_driver = { + .read = read_hum, + .write = saul_notsup, + .type = SAUL_SENSE_HUM +}; diff --git a/sys/auto_init/auto_init_sht1x.c b/sys/auto_init/auto_init_sht1x.c index 49d9e6f5c9..3264ab9b45 100644 --- a/sys/auto_init/auto_init_sht1x.c +++ b/sys/auto_init/auto_init_sht1x.c @@ -38,6 +38,23 @@ */ sht1x_dev_t sht1x_devs[SHT1X_NUM]; +#ifdef MODULE_AUTO_INIT_SAUL + +/** + * @brief Memory for the SAUL registry entries + */ +static saul_reg_t saul_entries[SHT1X_NUM * 2]; + +/** + * @name Import SAUL endpoints + * @{ + */ +extern const saul_driver_t sht1x_saul_temp_driver; +extern const saul_driver_t sht1x_saul_hum_driver; +/** @} */ + +#endif /* MODULE_AUTO_INIT_SAUL */ + static void sht1x_error(unsigned int num, const char *reason) { LOG_ERROR("[auto_init] error initializing SHT10/SHT11/SHT15 sensor " @@ -66,6 +83,17 @@ void auto_init_sht1x(void) sht1x_error(i, "?"); continue; } + +#ifdef MODULE_AUTO_INIT_SAUL + saul_entries[(i * 2) ].dev = &(sht1x_devs[i]); + saul_entries[(i * 2) + 1].dev = &(sht1x_devs[i]); + saul_entries[(i * 2) ].name = sht1x_saul_info[(i * 2) ].name; + saul_entries[(i * 2) + 1].name = sht1x_saul_info[(i * 2) + 1].name; + saul_entries[(i * 2) ].driver = &sht1x_saul_temp_driver; + saul_entries[(i * 2) + 1].driver = &sht1x_saul_hum_driver; + saul_reg_add(&(saul_entries[(i * 2) ])); + saul_reg_add(&(saul_entries[(i * 2) + 1])); +#endif /* MODULE_AUTO_INIT_SAUL */ } } From 8e200673d3aae6ab034c8a3640efc43209f24d65 Mon Sep 17 00:00:00 2001 From: Marian Buschsieweke Date: Tue, 12 Jun 2018 21:53:51 +0200 Subject: [PATCH 5/5] tests/driver_sht1x: Added tests for sht1x --- tests/driver_sht1x/Makefile | 12 +++ tests/driver_sht1x/main.c | 172 ++++++++++++++++++++++++++++++++++++ 2 files changed, 184 insertions(+) create mode 100644 tests/driver_sht1x/Makefile create mode 100644 tests/driver_sht1x/main.c diff --git a/tests/driver_sht1x/Makefile b/tests/driver_sht1x/Makefile new file mode 100644 index 0000000000..4c51663c52 --- /dev/null +++ b/tests/driver_sht1x/Makefile @@ -0,0 +1,12 @@ +include ../Makefile.tests_common + +DRIVER ?= sht11 +BOARD ?= msba2 + +USEMODULE += $(DRIVER) +USEMODULE += shell +USEMODULE += saul_default +USEMODULE += shell_commands +USEMODULE += ps + +include $(RIOTBASE)/Makefile.include diff --git a/tests/driver_sht1x/main.c b/tests/driver_sht1x/main.c new file mode 100644 index 0000000000..864ce7f6a2 --- /dev/null +++ b/tests/driver_sht1x/main.c @@ -0,0 +1,172 @@ +/* + * 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 tests + * @{ + * + * @file + * @brief Test application for the SHT10/11/15 family of temperature and + * humidity sensors + * + * @author Marian Buschsieweke + * + * @} + */ + +#include + +#include "shell.h" +#include "shell_commands.h" +#include "sht1x_params.h" + +#define SHT1X_NUM (sizeof(sht1x_params) / sizeof(sht1x_params[0])) +extern sht1x_dev_t sht1x_devs[SHT1X_NUM]; +static sht1x_dev_t *dev = &sht1x_devs[0]; + +static int run_tests(void) +{ + const char *resolution[] = { "high", "low" }; + const char *calibration[] = { "on", "off" }; + const char *heater[] = { "off", "on" }; + const char *crc[] = { "on", "off" }; + uint8_t conf = 0; + + puts("Reading the sensor three times for all possible configurations:"); + + for (int i_res = 0; i_res < 2; i_res++) { + if (i_res) { + conf |= SHT1X_CONF_LOW_RESOLUTION; + } + else { + conf &= ~(SHT1X_CONF_LOW_RESOLUTION); + } + + for (int i_cal = 0; i_cal < 2; i_cal++) { + if (i_cal) { + conf |= SHT1X_CONF_SKIP_CALIBRATION; + } + else { + conf &= ~(SHT1X_CONF_SKIP_CALIBRATION); + } + + for (int i_heater = 0; i_heater < 2; i_heater++) { + if (i_heater) { + conf |= SHT1X_CONF_ENABLE_HEATER; + } + else { + conf &= ~(SHT1X_CONF_ENABLE_HEATER); + } + + for (int i_crc = 0; i_crc < 2; i_crc++) { + if (i_crc) { + conf |= SHT1X_CONF_SKIP_CRC; + } + else { + conf &= ~(SHT1X_CONF_SKIP_CRC); + } + + printf("Resolution: %s, calibration: %s, heater: %s, " + "CRC-checking: %s\n", + resolution[i_res], + calibration[i_cal], + heater[i_heater], + crc[i_crc]); + switch (sht1x_configure(dev, conf)) { + case 0: + break; + case -EIO: + puts("Error: gpio_init() failed"); + return -1; + case -EPROTO: + puts("Error: Sensor did not acknowledge command"); + return -1; + case -ECANCELED: + puts("Error: Sensor did not apply configuration"); + return -1; + case -EBADMSG: + puts("Error: CRC error while validating " + "configuration"); + return -1; + default: + /* Will never happen, but better safe than sorry */ + puts("Unknown error"); + return -1; + } + + for (int i = 0; i < 3; i++) { + int16_t temp, hum; + switch (sht1x_read(dev, &temp, &hum)) { + case 0: + break; + case -EIO: + puts("Error: gpio_init() failed"); + return -1; + case -EPROTO: + puts("Error: Sensor did not acknowledge " + "command"); + return -1; + case -ECANCELED: + puts("Error: Measurement timed out"); + return -1; + default: + /* Won't happen, but better safe than sorry */ + puts("Unknown error"); + return -1; + } + + printf("Temperature: %i.%02i°C, Humidity: %i.%02i%%\n", + (int)temp / 100, (int)temp % 100, + (int)hum / 100, (int)hum % 100); + } + } + } + } + } + + puts("Restoring default configuration"); + switch (sht1x_configure(dev, 0)) { + case 0: + break; + case -EIO: + puts("Error: gpio_init() failed"); + return -1; + case -EPROTO: + puts("Error: Sensor did not acknowledge command"); + return -1; + case -ECANCELED: + puts("Error: Sensor did not apply configuration"); + return -1; + case -EBADMSG: + puts("Error: CRC error while validating " + "configuration"); + return -1; + default: + /* Will never happen, but better safe than sorry */ + puts("Unknown error"); + return -1; + } + + return 0; +} + +int main(void) +{ + if (run_tests()) { + puts("TESTS FAILED!"); + } + else { + puts("All automatic tests finished."); + } + + puts("Dropping to shell for manual testing"); + char line_buf[SHELL_DEFAULT_BUFSIZE]; + shell_run(NULL, line_buf, SHELL_DEFAULT_BUFSIZE); + + return 0; +}