SensorLib 0.5.0
Multi-platform sensor driver library for Arduino, PlatformIO, and ESP-IDF
Loading...
Searching...
No Matches
SensorQMI8658.hpp
Go to the documentation of this file.
1
30#pragma once
31
32#include "SensorBuildOpt.h"
33#if !SENSORLIB_EXCLUDE_QMI8658
34
35#pragma message("Warning: Please replace with a new driver. Please refer to the examples/QMI8658 example. SensorQMI8658.hpp will be removed in the next version.")
36
38#include <math.h>
39
40static constexpr uint8_t QMI8658_L_SLAVE_ADDRESS = (0x6B);
41static constexpr uint8_t QMI8658_H_SLAVE_ADDRESS = (0x6A);
42
43typedef struct {
44 float x;
45 float y;
46 float z;
47} IMUdata;
48
50{
51public:
52 typedef void (*EventCallBack_t)(void);
53
55 ACC_RANGE_2G, // ±2g
56 ACC_RANGE_4G, // ±4g
57 ACC_RANGE_8G, // ±8g
58 ACC_RANGE_16G // ±16g
59 };
60
61 enum GyroRange {
62 GYR_RANGE_16DPS, // 16 degrees per second
63 GYR_RANGE_32DPS, // 32 degrees per second
64 GYR_RANGE_64DPS, // 64 degrees per second
65 GYR_RANGE_128DPS, // 128 degrees per second
66 GYR_RANGE_256DPS, // 256 degrees per second
67 GYR_RANGE_512DPS, // 512 degrees per second
68 GYR_RANGE_1024DPS, // 1024 degrees per second
69 };
70
71 // In 6DOF mode (accelerometer and gyroscope are both enabled),
72 // the output data rate is derived from the nature frequency of gyroscope
73 enum AccelODR {
74 ACC_ODR_1000Hz = 3, // 1000 Hz
75 ACC_ODR_500Hz, // 500 Hz
76 ACC_ODR_250Hz, // 250 Hz
77 ACC_ODR_125Hz, // 125 Hz
78 ACC_ODR_62_5Hz, // 62.5 Hz
79 ACC_ODR_31_25Hz, // 31.25 Hz
80 ACC_ODR_LOWPOWER_128Hz = 12, // The accelerometer low power mode is only available when the gyroscope is disabled
81 ACC_ODR_LOWPOWER_21Hz, // The accelerometer low power mode is only available when the gyroscope is disabled
82 ACC_ODR_LOWPOWER_11Hz, // The accelerometer low power mode is only available when the gyroscope is disabled
83 ACC_ODR_LOWPOWER_3Hz // The accelerometer low power mode is only available when the gyroscope is disabled
84 };
85
86 enum GyroODR {
87 GYR_ODR_7174_4Hz, // 7174.4 Hz
88 GYR_ODR_3587_2Hz, // 3587.2 Hz
89 GYR_ODR_1793_6Hz, // 1793.6 Hz
90 GYR_ODR_896_8Hz, // 896.8 Hz
91 GYR_ODR_448_4Hz, // 448.4 Hz
92 GYR_ODR_224_2Hz, // 224.2 Hz
93 GYR_ODR_112_1Hz, // 112.1 Hz
94 GYR_ODR_56_05Hz, // 56.05 Hz
95 GYR_ODR_28_025Hz // 28.025 Hz
96 };
97
98 enum TapEvent {
99 INVALID_TAP, // Invalid tap event
100 SINGLE_TAP, // Single tap event
101 DOUBLE_TAP, // Double tap event
102 };
103
104 //Low-Pass Filter.
105 enum LpfMode {
106 LPF_MODE_0, //2.66% of output data rate
107 LPF_MODE_1, //3.63% of output data rate
108 LPF_MODE_2, //5.39% of output data rate
109 LPF_MODE_3, //13.37% of output data rate
110 LPF_OFF, //OFF Low-Pass Filter
111 };
112
114 MOTION_TAP, // Tap motion detected
115 MOTION_ANT_MOTION, // Any motion detected
116 MOTION_NO_MOTION, // No motion detected
117 MOTION_SIGNIFICANT, // Significant motion detected
118 MOTION_PEDOMETER, // Pedometer motion detected
119 };
120
121 enum IntPin {
122 INTERRUPT_PIN_1, // Interrupt pin 1
123 INTERRUPT_PIN_2, // Interrupt pin 2
124 INTERRUPT_PIN_DISABLE // Disable interrupt
125 };
126
128 FIFO_SAMPLES_16, // Configure the FIFO watermark level to 16 samples.
129 FIFO_SAMPLES_32, // Configure the FIFO watermark level to 32 samples.
130 FIFO_SAMPLES_64, // Configure the FIFO watermark level to 64 samples.
131 FIFO_SAMPLES_128, // Configure the FIFO watermark level to 128 samples.
132 };
133
135 // Configure the FIFO_MODE to Bypass (0) mode, will disable the FIFO functionality.
137 // In FIFO mode, once FIFO is full,
138 // the data filling will stop and new data will be discarded until host reads out the FIFO data and release the space for new data to be written to.
140 // In Stream mode, once FIFO is full,
141 // the data filling will continue and the oldest data will be discarded,
142 // until host reads out the FIFO data and release the space for new data to be written to
144 };
145
147 SYNC_MODE, //Synchronous sampling
148 ASYNC_MODE, //Asynchronous sampling
149 };
150
168
177
179 STATUS_INT_CTRL9_CMD_DONE = 0x0001, // bit 0
180 STATUS_INT_LOCKED = 0x0002, // bit 1
181 STATUS_INT_AVAIL = 0x0004, // bit 2
182 STATUS0_GYRO_DATA_READY = 0x0008, // bit 3
183 STATUS0_ACCEL_DATA_READY = 0x0010, // bit 4
184 STATUS1_SIGNIFICANT_MOTION = 0x0020, // bit 5
185 STATUS1_NO_MOTION = 0x0040, // bit 6
186 STATUS1_ANY_MOTION = 0x0080, // bit 7
187 STATUS1_PEDOMETER_MOTION = 0x0100, // bit 8
188 STATUS1_WOM_MOTION = 0x0200, // bit 9
189 STATUS1_TAP_MOTION = 0x0400, // bit 10
190 };
191
193 PRIORITY0, // (X > Y> Z)
194 PRIORITY1, // (X > Z > Y)
195 PRIORITY2, // (Y > X > Z)
196 PRIORITY3, // (Y > Z > X)
197 PRIORITY4, // (Z > X > Y)
198 PRIORITY5, // (Z > Y > X)
199 };
200
202
206
207 //Logic-AND between events of enabled axes for No-Motion detection, Otherwise, logical OR
209
213
214 //Logic-AND between events of enabled axes for No-Motion detection , Otherwise, logical OR
216 };
217
223 SensorQMI8658() = default;
224
231 {
232 if (fifo_buffer) {
233 free(fifo_buffer);
234 fifo_buffer = NULL;
235 }
236 }
237
244 void setPins(int _irq)
245 {
246 this->_irq = _irq;
247 }
248
256 bool reset(bool waitResult = true, uint32_t timeout = 500)
257 {
258 int val = 0; // initialize with some value to avoid compilation errors
260 // Maximum 15ms for the Reset process to be finished
261 if (waitResult) {
262 uint32_t start = hal->millis();
263 while (hal->millis() - start < timeout) {
264 val = comm->readRegister(QMI8658_REG_RST_RESULT);
265 if (val != -1 && val == QMI8658_REG_RST_RESULT_VAL) {
266
267 //EN.ADDR_AI
268 comm->setRegisterBit(QMI8658_REG_CTRL1, 6);
269
270 return true;
271 }
272 hal->delay(10);
273 }
274 SENSORLIB_LOG_E("Reset chip failed, Response val = %d - 0x%X", val, val);
275 return false;
276 }
277
278 //EN.ADDR_AI
279 comm->setRegisterBit(QMI8658_REG_CTRL1, 6);
280
281 return true;
282 }
283
288 uint8_t getChipID()
289 {
290 return comm->readRegister(QMI8658_REG_REVISION);
291 }
292
298 int whoAmI()
299 {
300 return comm->readRegister(QMI8658_REG_WHOAMI);
301 }
302
308 uint32_t getTimestamp()
309 {
310 uint8_t buffer[3];
311 uint32_t timestamp;
312 if (comm->readRegister(QMI8658_REG_TIMESTAMP_L, buffer, 3) != -1) {
313 timestamp = (uint32_t)(((uint32_t)buffer[2] << 16) |
314 ((uint32_t)buffer[1] << 8) | buffer[0]);
315 if (timestamp > lastTimestamp) {
316 lastTimestamp = timestamp;
317 } else {
318 lastTimestamp = (timestamp + 0x1000000 - lastTimestamp);
319 }
320 }
321 return lastTimestamp;
322 }
323
329 {
330 uint8_t buffer[2];
331 if (comm->readRegister(QMI8658_REG_TEMPERATURE_L, buffer, 2) != -1) {
332 return (float)buffer[1] + ((float)buffer[0] / 256.0);
333 }
334 return NAN;
335 }
336
342 void enableINT(IntPin pin, bool enable = true)
343 {
344 switch (pin) {
345 case INTERRUPT_PIN_1:
346 enable ? comm->setRegisterBit(QMI8658_REG_CTRL1, 3) : comm->clrRegisterBit(QMI8658_REG_CTRL1, 3);
347 _irq_enable_mask = enable ? _irq_enable_mask | 0x01 : _irq_enable_mask & 0xFE;
348 break;
349 case INTERRUPT_PIN_2:
350 enable ? comm->setRegisterBit(QMI8658_REG_CTRL1, 4) : comm->clrRegisterBit(QMI8658_REG_CTRL1, 4);
351 _irq_enable_mask = enable ? _irq_enable_mask | 0x02 : _irq_enable_mask & 0xFD;
352 break;
353 default:
354 break;
355 }
356 }
357
363 uint8_t getIrqStatus()
364 {
365 return comm->readRegister(QMI8658_REG_STATUS_INT);
366 }
367
372 void enableDataReadyINT(bool enable = true)
373 {
374 enable ? comm->clrRegisterBit(QMI8658_REG_CTRL7, 5) :
375 comm->setRegisterBit(QMI8658_REG_CTRL7, 5);
376 }
377
386 {
387 bool en = isEnableAccelerometer();
388
389 if (en) {
391 }
392
393 //setAccelRange
394 if (comm->writeRegister(QMI8658_REG_CTRL2, 0x8F, (range << 4)) != 0) {
395 return false;
396 }
397
398 switch (range) {
399 // Possible accelerometer scales (and their register bit settings) are:
400 // 2 Gs (00), 4 Gs (01), 8 Gs (10), and 16 Gs (11).
401 // Here's a bit of an algorithm to calculate DPS/(ADC tick) based on that
402 // 2-bit value:
403 case ACC_RANGE_2G:
404 accelScales = 2.0 / 32768.0;
405 break;
406 case ACC_RANGE_4G:
407 accelScales = 4.0 / 32768.0;
408 break;
409 case ACC_RANGE_8G:
410 accelScales = 8.0 / 32768.0;
411 break;
412 case ACC_RANGE_16G:
413 accelScales = 16.0 / 32768.0;
414 break;
415 }
416
417 // setAccelOutputDataRate
418 if (comm->writeRegister(QMI8658_REG_CTRL2, 0xF0, odr) != 0) {
419 return false;
420 }
421
422 if (lpfOdr != LPF_OFF) {
423 // setAccelLowPassFitterOdr
424 if (comm->writeRegister(QMI8658_REG_CTRL5, QMI8658_ACCEL_LPF_MASK, (lpfOdr << 1)) != 0) {
425 return false;
426 }
427 // Enable Low-Pass Fitter
428 comm->setRegisterBit(QMI8658_REG_CTRL5, 0);
429 } else {
430 // Disable Low-Pass Fitter
431 comm->clrRegisterBit(QMI8658_REG_CTRL5, 0);
432 }
433
434 // setAccelSelfTest
435 // selfTest ? comm->setRegisterBit(QMI8658_REG_CTRL2, 7) : comm->clrRegisterBit(QMI8658_REG_CTRL2, 7);
436
437 if (en) {
439 }
440
441 return true;
442 }
443
444
454 {
455 bool en = isEnableGyroscope();
456
457 if (en) {
459 }
460
461 // setGyroRange
462 if (comm->writeRegister(QMI8658_REG_CTRL3, 0x8F, (range << 4)) != 0) {
463 return false;
464 }
465
466 switch (range) {
467 // Possible gyro scales (and their register bit settings) are:
468 // 250 DPS (00), 500 DPS (01), 1000 DPS (10), and 2000 DPS (11).
469 // Here's a bit of an algorithm to calculate DPS/(ADC tick) based on that
470 // 2-bit value:
471 case GYR_RANGE_16DPS:
472 gyroScales = 16.0 / 32768.0;
473 break;
474 case GYR_RANGE_32DPS:
475 gyroScales = 32.0 / 32768.0;
476 break;
477 case GYR_RANGE_64DPS:
478 gyroScales = 64.0 / 32768.0;
479 break;
480 case GYR_RANGE_128DPS:
481 gyroScales = 128.0 / 32768.0;
482 break;
483 case GYR_RANGE_256DPS:
484 gyroScales = 256.0 / 32768.0;
485 break;
486 case GYR_RANGE_512DPS:
487 gyroScales = 512.0 / 32768.0;
488 break;
490 gyroScales = 1024.0 / 32768.0;
491 break;
492 }
493
494 // setGyroOutputDataRate
495 if (comm->writeRegister(QMI8658_REG_CTRL3, 0xF0, odr) != 0) {
496 return false;
497 }
498
499 // setGyroLowPassFitterOdr
500 if (lpfOdr != LPF_OFF) {
501 if (comm->writeRegister(QMI8658_REG_CTRL5, QMI8658_GYRO_LPF_MASK, (lpfOdr << 5)) != 0) {
502 return false;
503 }
504 // Enable Low-Pass Fitter
505 comm->setRegisterBit(QMI8658_REG_CTRL5, 4);
506 } else {
507 // Disable Low-Pass Fitter
508 comm->clrRegisterBit(QMI8658_REG_CTRL5, 4);
509 }
510
511 // setGyroSelfTest
512 // selfTest ? comm->setRegisterBit(QMI8658_REG_CTRL3, 7) : comm->clrRegisterBit(QMI8658_REG_CTRL3, 7);
513
514 if (en) {
516 }
517
518 return true;
519 }
520
531 IntPin pin = INTERRUPT_PIN_DISABLE, uint8_t trigger_samples = 16)
532 {
533 bool enGyro = isEnableGyroscope();
534 bool enAccel = isEnableAccelerometer();
535
536 if (enGyro) {
538 }
539
540 if (enAccel) {
542 }
543
544 // Reset FIFO configure
546 SENSORLIB_LOG_E("Reset fifo failed!");
547 return false;
548 }
549
550 _fifo_interrupt = true;
551
552 switch (pin) {
553 case INTERRUPT_PIN_1:
554 comm->setRegisterBit(QMI8658_REG_CTRL1, 2);
555 break;
556 case INTERRUPT_PIN_2:
557 comm->clrRegisterBit(QMI8658_REG_CTRL1, 2);
558 break;
560 // Saves whether the fifo interrupt pin is enabled
561 _fifo_interrupt = false;
562 break;
563 default:
564 break;
565 }
566
567 // Set fifo mode and samples len
568 _fifo_mode = (samples << 2) | mode;
569 if (comm->writeRegister(QMI8658_REG_FIFO_CTRL, _fifo_mode) == -1) {
570 return false;
571 }
572
573 /*
574 * The FIFO_WTM register(0x13) indicates the expected level of FIFO data that host wants to get the FIFO Watermark interrupt.
575 * The unit is sample, which means 6 bytes if one of accelerometer and gyroscope is enabled, and 12 bytes if both are enabled.
576 * */
577 if (comm->writeRegister(QMI8658_REG_FIFO_WTM_TH, trigger_samples ) == -1) {
578 return false;
579 }
580
581 if (enGyro) {
583 }
584
585 if (enAccel) {
587 }
588
589 int res = comm->readRegister(QMI8658_REG_FIFO_CTRL);
590 SENSORLIB_LOG_D("QMI8658_REG_FIFO_CTRL : 0x%X", res);
591 if ((res & 0x02) == 0x02) {
592 SENSORLIB_LOG_D("Enabled Stream mode.");
593 } else if ((res & 0x01) == 0x01) {
594 SENSORLIB_LOG_D("Enabled FIFO mode.");
595 } else if ((res & 0x03) == 0x00) {
596 SENSORLIB_LOG_D("Disabled FIFO.");
597 }
598 res >>= 2;
599 if ((res & 0x03) == 0x03) {
600 SENSORLIB_LOG_D("128 samples.");
601 } else if ((res & 0x02) == 0x02) {
602 SENSORLIB_LOG_D("64 samples.");
603 } else if ((res & 0x01) == 0x01) {
604 SENSORLIB_LOG_D("32 samples.");
605 } else if ((res & 0x03) == 0x00) {
606 SENSORLIB_LOG_D("16 samples.");
607 }
608
609 return true;
610 }
611
621 uint16_t readFromFifo(IMUdata *acc, uint16_t accLength, IMUdata *gyro, uint16_t gyrLength)
622 {
624 SENSORLIB_LOG_E("FIFO is not configured.");
625 return 0;
626 }
627
628 if (!_gyro_enabled && !_accel_enabled) {
629 SENSORLIB_LOG_E("Sensor not enabled.");
630 return 0;
631 }
632
633 uint16_t data_bytes = readFromFifo();
634 if (data_bytes == 0) {
635 return 0;
636 }
637
638 if (!fifo_buffer) {
639 SENSORLIB_LOG_E("FIFO buffer is NULL");
640 return 0;
641 }
642
643 uint8_t enabled_sensor_count = (_accel_enabled && _gyro_enabled) ? 2 : 1;
644 uint16_t samples_per_sensor = data_bytes / (6 * enabled_sensor_count);
645 uint16_t total_samples = samples_per_sensor * enabled_sensor_count;
646
647 SENSORLIB_LOG_D("Total samples: %u", total_samples);
648
649 uint16_t accel_index = 0;
650 uint16_t gyro_index = 0;
651
652 for (uint16_t i = 0; i < total_samples; ++i) {
653 auto data = reinterpret_cast < int16_t * > (&fifo_buffer[i * 6]);
654 int16_t x = data[0];
655 int16_t y = data[1];
656 int16_t z = data[2];
657
659 if (i % 2 == 0) {
660 // Accel
661 if (accel_index < accLength) {
662 acc[accel_index].x = x * accelScales;
663 acc[accel_index].y = y * accelScales;
664 acc[accel_index].z = z * accelScales;
665 accel_index++;
666 }
667 } else {
668 // Gyro
669 if (gyro_index < gyrLength) {
670 gyro[gyro_index].x = x * gyroScales;
671 gyro[gyro_index].y = y * gyroScales;
672 gyro[gyro_index].z = z * gyroScales;
673 gyro_index++;
674 }
675 }
676 } else if (_accel_enabled) {
677 if (accel_index < accLength) {
678 acc[accel_index].x = x * accelScales;
679 acc[accel_index].y = y * accelScales;
680 acc[accel_index].z = z * accelScales;
681 accel_index++;
682 }
683 } else if (_gyro_enabled) {
684 if (gyro_index < gyrLength) {
685 gyro[gyro_index].x = x * gyroScales;
686 gyro[gyro_index].y = y * gyroScales;
687 gyro[gyro_index].z = z * gyroScales;
688 gyro_index++;
689 }
690 }
691 }
692 return samples_per_sensor;
693 }
694
701 {
702 if (comm->setRegisterBit(QMI8658_REG_CTRL7, 0)) {
703 _accel_enabled = true;
704 }
705 return _accel_enabled;
706 }
707
714 {
715 if (comm->clrRegisterBit(QMI8658_REG_CTRL7, 0)) {
716 _accel_enabled = false;
717 return true;
718 }
719 return false;
720 }
721
728 {
729 return _accel_enabled;
730 }
731
738 {
739 return _gyro_enabled;
740 }
741
748 {
749 if (comm->setRegisterBit(QMI8658_REG_CTRL7, 1)) {
750 _gyro_enabled = true;
751 }
752 return _gyro_enabled;
753 }
754
761 {
762 if (comm->clrRegisterBit(QMI8658_REG_CTRL7, 1)) {
763 _gyro_enabled = false;
764 return true;
765 }
766 return false;
767 }
768
775 bool getAccelRaw(int16_t *rawBuffer)
776 {
777 if (!_accel_enabled) {
778 return false;
779 }
780 uint8_t buffer[6] = {0};
781 if (comm->readRegister(QMI8658_REG_AX_L, buffer, 6) != -1) {
782 rawBuffer[0] = (int16_t)(buffer[1] << 8) | (buffer[0]);
783 rawBuffer[1] = (int16_t)(buffer[3] << 8) | (buffer[2]);
784 rawBuffer[2] = (int16_t)(buffer[5] << 8) | (buffer[4]);
785 } else {
786 return false;
787 }
788 return true;
789 }
790
799 bool getAccelerometer(float &x, float &y, float &z)
800 {
801 if (!_accel_enabled) {
802 return false;
803 }
804 int16_t raw[3];
805 if (getAccelRaw(raw)) {
806 x = raw[0] * accelScales;
807 y = raw[1] * accelScales;
808 z = raw[2] * accelScales;
809 return true;
810 }
811 return false;
812 }
813
820 {
821 return accelScales;
822 }
823
830 {
831 return gyroScales;
832 }
833
840 bool getGyroRaw(int16_t *rawBuffer)
841 {
842 if (!_gyro_enabled) {
843 return false;
844 }
845 uint8_t buffer[6] = {0};
846 if (comm->readRegister(QMI8658_REG_GX_L, buffer, 6) != -1) {
847 rawBuffer[0] = (int16_t)(buffer[1] << 8) | (buffer[0]);
848 rawBuffer[1] = (int16_t)(buffer[3] << 8) | (buffer[2]);
849 rawBuffer[2] = (int16_t)(buffer[5] << 8) | (buffer[4]);
850 } else {
851 return false;
852 }
853 return true;
854 }
855
864 bool getGyroscope(float &x, float &y, float &z)
865 {
866 if (!_gyro_enabled) {
867 return false;
868 }
869 int16_t raw[3];
870 if (getGyroRaw(raw)) {
871 x = raw[0] * gyroScales;
872 y = raw[1] * gyroScales;
873 z = raw[2] * gyroScales;
874 return true;
875 }
876 return false;
877 }
878
885 {
886 if ((_irq_enable_mask & 0x03) && (_irq != -1)) {
887 if (hal->digitalRead(_irq)) {
888 return false;
889 }
890 }
891
892 switch (sampleMode) {
893 case SYNC_MODE:
894 return comm->getRegisterBit(QMI8658_REG_STATUS_INT, 1);
895 case ASYNC_MODE:
896 //TODO: When Accel and Gyro are configured with different rates, this will always be false
898 return comm->readRegister(QMI8658_REG_STATUS0) & 0x03;
899 } else if (_gyro_enabled) {
900 return comm->readRegister(QMI8658_REG_STATUS0) & 0x02;
901 } else if (_accel_enabled) {
902 return comm->readRegister(QMI8658_REG_STATUS0) & 0x01;
903 }
904 break;
905 default:
906 break;
907 }
908 return false;
909 }
910
917 {
918 sampleMode = SYNC_MODE;
919 return comm->setRegisterBit(QMI8658_REG_CTRL7, 7);
920 }
921
928 {
929 sampleMode = ASYNC_MODE;
930 return comm->clrRegisterBit(QMI8658_REG_CTRL7, 7);
931 }
932
939 {
941 if (comm->writeRegister(QMI8658_REG_CAL1_L, 0x01) != 0) {
942 return false;
943 }
945 }
946
953 {
955 if (comm->writeRegister(QMI8658_REG_CAL1_L, (uint8_t)0x00) != 0) {
956 return -1;
957 }
959 }
960
967 {
968 uint8_t buffer[9];
969 comm->readRegister(QMI8658_REG_CTRL1, buffer, 9);
970 for (int i = 0; i < 9; ++i) {
971 SENSORLIB_LOG_D("CTRL%d: REG:0x%02X HEX:0x%02X\n", i + 1, QMI8658_REG_CTRL1 + i, buffer[i]);
972 }
973
974 buffer[0] = comm->readRegister(QMI8658_REG_FIFO_CTRL);
975 SENSORLIB_LOG_D("FIFO_CTRL: REG:0x%02X HEX:0x%02X\n", QMI8658_REG_FIFO_CTRL, buffer[0]);
976 }
977
984 {
987 comm->setRegisterBit(QMI8658_REG_CTRL1, 1);
988 }
989
990
996 void powerOn()
997 {
998 comm->clrRegisterBit(QMI8658_REG_CTRL1, 1);
999 }
1000
1007 {
1008 return comm->readRegister(QMI8658_REG_STATUS1);
1009 }
1010
1017 {
1018 return pin == INTERRUPT_PIN_1 ? comm->setRegisterBit(QMI8658_REG_CTRL8, 6)
1019 : comm->clrRegisterBit(QMI8658_REG_CTRL8, 6);
1020 }
1021
1050 bool configPedometer(uint16_t ped_sample_cnt, uint16_t ped_fix_peak2peak, uint16_t ped_fix_peak,
1051 uint16_t ped_time_up, uint8_t ped_time_low = 0x14, uint8_t ped_time_cnt_entry = 0x0A, uint8_t ped_fix_precision = 0x00,
1052 uint8_t ped_sig_count = 0x04)
1053 {
1054 // The Pedometer can only work in Non-SyncSample mode
1056
1057 bool enGyro = isEnableGyroscope();
1058 bool enAccel = isEnableAccelerometer();
1059
1060 if (enGyro) {
1062 }
1063
1064 if (enAccel) {
1066 }
1067
1068 comm->writeRegister(QMI8658_REG_CAL1_L, ped_sample_cnt & 0xFF);
1069 comm->writeRegister(QMI8658_REG_CAL1_H, (ped_sample_cnt >> 8) & 0xFF);
1070 comm->writeRegister(QMI8658_REG_CAL2_L, ped_fix_peak2peak & 0xFF);
1071 comm->writeRegister(QMI8658_REG_CAL2_H, (ped_fix_peak2peak >> 8) & 0xFF);
1072 comm->writeRegister(QMI8658_REG_CAL3_L, ped_fix_peak & 0xFF);
1073 comm->writeRegister(QMI8658_REG_CAL3_H, (ped_fix_peak >> 8) & 0xFF);
1074 comm->writeRegister(QMI8658_REG_CAL4_H, 0x01);
1075 comm->writeRegister(QMI8658_REG_CAL4_L, 0x02);
1076
1078
1079 comm->writeRegister(QMI8658_REG_CAL1_L, ped_time_up & 0xFF);
1080 comm->writeRegister(QMI8658_REG_CAL1_H, (ped_time_up >> 8) & 0xFF);
1081 comm->writeRegister(QMI8658_REG_CAL2_L, ped_time_low);
1082 comm->writeRegister(QMI8658_REG_CAL2_H, ped_time_cnt_entry);
1083 comm->writeRegister(QMI8658_REG_CAL3_L, ped_fix_precision);
1084 comm->writeRegister(QMI8658_REG_CAL3_H, ped_sig_count);
1085 comm->writeRegister(QMI8658_REG_CAL4_H, 0x02);
1086 comm->writeRegister(QMI8658_REG_CAL4_L, 0x02);
1087
1089
1090 if (enGyro) {
1092 }
1093
1094 if (enAccel) {
1096 }
1097 return true;
1098 }
1099
1106 {
1107 uint8_t buffer[3];
1108 if (comm->readRegister(QMI8658_REG_STEP_CNT_LOW, buffer, 3) != -1) {
1109 return (uint32_t)(((uint32_t)buffer[2] << 16) | ((uint32_t)buffer[1] << 8) | buffer[0]);
1110 }
1111 return 0;
1112 }
1113
1120 {
1122 }
1123
1131 {
1132 if (!_accel_enabled)return false;
1133
1134 switch (pin) {
1135 case INTERRUPT_PIN_1:
1136 case INTERRUPT_PIN_2:
1138 enableINT(pin);
1139 break;
1140 default:
1141 break;
1142 }
1143 return comm->setRegisterBit(QMI8658_REG_CTRL8, 4);
1144 }
1145
1147 {
1148 if (!_accel_enabled)return false;
1149 return comm->clrRegisterBit(QMI8658_REG_CTRL8, 4);
1150 }
1151
1152
1153
1185 bool configTap(uint8_t priority, uint8_t peakWindow, uint16_t tapWindow, uint16_t dTapWindow,
1186 float alpha, float gamma, float peakMagThr, float UDMThr)
1187 {
1188
1189 // The Tap detection can only work in Non-SyncSample mode
1190 if (!disableSyncSampleMode()) {
1191 return false;
1192 }
1193
1194 bool enGyro = isEnableGyroscope();
1195 bool enAccel = isEnableAccelerometer();
1196
1197 if (enGyro) {
1199 }
1200
1201 if (enAccel) {
1203 }
1204 comm->writeRegister(QMI8658_REG_CAL1_L, peakWindow);
1205 comm->writeRegister(QMI8658_REG_CAL1_H, priority);
1206 comm->writeRegister(QMI8658_REG_CAL2_L, tapWindow & 0xFF);
1207 comm->writeRegister(QMI8658_REG_CAL2_H, (tapWindow >> 8) & 0xFF);
1208 comm->writeRegister(QMI8658_REG_CAL3_L, dTapWindow & 0xFF);
1209 comm->writeRegister(QMI8658_REG_CAL3_H, (dTapWindow >> 8) & 0xFF);
1210 // comm->writeRegister(QMI8658_REG_CAL4_L, 0x02);
1211 comm->writeRegister(QMI8658_REG_CAL4_H, 0x01);
1212
1214
1215 // 1-byte unsigned,7-bits fraction
1216 uint8_t alphaHex = (uint8_t)(alpha * 128);
1217 comm->writeRegister(QMI8658_REG_CAL1_L, alphaHex);
1218
1219 // 1-byte unsigned,7-bits fraction
1220 uint8_t gammaHex = (uint8_t)(gamma * 128);
1221 comm->writeRegister(QMI8658_REG_CAL1_H, gammaHex);
1222
1223 const double g = 9.81; // Earth's gravitational acceleration m/s^2
1224 double resolution = 0.001 * g * g; // Calculation resolution 0.001g^2
1225
1226 double acceleration_square = peakMagThr * g * g; // Calculate the square of the acceleration
1227 uint16_t value = (uint16_t)(acceleration_square / resolution); // Calculates the value of a 2-byte unsigned integer
1228
1229 comm->writeRegister(QMI8658_REG_CAL2_L, sensorlib::_lowByte(value));
1230 comm->writeRegister(QMI8658_REG_CAL2_H, sensorlib::_highByte(value));
1231
1232 acceleration_square = UDMThr * g * g; // Calculate the square of the acceleration
1233 value = (uint16_t)(acceleration_square / resolution); // Calculates the value of a 2-byte unsigned integer
1234
1235 comm->writeRegister(QMI8658_REG_CAL3_L, sensorlib::_lowByte(value));
1236 comm->writeRegister(QMI8658_REG_CAL3_H, sensorlib::_highByte(value));
1237 // comm->writeRegister(QMI8658_REG_CAL4_L, 0x02);
1238 comm->writeRegister(QMI8658_REG_CAL4_H, 0x02);
1239
1241
1242 if (enGyro) {
1244 }
1245
1246 if (enAccel) {
1248 }
1249
1250 return true;
1251 }
1252
1260 {
1261 if (!_accel_enabled)return false;
1262 switch (pin) {
1263 case INTERRUPT_PIN_1:
1264 case INTERRUPT_PIN_2:
1266 enableINT(pin);
1267 break;
1268 default:
1269 break;
1270 }
1271 return comm->setRegisterBit(QMI8658_REG_CTRL8, 0);
1272 }
1273
1280 {
1281 return comm->clrRegisterBit(QMI8658_REG_CTRL8, 0);
1282 }
1283
1290 {
1291 int val = comm->readRegister(QMI8658_REG_TAP_STATUS);
1292 if (val & sensorlib::_bv(7)) {
1293 SENSORLIB_LOG_I("Tap was detected on the negative direction of the Tap axis");
1294 } else {
1295 SENSORLIB_LOG_I("Tap was detected on the positive direction of the Tap axis");
1296 }
1297 uint8_t t = (val >> 4) & 0x03;
1298 switch (t) {
1299 case 0:
1300 SENSORLIB_LOG_I("No Tap was detected");
1301 break;
1302 case 1:
1303 SENSORLIB_LOG_I("Tap was detected on X axis");
1304 break;
1305 case 2:
1306 SENSORLIB_LOG_I("Tap was detected on Y axis");
1307 break;
1308 case 3:
1309 SENSORLIB_LOG_I("Tap was detected on Z axis");
1310 break;
1311 default:
1312 break;
1313 }
1314 t = val & 0x03;
1315 switch (t) {
1316 case 0:
1317 SENSORLIB_LOG_I("No Tap was detected");
1318 return INVALID_TAP;
1319 case 1:
1320 SENSORLIB_LOG_I("Single-Tap was detected");
1321 return SINGLE_TAP;
1322 case 2:
1323 SENSORLIB_LOG_I("Double-Tap was detected");
1324 return DOUBLE_TAP;
1325 default:
1326 break;
1327 }
1328 return INVALID_TAP;
1329 }
1330
1331
1332 //TODO:Need Test
1334 //* See enum MotionCtrl
1335 uint8_t modeCtrl,
1336 //* Define the slope threshold of the x-axis for arbitrary motion detection
1337 float AnyMotionXThr,
1338 //* Define the slope threshold of the y-axis for arbitrary motion detection
1339 float AnyMotionYThr,
1340 //* Define the slope threshold of the z-axis for arbitrary motion detection
1341 float AnyMotionZThr,
1342 //* Defines the minimum number of consecutive samples (duration) that the absolute
1343 //* of the slope of the enabled axis/axes data should keep higher than the threshold
1344 uint8_t AnyMotionWindow,
1345 //* Defines the slope threshold of the x-axis for no motion detection
1346 float NoMotionXThr,
1347 //* Defines the slope threshold of the y-axis for no motion detection
1348 float NoMotionYThr,
1349 //* Defines the slope threshold of the z-axis for no motion detection
1350 float NoMotionZThr,
1351 //* Defines the minimum number of consecutive samples (duration) that the absolute
1352 //* of the slope of the enabled axis/axes data should keep lower than the threshold
1353 uint8_t NoMotionWindow,
1354 //* Defines the wait window (idle time) starts from the first Any-Motion event until
1355 //* starting to detecting another Any-Motion event form confirmation
1356 uint16_t SigMotionWaitWindow,
1357 //* Defines the maximum duration for detecting the other Any-Motion
1358 //* event to confirm Significant-Motion, starts from the first Any -Motion event
1359 uint16_t SigMotionConfirmWindow)
1360 {
1361 // Only work in Non-SyncSample mode
1362 if (!disableSyncSampleMode()) {
1363 return false;
1364 }
1365
1366 bool enGyro = isEnableGyroscope();
1367 bool enAccel = isEnableAccelerometer();
1368
1369 if (enGyro) {
1371 }
1372
1373 if (enAccel) {
1375 }
1376
1377 comm->writeRegister(QMI8658_REG_CAL1_L, mgToBytes(AnyMotionXThr));
1378 comm->writeRegister(QMI8658_REG_CAL1_H, mgToBytes(AnyMotionYThr));
1379 comm->writeRegister(QMI8658_REG_CAL2_L, mgToBytes(AnyMotionZThr));
1380 comm->writeRegister(QMI8658_REG_CAL2_H, mgToBytes(NoMotionXThr));
1381 comm->writeRegister(QMI8658_REG_CAL3_L, mgToBytes(NoMotionYThr));
1382 comm->writeRegister(QMI8658_REG_CAL3_H, mgToBytes(NoMotionZThr));
1383 comm->writeRegister(QMI8658_REG_CAL4_L, modeCtrl);
1384 comm->writeRegister(QMI8658_REG_CAL4_H, 0x01);
1385
1387
1388 comm->writeRegister(QMI8658_REG_CAL1_L, AnyMotionWindow);
1389 comm->writeRegister(QMI8658_REG_CAL1_H, NoMotionWindow);
1390 comm->writeRegister(QMI8658_REG_CAL2_L, sensorlib::_lowByte(SigMotionWaitWindow));
1391 comm->writeRegister(QMI8658_REG_CAL2_H, sensorlib::_highByte(SigMotionWaitWindow));
1392 comm->writeRegister(QMI8658_REG_CAL3_L, sensorlib::_lowByte(SigMotionConfirmWindow));
1393 comm->writeRegister(QMI8658_REG_CAL3_H, sensorlib::_highByte(SigMotionConfirmWindow));
1394 // comm->writeRegister(QMI8658_REG_CAL4_L, 0x02);
1395 comm->writeRegister(QMI8658_REG_CAL4_H, 0x02);
1396
1398
1399 if (enGyro) {
1401 }
1402
1403 if (enAccel) {
1405 }
1406 return true;
1407 }
1408
1416 {
1417 if (!_accel_enabled)return false;
1418 switch (pin) {
1419 case INTERRUPT_PIN_1:
1420 case INTERRUPT_PIN_2:
1422 enableINT(pin);
1423 break;
1424 default:
1425 break;
1426 }
1427 comm->setRegisterBit(QMI8658_REG_CTRL8, 1);
1428 comm->setRegisterBit(QMI8658_REG_CTRL8, 2);
1429 comm->setRegisterBit(QMI8658_REG_CTRL8, 3);
1430 return true;
1431 }
1432
1439 {
1440 comm->clrRegisterBit(QMI8658_REG_CTRL8, 1);
1441 comm->clrRegisterBit(QMI8658_REG_CTRL8, 2);
1442 comm->clrRegisterBit(QMI8658_REG_CTRL8, 3);
1443 return false;
1444 }
1445
1446
1465 bool configWakeOnMotion(uint8_t WoMThreshold = 200,
1467 IntPin pin = INTERRUPT_PIN_2,
1468 uint8_t defaultPinValue = 1,
1469 uint8_t blankingTime = 0x20,
1470 AccelRange accRange = ACC_RANGE_8G)
1471 {
1472
1473 uint8_t val = 0;
1474
1475 // Reset default value
1476 if (!reset()) {
1477 return false;
1478 }
1479
1480 // Disable sensors
1481 comm->clrRegisterBit(QMI8658_REG_CTRL7, 0);
1482
1483 // SetAccelRange
1484 if (comm->writeRegister(QMI8658_REG_CTRL2, 0x8F, (accRange << 4)) != 0) {
1485 return false;
1486 }
1487
1488 // setAccelOutputDataRate
1489 if (comm->writeRegister(QMI8658_REG_CTRL2, 0xF0, odr) != 0) {
1490 return false;
1491 }
1492
1493 // Set wom
1494 if (comm->writeRegister(QMI8658_REG_CAL1_L, WoMThreshold) != 0) {
1495 return false;
1496 }
1497
1498 if ( pin == INTERRUPT_PIN_1) {
1499 val = defaultPinValue ? 0x02 : 0x00;
1500 } else if (pin == INTERRUPT_PIN_2) {
1501 val = defaultPinValue ? 0x03 : 0x01;
1502 }
1503
1504 val <<= 6;
1505 val |= (blankingTime & 0x3F);
1506 if (comm->writeRegister(QMI8658_REG_CAL1_H, val) != 0) {
1507 return false;
1508 }
1509
1511 return false;
1512 }
1513
1515
1516 enableINT(pin);
1517
1518 return true;
1519 }
1520
1521
1528 void getChipUsid(uint8_t *buffer, uint8_t length)
1529 {
1530 if (length > 6) {
1531 length = 6;
1532 }
1533 memcpy(buffer, usid, length);
1534 }
1535
1536
1543 {
1544 return revisionID;
1545 }
1546
1552 uint16_t update()
1553 {
1554 uint16_t result = 0;
1555 // STATUSINT 0x2D
1556 // STATUS0 0x2E
1557 // STATUS1 0x2F
1558 uint8_t status[3];
1559 if (comm->readRegister(QMI8658_REG_STATUS_INT, status, 3) != 0) {
1560 return 0;
1561 }
1562
1563 // SENSORLIB_LOG_I("STATUSINT:0x%X BIN:", status[0]);
1564 // SENSORLIB_LOG_I("STATUS0:0x%X BIN:", status[1]);
1565 // SENSORLIB_LOG_I("STATUS1:0x%X BIN:", status[2]);
1566 // SENSORLIB_LOG_I("------------------\n");
1567
1568 // Ctrl9 CmdDone
1569 // Indicates CTRL9 Command was done, as part of CTRL9 protocol
1570 // 0: Not Completed
1571 // 1: Done
1572 if (status[0] & 0x80) {
1573 result |= STATUS_INT_CTRL9_CMD_DONE;
1574 }
1575 // If syncSample (CTRL7.bit7) = 1:
1576 // 0: Sensor Data is not locked.
1577 // 1: Sensor Data is locked.
1578 // If syncSample = 0, this bit shows the same value of INT1 level
1579 if (status[0] & 0x02) {
1580 result |= STATUS_INT_LOCKED;
1581 }
1582 // If syncSample (CTRL7.bit7) = 1:
1583 // 0: Sensor Data is not available
1584 // 1: Sensor Data is available for reading
1585 // If syncSample = 0, this bit shows the same value of INT2 level
1586 if (status[0] & 0x01) {
1587 result |= STATUS_INT_AVAIL;
1588 // if (eventGyroDataReady)eventGyroDataReady();
1589 // if (eventAccelDataReady)eventAccelDataReady();
1590 }
1591
1592 //Locking Mechanism Can reading..
1593 if ((status[0] & 0x03) == 0x03) {
1594 if (eventDataLocking)eventDataLocking();
1595 }
1596
1597 //=======================================
1598 // Valid only in asynchronous mode
1599 if (sampleMode == ASYNC_MODE) {
1600 // Gyroscope new data available
1601 // 0: No updates since last read.
1602 // 1: New data available
1603 if (status[1] & 0x02) {
1604 result |= STATUS0_GYRO_DATA_READY;
1605 if (eventGyroDataReady)eventGyroDataReady();
1606 _gDataReady = true;
1607 }
1608 // Accelerometer new data available
1609 // 0: No updates since last read.
1610 // 1: New data available.
1611 if (status[1] & 0x01) {
1612 result |= STATUS0_ACCEL_DATA_READY;
1613 if (eventAccelDataReady)eventAccelDataReady();
1614 _aDataReady = true;
1615 }
1616 }
1617
1618 //=======================================
1619 // Significant Motion
1620 // 0: No Significant-Motion was detected
1621 // 1: Significant-Motion was detected
1622 if (status[2] & 0x80) {
1624 if (eventSignificantMotion)eventSignificantMotion();
1625 }
1626 // No Motion
1627 // 0: No No-Motion was detected
1628 // 1: No-Motion was detected
1629 if (status[2] & 0x40) {
1630 result |= STATUS1_NO_MOTION;
1631 if (eventNoMotionEvent)eventNoMotionEvent();
1632 }
1633 // Any Motion
1634 // 0: No Any-Motion was detected
1635 // 1: Any-Motion was detected
1636 if (status[2] & 0x20) {
1637 result |= STATUS1_ANY_MOTION;
1638 if (eventAnyMotionEvent)eventAnyMotionEvent();
1639 }
1640 // Pedometer
1641 // 0: No step was detected
1642 // 1: step was detected
1643 if (status[2] & 0x10) {
1644 result |= STATUS1_PEDOMETER_MOTION;
1645 if (eventPedometerEvent)eventPedometerEvent();
1646 }
1647 // WoM
1648 // 0: No WoM was detected
1649 // 1: WoM was detected
1650 if (status[2] & 0x04) {
1651 result |= STATUS1_WOM_MOTION;
1652 if (eventWomEvent)eventWomEvent();
1653 }
1654 // TAP
1655 // 0: No Tap was detected
1656 // 1: Tap was detected
1657 if (status[2] & 0x02) {
1658 result |= STATUS1_TAP_MOTION;
1659 if (eventTagEvent)eventTagEvent();
1660 }
1661 return result;
1662 }
1663
1665 {
1666 eventWomEvent = cb;
1667 }
1668
1670 {
1671 eventTagEvent = cb;
1672 }
1673
1675 {
1676 eventPedometerEvent = cb;
1677 }
1678
1680 {
1681 eventNoMotionEvent = cb;
1682 }
1683
1685 {
1686 eventAnyMotionEvent = cb;
1687 }
1688
1690 {
1691 eventSignificantMotion = cb;
1692 }
1693
1695 {
1696 eventGyroDataReady = cb;
1697 }
1698
1700 {
1701 eventAccelDataReady = cb;
1702 }
1703
1705 {
1706 eventDataLocking = cb;
1707 }
1708
1709
1718 bool calibration(uint16_t *gX_gain = NULL, uint16_t *gY_gain = NULL, uint16_t *gZ_gain = NULL)
1719 {
1720 // 1.Set CTRL7.aEN = 0 and CTRL7.gEN = 0, to disable the accelerometer and gyroscope.
1721 if (comm->writeRegister(QMI8658_REG_CTRL7, (uint8_t)0x00) != 0) {
1722 return false;
1723 }
1724
1725 // 2.Issue the CTRL_CMD_ON_DEMAND_CALIBRATION (0xA2) by CTRL9 command.
1727 return false;
1728 }
1729
1730 // 3.And wait about 1.5 seconds for QMI8658A to finish the CTRL9 command.
1731 hal->delay(1600);
1732
1733 // 4.Read the COD_STATUS register (0x46) to check the result/status of the COD implementation.
1734 int result = comm->readRegister(QMI8658_REG_COD_STATUS);
1735
1736 if (result == -1)return false;
1737
1738 // During the process, it is recommended to place the device in quiet, otherwise, the COD might fail and report error.
1739
1740 if (result & sensorlib::_bv(7)) {
1741 SENSORLIB_LOG_E("COD failed for checking low sensitivity limit of X axis of gyroscope");
1742 return false;
1743 }
1744 if (result & sensorlib::_bv(6)) {
1745 SENSORLIB_LOG_E("COD failed for checking high sensitivity limit of X axis of gyroscope");
1746 return false;
1747 }
1748 if (result & sensorlib::_bv(5)) {
1749 SENSORLIB_LOG_E("COD failed for checking low sensitivity limit of Y axis of gyroscope");
1750 return false;
1751 }
1752 if (result & sensorlib::_bv(4)) {
1753 SENSORLIB_LOG_E("COD failed for checking high sensitivity limit of Y axis of gyroscope");
1754 return false;
1755 }
1756 if (result & sensorlib::_bv(3)) {
1757 SENSORLIB_LOG_E("Accelerometer checked failed (significant vibration happened during COD)");
1758 return false;
1759 }
1760 if (result & sensorlib::_bv(2)) {
1761 SENSORLIB_LOG_E("Gyroscope startup failure happened when COD was called");
1762 return false;
1763 }
1764 if (result & sensorlib::_bv(1)) {
1765 SENSORLIB_LOG_E("COD was called while gyroscope was enabled, COD return failure");
1766 return false;
1767 }
1768 if (result & sensorlib::_bv(0)) {
1769 SENSORLIB_LOG_E("COD failed; no COD correction applied");
1770 return false;
1771 }
1772 SENSORLIB_LOG_D("All calibrations are completed");
1773
1774 if (gX_gain && gY_gain && gZ_gain) {
1775 uint8_t rawBuffer[6] = {0};
1776 if (comm->readRegister(QMI8658_REG_DVX_L, rawBuffer, 6) != 0) {
1777 return false;
1778 }
1779 *gX_gain = ((uint16_t)rawBuffer[0]) | (uint16_t)(rawBuffer[1] << 8);
1780 *gY_gain = ((uint16_t)rawBuffer[2]) | (uint16_t)(rawBuffer[3] << 8);
1781 *gZ_gain = ((uint16_t)rawBuffer[4]) | (uint16_t)(rawBuffer[5] << 8);
1782 }
1783
1784 return true;
1785 }
1786
1787
1796 bool writeCalibration(uint16_t gX_gain, uint16_t gY_gain, uint16_t gZ_gain)
1797 {
1798 // 1. Disable Accelerometer and Gyroscope by setting CTRL7.aEN = 0 and CTRL7.gEN = 0
1799 if (comm->writeRegister(QMI8658_REG_CTRL7, (uint8_t)0x00) != 0) {
1800 return false;
1801 }
1802
1803 uint8_t buffer[] = {
1804 // 2. write Gyro-X gain (16 bits) to registers CAL1_L and CAL1_H registers (0x0B, 0x0C)
1805 sensorlib::_lowByte(gX_gain),
1806 sensorlib::_highByte(gX_gain),
1807 // 3. write Gyro-Y gain (16 bits) to registers CAL2_L and CAL2_H registers (0x0D, 0x0E)
1808 sensorlib::_lowByte(gY_gain),
1809 sensorlib::_highByte(gY_gain),
1810 // 4. write Gyro-Z gain (16 bits) to registers CAL3_L and CAL3_H registers (0x0F, 0x10)
1811 sensorlib::_lowByte(gZ_gain),
1812 sensorlib::_highByte(gZ_gain),
1813 };
1814
1815 comm->writeRegister(QMI8658_REG_CAL1_L, buffer, sizeof(buffer));
1816
1817 // 5. Write 0xAA to CTRL9 and follow CTRL9 protocol
1818 if (writeCommand(CTRL_CMD_APPLY_GYRO_GAINS, 3000) != 0) {
1819 return false;
1820 }
1821
1822 return true;
1823 }
1824
1831 {
1832 // 1- Disable the sensors (CTRL7 = 0x00).
1833 if (comm->writeRegister(QMI8658_REG_CTRL7, (uint8_t)0x00) != 0) {
1834 return false;
1835 }
1836
1837 // 2- Set proper accelerometer ODR (CTRL2.aODR) and bit CTRL2.aST (bit7) to 1 to trigger the Self-Test.
1838 if (comm->writeRegister(QMI8658_REG_CTRL2, 0xF0, ACC_ODR_1000Hz | 0x80) != 0) {
1839 return false;
1840 }
1841
1842 // 3- Wait for QMI8658A to drive INT2 to High, if INT2 is enabled (CTRL1.bit4 = 1), or STATUSINT.bit0 is set to 1.
1843 int retry = 50;
1844 int dataReady = 0x00;
1845 while (dataReady != 0x01) {
1846 uint8_t reg_var = comm->readRegister(QMI8658_REG_STATUS_INT);
1847 SENSORLIB_LOG_D("reg_var : %x", reg_var);
1848 dataReady = reg_var & 0x01;
1849 // dataReady = comm->readRegister(QMI8658_REG_STATUS_INT) & 0x01;
1850 hal->delay(20);
1851 if (--retry <= 0) {
1852 SENSORLIB_LOG_E("No response.");
1853 return false;
1854 }
1855 }
1856
1857 SENSORLIB_LOG_I("Data is ready for reading....");
1858
1859 //4- Set CTRL2.aST(bit7) to 0, to clear STATUSINT1.bit0 and/or INT2.
1860 comm->clrRegisterBit(QMI8658_REG_CTRL2, 7);
1861
1862 // 5- Check for QMI8658A drives INT2 back to Low, and sets STATUSINT1.bit0 to 0.
1863 retry = 50;
1864 while (dataReady == 0x01) {
1865 uint8_t reg_var = comm->readRegister(QMI8658_REG_STATUS_INT);
1866 SENSORLIB_LOG_D("reg_var : %x", reg_var);
1867 dataReady = (reg_var & 0x01);
1868 // dataReady = !(comm->readRegister(QMI8658_REG_STATUS_INT) & 0x01);
1869 hal->delay(20);
1870 if (--retry <= 0) {
1871 SENSORLIB_LOG_E("No response.");
1872 return false;
1873 }
1874 }
1875
1876 /*
1877 6- Read the Accel Self-Test result:
1878 X channel: dVX_L and dVX_H (registers 0x51 and 0x52)
1879 Y channel: dVY_L and dVY_H (registers 0x53 and 0x54)
1880 Z channel: dVZ_L and dVZ_H (registers 0x55 and 0x56)
1881 The results are 16-bits in format signed U5.11, resolution 0.5mg (1 / 2^11 g).
1882 */
1883 uint8_t rawBuffer[6];
1884
1885 if (comm->readRegister(QMI8658_REG_DVX_L, rawBuffer, 6) != 0) {
1886 return false;
1887 }
1888
1889 int16_t dVX = (int16_t)(rawBuffer[0]) | (int16_t)(((int16_t)rawBuffer[1]) << 8);
1890 int16_t dVY = (int16_t)(rawBuffer[2]) | (int16_t)(((int16_t)rawBuffer[3]) << 8);
1891 int16_t dVZ = (int16_t)(rawBuffer[4]) | (int16_t)(((int16_t)rawBuffer[5]) << 8);
1892
1893 // To convert to mg, considering the U5.11 format, we need to divide by (2^11) to get the actual mg value
1894 float dVX_mg = dVX * 0.5; // 0.5mg is the smallest unit of this format
1895 float dVY_mg = dVY * 0.5;
1896 float dVZ_mg = dVZ * 0.5;
1897
1898 SENSORLIB_LOG_D("\n\tdVX_mg:%05.11f \n\tdVY_mg:%05.11f \n\tdVZ_mg:%05.11f", dVX_mg, dVY_mg, dVZ_mg);
1899 // If the absolute results of all three axes are higher than 200mg, the accelerometer can be considered functional.
1900 // Otherwise, the accelerometer cannot be considered functional.
1901 if (abs(dVX_mg) > 200 && abs(dVY_mg) > 200 && abs(dVZ_mg) > 200) {
1902 SENSORLIB_LOG_D("Accelerometer is working properly.");
1903 } else {
1904 SENSORLIB_LOG_D("Accelerometer is not working properly.");
1905 return false;
1906 }
1907 return true;
1908 }
1909
1910
1917 {
1918 // 1- Disable the sensors (CTRL7 = 0x00).
1919 if (comm->writeRegister(QMI8658_REG_CTRL7, (uint8_t)0x00) != 0) {
1920 return false;
1921 }
1922
1923 // 2- Set the bit gST to 1. (CTRL3.bit7 = 1"b1).
1924 comm->setRegisterBit(QMI8658_REG_CTRL3, 7);
1925
1926 // 3- Wait for QMI8658A to drive INT2 to High, if INT2 is enabled, or STATUS_INT.bit0 is set to 1.
1927 int retry = 50;
1928 int dataReady = 0x00;
1929 while (dataReady != 0x01) {
1930 dataReady = comm->readRegister(QMI8658_REG_STATUS_INT) & 0x01;
1931 hal->delay(20);
1932 if (--retry <= 0) {
1933 SENSORLIB_LOG_E("No response.");
1934 return false;
1935 }
1936 }
1937
1938 SENSORLIB_LOG_I("Data is ready for reading....");
1939
1940 //4- Set CTRL3.aST(bit7) to 0, to clear STATUS_INT1.bit0 and/or INT2.
1941 comm->clrRegisterBit(QMI8658_REG_CTRL3, 7);
1942
1943 // 5- Check for QMI8658A drives INT2 back to Low, or sets STATUSINT1.bit0 to 0.
1944 retry = 50;
1945 while (dataReady != 0x00) {
1946 dataReady = !(comm->readRegister(QMI8658_REG_STATUS_INT) & 0x01);
1947 hal->delay(20);
1948 if (--retry <= 0) {
1949 SENSORLIB_LOG_E("No response.");
1950 return false;
1951 }
1952 }
1953
1954 /*
1955 6- Read the Gyro Self-Test result:
1956 X channel: dVX_L and dVX_H (registers 0x51 and 0x52)
1957 Y channel: dVY_L and dVY_H (registers 0x53 and 0x54)
1958 Z channel: dVZ_L and dVZ_H (registers 0x55 and 0x56)
1959 Read the 16 bits result in format signed U12.4, resolution is 62.5mdps (1 / 2^4 dps).
1960 */
1961 uint8_t rawBuffer[6];
1962 if (comm->readRegister(QMI8658_REG_DVX_L, rawBuffer, 6) != 0) {
1963 return false;
1964 }
1965
1966 // int16_t x = (int16_t)(rawBuffer[0]) | ((int16_t)(rawBuffer[1] << 8));
1967 // int16_t y = (int16_t)(rawBuffer[2]) | ((int16_t)(rawBuffer[3] << 8));
1968 // int16_t z = (int16_t)(rawBuffer[4]) | ((int16_t)(rawBuffer[5] << 8));
1969
1970 float dVX = (((int16_t)rawBuffer[0]) << 12) | ((int16_t)(rawBuffer[1]) >> 4);
1971 float dVY = (((int16_t)rawBuffer[2]) << 12) | ((int16_t)(rawBuffer[3]) >> 4);
1972 float dVZ = (((int16_t)rawBuffer[4]) << 12) | ((int16_t)(rawBuffer[5]) >> 4);
1973
1974 dVX *= (1.0 / (1 << 4)); // 62.5 mdps
1975 dVY *= (1.0 / (1 << 4)); // 62.5 mdps
1976 dVZ *= (1.0 / (1 << 4)); // 62.5 mdps
1977
1978 SENSORLIB_LOG_D("\n\tdVX:%12.4f \n\tdVY:%12.4f \n\tdVZ:%12.4f", dVX, dVY, dVZ);
1979
1980 // If the absolute results of all three axes are higher than 300dps, the gyroscope can be considered functional.
1981 // Otherwise, the gyroscope cannot be considered functional.
1982 if (abs(dVX) > 300 && abs(dVY) > 300 && abs(dVZ) > 300) {
1983 SENSORLIB_LOG_D("Gyro is working properly.");
1984 } else {
1985 SENSORLIB_LOG_D("Gyro is not working properly.");
1986 return false;
1987 }
1988
1989 return true;
1990 }
1991
2001 void setAccelOffset(int16_t offset_x, int16_t offset_y, int16_t offset_z)
2002 {
2003 uint8_t data[6];
2004 data[0] = sensorlib::_lowByte(offset_x);
2005 data[1] = sensorlib::_highByte(offset_x);
2006 data[2] = sensorlib::_lowByte(offset_y);
2007 data[3] = sensorlib::_highByte(offset_y);
2008 data[4] = sensorlib::_lowByte(offset_z);
2009 data[5] = sensorlib::_highByte(offset_z);
2010 comm->writeRegister(QMI8658_REG_CAL1_L, data, 2);
2011 comm->writeRegister(QMI8658_REG_CAL2_L, data + 2, 2);
2012 comm->writeRegister(QMI8658_REG_CAL3_L, data + 4, 2);
2014 }
2015
2025 void setGyroOffset(int16_t offset_x, int16_t offset_y, int16_t offset_z)
2026 {
2027 uint8_t data[6];
2028 data[0] = sensorlib::_lowByte(offset_x);
2029 data[1] = sensorlib::_highByte(offset_x);
2030 data[2] = sensorlib::_lowByte(offset_y);
2031 data[3] = sensorlib::_highByte(offset_y);
2032 data[4] = sensorlib::_lowByte(offset_z);
2033 data[5] = sensorlib::_highByte(offset_z);
2034 comm->writeRegister(QMI8658_REG_CAL1_L, data, 2);
2035 comm->writeRegister(QMI8658_REG_CAL2_L, data + 2, 2);
2036 comm->writeRegister(QMI8658_REG_CAL3_L, data + 4, 2);
2038 }
2039
2040private:
2041
2047 uint16_t getFifoNeedBytes()
2048 {
2049 uint8_t sam[] = {16, 32, 64, 128};
2050 uint8_t sensors = 0;
2052 sensors = 2;
2053 } else if (_gyro_enabled || _accel_enabled) {
2054 sensors = 1;
2055 }
2056 uint8_t samples = ((_fifo_mode >> 2) & 0x03) ;
2057 return sam[samples] * 6 * sensors;
2058 }
2059
2060
2066 uint16_t readFromFifo()
2067 {
2068 uint8_t status[2];
2069 uint16_t fifo_bytes = 0;
2070
2071 if ((_irq != -1) && _fifo_interrupt) {
2072 /*
2073 * Once the corresponds INT pin is configured to the push-pull mode, the FIFO watermark interrupt can be seen on the
2074 * corresponds INT pin. It will keep high level as long as the FIFO filled level is equal to or higher than the watermark, will
2075 * drop to low level as long as the FIFO filled level is lower than the configured FIFO watermark after reading out by host
2076 * and FIFO_RD_MODE is cleared.
2077 */
2078 if (hal->digitalRead(_irq) == LOW) {
2079 return false;
2080 }
2081 }
2082
2083 size_t alloc_size = getFifoNeedBytes();
2084 if (!fifo_buffer) {
2085 fifo_buffer = (uint8_t *)calloc(alloc_size, sizeof(uint8_t));
2086 if (!fifo_buffer) {
2087 SENSORLIB_LOG_E("Calloc buffer size %u bytes failed!", alloc_size);
2088 return 0;
2089 }
2090 _fifo_size = alloc_size;
2091
2092 } else if (alloc_size > _fifo_size) {
2093 fifo_buffer = (uint8_t *)realloc(fifo_buffer, alloc_size);
2094 if (!fifo_buffer) {
2095 SENSORLIB_LOG_E("Realloc buffer size %u bytes failed!", alloc_size);
2096 return 0;
2097 }
2098 }
2099
2100 // Got FIFO watermark interrupt by INT pin or polling the FIFO_STATUS register (FIFO_WTM and/or FIFO_FULL).
2101 int val = comm->readRegister(QMI8658_REG_FIFO_STATUS);
2102 if (val == -1) {
2103 return 0;
2104 }
2105 SENSORLIB_LOG_D("FIFO status:0x%x", val);
2106
2107 if (!(val & sensorlib::_bv(4))) {
2108 SENSORLIB_LOG_D("FIFO is Empty");
2109 return 0;
2110 }
2111 if (val & sensorlib::_bv(5)) {
2112 SENSORLIB_LOG_D("FIFO Overflow condition has happened (data dropping happened)");
2113 // return 0;
2114 }
2115 if (val & sensorlib::_bv(6)) {
2116 SENSORLIB_LOG_D("FIFO Water Mark Level Hit");
2117 }
2118 if (val & sensorlib::_bv(7)) {
2119 SENSORLIB_LOG_D("FIFO is Full");
2120 }
2121
2122 // Read the FIFO_SMPL_CNT and FIFO_STATUS registers, to calculate the level of FIFO content data, refer to 8.4 FIFO Sample Count.
2123 if (comm->readRegister(QMI8658_REG_FIFO_COUNT, status, 2) == -1) {
2124 SENSORLIB_LOG_E("Bus communication failed!");
2125 return 0;
2126 }
2127
2128 // FIFO_Sample_Count (in byte) = 2 * (fifo_smpl_cnt_msb[1:0] * 256 + fifo_smpl_cnt_lsb[7:0])
2129 fifo_bytes = 2 * (((status[1] & 0x03)) << 8 | status[0]);
2130
2131 SENSORLIB_LOG_D("reg fifo_bytes:%d ", fifo_bytes);
2132
2133 //Samples 16 * 6 * 2 = 192
2134 //Samples 32 * 6 * 2 = 384
2135 //Samples 64 * 6 * 2 = 768
2136 //Samples 128 * 6 * 2 = 1536
2137
2138 // Send CTRL_CMD_REQ_FIFO (0x05) by CTRL9 command, to enable FIFO read mode. Refer to CTRL_CMD_REQ_FIFO for details.
2139 if (writeCommand(CTRL_CMD_REQ_FIFO) != 0) {
2140 SENSORLIB_LOG_E("Request FIFO failed!");
2141 return 0;
2142 }
2143
2144 // Read from the FIFO_DATA register per FIFO_Sample_Count.
2145 if (comm->readRegister(QMI8658_REG_FIFO_DATA, fifo_buffer, fifo_bytes) == -1) {
2146 SENSORLIB_LOG_E("Request FIFO data failed !");
2147 return 0;
2148 }
2149
2150 // Disable the FIFO Read Mode by setting FIFO_CTRL.FIFO_rd_mode to 0. New data will be filled into FIFO afterwards.
2151 if (comm->writeRegister(QMI8658_REG_FIFO_CTRL, _fifo_mode) == -1) {
2152 SENSORLIB_LOG_E("Clear FIFO flag failed!");
2153 return 0;
2154 }
2155
2156 return fifo_bytes;
2157 }
2158
2159
2166 int writeCommand(CommandTable cmd, uint32_t wait_ms = 1000)
2167 {
2168 int val;
2169 uint32_t startMillis;
2170 if (comm->writeRegister(QMI8658_REG_CTRL9, cmd) == -1) {
2171 return -1;
2172 }
2173 startMillis = hal->millis();
2174 do {
2175 val = comm->readRegister(QMI8658_REG_STATUS_INT);
2176 hal->delay(1);
2177 if (hal->millis() - startMillis > wait_ms) {
2178 SENSORLIB_LOG_E("wait for ctrl9 command done time out : %d val:%d", cmd, val);
2179 return -1;
2180 }
2181 } while (val != -1 && !(val & 0x80));
2182
2183 if (comm->writeRegister(QMI8658_REG_CTRL9, CTRL_CMD_ACK) == -1) {
2184 return -1;
2185 }
2186
2187 startMillis = hal->millis();
2188 do {
2189 val = comm->readRegister(QMI8658_REG_STATUS_INT);
2190 hal->delay(1);
2191 if (hal->millis() - startMillis > wait_ms) {
2192 SENSORLIB_LOG_E("Clear ctrl9 command done flag timeout : %d val:%d", cmd, val);
2193 return -1;
2194 }
2195 } while (val != -1 && (val & 0x80));
2196
2197 return 0;
2198 }
2199
2200
2207 uint8_t mgToBytes(float mg)
2208 {
2209 float g = mg / 1000.0; // Convert to grams
2210 int units = (int)round(g / 0.03125); //Convert grams to units of specified(1/32) resolution
2211 return (units & 0x1F) << 3; // Shift the 5 decimal places to the left by 3 places, because there are only 3 integer places
2212 }
2213
2214
2215 int _irq = -1;
2216 float accelScales = 0.0f, gyroScales = 0.0f;
2217 bool _accel_enabled = false;
2218 bool _gyro_enabled = false;
2219 bool _gDataReady = false;
2220 bool _aDataReady = false;
2221 bool _fifo_interrupt = false;
2222
2223 uint8_t usid[6];
2224 uint8_t sampleMode = ASYNC_MODE;
2225 uint8_t _irq_enable_mask = false;
2226 uint8_t _fifo_mode = 0x00;
2227 uint8_t *fifo_buffer = NULL;
2228 uint16_t _fifo_size = 0;
2229
2230 uint32_t lastTimestamp = 0;
2231 uint32_t revisionID = 0x00;
2232
2233 EventCallBack_t eventWomEvent = NULL;
2234 EventCallBack_t eventTagEvent = NULL;
2235 EventCallBack_t eventPedometerEvent = NULL;
2236 EventCallBack_t eventNoMotionEvent = NULL;
2237 EventCallBack_t eventAnyMotionEvent = NULL;
2238 EventCallBack_t eventSignificantMotion = NULL;
2239 EventCallBack_t eventGyroDataReady = NULL;
2240 EventCallBack_t eventAccelDataReady = NULL;
2241 EventCallBack_t eventDataLocking = NULL;
2242
2243
2244protected:
2245
2246 bool initImpl(uint8_t param) override
2247 {
2248 uint8_t buffer[6] = {0};
2249
2250
2251 if (_irq != -1) {
2252 hal->pinMode(_irq, INPUT);
2253 }
2254
2255 if (!reset()) {
2256 return false;
2257 }
2258
2259 uint8_t id = whoAmI();
2260 if (id != QMI8658_REG_WHOAMI_DEFAULT) {
2261 SENSORLIB_LOG_E("ERROR! ID NOT MATCH QMI8658 , Response id is 0x%x", id);
2262 return false;
2263 }
2264 // Enable address auto increment, Big-Endian format
2265 // comm->writeRegister(QMI8658_REG_CTRL1, 0x60);
2266
2267 // Little-Endian / address auto increment
2268 // comm->writeRegister(QMI8658_REG_CTRL1, 0x40);
2269
2270 // no need . reset function has set
2271 //EN.ADDR_AI
2272 // comm->setRegisterBit(QMI8658_REG_CTRL1, 6);
2273
2274 // Use STATUS_INT.bit7 as CTRL9 handshake
2275 comm->writeRegister(QMI8658_REG_CTRL8, 0x80);
2276
2277 // Get firmware version and usid
2279
2280 if (comm->readRegister(QMI8658_REG_DQW_L, buffer, 3) != -1) {
2281 revisionID = buffer[0] | (uint32_t)(buffer[1] << 8) | (uint32_t)(buffer[2] << 16);
2282 SENSORLIB_LOG_D("FW Version :0x%02X%02X%02X", buffer[0], buffer[1], buffer[2]);
2283 }
2284
2285 if (comm->readRegister(QMI8658_REG_DVX_L, usid, 6) != -1) {
2286 SENSORLIB_LOG_D("USID :%02X%02X%02X%02X%02X%02X",
2287 usid[0], usid[1], usid[2],
2288 usid[3], usid[4], usid[5]);
2289 }
2290
2291 return true;
2292 }
2293
2294 // @brief registers default value
2295 static constexpr uint8_t QMI8658_REG_WHOAMI_DEFAULT = 0x05;
2296 static constexpr uint8_t QMI8658_REG_STATUS_DEFAULT = 0x03;
2297 static constexpr uint8_t QMI8658_REG_RESET_DEFAULT = 0xB0;
2298
2299
2300 //* General Purpose Registers
2301 static constexpr uint8_t QMI8658_REG_WHOAMI = 0x00;
2302 static constexpr uint8_t QMI8658_REG_REVISION = 0x01;
2303
2304
2305 //* Setup and Control Registers
2306 static constexpr uint8_t QMI8658_REG_CTRL1 = 0x02;
2307 static constexpr uint8_t QMI8658_REG_CTRL2 = 0x03;
2308 static constexpr uint8_t QMI8658_REG_CTRL3 = 0x04;
2309 // Reserved
2310 static constexpr uint8_t QMI8658_REG_CTRL5 = 0x06;
2311 // Reserved
2312 static constexpr uint8_t QMI8658_REG_CTRL7 = 0x08;
2313 static constexpr uint8_t QMI8658_REG_CTRL8 = 0x09;
2314 static constexpr uint8_t QMI8658_REG_CTRL9 = 0x0A;
2315
2316 //* Host Controlled Calibration Registers (See CTRL9, Usage is Optional)
2317 static constexpr uint8_t QMI8658_REG_CAL1_L = 0x0B;
2318 static constexpr uint8_t QMI8658_REG_CAL1_H = 0x0C;
2319 static constexpr uint8_t QMI8658_REG_CAL2_L = 0x0D;
2320 static constexpr uint8_t QMI8658_REG_CAL2_H = 0x0E;
2321 static constexpr uint8_t QMI8658_REG_CAL3_L = 0x0F;
2322 static constexpr uint8_t QMI8658_REG_CAL3_H = 0x10;
2323 static constexpr uint8_t QMI8658_REG_CAL4_L = 0x11;
2324 static constexpr uint8_t QMI8658_REG_CAL4_H = 0x12;
2325
2326 //* FIFO Registers
2327 static constexpr uint8_t QMI8658_REG_FIFO_WTM_TH = 0x13;
2328 static constexpr uint8_t QMI8658_REG_FIFO_CTRL = 0x14;
2329 static constexpr uint8_t QMI8658_REG_FIFO_COUNT = 0x15;
2330 static constexpr uint8_t QMI8658_REG_FIFO_STATUS = 0x16;
2331 static constexpr uint8_t QMI8658_REG_FIFO_DATA = 0x17;
2332
2333 //* Status Registers
2334 static constexpr uint8_t QMI8658_REG_STATUS_INT = 0x2D;
2335 static constexpr uint8_t QMI8658_REG_STATUS0 = 0x2E;
2336 static constexpr uint8_t QMI8658_REG_STATUS1 = 0x2F;
2337
2338 //* Timestamp Register
2339 static constexpr uint8_t QMI8658_REG_TIMESTAMP_L = 0x30;
2340 static constexpr uint8_t QMI8658_REG_TIMESTAMP_M = 0x31;
2341 static constexpr uint8_t QMI8658_REG_TIMESTAMP_H = 0x32;
2342
2343 //* Data Output Registers (16 bits 2’s Complement Except COD Sensor Data)
2344 static constexpr uint8_t QMI8658_REG_TEMPERATURE_L = 0x33;
2345 static constexpr uint8_t QMI8658_REG_TEMPERATURE_H = 0x34;
2346 static constexpr uint8_t QMI8658_REG_AX_L = 0x35;
2347 static constexpr uint8_t QMI8658_REG_AX_H = 0x36;
2348 static constexpr uint8_t QMI8658_REG_AY_L = 0x37;
2349 static constexpr uint8_t QMI8658_REG_AY_H = 0x38;
2350 static constexpr uint8_t QMI8658_REG_AZ_L = 0x39;
2351 static constexpr uint8_t QMI8658_REG_AZ_H = 0x3A;
2352 static constexpr uint8_t QMI8658_REG_GX_L = 0x3B;
2353 static constexpr uint8_t QMI8658_REG_GX_H = 0x3C;
2354 static constexpr uint8_t QMI8658_REG_GY_L = 0x3D;
2355 static constexpr uint8_t QMI8658_REG_GY_H = 0x3E;
2356 static constexpr uint8_t QMI8658_REG_GZ_L = 0x3F;
2357 static constexpr uint8_t QMI8658_REG_GZ_H = 0x40;
2358
2359 //* COD Indication and General Purpose Registers
2360
2361 // Calibration-On-Demand status register
2362 static constexpr uint8_t QMI8658_REG_COD_STATUS = 0x46;
2363 static constexpr uint8_t QMI8658_REG_DQW_L = 0x49;
2364 static constexpr uint8_t QMI8658_REG_DQW_H = 0x4A;
2365 static constexpr uint8_t QMI8658_REG_DQX_L = 0x4B;
2366 static constexpr uint8_t QMI8658_REG_DQX_H = 0x4C;
2367
2368 static constexpr uint8_t QMI8658_REG_DQY_L = 0x4D;
2369 static constexpr uint8_t QMI8658_REG_DQY_H = 0x4E;
2370 static constexpr uint8_t QMI8658_REG_DQZ_L = 0x4F;
2371 static constexpr uint8_t QMI8658_REG_DQZ_H = 0x50;
2372
2373 static constexpr uint8_t QMI8658_REG_DVX_L = 0x51;
2374 static constexpr uint8_t QMI8658_REG_DVX_H = 0x52;
2375 static constexpr uint8_t QMI8658_REG_DVY_L = 0x53;
2376 static constexpr uint8_t QMI8658_REG_DVY_H = 0x54;
2377 static constexpr uint8_t QMI8658_REG_DVZ_L = 0x55;
2378 static constexpr uint8_t QMI8658_REG_DVZ_H = 0x56;
2379
2380 //* Activity Detection Output Registers
2381 static constexpr uint8_t QMI8658_REG_TAP_STATUS = 0x59;
2382 static constexpr uint8_t QMI8658_REG_STEP_CNT_LOW = 0x5A;
2383 static constexpr uint8_t QMI8658_REG_STEP_CNT_MID = 0x5B;
2384 static constexpr uint8_t QMI8658_REG_STEP_CNT_HIGH = 0x5C;
2385 static constexpr uint8_t QMI8658_REG_RESET = 0x60;
2386
2387 //* Reset Register
2388 static constexpr uint8_t QMI8658_REG_RST_RESULT = 0x4D;
2389 static constexpr uint8_t QMI8658_REG_RST_RESULT_VAL = 0x80;
2390
2391 static constexpr uint8_t STATUS0_ACCEL_AVAIL = 0x01;
2392 static constexpr uint8_t STATUS0_GYRO_AVAIL = 0x02;
2393 static constexpr uint8_t QMI8658_ACCEL_LPF_MASK = 0xF9;
2394 static constexpr uint8_t QMI8658_GYRO_LPF_MASK = 0x9F;
2395
2396 static constexpr uint8_t QMI8658_ACCEL_EN_MASK = 0x01;
2397 static constexpr uint8_t QMI8658_GYRO_EN_MASK = 0x02;
2398 static constexpr uint8_t QMI8658_ACCEL_GYRO_EN_MASK = 0x03;
2399
2400
2401 static constexpr uint8_t QMI8658_FIFO_MAP_INT1 = 0x04;
2402};
2403
2404#endif
@license MIT License
#define SENSORLIB_LOG_I(...)
#define SENSORLIB_LOG_E(...)
#define SENSORLIB_LOG_D(...)
std::unique_ptr< SensorCommBase > comm
std::unique_ptr< SensorHal > hal
QMI8658 IMU sensor driver class.
GyroODR
Gyroscope output data rate enumeration.
bool enableSyncSampleMode()
Enable the synchronous sample mode.
bool reset() override
Reset the IMU sensor to its default state.
void setPedometerEventCallBack(EventCallBack_t cb)
static constexpr uint8_t QMI8658_REG_TIMESTAMP_M
bool getGyroscope(float &x, float &y, float &z)
Get the raw gyroscope data.
void setAccelOffset(int16_t offset_x, int16_t offset_y, int16_t offset_z)
Write accelerometer calibration offsets.
void powerDown()
Power down the sensor.
static constexpr uint8_t QMI8658_REG_TIMESTAMP_L
bool disableTap()
Disable tap detection.
float getTemperature_C()
Get the temperature in degree Celsius.
static constexpr uint8_t QMI8658_REG_WHOAMI_DEFAULT
static constexpr uint8_t QMI8658_REG_CAL2_L
static constexpr uint8_t QMI8658_ACCEL_GYRO_EN_MASK
static constexpr uint8_t QMI8658_REG_DVY_H
static constexpr uint8_t QMI8658_REG_TIMESTAMP_H
static constexpr uint8_t QMI8658_REG_STATUS_INT
static constexpr uint8_t QMI8658_REG_FIFO_WTM_TH
static constexpr uint8_t QMI8658_REG_DVZ_H
static constexpr uint8_t QMI8658_REG_COD_STATUS
uint8_t getChipID()
Get the chip ID.
void setGyroDataReadyCallBack(EventCallBack_t cb)
static constexpr uint8_t QMI8658_REG_DQZ_L
static constexpr uint8_t QMI8658_REG_AX_L
static constexpr uint8_t QMI8658_REG_GY_H
bool configTap(uint8_t priority, uint8_t peakWindow, uint16_t tapWindow, uint16_t dTapWindow, float alpha, float gamma, float peakMagThr, float UDMThr)
configTap
static constexpr uint8_t QMI8658_REG_FIFO_DATA
bool disableMotionDetect()
Disable motion detection.
static constexpr uint8_t QMI8658_GYRO_EN_MASK
bool configMotion(uint8_t modeCtrl, float AnyMotionXThr, float AnyMotionYThr, float AnyMotionZThr, uint8_t AnyMotionWindow, float NoMotionXThr, float NoMotionYThr, float NoMotionZThr, uint8_t NoMotionWindow, uint16_t SigMotionWaitWindow, uint16_t SigMotionConfirmWindow)
static constexpr uint8_t QMI8658_REG_STEP_CNT_LOW
void dumpCtrlRegister()
Dump the control register values.
SensorQMI8658()=default
Constructor for SensorQMI8658.
int writeCommand(uint8_t cmd, uint32_t timeout_ms=1000)
static constexpr uint8_t QMI8658_REG_CTRL7
static constexpr uint8_t QMI8658_FIFO_MAP_INT1
static constexpr uint8_t QMI8658_REG_GX_H
void setAnyMotionEventCallBack(EventCallBack_t cb)
static constexpr uint8_t QMI8658_REG_CTRL5
static constexpr uint8_t QMI8658_REG_RESET
uint8_t getIrqStatus()
Get the IRQ status.
bool enableMotionDetect(IntPin pin=INTERRUPT_PIN_1)
Enable motion detection.
static constexpr uint8_t QMI8658_REG_AX_H
static constexpr uint8_t QMI8658_REG_CTRL9
static constexpr uint8_t QMI8658_REG_DQY_H
static constexpr uint8_t QMI8658_REG_GY_L
static constexpr uint8_t QMI8658_REG_CTRL2
static constexpr uint8_t QMI8658_GYRO_LPF_MASK
float getGyroscopeScales()
Get the gyroscope scales.
bool disableGyroscope()
Disable the gyroscope.
void setWakeupMotionEventCallBack(EventCallBack_t cb)
static constexpr uint8_t QMI8658_REG_CAL2_H
static constexpr uint8_t QMI8658_REG_DVY_L
static constexpr uint8_t QMI8658_REG_RST_RESULT
void setTapEventCallBack(EventCallBack_t cb)
static constexpr uint8_t QMI8658_REG_DQW_L
static constexpr uint8_t QMI8658_REG_DQY_L
static constexpr uint8_t QMI8658_REG_STEP_CNT_MID
static constexpr uint8_t QMI8658_REG_DVX_H
void enableINT(IntPin pin, bool enable=true)
Enable or disable the interrupt.
static constexpr uint8_t QMI8658_REG_CAL4_H
AccelODR
Accelerometer output data rate enumeration.
bool getAccelRaw(int16_t *rawBuffer)
Get the raw accelerometer data.
uint16_t readFromFifo(IMUdata *acc, uint16_t accLength, IMUdata *gyro, uint16_t gyrLength)
readFromFifo
bool disableLockingMechanism()
Disable the locking mechanism.
static constexpr uint8_t QMI8658_REG_CAL3_L
bool selfTestGyro()
Perform self-test on the gyroscope.
static constexpr uint8_t QMI8658_REG_STATUS0
static constexpr uint8_t QMI8658_REG_STATUS1
static constexpr uint8_t QMI8658_REG_AY_H
static constexpr uint8_t QMI8658_REG_AZ_L
static constexpr uint8_t QMI8658_REG_DQW_H
static constexpr uint8_t QMI8658_ACCEL_EN_MASK
static constexpr uint8_t QMI8658_REG_CAL3_H
uint16_t readFromFifo(AccelerometerData *accel_data, uint16_t accel_count, GyroscopeData *gyro_data, uint16_t gyro_count) override
Read data from FIFO buffer.
static constexpr uint8_t QMI8658_REG_CTRL8
bool clearPedometerCounter()
Clear the Pedometer counter.
bool enableLockingMechanism()
Enable the locking mechanism.
static constexpr uint8_t QMI8658_REG_DQZ_H
void enableDataReadyINT(bool enable=true)
Enable or disable the Data Ready interrupt.
bool configPedometer(uint16_t ped_sample_cnt, uint16_t ped_fix_peak2peak, uint16_t ped_fix_peak, uint16_t ped_time_up, uint8_t ped_time_low=0x14, uint8_t ped_time_cnt_entry=0x0A, uint8_t ped_fix_precision=0x00, uint8_t ped_sig_count=0x04)
configPedometer
GyroRange
Gyroscope full-scale range enumeration.
static constexpr uint8_t QMI8658_REG_AY_L
bool configAccelerometer(AccelRange range, AccelODR odr, LpfMode lpfOdr=LPF_MODE_0)
Configure the accelerometer.
void setAccelDataReadyEventCallBack(EventCallBack_t cb)
static constexpr uint8_t QMI8658_REG_AZ_H
uint32_t getChipFirmwareVersion()
Get Sensor chip firmware version.
void setPins(int _irq)
Set sensor interrupt pins.
void powerOn()
Power on the sensor.
static constexpr uint8_t QMI8658_REG_WHOAMI
LpfMode
Low-pass filter mode enumeration.
AccelRange
Accelerometer full-scale range enumeration.
static constexpr uint8_t QMI8658_REG_DVX_L
static constexpr uint8_t QMI8658_REG_CAL1_H
bool writeCalibration(uint16_t gX_gain, uint16_t gY_gain, uint16_t gZ_gain)
Write Gyroscope calibration gains.
void setSignificantMotionEventCallBack(EventCallBack_t cb)
bool configGyroscope(GyroRange range, GyroODR odr, LpfMode lpfOdr=LPF_MODE_0)
Configure the gyroscope.
static constexpr uint8_t QMI8658_REG_STATUS_DEFAULT
static constexpr uint8_t QMI8658_REG_REVISION
void(* EventCallBack_t)(void)
bool isEnableAccelerometer()
Check if the accelerometer is enabled.
static constexpr uint8_t QMI8658_REG_STEP_CNT_HIGH
uint32_t getPedometerCounter()
Get the Pedometer counter.
bool initImpl(uint8_t param) override
static constexpr uint8_t QMI8658_REG_CAL1_L
TapEvent getTapStatus()
Get the current tap status.
int configActivityInterruptMap(IntPin pin)
Config activity interrupt pin mapping.
void setGyroOffset(int16_t offset_x, int16_t offset_y, int16_t offset_z)
Write gyroscope calibration offsets.
bool getGyroRaw(int16_t *rawBuffer)
Get the raw gyroscope data.
void setNoMotionEventCallBack(EventCallBack_t cb)
static constexpr uint8_t QMI8658_REG_DQX_L
static constexpr uint8_t STATUS0_GYRO_AVAIL
float getAccelerometerScales()
Get the accelerometer scales.
bool disableSyncSampleMode()
Disable the synchronous sample mode.
static constexpr uint8_t QMI8658_REG_CAL4_L
static constexpr uint8_t STATUS0_ACCEL_AVAIL
bool isEnableGyroscope()
Check if the gyroscope is enabled.
static constexpr uint8_t QMI8658_REG_FIFO_CTRL
~SensorQMI8658()
Destructor for SensorQMI8658.
int whoAmI()
Get the WHO_AM_I register value.
bool configFIFO(FIFO_Mode mode, FIFO_Samples samples=FIFO_SAMPLES_16, IntPin pin=INTERRUPT_PIN_DISABLE, uint8_t trigger_samples=16)
Configure the FIFO.
uint16_t update()
Update sensor status.
bool enableGyroscope()
Enable the gyroscope.
static constexpr uint8_t QMI8658_REG_GX_L
int getStatusRegister()
Get the Pedometer counter.
void setDataLockingEventCallBack(EventCallBack_t cb)
static constexpr uint8_t QMI8658_REG_DQX_H
static constexpr uint8_t QMI8658_REG_GZ_L
bool enableAccelerometer()
Enable the accelerometer.
bool configWakeOnMotion(uint8_t WoMThreshold=200, AccelODR odr=ACC_ODR_LOWPOWER_128Hz, IntPin pin=INTERRUPT_PIN_2, uint8_t defaultPinValue=1, uint8_t blankingTime=0x20, AccelRange accRange=ACC_RANGE_8G)
configWakeOnMotion
static constexpr uint8_t QMI8658_REG_FIFO_COUNT
bool reset(bool waitResult=true, uint32_t timeout=500)
Reset the sensor.
static constexpr uint8_t QMI8658_REG_DVZ_L
static constexpr uint8_t QMI8658_REG_RST_RESULT_VAL
bool getDataReady()
Check if new data is available.
static constexpr uint8_t QMI8658_ACCEL_LPF_MASK
bool selfTestAccel()
Perform self-test on the accelerometer.
bool enableTap(IntPin pin=INTERRUPT_PIN_1)
Enable tap detection.
static constexpr uint8_t QMI8658_REG_TEMPERATURE_L
bool enablePedometer(IntPin pin=INTERRUPT_PIN_DISABLE)
enablePedometer
static constexpr uint8_t QMI8658_REG_CTRL1
bool calibration(uint16_t *gX_gain=NULL, uint16_t *gY_gain=NULL, uint16_t *gZ_gain=NULL)
Set Gyroscope calibration gains.
void getChipUsid(uint8_t *buffer, uint8_t length)
Get Sensor chip USID.
uint32_t getTimestamp()
Get the timestamp.
static constexpr uint8_t QMI8658_REG_GZ_H
static constexpr uint8_t QMI8658_REG_RESET_DEFAULT
bool getAccelerometer(float &x, float &y, float &z)
Get the accelerometer data.
uint8_t mgToBytes(float mg)
static constexpr uint8_t QMI8658_REG_FIFO_STATUS
static constexpr uint8_t QMI8658_REG_TEMPERATURE_H
bool disableAccelerometer()
Disable the accelerometer.
static constexpr uint8_t QMI8658_REG_CTRL3
static constexpr uint8_t QMI8658_REG_TAP_STATUS
constexpr uint32_t _bv(uint8_t b)
Definition SensorLib.h:62
constexpr uint8_t _lowByte(uint16_t w)
Definition SensorLib.h:69
constexpr uint8_t _highByte(uint16_t w)
Definition SensorLib.h:73
uint8_t i
IMUdata gyro[buffer_size]
uint16_t tapWindow
uint8_t peakWindow
int16_t x[5]
int16_t y[5]