LibDriver SGP41
Loading...
Searching...
No Matches
driver_sgp41.c
Go to the documentation of this file.
1
36
37#include "driver_sgp41.h"
38
42#define CHIP_NAME "Sensirion SGP41"
43#define MANUFACTURER_NAME "Sensirion"
44#define SUPPLY_VOLTAGE_MIN 1.70f
45#define SUPPLY_VOLTAGE_MAX 3.60f
46#define MAX_CURRENT 4.80f
47#define TEMPERATURE_MIN -10.0f
48#define TEMPERATURE_MAX 50.0f
49#define DRIVER_VERSION 1000
50
54#define SGP41_ADDRESS (0x59 << 1)
55
59#define SGP41_COMMAND_EXECUTE_CONDITIONING 0x2612U
60#define SGP41_COMMAND_MEASURE_RAW 0x2619U
61#define SGP41_COMMAND_EXECUTE_SELF_TEST 0x280EU
62#define SGP41_COMMAND_TURN_HEATER_OFF 0x3615U
63#define SGP41_COMMAND_GET_SERIAL_ID 0x3682U
64#define SGP41_COMMAND_SOFT_RESET 0x0006U
65
69#define SGP41_CRC8_POLYNOMIAL 0x31
70#define SGP41_CRC8_INIT 0xFF
71
86static uint8_t a_sgp41_iic_read_with_param(sgp41_handle_t *handle, uint16_t reg, uint8_t *data, uint16_t len,
87 uint16_t delay_ms, uint8_t *output, uint16_t output_len)
88{
89 uint8_t buf[16];
90 uint16_t i;
91
92 if ((len + 2) > 16) /* check length */
93 {
94 return 1; /* return error */
95 }
96 memset(buf, 0, sizeof(uint8_t) * 16); /* clear the buffer */
97 buf[0] = (uint8_t)((reg >> 8) & 0xFF); /* set MSB of reg */
98 buf[1] = (uint8_t)(reg & 0xFF); /* set LSB of reg */
99 for (i = 0; i < len; i++)
100 {
101 buf[2 + i] = data[i]; /* copy write data */
102 }
103
104 if (handle->iic_write_cmd(SGP41_ADDRESS, (uint8_t *)buf, len + 2) != 0) /* write iic command */
105 {
106 return 1; /* write command */
107 }
108 handle->delay_ms(delay_ms); /* delay ms */
109 if (handle->iic_read_cmd(SGP41_ADDRESS, output, output_len) != 0) /* read data */
110 {
111 return 1; /* write command */
112 }
113 else
114 {
115 return 0; /* success return 0 */
116 }
117}
118
131static uint8_t a_sgp41_iic_read(sgp41_handle_t *handle, uint16_t reg, uint8_t *data, uint16_t len, uint16_t delay_ms)
132{
133 uint8_t buf[2];
134
135 memset(buf, 0, sizeof(uint8_t) * 2); /* clear the buffer */
136 buf[0] = (uint8_t)((reg >> 8) & 0xFF); /* set reg MSB */
137 buf[1] = (uint8_t)(reg & 0xFF); /* set reg LSB */
138 if (handle->iic_write_cmd(SGP41_ADDRESS, (uint8_t *)buf, 2) != 0) /* write command */
139 {
140 return 1; /* return error */
141 }
142 handle->delay_ms(delay_ms); /* delay ms */
143 if (handle->iic_read_cmd(SGP41_ADDRESS, data, len) != 0) /* read data */
144 {
145 return 1; /* write command */
146 }
147 else
148 {
149 return 0; /* success return 0 */
150 }
151}
152
164static uint8_t a_sgp41_iic_write(sgp41_handle_t *handle, uint16_t reg, uint8_t *data, uint16_t len)
165{
166 uint8_t buf[16];
167 uint16_t i;
168
169 if ((len + 2) > 16) /* check length */
170 {
171 return 1; /* return error */
172 }
173 memset(buf, 0, sizeof(uint8_t) * 16); /* clear the buffer */
174 buf[0] = (uint8_t)((reg >> 8) & 0xFF); /* set MSB of reg */
175 buf[1] = (uint8_t)(reg & 0xFF); /* set LSB of reg */
176 for (i = 0; i < len; i++)
177 {
178 buf[2 + i] = data[i]; /* copy write data */
179 }
180
181 if (handle->iic_write_cmd(SGP41_ADDRESS, (uint8_t *)buf, len + 2) != 0) /* write iic command */
182 {
183 return 1; /* write command */
184 }
185 else
186 {
187 return 0; /* success return 0 */
188 }
189}
190
198static uint8_t a_sgp41_generate_crc(uint8_t* data, uint8_t count)
199{
200 uint8_t current_byte;
201 uint8_t crc = SGP41_CRC8_INIT;
202 uint8_t crc_bit;
203
204 for (current_byte = 0; current_byte < count; ++current_byte) /* calculate crc */
205 {
206 crc ^= (data[current_byte]); /* xor data */
207 for (crc_bit = 8; crc_bit > 0; --crc_bit) /* 8 bit */
208 {
209 if ((crc & 0x80) != 0) /* if 7th bit is 1 */
210 {
211 crc = (crc << 1) ^ SGP41_CRC8_POLYNOMIAL; /* xor */
212 }
213 else
214 {
215 crc = crc << 1; /* left shift 1 */
216 }
217 }
218 }
219
220 return crc; /* return crc */
221}
222
235uint8_t sgp41_humidity_convert_to_register(sgp41_handle_t *handle, float rh, uint16_t *reg)
236{
237 if (handle == NULL) /* check handle */
238 {
239 return 2; /* return error */
240 }
241 if (handle->inited != 1) /* check handle initialization */
242 {
243 return 3; /* return error */
244 }
245
246 *reg = (uint16_t)(rh / 100.0f * 65535.0f); /* convert the humidity */
247
248 return 0; /* success return 0 */
249}
250
263uint8_t sgp41_temperature_convert_to_register(sgp41_handle_t *handle, float temp, uint16_t *reg)
264{
265 if (handle == NULL) /* check handle */
266 {
267 return 2; /* return error */
268 }
269 if (handle->inited != 1) /* check handle initialization */
270 {
271 return 3; /* return error */
272 }
273
274 *reg = (uint16_t)((temp + 45.0f) / 175.0f * 65535.0f); /* convert the humidity */
275
276 return 0; /* success return 0 */
277}
278
290uint8_t sgp41_get_execute_conditioning(sgp41_handle_t *handle, uint16_t *sraw_voc)
291{
292 uint8_t res;
293 uint8_t input[6];
294 uint8_t buf[3];
295
296 if (handle == NULL) /* check handle */
297 {
298 return 2; /* return error */
299 }
300 if (handle->inited != 1) /* check handle initialization */
301 {
302 return 3; /* return error */
303 }
304
305 memset(buf, 0, sizeof(uint8_t) * 3); /* clear the buffer */
306 input[0] = 0x80; /* index 0 */
307 input[1] = 0x00; /* index 1 */
308 input[2] = 0xA2; /* index 2 */
309 input[3] = 0x66; /* index 3 */
310 input[4] = 0x66; /* index 4 */
311 input[5] = 0x93; /* index 5 */
312 res = a_sgp41_iic_read_with_param(handle, SGP41_COMMAND_EXECUTE_CONDITIONING, input, 6, 50,
313 buf, 3); /* read measure raw */
314 if (res != 0) /* check result */
315 {
316 handle->debug_print("sgp41: read measure raw failed.\n"); /* read measure failed */
317
318 return 1; /* return error */
319 }
320 if (buf[2] != a_sgp41_generate_crc((uint8_t *)buf, 2)) /* check 1st crc */
321 {
322 handle->debug_print("sgp41: sraw voc crc check error.\n"); /* sraw voc crc check error */
323
324 return 1; /* return error */
325 }
326 *sraw_voc = (uint16_t)(((uint16_t)buf[0]) << 8 | buf[1]); /* get raw voc data */
327
328 return 0; /* success return 0 */
329}
330
345uint8_t sgp41_get_measure_raw(sgp41_handle_t *handle, uint16_t raw_humidity, uint16_t raw_temperature,
346 uint16_t *sraw_voc, uint16_t *sraw_nox)
347{
348 uint8_t res;
349 uint8_t input[6];
350 uint8_t buf[6];
351
352 if (handle == NULL) /* check handle */
353 {
354 return 2; /* return error */
355 }
356 if (handle->inited != 1) /* check handle initialization */
357 {
358 return 3; /* return error */
359 }
360
361 memset(buf, 0, sizeof(uint8_t) * 6); /* clear the buffer */
362 input[0] = (raw_humidity >> 8) & 0xFF; /* index 0 */
363 input[1] = (raw_humidity >> 0) & 0xFF; /* index 1 */
364 input[2] = a_sgp41_generate_crc(&input[0], 2); /* index 2 */
365 input[3] = (raw_temperature >> 8) & 0xFF; /* index 3 */
366 input[4] = (raw_temperature >> 0) & 0xFF; /* index 4 */
367 input[5] = a_sgp41_generate_crc(&input[3], 2); /* index 5 */
368 res = a_sgp41_iic_read_with_param(handle, SGP41_COMMAND_MEASURE_RAW, input, 6, 50, buf, 6); /* read measure raw */
369 if (res != 0) /* check result */
370 {
371 handle->debug_print("sgp41: read measure raw failed.\n"); /* read measure failed */
372
373 return 1; /* return error */
374 }
375 if (buf[2] != a_sgp41_generate_crc((uint8_t *)buf, 2)) /* check 1st crc */
376 {
377 handle->debug_print("sgp41: sraw voc crc check error.\n"); /* sraw voc crc check error */
378
379 return 1; /* return error */
380 }
381 if (buf[5] != a_sgp41_generate_crc((uint8_t *)&buf[3], 2)) /* check 2nd crc */
382 {
383 handle->debug_print("sgp41: sraw nox crc check error.\n"); /* sraw nox crc check error */
384
385 return 1; /* return error */
386 }
387 *sraw_voc = (uint16_t)(((uint16_t)buf[0]) << 8 | buf[1]); /* get raw voc data */
388 *sraw_nox = (uint16_t)(((uint16_t)buf[3]) << 8 | buf[4]); /* get raw nox data */
389
390 return 0; /* success return 0 */
391}
392
405uint8_t sgp41_get_measure_raw_without_compensation(sgp41_handle_t *handle, uint16_t *sraw_voc, uint16_t *sraw_nox)
406{
407 uint8_t res;
408 uint8_t input[6];
409 uint8_t buf[6];
410
411 if (handle == NULL) /* check handle */
412 {
413 return 2; /* return error */
414 }
415 if (handle->inited != 1) /* check handle initialization */
416 {
417 return 3; /* return error */
418 }
419
420 memset(buf, 0, sizeof(uint8_t) * 6); /* clear the buffer */
421 input[0] = 0x80; /* index 0 */
422 input[1] = 0x00; /* index 1 */
423 input[2] = 0xA2; /* index 2 */
424 input[3] = 0x66; /* index 3 */
425 input[4] = 0x66; /* index 4 */
426 input[5] = 0x93; /* index 5 */
427 res = a_sgp41_iic_read_with_param(handle, SGP41_COMMAND_MEASURE_RAW, input, 6, 50, buf, 6); /* read measure raw */
428 if (res != 0) /* check result */
429 {
430 handle->debug_print("sgp41: read measure raw failed.\n"); /* read measure failed */
431
432 return 1; /* return error */
433 }
434 if (buf[2] != a_sgp41_generate_crc((uint8_t *)buf, 2)) /* check 1st crc */
435 {
436 handle->debug_print("sgp41: sraw voc crc check error.\n"); /* sraw voc crc check error */
437
438 return 1; /* return error */
439 }
440 if (buf[5] != a_sgp41_generate_crc((uint8_t *)&buf[3], 2)) /* check 2nd crc */
441 {
442 handle->debug_print("sgp41: sraw nox crc check error.\n"); /* sraw nox crc check error */
443
444 return 1; /* return error */
445 }
446 *sraw_voc = (uint16_t)(((uint16_t)buf[0]) << 8 | buf[1]); /* get raw voc data */
447 *sraw_nox = (uint16_t)(((uint16_t)buf[3]) << 8 | buf[4]); /* get raw nox data */
448
449 return 0; /* success return 0 */
450}
451
463uint8_t sgp41_get_measure_test(sgp41_handle_t *handle, uint16_t *result)
464{
465 uint8_t res;
466 uint8_t buf[3];
467
468 if (handle == NULL) /* check handle */
469 {
470 return 2; /* return error */
471 }
472 if (handle->inited != 1) /* check handle initialization */
473 {
474 return 3; /* return error */
475 }
476
477 memset(buf, 0, sizeof(uint8_t) * 3); /* clear the buffer */
478 res = a_sgp41_iic_read(handle, SGP41_COMMAND_EXECUTE_SELF_TEST, (uint8_t *)buf, 3, 320); /* read measure test */
479 if (res != 0) /* check result */
480 {
481 handle->debug_print("sgp41: read measure test failed.\n"); /* read measure test failed */
482
483 return 1; /* return error */
484 }
485 if (buf[2] != a_sgp41_generate_crc((uint8_t *)buf, 2)) /* check crc */
486 {
487 handle->debug_print("sgp41: measure test check error.\n"); /* measure test check error */
488
489 return 1; /* return error */
490 }
491 *result = (uint16_t)(((uint16_t)buf[0]) << 8 | buf[1]); /* combine data */
492
493 return 0; /* success return 0 */
494}
495
507{
508 uint8_t res;
509 uint8_t reg;
510
511 if (handle == NULL) /* check handle */
512 {
513 return 2; /* return error */
514 }
515 if (handle->inited != 1) /* check handle initialization */
516 {
517 return 3; /* return error */
518 }
519
520 reg = 0x06; /* soft reset command */
521 res = handle->iic_write_cmd(0x00, (uint8_t *)&reg, 1); /* write reset config */
522 if (res != 0) /* check result */
523 {
524 handle->debug_print("sgp41: write soft reset failed.\n"); /* write soft reset failed */
525
526 return 1; /* return error */
527 }
528 handle->delay_ms(5); /* delay 5ms */
529
530 return 0; /* success return 0 */
531}
532
544{
545 uint8_t res;
546
547 if (handle == NULL) /* check handle */
548 {
549 return 2; /* return error */
550 }
551 if (handle->inited != 1) /* check handle initialization */
552 {
553 return 3; /* return error */
554 }
555
556 res = a_sgp41_iic_write(handle, SGP41_COMMAND_TURN_HEATER_OFF, NULL, 0); /* write turn heater off command */
557 if (res != 0) /* check result */
558 {
559 handle->debug_print("sgp41: write turn heater off failed.\n"); /* write turn heater off failed */
560
561 return 1; /* return error */
562 }
563 handle->delay_ms(1); /* delay 1 ms */
564
565 return 0; /* success return 0 */
566}
567
579uint8_t sgp41_get_serial_id(sgp41_handle_t *handle, uint16_t id[3])
580{
581 uint8_t res;
582 uint8_t buf[9];
583
584 if (handle == NULL) /* check handle */
585 {
586 return 2; /* return error */
587 }
588 if (handle->inited != 1) /* check handle initialization */
589 {
590 return 3; /* return error */
591 }
592
593 memset(buf, 0, sizeof(uint8_t) * 9); /* clear the buffer */
594 res = a_sgp41_iic_read(handle, SGP41_COMMAND_GET_SERIAL_ID, (uint8_t *)buf, 9, 1); /* read config */
595 if (res != 0) /* check result */
596 {
597 handle->debug_print("sgp41: read serial id failed.\n"); /* read serial id failed */
598
599 return 1; /* return error */
600 }
601 if (buf[2] != a_sgp41_generate_crc((uint8_t *)&buf[0], 2)) /* check 1st crc */
602 {
603 handle->debug_print("sgp41: crc 1 check failed.\n"); /* crc 1 check failed */
604
605 return 1; /* return error */
606 }
607 if (buf[5] != a_sgp41_generate_crc((uint8_t *)&buf[3], 2)) /* check 2nd crc */
608 {
609 handle->debug_print("sgp41: crc 2 check failed.\n"); /* crc 2 check failed */
610
611 return 1; /* return error */
612 }
613 if (buf[8] != a_sgp41_generate_crc((uint8_t *)&buf[6], 2)) /* check 3rd crc */
614 {
615 handle->debug_print("sgp41: crc 3 check failed.\n"); /* crc 3 check failed */
616
617 return 1; /* return error */
618 }
619 id[0] = (uint16_t)((((uint16_t)buf[0]) << 8) | buf[1]); /* set id 0 */
620 id[1] = (uint16_t)((((uint16_t)buf[3]) << 8) | buf[4]); /* set id 1 */
621 id[2] = (uint16_t)((((uint16_t)buf[6]) << 8) | buf[7]); /* set id 2 */
622
623 return 0; /* success return 0 */
624}
625
637{
638 if (handle == NULL) /* check handle */
639 {
640 return 2; /* return error */
641 }
642 if (handle->debug_print == NULL) /* check debug_print */
643 {
644 return 3; /* return error */
645 }
646 if (handle->iic_init == NULL) /* check iic_init */
647 {
648 handle->debug_print("sgp41: iic_init is null.\n"); /* iic_init is null */
649
650 return 3; /* return error */
651 }
652 if (handle->iic_deinit == NULL) /* check iic_deinit */
653 {
654 handle->debug_print("sgp41: iic_deinit is null.\n"); /* iic_deinit is null */
655
656 return 3; /* return error */
657 }
658 if (handle->iic_write_cmd == NULL) /* check iic_write_cmd */
659 {
660 handle->debug_print("sgp41: iic_write_cmd is null.\n"); /* iic_write_cmd is null */
661
662 return 3; /* return error */
663 }
664 if (handle->iic_read_cmd == NULL) /* check iic_read_cmd */
665 {
666 handle->debug_print("sgp41: iic_read_cmd is null.\n"); /* iic_read_cmd is null */
667
668 return 3; /* return error */
669 }
670 if (handle->delay_ms == NULL) /* check delay_ms */
671 {
672 handle->debug_print("sgp41: delay_ms is null.\n"); /* delay_ms is null */
673
674 return 3; /* return error */
675 }
676
677 if (handle->iic_init() != 0) /* iic init */
678 {
679 handle->debug_print("sgp41: iic init failed.\n"); /* iic init failed */
680
681 return 3; /* return error */
682 }
683 handle->inited = 1; /* flag finish initialization */
684
685 return 0; /* success return 0 */
686}
687
700{
701 if (handle == NULL) /* check handle */
702 {
703 return 2; /* return error */
704 }
705 if (handle->inited != 1) /* check handle initialization */
706 {
707 return 3; /* return error */
708 }
709
710 if (sgp41_turn_heater_off(handle) != 0) /* turn heater off */
711 {
712 handle->debug_print("sgp41: turn heater off failed.\n"); /* turn heater off failed */
713
714 return 4; /* return error */
715 }
716 if (handle->iic_deinit() != 0) /* iic deinit */
717 {
718 handle->debug_print("sgp41: iic close failed.\n"); /* iic close failed */
719
720 return 3; /* return error */
721 }
722 handle->inited = 0; /* flag close initialization */
723
724 return 0; /* success return 0 */
725}
726
740uint8_t sgp41_set_reg(sgp41_handle_t *handle, uint16_t reg, uint8_t *buf, uint16_t len)
741{
742 if (handle == NULL) /* check handle */
743 {
744 return 2; /* return error */
745 }
746 if (handle->inited != 1) /* check handle initialization */
747 {
748 return 3; /* return error */
749 }
750
751 return a_sgp41_iic_write(handle, reg, buf, len); /* write data */
752}
753
767uint8_t sgp41_get_reg(sgp41_handle_t *handle, uint16_t reg, uint8_t *buf, uint16_t len)
768{
769 if (handle == NULL) /* check handle */
770 {
771 return 2; /* return error */
772 }
773 if (handle->inited != 1) /* check handle initialization */
774 {
775 return 3; /* return error */
776 }
777
778 return a_sgp41_iic_read(handle, reg, buf, len, 320); /* read data */
779}
780
790{
791 if (info == NULL) /* check handle */
792 {
793 return 2; /* return error */
794 }
795
796 memset(info, 0, sizeof(sgp41_info_t)); /* initialize sgp41 info structure */
797 strncpy(info->chip_name, CHIP_NAME, 32); /* copy chip name */
798 strncpy(info->manufacturer_name, MANUFACTURER_NAME, 32); /* copy manufacturer name */
799 strncpy(info->interface, "IIC", 8); /* copy interface name */
800 info->supply_voltage_min_v = SUPPLY_VOLTAGE_MIN; /* set minimal supply voltage */
801 info->supply_voltage_max_v = SUPPLY_VOLTAGE_MAX; /* set maximum supply voltage */
802 info->max_current_ma = MAX_CURRENT; /* set maximum current */
803 info->temperature_max = TEMPERATURE_MAX; /* set minimal temperature */
804 info->temperature_min = TEMPERATURE_MIN; /* set maximum temperature */
805 info->driver_version = DRIVER_VERSION; /* set driver version */
806
807 return 0; /* success return 0 */
808}
#define SGP41_CRC8_INIT
#define MAX_CURRENT
#define SGP41_COMMAND_TURN_HEATER_OFF
#define SGP41_CRC8_POLYNOMIAL
crc8 definition
#define SGP41_COMMAND_GET_SERIAL_ID
#define SUPPLY_VOLTAGE_MAX
#define TEMPERATURE_MAX
#define SGP41_COMMAND_EXECUTE_SELF_TEST
#define MANUFACTURER_NAME
#define TEMPERATURE_MIN
#define SUPPLY_VOLTAGE_MIN
#define CHIP_NAME
chip information definition
#define SGP41_COMMAND_MEASURE_RAW
#define SGP41_ADDRESS
chip address definition
#define DRIVER_VERSION
#define SGP41_COMMAND_EXECUTE_CONDITIONING
chip command definition
driver sgp41 header file
uint8_t sgp41_temperature_convert_to_register(sgp41_handle_t *handle, float temp, uint16_t *reg)
convert the temperature to the register data
uint8_t sgp41_get_measure_raw(sgp41_handle_t *handle, uint16_t raw_humidity, uint16_t raw_temperature, uint16_t *sraw_voc, uint16_t *sraw_nox)
get the measure raw result
uint8_t sgp41_get_execute_conditioning(sgp41_handle_t *handle, uint16_t *sraw_voc)
get execute conditioning
uint8_t sgp41_info(sgp41_info_t *info)
get chip information
uint8_t sgp41_deinit(sgp41_handle_t *handle)
close the chip
struct sgp41_info_s sgp41_info_t
sgp41 information structure definition
uint8_t sgp41_get_measure_test(sgp41_handle_t *handle, uint16_t *result)
get the chip measure test
uint8_t sgp41_turn_heater_off(sgp41_handle_t *handle)
turn heater off
uint8_t sgp41_soft_reset(sgp41_handle_t *handle)
soft reset the chip
struct sgp41_handle_s sgp41_handle_t
sgp41 handle structure definition
uint8_t sgp41_get_serial_id(sgp41_handle_t *handle, uint16_t id[3])
get the chip serial id
uint8_t sgp41_init(sgp41_handle_t *handle)
initialize the chip
uint8_t sgp41_get_measure_raw_without_compensation(sgp41_handle_t *handle, uint16_t *sraw_voc, uint16_t *sraw_nox)
get the measure raw result without compensation
uint8_t sgp41_humidity_convert_to_register(sgp41_handle_t *handle, float rh, uint16_t *reg)
convert the humidity to the register data
uint8_t sgp41_get_reg(sgp41_handle_t *handle, uint16_t reg, uint8_t *buf, uint16_t len)
get the chip register
uint8_t sgp41_set_reg(sgp41_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]