-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathsht3x.c
506 lines (465 loc) · 13 KB
/
sht3x.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
#include <string.h>
#define DBG_ENABLE
#define DBG_SECTION_NAME "sht3x"
#define DBG_LEVEL DBG_LOG
#define DBG_COLOR
#include <rtdbg.h>
#include "sht3x.h"
#ifdef PKG_USING_SHT3X
#define CRC_POLY 0x31
/**
* This function write 2-byte cmd to SHT3x
*
* @param dev the pointer of device driver structure
* @param cmd the 16bit command to be sent to SHT3x
*
* @return the cmd transfer status, RT_EOK reprensents setting successfully.
*/
static rt_err_t write_cmd(sht3x_device_t dev, rt_uint16_t cmd)
{
struct rt_i2c_msg msgs;
rt_uint8_t buf[2] ;
buf[0] = cmd >> 8 ;
buf[1] = cmd & 0xFF ;
msgs.addr = dev->sht3x_addr;
msgs.flags = RT_I2C_WR;
msgs.buf = buf;
msgs.len = 2;
if (rt_i2c_transfer(dev->i2c, &msgs, 1) == 1)
return RT_EOK;
else
return -RT_ERROR;
}
/**
* This function read len bytes from dev and store the bytes in to buf
*
* @param dev the pointer of device driver structure
* @param buf the pointer to buffer array
* @param len the number of bytes to be read
*
* @return the i2c read status, RT_EOK represents success.
*/
static rt_err_t read_bytes(sht3x_device_t dev, rt_uint8_t * buf, rt_uint8_t len)
{
if(rt_i2c_master_recv(dev->i2c, dev->sht3x_addr, RT_I2C_RD, buf, len) == len){
return RT_EOK ;
}else
{
return - RT_ERROR ;
}
}
/**
* This function calculate CRC value of bytes in buffer
* CRC_POLY is predefined as 0x31
*
* @param buf the pointer to buffer array
* @param len the length of buffer array
*
* @return calculated CRC value.
*/
static rt_uint8_t crc8(rt_uint8_t * buf, rt_uint8_t len)
{
rt_uint8_t crc = 0xFF ;
rt_uint8_t i, j ;
for(j = len; j; j --){
crc ^= *buf ++ ;
for( i = 8; i; i --){
crc = (crc & 0x80) ? (crc << 1) ^ CRC_POLY : (crc << 1) ;
}
}
return crc ;
}
/**
* This function read temperature and humidity by single shot mode
* Attention:
* - rt_thread_mdelay() is called to wait for SHT3x to be ready to read
* - the temperature and humidity is stored in the device driver structure
*
* @param dev the pointer of device driver structure
*
* @return the status of read data from SHT3x, RT_EOK means success.
*/
rt_err_t sht3x_read_singleshot(sht3x_device_t dev)
{
rt_uint8_t temp[6] ;
rt_err_t result;
RT_ASSERT(dev);
result = rt_mutex_take(dev->lock, RT_WAITING_FOREVER);
if (result == RT_EOK)
{
if( write_cmd(dev, dev->cmd_readout) == RT_EOK)
{
// wait about 5 ms
rt_thread_mdelay(5);
if(read_bytes(dev, temp, 6) == RT_EOK){
if(crc8(temp, 2) == temp[2]){
dev->temperature = -45.0 + (temp[1] | temp[0] << 8) * 175.0 / (0xFFFF - 1) ; //sensor temperature convert to reality
result = RT_EOK ;
}else{
result = -RT_ERROR ;
}
if(crc8(temp + 3, 2) == temp[5]){
dev->humidity = (temp[4] | temp[3] << 8) * 0.0015259022 ; //sensor humidity convert to reality
}else{
result = -RT_ERROR ;
}
}else
{
result = -RT_ERROR ;
}
}
else
{
result = -RT_ERROR ;
}
rt_mutex_release(dev->lock);
}
else
{
LOG_E("Taking mutex of SHT3x failed.");
result = -RT_ERROR;
}
return result;
}
/**
* This function resets all parameter with default
*
* @param dev the pointer of device driver structure
*
* @return the softreset status, RT_EOK reprensents setting successfully.
*/
rt_err_t sht3x_softreset(sht3x_device_t dev)
{
RT_ASSERT(dev);
if( write_cmd(dev, CMD_SOFT_RESET) == RT_EOK)
{
return RT_EOK;
}else{
return RT_ERROR ;
}
}
/**
* This function clear the status register in SHT3x
*
* @param dev the pointer of device driver structure
*
* @return the command transfer status, RT_EOK means success.
*/
rt_err_t sht3x_clear_status(sht3x_device_t dev)
{
RT_ASSERT(dev);
if( write_cmd(dev, CMD_CLEAR_STATUS) == RT_EOK)
{
return RT_EOK ;
}else{
return RT_ERROR ;
}
}
/**
* This function read the status register from SHT3x
* Attention:
* - the status word is stored in device driver structure
*
* @param dev the pointer of device driver structure
*
* @return the command transfer status, RT_EOK means success.
*/
rt_err_t sht3x_read_status(sht3x_device_t dev)
{
rt_uint8_t buf[3];
RT_ASSERT(dev);
if( write_cmd(dev, CMD_READ_STATUS) == RT_EOK)
{
read_bytes(dev, buf, 3);
if( crc8(buf, 2) == buf[2])
{
dev->status.status_word = ( buf[0] << 8 ) | buf[1];
return RT_EOK ;
}
}
return -RT_ERROR ;
}
/**
* This function enable heater
* @param dev the pointer of device driver structure
*
* @return the command transfer status, RT_EOK means success.
*/
rt_err_t sht3x_enable_heater(sht3x_device_t dev)
{
RT_ASSERT(dev);
if( write_cmd(dev, CMD_HEATER_ENABLE) == RT_EOK)
{
return RT_EOK ;
}else
{
return -RT_ERROR ;
}
}
/**
* This function disable heater
* @param dev the pointer of device driver structure
*
* @return the command transfer status, RT_EOK means success.
*/
rt_err_t sht3x_disable_heater(sht3x_device_t dev)
{
RT_ASSERT(dev);
if( write_cmd(dev, CMD_HEATER_DISABLE) == RT_EOK)
{
return RT_EOK ;
}else
{
return -RT_ERROR ;
}
}
/**
* This function write accelerated response time command to SHT3x
* @param dev the pointer of device driver structure
*
* @return the command transfer status, RT_EOK means success.
*/
rt_err_t sht3x_acc_resp_time(sht3x_device_t dev)
{
RT_ASSERT(dev);
if( write_cmd(dev, CMD_ART) == RT_EOK)
{
return RT_EOK ;
}else
{
return -RT_ERROR ;
}
}
/**
* This function write break command to SHT3x to break out of continuous readout mode
* @param dev the pointer of device driver structure
*
* @return the command transfer status, RT_EOK means success.
*/
rt_err_t sht3x_break(sht3x_device_t dev)
{
RT_ASSERT(dev);
if( write_cmd(dev, CMD_BREAK) == RT_EOK)
{
return RT_EOK ;
}else
{
return -RT_ERROR ;
}
}
/**
* This function initializes sht3x registered device driver
*
* @param i2c_bus_name the name of i2c device used by SHT3x device
* @param sht3x_addr the address of SHT3x device
*
* @return the pointer to sht3x device driver structure.
*/
sht3x_device_t sht3x_init(const char *i2c_bus_name, rt_uint8_t sht3x_addr)
{
sht3x_device_t dev;
RT_ASSERT(i2c_bus_name);
dev = rt_calloc(1, sizeof(struct sht3x_device));
if (dev == RT_NULL)
{
LOG_E("Can't allocate memory for sht3x device on '%s' ", i2c_bus_name);
return RT_NULL;
}
if(sht3x_addr == SHT3X_ADDR_PD || sht3x_addr == SHT3X_ADDR_PU){
dev->sht3x_addr = sht3x_addr ;
}else{
LOG_E("Illegal sht3x address:'%x'", sht3x_addr);
rt_free(dev);
return RT_NULL;
}
dev->i2c = rt_i2c_bus_device_find(i2c_bus_name);
if (dev->i2c == RT_NULL)
{
LOG_E("Can't find sht3x device on '%s' ", i2c_bus_name);
rt_free(dev);
return RT_NULL;
}
dev->lock = rt_mutex_create("mutex_sht3x", RT_IPC_FLAG_FIFO);
if (dev->lock == RT_NULL)
{
LOG_E("Can't create mutex for sht3x device on '%s' ", i2c_bus_name);
rt_free(dev);
return RT_NULL;
}
// I2C streching disabled, medium repeatability for default single shot readout
dev->cmd_readout = CMD_MEAS_POLLING_M ;
// clear the status register
sht3x_clear_status(dev);
return dev;
}
/**
* This function releases memory and deletes mutex lock
*
* @param dev the pointer of device driver structure
*/
void sht3x_deinit(sht3x_device_t dev)
{
RT_ASSERT(dev);
rt_mutex_delete(dev->lock);
rt_free(dev);
}
/**
* This function is exported to MSH commands list
* Usage example:
* - sht3x probe i2c1 pu : initialize sht3x device on i2c1 bus with address pin pulled up(i2c address 0x45)
* - sht3x probe i2c1: initialize sht3x device one i2c1 bus with address pin pulled down by default(i2c address 0x44)
* - sht3x read: read and print temperature and humidity from previously initialized sht3x
*/
void sht3x(int argc, char *argv[])
{
static sht3x_device_t dev = RT_NULL;
rt_uint8_t sht_addr = SHT3X_ADDR_PD ;
if (argc > 1)
{
if (!strcmp(argv[1], "probe"))
{
if (argc >= 3)
{
/* initialize the sensor when first probe */
if (!dev || strcmp(dev->i2c->parent.parent.name, argv[2]))
{
/* deinit the old device */
if(dev)
{
rt_kprintf("Deinit sht3x");
sht3x_deinit(dev);
}
// no else needed here
if( argc > 3)
{
if( !strcmp("pd", argv[3]))
{
sht_addr = SHT3X_ADDR_PD ;
}
else if( !strcmp("pu", argv[3]))
{
sht_addr = SHT3X_ADDR_PU ;
}
else
{
rt_kprintf("Illegal sht3x address, using 0x44 by default\n");
sht_addr = SHT3X_ADDR_PD ; // pulled down by default: 0x44
}
}
// no else needed here
dev = sht3x_init(argv[2], sht_addr);
if(!dev)
{
rt_kprintf("sht3x probe failed, check input args\n");
}else
{
rt_kprintf("sht3x probed, addr:0x%x\n", sht_addr) ;
}
}
}
else
{
rt_kprintf("sht3x probe <i2c dev name> - probe sensor by given name\n");
}
}
else if (!strcmp(argv[1], "read"))
{
if (dev)
{
/* read the sensor data */
sht3x_read_singleshot(dev);
rt_kprintf("sht3x humidity : %d.%d \n", (int)dev->humidity, (int)(dev->humidity * 10) % 10);
rt_kprintf("sht3x temperature: %d.%d \n", (int)dev->temperature, (int)(dev->temperature * 10) % 10);
}
else
{
rt_kprintf("Please using 'sht3x probe <i2c dev name> <pu/pd>' first\n");
}
}
else if (!strcmp(argv[1], "status"))
{
if(dev)
{
if(sht3x_read_status(dev) == RT_EOK)
{
rt_kprintf("sht3x status:\n");
rt_kprintf("\tchecksum:\t%d\t- 0 means checksum correct\n", dev->status.bits.checksum_ok);
rt_kprintf("\tcommand:\t%d\t- 0 means last cmd executed OK\n", dev->status.bits.command_ok);
rt_kprintf("\treset deteced:\t%d\n", dev->status.bits.reset_detected);
rt_kprintf("\talert pending:\t%d\n", dev->status.bits.alert_pending);
rt_kprintf("\tT track alert:\t%d\n", dev->status.bits.T_tracking_alert);
rt_kprintf("\tRH track alert:\t%d\n", dev->status.bits.RH_tracking_alert);
rt_kprintf("\theater enabled:\t%d\n", dev->status.bits.heater);
}else
{
rt_kprintf("sht3x status not read\n");
}
}else
{
rt_kprintf("Please using 'sht3x probe <i2c dev name> <pu/pd>' first\n");
}
}
else if (!strcmp(argv[1], "reset"))
{
if(dev)
{
if(sht3x_softreset(dev) == RT_EOK)
{
rt_kprintf("sht3x reset cmd sent\n");
}else
{
rt_kprintf("sht3x reset cmd not sent\n");
}
}else
{
rt_kprintf("Please using 'sht3x probe <i2c dev name> <pu/pd>' first\n");
}
}
else if (!strcmp(argv[1], "heater"))
{
if(dev)
{
if( !strcmp(argv[2], "on"))
{
if(sht3x_enable_heater(dev) == RT_EOK)
{
rt_kprintf("sht3x heater cmd sent\n");
}else
{
rt_kprintf("sht3x heater cmd not sent\n");
}
}else if( !strcmp(argv[2], "off"))
{
if(sht3x_disable_heater(dev) == RT_EOK)
{
rt_kprintf("sht3x heater cmd sent\n");
}else
{
rt_kprintf("sht3x heater cmd not sent\n");
}
}
else{
rt_kprintf("Please input correct format:sht3x heater on/off\n");
}
}else
{
rt_kprintf("Please using 'sht3x probe <i2c dev name> <pu/pd>' first\n");
}
}
else
{
rt_kprintf("Unknown command. Enter 'sht3x' for help\n");
}
}
else
{
rt_kprintf("Usage:\n");
rt_kprintf("\tsht3x probe <i2c dev name> <pu/pd> -- probe sensor by i2c dev name and pull config\n");
rt_kprintf("\tsht3x read -- read sensor sht3x data\n");
rt_kprintf("\tsht3x status -- status register of sht3x\n");
rt_kprintf("\tsht3x reset -- send soft reset command to sht3x\n");
rt_kprintf("\tsht3x heater <on/off> -- turn on/off heater of sht3x\n");
}
}
MSH_CMD_EXPORT(sht3x, sht3x sensor);
#endif /* PKG_USING_SHT3X */