Contiki-NG
sht21.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2014, OpenMote Technologies, S.L.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the Institute nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * This file is part of the Contiki operating system.
30 *
31 */
32/*---------------------------------------------------------------------------*/
33/**
34 * \addtogroup openmote-sht21-sensor
35 * @{
36 *
37 * \file
38 * Driver for the SHT21 temperature and relative humidity sensor
39 *
40 * \author
41 * Pere Tuset <peretuset@openmote.com>
42 */
43/*---------------------------------------------------------------------------*/
44#include "dev/i2c.h"
45#include "dev/sht21.h"
46#include "lib/sensors.h"
47/*---------------------------------------------------------------------------*/
48#define DEBUG 0
49#if DEBUG
50#define PRINTF(...) printf(__VA_ARGS__)
51#else
52#define PRINTF(...)
53#endif
54/*---------------------------------------------------------------------------*/
55/**
56 * \name SHT21 address
57 * @{
58 */
59#define SHT21_ADDRESS (0x40)
60/** @} */
61/*---------------------------------------------------------------------------*/
62/**
63 * \name SHT21 register addresses and values
64 * @{
65 */
66#define SHT21_USER_REG_READ (0xE7)
67#define SHT21_USER_REG_WRITE (0xE6)
68#define SHT21_USER_REG_RESERVED_BITS (0x38)
69
70#define SHT21_TEMPERATURE_HM_CMD (0xE3)
71#define SHT21_HUMIDITY_HM_CMD (0xE5)
72#define SHT21_TEMPERATURE_NHM_CMD (0xF3)
73#define SHT21_HUMIDITY_NHM_CMD (0xF5)
74#define SHT21_RESET_CMD (0xFE)
75
76#define SHT21_STATUS_MASK (0xFC)
77
78#define SHT21_RESOLUTION_12b_14b ((0 << 7) | (0 << 0))
79#define SHT21_RESOLUTION_8b_12b ((0 << 7) | (1 << 0))
80#define SHT21_RESOLUTION_10b_13b ((1 << 7) | (0 << 0))
81#define SHT21_RESOLUTION_11b_11b ((1 << 7) | (1 << 0))
82#define SHT21_BATTERY_ABOVE_2V25 (0 << 6)
83#define SHT21_BATTERY_BELOW_2V25 (1 << 6)
84#define SHT21_ONCHIP_HEATER_ENABLE (1 << 2)
85#define SHT21_ONCHIP_HEATER_DISABLE (0 << 2)
86#define SHT21_OTP_RELOAD_ENABLE (0 << 1)
87#define SHT21_OTP_RELOAD_DISABLE (1 << 1)
88/** @} */
89/*---------------------------------------------------------------------------*/
90/**
91 * \name SHT21 configuration values
92 * @{
93 */
94#define SHT21_DEFAULT_CONFIG (SHT21_RESOLUTION_12b_14b | \
95 SHT21_ONCHIP_HEATER_DISABLE | \
96 SHT21_BATTERY_ABOVE_2V25 | \
97 SHT21_OTP_RELOAD_DISABLE)
98
99#define SHT21_USER_CONFIG (SHT21_RESOLUTION_12b_14b | \
100 SHT21_ONCHIP_HEATER_DISABLE | \
101 SHT21_BATTERY_ABOVE_2V25 | \
102 SHT21_OTP_RELOAD_DISABLE)
103/** @} */
104/*---------------------------------------------------------------------------*/
105static uint8_t enabled;
106/*---------------------------------------------------------------------------*/
107static void
108sht21_init(void)
109{
110 uint8_t config[2];
111
112 /* Setup the configuration vector, the first position holds address */
113 /* and the second position holds the actual configuration */
114 config[0] = SHT21_USER_REG_WRITE;
115 config[1] = 0;
116
117 /* Read the current configuration according to the datasheet (pag. 9, fig. 18) */
118 i2c_single_send(SHT21_ADDRESS, SHT21_USER_REG_READ);
119 i2c_single_receive(SHT21_ADDRESS, &config[1]);
120
121 /* Clean all the configuration bits except those reserved */
122 config[1] &= SHT21_USER_REG_RESERVED_BITS;
123
124 /* Set the configuration bits without changing those reserved */
125 config[1] |= SHT21_USER_CONFIG;
126
127 i2c_burst_send(SHT21_ADDRESS, config, sizeof(config));
128}
129/*---------------------------------------------------------------------------*/
130static void
131sht21_reset(void)
132{
133 /* Send a soft-reset command according to the datasheet (pag. 9, fig. 17) */
134 i2c_single_send(SHT21_ADDRESS, SHT21_RESET_CMD);
135}
136/*---------------------------------------------------------------------------*/
137static uint8_t
138sht21_is_present(void)
139{
140 uint8_t status;
141 uint8_t is_present;
142
143 /* Read the current configuration according to the datasheet (pag. 9, fig. 18) */
144 i2c_single_send(SHT21_ADDRESS, SHT21_USER_REG_READ);
145 status = i2c_single_receive(SHT21_ADDRESS, &is_present);
146 if(status != I2C_MASTER_ERR_NONE) {
147 return 0;
148 }
149
150 /* Clear the reserved bits according to the datasheet (pag. 9, tab. 8) */
151 is_present &= ~SHT21_USER_REG_RESERVED_BITS;
152
153 return (is_present == SHT21_USER_CONFIG) || (is_present == SHT21_DEFAULT_CONFIG);
154}
155/*---------------------------------------------------------------------------*/
156static uint32_t
157sht21_read_temperature(void)
158{
159 uint8_t sht21_temperature[2];
160 uint16_t temperature;
161
162 /* Read the current temperature according to the datasheet (pag. 8, fig. 15) */
163 i2c_single_send(SHT21_ADDRESS, SHT21_TEMPERATURE_HM_CMD);
164 i2c_burst_receive(SHT21_ADDRESS, sht21_temperature, sizeof(sht21_temperature));
165
166 temperature = (sht21_temperature[0] << 8) | ((sht21_temperature[1] & SHT21_STATUS_MASK));
167
168 return temperature;
169}
170/*---------------------------------------------------------------------------*/
171static int16_t
172sht21_convert_temperature(uint32_t temperature)
173{
174 int16_t result;
175
176 temperature *= 17572;
177 temperature = temperature >> 16;
178 result = (int16_t)temperature - 4685;
179
180 return result;
181}
182/*---------------------------------------------------------------------------*/
183static uint32_t
184sht21_read_humidity(void)
185{
186 uint8_t sht21_humidity[2];
187 uint16_t humidity;
188
189 /* Read the current humidity according to the datasheet (pag. 8, fig. 15) */
190 i2c_single_send(SHT21_ADDRESS, SHT21_HUMIDITY_HM_CMD);
191 i2c_burst_receive(SHT21_ADDRESS, sht21_humidity, sizeof(sht21_humidity));
192
193 humidity = (sht21_humidity[0] << 8) | ((sht21_humidity[1] & SHT21_STATUS_MASK));
194
195 return humidity;
196}
197/*---------------------------------------------------------------------------*/
198static int16_t
199sht21_convert_humidity(uint32_t humidity)
200{
201 int16_t result;
202
203 humidity *= 12500;
204 humidity = humidity >> 16;
205 result = (int16_t)humidity - 600;
206 result = (result > 10000) ? 10000 : result;
207
208 return result;
209}
210/*---------------------------------------------------------------------------*/
211static int
212status(int type)
213{
214 switch(type) {
215 case SENSORS_ACTIVE:
216 case SENSORS_READY:
217 return enabled;
218 }
219 return 0;
220}
221/*---------------------------------------------------------------------------*/
222static int
223value(int type)
224{
225 uint32_t value;
226
227 if(!enabled) {
228 PRINTF("SHT21: sensor not started\n");
229 return SHT21_ERROR;
230 }
231
232 if(type == SHT21_READ_RAW_TEMP) {
233 return sht21_read_temperature();
234 } else if(type == SHT21_READ_RAW_RHUM) {
235 return sht21_read_humidity();
236 } else if(type == SHT21_READ_TEMP) {
237 value = sht21_read_temperature();
238 return sht21_convert_temperature(value);
239 } else if(type == SHT21_READ_RHUM) {
240 value = sht21_read_humidity();
241 return sht21_convert_humidity(value);
242 } else {
243 PRINTF("SHT21: invalid value requested\n");
244 return SHT21_ERROR;
245 }
246}
247/*---------------------------------------------------------------------------*/
248static int
249configure(int type, int value)
250{
251 if(type == SHT21_ACTIVATE) {
252 if(!sht21_is_present()) {
253 PRINTF("SHT21: is not present\n");
254 return SHT21_ERROR;
255 } else {
256 sht21_init();
257 enabled = 1;
258 return SHT21_SUCCESS;
259 }
260 }
261
262 if(type == SHT21_RESET && enabled) {
263 sht21_reset();
264 return SHT21_SUCCESS;
265 } else {
266 PRINTF("SHT21: is not enabled\n");
267 return SHT21_ERROR;
268 }
269
270 return SHT21_ERROR;
271}
272/*---------------------------------------------------------------------------*/
273SENSORS_SENSOR(sht21, SHT21_SENSOR, value, configure, status);
274/*---------------------------------------------------------------------------*/
275/** @} */
uint8_t i2c_burst_send(uint8_t slave_addr, uint8_t *data, uint8_t len)
Perform all operations to send multiple bytes to a slave.
Definition: i2c.c:188
uint8_t i2c_single_receive(uint8_t slave_addr, uint8_t *data)
Perform all operations to receive a byte from a slave.
Definition: i2c.c:172
uint8_t i2c_burst_receive(uint8_t slave_addr, uint8_t *data, uint8_t len)
Perform all operations to receive multiple bytes from a slave.
Definition: i2c.c:218
uint8_t i2c_single_send(uint8_t slave_addr, uint8_t data)
Perform all operations to send a byte to a slave.
Definition: i2c.c:159
Header file for the SHT21 temperature and humidity sensor driver.