LibDriver SGP40
Loading...
Searching...
No Matches
driver_sgp40.c
Go to the documentation of this file.
1
36
37#include "driver_sgp40.h"
38
42#define CHIP_NAME "Sensirion SGP40"
43#define MANUFACTURER_NAME "Sensirion"
44#define SUPPLY_VOLTAGE_MIN 1.70f
45#define SUPPLY_VOLTAGE_MAX 3.60f
46#define MAX_CURRENT 4.00f
47#define TEMPERATURE_MIN -20.0f
48#define TEMPERATURE_MAX 55.0f
49#define DRIVER_VERSION 1000
50
54#define SGP40_ADDRESS (0x59 << 1)
55
59#define SGP40_COMMAND_MEASURE_RAW 0x260FU
60#define SGP40_COMMAND_EXECUTE_SELF_TEST 0x280EU
61#define SGP40_COMMAND_TURN_HEATER_OFF 0x3615U
62#define SGP40_COMMAND_GET_SERIAL_ID 0x3682U
63#define SGP40_COMMAND_SOFT_RESET 0x0006U
64
68#define SGP40_CRC8_POLYNOMIAL 0x31
69#define SGP40_CRC8_INIT 0xFF
70
85static uint8_t a_sgp40_iic_read_with_param(sgp40_handle_t *handle, uint16_t reg, uint8_t *data, uint16_t len,
86 uint16_t delay_ms, uint8_t *output, uint16_t output_len)
87{
88 uint8_t buf[16];
89 uint16_t i;
90
91 if ((len + 2) > 16) /* check length */
92 {
93 return 1; /* return error */
94 }
95 memset(buf, 0, sizeof(uint8_t) * 16); /* clear the buffer */
96 buf[0] = (uint8_t)((reg >> 8) & 0xFF); /* set MSB of reg */
97 buf[1] = (uint8_t)(reg & 0xFF); /* set LSB of reg */
98 for (i = 0; i < len; i++)
99 {
100 buf[2 + i] = data[i]; /* copy write data */
101 }
102
103 if (handle->iic_write_cmd(SGP40_ADDRESS, (uint8_t *)buf, len + 2) != 0) /* write iic command */
104 {
105 return 1; /* write command */
106 }
107 handle->delay_ms(delay_ms); /* delay ms */
108 if (handle->iic_read_cmd(SGP40_ADDRESS, output, output_len) != 0) /* read data */
109 {
110 return 1; /* write command */
111 }
112 else
113 {
114 return 0; /* success return 0 */
115 }
116}
117
130static uint8_t a_sgp40_iic_read(sgp40_handle_t *handle, uint16_t reg, uint8_t *data, uint16_t len, uint16_t delay_ms)
131{
132 uint8_t buf[2];
133
134 memset(buf, 0, sizeof(uint8_t) * 2); /* clear the buffer */
135 buf[0] = (uint8_t)((reg >> 8) & 0xFF); /* set reg MSB */
136 buf[1] = (uint8_t)(reg & 0xFF); /* set reg LSB */
137 if (handle->iic_write_cmd(SGP40_ADDRESS, (uint8_t *)buf, 2) != 0) /* write command */
138 {
139 return 1; /* return error */
140 }
141 handle->delay_ms(delay_ms); /* delay ms */
142 if (handle->iic_read_cmd(SGP40_ADDRESS, data, len) != 0) /* read data */
143 {
144 return 1; /* write command */
145 }
146 else
147 {
148 return 0; /* success return 0 */
149 }
150}
151
163static uint8_t a_sgp40_iic_write(sgp40_handle_t *handle, uint16_t reg, uint8_t *data, uint16_t len)
164{
165 uint8_t buf[16];
166 uint16_t i;
167
168 if ((len + 2) > 16) /* check length */
169 {
170 return 1; /* return error */
171 }
172 memset(buf, 0, sizeof(uint8_t) * 16); /* clear the buffer */
173 buf[0] = (uint8_t)((reg >> 8) & 0xFF); /* set MSB of reg */
174 buf[1] = (uint8_t)(reg & 0xFF); /* set LSB of reg */
175 for (i = 0; i < len; i++)
176 {
177 buf[2 + i] = data[i]; /* copy write data */
178 }
179
180 if (handle->iic_write_cmd(SGP40_ADDRESS, (uint8_t *)buf, len + 2) != 0) /* write iic command */
181 {
182 return 1; /* write command */
183 }
184 else
185 {
186 return 0; /* success return 0 */
187 }
188}
189
197static uint8_t a_sgp40_generate_crc(uint8_t* data, uint8_t count)
198{
199 uint8_t current_byte;
200 uint8_t crc = SGP40_CRC8_INIT;
201 uint8_t crc_bit;
202
203 for (current_byte = 0; current_byte < count; ++current_byte) /* calculate crc */
204 {
205 crc ^= (data[current_byte]); /* xor data */
206 for (crc_bit = 8; crc_bit > 0; --crc_bit) /* 8 bit */
207 {
208 if ((crc & 0x80) != 0) /* if 7th bit is 1 */
209 {
210 crc = (crc << 1) ^ SGP40_CRC8_POLYNOMIAL; /* xor */
211 }
212 else
213 {
214 crc = crc << 1; /* left shift 1 */
215 }
216 }
217 }
218
219 return crc; /* return crc */
220}
221
234uint8_t sgp40_humidity_convert_to_register(sgp40_handle_t *handle, float rh, uint16_t *reg)
235{
236 if (handle == NULL) /* check handle */
237 {
238 return 2; /* return error */
239 }
240 if (handle->inited != 1) /* check handle initialization */
241 {
242 return 3; /* return error */
243 }
244
245 *reg = (uint16_t)(rh / 100.0f * 65535.0f); /* convert the humidity */
246
247 return 0; /* success return 0 */
248}
249
262uint8_t sgp40_temperature_convert_to_register(sgp40_handle_t *handle, float temp, uint16_t *reg)
263{
264 if (handle == NULL) /* check handle */
265 {
266 return 2; /* return error */
267 }
268 if (handle->inited != 1) /* check handle initialization */
269 {
270 return 3; /* return error */
271 }
272
273 *reg = (uint16_t)((temp + 45.0f) / 175.0f * 65535.0f); /* convert the humidity */
274
275 return 0; /* success return 0 */
276}
277
291uint8_t sgp40_get_measure_raw(sgp40_handle_t *handle, uint16_t raw_humidity,
292 uint16_t raw_temperature, uint16_t *sraw_voc)
293{
294 uint8_t res;
295 uint8_t input[6];
296 uint8_t buf[3];
297
298 if (handle == NULL) /* check handle */
299 {
300 return 2; /* return error */
301 }
302 if (handle->inited != 1) /* check handle initialization */
303 {
304 return 3; /* return error */
305 }
306
307 memset(buf, 0, sizeof(uint8_t) * 3); /* clear the buffer */
308 input[0] = (raw_humidity >> 8) & 0xFF; /* index 0 */
309 input[1] = (raw_humidity >> 0) & 0xFF; /* index 1 */
310 input[2] = a_sgp40_generate_crc(&input[0], 2); /* index 2 */
311 input[3] = (raw_temperature >> 8) & 0xFF; /* index 3 */
312 input[4] = (raw_temperature >> 0) & 0xFF; /* index 4 */
313 input[5] = a_sgp40_generate_crc(&input[3], 2); /* index 5 */
314 res = a_sgp40_iic_read_with_param(handle, SGP40_COMMAND_MEASURE_RAW, input, 6, 50, buf, 3); /* read measure raw */
315 if (res != 0) /* check result */
316 {
317 handle->debug_print("sgp40: read measure raw failed.\n"); /* read measure failed */
318
319 return 1; /* return error */
320 }
321 if (buf[2] != a_sgp40_generate_crc((uint8_t *)buf, 2)) /* check 1st crc */
322 {
323 handle->debug_print("sgp40: sraw voc crc check error.\n"); /* sraw voc crc check error */
324
325 return 1; /* return error */
326 }
327 *sraw_voc = (uint16_t)(((uint16_t)buf[0]) << 8 | buf[1]); /* get raw voc data */
328
329 return 0; /* success return 0 */
330}
331
344{
345 uint8_t res;
346 uint8_t input[6];
347 uint8_t buf[3];
348
349 if (handle == NULL) /* check handle */
350 {
351 return 2; /* return error */
352 }
353 if (handle->inited != 1) /* check handle initialization */
354 {
355 return 3; /* return error */
356 }
357
358 memset(buf, 0, sizeof(uint8_t) * 3); /* clear the buffer */
359 input[0] = 0x80; /* index 0 */
360 input[1] = 0x00; /* index 1 */
361 input[2] = 0xA2; /* index 2 */
362 input[3] = 0x66; /* index 3 */
363 input[4] = 0x66; /* index 4 */
364 input[5] = 0x93; /* index 5 */
365 res = a_sgp40_iic_read_with_param(handle, SGP40_COMMAND_MEASURE_RAW, input, 6, 50, buf, 3); /* read measure raw */
366 if (res != 0) /* check result */
367 {
368 handle->debug_print("sgp40: read measure raw failed.\n"); /* read measure failed */
369
370 return 1; /* return error */
371 }
372 if (buf[2] != a_sgp40_generate_crc((uint8_t *)buf, 2)) /* check 1st crc */
373 {
374 handle->debug_print("sgp40: sraw voc crc check error.\n"); /* sraw voc crc check error */
375
376 return 1; /* return error */
377 }
378 *sraw_voc = (uint16_t)(((uint16_t)buf[0]) << 8 | buf[1]); /* get raw voc data */
379
380 return 0; /* success return 0 */
381}
382
394uint8_t sgp40_get_measure_test(sgp40_handle_t *handle, uint16_t *result)
395{
396 uint8_t res;
397 uint8_t buf[3];
398
399 if (handle == NULL) /* check handle */
400 {
401 return 2; /* return error */
402 }
403 if (handle->inited != 1) /* check handle initialization */
404 {
405 return 3; /* return error */
406 }
407
408 memset(buf, 0, sizeof(uint8_t) * 3); /* clear the buffer */
409 res = a_sgp40_iic_read(handle, SGP40_COMMAND_EXECUTE_SELF_TEST, (uint8_t *)buf, 3, 320); /* read measure test */
410 if (res != 0) /* check result */
411 {
412 handle->debug_print("sgp40: read measure test failed.\n"); /* read measure test failed */
413
414 return 1; /* return error */
415 }
416 if (buf[2] != a_sgp40_generate_crc((uint8_t *)buf, 2)) /* check crc */
417 {
418 handle->debug_print("sgp40: measure test check error.\n"); /* measure test check error */
419
420 return 1; /* return error */
421 }
422 *result = (uint16_t)(((uint16_t)buf[0]) << 8 | buf[1]); /* combine data */
423
424 return 0; /* success return 0 */
425}
426
438{
439 uint8_t res;
440 uint8_t reg;
441
442 if (handle == NULL) /* check handle */
443 {
444 return 2; /* return error */
445 }
446 if (handle->inited != 1) /* check handle initialization */
447 {
448 return 3; /* return error */
449 }
450
451 reg = 0x06; /* soft reset command */
452 res = handle->iic_write_cmd(0x00, (uint8_t *)&reg, 1); /* write reset config */
453 if (res != 0) /* check result */
454 {
455 handle->debug_print("sgp40: write soft reset failed.\n"); /* write soft reset failed */
456
457 return 1; /* return error */
458 }
459 handle->delay_ms(5); /* delay 5ms */
460
461 return 0; /* success return 0 */
462}
463
475{
476 uint8_t res;
477
478 if (handle == NULL) /* check handle */
479 {
480 return 2; /* return error */
481 }
482 if (handle->inited != 1) /* check handle initialization */
483 {
484 return 3; /* return error */
485 }
486
487 res = a_sgp40_iic_write(handle, SGP40_COMMAND_TURN_HEATER_OFF, NULL, 0); /* write turn heater off command */
488 if (res != 0) /* check result */
489 {
490 handle->debug_print("sgp40: write turn heater off failed.\n"); /* write turn heater off failed */
491
492 return 1; /* return error */
493 }
494 handle->delay_ms(1); /* delay 1 ms */
495
496 return 0; /* success return 0 */
497}
498
510uint8_t sgp40_get_serial_id(sgp40_handle_t *handle, uint16_t id[3])
511{
512 uint8_t res;
513 uint8_t buf[9];
514
515 if (handle == NULL) /* check handle */
516 {
517 return 2; /* return error */
518 }
519 if (handle->inited != 1) /* check handle initialization */
520 {
521 return 3; /* return error */
522 }
523
524 memset(buf, 0, sizeof(uint8_t) * 9); /* clear the buffer */
525 res = a_sgp40_iic_read(handle, SGP40_COMMAND_GET_SERIAL_ID, (uint8_t *)buf, 9, 1); /* read config */
526 if (res != 0) /* check result */
527 {
528 handle->debug_print("sgp40: read serial id failed.\n"); /* read serial id failed */
529
530 return 1; /* return error */
531 }
532 if (buf[2] != a_sgp40_generate_crc((uint8_t *)&buf[0], 2)) /* check 1st crc */
533 {
534 handle->debug_print("sgp40: crc 1 check failed.\n"); /* crc 1 check failed */
535
536 return 1; /* return error */
537 }
538 if (buf[5] != a_sgp40_generate_crc((uint8_t *)&buf[3], 2)) /* check 2nd crc */
539 {
540 handle->debug_print("sgp40: crc 2 check failed.\n"); /* crc 2 check failed */
541
542 return 1; /* return error */
543 }
544 if (buf[8] != a_sgp40_generate_crc((uint8_t *)&buf[6], 2)) /* check 3rd crc */
545 {
546 handle->debug_print("sgp40: crc 3 check failed.\n"); /* crc 3 check failed */
547
548 return 1; /* return error */
549 }
550 id[0] = (uint16_t)((((uint16_t)buf[0]) << 8) | buf[1]); /* set id 0 */
551 id[1] = (uint16_t)((((uint16_t)buf[3]) << 8) | buf[4]); /* set id 1 */
552 id[2] = (uint16_t)((((uint16_t)buf[6]) << 8) | buf[7]); /* set id 2 */
553
554 return 0; /* success return 0 */
555}
556
568{
569 if (handle == NULL) /* check handle */
570 {
571 return 2; /* return error */
572 }
573 if (handle->debug_print == NULL) /* check debug_print */
574 {
575 return 3; /* return error */
576 }
577 if (handle->iic_init == NULL) /* check iic_init */
578 {
579 handle->debug_print("sgp40: iic_init is null.\n"); /* iic_init is null */
580
581 return 3; /* return error */
582 }
583 if (handle->iic_deinit == NULL) /* check iic_deinit */
584 {
585 handle->debug_print("sgp40: iic_deinit is null.\n"); /* iic_deinit is null */
586
587 return 3; /* return error */
588 }
589 if (handle->iic_write_cmd == NULL) /* check iic_write_cmd */
590 {
591 handle->debug_print("sgp40: iic_write_cmd is null.\n"); /* iic_write_cmd is null */
592
593 return 3; /* return error */
594 }
595 if (handle->iic_read_cmd == NULL) /* check iic_read_cmd */
596 {
597 handle->debug_print("sgp40: iic_read_cmd is null.\n"); /* iic_read_cmd is null */
598
599 return 3; /* return error */
600 }
601 if (handle->delay_ms == NULL) /* check delay_ms */
602 {
603 handle->debug_print("sgp40: delay_ms is null.\n"); /* delay_ms is null */
604
605 return 3; /* return error */
606 }
607
608 if (handle->iic_init() != 0) /* iic init */
609 {
610 handle->debug_print("sgp40: iic init failed.\n"); /* iic init failed */
611
612 return 3; /* return error */
613 }
614 handle->inited = 1; /* flag finish initialization */
615
616 return 0; /* success return 0 */
617}
618
631{
632 if (handle == NULL) /* check handle */
633 {
634 return 2; /* return error */
635 }
636 if (handle->inited != 1) /* check handle initialization */
637 {
638 return 3; /* return error */
639 }
640
641 if (sgp40_turn_heater_off(handle) != 0) /* turn heater off */
642 {
643 handle->debug_print("sgp40: turn heater off failed.\n"); /* turn heater off failed */
644
645 return 4; /* return error */
646 }
647 if (handle->iic_deinit() != 0) /* iic deinit */
648 {
649 handle->debug_print("sgp40: iic close failed.\n"); /* iic close failed */
650
651 return 3; /* return error */
652 }
653 handle->inited = 0; /* flag close initialization */
654
655 return 0; /* success return 0 */
656}
657
671uint8_t sgp40_set_reg(sgp40_handle_t *handle, uint16_t reg, uint8_t *buf, uint16_t len)
672{
673 if (handle == NULL) /* check handle */
674 {
675 return 2; /* return error */
676 }
677 if (handle->inited != 1) /* check handle initialization */
678 {
679 return 3; /* return error */
680 }
681
682 return a_sgp40_iic_write(handle, reg, buf, len); /* write data */
683}
684
698uint8_t sgp40_get_reg(sgp40_handle_t *handle, uint16_t reg, uint8_t *buf, uint16_t len)
699{
700 if (handle == NULL) /* check handle */
701 {
702 return 2; /* return error */
703 }
704 if (handle->inited != 1) /* check handle initialization */
705 {
706 return 3; /* return error */
707 }
708
709 return a_sgp40_iic_read(handle, reg, buf, len, 320); /* read data */
710}
711
721{
722 if (info == NULL) /* check handle */
723 {
724 return 2; /* return error */
725 }
726
727 memset(info, 0, sizeof(sgp40_info_t)); /* initialize sgp40 info structure */
728 strncpy(info->chip_name, CHIP_NAME, 32); /* copy chip name */
729 strncpy(info->manufacturer_name, MANUFACTURER_NAME, 32); /* copy manufacturer name */
730 strncpy(info->interface, "IIC", 8); /* copy interface name */
731 info->supply_voltage_min_v = SUPPLY_VOLTAGE_MIN; /* set minimal supply voltage */
732 info->supply_voltage_max_v = SUPPLY_VOLTAGE_MAX; /* set maximum supply voltage */
733 info->max_current_ma = MAX_CURRENT; /* set maximum current */
734 info->temperature_max = TEMPERATURE_MAX; /* set minimal temperature */
735 info->temperature_min = TEMPERATURE_MIN; /* set maximum temperature */
736 info->driver_version = DRIVER_VERSION; /* set driver version */
737
738 return 0; /* success return 0 */
739}
#define SGP40_CRC8_INIT
#define SGP40_COMMAND_MEASURE_RAW
chip command definition
#define SGP40_COMMAND_TURN_HEATER_OFF
#define MAX_CURRENT
#define SGP40_CRC8_POLYNOMIAL
crc8 definition
#define SGP40_ADDRESS
chip address definition
#define SUPPLY_VOLTAGE_MAX
#define TEMPERATURE_MAX
#define SGP40_COMMAND_GET_SERIAL_ID
#define SGP40_COMMAND_EXECUTE_SELF_TEST
#define MANUFACTURER_NAME
#define TEMPERATURE_MIN
#define SUPPLY_VOLTAGE_MIN
#define CHIP_NAME
chip information definition
#define DRIVER_VERSION
driver sgp40 header file
uint8_t sgp40_get_measure_raw(sgp40_handle_t *handle, uint16_t raw_humidity, uint16_t raw_temperature, uint16_t *sraw_voc)
get the measure raw result
uint8_t sgp40_get_serial_id(sgp40_handle_t *handle, uint16_t id[3])
get the chip serial id
uint8_t sgp40_init(sgp40_handle_t *handle)
initialize the chip
uint8_t sgp40_soft_reset(sgp40_handle_t *handle)
soft reset the chip
uint8_t sgp40_get_measure_raw_without_compensation(sgp40_handle_t *handle, uint16_t *sraw_voc)
get the measure raw result without compensation
uint8_t sgp40_info(sgp40_info_t *info)
get chip information
uint8_t sgp40_humidity_convert_to_register(sgp40_handle_t *handle, float rh, uint16_t *reg)
convert the humidity to the register data
uint8_t sgp40_turn_heater_off(sgp40_handle_t *handle)
turn heater off
uint8_t sgp40_deinit(sgp40_handle_t *handle)
close the chip
uint8_t sgp40_get_measure_test(sgp40_handle_t *handle, uint16_t *result)
get the chip measure test
struct sgp40_handle_s sgp40_handle_t
sgp40 handle structure definition
uint8_t sgp40_temperature_convert_to_register(sgp40_handle_t *handle, float temp, uint16_t *reg)
convert the temperature to the register data
struct sgp40_info_s sgp40_info_t
sgp40 information structure definition
uint8_t sgp40_get_reg(sgp40_handle_t *handle, uint16_t reg, uint8_t *buf, uint16_t len)
get the chip register
uint8_t sgp40_set_reg(sgp40_handle_t *handle, uint16_t reg, uint8_t *buf, uint16_t len)
set the chip register
void(* delay_ms)(uint32_t ms)
void(* debug_print)(const char *const fmt,...)
uint8_t(* iic_init)(void)
uint8_t(* iic_read_cmd)(uint8_t addr, uint8_t *buf, uint16_t len)
uint8_t(* iic_deinit)(void)
uint8_t(* iic_write_cmd)(uint8_t addr, uint8_t *buf, uint16_t len)
float temperature_max
float supply_voltage_max_v
uint32_t driver_version
float temperature_min
float max_current_ma
char manufacturer_name[32]
float supply_voltage_min_v
char interface[8]
char chip_name[32]