30#include "../../../SensorBuildOpt.h"
31#if !SENSORLIB_EXCLUDE_QMI8658
34#include "../../AccelerometerUtils.hpp"
64 return FIFO_MODE_BYPASS;
66 return FIFO_MODE_FIFO;
68 return FIFO_MODE_STREAM;
70 return FIFO_MODE_BYPASS;
78 return FIFO_SAMPLES_16;
80 return FIFO_SAMPLES_32;
82 return FIFO_SAMPLES_64;
84 return FIFO_SAMPLES_128;
86 return FIFO_SAMPLES_16;
94 return TAP_PRIORITY_X_GT_Y_GT_Z;
96 return TAP_PRIORITY_X_GT_Z_GT_Y;
98 return TAP_PRIORITY_Y_GT_X_GT_Z;
100 return TAP_PRIORITY_Y_GT_Z_GT_X;
102 return TAP_PRIORITY_Z_GT_X_GT_Y;
104 return TAP_PRIORITY_Z_GT_Y_GT_X;
106 return TAP_PRIORITY_X_GT_Y_GT_Z;
113 case SensorQMI8658::IntPin::PIN1:
117 case SensorQMI8658::IntPin::PIN2:
201 , _accel_scale(ACCEL_SCALE_8G)
202 , _gyro_scale(GYRO_SCALE_1024DPS)
205 , _motion_any_configured(false)
206 , _motion_no_configured(false)
207 , _motion_sig_configured(false)
208 , _motion_any_thr{0, 0, 0}
209 , _motion_no_thr{0, 0, 0}
210 , _motion_any_window(4)
211 , _motion_no_window(10)
212 , _motion_sig_wait_window(0)
213 , _motion_sig_confirm_window(8)
214 , _accel_enabled(false)
215 , _gyro_enabled(false)
217 , _fifo_enabled(false)
219 , _fifo_watermark(16)
222 , _int_enabled(false)
223 , _last_step_count(0)
224 , _tap_event_active(false)
226 , _last_tap_event_ms(0)
228 , _firmware_version(0)
229 , _fifo_buffer(nullptr)
230 , _fifo_buffer_size(0)
231 , _axis_layout(
Layout::LAYOUT_DEFAULT)
232 , _static_cali_sample_count(0)
233 , _static_cali_enabled(false)
234 , _static_cali_complete(false)
235 , _dyn_cal_enabled(false)
236 , _dyn_static_delay(0)
237 , _dyn_static_flag(0)
238 , _dyn_cali_sample_count(0)
239 , _gyro_static_deviation(0)
240 , _accel_static_deviation(0)
241 , _dyn_offset_applied(0)
273 uint32_t start =
hal->millis();
274 while (
hal->millis() - start < timeout_ms) {
275 uint8_t status =
readReg(REG_STATUS_INT);
276 if (status != 0xFF && (status & MASK_INT_CTRL9_DONE)) {
286 start =
hal->millis();
287 while (
hal->millis() - start < timeout_ms) {
288 uint8_t status =
readReg(REG_STATUS_INT);
289 if (status != 0xFF && !(status & MASK_INT_CTRL9_DONE)) {
300 if (!
hal)
return false;
302 writeReg(REG_RESET, QMI8658_RESET_VAL);
304 uint32_t start =
hal->millis();
305 while (
hal->millis() - start < 500) {
306 uint8_t val =
readReg(REG_RST_RESULT);
307 if (val != 0xFF && (val & MASK_RST_RESULT)) {
325 return getChipID() == QMI8658_WHO_AM_I_VAL;
344 return setRegBit(REG_CTRL1, SHIFT_SENSOR_DISABLE);
346 return clrRegBit(REG_CTRL1, SHIFT_SENSOR_DISABLE);
355 if (
readRegBuff(REG_TEMPERATURE_L, buffer, 2) == 0) {
356 return static_cast<float>(buffer[1]) + (
static_cast<float>(buffer[0]) / 256.0f);
364 if (
readRegBuff(REG_TIMESTAMP_L, buffer, 3) == 0) {
365 uint32_t ts = (uint32_t)(buffer[2] << 16) | (uint32_t)(buffer[1] << 8) | buffer[0];
403 x = (int16_t)((buffer[1] << 8) | buffer[0]);
404 y = (int16_t)((buffer[3] << 8) | buffer[2]);
405 z = (int16_t)((buffer[5] << 8) | buffer[4]);
436 int ret =
updateBits(REG_CTRL2, 0x70, (reg_val << 4));
448 if (
updateBits(REG_CTRL2, 0x0F, reg_val) != 0) {
462 default:
return ACCEL_RANGE_8G;
473 default:
return ACCEL_SCALE_8G;
488 int16_t accel_tmp[3] = {0, 0, 0};
489 int16_t gyro_tmp[3] = {
x,
y, z};
493 accel_tmp[0] =
static_cast<int16_t
>((abuf[1] << 8) | abuf[0]);
494 accel_tmp[1] =
static_cast<int16_t
>((abuf[3] << 8) | abuf[2]);
495 accel_tmp[2] =
static_cast<int16_t
>((abuf[5] << 8) | abuf[4]);
522 float x_corr =
static_cast<float>(
x - bias_x);
523 float y_corr =
static_cast<float>(
y - bias_y);
524 float z_corr =
static_cast<float>(z - bias_z);
542 x = (int16_t)((buffer[1] << 8) | buffer[0]);
543 y = (int16_t)((buffer[3] << 8) | buffer[2]);
544 z = (int16_t)((buffer[5] << 8) | buffer[4]);
575 int ret =
updateBits(REG_CTRL3, 0x70, (reg_val << 4));
587 if (
updateBits(REG_CTRL3, 0x0F, reg_val) != 0) {
602 default:
return GYRO_RANGE_1024DPS;
614 default:
return GYRO_SCALE_1024DPS;
645 uint8_t ctrl2 =
static_cast<uint8_t
>((range_val << 4) | odr_val);
646 if (
writeReg(REG_CTRL2, ctrl2) != 0) {
654 uint8_t lpf_val = toQmiLpfMode(lpf);
655 updateBits(REG_CTRL5, 0x06,
static_cast<uint8_t
>(lpf_val << 1));
677 uint8_t ctrl3 =
static_cast<uint8_t
>((range_val << 4) | odr_val);
678 if (
writeReg(REG_CTRL3, ctrl3) != 0) {
686 uint8_t lpf_val = toQmiLpfMode(lpf);
687 updateBits(REG_CTRL5, 0x60,
static_cast<uint8_t
>(lpf_val << 5));
707 if (hz <= 28.0f)
return ACCEL_ODR_28_025HZ;
708 if (hz <= 56.0f)
return ACCEL_ODR_56_05HZ;
709 if (hz <= 112.0f)
return ACCEL_ODR_112_1HZ;
710 if (hz <= 224.0f)
return ACCEL_ODR_224_2HZ;
711 if (hz <= 448.0f)
return ACCEL_ODR_448_4HZ;
712 if (hz <= 896.0f)
return ACCEL_ODR_896_8HZ;
713 if (hz <= 1792.0f)
return ACCEL_ODR_1793_6HZ;
714 if (hz <= 3584.0f)
return ACCEL_ODR_3587_2HZ;
715 return ACCEL_ODR_7174_4HZ;
720 if (hz <= 28.0f)
return GYRO_ODR_28_025HZ;
721 if (hz <= 56.0f)
return GYRO_ODR_56_05HZ;
722 if (hz <= 112.0f)
return GYRO_ODR_112_1HZ;
723 if (hz <= 224.0f)
return GYRO_ODR_224_2HZ;
724 if (hz <= 448.0f)
return GYRO_ODR_448_4HZ;
725 if (hz <= 896.0f)
return GYRO_ODR_896_8HZ;
726 if (hz <= 1792.0f)
return GYRO_ODR_1793_6HZ;
727 if (hz <= 3584.0f)
return GYRO_ODR_3587_2HZ;
728 return GYRO_ODR_7174_4HZ;
733 if (hz <= 3.0f)
return ACCEL_ODR_LP_3HZ;
734 if (hz <= 11.0f)
return ACCEL_ODR_LP_11HZ;
735 if (hz <= 21.0f)
return ACCEL_ODR_LP_21HZ;
736 return ACCEL_ODR_LP_128HZ;
743 if (!toQmiInterruptBit(pin, bit_pos, mask)) {
758 if (!toQmiInterruptBit(pin, bit_pos, mask)) {
773 if (pin != IntPin::PIN2) {
782 return readReg(REG_STATUS_INT);
797 uint8_t status0 =
readReg(REG_STATUS0);
798 uint8_t req = mask & 0x03;
802 if (accel_enabled && gyro_enabled) {
804 }
else if (accel_enabled) {
806 }
else if (gyro_enabled) {
812 return (status0 & req) == req;
818 if (
hal && pin >= 0) {
819 hal->pinMode(pin, INPUT);
850 if (
writeReg(REG_FIFO_WTM_TH, watermark_samples) != 0) {
887 uint8_t wm = watermark_samples;
904 if (
writeReg(REG_FIFO_WTM_TH, wm) != 0) {
908 uint8_t mode_val = toQmiFifoMode(mode);
909 uint8_t samples_val = toQmiFifoSamples(samples);
930 return readReg(REG_FIFO_STATUS);
941 if (!(status & MASK_FIFO_EMPTY)) {
946 uint8_t count_buf[2];
947 if (
readRegBuff(REG_FIFO_SMPL_CNT_L, count_buf, 2) != 0) {
952 uint16_t fifo_bytes =
static_cast<uint16_t
>(2 * (((count_buf[1] & 0x03) << 8) | count_buf[0]));
954 if (fifo_bytes == 0 || fifo_bytes > 1536 || (fifo_bytes % 6) != 0) {
976 static constexpr uint16_t kFifoReadChunk = 240;
977 uint16_t remaining = fifo_bytes;
979 while (remaining > 0) {
980 uint16_t chunk = remaining > kFifoReadChunk ? kFifoReadChunk : remaining;
991 uint16_t accel_idx = 0;
992 uint16_t gyro_idx = 0;
996 uint16_t sample_sets =
static_cast<uint16_t
>(fifo_bytes / 12);
997 uint16_t usable = sample_sets;
998 if (accel_data && usable > accel_count) usable = accel_count;
999 if (gyro_data && usable > gyro_count) usable = gyro_count;
1001 for (uint16_t
i = 0;
i < usable; ++
i) {
1002 uint16_t off =
static_cast<uint16_t
>(
i * 12);
1013 accel_data[accel_idx].
raw.
x = ax;
1014 accel_data[accel_idx].
raw.
y = ay;
1015 accel_data[accel_idx].
raw.
z = az;
1023 gyro_data[gyro_idx].
raw.
x = gx;
1024 gyro_data[gyro_idx].
raw.
y = gy;
1025 gyro_data[gyro_idx].
raw.
z = gz;
1038 float gx_corr =
static_cast<float>(gx - bias_x);
1039 float gy_corr =
static_cast<float>(gy - bias_y);
1040 float gz_corr =
static_cast<float>(gz - bias_z);
1050 uint16_t samples_read =
static_cast<uint16_t
>(fifo_bytes / 6);
1051 for (uint16_t
i = 0;
i < samples_read; ++
i) {
1057 accel_data[accel_idx].
raw.
x =
x;
1058 accel_data[accel_idx].
raw.
y =
y;
1059 accel_data[accel_idx].
raw.
z = z;
1064 }
else if (
_gyro_enabled && gyro_idx < gyro_count && gyro_data) {
1065 gyro_data[gyro_idx].
raw.
x =
x;
1066 gyro_data[gyro_idx].
raw.
y =
y;
1067 gyro_data[gyro_idx].
raw.
z = z;
1080 float x_corr =
static_cast<float>(
x - bias_x);
1081 float y_corr =
static_cast<float>(
y - bias_y);
1082 float z_corr =
static_cast<float>(z - bias_z);
1090 return samples_read;
1096 if (
writeReg(REG_CAL1_L, 0x01) != 0) {
1105 if (
writeReg(REG_CAL1_L, 0x00) != 0) {
1113 if (!
hal)
return false;
1127 uint8_t status =
readReg(REG_COD_STATUS);
1128 if (status & MASK_COD_FAIL) {
1132 if (status & MASK_COD_GYRO_ENABLED_ERR) {
1136 if (status & MASK_COD_GYRO_STARTUP_ERR) {
1140 if (status & MASK_COD_ACCEL_ERR) {
1147 if (gyro_x_gain) *gyro_x_gain = (uint16_t)buffer[0] | ((uint16_t)buffer[1] << 8);
1148 if (gyro_y_gain) *gyro_y_gain = (uint16_t)buffer[2] | ((uint16_t)buffer[3] << 8);
1149 if (gyro_z_gain) *gyro_z_gain = (uint16_t)buffer[4] | ((uint16_t)buffer[5] << 8);
1162 uint8_t buffer[6] = {
1163 (uint8_t)(gyro_x_gain & 0xFF),
1164 (uint8_t)((gyro_x_gain >> 8) & 0xFF),
1165 (uint8_t)(gyro_y_gain & 0xFF),
1166 (uint8_t)((gyro_y_gain >> 8) & 0xFF),
1167 (uint8_t)(gyro_z_gain & 0xFF),
1168 (uint8_t)((gyro_z_gain >> 8) & 0xFF),
1181 data[0] = (uint8_t)(
x & 0xFF);
1182 data[1] = (uint8_t)((
x >> 8) & 0xFF);
1184 data[0] = (uint8_t)(
y & 0xFF);
1185 data[1] = (uint8_t)((
y >> 8) & 0xFF);
1187 data[0] = (uint8_t)(z & 0xFF);
1188 data[1] = (uint8_t)((z >> 8) & 0xFF);
1196 data[0] = (uint8_t)(
x & 0xFF);
1197 data[1] = (uint8_t)((
x >> 8) & 0xFF);
1199 data[0] = (uint8_t)(
y & 0xFF);
1200 data[1] = (uint8_t)((
y >> 8) & 0xFF);
1202 data[0] = (uint8_t)(z & 0xFF);
1203 data[1] = (uint8_t)((z >> 8) & 0xFF);
1210 if (!
hal)
return false;
1215 if (
writeReg(REG_CTRL7, 0x00) != 0) {
1219 if (
updateBits(REG_CTRL2, 0xF0, (ACCEL_ODR_7174_4HZ | 0x80)) != 0) {
1224 while (retry-- > 0) {
1225 uint8_t status =
readReg(REG_STATUS_INT);
1226 if (status != 0xFF && (status & MASK_INT_AVAIL)) {
1244 int16_t dVX = (int16_t)((buffer[1] << 8) | buffer[0]);
1245 int16_t dVY = (int16_t)((buffer[3] << 8) | buffer[2]);
1246 int16_t dVZ = (int16_t)((buffer[5] << 8) | buffer[4]);
1248 float dVX_mg = dVX * 0.5f;
1249 float dVY_mg = dVY * 0.5f;
1250 float dVZ_mg = dVZ * 0.5f;
1252 if (abs(dVX_mg) > 200.0f && abs(dVY_mg) > 200.0f && abs(dVZ_mg) > 200.0f) {
1256 SENSORLIB_LOG_E(
"Accelerometer self-test failed: dVX=%.1f, dVY=%.1f, dVZ=%.1f", dVX_mg, dVY_mg, dVZ_mg);
1262 if (!
hal)
return false;
1267 if (
writeReg(REG_CTRL7, 0x00) != 0) {
1274 while (retry-- > 0) {
1275 uint8_t status =
readReg(REG_STATUS_INT);
1276 if (status != 0xFF && (status & MASK_INT_AVAIL)) {
1294 float dVX = (float)(((int16_t)buffer[0] << 12) | (buffer[1] >> 4));
1295 float dVY = (float)(((int16_t)buffer[2] << 12) | (buffer[3] >> 4));
1296 float dVZ = (float)(((int16_t)buffer[4] << 12) | (buffer[5] >> 4));
1298 dVX *= (1.0f / 16.0f);
1299 dVY *= (1.0f / 16.0f);
1300 dVZ *= (1.0f / 16.0f);
1302 if (abs(dVX) > 300.0f && abs(dVY) > 300.0f && abs(dVZ) > 300.0f) {
1306 SENSORLIB_LOG_E(
"Gyroscope self-test failed: dVX=%.1f, dVY=%.1f, dVZ=%.1f", dVX, dVY, dVZ);
1311 float threshold_z, uint8_t duration)
1391 uint8_t mode_ctrl = 0;
1393 mode_ctrl |= MASK_ANY_MOTION_X_EN | MASK_ANY_MOTION_Y_EN | MASK_ANY_MOTION_Z_EN;
1396 mode_ctrl |= MASK_NO_MOTION_X_EN | MASK_NO_MOTION_Y_EN | MASK_NO_MOTION_Z_EN;
1399 mode_ctrl |= MASK_NO_MOTION_LOGIC;
1402 ok = ok && (
writeReg(REG_CAL4_L, mode_ctrl) == 0);
1403 ok = ok && (
writeReg(REG_CAL4_H, 0x01) == 0);
1412 ok = ok && (
writeReg(REG_CAL4_H, 0x02) == 0);
1455 setRegBit(REG_CTRL8, SHIFT_ANY_MOTION_ENABLE);
1457 clrRegBit(REG_CTRL8, SHIFT_ANY_MOTION_ENABLE);
1461 setRegBit(REG_CTRL8, SHIFT_NO_MOTION_ENABLE);
1463 clrRegBit(REG_CTRL8, SHIFT_NO_MOTION_ENABLE);
1467 setRegBit(REG_CTRL8, SHIFT_SIGNIFICANT_MOTION_EN);
1469 clrRegBit(REG_CTRL8, SHIFT_SIGNIFICANT_MOTION_EN);
1477 clrRegBit(REG_CTRL8, SHIFT_ANY_MOTION_ENABLE);
1478 clrRegBit(REG_CTRL8, SHIFT_NO_MOTION_ENABLE);
1479 clrRegBit(REG_CTRL8, SHIFT_SIGNIFICANT_MOTION_EN);
1490 uint8_t default_pin_value, uint8_t blanking_time,
1493 if (!
hal)
return false;
1500 if (
updateBits(REG_CTRL2, 0x70,
static_cast<uint8_t
>(range_val << 4)) != 0) {
1505 if (
updateBits(REG_CTRL2, 0x0F, odr_val) != 0) {
1509 if (
writeReg(REG_CAL1_L, threshold) != 0) {
1514 if (pin == IntPin::PIN1) {
1515 cal1_h = default_pin_value ? 0x02 : 0x00;
1516 }
else if (pin == IntPin::PIN2) {
1517 cal1_h = default_pin_value ? 0x03 : 0x01;
1521 cal1_h =
static_cast<uint8_t
>((cal1_h << 6) | (blanking_time & 0x3F));
1522 if (
writeReg(REG_CAL1_H, cal1_h) != 0) {
1553 return configAccel(common_range, legacyAccelOdrToFloat(odr), lpf);
1573 return configAccel(common_range, data_rate_hz, lpf);
1599 return configGyro(common_range, legacyGyroOdrToFloat(odr), lpf);
1625 return configGyro(common_range, data_rate_hz, lpf);
1634 uint8_t default_pin_value, uint8_t blanking_time,
1638 switch (acc_range) {
1653 default_pin_value, blanking_time, common_range);
1658 float g = mg / 1000.0f;
1659 int units =
static_cast<int>(roundf(g / 0.03125f));
1662 }
else if (units > 0xFF) {
1665 return static_cast<uint8_t
>(units);
1669 uint16_t double_tap_window,
float peak_mag_threshold,
float quiet_threshold)
1679 writeReg(REG_CAL1_H, toQmiTapPriority(priority));
1680 writeReg(REG_CAL2_L, (uint8_t)(tap_window & 0xFF));
1681 writeReg(REG_CAL2_H, (uint8_t)((tap_window >> 8) & 0xFF));
1682 writeReg(REG_CAL3_L, (uint8_t)(double_tap_window & 0xFF));
1683 writeReg(REG_CAL3_H, (uint8_t)((double_tap_window >> 8) & 0xFF));
1688 const float alpha = 0.0625f;
1689 const float gamma = 0.25f;
1690 uint8_t alpha_hex =
static_cast<uint8_t
>(alpha * 128.0f);
1691 uint8_t gamma_hex =
static_cast<uint8_t
>(gamma * 128.0f);
1695 const float g = QMI8658_CONSTANT_ONE_G;
1696 float resolution = 0.001f * g * g;
1698 uint16_t peak_val = (uint16_t)((peak_mag_threshold * g * g) / resolution);
1699 uint16_t quiet_val = (uint16_t)((quiet_threshold * g * g) / resolution);
1701 writeReg(REG_CAL2_L, (uint8_t)(peak_val & 0xFF));
1702 writeReg(REG_CAL2_H, (uint8_t)((peak_val >> 8) & 0xFF));
1703 writeReg(REG_CAL3_L, (uint8_t)(quiet_val & 0xFF));
1704 writeReg(REG_CAL3_H, (uint8_t)((quiet_val >> 8) & 0xFF));
1747 uint8_t status =
readReg(REG_TAP_STATUS);
1748 uint8_t tap_type = status & MASK_TAP_TYPE;
1751 case TAP_TYPE_SINGLE:
1753 case TAP_TYPE_DOUBLE:
1761 uint16_t time_up, uint8_t time_low, uint8_t entry_count,
1762 uint8_t fix_precision, uint8_t sig_count)
1772 data[0] = (uint8_t)(sample_count & 0xFF);
1773 data[1] = (uint8_t)((sample_count >> 8) & 0xFF);
1777 data[0] = (uint8_t)(peak_to_peak & 0xFF);
1778 data[1] = (uint8_t)((peak_to_peak >> 8) & 0xFF);
1782 data[0] = (uint8_t)(peak_threshold & 0xFF);
1783 data[1] = (uint8_t)((peak_threshold >> 8) & 0xFF);
1795 data[0] = (uint8_t)(time_up & 0xFF);
1796 data[1] = (uint8_t)((time_up >> 8) & 0xFF);
1800 if (
writeReg(REG_CAL2_L, time_low) != 0 ||
writeReg(REG_CAL2_H, entry_count) != 0 ||
1801 writeReg(REG_CAL3_L, fix_precision) != 0 ||
writeReg(REG_CAL3_H, sig_count) != 0 ||
1818 float rate = 1000.0f / odr;
1819 uint16_t sample_count = 50;
1820 uint16_t peak_to_peak = 100;
1821 uint16_t peak_threshold = 116;
1822 uint16_t time_up =
static_cast<uint16_t
>(2000.0f / rate);
1823 uint8_t time_low =
static_cast<uint8_t
>(300.0f / rate);
1824 uint8_t entry_count = 8;
1825 uint8_t sig_count = 1;
1828 time_up, time_low, entry_count, 0, sig_count);
1870 if (
readRegBuff(REG_STEP_CNT_L, buffer, 3) == 0) {
1871 return (uint32_t)(buffer[2] << 16) | (uint32_t)(buffer[1] << 8) | buffer[0];
1943 uint16_t result = 0;
1946 if (
readRegBuff(REG_STATUS_INT, status, 3) != 0) {
1950 if (status[0] & MASK_INT_CTRL9_DONE) {
1954 if (status[0] & MASK_INT_AVAIL) {
1958 if ((status[0] & 0x03) == 0x03) {
1966 if (status[1] & MASK_GYRO_DATA_RDY) {
1973 if (status[1] & MASK_ACCEL_DATA_RDY) {
2005 pedometer_event =
true;
2008 if (pedometer_event) {
2026 uint32_t now_ms = 0;
2027 now_ms =
hal->millis();
2049 for (
int i = 0;
i < 9; ++
i) {
2065 memcpy(buffer,
_usid, length);
2090 int16_t raw_a[3], raw_g[3];
2092 raw_a[0] = accel_data[0];
2093 raw_a[1] = accel_data[1];
2094 raw_a[2] = accel_data[2];
2095 raw_g[0] = gyro_data[0];
2096 raw_g[1] = gyro_data[1];
2097 raw_g[2] = gyro_data[2];
2101 if (layout >= 4 && layout <= 7) {
2102 accel_data[2] = -accel_data[2];
2103 gyro_data[2] = -gyro_data[2];
2106 if (layout & 0x01) {
2107 accel_data[0] = raw_a[1];
2108 accel_data[1] = raw_a[0];
2109 gyro_data[0] = raw_g[1];
2110 gyro_data[1] = raw_g[0];
2112 accel_data[0] = raw_a[0];
2113 accel_data[1] = raw_a[1];
2114 gyro_data[0] = raw_g[0];
2115 gyro_data[1] = raw_g[1];
2118 if (layout == 1 || layout == 2 || layout == 4 || layout == 7) {
2119 accel_data[0] = -accel_data[0];
2120 gyro_data[0] = -gyro_data[0];
2122 if (layout == 2 || layout == 3 || layout == 6 || layout == 7) {
2123 accel_data[1] = -accel_data[1];
2124 gyro_data[1] = -gyro_data[1];
2158 for (
int i = 0;
i < 3;
i++) {
2170 for (
int i = 0;
i < 3;
i++) {
2235 float gyro_magnitude = sqrtf(
2236 static_cast<float>(gyro_data[0]) * gyro_data[0] +
2237 static_cast<float>(gyro_data[1]) * gyro_data[1] +
2238 static_cast<float>(gyro_data[2]) * gyro_data[2]
2240 float accel_magnitude = sqrtf(
2241 static_cast<float>(accel_data[0]) * accel_data[0] +
2242 static_cast<float>(accel_data[1]) * accel_data[1] +
2243 static_cast<float>(accel_data[2]) * accel_data[2]
2247 float accel_sum = 0;
2269 accel_sum += diff * diff;
2271 gyro_sum += diff * diff;
2288 for (
int i = 0;
i < 3;
i++) {
2293 for (
int i = 0;
i < 3;
i++) {
2298 for (
int i = 0;
i < 3;
i++) {
2316 if (!
hal)
return false;
2326 writeReg(REG_CTRL2,
static_cast<uint8_t
>((ACCEL_RANGE_8G << 4) | ACCEL_ODR_224_2HZ | 0x80));
2329 while (retry-- > 0) {
2330 uint8_t status =
readReg(REG_STATUS_INT);
2331 if (status != 0xFF && (status & MASK_INT_AVAIL)) {
2337 writeReg(REG_CTRL2,
static_cast<uint8_t
>((ACCEL_RANGE_8G << 4) | ACCEL_ODR_224_2HZ));
2340 while (retry-- > 0) {
2341 uint8_t status =
readReg(REG_STATUS_INT);
2342 if (status != 0xFF && !(status & MASK_INT_AVAIL)) {
2348 uint8_t reg_data[6];
2355 int16_t raw_x = (int16_t)((reg_data[1] << 8) | reg_data[0]);
2356 int16_t raw_y = (int16_t)((reg_data[3] << 8) | reg_data[2]);
2357 int16_t raw_z = (int16_t)((reg_data[5] << 8) | reg_data[4]);
2375 writeReg(REG_CTRL3,
static_cast<uint8_t
>((GYRO_RANGE_1024DPS << 4) | GYRO_ODR_224_2HZ | 0x80));
2378 while (retry-- > 0) {
2379 uint8_t status =
readReg(REG_STATUS_INT);
2380 if (status != 0xFF && (status & MASK_INT_AVAIL)) {
2386 writeReg(REG_CTRL3,
static_cast<uint8_t
>((GYRO_RANGE_1024DPS << 4) | GYRO_ODR_224_2HZ));
2389 while (retry-- > 0) {
2390 uint8_t status =
readReg(REG_STATUS_INT);
2391 if (status != 0xFF && !(status & MASK_INT_AVAIL)) {
2397 uint8_t reg_data[6];
2404 int16_t raw_x = (int16_t)((reg_data[1] << 8) | reg_data[0]);
2405 int16_t raw_y = (int16_t)((reg_data[3] << 8) | reg_data[2]);
2406 int16_t raw_z = (int16_t)((reg_data[5] << 8) | reg_data[4]);
2451 if (
id != QMI8658_WHO_AM_I_VAL) {
2452 SENSORLIB_LOG_E(
"QMI8658 ID mismatch: expected 0x%02X, got 0x%02X", QMI8658_WHO_AM_I_VAL,
id);
2463 uint8_t buffer[3] = {0};
2465 _firmware_version = buffer[0] | (uint32_t)(buffer[1] << 8) | (uint32_t)(buffer[2] << 16);
OperationMode
Enumeration of sensor operation modes.
GyroFullScaleRange
Enumeration of gyroscope full-scale range settings.
AccelFullScaleRange
Enumeration of accelerometer full-scale range settings.
#define SENSORLIB_LOG_I(...)
#define SENSORLIB_LOG_E(...)
#define SENSORLIB_LOG_D(...)
std::unique_ptr< SensorHal > hal
bool clrRegBit(uint8_t reg, uint8_t bit)
bool getRegBit(uint8_t reg, uint8_t bit)
int readReg(uint8_t reg) const
int writeRegBuff(uint8_t reg, uint8_t *buf, size_t len)
int writeReg(uint8_t reg, uint8_t val)
int readRegBuff(uint8_t reg, uint8_t *buf, size_t len) const
int updateBits(uint8_t reg, uint8_t mask, uint8_t value_shifted)
bool setRegBit(uint8_t reg, uint8_t bit)
bool configGyro(GyroFullScaleRange range, float data_rate_hz, LpfMode lpf=LpfMode::MODE_0)
Configure the gyroscope with specified parameters.
GyroODR
Gyroscope output data rate enumeration.
static constexpr uint8_t DYN_CAL_BUFFER_SIZE
bool reset() override
Reset the IMU sensor to its default state.
bool _motion_any_configured
bool resetFifo()
Reset the FIFO.
static constexpr uint8_t STATUS_TAP_EVENT
bool configPedometer(uint16_t sample_count, uint16_t peak_to_peak, uint16_t peak_threshold, uint16_t time_up, uint8_t time_low=20, uint8_t entry_count=10, uint8_t fix_precision=0, uint8_t sig_count=4)
Configure pedometer parameters.
uint16_t _static_cali_sample_count
float _accel_speed_buffer[DYN_CAL_BUFFER_SIZE]
bool readGyro(GyroscopeData &out) override
Read gyroscope data.
uint32_t _last_tap_event_ms
bool _static_cali_enabled
void setAccelOffset(int16_t x, int16_t y, int16_t z)
Set accelerometer host delta offsets.
float _hw_st_accel_result[3]
bool _static_cali_complete
float _gyro_static_deviation
@ CTRL_CMD_CONFIGURE_MOTION
@ CTRL_CMD_APPLY_GYRO_GAINS
@ CTRL_CMD_GYRO_HOST_DELTA_OFFSET
@ CTRL_CMD_ON_DEMAND_CALIBRATION
@ CTRL_CMD_WRITE_WOM_SETTING
@ CTRL_CMD_AHB_CLOCK_GATING
@ CTRL_CMD_RESET_PEDOMETER
@ CTRL_CMD_CONFIGURE_PEDOMETER
@ CTRL_CMD_ACCEL_HOST_DELTA_OFFSET
bool setOperationMode(OperationMode mode) override
Set IMU operation mode.
bool disableTap()
Disable tap detection.
bool readGyroRaw(int16_t &x, int16_t &y, int16_t &z) override
Read raw gyroscope data without scaling.
float getTemperature() override
Get the temperature reading from the sensor.
uint8_t getInterruptStatus()
Get interrupt status.
static constexpr uint8_t STATUS_WOM_EVENT
float getGyroScaleFromRange(GyroFullScaleRange range)
void getStaticCalibrationOffsets(int16_t accel_offset[3], int16_t gyro_offset[3])
Get static calibration offsets.
int16_t _dyn_gyro_offset[3]
void setSignificantMotionCallback(MotionCallback callback)
Set callback for significant motion event.
bool isGyroEnabled() override
Check if gyroscope is enabled.
bool isDataReady(uint8_t mask=static_cast< uint8_t >(ImuBase::DataReadyMask::BOTH)) override
Check if requested IMU data is available.
uint8_t findClosestAccelLpOdr(float hz)
bool configMotionDetectDefault(MotionType type)
Configure motion detection with default parameters.
static constexpr uint16_t MAX_STATIC_CALI_SAMPLES
uint16_t _motion_sig_wait_window
uint32_t getStepCount()
Get pedometer step count.
int16_t _accel_cali_offset[3]
bool disableMotionDetect()
Disable motion detection.
int writeCommand(uint8_t cmd, uint32_t timeout_ms=1000)
int32_t _accel_cali_sum[3]
bool setAccelOutputDataRate(float data_rate_hz) override
Set accelerometer output data rate.
void setDataLockingCallback(DataReadyCallback callback)
Set callback for data locking.
std::function< void(TapEvent event)> TapCallback
Callback function type for tap events.
uint8_t getAccelRangeRegValue(AccelFullScaleRange range)
bool enableAccel() override
Enable the accelerometer.
static constexpr uint8_t STATUS_SIGNIFICANT_MOTION
GyroFullScaleRange _gyro_range
static constexpr float HW_ST_ACCEL_THRESHOLD_MG
bool configFifo(FifoMode mode, FifoSamples samples=FifoSamples::SAMPLES_16, uint8_t watermark_samples=16)
Configure FIFO with specified mode.
bool isStaticCalibrationComplete() const
Get the current static calibration status.
bool processStaticCalibration(int16_t accel_data[3], int16_t gyro_data[3])
Process static calibration with current sensor data.
float getAccelScale()
Get the accelerometer scale factor.
uint8_t _dyn_cali_sample_count
uint8_t _motion_no_thr[3]
void resetStaticCalibration()
Reset static calibration.
uint8_t getChipID() override
Get the chip ID / WHO_AM_I value.
bool disableSyncMode() override
Disable synchronous sampling mode.
bool _motion_no_configured
bool enableSyncMode() override
Enable synchronous sampling mode.
void setIntPin(int pin)
Backward-compatible alias of setPins.
float odrToFloat(float odr)
float _hw_st_gyro_result[3]
AccelODR
Accelerometer output data rate enumeration.
@ ODR_LP_21Hz
Low power 21 Hz.
@ ODR_LP_11Hz
Low power 11 Hz.
@ ODR_LP_128Hz
Low power 128 Hz.
@ ODR_LP_3Hz
Low power 3 Hz.
bool disableLockingMechanism()
Disable the data locking mechanism.
uint32_t _dyn_static_delay
bool disableAccel() override
Disable the accelerometer.
bool selfTestGyro()
Perform gyroscope self-test.
void processDynamicCalibration(int16_t accel_data[3], int16_t gyro_data[3])
Process dynamic calibration with current sensor data.
bool enableInterrupt(IntPin pin)
Enable interrupt on specified pin.
void enableStaticCalibration(bool enable)
Start static calibration.
bool readAccel(AccelerometerData &out) override
Read accelerometer data.
void getDynamicGyroCalibrationOffsets(int16_t gyro_offset[3])
Get dynamic gyroscope calibration offsets.
uint8_t findClosestAccelOdr(float hz)
bool enablePedometer(IntPin pin=IntPin::DISABLE)
Enable pedometer.
FifoMode
FIFO mode enumeration.
@ STREAM
Stream mode (overwrites oldest)
@ BYPASS
Bypass mode (FIFO disabled)
@ FIFO
FIFO mode (stops when full)
void setTapCallback(TapCallback callback)
Set callback for tap event.
uint16_t _fifo_buffer_size
bool enableGyro() override
Enable the gyroscope.
bool configTap(TapPriority priority, uint8_t peak_window, uint16_t tap_window, uint16_t double_tap_window, float peak_mag_threshold, float quiet_threshold)
Configure tap detection parameters.
bool disableGyro() override
Disable the gyroscope.
~SensorQMI8658() override
Destroy the SensorQMI8658 object.
uint16_t readFromFifo(AccelerometerData *accel_data, uint16_t accel_count, GyroscopeData *gyro_data, uint16_t gyro_count) override
Read data from FIFO buffer.
bool enableDataReadyInterrupt(IntPin pin=IntPin::PIN2)
Enable data ready interrupt.
bool enableLockingMechanism()
Enable the data locking mechanism.
uint32_t getFirmwareVersion() override
Get the firmware version.
void setNoMotionCallback(MotionCallback callback)
Set callback for no-motion event.
static constexpr float HW_ST_GYRO_THRESHOLD_DPS
TapEvent getTapStatus()
Get tap status.
static constexpr uint8_t STATUS_ANY_MOTION_EVENT
uint8_t _dyn_offset_applied
bool isPresent() override
Check if the IMU sensor is responding.
uint8_t getGyroRangeRegValue(GyroFullScaleRange range)
GyroRange
Gyroscope full-scale range enumeration.
@ FS_128DPS
±128 degrees per second
@ FS_512DPS
±512 degrees per second
@ FS_2048DPS
±2048 degrees per second
@ FS_1024DPS
±1024 degrees per second
@ FS_256DPS
±256 degrees per second
bool isAccelEnabled() override
Check if accelerometer is enabled.
bool configureFifo(bool enable, uint8_t watermark_samples=16) override
Configure the FIFO buffer.
EventCallbacks & getCallbacks()
Get current callbacks.
void enableDynamicGyroCalibration(bool enable)
Enable dynamic gyroscope calibration.
Layout getAxisLayout() const
Get the current axis layout setting.
int32_t _gyro_cali_sum[3]
float _gyro_speed_buffer[DYN_CAL_BUFFER_SIZE]
SensorQMI8658()
Construct a new SensorQMI8658 object.
bool enableTap(IntPin pin=IntPin::PIN1)
Enable tap detection.
void setGyroOffset(int16_t x, int16_t y, int16_t z)
Set gyroscope host delta offsets.
float getAccelScaleFromRange(AccelFullScaleRange range)
LpfMode
Low-pass filter mode enumeration.
@ MODE_0
2.66% of output data rate
@ OFF
Disable low-pass filter.
@ MODE_3
13.37% of output data rate
@ MODE_2
5.39% of output data rate
@ MODE_1
3.63% of output data rate
AccelRange
Accelerometer full-scale range enumeration.
bool enableMotionDetect(IntPin pin=IntPin::PIN1)
Enable motion detection on specified pin.
bool _motion_sig_configured
uint8_t findClosestGyroOdr(float hz)
bool calibrate(uint16_t *gyro_x_gain=nullptr, uint16_t *gyro_y_gain=nullptr, uint16_t *gyro_z_gain=nullptr)
Perform on-demand calibration.
bool initImpl(uint8_t param) override
bool isDynamicGyroCalibrationEnabled() const
Check if dynamic gyro calibration is enabled.
bool setGyroFullScaleRange(GyroFullScaleRange range) override
Set gyroscope full scale range.
MotionType
Motion detection type enumeration.
@ ANY_MOTION
Any motion detection.
@ NO_MOTION
No motion detection.
@ SIGNIFICANT
Significant motion detection.
bool setGyroOutputDataRate(float data_rate_hz) override
Set gyroscope output data rate.
AccelFullScaleRange _accel_range
uint8_t _motion_any_thr[3]
void setAccelDataReadyCallback(DataReadyCallback callback)
Set callback for accelerometer data ready.
void setPedometerCallback(MotionCallback callback)
Set callback for pedometer event.
std::function< void()> DataReadyCallback
Callback function type for data ready events.
int16_t _gyro_cali_offset[3]
uint8_t _motion_any_window
bool selfTest() override
Perform self-test on the IMU sensor.
void setAnyMotionCallback(MotionCallback callback)
Set callback for any-motion event.
void dumpRegisters()
Dump control registers for debugging.
bool resetStepCount()
Reset pedometer counter.
bool configAccel(AccelFullScaleRange range, float data_rate_hz, LpfMode lpf=LpfMode::MODE_0)
Configure the accelerometer with specified parameters.
uint16_t update()
Update sensor status and process events.
float getGyroScale()
Get the gyroscope scale factor.
void getHardwareSelfTestResults(float accel_result[3], float gyro_result[3])
Get hardware self-test results.
static constexpr uint8_t STATUS_PEDOMETER_EVENT
bool configTapDefault(TapPriority priority=TapPriority::X_GT_Y_GT_Z)
Configure tap detection with default parameters.
bool readAccelRaw(int16_t &x, int16_t &y, int16_t &z) override
Read raw accelerometer data without scaling.
uint8_t getFifoStatus()
Get FIFO status.
uint32_t getTimestamp() override
Get the timestamp from the sensor.
std::function< void()> MotionCallback
Callback function type for motion events.
bool setAccelFullScaleRange(AccelFullScaleRange range) override
Set accelerometer full scale range.
void setCallbacks(const EventCallbacks &cbs)
Set all event callbacks at once.
void setPins(int pin)
Set interrupt pin.
bool configWakeOnMotion(uint8_t threshold=200, float odr_hz=128.0f, IntPin pin=IntPin::PIN2)
Configure wake-on-motion (WoM) feature.
bool configPedometerDefault(float odr=125.0f)
Configure pedometer with default parameters.
uint8_t _motion_no_window
bool disablePedometer()
Disable pedometer.
void setGyroDataReadyCallback(DataReadyCallback callback)
Set callback for gyroscope data ready.
bool hardwareSelfTest(bool includeAccel=true, bool includeGyro=true)
Perform hardware self-test on both sensors.
TapPriority
Tap detection axis priority enumeration.
void setAxisLayout(Layout layout)
Set the sensor axis layout for coordinate transformation.
uint16_t _motion_sig_confirm_window
bool configWakeOnMotionAdvanced(uint8_t threshold, float odr_hz, IntPin pin, uint8_t default_pin_value, uint8_t blanking_time, AccelFullScaleRange acc_range)
Configure wake-on-motion (WoM) with full vendor parameters.
bool isStaticCalibrationEnabled() const
Check if static calibration is enabled.
void setWakeOnMotionCallback(MotionCallback callback)
Set callback for wake-on-motion event.
void axisConvert(int16_t accel_data[3], int16_t gyro_data[3])
Apply axis conversion to raw sensor data.
bool selfTestAccel()
Perform accelerometer self-test.
static constexpr uint8_t STATUS_NO_MOTION_EVENT
static constexpr uint8_t DYN_CAL_STATIC_COUNT
bool writeCalibration(uint16_t gyro_x_gain, uint16_t gyro_y_gain, uint16_t gyro_z_gain)
Write previously saved gyro calibration gains.
uint32_t _last_step_count
void getChipUsid(uint8_t *buffer, uint8_t length)
Get sensor USID (unique chip ID).
Layout
Sensor axis layout enumeration for coordinate transformation.
uint32_t _firmware_version
FifoSamples
FIFO sample count enumeration.
bool configMotionDetect(MotionType type, float threshold_x, float threshold_y, float threshold_z, uint8_t duration)
Configure motion detection parameters.
float _accel_static_deviation
bool disableInterrupt(IntPin pin)
Disable interrupt on specified pin.
uint8_t mgToBytes(float mg)
float gToMps2(float g_value)
Convert acceleration from g-force to m/s²
const uint16_t buffer_size
Structure representing accelerometer data.
SensorVector mps2
Acceleration in meters per second squared (m/s²)
float temperature
Temperature in degrees Celsius (if available)
RawVector raw
Raw sensor values in LSB (least significant bits)
Structure representing gyroscope data.
float temperature
Temperature in °C (if available)
SensorVector dps
Angular velocity in degrees per second (°/s)
RawVector raw
Raw sensor values in LSB.
int16_t x
X-axis raw value.
int16_t y
Y-axis raw value.
int16_t z
Z-axis raw value.
Grouped callbacks for QMI8658 events.
MotionCallback onAnyMotion
DataReadyCallback onAccelDataReady
MotionCallback onSignificantMotion
MotionCallback onNoMotion
DataReadyCallback onGyroDataReady
MotionCallback onPedometer
DataReadyCallback onDataLocking
MotionCallback onWakeOnMotion