1
1
/* ***************************************************************
2
- * Example5_DMP .ino
2
+ * Example5_DMP_Quat9_Orientation .ino
3
3
* ICM 20948 Arduino Library Demo
4
4
* Initialize the DMP based on the TDK InvenSense ICM20948_eMD_nucleo_1.0 example-icm20948
5
5
* Paul Clark, February 9th 2021
6
6
* Based on original code by:
7
7
* Owen Lyke @ SparkFun Electronics
8
8
* Original Creation Date: April 17 2019
9
9
*
10
- * ** This example is based on the InvenSense Application Note "Programming Sequence for DMP Hardware Functions".
11
- * ** We are grateful to InvenSense for providing this.
10
+ * ** This example is based on InvenSense's _confidential_ Application Note "Programming Sequence for DMP Hardware Functions".
11
+ * ** We are grateful to InvenSense for sharing this with us .
12
12
*
13
13
* ** Important note: by default the DMP functionality is disabled in the library
14
14
* ** as the DMP firmware takes up 14290 Bytes of program memory.
@@ -92,19 +92,20 @@ void setup() {
92
92
SERIAL_PORT.println (" Device connected!" );
93
93
94
94
// The ICM-20948 is awake and ready but hasn't been configured. Let's step through the configuration
95
+ // sequence from InvenSense's _confidential_ Application Note "Programming Sequence for DMP Hardware Functions".
95
96
96
97
bool success = true ; // Use success to show if the configuration was successful
97
98
98
99
// Configure clock source through PWR_MGMT_1
99
- // Auto selects the best available clock source – PLL if ready, else use the Internal oscillator
100
+ // ICM_20948_Clock_Auto selects the best available clock source – PLL if ready, else use the Internal oscillator
100
101
success &= (myICM.setClockSource (ICM_20948_Clock_Auto) == ICM_20948_Stat_Ok); // This is shorthand: success will be set to false if setClockSource fails
101
102
102
103
// Enable accel and gyro sensors through PWR_MGMT_2
103
104
// Enable Accelerometer (all axes) and Gyroscope (all axes) by writing zero to PWR_MGMT_2
104
105
uint8_t zero = 0 ;
105
106
success &= (myICM.write (AGB0_REG_PWR_MGMT_2, &zero, 1 ) == ICM_20948_Stat_Ok); // Write one byte to the PWR_MGMT_2 register
106
107
107
- // Configure Gyro/Accel in Low power mode with LP_CONFIG
108
+ // Configure Gyro/Accel in Low Power Mode (cycled) with LP_CONFIG
108
109
success &= (myICM.setSampleMode ( (ICM_20948_Internal_Acc | ICM_20948_Internal_Gyr), ICM_20948_Sample_Mode_Cycled ) == ICM_20948_Stat_Ok);
109
110
110
111
// Set Gyro FSR (Full scale range) to 2000dps through GYRO_CONFIG_1
@@ -123,9 +124,10 @@ void setup() {
123
124
success &= (myICM.setFullScale ( (ICM_20948_Internal_Acc | ICM_20948_Internal_Gyr), myFSS ) == ICM_20948_Stat_Ok);
124
125
125
126
// Enable interrupt for FIFO overflow from FIFOs through INT_ENABLE_2
127
+ // If we see this interrupt, we'll need to reset the FIFO
126
128
// success &= (myICM.intEnableOverflowFIFO( 0x1F ) == ICM_20948_Stat_Ok); // Enable the interrupt on all FIFOs
127
129
128
- // Turn off what goes into the FIFO through FIFO_EN , FIFO_EN_2
130
+ // Turn off what goes into the FIFO through FIFO_EN_1 , FIFO_EN_2
129
131
// Stop the peripheral data from being written to the FIFO by writing zero to FIFO_EN_1
130
132
success &= (myICM.write (AGB0_REG_FIFO_EN_1, &zero, 1 ) == ICM_20948_Stat_Ok);
131
133
// Stop the accelerometer, gyro and temperature data from being written to the FIFO by writing zero to FIFO_EN_2
@@ -184,26 +186,48 @@ void setup() {
184
186
success &= (myICM.writeDMPmems (CPASS_MTX_21, 4 , &mountMultiplierZero[0 ]) == ICM_20948_Stat_Ok);
185
187
success &= (myICM.writeDMPmems (CPASS_MTX_22, 4 , &mountMultiplierMinus[0 ]) == ICM_20948_Stat_Ok);
186
188
189
+ // Enable DMP interrupt
190
+ // This would be the most efficient way of getting the DMP data, instead of polling the FIFO
191
+ // success &= (myICM.intEnableDMP(true) == ICM_20948_Stat_Ok);
192
+
193
+ // DMP sensor options are defined in ICM_20948_DMP.h
194
+ // INV_ICM20948_SENSOR_ACCELEROMETER
195
+ // INV_ICM20948_SENSOR_GYROSCOPE
196
+ // INV_ICM20948_SENSOR_RAW_ACCELEROMETER
197
+ // INV_ICM20948_SENSOR_RAW_GYROSCOPE
198
+ // INV_ICM20948_SENSOR_MAGNETIC_FIELD_UNCALIBRATED
199
+ // INV_ICM20948_SENSOR_GYROSCOPE_UNCALIBRATED
200
+ // INV_ICM20948_SENSOR_ACTIVITY_CLASSIFICATON
201
+ // INV_ICM20948_SENSOR_STEP_DETECTOR
202
+ // INV_ICM20948_SENSOR_STEP_COUNTER
203
+ // INV_ICM20948_SENSOR_GAME_ROTATION_VECTOR
204
+ // INV_ICM20948_SENSOR_ROTATION_VECTOR
205
+ // INV_ICM20948_SENSOR_GEOMAGNETIC_ROTATION_VECTOR
206
+ // INV_ICM20948_SENSOR_GEOMAGNETIC_FIELD
207
+ // INV_ICM20948_SENSOR_WAKEUP_SIGNIFICANT_MOTION
208
+ // INV_ICM20948_SENSOR_FLIP_PICKUP
209
+ // INV_ICM20948_SENSOR_WAKEUP_TILT_DETECTOR
210
+ // INV_ICM20948_SENSOR_GRAVITY
211
+ // INV_ICM20948_SENSOR_LINEAR_ACCELERATION
212
+ // INV_ICM20948_SENSOR_ORIENTATION
213
+
214
+ // Enable the DMP orientation sensor
215
+ success &= (myICM.enableDMPSensor (INV_ICM20948_SENSOR_ORIENTATION) == ICM_20948_Stat_Ok);
216
+
217
+ // Set the DMP orientation sensor rate to 25Hz
218
+ success &= (myICM.setDMPODRrate (INV_ICM20948_SENSOR_ORIENTATION, 25 ) == ICM_20948_Stat_Ok);
219
+
187
220
// Enable the FIFO
188
221
success &= (myICM.enableFIFO () == ICM_20948_Stat_Ok);
189
222
190
- // Reset FIFO
191
- success &= (myICM.resetFIFO () == ICM_20948_Stat_Ok);
192
-
193
223
// Enable the DMP
194
224
success &= (myICM.enableDMP () == ICM_20948_Stat_Ok);
195
225
196
226
// Reset DMP
197
227
success &= (myICM.resetDMP () == ICM_20948_Stat_Ok);
198
228
199
- // Enable DMP interrupt
200
- // success &= (myICM.intEnableDMP(true) == ICM_20948_Stat_Ok);
201
-
202
- // Enable the DMP orientation sensor
203
- success &= (myICM.enableDMPSensor (INV_ICM20948_SENSOR_ORIENTATION) == ICM_20948_Stat_Ok);
204
-
205
- // Set the DMP orientation sensor rate to 25Hz
206
- success &= (myICM.setDMPODRrate (INV_ICM20948_SENSOR_ORIENTATION, 25 ) == ICM_20948_Stat_Ok);
229
+ // Reset FIFO
230
+ success &= (myICM.resetFIFO () == ICM_20948_Stat_Ok);
207
231
208
232
// Check success
209
233
if ( success )
@@ -218,145 +242,56 @@ void setup() {
218
242
219
243
void loop ()
220
244
{
245
+ // Read any data waiting in the FIFO
246
+ // Note:
247
+ // readDMPdataFromFIFO will return ICM_20948_Stat_FIFONoDataAvail if no data or incomplete data is available.
248
+ // If data is available, readDMPdataFromFIFO will attempt to read _one_ frame of DMP data.
249
+ // readDMPdataFromFIFO will return ICM_20948_Stat_Ok if a valid frame was read.
250
+ // readDMPdataFromFIFO will return ICM_20948_Stat_FIFOMoreDataAvail if a valid frame was read _and_ the FIFO contains more (unread) data.
221
251
icm_20948_DMP_data_t data;
222
252
myICM.readDMPdataFromFIFO (&data);
223
- if ( myICM.status == ICM_20948_Stat_Ok )
253
+
254
+ if (( myICM.status == ICM_20948_Stat_Ok ) || ( myICM.status == ICM_20948_Stat_FIFOMoreDataAvail )) // Was valid data available?
224
255
{
225
- SERIAL_PORT.print (F (" Received data! Header: 0x" ));
256
+ SERIAL_PORT.print (F (" Received data! Header: 0x" )); // Print the header in HEX
226
257
if ( data.header < 0x1000 ) SERIAL_PORT.print ( " 0" ); // Pad the zeros
227
258
if ( data.header < 0x100 ) SERIAL_PORT.print ( " 0" );
228
259
if ( data.header < 0x10 ) SERIAL_PORT.print ( " 0" );
229
260
SERIAL_PORT.println ( data.header , HEX );
230
- if ( (data.header | DMP_header_bitmap_Quat9) > 0 ) // We have asked for orientation data so we should receive Quat9
261
+
262
+ if ( (data.header & DMP_header_bitmap_Quat9) > 0 ) // We have asked for orientation data so we should receive Quat9
231
263
{
232
- SERIAL_PORT.print (F (" Quat9 data is: 0x" ));
233
- for (int i = 0 ; i < 14 ; i++) // Quat9 data is 14 bytes long
234
- {
235
- if ( data.Quat9 [i] < 0x10 ) SERIAL_PORT.print ( " 0" ); // Pad the zero
236
- SERIAL_PORT.print ( data.Quat9 [i], HEX );
237
- }
238
- SERIAL_PORT.println ();
264
+ // Q0 value is computed from this equation: Q20 + Q21 + Q22 + Q23 = 1.
265
+ // In case of drift, the sum will not add to 1, therefore, quaternion data need to be corrected with right bias values.
266
+ // The quaternion data is scaled by 2^30.
267
+ SERIAL_PORT.printf (" Quat9 data is: Q1:%ld Q2:%ld Q3:%ld Accuracy:%d\r\n " , data.Quat9 .Data .Q1 , data.Quat9 .Data .Q2 , data.Quat9 .Data .Q3 , data.Quat9 .Data .Accuracy );
239
268
}
240
269
}
241
- else if ( myICM.status != ICM_20948_Stat_FIFONoDataAvail )
270
+ else if ( myICM.status != ICM_20948_Stat_FIFONoDataAvail ) // Check for an error - but ignore "no data available"
242
271
{
243
- SERIAL_PORT.print (F (" readDMPdataFromFIFO failed! Status is: " ));
272
+ SERIAL_PORT.print (F (" readDMPdataFromFIFO failed! Status is: " )); // We got an error - so print it
244
273
SERIAL_PORT.print ( myICM.status );
245
274
SERIAL_PORT.print (" : " );
246
275
SERIAL_PORT.println ( myICM.statusString () );
247
- SERIAL_PORT.print (F (" Header is: 0x" ));
276
+
277
+ SERIAL_PORT.print (F (" Header is: 0x" )); // Print the header so we can check it manually
248
278
if ( data.header < 0x1000 ) SERIAL_PORT.print ( " 0" ); // Pad the zeros
249
279
if ( data.header < 0x100 ) SERIAL_PORT.print ( " 0" );
250
280
if ( data.header < 0x10 ) SERIAL_PORT.print ( " 0" );
251
281
SERIAL_PORT.println ( data.header , HEX );
252
- if ( data.header == DMP_header_bitmap_Header2 )
282
+
283
+ if ( data.header2 > 0 )
253
284
{
254
- SERIAL_PORT.print (F (" Header2 is: 0x" ));
285
+ SERIAL_PORT.print (F (" Header2 is: 0x" )); // Print header2 so we can check it manually
255
286
if ( data.header2 < 0x1000 ) SERIAL_PORT.print ( " 0" ); // Pad the zeros
256
287
if ( data.header2 < 0x100 ) SERIAL_PORT.print ( " 0" );
257
288
if ( data.header2 < 0x10 ) SERIAL_PORT.print ( " 0" );
258
289
SERIAL_PORT.println ( data.header2 , HEX );
259
290
}
260
291
}
261
292
262
- delay (10 );
263
- }
264
-
265
-
266
- // Below here are some helper functions to print the data nicely!
267
-
268
- void printPaddedInt16b ( int16_t val ){
269
- if (val > 0 ){
270
- SERIAL_PORT.print (" " );
271
- if (val < 10000 ){ SERIAL_PORT.print (" 0" ); }
272
- if (val < 1000 ){ SERIAL_PORT.print (" 0" ); }
273
- if (val < 100 ){ SERIAL_PORT.print (" 0" ); }
274
- if (val < 10 ){ SERIAL_PORT.print (" 0" ); }
275
- }else {
276
- SERIAL_PORT.print (" -" );
277
- if (abs (val) < 10000 ){ SERIAL_PORT.print (" 0" ); }
278
- if (abs (val) < 1000 ){ SERIAL_PORT.print (" 0" ); }
279
- if (abs (val) < 100 ){ SERIAL_PORT.print (" 0" ); }
280
- if (abs (val) < 10 ){ SERIAL_PORT.print (" 0" ); }
281
- }
282
- SERIAL_PORT.print (abs (val));
283
- }
284
-
285
- void printRawAGMT ( ICM_20948_AGMT_t agmt){
286
- SERIAL_PORT.print (" RAW. Acc [ " );
287
- printPaddedInt16b ( agmt.acc .axes .x );
288
- SERIAL_PORT.print (" , " );
289
- printPaddedInt16b ( agmt.acc .axes .y );
290
- SERIAL_PORT.print (" , " );
291
- printPaddedInt16b ( agmt.acc .axes .z );
292
- SERIAL_PORT.print (" ], Gyr [ " );
293
- printPaddedInt16b ( agmt.gyr .axes .x );
294
- SERIAL_PORT.print (" , " );
295
- printPaddedInt16b ( agmt.gyr .axes .y );
296
- SERIAL_PORT.print (" , " );
297
- printPaddedInt16b ( agmt.gyr .axes .z );
298
- SERIAL_PORT.print (" ], Mag [ " );
299
- printPaddedInt16b ( agmt.mag .axes .x );
300
- SERIAL_PORT.print (" , " );
301
- printPaddedInt16b ( agmt.mag .axes .y );
302
- SERIAL_PORT.print (" , " );
303
- printPaddedInt16b ( agmt.mag .axes .z );
304
- SERIAL_PORT.print (" ], Tmp [ " );
305
- printPaddedInt16b ( agmt.tmp .val );
306
- SERIAL_PORT.print (" ]" );
307
- SERIAL_PORT.println ();
308
- }
309
-
310
-
311
- void printFormattedFloat (float val, uint8_t leading, uint8_t decimals){
312
- float aval = abs (val);
313
- if (val < 0 ){
314
- SERIAL_PORT.print (" -" );
315
- }else {
316
- SERIAL_PORT.print (" " );
317
- }
318
- for ( uint8_t indi = 0 ; indi < leading; indi++ ){
319
- uint32_t tenpow = 0 ;
320
- if ( indi < (leading-1 ) ){
321
- tenpow = 1 ;
322
- }
323
- for (uint8_t c = 0 ; c < (leading-1 -indi); c++){
324
- tenpow *= 10 ;
325
- }
326
- if ( aval < tenpow){
327
- SERIAL_PORT.print (" 0" );
328
- }else {
329
- break ;
330
- }
331
- }
332
- if (val < 0 ){
333
- SERIAL_PORT.print (-val, decimals);
334
- }else {
335
- SERIAL_PORT.print (val, decimals);
293
+ if ( myICM.status != ICM_20948_Stat_FIFOMoreDataAvail ) // If more data is available then we should read it right away - and not delay
294
+ {
295
+ delay (10 );
336
296
}
337
297
}
338
-
339
- void printScaledAGMT ( ICM_20948_AGMT_t agmt){
340
- SERIAL_PORT.print (" Scaled. Acc (mg) [ " );
341
- printFormattedFloat ( myICM.accX (), 5 , 2 );
342
- SERIAL_PORT.print (" , " );
343
- printFormattedFloat ( myICM.accY (), 5 , 2 );
344
- SERIAL_PORT.print (" , " );
345
- printFormattedFloat ( myICM.accZ (), 5 , 2 );
346
- SERIAL_PORT.print (" ], Gyr (DPS) [ " );
347
- printFormattedFloat ( myICM.gyrX (), 5 , 2 );
348
- SERIAL_PORT.print (" , " );
349
- printFormattedFloat ( myICM.gyrY (), 5 , 2 );
350
- SERIAL_PORT.print (" , " );
351
- printFormattedFloat ( myICM.gyrZ (), 5 , 2 );
352
- SERIAL_PORT.print (" ], Mag (uT) [ " );
353
- printFormattedFloat ( myICM.magX (), 5 , 2 );
354
- SERIAL_PORT.print (" , " );
355
- printFormattedFloat ( myICM.magY (), 5 , 2 );
356
- SERIAL_PORT.print (" , " );
357
- printFormattedFloat ( myICM.magZ (), 5 , 2 );
358
- SERIAL_PORT.print (" ], Tmp (C) [ " );
359
- printFormattedFloat ( myICM.temp (), 5 , 2 );
360
- SERIAL_PORT.print (" ]" );
361
- SERIAL_PORT.println ();
362
- }
0 commit comments