JeVois  1.18
JeVois Smart Embedded Machine Vision Toolkit
Share this page:
ICM20948.C
Go to the documentation of this file.
1 // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2 //
3 // JeVois Smart Embedded Machine Vision Toolkit - Copyright (C) 2018 by Laurent Itti, the University of Southern
4 // California (USC), and iLab at USC. See http://iLab.usc.edu and http://jevois.org for information about this project.
5 //
6 // This file is part of the JeVois Smart Embedded Machine Vision Toolkit. This program is free software; you can
7 // redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software
8 // Foundation, version 2. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9 // without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
10 // License for more details. You should have received a copy of the GNU General Public License along with this program;
11 // if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
12 //
13 // Contact information: Laurent Itti - 3641 Watt Way, HNB-07A - Los Angeles, CA 90089-2520 - USA.
14 // Tel: +1 213 740 3527 - itti@pollux.usc.edu - http://iLab.usc.edu - http://jevois.org
15 // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
16 /*! \file */
17 
18 #include <jevois/Core/Engine.H>
19 #include <jevois/Core/ICM20948.H>
21 
22 // This code inspired by:
23 
24 /***************************************************************************//**
25  * file ICM20648.cpp
26  *******************************************************************************
27  * section License
28  * <b>(C) Copyright 2017 Silicon Labs, http://www.silabs.com</b>
29  *******************************************************************************
30  *
31  * SPDX-License-Identifier: Apache-2.0
32  *
33  * Licensed under the Apache License, Version 2.0 (the "License"); you may
34  * not use this file except in compliance with the License.
35  * You may obtain a copy of the License at
36  *
37  * http://www.apache.org/licenses/LICENSE-2.0
38  *
39  * Unless required by applicable law or agreed to in writing, software
40  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
41  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
42  * See the License for the specific language governing permissions and
43  * limitations under the License.
44  *
45  ******************************************************************************/
46 
47 // motion event control reg
48 #define JEVOIS_DMP_BAC_WEARABLE_EN 0x8000
49 #define JEVOIS_DMP_PEDOMETER_EN 0x4000
50 #define JEVOIS_DMP_PEDOMETER_INT_EN 0x2000
51 #define JEVOIS_DMP_SMD_EN 0x0800
52 #define JEVOIS_DMP_BTS_EN 0x0020
53 #define JEVOIS_DMP_FLIP_PICKUP_EN 0x0010
54 #define JEVOIS_DMP_GEOMAG_EN 0x0008
55 #define JEVOIS_DMP_ACCEL_CAL_EN 0x0200
56 #define JEVOIS_DMP_GYRO_CAL_EN 0x0100
57 #define JEVOIS_DMP_COMPASS_CAL_EN 0x0080
58 #define JEVOIS_DMP_NINE_AXIS_EN 0x0040
59 #define JEVOIS_DMP_BRING_AND_LOOK_T0_SEE_EN 0x0004
60 
61 // ####################################################################################################
62 jevois::ICM20948::ICM20948(std::string const & instance) :
63  jevois::Component(instance)
64 { }
65 
66 // ####################################################################################################
68 { }
69 
70 // ####################################################################################################
71 unsigned char jevois::ICM20948::readMagRegister(unsigned char magreg)
72 {
73  // We use slave4, which is oneshot:
74  itsIMU->writeRegister(ICM20948_REG_I2C_SLV4_ADDR, ICM20948_BIT_I2C_READ | COMPASS_SLAVEADDR);
75  itsIMU->writeRegister(ICM20948_REG_I2C_SLV4_REG, magreg);
76  itsIMU->writeRegister(ICM20948_REG_I2C_SLV4_CTRL, ICM20948_BIT_I2C_SLV_EN);
77 
78  waitForSlave4();
79 
80  return itsIMU->readRegister(ICM20948_REG_I2C_SLV4_DI);
81 }
82 
83 // ####################################################################################################
84 void jevois::ICM20948::waitForSlave4()
85 {
86  // Wait until the data is ready:
87  auto tooLate = std::chrono::steady_clock::now() + std::chrono::milliseconds(300);
88 
89  do
90  {
91  std::this_thread::sleep_for(std::chrono::milliseconds(10));
92  unsigned char status = itsIMU->readRegister(ICM20948_REG_I2C_MST_STATUS);
93  if (status & ICM20948_BIT_SLV4_NACK) LFATAL("Failed to communicate with compass: NACK");
94  if (status & ICM20948_BIT_SLV4_DONE) return; // Transaction to slave is complete
95  }
96  while (std::chrono::steady_clock::now() < tooLate);
97 
98  LFATAL("Failed to communicate with compass: timeout");
99 }
100 
101 // ####################################################################################################
102 void jevois::ICM20948::writeMagRegister(unsigned char magreg, unsigned char val)
103 {
104  // We use slave4, which is oneshot:
105  itsIMU->writeRegister(ICM20948_REG_I2C_SLV4_ADDR, COMPASS_SLAVEADDR);
106  itsIMU->writeRegister(ICM20948_REG_I2C_SLV4_REG, magreg);
107  itsIMU->writeRegister(ICM20948_REG_I2C_SLV4_DO, val);
108  itsIMU->writeRegister(ICM20948_REG_I2C_SLV4_CTRL, ICM20948_BIT_I2C_SLV_EN);
109 
110  waitForSlave4();
111 }
112 
113 // ####################################################################################################
115 {
116  // Make sure we have an IMU low-level driver:
117  itsIMU = engine()->imu();
118  if (!itsIMU) LFATAL("IMU chip was not detected but is required for this module -- ABORT");
119 
120  // Warm up the connection...
121  ready(); ready();
122 
123  // Make sure the chip has been detected:
124  if (ready() == false)
125  LFATAL("Cannot access ICM20948 inertial measurement unit (IMU) chip. This chip is only available on JeVois-A33 "
126  "with a modified Global Shutter OnSemi (Aptina) AR0135 camera sensor. It is not included with standard "
127  "JeVois-A33 cameras. It is included in JeVois-Pro.");
128 
129  // Configure the compass:
130 
131  // First, disable slaves:
132  itsIMU->writeRegister(ICM20948_REG_I2C_SLV0_CTRL, 0);
133  itsIMU->writeRegister(ICM20948_REG_I2C_SLV1_CTRL, 0);
134  itsIMU->writeRegister(ICM20948_REG_I2C_SLV2_CTRL, 0);
135  itsIMU->writeRegister(ICM20948_REG_I2C_SLV3_CTRL, 0);
136  itsIMU->writeRegister(ICM20948_REG_I2C_SLV4_CTRL, 0);
137 
138  // Recommended target for I2C master clock:
139  itsIMU->writeRegister(ICM20948_REG_I2C_MST_CTRL, 0x07 | ICM20948_BIT_I2C_MST_P_NSR);
140 
141  // Enable master I2C:
142  unsigned char v = itsIMU->readRegister(ICM20948_REG_USER_CTRL);
143  v |= ICM20948_BIT_I2C_MST_EN;
144  if (itsIMU->isSPI()) v |= ICM20948_BIT_I2C_IF_DIS;
145  itsIMU->writeRegister(ICM20948_REG_USER_CTRL, v);
146  std::this_thread::sleep_for(std::chrono::milliseconds(1));
147 
148  // Check the who-am-I of the magnetometer, to make sure I2C master is working:
149  unsigned char wia2 = readMagRegister(REG_AK09916_WIA);
150  if (wia2 != VAL_AK09916_WIA) LFATAL("Cannot communicate with magnetometer");
151  LINFO("AK09916 magnetometer ok.");
152 
153  // Enable 0x80 in ICM20948_REG_PWR_MGMT_2, needed by DMP:
154  itsIMU->writeRegister(ICM20948_REG_PWR_MGMT_2, itsIMU->readRegister(ICM20948_REG_PWR_MGMT_2) | 0x80);
155 
156  // Enable FSYNC time counting:
157  itsIMU->writeRegister(ICM20948_REG_FSYNC_CONFIG, ICM20948_BIT_FSYNC_TIME_EN | ICM20948_BIT_FSYNC_DEGLITCH_EN |
158  ICM20948_BIT_FSYNC_EDGE_EN | ICM20948_BITS_FSYNC_SET_TEMP);
159  itsIMU->writeRegister(ICM20948_REG_INT_PIN_CFG, ICM20948_BIT_INT_FSYNC_EN); //| ICM20948_BIT_INT_ACTL_FSYNC);
160  itsIMU->writeRegister(ICM20948_REG_INT_ENABLE, ICM20948_BIT_FSYNC_INT_EN);
161 }
162 
163 // ####################################################################################################
165 {
166  // Configure the DMP if desired:
167  mode::freeze();
168  switch (mode::get())
169  {
170  case jevois::imu::Mode::DMP:
171  {
172  // The DMP code was loaded by the kernel driver, which also has set the start address. So here we just need to
173  // launch the DMP. First, disable FIFO and DMP:
174  unsigned char v = itsIMU->readRegister(ICM20948_REG_USER_CTRL);
175  v &= ~(ICM20948_BIT_DMP_EN | ICM20948_BIT_FIFO_EN); v |= ICM20948_BIT_DMP_RST;
176  if (itsIMU->isSPI()) v |= ICM20948_BIT_I2C_IF_DIS;
177  itsIMU->writeRegister(ICM20948_REG_USER_CTRL, v);
178  std::this_thread::sleep_for(std::chrono::milliseconds(1));
179 
180  // Reset / setup the FIFO:
181  itsIMU->writeRegister(ICM20948_REG_FIFO_CFG, ICM20948_BIT_MULTI_FIFO_CFG); // FIFO Config
182  itsIMU->writeRegister(ICM20948_REG_FIFO_RST, 0x1f); // Reset all FIFOs.
183  itsIMU->writeRegister(ICM20948_REG_FIFO_RST, 0x1e); // Keep all but Gyro FIFO in reset.
184  itsIMU->writeRegister(ICM20948_REG_FIFO_EN_1, 0x0); // Slave FIFO turned off.
185  itsIMU->writeRegister(ICM20948_REG_FIFO_EN_2, 0x0); // Hardware FIFO turned off.
186 
187  itsIMU->writeRegister(ICM20948_REG_SINGLE_FIFO_PRIORITY_SEL, 0xe4); // Use a single interrupt for FIFO
188 
189  // Enable DMP interrupts:
190  itsIMU->writeRegister(ICM20948_REG_INT_ENABLE,
191  ICM20948_BIT_FSYNC_INT_EN | ICM20948_BIT_DMP_INT_EN); // Enable DMP Interrupt
192  itsIMU->writeRegister(ICM20948_REG_INT_ENABLE_1, ICM20948_BIT_RAW_DATA_0_RDY_EN | ICM20948_BIT_RAW_DATA_1_RDY_EN |
193  ICM20948_BIT_RAW_DATA_2_RDY_EN |
194  ICM20948_BIT_RAW_DATA_3_RDY_EN); // Enable raw data ready Interrupt
195  itsIMU->writeRegister(ICM20948_REG_INT_ENABLE_2, ICM20948_BIT_FIFO_OVERFLOW_EN_0); // Enable FIFO Overflow Interrupt
196 
197  // Force an execution of our dmp callback:
198  dmp::set(dmp::get());
199 
200  // Enable DMP:
201  v |= ICM20948_BIT_DMP_EN | ICM20948_BIT_FIFO_EN; v &= ~ICM20948_BIT_DMP_RST;
202  if (itsIMU->isSPI()) v |= ICM20948_BIT_I2C_IF_DIS;
203  itsIMU->writeRegister(ICM20948_REG_USER_CTRL, v);
204 
205  LINFO("IMU Digital Motion Processor (DMP) enabled.");
206  }
207  break;
208 
209  case jevois::imu::Mode::FIFO:
210  {
211  // Disable the DMP:
212  unsigned char v = itsIMU->readRegister(ICM20948_REG_USER_CTRL);
213  v &= ~ICM20948_BIT_DMP_EN; v |= ICM20948_BIT_DMP_RST;
214  if (itsIMU->isSPI()) v |= ICM20948_BIT_I2C_IF_DIS;
215  itsIMU->writeRegister(ICM20948_REG_USER_CTRL, v);
216 
217  // Enable FIFO, set packet size, nuke any old FIFO data:
218  computeFIFOpktSize(-1.0F, -1.0F, -1);
219 
220  // DMP is not available:
221  dmp::freeze();
222 
223  LINFO("IMU FIFO mode enabled.");
224  }
225  break;
226 
227  case jevois::imu::Mode::RAW:
228  {
229  // Disable the DMP and FIFO:
230  unsigned char v = itsIMU->readRegister(ICM20948_REG_USER_CTRL);
231  v &= ~(ICM20948_BIT_DMP_EN | ICM20948_BIT_FIFO_EN); v |= ICM20948_BIT_DMP_RST;
232  if (itsIMU->isSPI()) v |= ICM20948_BIT_I2C_IF_DIS;
233  itsIMU->writeRegister(ICM20948_REG_USER_CTRL, v);
234 
235  // DMP is not available:
236  dmp::freeze();
237  pktdbg::freeze();
238 
239  LINFO("IMU raw data mode enabled.");
240  }
241  break;
242  }
243 }
244 
245 // ####################################################################################################
247 {
248  mode::unFreeze();
249 }
250 
251 // ####################################################################################################
253 {
254  return (itsIMU->readRegister(ICM20948_REG_WHO_AM_I) == ICM20948_DEVICE_ID);
255 }
256 
257 // ####################################################################################################
259 {
260  switch(mode::get())
261  {
262  case jevois::imu::Mode::FIFO:
263  case jevois::imu::Mode::DMP:
264  {
265  unsigned char datalen[2];
266  itsIMU->readRegisterArray(ICM20948_REG_FIFO_COUNT_H, &datalen[0], 2);
267  return (datalen[0] << 8) + datalen[1];
268  }
269  case jevois::imu::Mode::RAW:
270  {
271  unsigned char val = itsIMU->readRegister(ICM20948_REG_INT_STATUS_1);
272  if (val & ICM20948_BIT_RAW_DATA_0_RDY_INT) return 1;
273  return 0;
274  }
275  }
276  return 0; // Keep compiler happy
277 }
278 
279 // ####################################################################################################
281 {
282  IMUrawData d;
283 
284  switch(mode::get())
285  {
286  // ----------------------------------------------------------------------------------------------------
287  case jevois::imu::Mode::FIFO:
288  {
289  int siz = dataReady();
290 
291  // Gobble up the FIFO if it is getting full, so that we never get out of sync:
292  if (siz > 500)
293  {
294  LERROR("IMU FIFO filling up. You need to call get() more often or reduce rate. Data will be lost.");
295  while (siz > 100)
296  {
297  unsigned char trash[itsFIFOpktSiz];
298  itsIMU->readRegisterArray(ICM20948_REG_FIFO_R_W, &trash[0], itsFIFOpktSiz);
299  siz = dataReady();
300  }
301  }
302 
303  if (siz < itsFIFOpktSiz)
304  {
305  if (blocking == false) return d;
306 
307  auto tooLate = std::chrono::steady_clock::now() + std::chrono::seconds(2);
308  do
309  {
310  std::this_thread::sleep_for(std::chrono::milliseconds(1));
311  if (std::chrono::steady_clock::now() > tooLate)
312  { LERROR("TIMEOUT waiting for IMU FIFO data - RETURNING BLANK"); return d; }
313  siz = dataReady();
314  }
315  while (siz < itsFIFOpktSiz);
316  }
317 
318  // Read the packet:
319  unsigned char packet[itsFIFOpktSiz];
320  itsIMU->readRegisterArray(ICM20948_REG_FIFO_R_W, &packet[0], itsFIFOpktSiz);
321 
322  // Decode the packet:
323  int off = 0;
324  if (arate::get() > 0.0F)
325  {
326  d.ax() = (packet[off + 0] << 8) | packet[off + 1];
327  d.ay() = (packet[off + 2] << 8) | packet[off + 3];
328  d.az() = (packet[off + 4] << 8) | packet[off + 5];
329  off += 6;
330  }
331  if (grate::get() > 0.0F)
332  {
333  d.gx() = (packet[off + 0] << 8) | packet[off + 1];
334  d.gy() = (packet[off + 2] << 8) | packet[off + 3];
335  d.gz() = (packet[off + 4] << 8) | packet[off + 5];
336  off += 6;
337  }
338  if (mrate::get() != jevois::imu::MagRate::Off && mrate::get() != jevois::imu::MagRate::Once)
339  {
340  d.mx() = (packet[off + 0] << 8) | packet[off + 1];
341  d.my() = (packet[off + 2] << 8) | packet[off + 3];
342  d.mz() = (packet[off + 4] << 8) | packet[off + 5];
343  d.mst2() = (packet[off + 6] << 8) | packet[off + 7];
344  off += 8;
345  }
346  d.temp() = 0; // temp not available in FIFO mode
347 
348  // Debug raw packet dump:
349  if (pktdbg::get())
350  {
351  std::stringstream stream; stream << "RAW" << std::hex;
352  for (int i = 0; i < itsFIFOpktSiz; ++i) stream << ' ' << (unsigned int)(packet[i]);
353  LINFO(stream.str());
354  }
355  }
356  break;
357 
358  // ----------------------------------------------------------------------------------------------------
359  case jevois::imu::Mode::RAW:
360  case jevois::imu::Mode::DMP:
361  {
362  // Grab the raw data register contents:
363  itsIMU->readRegisterArray(ICM20948_REG_ACCEL_XOUT_H_SH, reinterpret_cast<unsigned char *>(&d.v[0]), 11*2);
364 
365  // The data from the sensor is in big endian, convert to little endian:
366  for (short & s : d.v) { short hi = (s & 0xff00) >> 8; short lo = s & 0x00ff; s = (lo << 8) | hi; }
367  }
368  break;
369  }
370 
371  return d;
372 }
373 
374 // ####################################################################################################
376 {
378 }
379 
380 // ####################################################################################################
382 {
383  if (mode::get() != jevois::imu::Mode::DMP) LFATAL("getDMP() only available when mode=DMP, see params.cfg");
384  DMPdata d;
385 
386  // Start parsing a new packet?
387  if (itsDMPsz < 4)
388  {
389  // We need at least 4 bytes in the FIFO to get going. Could be either two empty packets (may not exist), or the
390  // start of a non-empty packet, possibly with a header2 (which is why we want 4):
391  size_t got = getDMPsome(blocking, 4);
392  if (got < 4) return d;
393  }
394 
395  // Parse the headers:
396  unsigned short ctl1 = (itsDMPpacket[0] << 8) | itsDMPpacket[1];
397  int off = 2; // offset to where we are in parsing the packet so far
398  unsigned short ctl2 = 0;
399  if (ctl1 & JEVOIS_DMP_HEADER2) { ctl2 = (itsDMPpacket[off] << 8) | itsDMPpacket[off + 1]; off += 2; }
400 
401  // Compute how much data remains to be grabbed for this packet:
402  size_t need = jevois::DMPpacketSize(ctl1, ctl2) - itsDMPsz;
403 
404  // Read the rest of the packet if needed:
405  while (need > 0)
406  {
407  // We can read out max 32 bytes at a time:
408  size_t need2 = std::min(need, size_t(32));
409  size_t got = getDMPsome(blocking, need2);
410  if (got < need2) return d;
411  need -= got;
412  }
413 
414  // We have the whole packet, parse it:
415  d.parsePacket(itsDMPpacket, itsDMPsz);
416 
417  // Debug raw packet dump:
418  if (pktdbg::get())
419  {
420  std::stringstream stream; stream << "RAW" << std::hex;
421  for (int i = 0; i < itsDMPsz; ++i) stream << ' ' << (unsigned int)(itsDMPpacket[i]);
422  LINFO(stream.str());
423  }
424 
425  // Done with this packet, nuke it:
426  itsDMPsz = 0;
427 
428  return d;
429 }
430 
431 // ####################################################################################################
432 size_t jevois::ICM20948::getDMPsome(bool blocking, size_t desired)
433 {
434  size_t siz = dataReady();
435 
436  if (siz < desired)
437  {
438  if (blocking == false) return 0;
439 
440  auto tooLate = std::chrono::steady_clock::now() + std::chrono::seconds(2);
441  do
442  {
443  std::this_thread::sleep_for(std::chrono::milliseconds(1));
444 
445  if (std::chrono::steady_clock::now() >= tooLate)
446  { LERROR("TIMEOUT waiting for IMU DMP data - RETURNING BLANK"); return 0; }
447 
448  siz = dataReady();
449  }
450  while (siz < desired);
451  }
452 
453  // We have enough data in the FIFO, read out what we wanted:
454  itsIMU->readRegisterArray(ICM20948_REG_FIFO_R_W, &itsDMPpacket[itsDMPsz], desired);
455  itsDMPsz += desired;
456 
457  return desired;
458 }
459 
460 
461 // ####################################################################################################
463 {
464  // Set H_RESET bit to initiate soft reset:
465  itsIMU->writeRegister(ICM20948_REG_PWR_MGMT_1, ICM20948_BIT_H_RESET | ICM20948_BIT_CLK_PLL);
466 
467  // Wait a bit to complete the reset sequence:
468  std::this_thread::sleep_for(std::chrono::milliseconds(30));
469 }
470 
471 // ####################################################################################################
472 void jevois::ICM20948::onParamChange(jevois::imu::arate const & JEVOIS_UNUSED_PARAM(param), float const & newval)
473 {
474  // Disable or enable accelerometer:
475  uint8_t pwr = itsIMU->readRegister(ICM20948_REG_PWR_MGMT_2);
476  if (newval == 0.0F) pwr |= ICM20948_BIT_PWR_ACCEL_STBY; else pwr &= ~ICM20948_BIT_PWR_ACCEL_STBY;
477  itsIMU->writeRegister(ICM20948_REG_PWR_MGMT_2, pwr);
478 
479  if (newval)
480  {
481  // Calculate the sample rate divider:
482  float accelSampleRate = (1125.0F / newval) - 1.0F;
483 
484  // Check if it fits in the divider registers:
485  if (accelSampleRate > 4095.0F) accelSampleRate = 4095.0F; else if (accelSampleRate < 0.0F) accelSampleRate = 0.0F;
486 
487  // Write the value to the registers:
488  uint16_t const accelDiv = uint16_t(accelSampleRate);
489  itsIMU->writeRegister(ICM20948_REG_ACCEL_SMPLRT_DIV_1, uint8_t(accelDiv >> 8) );
490  itsIMU->writeRegister(ICM20948_REG_ACCEL_SMPLRT_DIV_2, uint8_t(accelDiv & 0xFF) );
491 
492  // Calculate the actual sample rate from the divider value:
493  LINFO("Accelerometer sampling rate set to " << 1125.0F / (accelDiv + 1.0F) << " Hz");
494  }
495 
496  computeFIFOpktSize(newval, -1.0F, -1);
497 }
498 
499 // ####################################################################################################
500 void jevois::ICM20948::onParamChange(jevois::imu::grate const & JEVOIS_UNUSED_PARAM(param), float const & newval)
501 {
502  // Disable or enable gyro:
503  uint8_t pwr = itsIMU->readRegister(ICM20948_REG_PWR_MGMT_2);
504  if (newval == 0.0F) pwr |= ICM20948_BIT_PWR_GYRO_STBY; else pwr &= ~ICM20948_BIT_PWR_GYRO_STBY;
505  itsIMU->writeRegister(ICM20948_REG_PWR_MGMT_2, pwr);
506 
507  if (newval)
508  {
509  // Calculate the sample rate divider:
510  float gyroSampleRate = (1125.0F / newval) - 1.0F; // FIXME: code says 1125, datasheet says 1100
511 
512  // Check if it fits in the divider registers:
513  if (gyroSampleRate > 255.0F) gyroSampleRate = 255.0F; else if (gyroSampleRate < 0.0F) gyroSampleRate = 0.0F;
514 
515  // Write the value to the register:
516  uint8_t const gyroDiv = uint8_t(gyroSampleRate);
517  itsIMU->writeRegister(ICM20948_REG_GYRO_SMPLRT_DIV, gyroDiv);
518 
519  // Calculate the actual sample rate from the divider value:
520  LINFO("Gyroscope sampling rate set to " << 1125.0F / (gyroDiv + 1.0F) << " Hz");
521  }
522  else std::this_thread::sleep_for(std::chrono::microseconds(22)); // Per datasheet: wait 22us after disabling gyro
523 
524  computeFIFOpktSize(-1.0F, newval, -1);
525 }
526 
527 // ####################################################################################################
528 void jevois::ICM20948::onParamChange(jevois::imu::mrate const & JEVOIS_UNUSED_PARAM(param),
529  jevois::imu::MagRate const & newval)
530 {
531  // Turn off the magnetometer:
532  writeMagRegister(REG_AK09916_CNTL2, VAL_AK09916_CNTL2_PD);
533 
534  // Set the mode value:
535  unsigned char mod;
536  switch (newval)
537  {
538  case jevois::imu::MagRate::Off: mod = VAL_AK09916_CNTL2_PD; break;
539  case jevois::imu::MagRate::Once: mod = VAL_AK09916_CNTL2_SNGL; break;
540  case jevois::imu::MagRate::M10Hz: mod = VAL_AK09916_CNTL2_MOD1; break;
541  case jevois::imu::MagRate::M20Hz: mod = VAL_AK09916_CNTL2_MOD2; break;
542  case jevois::imu::MagRate::M50Hz: mod = VAL_AK09916_CNTL2_MOD3; break;
543  case jevois::imu::MagRate::M100Hz: mod = VAL_AK09916_CNTL2_MOD4; break;
544  default: LFATAL("Invalid mode value: " << newval);
545  }
546 
547  // Wait until mag is down:
548  std::this_thread::sleep_for(std::chrono::milliseconds(10));
549 
550  // Now turn it back on in the specified mode:
551  writeMagRegister(REG_AK09916_CNTL2, mod);
552 
553  // Set output data rate (but is overridden by gyro ODR wen gyro is on):
554  itsIMU->writeRegister(ICM20948_REG_I2C_MST_ODR_CONFIG, 0x04); // Rate is 1.1kHz/(2^value)
555 
556  // Wait for magnetometer to be on:
557  std::this_thread::sleep_for(std::chrono::milliseconds(10));
558 
559  computeFIFOpktSize(-1.0F, -1.0F, mod);
560 
561  // Setup to transfer 8 bytes (RAW, FIFO) or 6 bytes (DMP) of data from magnetometer to ICM20948 main:
562  itsIMU->writeRegister(ICM20948_REG_I2C_SLV0_ADDR, ICM20948_BIT_I2C_READ | COMPASS_SLAVEADDR);
563  itsIMU->writeRegister(ICM20948_REG_I2C_SLV0_REG, REG_AK09916_HXL);
564  int siz = (mode::get() == jevois::imu::Mode::DMP) ? 6 : 8;
565  itsIMU->writeRegister(ICM20948_REG_I2C_SLV0_CTRL, // Enable, byteswap, odd-grouping, and read 8 or 6 bytes
566  ICM20948_BIT_I2C_SLV_EN | ICM20948_BIT_I2C_BYTE_SW | ICM20948_BIT_I2C_GRP | siz);
567 }
568 
569 // ####################################################################################################
570 void jevois::ICM20948::onParamChange(jevois::imu::abw const & JEVOIS_UNUSED_PARAM(param),
571  unsigned int const & newval)
572 {
573  uint8_t reg = itsIMU->readRegister(ICM20948_REG_ACCEL_CONFIG);
574 
575  switch (newval)
576  {
577  case 0: reg &= ~ICM20948_BIT_ACCEL_FCHOICE; break; // turn off low-pass filter
578  case 6: reg &= ~ICM20948_MASK_ACCEL_BW; reg |= ICM20948_ACCEL_BW_6HZ; break;
579  case 12: reg &= ~ICM20948_MASK_ACCEL_BW; reg |= ICM20948_ACCEL_BW_12HZ; break;
580  case 24: reg &= ~ICM20948_MASK_ACCEL_BW; reg |= ICM20948_ACCEL_BW_24HZ; break;
581  case 50: reg &= ~ICM20948_MASK_ACCEL_BW; reg |= ICM20948_ACCEL_BW_50HZ; break;
582  case 111: reg &= ~ICM20948_MASK_ACCEL_BW; reg |= ICM20948_ACCEL_BW_111HZ; break;
583  case 246: reg &= ~ICM20948_MASK_ACCEL_BW; reg |= ICM20948_ACCEL_BW_246HZ; break;
584  case 470: reg &= ~ICM20948_MASK_ACCEL_BW; reg |= ICM20948_ACCEL_BW_470HZ; break;
585  case 1210: reg &= ~ICM20948_MASK_ACCEL_BW; reg |= ICM20948_ACCEL_BW_1210HZ; break;
586  default: LFATAL("Invalid value");
587  }
588 
589  itsIMU->writeRegister(ICM20948_REG_ACCEL_CONFIG, reg);
590 }
591 
592 // ####################################################################################################
593 void jevois::ICM20948::onParamChange(jevois::imu::gbw const & JEVOIS_UNUSED_PARAM(param),
594  unsigned int const & newval)
595 {
596  uint8_t reg = itsIMU->readRegister(ICM20948_REG_GYRO_CONFIG_1);
597 
598  switch (newval)
599  {
600  case 0: reg &= ~ICM20948_BIT_GYRO_FCHOICE; break; // turn off low-pass filter
601  case 6: reg &= ~ICM20948_MASK_GYRO_BW; reg |= ICM20948_GYRO_BW_6HZ; break;
602  case 12: reg &= ~ICM20948_MASK_GYRO_BW; reg |= ICM20948_GYRO_BW_12HZ; break;
603  case 24: reg &= ~ICM20948_MASK_GYRO_BW; reg |= ICM20948_GYRO_BW_24HZ; break;
604  case 51: reg &= ~ICM20948_MASK_GYRO_BW; reg |= ICM20948_GYRO_BW_51HZ; break;
605  case 120: reg &= ~ICM20948_MASK_GYRO_BW; reg |= ICM20948_GYRO_BW_120HZ; break;
606  case 150: reg &= ~ICM20948_MASK_GYRO_BW; reg |= ICM20948_GYRO_BW_150HZ; break;
607  case 200: reg &= ~ICM20948_MASK_GYRO_BW; reg |= ICM20948_GYRO_BW_200HZ; break;
608  case 360: reg &= ~ICM20948_MASK_GYRO_BW; reg |= ICM20948_GYRO_BW_360HZ; break;
609  case 12100: reg &= ~ICM20948_MASK_GYRO_BW; reg |= ICM20948_GYRO_BW_12100HZ; break;
610  default: LFATAL("Invalid value");
611  }
612 
613  itsIMU->writeRegister(ICM20948_REG_GYRO_CONFIG_1, reg);
614 }
615 
616 // ####################################################################################################
617 void jevois::ICM20948::onParamChange(jevois::imu::tbw const & JEVOIS_UNUSED_PARAM(param),
618  unsigned int const & newval)
619 {
620  // Disable or enable temperature:
621  uint8_t pwr = itsIMU->readRegister(ICM20948_REG_PWR_MGMT_1);
622  if (newval == 0) pwr |= ICM20948_BIT_TEMP_DIS; else pwr &= ~ICM20948_BIT_TEMP_DIS;
623  itsIMU->writeRegister(ICM20948_REG_PWR_MGMT_1, pwr);
624 
625  if (newval == 0) return;
626 
627  switch (newval)
628  {
629  case 9: itsIMU->writeRegister(ICM20948_REG_TEMP_CONFIG, 6); break;
630  case 17: itsIMU->writeRegister(ICM20948_REG_TEMP_CONFIG, 5); break;
631  case 34: itsIMU->writeRegister(ICM20948_REG_TEMP_CONFIG, 4); break;
632  case 66: itsIMU->writeRegister(ICM20948_REG_TEMP_CONFIG, 3); break;
633  case 123: itsIMU->writeRegister(ICM20948_REG_TEMP_CONFIG, 2); break;
634  case 218: itsIMU->writeRegister(ICM20948_REG_TEMP_CONFIG, 1); break;
635  case 7932: itsIMU->writeRegister(ICM20948_REG_TEMP_CONFIG, 0); break;
636  default: LFATAL("Invalid value");
637  }
638 }
639 
640 // ####################################################################################################
641 void jevois::ICM20948::onParamChange(jevois::imu::arange const & JEVOIS_UNUSED_PARAM(param),
642  unsigned int const & newval)
643 {
644  uint8_t reg = itsIMU->readRegister(ICM20948_REG_ACCEL_CONFIG) & ~ICM20948_MASK_ACCEL_FULLSCALE;
645 
646  switch (newval)
647  {
648  case 2: reg |= ICM20948_ACCEL_FULLSCALE_2G; break;
649  case 4: reg |= ICM20948_ACCEL_FULLSCALE_4G; break;
650  case 8: reg |= ICM20948_ACCEL_FULLSCALE_8G; break;
651  case 16: reg |= ICM20948_ACCEL_FULLSCALE_16G; break;
652  default: LFATAL("Invalid value");
653  }
654  itsIMU->writeRegister(ICM20948_REG_ACCEL_CONFIG, reg);
655 }
656 
657 // ####################################################################################################
658 void jevois::ICM20948::onParamChange(jevois::imu::grange const & JEVOIS_UNUSED_PARAM(param),
659  unsigned int const & newval)
660 {
661  uint8_t reg = itsIMU->readRegister(ICM20948_REG_GYRO_CONFIG_1) & ~ICM20948_MASK_GYRO_FULLSCALE;
662 
663  switch (newval)
664  {
665  case 250: reg |= ICM20948_GYRO_FULLSCALE_250DPS; break;
666  case 500: reg |= ICM20948_GYRO_FULLSCALE_500DPS; break;
667  case 1000: reg |= ICM20948_GYRO_FULLSCALE_1000DPS; break;
668  case 2000: reg |= ICM20948_GYRO_FULLSCALE_2000DPS; break;
669  default: LFATAL("Invalid value");
670  }
671  itsIMU->writeRegister(ICM20948_REG_GYRO_CONFIG_1, reg);
672 }
673 
674 // ####################################################################################################
675 void jevois::ICM20948::sleep(bool enable)
676 {
677  uint8_t reg = itsIMU->readRegister(ICM20948_REG_PWR_MGMT_1);
678 
679  if (enable) reg |= ICM20948_BIT_SLEEP;
680  else reg &= ~(ICM20948_BIT_SLEEP);
681 
682  reg |= ICM20948_BIT_CLK_PLL;
683 
684  itsIMU->writeRegister(ICM20948_REG_PWR_MGMT_1, reg);
685 
686  std::this_thread::sleep_for(std::chrono::milliseconds(2));
687 }
688 
689 // ####################################################################################################
690 void jevois::ICM20948::cycle(bool enable)
691 {
692  uint8_t reg = ICM20948_REG_LP_CONFIG;
693  uint8_t const mask = ICM20948_BIT_I2C_MST_CYCLE | ICM20948_BIT_ACCEL_CYCLE | ICM20948_BIT_GYRO_CYCLE;
694 
695  if (enable) reg |= mask; else reg &= ~mask;
696 
697  itsIMU->writeRegister(ICM20948_REG_LP_CONFIG, reg);
698 }
699 
700 // ####################################################################################################
702 { return itsIMU->readRegister(ICM20948_REG_WHO_AM_I); }
703 
704 // ####################################################################################################
705 void jevois::ICM20948::onParamChange(imu::dmp const & JEVOIS_UNUSED_PARAM(param), std::string const & newval)
706 {
707  unsigned short ctl1 = 0, ctl2 = 0, mec = 0;
708  bool a = false, g = false, m = false, h2 = false;
709 
710  LINFO("Setting dmp parameter to " << newval);
711 
712  for (unsigned char c : newval)
713  switch(c)
714  {
715  case 'A': ctl1 |= JEVOIS_DMP_ACCEL; a = true; break;
716  case 'G': ctl1 |= JEVOIS_DMP_GYRO; g = true; break;
717  case 'M': ctl1 |= JEVOIS_DMP_CPASS; m = true; break;
718  case 'R': ctl1 |= JEVOIS_DMP_QUAT6; a = true; g = true; break;
719  case 'Q': ctl1 |= JEVOIS_DMP_QUAT9; a = true; g = true; m = true; mec |= JEVOIS_DMP_NINE_AXIS_EN; break;
720  case 'E': ctl1 |= JEVOIS_DMP_GEOMAG; a = true; g = true; m = true; mec |= JEVOIS_DMP_GEOMAG_EN; break;
721  case 'g': ctl1 |= JEVOIS_DMP_GYRO_CALIBR; g = true; break;
722  case 'm': ctl1 |= JEVOIS_DMP_CPASS_CALIBR; m = true; break;
723  case 'S': ctl1 |= JEVOIS_DMP_PED_STEPDET; a = true; mec |= JEVOIS_DMP_PEDOMETER_EN; break;
724  case 'b': ctl2 |= JEVOIS_DMP_ACCEL_ACCURACY; h2 = true; a = true; break;
725  case 'h': ctl2 |= JEVOIS_DMP_GYRO_ACCURACY; h2 = true; g = true; break;
726  case 'n': ctl2 |= JEVOIS_DMP_CPASS_ACCURACY; h2 = true; m = true; break;
727  case 'P': ctl2 |= JEVOIS_DMP_FLIP_PICKUP; h2 = true; a = true; g = true; mec |= JEVOIS_DMP_FLIP_PICKUP_EN; break;
728  case 'T': ctl2 |= JEVOIS_DMP_ACT_RECOG; h2 = true; a = true; g = true;
731  case 'w': mec |= JEVOIS_DMP_BAC_WEARABLE_EN; break;
732  case 'F': h2 = true; ctl2 |= JEVOIS_DMP_FSYNC; break;
733 
734  default: LERROR("Phony character '" << c << "' ignored while parsing parameter dmp.");
735  }
736 
737  // Apply a few dependencies:
738  if (a) { h2 = true; ctl2 |= JEVOIS_DMP_ACCEL_ACCURACY; mec |= JEVOIS_DMP_ACCEL_CAL_EN; }
739  if (g) { h2 = true; ctl2 |= JEVOIS_DMP_GYRO_ACCURACY; mec |= JEVOIS_DMP_GYRO_CAL_EN; }
740  if (m) { h2 = true; ctl2 |= JEVOIS_DMP_CPASS_ACCURACY; mec |= JEVOIS_DMP_COMPASS_CAL_EN; }
741  if (h2) ctl1 |= JEVOIS_DMP_HEADER2;
742 
743  // Set the two control parameters in the IMU:
744  itsIMU->writeDMPregister(DMP_DATA_OUT_CTL1, ctl1);
745  itsIMU->writeDMPregister(DMP_DATA_OUT_CTL2, ctl2);
746  itsIMU->writeDMPregister(DMP_FIFO_WATERMARK, 800);
747 
748  // Setup the DMP:
749  itsIMU->writeDMPregister(DMP_DATA_INTR_CTL, ctl1);
750  itsIMU->writeDMPregister(DMP_MOTION_EVENT_CTL, mec);
751  itsIMU->writeDMPregister(DMP_DATA_RDY_STATUS, (a ? 0x02 : 0x00) | (g ? 0x01 : 0x00) | (m ? 0x08 : 0x00));
752 }
753 
754 // ####################################################################################################
755 void jevois::ICM20948::computeFIFOpktSize(float ar, float gr, int mm)
756 {
757  itsFIFOpktSiz = 0;
758 
759  // If we are in FIFO mode, make sure we send that data to the FIFO:
760  if (mode::get() == jevois::imu::Mode::FIFO)
761  {
762  // Since this is called from within parameter callbacks, we need a bit of trickery to get the new rate:
763  float acc; if (ar < 0.0F) acc = arate::get(); else acc = ar;
764  float gyr; if (gr < 0.0F) gyr = grate::get(); else gyr = gr;
765  jevois::imu::MagRate mag; if (mm == -1) mag = mrate::get(); else mag = jevois::imu::MagRate::M100Hz; // any value ok
766 
767  // Packet size may change. We need to nuke the FIFO to avoid mixed packets:
768  unsigned char ctl = itsIMU->readRegister(ICM20948_REG_USER_CTRL);
769  ctl &= ~ICM20948_BIT_FIFO_EN;
770  if (itsIMU->isSPI()) ctl |= ICM20948_BIT_I2C_IF_DIS;
771  itsIMU->writeRegister(ICM20948_REG_USER_CTRL, ctl);
772 
773  itsIMU->writeRegister(ICM20948_REG_FIFO_CFG, ICM20948_BIT_SINGLE_FIFO_CFG); // FIFO Config
774  itsIMU->writeRegister(ICM20948_REG_FIFO_RST, 0x1f); // Reset all FIFOs.
775  itsIMU->writeRegister(ICM20948_REG_FIFO_EN_1, 0x0); // Slave FIFO turned off.
776  itsIMU->writeRegister(ICM20948_REG_FIFO_EN_2, 0x0); // Hardware FIFO turned off.
777 
778  std::this_thread::sleep_for(std::chrono::milliseconds(100)); // FIXME: should wait more at low rates...
779 
780  int siz = dataReady(); unsigned char trash[16];
781  while (siz)
782  {
783  itsIMU->readRegisterArray(ICM20948_REG_FIFO_R_W, &trash[0], std::min(siz, 16));
784  siz = dataReady();
785  }
786 
787  itsIMU->writeRegister(ICM20948_REG_FIFO_RST, 0x00); // Stop FIFO reset
788 
789  unsigned char v = itsIMU->readRegister(ICM20948_REG_FIFO_EN_2);
790  if (acc > 0.0F) { v |= ICM20948_BIT_ACCEL_FIFO_EN; itsFIFOpktSiz += 6; } // 3 axes, short int values
791  else v &= ~ICM20948_BIT_ACCEL_FIFO_EN;
792  if (gyr > 0.0F) { v |= ICM20948_BITS_GYRO_FIFO_EN; itsFIFOpktSiz += 6; } // 3 axes, short int values
793  else v &= ~ICM20948_BITS_GYRO_FIFO_EN;
794  itsIMU->writeRegister(ICM20948_REG_FIFO_EN_2, v);
795 
796  v = itsIMU->readRegister(ICM20948_REG_FIFO_EN_1);
797  if (mag != jevois::imu::MagRate::Off && mag != jevois::imu::MagRate::Once)
798  { v |= ICM20948_BIT_SLV_0_FIFO_EN; itsFIFOpktSiz += 8; } // 3 axes, short int values + short status
799  else v &= ~ICM20948_BIT_SLV_0_FIFO_EN;
800  itsIMU->writeRegister(ICM20948_REG_FIFO_EN_1, v);
801 
802  // Enable FIFO:
803  ctl |= ICM20948_BIT_FIFO_EN;
804  if (itsIMU->isSPI()) ctl |= ICM20948_BIT_I2C_IF_DIS;
805  itsIMU->writeRegister(ICM20948_REG_USER_CTRL, ctl);
806  }
807 }
808 
jevois::imu::get
Data collection mode RAW means that the latest available raw data is returned each time get() is called
jevois::ICM20948::devid
uint32_t devid()
Read device ID.
Definition: ICM20948.C:701
jevois::ICM20948::getDMP
DMPdata getDMP(bool blocking=true)
Get one packet of DMP data.
Definition: ICM20948.C:381
JEVOIS_DMP_FLIP_PICKUP_EN
#define JEVOIS_DMP_FLIP_PICKUP_EN
Definition: ICM20948.C:53
jevois::ICM20948::reset
void reset()
Reset the IMU chip - not recommended in normal operation.
Definition: ICM20948.C:462
JEVOIS_DMP_QUAT6
#define JEVOIS_DMP_QUAT6
Definition: IMUdata.H:104
JEVOIS_DMP_HEADER2
#define JEVOIS_DMP_HEADER2
Definition: IMUdata.H:112
jevois::ICM20948::sleep
void sleep(bool enable)
Turn on/off sleep mode.
Definition: ICM20948.C:675
jevois::IMUrawData::mst2
short & mst2()
Definition: IMUdata.H:60
JEVOIS_DMP_QUAT9
#define JEVOIS_DMP_QUAT9
Definition: IMUdata.H:105
JEVOIS_DMP_COMPASS_CAL_EN
#define JEVOIS_DMP_COMPASS_CAL_EN
Definition: ICM20948.C:57
jevois::IMUrawData::ay
short & ay()
Definition: IMUdata.H:42
jevois::Component
A component of a model hierarchy.
Definition: Component.H:181
jevois::ICM20948::ICM20948
ICM20948(std::string const &instance)
Constructor, low-level communication driver is null.
Definition: ICM20948.C:62
jevois::IMUrawData::az
short & az()
Definition: IMUdata.H:44
DMP_MOTION_EVENT_CTL
#define DMP_MOTION_EVENT_CTL
Definition: ICM20948_regs.H:408
JEVOIS_DMP_PED_STEPDET
#define JEVOIS_DMP_PED_STEPDET
Definition: IMUdata.H:111
jevois::IMUrawData::gz
short & gz()
Definition: IMUdata.H:50
JEVOIS_DMP_ACCEL_CAL_EN
#define JEVOIS_DMP_ACCEL_CAL_EN
Definition: ICM20948.C:55
JEVOIS_DMP_PEDOMETER_EN
#define JEVOIS_DMP_PEDOMETER_EN
Definition: ICM20948.C:49
jevois::imu::MagRate
MagRate
Definition: ICM20948.H:111
JEVOIS_DMP_BAC_WEARABLE_EN
#define JEVOIS_DMP_BAC_WEARABLE_EN
Definition: ICM20948.C:48
JEVOIS_DMP_BRING_AND_LOOK_T0_SEE_EN
#define JEVOIS_DMP_BRING_AND_LOOK_T0_SEE_EN
Definition: ICM20948.C:59
LERROR
#define LERROR(msg)
Convenience macro for users to print out console or syslog messages, ERROR level.
Definition: Log.H:211
DMP_DATA_OUT_CTL2
#define DMP_DATA_OUT_CTL2
Definition: ICM20948_regs.H:403
jevois::IMUrawData::gy
short & gy()
Definition: IMUdata.H:48
JEVOIS_DMP_ACCEL_ACCURACY
#define JEVOIS_DMP_ACCEL_ACCURACY
Definition: IMUdata.H:115
JEVOIS_DMP_GYRO_ACCURACY
#define JEVOIS_DMP_GYRO_ACCURACY
Definition: IMUdata.H:116
jevois::DMPpacketSize
size_t DMPpacketSize(unsigned short ctl1, unsigned short ctl2)
Helper function to determine DMP packet size depending on options.
Definition: IMUdata.C:52
JEVOIS_DMP_GEOMAG
#define JEVOIS_DMP_GEOMAG
Definition: IMUdata.H:107
jevois::ICM20948::preUninit
void preUninit() override
Unfreeze any previously frozen parameters.
Definition: ICM20948.C:246
jevois
Definition: Concepts.dox:1
JEVOIS_DMP_SMD_EN
#define JEVOIS_DMP_SMD_EN
Definition: ICM20948.C:51
F
float F
Definition: GUIhelper.C:1968
Engine.H
JEVOIS_DMP_FSYNC
#define JEVOIS_DMP_FSYNC
Definition: IMUdata.H:118
ICM20948_regs.H
JEVOIS_DMP_GYRO_CALIBR
#define JEVOIS_DMP_GYRO_CALIBR
Definition: IMUdata.H:109
JEVOIS_DMP_CPASS_CALIBR
#define JEVOIS_DMP_CPASS_CALIBR
Definition: IMUdata.H:110
jevois::IMUrawData::mx
short & mx()
Definition: IMUdata.H:54
JEVOIS_DMP_BTS_EN
#define JEVOIS_DMP_BTS_EN
Definition: ICM20948.C:52
jevois::IMUrawData
Raw IMU data.
Definition: IMUdata.H:36
JEVOIS_DMP_CPASS
#define JEVOIS_DMP_CPASS
Definition: IMUdata.H:102
jevois::IMUrawData::mz
short & mz()
Definition: IMUdata.H:58
JEVOIS_DMP_GEOMAG_EN
#define JEVOIS_DMP_GEOMAG_EN
Definition: ICM20948.C:54
DMP_DATA_RDY_STATUS
#define DMP_DATA_RDY_STATUS
Definition: ICM20948_regs.H:414
jevois::ICM20948::ready
bool ready()
Returns true if this camera indeed has a working ICM20948.
Definition: ICM20948.C:252
jevois::ICM20948::postInit
void postInit() override
Configure RAW vs DMP mode:
Definition: ICM20948.C:164
LFATAL
#define LFATAL(msg)
Convenience macro for users to print out console or syslog messages, FATAL level.
jevois::DMPdata
DMP data (Digital Motion Processor)
Definition: IMUdata.H:129
jevois::ICM20948::dataReady
int dataReady()
Returns the amount of new data that had not previously been obtained.
Definition: ICM20948.C:258
jevois::ICM20948::preInit
void preInit() override
Connect to and initialize the IMU chip.
Definition: ICM20948.C:114
jevois::ICM20948::get
IMUdata get(bool blocking=true)
Get one round of scaled raw data.
Definition: ICM20948.C:375
JEVOIS_DMP_ACT_RECOG
#define JEVOIS_DMP_ACT_RECOG
Definition: IMUdata.H:121
JEVOIS_DMP_CPASS_ACCURACY
#define JEVOIS_DMP_CPASS_ACCURACY
Definition: IMUdata.H:117
jevois::DMPdata::parsePacket
void parsePacket(unsigned char const *packet, size_t siz)
Populate our fields from a packet received from the DMP.
Definition: IMUdata.C:84
JEVOIS_DMP_GYRO_CAL_EN
#define JEVOIS_DMP_GYRO_CAL_EN
Definition: ICM20948.C:56
DMP_DATA_OUT_CTL1
#define DMP_DATA_OUT_CTL1
Definition: ICM20948_regs.H:402
JEVOIS_DMP_NINE_AXIS_EN
#define JEVOIS_DMP_NINE_AXIS_EN
Definition: ICM20948.C:58
jevois::ICM20948::~ICM20948
virtual ~ICM20948()
Virtual destructor for safe inheritance.
Definition: ICM20948.C:67
DMP_DATA_INTR_CTL
#define DMP_DATA_INTR_CTL
Definition: ICM20948_regs.H:404
JEVOIS_DMP_GYRO
#define JEVOIS_DMP_GYRO
Definition: IMUdata.H:101
jevois::IMUrawData::v
short v[11]
The values: ax, ay, az, gy, gy, gz, temp, mx, my, mz, mst2.
Definition: IMUdata.H:38
jevois::IMUrawData::my
short & my()
Definition: IMUdata.H:56
jevois::ICM20948::cycle
void cycle(bool enable)
Turn on/off cycle mode vs continuous for accel, gyro and compass.
Definition: ICM20948.C:690
jevois::ICM20948::getRaw
IMUrawData getRaw(bool blocking=true)
Get one round of raw data.
Definition: ICM20948.C:280
jevois::IMUrawData::ax
short & ax()
Definition: IMUdata.H:40
JEVOIS_DMP_FLIP_PICKUP
#define JEVOIS_DMP_FLIP_PICKUP
Definition: IMUdata.H:119
LINFO
#define LINFO(msg)
Convenience macro for users to print out console or syslog messages, INFO level.
Definition: Log.H:194
jevois::IMUrawData::temp
short & temp()
Definition: IMUdata.H:52
DMP_FIFO_WATERMARK
#define DMP_FIFO_WATERMARK
Definition: ICM20948_regs.H:405
ICM20948.H
jevois::IMUrawData::gx
short & gx()
Definition: IMUdata.H:46
JEVOIS_DMP_ACCEL
#define JEVOIS_DMP_ACCEL
Definition: IMUdata.H:100
jevois::IMUdata
IMU data.
Definition: IMUdata.H:67