SensorLib 0.5.1
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 hal->delay(2); // chip NACKs while it is resetting. https://github.com/lewisxhe/SensorLib/issues/46
261 // Maximum 15ms for the Reset process to be finished
262 if (waitResult) {
263 uint32_t start = hal->millis();
264 while (hal->millis() - start < timeout) {
265 val = comm->readRegister(QMI8658_REG_RST_RESULT);
266 if (val != -1 && val == QMI8658_REG_RST_RESULT_VAL) {
267
268 //EN.ADDR_AI
269 comm->setRegisterBit(QMI8658_REG_CTRL1, 6);
270
271 return true;
272 }
273 hal->delay(10);
274 }
275 SENSORLIB_LOG_E("Reset chip failed, Response val = %d - 0x%X", val, val);
276 return false;
277 }
278
279 //EN.ADDR_AI
280 comm->setRegisterBit(QMI8658_REG_CTRL1, 6);
281
282 return true;
283 }
284
289 uint8_t getChipID()
290 {
291 return comm->readRegister(QMI8658_REG_REVISION);
292 }
293
299 int whoAmI()
300 {
301 return comm->readRegister(QMI8658_REG_WHOAMI);
302 }
303
309 uint32_t getTimestamp()
310 {
311 uint8_t buffer[3];
312 uint32_t timestamp;
313 if (comm->readRegister(QMI8658_REG_TIMESTAMP_L, buffer, 3) != -1) {
314 timestamp = (uint32_t)(((uint32_t)buffer[2] << 16) |
315 ((uint32_t)buffer[1] << 8) | buffer[0]);
316 if (timestamp > lastTimestamp) {
317 lastTimestamp = timestamp;
318 } else {
319 lastTimestamp = (timestamp + 0x1000000 - lastTimestamp);
320 }
321 }
322 return lastTimestamp;
323 }
324
330 {
331 uint8_t buffer[2];
332 if (comm->readRegister(QMI8658_REG_TEMPERATURE_L, buffer, 2) != -1) {
333 return (float)buffer[1] + ((float)buffer[0] / 256.0);
334 }
335 return NAN;
336 }
337
343 void enableINT(IntPin pin, bool enable = true)
344 {
345 switch (pin) {
346 case INTERRUPT_PIN_1:
347 enable ? comm->setRegisterBit(QMI8658_REG_CTRL1, 3) : comm->clrRegisterBit(QMI8658_REG_CTRL1, 3);
348 _irq_enable_mask = enable ? _irq_enable_mask | 0x01 : _irq_enable_mask & 0xFE;
349 break;
350 case INTERRUPT_PIN_2:
351 enable ? comm->setRegisterBit(QMI8658_REG_CTRL1, 4) : comm->clrRegisterBit(QMI8658_REG_CTRL1, 4);
352 _irq_enable_mask = enable ? _irq_enable_mask | 0x02 : _irq_enable_mask & 0xFD;
353 break;
354 default:
355 break;
356 }
357 }
358
364 uint8_t getIrqStatus()
365 {
366 return comm->readRegister(QMI8658_REG_STATUS_INT);
367 }
368
373 void enableDataReadyINT(bool enable = true)
374 {
375 enable ? comm->clrRegisterBit(QMI8658_REG_CTRL7, 5) :
376 comm->setRegisterBit(QMI8658_REG_CTRL7, 5);
377 }
378
387 {
388 bool en = isEnableAccelerometer();
389
390 if (en) {
392 }
393
394 //setAccelRange
395 if (comm->writeRegister(QMI8658_REG_CTRL2, 0x8F, (range << 4)) != 0) {
396 return false;
397 }
398
399 switch (range) {
400 // Possible accelerometer scales (and their register bit settings) are:
401 // 2 Gs (00), 4 Gs (01), 8 Gs (10), and 16 Gs (11).
402 // Here's a bit of an algorithm to calculate DPS/(ADC tick) based on that
403 // 2-bit value:
404 case ACC_RANGE_2G:
405 accelScales = 2.0 / 32768.0;
406 break;
407 case ACC_RANGE_4G:
408 accelScales = 4.0 / 32768.0;
409 break;
410 case ACC_RANGE_8G:
411 accelScales = 8.0 / 32768.0;
412 break;
413 case ACC_RANGE_16G:
414 accelScales = 16.0 / 32768.0;
415 break;
416 }
417
418 // setAccelOutputDataRate
419 if (comm->writeRegister(QMI8658_REG_CTRL2, 0xF0, odr) != 0) {
420 return false;
421 }
422
423 if (lpfOdr != LPF_OFF) {
424 // setAccelLowPassFitterOdr
425 if (comm->writeRegister(QMI8658_REG_CTRL5, QMI8658_ACCEL_LPF_MASK, (lpfOdr << 1)) != 0) {
426 return false;
427 }
428 // Enable Low-Pass Fitter
429 comm->setRegisterBit(QMI8658_REG_CTRL5, 0);
430 } else {
431 // Disable Low-Pass Fitter
432 comm->clrRegisterBit(QMI8658_REG_CTRL5, 0);
433 }
434
435 // setAccelSelfTest
436 // selfTest ? comm->setRegisterBit(QMI8658_REG_CTRL2, 7) : comm->clrRegisterBit(QMI8658_REG_CTRL2, 7);
437
438 if (en) {
440 }
441
442 return true;
443 }
444
445
455 {
456 bool en = isEnableGyroscope();
457
458 if (en) {
460 }
461
462 // setGyroRange
463 if (comm->writeRegister(QMI8658_REG_CTRL3, 0x8F, (range << 4)) != 0) {
464 return false;
465 }
466
467 switch (range) {
468 // Possible gyro scales (and their register bit settings) are:
469 // 250 DPS (00), 500 DPS (01), 1000 DPS (10), and 2000 DPS (11).
470 // Here's a bit of an algorithm to calculate DPS/(ADC tick) based on that
471 // 2-bit value:
472 case GYR_RANGE_16DPS:
473 gyroScales = 16.0 / 32768.0;
474 break;
475 case GYR_RANGE_32DPS:
476 gyroScales = 32.0 / 32768.0;
477 break;
478 case GYR_RANGE_64DPS:
479 gyroScales = 64.0 / 32768.0;
480 break;
481 case GYR_RANGE_128DPS:
482 gyroScales = 128.0 / 32768.0;
483 break;
484 case GYR_RANGE_256DPS:
485 gyroScales = 256.0 / 32768.0;
486 break;
487 case GYR_RANGE_512DPS:
488 gyroScales = 512.0 / 32768.0;
489 break;
491 gyroScales = 1024.0 / 32768.0;
492 break;
493 }
494
495 // setGyroOutputDataRate
496 if (comm->writeRegister(QMI8658_REG_CTRL3, 0xF0, odr) != 0) {
497 return false;
498 }
499
500 // setGyroLowPassFitterOdr
501 if (lpfOdr != LPF_OFF) {
502 if (comm->writeRegister(QMI8658_REG_CTRL5, QMI8658_GYRO_LPF_MASK, (lpfOdr << 5)) != 0) {
503 return false;
504 }
505 // Enable Low-Pass Fitter
506 comm->setRegisterBit(QMI8658_REG_CTRL5, 4);
507 } else {
508 // Disable Low-Pass Fitter
509 comm->clrRegisterBit(QMI8658_REG_CTRL5, 4);
510 }
511
512 // setGyroSelfTest
513 // selfTest ? comm->setRegisterBit(QMI8658_REG_CTRL3, 7) : comm->clrRegisterBit(QMI8658_REG_CTRL3, 7);
514
515 if (en) {
517 }
518
519 return true;
520 }
521
532 IntPin pin = INTERRUPT_PIN_DISABLE, uint8_t trigger_samples = 16)
533 {
534 bool enGyro = isEnableGyroscope();
535 bool enAccel = isEnableAccelerometer();
536
537 if (enGyro) {
539 }
540
541 if (enAccel) {
543 }
544
545 // Reset FIFO configure
547 SENSORLIB_LOG_E("Reset fifo failed!");
548 return false;
549 }
550
551 _fifo_interrupt = true;
552
553 switch (pin) {
554 case INTERRUPT_PIN_1:
555 comm->setRegisterBit(QMI8658_REG_CTRL1, 2);
556 break;
557 case INTERRUPT_PIN_2:
558 comm->clrRegisterBit(QMI8658_REG_CTRL1, 2);
559 break;
561 // Saves whether the fifo interrupt pin is enabled
562 _fifo_interrupt = false;
563 break;
564 default:
565 break;
566 }
567
568 // Set fifo mode and samples len
569 _fifo_mode = (samples << 2) | mode;
570 if (comm->writeRegister(QMI8658_REG_FIFO_CTRL, _fifo_mode) == -1) {
571 return false;
572 }
573
574 /*
575 * The FIFO_WTM register(0x13) indicates the expected level of FIFO data that host wants to get the FIFO Watermark interrupt.
576 * The unit is sample, which means 6 bytes if one of accelerometer and gyroscope is enabled, and 12 bytes if both are enabled.
577 * */
578 if (comm->writeRegister(QMI8658_REG_FIFO_WTM_TH, trigger_samples ) == -1) {
579 return false;
580 }
581
582 if (enGyro) {
584 }
585
586 if (enAccel) {
588 }
589
590 int res = comm->readRegister(QMI8658_REG_FIFO_CTRL);
591 SENSORLIB_LOG_D("QMI8658_REG_FIFO_CTRL : 0x%X", res);
592 if ((res & 0x02) == 0x02) {
593 SENSORLIB_LOG_D("Enabled Stream mode.");
594 } else if ((res & 0x01) == 0x01) {
595 SENSORLIB_LOG_D("Enabled FIFO mode.");
596 } else if ((res & 0x03) == 0x00) {
597 SENSORLIB_LOG_D("Disabled FIFO.");
598 }
599 res >>= 2;
600 if ((res & 0x03) == 0x03) {
601 SENSORLIB_LOG_D("128 samples.");
602 } else if ((res & 0x02) == 0x02) {
603 SENSORLIB_LOG_D("64 samples.");
604 } else if ((res & 0x01) == 0x01) {
605 SENSORLIB_LOG_D("32 samples.");
606 } else if ((res & 0x03) == 0x00) {
607 SENSORLIB_LOG_D("16 samples.");
608 }
609
610 return true;
611 }
612
622 uint16_t readFromFifo(IMUdata *acc, uint16_t accLength, IMUdata *gyro, uint16_t gyrLength)
623 {
625 SENSORLIB_LOG_E("FIFO is not configured.");
626 return 0;
627 }
628
629 if (!_gyro_enabled && !_accel_enabled) {
630 SENSORLIB_LOG_E("Sensor not enabled.");
631 return 0;
632 }
633
634 uint16_t data_bytes = readFromFifo();
635 if (data_bytes == 0) {
636 return 0;
637 }
638
639 if (!fifo_buffer) {
640 SENSORLIB_LOG_E("FIFO buffer is NULL");
641 return 0;
642 }
643
644 uint8_t enabled_sensor_count = (_accel_enabled && _gyro_enabled) ? 2 : 1;
645 uint16_t samples_per_sensor = data_bytes / (6 * enabled_sensor_count);
646 uint16_t total_samples = samples_per_sensor * enabled_sensor_count;
647
648 SENSORLIB_LOG_D("Total samples: %u", total_samples);
649
650 uint16_t accel_index = 0;
651 uint16_t gyro_index = 0;
652
653 for (uint16_t i = 0; i < total_samples; ++i) {
654 auto data = reinterpret_cast < int16_t * > (&fifo_buffer[i * 6]);
655 int16_t x = data[0];
656 int16_t y = data[1];
657 int16_t z = data[2];
658
660 if (i % 2 == 0) {
661 // Accel
662 if (accel_index < accLength) {
663 acc[accel_index].x = x * accelScales;
664 acc[accel_index].y = y * accelScales;
665 acc[accel_index].z = z * accelScales;
666 accel_index++;
667 }
668 } else {
669 // Gyro
670 if (gyro_index < gyrLength) {
671 gyro[gyro_index].x = x * gyroScales;
672 gyro[gyro_index].y = y * gyroScales;
673 gyro[gyro_index].z = z * gyroScales;
674 gyro_index++;
675 }
676 }
677 } else if (_accel_enabled) {
678 if (accel_index < accLength) {
679 acc[accel_index].x = x * accelScales;
680 acc[accel_index].y = y * accelScales;
681 acc[accel_index].z = z * accelScales;
682 accel_index++;
683 }
684 } else if (_gyro_enabled) {
685 if (gyro_index < gyrLength) {
686 gyro[gyro_index].x = x * gyroScales;
687 gyro[gyro_index].y = y * gyroScales;
688 gyro[gyro_index].z = z * gyroScales;
689 gyro_index++;
690 }
691 }
692 }
693 return samples_per_sensor;
694 }
695
702 {
703 if (comm->setRegisterBit(QMI8658_REG_CTRL7, 0)) {
704 _accel_enabled = true;
705 }
706 return _accel_enabled;
707 }
708
715 {
716 if (comm->clrRegisterBit(QMI8658_REG_CTRL7, 0)) {
717 _accel_enabled = false;
718 return true;
719 }
720 return false;
721 }
722
729 {
730 return _accel_enabled;
731 }
732
739 {
740 return _gyro_enabled;
741 }
742
749 {
750 if (comm->setRegisterBit(QMI8658_REG_CTRL7, 1)) {
751 _gyro_enabled = true;
752 }
753 return _gyro_enabled;
754 }
755
762 {
763 if (comm->clrRegisterBit(QMI8658_REG_CTRL7, 1)) {
764 _gyro_enabled = false;
765 return true;
766 }
767 return false;
768 }
769
776 bool getAccelRaw(int16_t *rawBuffer)
777 {
778 if (!_accel_enabled) {
779 return false;
780 }
781 uint8_t buffer[6] = {0};
782 if (comm->readRegister(QMI8658_REG_AX_L, buffer, 6) != -1) {
783 rawBuffer[0] = (int16_t)(buffer[1] << 8) | (buffer[0]);
784 rawBuffer[1] = (int16_t)(buffer[3] << 8) | (buffer[2]);
785 rawBuffer[2] = (int16_t)(buffer[5] << 8) | (buffer[4]);
786 } else {
787 return false;
788 }
789 return true;
790 }
791
800 bool getAccelerometer(float &x, float &y, float &z)
801 {
802 if (!_accel_enabled) {
803 return false;
804 }
805 int16_t raw[3];
806 if (getAccelRaw(raw)) {
807 x = raw[0] * accelScales;
808 y = raw[1] * accelScales;
809 z = raw[2] * accelScales;
810 return true;
811 }
812 return false;
813 }
814
821 {
822 return accelScales;
823 }
824
831 {
832 return gyroScales;
833 }
834
841 bool getGyroRaw(int16_t *rawBuffer)
842 {
843 if (!_gyro_enabled) {
844 return false;
845 }
846 uint8_t buffer[6] = {0};
847 if (comm->readRegister(QMI8658_REG_GX_L, buffer, 6) != -1) {
848 rawBuffer[0] = (int16_t)(buffer[1] << 8) | (buffer[0]);
849 rawBuffer[1] = (int16_t)(buffer[3] << 8) | (buffer[2]);
850 rawBuffer[2] = (int16_t)(buffer[5] << 8) | (buffer[4]);
851 } else {
852 return false;
853 }
854 return true;
855 }
856
865 bool getGyroscope(float &x, float &y, float &z)
866 {
867 if (!_gyro_enabled) {
868 return false;
869 }
870 int16_t raw[3];
871 if (getGyroRaw(raw)) {
872 x = raw[0] * gyroScales;
873 y = raw[1] * gyroScales;
874 z = raw[2] * gyroScales;
875 return true;
876 }
877 return false;
878 }
879
886 {
887 if ((_irq_enable_mask & 0x03) && (_irq != -1)) {
888 if (hal->digitalRead(_irq)) {
889 return false;
890 }
891 }
892
893 switch (sampleMode) {
894 case SYNC_MODE:
895 return comm->getRegisterBit(QMI8658_REG_STATUS_INT, 1);
896 case ASYNC_MODE:
897 //TODO: When Accel and Gyro are configured with different rates, this will always be false
899 return comm->readRegister(QMI8658_REG_STATUS0) & 0x03;
900 } else if (_gyro_enabled) {
901 return comm->readRegister(QMI8658_REG_STATUS0) & 0x02;
902 } else if (_accel_enabled) {
903 return comm->readRegister(QMI8658_REG_STATUS0) & 0x01;
904 }
905 break;
906 default:
907 break;
908 }
909 return false;
910 }
911
918 {
919 sampleMode = SYNC_MODE;
920 return comm->setRegisterBit(QMI8658_REG_CTRL7, 7);
921 }
922
929 {
930 sampleMode = ASYNC_MODE;
931 return comm->clrRegisterBit(QMI8658_REG_CTRL7, 7);
932 }
933
940 {
942 if (comm->writeRegister(QMI8658_REG_CAL1_L, 0x01) != 0) {
943 return false;
944 }
946 }
947
954 {
956 if (comm->writeRegister(QMI8658_REG_CAL1_L, (uint8_t)0x00) != 0) {
957 return -1;
958 }
960 }
961
968 {
969 uint8_t buffer[9];
970 comm->readRegister(QMI8658_REG_CTRL1, buffer, 9);
971 for (int i = 0; i < 9; ++i) {
972 SENSORLIB_LOG_D("CTRL%d: REG:0x%02X HEX:0x%02X\n", i + 1, QMI8658_REG_CTRL1 + i, buffer[i]);
973 }
974
975 buffer[0] = comm->readRegister(QMI8658_REG_FIFO_CTRL);
976 SENSORLIB_LOG_D("FIFO_CTRL: REG:0x%02X HEX:0x%02X\n", QMI8658_REG_FIFO_CTRL, buffer[0]);
977 }
978
985 {
988 comm->setRegisterBit(QMI8658_REG_CTRL1, 1);
989 }
990
991
997 void powerOn()
998 {
999 comm->clrRegisterBit(QMI8658_REG_CTRL1, 1);
1000 }
1001
1008 {
1009 return comm->readRegister(QMI8658_REG_STATUS1);
1010 }
1011
1018 {
1019 return pin == INTERRUPT_PIN_1 ? comm->setRegisterBit(QMI8658_REG_CTRL8, 6)
1020 : comm->clrRegisterBit(QMI8658_REG_CTRL8, 6);
1021 }
1022
1051 bool configPedometer(uint16_t ped_sample_cnt, uint16_t ped_fix_peak2peak, uint16_t ped_fix_peak,
1052 uint16_t ped_time_up, uint8_t ped_time_low = 0x14, uint8_t ped_time_cnt_entry = 0x0A, uint8_t ped_fix_precision = 0x00,
1053 uint8_t ped_sig_count = 0x04)
1054 {
1055 // The Pedometer can only work in Non-SyncSample mode
1057
1058 bool enGyro = isEnableGyroscope();
1059 bool enAccel = isEnableAccelerometer();
1060
1061 if (enGyro) {
1063 }
1064
1065 if (enAccel) {
1067 }
1068
1069 comm->writeRegister(QMI8658_REG_CAL1_L, ped_sample_cnt & 0xFF);
1070 comm->writeRegister(QMI8658_REG_CAL1_H, (ped_sample_cnt >> 8) & 0xFF);
1071 comm->writeRegister(QMI8658_REG_CAL2_L, ped_fix_peak2peak & 0xFF);
1072 comm->writeRegister(QMI8658_REG_CAL2_H, (ped_fix_peak2peak >> 8) & 0xFF);
1073 comm->writeRegister(QMI8658_REG_CAL3_L, ped_fix_peak & 0xFF);
1074 comm->writeRegister(QMI8658_REG_CAL3_H, (ped_fix_peak >> 8) & 0xFF);
1075 comm->writeRegister(QMI8658_REG_CAL4_H, 0x01);
1076 comm->writeRegister(QMI8658_REG_CAL4_L, 0x02);
1077
1079
1080 comm->writeRegister(QMI8658_REG_CAL1_L, ped_time_up & 0xFF);
1081 comm->writeRegister(QMI8658_REG_CAL1_H, (ped_time_up >> 8) & 0xFF);
1082 comm->writeRegister(QMI8658_REG_CAL2_L, ped_time_low);
1083 comm->writeRegister(QMI8658_REG_CAL2_H, ped_time_cnt_entry);
1084 comm->writeRegister(QMI8658_REG_CAL3_L, ped_fix_precision);
1085 comm->writeRegister(QMI8658_REG_CAL3_H, ped_sig_count);
1086 comm->writeRegister(QMI8658_REG_CAL4_H, 0x02);
1087 comm->writeRegister(QMI8658_REG_CAL4_L, 0x02);
1088
1090
1091 if (enGyro) {
1093 }
1094
1095 if (enAccel) {
1097 }
1098 return true;
1099 }
1100
1107 {
1108 uint8_t buffer[3];
1109 if (comm->readRegister(QMI8658_REG_STEP_CNT_LOW, buffer, 3) != -1) {
1110 return (uint32_t)(((uint32_t)buffer[2] << 16) | ((uint32_t)buffer[1] << 8) | buffer[0]);
1111 }
1112 return 0;
1113 }
1114
1121 {
1123 }
1124
1132 {
1133 if (!_accel_enabled)return false;
1134
1135 switch (pin) {
1136 case INTERRUPT_PIN_1:
1137 case INTERRUPT_PIN_2:
1139 enableINT(pin);
1140 break;
1141 default:
1142 break;
1143 }
1144 return comm->setRegisterBit(QMI8658_REG_CTRL8, 4);
1145 }
1146
1148 {
1149 if (!_accel_enabled)return false;
1150 return comm->clrRegisterBit(QMI8658_REG_CTRL8, 4);
1151 }
1152
1153
1154
1186 bool configTap(uint8_t priority, uint8_t peakWindow, uint16_t tapWindow, uint16_t dTapWindow,
1187 float alpha, float gamma, float peakMagThr, float UDMThr)
1188 {
1189
1190 // The Tap detection can only work in Non-SyncSample mode
1191 if (!disableSyncSampleMode()) {
1192 return false;
1193 }
1194
1195 bool enGyro = isEnableGyroscope();
1196 bool enAccel = isEnableAccelerometer();
1197
1198 if (enGyro) {
1200 }
1201
1202 if (enAccel) {
1204 }
1205 comm->writeRegister(QMI8658_REG_CAL1_L, peakWindow);
1206 comm->writeRegister(QMI8658_REG_CAL1_H, priority);
1207 comm->writeRegister(QMI8658_REG_CAL2_L, tapWindow & 0xFF);
1208 comm->writeRegister(QMI8658_REG_CAL2_H, (tapWindow >> 8) & 0xFF);
1209 comm->writeRegister(QMI8658_REG_CAL3_L, dTapWindow & 0xFF);
1210 comm->writeRegister(QMI8658_REG_CAL3_H, (dTapWindow >> 8) & 0xFF);
1211 // comm->writeRegister(QMI8658_REG_CAL4_L, 0x02);
1212 comm->writeRegister(QMI8658_REG_CAL4_H, 0x01);
1213
1215
1216 // 1-byte unsigned,7-bits fraction
1217 uint8_t alphaHex = (uint8_t)(alpha * 128);
1218 comm->writeRegister(QMI8658_REG_CAL1_L, alphaHex);
1219
1220 // 1-byte unsigned,7-bits fraction
1221 uint8_t gammaHex = (uint8_t)(gamma * 128);
1222 comm->writeRegister(QMI8658_REG_CAL1_H, gammaHex);
1223
1224 const double g = 9.81; // Earth's gravitational acceleration m/s^2
1225 double resolution = 0.001 * g * g; // Calculation resolution 0.001g^2
1226
1227 double acceleration_square = peakMagThr * g * g; // Calculate the square of the acceleration
1228 uint16_t value = (uint16_t)(acceleration_square / resolution); // Calculates the value of a 2-byte unsigned integer
1229
1230 comm->writeRegister(QMI8658_REG_CAL2_L, sensorlib::_lowByte(value));
1231 comm->writeRegister(QMI8658_REG_CAL2_H, sensorlib::_highByte(value));
1232
1233 acceleration_square = UDMThr * g * g; // Calculate the square of the acceleration
1234 value = (uint16_t)(acceleration_square / resolution); // Calculates the value of a 2-byte unsigned integer
1235
1236 comm->writeRegister(QMI8658_REG_CAL3_L, sensorlib::_lowByte(value));
1237 comm->writeRegister(QMI8658_REG_CAL3_H, sensorlib::_highByte(value));
1238 // comm->writeRegister(QMI8658_REG_CAL4_L, 0x02);
1239 comm->writeRegister(QMI8658_REG_CAL4_H, 0x02);
1240
1242
1243 if (enGyro) {
1245 }
1246
1247 if (enAccel) {
1249 }
1250
1251 return true;
1252 }
1253
1261 {
1262 if (!_accel_enabled)return false;
1263 switch (pin) {
1264 case INTERRUPT_PIN_1:
1265 case INTERRUPT_PIN_2:
1267 enableINT(pin);
1268 break;
1269 default:
1270 break;
1271 }
1272 return comm->setRegisterBit(QMI8658_REG_CTRL8, 0);
1273 }
1274
1281 {
1282 return comm->clrRegisterBit(QMI8658_REG_CTRL8, 0);
1283 }
1284
1291 {
1292 int val = comm->readRegister(QMI8658_REG_TAP_STATUS);
1293 if (val & sensorlib::_bv(7)) {
1294 SENSORLIB_LOG_I("Tap was detected on the negative direction of the Tap axis");
1295 } else {
1296 SENSORLIB_LOG_I("Tap was detected on the positive direction of the Tap axis");
1297 }
1298 uint8_t t = (val >> 4) & 0x03;
1299 switch (t) {
1300 case 0:
1301 SENSORLIB_LOG_I("No Tap was detected");
1302 break;
1303 case 1:
1304 SENSORLIB_LOG_I("Tap was detected on X axis");
1305 break;
1306 case 2:
1307 SENSORLIB_LOG_I("Tap was detected on Y axis");
1308 break;
1309 case 3:
1310 SENSORLIB_LOG_I("Tap was detected on Z axis");
1311 break;
1312 default:
1313 break;
1314 }
1315 t = val & 0x03;
1316 switch (t) {
1317 case 0:
1318 SENSORLIB_LOG_I("No Tap was detected");
1319 return INVALID_TAP;
1320 case 1:
1321 SENSORLIB_LOG_I("Single-Tap was detected");
1322 return SINGLE_TAP;
1323 case 2:
1324 SENSORLIB_LOG_I("Double-Tap was detected");
1325 return DOUBLE_TAP;
1326 default:
1327 break;
1328 }
1329 return INVALID_TAP;
1330 }
1331
1332
1333 //TODO:Need Test
1335 //* See enum MotionCtrl
1336 uint8_t modeCtrl,
1337 //* Define the slope threshold of the x-axis for arbitrary motion detection
1338 float AnyMotionXThr,
1339 //* Define the slope threshold of the y-axis for arbitrary motion detection
1340 float AnyMotionYThr,
1341 //* Define the slope threshold of the z-axis for arbitrary motion detection
1342 float AnyMotionZThr,
1343 //* Defines the minimum number of consecutive samples (duration) that the absolute
1344 //* of the slope of the enabled axis/axes data should keep higher than the threshold
1345 uint8_t AnyMotionWindow,
1346 //* Defines the slope threshold of the x-axis for no motion detection
1347 float NoMotionXThr,
1348 //* Defines the slope threshold of the y-axis for no motion detection
1349 float NoMotionYThr,
1350 //* Defines the slope threshold of the z-axis for no motion detection
1351 float NoMotionZThr,
1352 //* Defines the minimum number of consecutive samples (duration) that the absolute
1353 //* of the slope of the enabled axis/axes data should keep lower than the threshold
1354 uint8_t NoMotionWindow,
1355 //* Defines the wait window (idle time) starts from the first Any-Motion event until
1356 //* starting to detecting another Any-Motion event form confirmation
1357 uint16_t SigMotionWaitWindow,
1358 //* Defines the maximum duration for detecting the other Any-Motion
1359 //* event to confirm Significant-Motion, starts from the first Any -Motion event
1360 uint16_t SigMotionConfirmWindow)
1361 {
1362 // Only work in Non-SyncSample mode
1363 if (!disableSyncSampleMode()) {
1364 return false;
1365 }
1366
1367 bool enGyro = isEnableGyroscope();
1368 bool enAccel = isEnableAccelerometer();
1369
1370 if (enGyro) {
1372 }
1373
1374 if (enAccel) {
1376 }
1377
1378 comm->writeRegister(QMI8658_REG_CAL1_L, mgToBytes(AnyMotionXThr));
1379 comm->writeRegister(QMI8658_REG_CAL1_H, mgToBytes(AnyMotionYThr));
1380 comm->writeRegister(QMI8658_REG_CAL2_L, mgToBytes(AnyMotionZThr));
1381 comm->writeRegister(QMI8658_REG_CAL2_H, mgToBytes(NoMotionXThr));
1382 comm->writeRegister(QMI8658_REG_CAL3_L, mgToBytes(NoMotionYThr));
1383 comm->writeRegister(QMI8658_REG_CAL3_H, mgToBytes(NoMotionZThr));
1384 comm->writeRegister(QMI8658_REG_CAL4_L, modeCtrl);
1385 comm->writeRegister(QMI8658_REG_CAL4_H, 0x01);
1386
1388
1389 comm->writeRegister(QMI8658_REG_CAL1_L, AnyMotionWindow);
1390 comm->writeRegister(QMI8658_REG_CAL1_H, NoMotionWindow);
1391 comm->writeRegister(QMI8658_REG_CAL2_L, sensorlib::_lowByte(SigMotionWaitWindow));
1392 comm->writeRegister(QMI8658_REG_CAL2_H, sensorlib::_highByte(SigMotionWaitWindow));
1393 comm->writeRegister(QMI8658_REG_CAL3_L, sensorlib::_lowByte(SigMotionConfirmWindow));
1394 comm->writeRegister(QMI8658_REG_CAL3_H, sensorlib::_highByte(SigMotionConfirmWindow));
1395 // comm->writeRegister(QMI8658_REG_CAL4_L, 0x02);
1396 comm->writeRegister(QMI8658_REG_CAL4_H, 0x02);
1397
1399
1400 if (enGyro) {
1402 }
1403
1404 if (enAccel) {
1406 }
1407 return true;
1408 }
1409
1417 {
1418 if (!_accel_enabled)return false;
1419 switch (pin) {
1420 case INTERRUPT_PIN_1:
1421 case INTERRUPT_PIN_2:
1423 enableINT(pin);
1424 break;
1425 default:
1426 break;
1427 }
1428 comm->setRegisterBit(QMI8658_REG_CTRL8, 1);
1429 comm->setRegisterBit(QMI8658_REG_CTRL8, 2);
1430 comm->setRegisterBit(QMI8658_REG_CTRL8, 3);
1431 return true;
1432 }
1433
1440 {
1441 comm->clrRegisterBit(QMI8658_REG_CTRL8, 1);
1442 comm->clrRegisterBit(QMI8658_REG_CTRL8, 2);
1443 comm->clrRegisterBit(QMI8658_REG_CTRL8, 3);
1444 return false;
1445 }
1446
1447
1466 bool configWakeOnMotion(uint8_t WoMThreshold = 200,
1468 IntPin pin = INTERRUPT_PIN_2,
1469 uint8_t defaultPinValue = 1,
1470 uint8_t blankingTime = 0x20,
1471 AccelRange accRange = ACC_RANGE_8G)
1472 {
1473
1474 uint8_t val = 0;
1475
1476 // Reset default value
1477 if (!reset()) {
1478 return false;
1479 }
1480
1481 // Disable sensors
1482 comm->clrRegisterBit(QMI8658_REG_CTRL7, 0);
1483
1484 // SetAccelRange
1485 if (comm->writeRegister(QMI8658_REG_CTRL2, 0x8F, (accRange << 4)) != 0) {
1486 return false;
1487 }
1488
1489 // setAccelOutputDataRate
1490 if (comm->writeRegister(QMI8658_REG_CTRL2, 0xF0, odr) != 0) {
1491 return false;
1492 }
1493
1494 // Set wom
1495 if (comm->writeRegister(QMI8658_REG_CAL1_L, WoMThreshold) != 0) {
1496 return false;
1497 }
1498
1499 if ( pin == INTERRUPT_PIN_1) {
1500 val = defaultPinValue ? 0x02 : 0x00;
1501 } else if (pin == INTERRUPT_PIN_2) {
1502 val = defaultPinValue ? 0x03 : 0x01;
1503 }
1504
1505 val <<= 6;
1506 val |= (blankingTime & 0x3F);
1507 if (comm->writeRegister(QMI8658_REG_CAL1_H, val) != 0) {
1508 return false;
1509 }
1510
1512 return false;
1513 }
1514
1516
1517 enableINT(pin);
1518
1519 return true;
1520 }
1521
1522
1529 void getChipUsid(uint8_t *buffer, uint8_t length)
1530 {
1531 if (length > 6) {
1532 length = 6;
1533 }
1534 memcpy(buffer, usid, length);
1535 }
1536
1537
1544 {
1545 return revisionID;
1546 }
1547
1553 uint16_t update()
1554 {
1555 uint16_t result = 0;
1556 // STATUSINT 0x2D
1557 // STATUS0 0x2E
1558 // STATUS1 0x2F
1559 uint8_t status[3];
1560 if (comm->readRegister(QMI8658_REG_STATUS_INT, status, 3) != 0) {
1561 return 0;
1562 }
1563
1564 // SENSORLIB_LOG_I("STATUSINT:0x%X BIN:", status[0]);
1565 // SENSORLIB_LOG_I("STATUS0:0x%X BIN:", status[1]);
1566 // SENSORLIB_LOG_I("STATUS1:0x%X BIN:", status[2]);
1567 // SENSORLIB_LOG_I("------------------\n");
1568
1569 // Ctrl9 CmdDone
1570 // Indicates CTRL9 Command was done, as part of CTRL9 protocol
1571 // 0: Not Completed
1572 // 1: Done
1573 if (status[0] & 0x80) {
1574 result |= STATUS_INT_CTRL9_CMD_DONE;
1575 }
1576 // If syncSample (CTRL7.bit7) = 1:
1577 // 0: Sensor Data is not locked.
1578 // 1: Sensor Data is locked.
1579 // If syncSample = 0, this bit shows the same value of INT1 level
1580 if (status[0] & 0x02) {
1581 result |= STATUS_INT_LOCKED;
1582 }
1583 // If syncSample (CTRL7.bit7) = 1:
1584 // 0: Sensor Data is not available
1585 // 1: Sensor Data is available for reading
1586 // If syncSample = 0, this bit shows the same value of INT2 level
1587 if (status[0] & 0x01) {
1588 result |= STATUS_INT_AVAIL;
1589 // if (eventGyroDataReady)eventGyroDataReady();
1590 // if (eventAccelDataReady)eventAccelDataReady();
1591 }
1592
1593 //Locking Mechanism Can reading..
1594 if ((status[0] & 0x03) == 0x03) {
1595 if (eventDataLocking)eventDataLocking();
1596 }
1597
1598 //=======================================
1599 // Valid only in asynchronous mode
1600 if (sampleMode == ASYNC_MODE) {
1601 // Gyroscope new data available
1602 // 0: No updates since last read.
1603 // 1: New data available
1604 if (status[1] & 0x02) {
1605 result |= STATUS0_GYRO_DATA_READY;
1606 if (eventGyroDataReady)eventGyroDataReady();
1607 _gDataReady = true;
1608 }
1609 // Accelerometer new data available
1610 // 0: No updates since last read.
1611 // 1: New data available.
1612 if (status[1] & 0x01) {
1613 result |= STATUS0_ACCEL_DATA_READY;
1614 if (eventAccelDataReady)eventAccelDataReady();
1615 _aDataReady = true;
1616 }
1617 }
1618
1619 //=======================================
1620 // Significant Motion
1621 // 0: No Significant-Motion was detected
1622 // 1: Significant-Motion was detected
1623 if (status[2] & 0x80) {
1625 if (eventSignificantMotion)eventSignificantMotion();
1626 }
1627 // No Motion
1628 // 0: No No-Motion was detected
1629 // 1: No-Motion was detected
1630 if (status[2] & 0x40) {
1631 result |= STATUS1_NO_MOTION;
1632 if (eventNoMotionEvent)eventNoMotionEvent();
1633 }
1634 // Any Motion
1635 // 0: No Any-Motion was detected
1636 // 1: Any-Motion was detected
1637 if (status[2] & 0x20) {
1638 result |= STATUS1_ANY_MOTION;
1639 if (eventAnyMotionEvent)eventAnyMotionEvent();
1640 }
1641 // Pedometer
1642 // 0: No step was detected
1643 // 1: step was detected
1644 if (status[2] & 0x10) {
1645 result |= STATUS1_PEDOMETER_MOTION;
1646 if (eventPedometerEvent)eventPedometerEvent();
1647 }
1648 // WoM
1649 // 0: No WoM was detected
1650 // 1: WoM was detected
1651 if (status[2] & 0x04) {
1652 result |= STATUS1_WOM_MOTION;
1653 if (eventWomEvent)eventWomEvent();
1654 }
1655 // TAP
1656 // 0: No Tap was detected
1657 // 1: Tap was detected
1658 if (status[2] & 0x02) {
1659 result |= STATUS1_TAP_MOTION;
1660 if (eventTagEvent)eventTagEvent();
1661 }
1662 return result;
1663 }
1664
1666 {
1667 eventWomEvent = cb;
1668 }
1669
1671 {
1672 eventTagEvent = cb;
1673 }
1674
1676 {
1677 eventPedometerEvent = cb;
1678 }
1679
1681 {
1682 eventNoMotionEvent = cb;
1683 }
1684
1686 {
1687 eventAnyMotionEvent = cb;
1688 }
1689
1691 {
1692 eventSignificantMotion = cb;
1693 }
1694
1696 {
1697 eventGyroDataReady = cb;
1698 }
1699
1701 {
1702 eventAccelDataReady = cb;
1703 }
1704
1706 {
1707 eventDataLocking = cb;
1708 }
1709
1710
1719 bool calibration(uint16_t *gX_gain = NULL, uint16_t *gY_gain = NULL, uint16_t *gZ_gain = NULL)
1720 {
1721 // 1.Set CTRL7.aEN = 0 and CTRL7.gEN = 0, to disable the accelerometer and gyroscope.
1722 if (comm->writeRegister(QMI8658_REG_CTRL7, (uint8_t)0x00) != 0) {
1723 return false;
1724 }
1725
1726 // 2.Issue the CTRL_CMD_ON_DEMAND_CALIBRATION (0xA2) by CTRL9 command.
1728 return false;
1729 }
1730
1731 // 3.And wait about 1.5 seconds for QMI8658A to finish the CTRL9 command.
1732 hal->delay(1600);
1733
1734 // 4.Read the COD_STATUS register (0x46) to check the result/status of the COD implementation.
1735 int result = comm->readRegister(QMI8658_REG_COD_STATUS);
1736
1737 if (result == -1)return false;
1738
1739 // During the process, it is recommended to place the device in quiet, otherwise, the COD might fail and report error.
1740
1741 if (result & sensorlib::_bv(7)) {
1742 SENSORLIB_LOG_E("COD failed for checking low sensitivity limit of X axis of gyroscope");
1743 return false;
1744 }
1745 if (result & sensorlib::_bv(6)) {
1746 SENSORLIB_LOG_E("COD failed for checking high sensitivity limit of X axis of gyroscope");
1747 return false;
1748 }
1749 if (result & sensorlib::_bv(5)) {
1750 SENSORLIB_LOG_E("COD failed for checking low sensitivity limit of Y axis of gyroscope");
1751 return false;
1752 }
1753 if (result & sensorlib::_bv(4)) {
1754 SENSORLIB_LOG_E("COD failed for checking high sensitivity limit of Y axis of gyroscope");
1755 return false;
1756 }
1757 if (result & sensorlib::_bv(3)) {
1758 SENSORLIB_LOG_E("Accelerometer checked failed (significant vibration happened during COD)");
1759 return false;
1760 }
1761 if (result & sensorlib::_bv(2)) {
1762 SENSORLIB_LOG_E("Gyroscope startup failure happened when COD was called");
1763 return false;
1764 }
1765 if (result & sensorlib::_bv(1)) {
1766 SENSORLIB_LOG_E("COD was called while gyroscope was enabled, COD return failure");
1767 return false;
1768 }
1769 if (result & sensorlib::_bv(0)) {
1770 SENSORLIB_LOG_E("COD failed; no COD correction applied");
1771 return false;
1772 }
1773 SENSORLIB_LOG_D("All calibrations are completed");
1774
1775 if (gX_gain && gY_gain && gZ_gain) {
1776 uint8_t rawBuffer[6] = {0};
1777 if (comm->readRegister(QMI8658_REG_DVX_L, rawBuffer, 6) != 0) {
1778 return false;
1779 }
1780 *gX_gain = ((uint16_t)rawBuffer[0]) | (uint16_t)(rawBuffer[1] << 8);
1781 *gY_gain = ((uint16_t)rawBuffer[2]) | (uint16_t)(rawBuffer[3] << 8);
1782 *gZ_gain = ((uint16_t)rawBuffer[4]) | (uint16_t)(rawBuffer[5] << 8);
1783 }
1784
1785 return true;
1786 }
1787
1788
1797 bool writeCalibration(uint16_t gX_gain, uint16_t gY_gain, uint16_t gZ_gain)
1798 {
1799 // 1. Disable Accelerometer and Gyroscope by setting CTRL7.aEN = 0 and CTRL7.gEN = 0
1800 if (comm->writeRegister(QMI8658_REG_CTRL7, (uint8_t)0x00) != 0) {
1801 return false;
1802 }
1803
1804 uint8_t buffer[] = {
1805 // 2. write Gyro-X gain (16 bits) to registers CAL1_L and CAL1_H registers (0x0B, 0x0C)
1806 sensorlib::_lowByte(gX_gain),
1807 sensorlib::_highByte(gX_gain),
1808 // 3. write Gyro-Y gain (16 bits) to registers CAL2_L and CAL2_H registers (0x0D, 0x0E)
1809 sensorlib::_lowByte(gY_gain),
1810 sensorlib::_highByte(gY_gain),
1811 // 4. write Gyro-Z gain (16 bits) to registers CAL3_L and CAL3_H registers (0x0F, 0x10)
1812 sensorlib::_lowByte(gZ_gain),
1813 sensorlib::_highByte(gZ_gain),
1814 };
1815
1816 comm->writeRegister(QMI8658_REG_CAL1_L, buffer, sizeof(buffer));
1817
1818 // 5. Write 0xAA to CTRL9 and follow CTRL9 protocol
1819 if (writeCommand(CTRL_CMD_APPLY_GYRO_GAINS, 3000) != 0) {
1820 return false;
1821 }
1822
1823 return true;
1824 }
1825
1832 {
1833 // 1- Disable the sensors (CTRL7 = 0x00).
1834 if (comm->writeRegister(QMI8658_REG_CTRL7, (uint8_t)0x00) != 0) {
1835 return false;
1836 }
1837
1838 // 2- Set proper accelerometer ODR (CTRL2.aODR) and bit CTRL2.aST (bit7) to 1 to trigger the Self-Test.
1839 if (comm->writeRegister(QMI8658_REG_CTRL2, 0xF0, ACC_ODR_1000Hz | 0x80) != 0) {
1840 return false;
1841 }
1842
1843 // 3- Wait for QMI8658A to drive INT2 to High, if INT2 is enabled (CTRL1.bit4 = 1), or STATUSINT.bit0 is set to 1.
1844 int retry = 50;
1845 int dataReady = 0x00;
1846 while (dataReady != 0x01) {
1847 uint8_t reg_var = comm->readRegister(QMI8658_REG_STATUS_INT);
1848 SENSORLIB_LOG_D("reg_var : %x", reg_var);
1849 dataReady = reg_var & 0x01;
1850 // dataReady = comm->readRegister(QMI8658_REG_STATUS_INT) & 0x01;
1851 hal->delay(20);
1852 if (--retry <= 0) {
1853 SENSORLIB_LOG_E("No response.");
1854 return false;
1855 }
1856 }
1857
1858 SENSORLIB_LOG_I("Data is ready for reading....");
1859
1860 //4- Set CTRL2.aST(bit7) to 0, to clear STATUSINT1.bit0 and/or INT2.
1861 comm->clrRegisterBit(QMI8658_REG_CTRL2, 7);
1862
1863 // 5- Check for QMI8658A drives INT2 back to Low, and sets STATUSINT1.bit0 to 0.
1864 retry = 50;
1865 while (dataReady == 0x01) {
1866 uint8_t reg_var = comm->readRegister(QMI8658_REG_STATUS_INT);
1867 SENSORLIB_LOG_D("reg_var : %x", reg_var);
1868 dataReady = (reg_var & 0x01);
1869 // dataReady = !(comm->readRegister(QMI8658_REG_STATUS_INT) & 0x01);
1870 hal->delay(20);
1871 if (--retry <= 0) {
1872 SENSORLIB_LOG_E("No response.");
1873 return false;
1874 }
1875 }
1876
1877 /*
1878 6- Read the Accel Self-Test result:
1879 X channel: dVX_L and dVX_H (registers 0x51 and 0x52)
1880 Y channel: dVY_L and dVY_H (registers 0x53 and 0x54)
1881 Z channel: dVZ_L and dVZ_H (registers 0x55 and 0x56)
1882 The results are 16-bits in format signed U5.11, resolution 0.5mg (1 / 2^11 g).
1883 */
1884 uint8_t rawBuffer[6];
1885
1886 if (comm->readRegister(QMI8658_REG_DVX_L, rawBuffer, 6) != 0) {
1887 return false;
1888 }
1889
1890 int16_t dVX = (int16_t)(rawBuffer[0]) | (int16_t)(((int16_t)rawBuffer[1]) << 8);
1891 int16_t dVY = (int16_t)(rawBuffer[2]) | (int16_t)(((int16_t)rawBuffer[3]) << 8);
1892 int16_t dVZ = (int16_t)(rawBuffer[4]) | (int16_t)(((int16_t)rawBuffer[5]) << 8);
1893
1894 // To convert to mg, considering the U5.11 format, we need to divide by (2^11) to get the actual mg value
1895 float dVX_mg = dVX * 0.5; // 0.5mg is the smallest unit of this format
1896 float dVY_mg = dVY * 0.5;
1897 float dVZ_mg = dVZ * 0.5;
1898
1899 SENSORLIB_LOG_D("\n\tdVX_mg:%05.11f \n\tdVY_mg:%05.11f \n\tdVZ_mg:%05.11f", dVX_mg, dVY_mg, dVZ_mg);
1900 // If the absolute results of all three axes are higher than 200mg, the accelerometer can be considered functional.
1901 // Otherwise, the accelerometer cannot be considered functional.
1902 if (abs(dVX_mg) > 200 && abs(dVY_mg) > 200 && abs(dVZ_mg) > 200) {
1903 SENSORLIB_LOG_D("Accelerometer is working properly.");
1904 } else {
1905 SENSORLIB_LOG_D("Accelerometer is not working properly.");
1906 return false;
1907 }
1908 return true;
1909 }
1910
1911
1918 {
1919 // 1- Disable the sensors (CTRL7 = 0x00).
1920 if (comm->writeRegister(QMI8658_REG_CTRL7, (uint8_t)0x00) != 0) {
1921 return false;
1922 }
1923
1924 // 2- Set the bit gST to 1. (CTRL3.bit7 = 1"b1).
1925 comm->setRegisterBit(QMI8658_REG_CTRL3, 7);
1926
1927 // 3- Wait for QMI8658A to drive INT2 to High, if INT2 is enabled, or STATUS_INT.bit0 is set to 1.
1928 int retry = 50;
1929 int dataReady = 0x00;
1930 while (dataReady != 0x01) {
1931 dataReady = comm->readRegister(QMI8658_REG_STATUS_INT) & 0x01;
1932 hal->delay(20);
1933 if (--retry <= 0) {
1934 SENSORLIB_LOG_E("No response.");
1935 return false;
1936 }
1937 }
1938
1939 SENSORLIB_LOG_I("Data is ready for reading....");
1940
1941 //4- Set CTRL3.aST(bit7) to 0, to clear STATUS_INT1.bit0 and/or INT2.
1942 comm->clrRegisterBit(QMI8658_REG_CTRL3, 7);
1943
1944 // 5- Check for QMI8658A drives INT2 back to Low, or sets STATUSINT1.bit0 to 0.
1945 retry = 50;
1946 while (dataReady != 0x00) {
1947 dataReady = !(comm->readRegister(QMI8658_REG_STATUS_INT) & 0x01);
1948 hal->delay(20);
1949 if (--retry <= 0) {
1950 SENSORLIB_LOG_E("No response.");
1951 return false;
1952 }
1953 }
1954
1955 /*
1956 6- Read the Gyro Self-Test result:
1957 X channel: dVX_L and dVX_H (registers 0x51 and 0x52)
1958 Y channel: dVY_L and dVY_H (registers 0x53 and 0x54)
1959 Z channel: dVZ_L and dVZ_H (registers 0x55 and 0x56)
1960 Read the 16 bits result in format signed U12.4, resolution is 62.5mdps (1 / 2^4 dps).
1961 */
1962 uint8_t rawBuffer[6];
1963 if (comm->readRegister(QMI8658_REG_DVX_L, rawBuffer, 6) != 0) {
1964 return false;
1965 }
1966
1967 // int16_t x = (int16_t)(rawBuffer[0]) | ((int16_t)(rawBuffer[1] << 8));
1968 // int16_t y = (int16_t)(rawBuffer[2]) | ((int16_t)(rawBuffer[3] << 8));
1969 // int16_t z = (int16_t)(rawBuffer[4]) | ((int16_t)(rawBuffer[5] << 8));
1970
1971 float dVX = (((int16_t)rawBuffer[0]) << 12) | ((int16_t)(rawBuffer[1]) >> 4);
1972 float dVY = (((int16_t)rawBuffer[2]) << 12) | ((int16_t)(rawBuffer[3]) >> 4);
1973 float dVZ = (((int16_t)rawBuffer[4]) << 12) | ((int16_t)(rawBuffer[5]) >> 4);
1974
1975 dVX *= (1.0 / (1 << 4)); // 62.5 mdps
1976 dVY *= (1.0 / (1 << 4)); // 62.5 mdps
1977 dVZ *= (1.0 / (1 << 4)); // 62.5 mdps
1978
1979 SENSORLIB_LOG_D("\n\tdVX:%12.4f \n\tdVY:%12.4f \n\tdVZ:%12.4f", dVX, dVY, dVZ);
1980
1981 // If the absolute results of all three axes are higher than 300dps, the gyroscope can be considered functional.
1982 // Otherwise, the gyroscope cannot be considered functional.
1983 if (abs(dVX) > 300 && abs(dVY) > 300 && abs(dVZ) > 300) {
1984 SENSORLIB_LOG_D("Gyro is working properly.");
1985 } else {
1986 SENSORLIB_LOG_D("Gyro is not working properly.");
1987 return false;
1988 }
1989
1990 return true;
1991 }
1992
2002 void setAccelOffset(int16_t offset_x, int16_t offset_y, int16_t offset_z)
2003 {
2004 uint8_t data[6];
2005 data[0] = sensorlib::_lowByte(offset_x);
2006 data[1] = sensorlib::_highByte(offset_x);
2007 data[2] = sensorlib::_lowByte(offset_y);
2008 data[3] = sensorlib::_highByte(offset_y);
2009 data[4] = sensorlib::_lowByte(offset_z);
2010 data[5] = sensorlib::_highByte(offset_z);
2011 comm->writeRegister(QMI8658_REG_CAL1_L, data, 2);
2012 comm->writeRegister(QMI8658_REG_CAL2_L, data + 2, 2);
2013 comm->writeRegister(QMI8658_REG_CAL3_L, data + 4, 2);
2015 }
2016
2026 void setGyroOffset(int16_t offset_x, int16_t offset_y, int16_t offset_z)
2027 {
2028 uint8_t data[6];
2029 data[0] = sensorlib::_lowByte(offset_x);
2030 data[1] = sensorlib::_highByte(offset_x);
2031 data[2] = sensorlib::_lowByte(offset_y);
2032 data[3] = sensorlib::_highByte(offset_y);
2033 data[4] = sensorlib::_lowByte(offset_z);
2034 data[5] = sensorlib::_highByte(offset_z);
2035 comm->writeRegister(QMI8658_REG_CAL1_L, data, 2);
2036 comm->writeRegister(QMI8658_REG_CAL2_L, data + 2, 2);
2037 comm->writeRegister(QMI8658_REG_CAL3_L, data + 4, 2);
2039 }
2040
2041private:
2042
2048 uint16_t getFifoNeedBytes()
2049 {
2050 uint8_t sam[] = {16, 32, 64, 128};
2051 uint8_t sensors = 0;
2053 sensors = 2;
2054 } else if (_gyro_enabled || _accel_enabled) {
2055 sensors = 1;
2056 }
2057 uint8_t samples = ((_fifo_mode >> 2) & 0x03) ;
2058 return sam[samples] * 6 * sensors;
2059 }
2060
2061
2067 uint16_t readFromFifo()
2068 {
2069 uint8_t status[2];
2070 uint16_t fifo_bytes = 0;
2071
2072 if ((_irq != -1) && _fifo_interrupt) {
2073 /*
2074 * Once the corresponds INT pin is configured to the push-pull mode, the FIFO watermark interrupt can be seen on the
2075 * corresponds INT pin. It will keep high level as long as the FIFO filled level is equal to or higher than the watermark, will
2076 * drop to low level as long as the FIFO filled level is lower than the configured FIFO watermark after reading out by host
2077 * and FIFO_RD_MODE is cleared.
2078 */
2079 if (hal->digitalRead(_irq) == LOW) {
2080 return false;
2081 }
2082 }
2083
2084 size_t alloc_size = getFifoNeedBytes();
2085 if (!fifo_buffer) {
2086 fifo_buffer = (uint8_t *)calloc(alloc_size, sizeof(uint8_t));
2087 if (!fifo_buffer) {
2088 SENSORLIB_LOG_E("Calloc buffer size %u bytes failed!", alloc_size);
2089 return 0;
2090 }
2091 _fifo_size = alloc_size;
2092
2093 } else if (alloc_size > _fifo_size) {
2094 fifo_buffer = (uint8_t *)realloc(fifo_buffer, alloc_size);
2095 if (!fifo_buffer) {
2096 SENSORLIB_LOG_E("Realloc buffer size %u bytes failed!", alloc_size);
2097 return 0;
2098 }
2099 }
2100
2101 // Got FIFO watermark interrupt by INT pin or polling the FIFO_STATUS register (FIFO_WTM and/or FIFO_FULL).
2102 int val = comm->readRegister(QMI8658_REG_FIFO_STATUS);
2103 if (val == -1) {
2104 return 0;
2105 }
2106 SENSORLIB_LOG_D("FIFO status:0x%x", val);
2107
2108 if (!(val & sensorlib::_bv(4))) {
2109 SENSORLIB_LOG_D("FIFO is Empty");
2110 return 0;
2111 }
2112 if (val & sensorlib::_bv(5)) {
2113 SENSORLIB_LOG_D("FIFO Overflow condition has happened (data dropping happened)");
2114 // return 0;
2115 }
2116 if (val & sensorlib::_bv(6)) {
2117 SENSORLIB_LOG_D("FIFO Water Mark Level Hit");
2118 }
2119 if (val & sensorlib::_bv(7)) {
2120 SENSORLIB_LOG_D("FIFO is Full");
2121 }
2122
2123 // Read the FIFO_SMPL_CNT and FIFO_STATUS registers, to calculate the level of FIFO content data, refer to 8.4 FIFO Sample Count.
2124 if (comm->readRegister(QMI8658_REG_FIFO_COUNT, status, 2) == -1) {
2125 SENSORLIB_LOG_E("Bus communication failed!");
2126 return 0;
2127 }
2128
2129 // FIFO_Sample_Count (in byte) = 2 * (fifo_smpl_cnt_msb[1:0] * 256 + fifo_smpl_cnt_lsb[7:0])
2130 fifo_bytes = 2 * (((status[1] & 0x03)) << 8 | status[0]);
2131
2132 SENSORLIB_LOG_D("reg fifo_bytes:%d ", fifo_bytes);
2133
2134 //Samples 16 * 6 * 2 = 192
2135 //Samples 32 * 6 * 2 = 384
2136 //Samples 64 * 6 * 2 = 768
2137 //Samples 128 * 6 * 2 = 1536
2138
2139 // Send CTRL_CMD_REQ_FIFO (0x05) by CTRL9 command, to enable FIFO read mode. Refer to CTRL_CMD_REQ_FIFO for details.
2140 if (writeCommand(CTRL_CMD_REQ_FIFO) != 0) {
2141 SENSORLIB_LOG_E("Request FIFO failed!");
2142 return 0;
2143 }
2144
2145 // Read from the FIFO_DATA register per FIFO_Sample_Count.
2146 if (comm->readRegister(QMI8658_REG_FIFO_DATA, fifo_buffer, fifo_bytes) == -1) {
2147 SENSORLIB_LOG_E("Request FIFO data failed !");
2148 return 0;
2149 }
2150
2151 // Disable the FIFO Read Mode by setting FIFO_CTRL.FIFO_rd_mode to 0. New data will be filled into FIFO afterwards.
2152 if (comm->writeRegister(QMI8658_REG_FIFO_CTRL, _fifo_mode) == -1) {
2153 SENSORLIB_LOG_E("Clear FIFO flag failed!");
2154 return 0;
2155 }
2156
2157 return fifo_bytes;
2158 }
2159
2160
2167 int writeCommand(CommandTable cmd, uint32_t wait_ms = 1000)
2168 {
2169 int val;
2170 uint32_t startMillis;
2171 if (comm->writeRegister(QMI8658_REG_CTRL9, cmd) == -1) {
2172 return -1;
2173 }
2174 startMillis = hal->millis();
2175 do {
2176 val = comm->readRegister(QMI8658_REG_STATUS_INT);
2177 hal->delay(1);
2178 if (hal->millis() - startMillis > wait_ms) {
2179 SENSORLIB_LOG_E("wait for ctrl9 command done time out : %d val:%d", cmd, val);
2180 return -1;
2181 }
2182 } while (val != -1 && !(val & 0x80));
2183
2184 if (comm->writeRegister(QMI8658_REG_CTRL9, CTRL_CMD_ACK) == -1) {
2185 return -1;
2186 }
2187
2188 startMillis = hal->millis();
2189 do {
2190 val = comm->readRegister(QMI8658_REG_STATUS_INT);
2191 hal->delay(1);
2192 if (hal->millis() - startMillis > wait_ms) {
2193 SENSORLIB_LOG_E("Clear ctrl9 command done flag timeout : %d val:%d", cmd, val);
2194 return -1;
2195 }
2196 } while (val != -1 && (val & 0x80));
2197
2198 return 0;
2199 }
2200
2201
2208 uint8_t mgToBytes(float mg)
2209 {
2210 float g = mg / 1000.0; // Convert to grams
2211 int units = (int)round(g / 0.03125); //Convert grams to units of specified(1/32) resolution
2212 return (units & 0x1F) << 3; // Shift the 5 decimal places to the left by 3 places, because there are only 3 integer places
2213 }
2214
2215
2216 int _irq = -1;
2217 float accelScales = 0.0f, gyroScales = 0.0f;
2218 bool _accel_enabled = false;
2219 bool _gyro_enabled = false;
2220 bool _gDataReady = false;
2221 bool _aDataReady = false;
2222 bool _fifo_interrupt = false;
2223
2224 uint8_t usid[6];
2225 uint8_t sampleMode = ASYNC_MODE;
2226 uint8_t _irq_enable_mask = false;
2227 uint8_t _fifo_mode = 0x00;
2228 uint8_t *fifo_buffer = NULL;
2229 uint16_t _fifo_size = 0;
2230
2231 uint32_t lastTimestamp = 0;
2232 uint32_t revisionID = 0x00;
2233
2234 EventCallBack_t eventWomEvent = NULL;
2235 EventCallBack_t eventTagEvent = NULL;
2236 EventCallBack_t eventPedometerEvent = NULL;
2237 EventCallBack_t eventNoMotionEvent = NULL;
2238 EventCallBack_t eventAnyMotionEvent = NULL;
2239 EventCallBack_t eventSignificantMotion = NULL;
2240 EventCallBack_t eventGyroDataReady = NULL;
2241 EventCallBack_t eventAccelDataReady = NULL;
2242 EventCallBack_t eventDataLocking = NULL;
2243
2244
2245protected:
2246
2247 bool initImpl(uint8_t param) override
2248 {
2249 uint8_t buffer[6] = {0};
2250
2251
2252 if (_irq != -1) {
2253 hal->pinMode(_irq, INPUT);
2254 }
2255
2256 if (!reset()) {
2257 return false;
2258 }
2259
2260 uint8_t id = whoAmI();
2261 if (id != QMI8658_REG_WHOAMI_DEFAULT) {
2262 SENSORLIB_LOG_E("ERROR! ID NOT MATCH QMI8658 , Response id is 0x%x", id);
2263 return false;
2264 }
2265 // Enable address auto increment, Big-Endian format
2266 // comm->writeRegister(QMI8658_REG_CTRL1, 0x60);
2267
2268 // Little-Endian / address auto increment
2269 // comm->writeRegister(QMI8658_REG_CTRL1, 0x40);
2270
2271 // no need . reset function has set
2272 //EN.ADDR_AI
2273 // comm->setRegisterBit(QMI8658_REG_CTRL1, 6);
2274
2275 // Use STATUS_INT.bit7 as CTRL9 handshake
2276 comm->writeRegister(QMI8658_REG_CTRL8, 0x80);
2277
2278 // Get firmware version and usid
2280
2281 if (comm->readRegister(QMI8658_REG_DQW_L, buffer, 3) != -1) {
2282 revisionID = buffer[0] | (uint32_t)(buffer[1] << 8) | (uint32_t)(buffer[2] << 16);
2283 SENSORLIB_LOG_D("FW Version :0x%02X%02X%02X", buffer[0], buffer[1], buffer[2]);
2284 }
2285
2286 if (comm->readRegister(QMI8658_REG_DVX_L, usid, 6) != -1) {
2287 SENSORLIB_LOG_D("USID :%02X%02X%02X%02X%02X%02X",
2288 usid[0], usid[1], usid[2],
2289 usid[3], usid[4], usid[5]);
2290 }
2291
2292 return true;
2293 }
2294
2295 // @brief registers default value
2296 static constexpr uint8_t QMI8658_REG_WHOAMI_DEFAULT = 0x05;
2297 static constexpr uint8_t QMI8658_REG_STATUS_DEFAULT = 0x03;
2298 static constexpr uint8_t QMI8658_REG_RESET_DEFAULT = 0xB0;
2299
2300
2301 //* General Purpose Registers
2302 static constexpr uint8_t QMI8658_REG_WHOAMI = 0x00;
2303 static constexpr uint8_t QMI8658_REG_REVISION = 0x01;
2304
2305
2306 //* Setup and Control Registers
2307 static constexpr uint8_t QMI8658_REG_CTRL1 = 0x02;
2308 static constexpr uint8_t QMI8658_REG_CTRL2 = 0x03;
2309 static constexpr uint8_t QMI8658_REG_CTRL3 = 0x04;
2310 // Reserved
2311 static constexpr uint8_t QMI8658_REG_CTRL5 = 0x06;
2312 // Reserved
2313 static constexpr uint8_t QMI8658_REG_CTRL7 = 0x08;
2314 static constexpr uint8_t QMI8658_REG_CTRL8 = 0x09;
2315 static constexpr uint8_t QMI8658_REG_CTRL9 = 0x0A;
2316
2317 //* Host Controlled Calibration Registers (See CTRL9, Usage is Optional)
2318 static constexpr uint8_t QMI8658_REG_CAL1_L = 0x0B;
2319 static constexpr uint8_t QMI8658_REG_CAL1_H = 0x0C;
2320 static constexpr uint8_t QMI8658_REG_CAL2_L = 0x0D;
2321 static constexpr uint8_t QMI8658_REG_CAL2_H = 0x0E;
2322 static constexpr uint8_t QMI8658_REG_CAL3_L = 0x0F;
2323 static constexpr uint8_t QMI8658_REG_CAL3_H = 0x10;
2324 static constexpr uint8_t QMI8658_REG_CAL4_L = 0x11;
2325 static constexpr uint8_t QMI8658_REG_CAL4_H = 0x12;
2326
2327 //* FIFO Registers
2328 static constexpr uint8_t QMI8658_REG_FIFO_WTM_TH = 0x13;
2329 static constexpr uint8_t QMI8658_REG_FIFO_CTRL = 0x14;
2330 static constexpr uint8_t QMI8658_REG_FIFO_COUNT = 0x15;
2331 static constexpr uint8_t QMI8658_REG_FIFO_STATUS = 0x16;
2332 static constexpr uint8_t QMI8658_REG_FIFO_DATA = 0x17;
2333
2334 //* Status Registers
2335 static constexpr uint8_t QMI8658_REG_STATUS_INT = 0x2D;
2336 static constexpr uint8_t QMI8658_REG_STATUS0 = 0x2E;
2337 static constexpr uint8_t QMI8658_REG_STATUS1 = 0x2F;
2338
2339 //* Timestamp Register
2340 static constexpr uint8_t QMI8658_REG_TIMESTAMP_L = 0x30;
2341 static constexpr uint8_t QMI8658_REG_TIMESTAMP_M = 0x31;
2342 static constexpr uint8_t QMI8658_REG_TIMESTAMP_H = 0x32;
2343
2344 //* Data Output Registers (16 bits 2’s Complement Except COD Sensor Data)
2345 static constexpr uint8_t QMI8658_REG_TEMPERATURE_L = 0x33;
2346 static constexpr uint8_t QMI8658_REG_TEMPERATURE_H = 0x34;
2347 static constexpr uint8_t QMI8658_REG_AX_L = 0x35;
2348 static constexpr uint8_t QMI8658_REG_AX_H = 0x36;
2349 static constexpr uint8_t QMI8658_REG_AY_L = 0x37;
2350 static constexpr uint8_t QMI8658_REG_AY_H = 0x38;
2351 static constexpr uint8_t QMI8658_REG_AZ_L = 0x39;
2352 static constexpr uint8_t QMI8658_REG_AZ_H = 0x3A;
2353 static constexpr uint8_t QMI8658_REG_GX_L = 0x3B;
2354 static constexpr uint8_t QMI8658_REG_GX_H = 0x3C;
2355 static constexpr uint8_t QMI8658_REG_GY_L = 0x3D;
2356 static constexpr uint8_t QMI8658_REG_GY_H = 0x3E;
2357 static constexpr uint8_t QMI8658_REG_GZ_L = 0x3F;
2358 static constexpr uint8_t QMI8658_REG_GZ_H = 0x40;
2359
2360 //* COD Indication and General Purpose Registers
2361
2362 // Calibration-On-Demand status register
2363 static constexpr uint8_t QMI8658_REG_COD_STATUS = 0x46;
2364 static constexpr uint8_t QMI8658_REG_DQW_L = 0x49;
2365 static constexpr uint8_t QMI8658_REG_DQW_H = 0x4A;
2366 static constexpr uint8_t QMI8658_REG_DQX_L = 0x4B;
2367 static constexpr uint8_t QMI8658_REG_DQX_H = 0x4C;
2368
2369 static constexpr uint8_t QMI8658_REG_DQY_L = 0x4D;
2370 static constexpr uint8_t QMI8658_REG_DQY_H = 0x4E;
2371 static constexpr uint8_t QMI8658_REG_DQZ_L = 0x4F;
2372 static constexpr uint8_t QMI8658_REG_DQZ_H = 0x50;
2373
2374 static constexpr uint8_t QMI8658_REG_DVX_L = 0x51;
2375 static constexpr uint8_t QMI8658_REG_DVX_H = 0x52;
2376 static constexpr uint8_t QMI8658_REG_DVY_L = 0x53;
2377 static constexpr uint8_t QMI8658_REG_DVY_H = 0x54;
2378 static constexpr uint8_t QMI8658_REG_DVZ_L = 0x55;
2379 static constexpr uint8_t QMI8658_REG_DVZ_H = 0x56;
2380
2381 //* Activity Detection Output Registers
2382 static constexpr uint8_t QMI8658_REG_TAP_STATUS = 0x59;
2383 static constexpr uint8_t QMI8658_REG_STEP_CNT_LOW = 0x5A;
2384 static constexpr uint8_t QMI8658_REG_STEP_CNT_MID = 0x5B;
2385 static constexpr uint8_t QMI8658_REG_STEP_CNT_HIGH = 0x5C;
2386 static constexpr uint8_t QMI8658_REG_RESET = 0x60;
2387
2388 //* Reset Register
2389 static constexpr uint8_t QMI8658_REG_RST_RESULT = 0x4D;
2390 static constexpr uint8_t QMI8658_REG_RST_RESULT_VAL = 0x80;
2391
2392 static constexpr uint8_t STATUS0_ACCEL_AVAIL = 0x01;
2393 static constexpr uint8_t STATUS0_GYRO_AVAIL = 0x02;
2394 static constexpr uint8_t QMI8658_ACCEL_LPF_MASK = 0xF9;
2395 static constexpr uint8_t QMI8658_GYRO_LPF_MASK = 0x9F;
2396
2397 static constexpr uint8_t QMI8658_ACCEL_EN_MASK = 0x01;
2398 static constexpr uint8_t QMI8658_GYRO_EN_MASK = 0x02;
2399 static constexpr uint8_t QMI8658_ACCEL_GYRO_EN_MASK = 0x03;
2400
2401
2402 static constexpr uint8_t QMI8658_FIFO_MAP_INT1 = 0x04;
2403};
2404
2405#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]