1 /* 2 $License: 3 Copyright 2011 InvenSense, Inc. 4 5 Licensed under the Apache License, Version 2.0 (the "License"); 6 you may not use this file except in compliance with the License. 7 You may obtain a copy of the License at 8 9 http://www.apache.org/licenses/LICENSE-2.0 10 11 Unless required by applicable law or agreed to in writing, software 12 distributed under the License is distributed on an "AS IS" BASIS, 13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 See the License for the specific language governing permissions and 15 limitations under the License. 16 $ 17 */ 18 /******************************************************************************* 19 * 20 * $Id: mlFIFO.c 5653 2011-06-16 21:06:55Z nroyer $ 21 * 22 *******************************************************************************/ 23 24 /** 25 * @defgroup MLFIFO 26 * @brief Motion Library - FIFO Driver. 27 * The FIFO API Interface. 28 * 29 * @{ 30 * @file mlFIFO.c 31 * @brief FIFO Interface. 32 **/ 33 34 #include <string.h> 35 #include "mpu.h" 36 #if defined CONFIG_MPU_SENSORS_MPU6050A2 37 # include "mpu6050a2.h" 38 #elif defined CONFIG_MPU_SENSORS_MPU6050B1 39 # include "mpu6050b1.h" 40 #elif defined CONFIG_MPU_SENSORS_MPU3050 41 # include "mpu3050.h" 42 #else 43 #error Invalid or undefined CONFIG_MPU_SENSORS_MPUxxxx 44 #endif 45 #include "mlFIFO.h" 46 #include "mlFIFOHW.h" 47 #include "dmpKey.h" 48 #include "mlMathFunc.h" 49 #include "ml.h" 50 #include "mldl.h" 51 #include "mldl_cfg.h" 52 #include "mlstates.h" 53 #include "mlsupervisor.h" 54 #include "mlos.h" 55 #include "mlmath.h" 56 #include "accel.h" 57 58 #include "log.h" 59 #undef MPL_LOG_TAG 60 #define MPL_LOG_TAG "MPL-fifo" 61 62 #define FIFO_DEBUG 0 63 64 #define REF_QUATERNION (0) 65 #define REF_GYROS (REF_QUATERNION + 4) 66 #define REF_CONTROL (REF_GYROS + 3) 67 #define REF_RAW (REF_CONTROL + 4) 68 #define REF_RAW_EXTERNAL (REF_RAW + 8) 69 #define REF_ACCEL (REF_RAW_EXTERNAL + 6) 70 #define REF_QUANT_ACCEL (REF_ACCEL + 3) 71 #define REF_QUATERNION_6AXIS (REF_QUANT_ACCEL + INV_MAX_NUM_ACCEL_SAMPLES) 72 #define REF_EIS (REF_QUATERNION_6AXIS + 4) 73 #define REF_DMP_PACKET (REF_EIS + 3) 74 #define REF_GARBAGE (REF_DMP_PACKET + 1) 75 #define REF_LAST (REF_GARBAGE + 1) 76 77 long fifo_scale[REF_LAST] = { 78 (1L << 30), (1L << 30), (1L << 30), (1L << 30), // Quaternion 79 // 2^(16+30)/((2^30)*((3.14159265358/180)/200)/2) 80 1501974482L, 1501974482L, 1501974482L, // Gyro 81 (1L << 30), (1L << 30), (1L << 30), (1L << 30), // Control 82 (1L << 14), // Temperature 83 (1L << 14), (1L << 14), (1L << 14), // Raw Gyro 84 (1L << 14), (1L << 14), (1L << 14), (0), // Raw Accel, plus padding 85 (1L << 14), (1L << 14), (1L << 14), // Raw External 86 (1L << 14), (1L << 14), (1L << 14), // Raw External 87 (1L << 16), (1L << 16), (1L << 16), // Accel 88 (1L << 30), (1L << 30), (1L << 30), (1L << 30), // Quant Accel 89 (1L << 30), (1L << 30), (1L << 30), (1L << 30), //Quant Accel 90 (1L << 30), (1L << 30), (1L << 30), (1L << 30), // Quaternion 6 Axis 91 (1L << 30), (1L << 30), (1L << 30), // EIS 92 (1L << 30), // Packet 93 (1L << 30), // Garbage 94 }; 95 96 // The scale factors for tap need to match the number in fifo_scale above. 97 // fifo_base_offset below may also need to be changed if this is not 8 98 #if INV_MAX_NUM_ACCEL_SAMPLES != 8 99 #error INV_MAX_NUM_ACCEL_SAMPLES must be defined to 8 100 #endif 101 102 #define CONFIG_QUAT (0) 103 #define CONFIG_GYROS (CONFIG_QUAT + 1) 104 #define CONFIG_CONTROL_DATA (CONFIG_GYROS + 1) 105 #define CONFIG_TEMPERATURE (CONFIG_CONTROL_DATA + 1) 106 #define CONFIG_RAW_DATA (CONFIG_TEMPERATURE + 1) 107 #define CONFIG_RAW_EXTERNAL (CONFIG_RAW_DATA + 1) 108 #define CONFIG_ACCEL (CONFIG_RAW_EXTERNAL + 1) 109 #define CONFIG_DMP_QUANT_ACCEL (CONFIG_ACCEL + 1) 110 #define CONFIG_EIS (CONFIG_DMP_QUANT_ACCEL + 1) 111 #define CONFIG_DMP_PACKET_NUMBER (CONFIG_EIS + 1) 112 #define CONFIG_FOOTER (CONFIG_DMP_PACKET_NUMBER + 1) 113 #define NUMFIFOELEMENTS (CONFIG_FOOTER + 1) 114 115 const int fifo_base_offset[NUMFIFOELEMENTS] = { 116 REF_QUATERNION * 4, 117 REF_GYROS * 4, 118 REF_CONTROL * 4, 119 REF_RAW * 4, 120 REF_RAW * 4 + 4, 121 REF_RAW_EXTERNAL * 4, 122 REF_ACCEL * 4, 123 REF_QUANT_ACCEL * 4, 124 REF_EIS * 4, 125 REF_DMP_PACKET * 4, 126 REF_GARBAGE * 4 127 }; 128 129 struct fifo_obj { 130 void (*fifo_process_cb) (void); 131 long decoded[REF_LAST]; 132 long decoded_accel[INV_MAX_NUM_ACCEL_SAMPLES][ACCEL_NUM_AXES]; 133 int offsets[REF_LAST * 4]; 134 int cache; 135 uint_fast8_t gyro_source; 136 unsigned short fifo_rate; 137 unsigned short sample_step_size_ms; 138 uint_fast16_t fifo_packet_size; 139 uint_fast16_t data_config[NUMFIFOELEMENTS]; 140 unsigned char reference_count[REF_LAST]; 141 long acc_bias_filt[3]; 142 float acc_filter_coef; 143 long gravity_cache[3]; 144 }; 145 146 static struct fifo_obj fifo_obj; 147 148 #define FIFO_CACHE_TEMPERATURE 1 149 #define FIFO_CACHE_GYRO 2 150 #define FIFO_CACHE_GRAVITY_BODY 4 151 #define FIFO_CACHE_ACC_BIAS 8 152 153 struct fifo_rate_obj { 154 // These describe callbacks happening everytime a FIFO block is processed 155 int_fast8_t num_cb; 156 HANDLE mutex; 157 inv_obj_func fifo_process_cb[MAX_HIGH_RATE_PROCESSES]; 158 int priority[MAX_HIGH_RATE_PROCESSES]; 159 }; 160 161 struct fifo_rate_obj fifo_rate_obj; 162 163 /** Sets accuracy to be one of 0, INV_32_BIT, or INV_16_BIT. Looks up old 164 * accuracy if needed. 165 */ 166 static uint_fast16_t inv_set_fifo_accuracy(uint_fast16_t elements, 167 uint_fast16_t accuracy, 168 uint_fast8_t configOffset) 169 { 170 if (elements) { 171 if (!accuracy) 172 accuracy = fifo_obj.data_config[configOffset]; 173 else if (accuracy & INV_16_BIT) 174 if ((fifo_obj.data_config[configOffset] & INV_32_BIT)) 175 accuracy = INV_32_BIT; // 32-bits takes priority 176 else 177 accuracy = INV_16_BIT; 178 else 179 accuracy = INV_32_BIT; 180 } else { 181 accuracy = 0; 182 } 183 184 return accuracy; 185 } 186 187 /** Adjusts (len) Reference Counts, at offset (refOffset). If increment is 0, 188 * the reference counts are subtracted, otherwise they are incremented for each 189 * bit set in element. The value returned are the elements that should be sent 190 * out as data through the FIFO. 191 */ 192 static uint_fast16_t inv_set_fifo_reference(uint_fast16_t elements, 193 uint_fast16_t increment, 194 uint_fast8_t refOffset, 195 uint_fast8_t len) 196 { 197 uint_fast8_t kk; 198 199 if (increment == 0) { 200 for (kk = 0; kk < len; ++kk) { 201 if ((elements & 1) 202 && (fifo_obj.reference_count[kk + refOffset] > 0)) { 203 fifo_obj.reference_count[kk + refOffset]--; 204 } 205 elements >>= 1; 206 } 207 } else { 208 for (kk = 0; kk < len; ++kk) { 209 if (elements & 1) 210 fifo_obj.reference_count[kk + refOffset]++; 211 elements >>= 1; 212 } 213 } 214 elements = 0; 215 for (kk = 0; kk < len; ++kk) { 216 if (fifo_obj.reference_count[kk + refOffset] > 0) 217 elements |= (1 << kk); 218 } 219 return elements; 220 } 221 222 /** 223 * @param[in] accuracy INV_16_BIT or INV_32_BIT when constructing data to send 224 * out the FIFO, 0 when removing from the FIFO. 225 */ 226 static inv_error_t inv_construct3_fifo(unsigned char *regs, 227 uint_fast16_t elements, 228 uint_fast16_t accuracy, 229 uint_fast8_t refOffset, 230 unsigned short key, 231 uint_fast8_t configOffset) 232 { 233 int_fast8_t kk; 234 inv_error_t result; 235 236 elements = inv_set_fifo_reference(elements, accuracy, refOffset, 3); 237 accuracy = inv_set_fifo_accuracy(elements, accuracy, configOffset); 238 239 if (accuracy & INV_16_BIT) { 240 regs[0] = DINAF8 + 2; 241 } 242 243 fifo_obj.data_config[configOffset] = elements | accuracy; 244 245 for (kk = 0; kk < 3; ++kk) { 246 if ((elements & 1) == 0) 247 regs[kk + 1] = DINAA0 + 3; 248 elements >>= 1; 249 } 250 251 result = inv_set_mpu_memory(key, 4, regs); 252 253 return result; 254 } 255 256 /** 257 * @internal 258 * Puts footer on FIFO data. 259 */ 260 static inv_error_t inv_set_footer(void) 261 { 262 unsigned char regs = DINA30; 263 uint_fast8_t tmp_count; 264 int_fast8_t i, j; 265 int offset; 266 int result; 267 int *fifo_offsets_ptr = fifo_obj.offsets; 268 269 fifo_obj.fifo_packet_size = 0; 270 for (i = 0; i < NUMFIFOELEMENTS; i++) { 271 tmp_count = 0; 272 offset = fifo_base_offset[i]; 273 for (j = 0; j < 8; j++) { 274 if ((fifo_obj.data_config[i] >> j) & 0x0001) { 275 #ifndef BIG_ENDIAN 276 // Special Case for Byte Ordering on Accel Data 277 if ((i == CONFIG_RAW_DATA) && (j > 2)) { 278 tmp_count += 2; 279 switch (inv_get_dl_config()->accel->endian) { 280 case EXT_SLAVE_BIG_ENDIAN: 281 *fifo_offsets_ptr++ = offset + 3; 282 *fifo_offsets_ptr++ = offset + 2; 283 break; 284 case EXT_SLAVE_LITTLE_ENDIAN: 285 *fifo_offsets_ptr++ = offset + 2; 286 *fifo_offsets_ptr++ = offset + 3; 287 break; 288 case EXT_SLAVE_FS8_BIG_ENDIAN: 289 if (j == 3) { 290 // Throw this byte away 291 *fifo_offsets_ptr++ = 292 fifo_base_offset[CONFIG_FOOTER]; 293 *fifo_offsets_ptr++ = offset + 3; 294 } else if (j == 4) { 295 *fifo_offsets_ptr++ = offset + 3; 296 *fifo_offsets_ptr++ = offset + 7; 297 } else { 298 // Throw these byte away 299 *fifo_offsets_ptr++ = 300 fifo_base_offset[CONFIG_FOOTER]; 301 *fifo_offsets_ptr++ = 302 fifo_base_offset[CONFIG_FOOTER]; 303 } 304 break; 305 case EXT_SLAVE_FS16_BIG_ENDIAN: 306 if (j == 3) { 307 // Throw this byte away 308 *fifo_offsets_ptr++ = 309 fifo_base_offset[CONFIG_FOOTER]; 310 *fifo_offsets_ptr++ = offset + 3; 311 } else if (j == 4) { 312 *fifo_offsets_ptr++ = offset - 2; 313 *fifo_offsets_ptr++ = offset + 3; 314 } else { 315 *fifo_offsets_ptr++ = offset - 2; 316 *fifo_offsets_ptr++ = offset + 3; 317 } 318 break; 319 default: 320 return INV_ERROR; // Bad value on ordering 321 } 322 } else { 323 tmp_count += 2; 324 *fifo_offsets_ptr++ = offset + 3; 325 *fifo_offsets_ptr++ = offset + 2; 326 if (fifo_obj.data_config[i] & INV_32_BIT) { 327 *fifo_offsets_ptr++ = offset + 1; 328 *fifo_offsets_ptr++ = offset; 329 tmp_count += 2; 330 } 331 } 332 #else 333 // Big Endian Platform 334 // Special Case for Byte Ordering on Accel Data 335 if ((i == CONFIG_RAW_DATA) && (j > 2)) { 336 tmp_count += 2; 337 switch (inv_get_dl_config()->accel->endian) { 338 case EXT_SLAVE_BIG_ENDIAN: 339 *fifo_offsets_ptr++ = offset + 2; 340 *fifo_offsets_ptr++ = offset + 3; 341 break; 342 case EXT_SLAVE_LITTLE_ENDIAN: 343 *fifo_offsets_ptr++ = offset + 3; 344 *fifo_offsets_ptr++ = offset + 2; 345 break; 346 case EXT_SLAVE_FS8_BIG_ENDIAN: 347 if (j == 3) { 348 // Throw this byte away 349 *fifo_offsets_ptr++ = 350 fifo_base_offset[CONFIG_FOOTER]; 351 *fifo_offsets_ptr++ = offset; 352 } else if (j == 4) { 353 *fifo_offsets_ptr++ = offset; 354 *fifo_offsets_ptr++ = offset + 4; 355 } else { 356 // Throw these bytes away 357 *fifo_offsets_ptr++ = 358 fifo_base_offset[CONFIG_FOOTER]; 359 *fifo_offsets_ptr++ = 360 fifo_base_offset[CONFIG_FOOTER]; 361 } 362 break; 363 case EXT_SLAVE_FS16_BIG_ENDIAN: 364 if (j == 3) { 365 // Throw this byte away 366 *fifo_offsets_ptr++ = 367 fifo_base_offset[CONFIG_FOOTER]; 368 *fifo_offsets_ptr++ = offset; 369 } else if (j == 4) { 370 *fifo_offsets_ptr++ = offset - 3; 371 *fifo_offsets_ptr++ = offset; 372 } else { 373 *fifo_offsets_ptr++ = offset - 3; 374 *fifo_offsets_ptr++ = offset; 375 } 376 break; 377 default: 378 return INV_ERROR; // Bad value on ordering 379 } 380 } else { 381 tmp_count += 2; 382 *fifo_offsets_ptr++ = offset; 383 *fifo_offsets_ptr++ = offset + 1; 384 if (fifo_obj.data_config[i] & INV_32_BIT) { 385 *fifo_offsets_ptr++ = offset + 2; 386 *fifo_offsets_ptr++ = offset + 3; 387 tmp_count += 2; 388 } 389 } 390 391 #endif 392 } 393 offset += 4; 394 } 395 fifo_obj.fifo_packet_size += tmp_count; 396 } 397 if (fifo_obj.data_config[CONFIG_FOOTER] == 0 && 398 fifo_obj.fifo_packet_size > 0) { 399 // Add footer 400 result = inv_set_mpu_memory(KEY_CFG_16, 1, ®s); 401 if (result) { 402 LOG_RESULT_LOCATION(result); 403 return result; 404 } 405 fifo_obj.data_config[CONFIG_FOOTER] = 0x0001 | INV_16_BIT; 406 fifo_obj.fifo_packet_size += 2; 407 } else if (fifo_obj.data_config[CONFIG_FOOTER] && 408 (fifo_obj.fifo_packet_size == 2)) { 409 // Remove Footer 410 regs = DINAA0 + 3; 411 result = inv_set_mpu_memory(KEY_CFG_16, 1, ®s); 412 if (result) { 413 LOG_RESULT_LOCATION(result); 414 return result; 415 } 416 fifo_obj.data_config[CONFIG_FOOTER] = 0; 417 fifo_obj.fifo_packet_size = 0; 418 } 419 420 return INV_SUCCESS; 421 } 422 423 inv_error_t inv_decode_quantized_accel(void) 424 { 425 int kk; 426 int fifoRate = inv_get_fifo_rate(); 427 428 if (!fifo_obj.data_config[CONFIG_DMP_QUANT_ACCEL]) 429 return INV_ERROR_FEATURE_NOT_ENABLED; 430 431 for (kk = (INV_MAX_NUM_ACCEL_SAMPLES - (fifoRate + 1)); 432 kk < INV_MAX_NUM_ACCEL_SAMPLES; kk++) { 433 union { 434 unsigned int u10:10; 435 signed int s10:10; 436 } temp; 437 438 union { 439 uint32_t u32; 440 int32_t s32; 441 } value; 442 443 value.u32 = fifo_obj.decoded[REF_QUANT_ACCEL + kk]; 444 // unquantize this samples. 445 // They are stored as x * 2^20 + y * 2^10 + z 446 // Z 447 temp.u10 = value.u32 & 0x3ff; 448 value.s32 -= temp.s10; 449 fifo_obj.decoded_accel[kk][2] = temp.s10 * 64; 450 // Y 451 value.s32 = value.s32 / 1024; 452 temp.u10 = value.u32 & 0x3ff; 453 value.s32 -= temp.s10; 454 fifo_obj.decoded_accel[kk][1] = temp.s10 * 64; 455 // X 456 value.s32 = value.s32 / 1024; 457 temp.u10 = value.u32 & 0x3ff; 458 fifo_obj.decoded_accel[kk][0] = temp.s10 * 64; 459 } 460 return INV_SUCCESS; 461 } 462 463 static inv_error_t inv_state_change_fifo(unsigned char newState) 464 { 465 inv_error_t result = INV_SUCCESS; 466 unsigned char regs[4]; 467 struct mldl_cfg *mldl_cfg = inv_get_dl_config(); 468 469 /* Don't reset the fifo on a fifo rate change */ 470 if ((mldl_cfg->requested_sensors & INV_DMP_PROCESSOR) && 471 (newState != inv_get_state()) && (inv_dmpkey_supported(KEY_D_1_178))) { 472 /* Delay output on restart by 50ms due to warm up time of gyros */ 473 474 short delay = (short)-((50 / inv_get_sample_step_size_ms()) + 1); 475 inv_init_fifo_hardare(); 476 inv_int16_to_big8(delay, regs); 477 result = inv_set_mpu_memory(KEY_D_1_178, 2, regs); 478 if (result) { 479 LOG_RESULT_LOCATION(result); 480 return result; 481 } 482 } 483 484 if (INV_STATE_DMP_STARTED == newState) { 485 if (inv_dmpkey_supported(KEY_D_1_128)) { 486 double tmp; 487 tmp = (0x20000000L * M_PI) / (fifo_obj.fifo_rate + 1); 488 if (tmp > 0x40000000L) 489 tmp = 0x40000000L; 490 (void)inv_int32_to_big8((long)tmp, regs); 491 result = inv_set_mpu_memory(KEY_D_1_128, sizeof(long), regs); 492 if (result) { 493 LOG_RESULT_LOCATION(result); 494 return result; 495 } 496 result = inv_reset_fifo(); 497 if (result) { 498 LOG_RESULT_LOCATION(result); 499 return result; 500 } 501 } 502 } 503 return result; 504 } 505 506 /** 507 * @internal 508 * @brief get the FIFO packet size 509 * @return the FIFO packet size 510 */ 511 uint_fast16_t inv_get_fifo_packet_size(void) 512 { 513 return fifo_obj.fifo_packet_size; 514 } 515 516 /** 517 * @brief Initializes all the internal static variables for 518 * the FIFO module. 519 * @note Should be called by the initialization routine such 520 * as inv_dmp_open(). 521 * @return INV_SUCCESS if successful, a non-zero error code otherwise. 522 */ 523 inv_error_t inv_init_fifo_param(void) 524 { 525 inv_error_t result; 526 memset(&fifo_obj, 0, sizeof(struct fifo_obj)); 527 fifo_obj.decoded[REF_QUATERNION] = 1073741824L; // Set to Identity 528 inv_set_linear_accel_filter_coef(0.f); 529 fifo_obj.fifo_rate = 20; 530 fifo_obj.sample_step_size_ms = 100; 531 memset(&fifo_rate_obj, 0, sizeof(struct fifo_rate_obj)); 532 result = inv_create_mutex(&fifo_rate_obj.mutex); 533 if (result) { 534 LOG_RESULT_LOCATION(result); 535 return result; 536 } 537 result = inv_register_state_callback(inv_state_change_fifo); 538 if (result) { 539 LOG_RESULT_LOCATION(result); 540 return result; 541 } 542 return result; 543 } 544 545 /** 546 * @brief Close the FIFO usage. 547 * @return INV_SUCCESS if successful, a non-zero error code otherwise. 548 */ 549 inv_error_t inv_close_fifo(void) 550 { 551 inv_error_t result; 552 inv_error_t first = INV_SUCCESS; 553 result = inv_unregister_state_callback(inv_state_change_fifo); 554 ERROR_CHECK_FIRST(first, result); 555 result = inv_destroy_mutex(fifo_rate_obj.mutex); 556 ERROR_CHECK_FIRST(first, result); 557 memset(&fifo_rate_obj, 0, sizeof(struct fifo_rate_obj)); 558 return first; 559 } 560 561 /** 562 * Set the gyro source to output to the fifo 563 * 564 * @param source The source. One of 565 * - INV_GYRO_FROM_RAW 566 * - INV_GYRO_FROM_QUATERNION 567 * 568 * @return INV_SUCCESS or non-zero error code; 569 */ 570 inv_error_t inv_set_gyro_data_source(uint_fast8_t source) 571 { 572 if (source != INV_GYRO_FROM_QUATERNION && source != INV_GYRO_FROM_RAW) { 573 return INV_ERROR_INVALID_PARAMETER; 574 } 575 576 fifo_obj.gyro_source = source; 577 return INV_SUCCESS; 578 } 579 580 /** 581 * @brief Reads and processes FIFO data. Also handles callbacks when data is 582 * ready. 583 * @param numPackets 584 * Number of FIFO packets to try to read. You should 585 * use a large number here, such as 100, if you want to read all 586 * the full packets in the FIFO, which is typical operation. 587 * @param processed 588 * The number of FIFO packets processed. This may be incremented 589 * even if high rate processes later fail. 590 * @return INV_SUCCESS if successful, a non-zero error code otherwise. 591 */ 592 inv_error_t inv_read_and_process_fifo(int_fast8_t numPackets, 593 int_fast8_t * processed) 594 { 595 int_fast8_t packet; 596 inv_error_t result = INV_SUCCESS; 597 uint_fast16_t read; 598 struct mldl_cfg *mldl_cfg = inv_get_dl_config(); 599 int kk; 600 601 if (NULL == processed) 602 return INV_ERROR_INVALID_PARAMETER; 603 604 *processed = 0; 605 if (fifo_obj.fifo_packet_size == 0) 606 return result; // Nothing to read 607 608 for (packet = 0; packet < numPackets; ++packet) { 609 if (mldl_cfg->requested_sensors & INV_DMP_PROCESSOR) { 610 unsigned char footer_n_data[MAX_FIFO_LENGTH + FIFO_FOOTER_SIZE]; 611 unsigned char *buf = &footer_n_data[FIFO_FOOTER_SIZE]; 612 read = inv_get_fifo((uint_fast16_t) fifo_obj.fifo_packet_size, 613 footer_n_data); 614 if (0 == read || 615 read != fifo_obj.fifo_packet_size - FIFO_FOOTER_SIZE) { 616 result = inv_get_fifo_status(); 617 if (INV_SUCCESS != result) { 618 memset(fifo_obj.decoded, 0, sizeof(fifo_obj.decoded)); 619 } 620 return result; 621 } 622 623 result = inv_process_fifo_packet(buf); 624 if (result) { 625 LOG_RESULT_LOCATION(result); 626 return result; 627 } 628 } else if (inv_accel_present()) { 629 long data[ACCEL_NUM_AXES]; 630 result = inv_get_accel_data(data); 631 if (result == INV_ERROR_ACCEL_DATA_NOT_READY) { 632 return INV_SUCCESS; 633 } 634 if (result) { 635 LOG_RESULT_LOCATION(result); 636 return result; 637 } 638 639 memset(fifo_obj.decoded, 0, sizeof(fifo_obj.decoded)); 640 fifo_obj.cache = 0; 641 for (kk = 0; kk < ACCEL_NUM_AXES; ++kk) { 642 fifo_obj.decoded[REF_RAW + 4 + kk] = 643 inv_q30_mult((data[kk] << 16), 644 fifo_scale[REF_RAW + 4 + kk]); 645 fifo_obj.decoded[REF_ACCEL + kk] = 646 inv_q30_mult((data[kk] << 15), fifo_scale[REF_ACCEL + kk]); 647 fifo_obj.decoded[REF_ACCEL + kk] -= 648 inv_obj.scaled_accel_bias[kk]; 649 } 650 } 651 // The buffer was processed correctly, so increment even if 652 // other processes fail later, which will return an error 653 *processed = *processed + 1; 654 655 if ((fifo_obj.fifo_rate < INV_MAX_NUM_ACCEL_SAMPLES) && 656 fifo_obj.data_config[CONFIG_DMP_QUANT_ACCEL]) { 657 result = inv_decode_quantized_accel(); 658 if (result) { 659 LOG_RESULT_LOCATION(result); 660 return result; 661 } 662 } 663 664 if (fifo_obj.data_config[CONFIG_QUAT]) { 665 result = inv_accel_compass_supervisor(); 666 if (result) { 667 LOG_RESULT_LOCATION(result); 668 return result; 669 } 670 } 671 672 result = inv_pressure_supervisor(); 673 if (result) { 674 LOG_RESULT_LOCATION(result); 675 return result; 676 } 677 678 // Callbacks now that we have a buffer of data ready 679 result = inv_run_fifo_rate_processes(); 680 if (result) { 681 LOG_RESULT_LOCATION(result); 682 return result; 683 } 684 685 } 686 return result; 687 } 688 689 /** 690 * @brief inv_set_fifo_processed_callback is used to set a processed data callback 691 * function. inv_set_fifo_processed_callback sets a user defined callback 692 * function that triggers when all the decoding has been finished by 693 * the motion processing engines. It is called before other bigger 694 * processing engines to allow lower latency for the user. 695 * 696 * @pre inv_dmp_open() 697 * @ifnot MPL_MF 698 * or inv_open_low_power_pedometer() 699 * or inv_eis_open_dmp() 700 * @endif 701 * and inv_dmp_start() 702 * must <b>NOT</b> have been called. 703 * 704 * @param func A user defined callback function. 705 * 706 * @return INV_SUCCESS if successful, or non-zero error code otherwise. 707 */ 708 inv_error_t inv_set_fifo_processed_callback(void (*func) (void)) 709 { 710 INVENSENSE_FUNC_START; 711 712 if (inv_get_state() < INV_STATE_DMP_OPENED) 713 return INV_ERROR_SM_IMPROPER_STATE; 714 715 fifo_obj.fifo_process_cb = func; 716 717 return INV_SUCCESS; 718 } 719 720 /** 721 * @internal 722 * @brief Process data from the dmp read via the fifo. Takes a buffer 723 * filled with bytes read from the DMP FIFO. 724 * Currently expects only the 16 bytes of quaternion data. 725 * Calculates the motion parameters from that data and stores the 726 * results in an internal data structure. 727 * @param[in,out] dmpData Pointer to the buffer containing the fifo data. 728 * @return INV_SUCCESS or error code. 729 **/ 730 inv_error_t inv_process_fifo_packet(const unsigned char *dmpData) 731 { 732 INVENSENSE_FUNC_START; 733 int N, kk; 734 unsigned char *p; 735 736 p = (unsigned char *)(&fifo_obj.decoded); 737 N = fifo_obj.fifo_packet_size; 738 if (N > sizeof(fifo_obj.decoded)) 739 return INV_ERROR_ASSERTION_FAILURE; 740 741 memset(&fifo_obj.decoded, 0, sizeof(fifo_obj.decoded)); 742 743 for (kk = 0; kk < N; ++kk) { 744 p[fifo_obj.offsets[kk]] = *dmpData++; 745 } 746 747 // If multiplies are much greater cost than if checks, you could check 748 // to see if fifo_scale is non-zero first, or equal to (1L<<30) 749 for (kk = 0; kk < REF_LAST; ++kk) { 750 fifo_obj.decoded[kk] = 751 inv_q30_mult(fifo_obj.decoded[kk], fifo_scale[kk]); 752 } 753 754 memcpy(&fifo_obj.decoded[REF_QUATERNION_6AXIS], 755 &fifo_obj.decoded[REF_QUATERNION], 4 * sizeof(long)); 756 757 inv_obj.flags[INV_PROCESSED_DATA_READY] = 1; 758 fifo_obj.cache = 0; 759 760 return INV_SUCCESS; 761 } 762 763 /** Converts 16-bit temperature data as read from temperature register 764 * into Celcius scaled by 2^16. 765 */ 766 long inv_decode_temperature(short tempReg) 767 { 768 #if defined CONFIG_MPU_SENSORS_MPU6050A2 769 // Celcius = 35 + (T + 3048.7)/325.9 770 return 2906830L + inv_q30_mult((long)tempReg << 16, 3294697L); 771 #endif 772 #if defined CONFIG_MPU_SENSORS_MPU6050B1 773 // Celcius = 35 + (T + 927.4)/360.6 774 return 2462307L + inv_q30_mult((long)tempReg << 16, 2977653L); 775 #endif 776 #if defined CONFIG_MPU_SENSORS_MPU3050 777 // Celcius = 35 + (T + 13200)/280 778 return 5383314L + inv_q30_mult((long)tempReg << 16, 3834792L); 779 #endif 780 } 781 782 /** @internal 783 * Returns the temperature in hardware units. The scaling may change from part to part. 784 */ 785 inv_error_t inv_get_temperature_raw(short *data) 786 { 787 if (data == NULL) 788 return INV_ERROR_INVALID_PARAMETER; 789 790 if (!fifo_obj.data_config[CONFIG_TEMPERATURE]) { 791 inv_error_t result; 792 unsigned char regs[2]; 793 if ((fifo_obj.cache & FIFO_CACHE_TEMPERATURE) == 0) { 794 if (FIFO_DEBUG) 795 MPL_LOGI("Fetching the temperature from the registers\n"); 796 fifo_obj.cache |= FIFO_CACHE_TEMPERATURE; 797 result = inv_serial_read(inv_get_serial_handle(), 798 inv_get_mpu_slave_addr(), MPUREG_TEMP_OUT_H, 2, 799 regs); 800 if (result) { 801 LOG_RESULT_LOCATION(result); 802 return result; 803 } 804 fifo_obj.decoded[REF_RAW] = ((short)regs[0] << 8) | (regs[1]); 805 } 806 } 807 *data = (short)fifo_obj.decoded[REF_RAW]; 808 return INV_SUCCESS; 809 } 810 811 /** 812 * @brief Returns 1-element vector of temperature. It is read from the hardware if it 813 * doesn't exist in the FIFO. 814 * @param[out] data 1-element vector of temperature 815 * @return 0 on success or an error code. 816 */ 817 inv_error_t inv_get_temperature(long *data) 818 { 819 short tr; 820 inv_error_t result; 821 822 if (data == NULL) 823 return INV_ERROR_INVALID_PARAMETER; 824 result = inv_get_temperature_raw(&tr); 825 if (result) { 826 LOG_RESULT_LOCATION(result); 827 return result; 828 } 829 data[0] = inv_decode_temperature(tr); 830 return INV_SUCCESS; 831 } 832 833 /** 834 * @brief Get the Decoded Accel Data. 835 * @param data 836 * a buffer to store the quantized data. 837 * @return INV_SUCCESS if successful, a non-zero error code otherwise. 838 */ 839 inv_error_t inv_get_unquantized_accel(long *data) 840 { 841 int ii, kk; 842 if (data == NULL) 843 return INV_ERROR_INVALID_PARAMETER; 844 845 if (!fifo_obj.data_config[CONFIG_DMP_QUANT_ACCEL]) 846 return INV_ERROR_FEATURE_NOT_ENABLED; 847 848 for (ii = 0; ii < INV_MAX_NUM_ACCEL_SAMPLES; ii++) { 849 for (kk = 0; kk < ACCEL_NUM_AXES; kk++) { 850 data[ii * ACCEL_NUM_AXES + kk] = fifo_obj.decoded_accel[ii][kk]; 851 } 852 } 853 854 return INV_SUCCESS; 855 } 856 857 /** 858 * @brief Get the Quantized Accel data algorithm output from the FIFO. 859 * @param data 860 * a buffer to store the quantized data. 861 * @return INV_SUCCESS if successful, a non-zero error code otherwise. 862 */ 863 inv_error_t inv_get_quantized_accel(long *data) 864 { 865 int ii; 866 if (data == NULL) 867 return INV_ERROR_INVALID_PARAMETER; 868 869 if (!fifo_obj.data_config[CONFIG_DMP_QUANT_ACCEL]) 870 return INV_ERROR_FEATURE_NOT_ENABLED; 871 872 for (ii = 0; ii < INV_MAX_NUM_ACCEL_SAMPLES; ii++) { 873 data[ii] = fifo_obj.decoded[REF_QUANT_ACCEL + ii]; 874 } 875 876 return INV_SUCCESS; 877 } 878 879 /** This gets raw gyro data. The data is taken from the FIFO if it was put in the FIFO 880 * and it is read from the registers if it was not put into the FIFO. The data is 881 * cached till the next FIFO processing block time. 882 * @param[out] data Length 3, Gyro data 883 */ 884 inv_error_t inv_get_gyro_sensor(long *data) 885 { 886 if (data == NULL) 887 return INV_ERROR_INVALID_PARAMETER; 888 if ((fifo_obj.data_config[CONFIG_RAW_DATA] & 7) != 7) { 889 inv_error_t result; 890 unsigned char regs[6]; 891 if ((fifo_obj.cache & FIFO_CACHE_GYRO) == 0) { 892 fifo_obj.cache |= FIFO_CACHE_GYRO; 893 result = 894 inv_serial_read(inv_get_serial_handle(), 895 inv_get_mpu_slave_addr(), MPUREG_GYRO_XOUT_H, 6, 896 regs); 897 if (result) { 898 LOG_RESULT_LOCATION(result); 899 return result; 900 } 901 fifo_obj.decoded[REF_RAW + 1] = 902 (((long)regs[0]) << 24) | (((long)regs[1]) << 16); 903 fifo_obj.decoded[REF_RAW + 2] = 904 (((long)regs[2]) << 24) | (((long)regs[3]) << 16); 905 fifo_obj.decoded[REF_RAW + 3] = 906 (((long)regs[4]) << 24) | (((long)regs[5]) << 16); 907 908 // Temperature starts at location 0, Gyro at location 1. 909 fifo_obj.decoded[REF_RAW + 1] = 910 inv_q30_mult(fifo_obj.decoded[REF_RAW + 1], 911 fifo_scale[REF_RAW + 1]); 912 fifo_obj.decoded[REF_RAW + 2] = 913 inv_q30_mult(fifo_obj.decoded[REF_RAW + 2], 914 fifo_scale[REF_RAW + 2]); 915 fifo_obj.decoded[REF_RAW + 3] = 916 inv_q30_mult(fifo_obj.decoded[REF_RAW + 3], 917 fifo_scale[REF_RAW + 3]); 918 } 919 data[0] = fifo_obj.decoded[REF_RAW + 1]; 920 data[1] = fifo_obj.decoded[REF_RAW + 2]; 921 data[2] = fifo_obj.decoded[REF_RAW + 3]; 922 } else { 923 long data2[6]; 924 inv_get_gyro_and_accel_sensor(data2); 925 data[0] = data2[0]; 926 data[1] = data2[1]; 927 data[2] = data2[2]; 928 } 929 return INV_SUCCESS; 930 } 931 932 /** 933 * @brief Returns 6-element vector of gyro and accel data 934 * @param[out] data 6-element vector of gyro and accel data 935 * @return 0 on success or an error code. 936 */ 937 inv_error_t inv_get_gyro_and_accel_sensor(long *data) 938 { 939 int ii; 940 if (data == NULL) 941 return INV_ERROR_INVALID_PARAMETER; 942 943 if (!fifo_obj.data_config[CONFIG_RAW_DATA]) 944 return INV_ERROR_FEATURE_NOT_ENABLED; 945 946 for (ii = 0; ii < (GYRO_NUM_AXES + ACCEL_NUM_AXES); ii++) { 947 data[ii] = fifo_obj.decoded[REF_RAW + 1 + ii]; 948 } 949 950 return INV_SUCCESS; 951 } 952 953 /** 954 * @brief Returns 3-element vector of external sensor 955 * @param[out] data 3-element vector of external sensor 956 * @return 0 on success or an error code. 957 */ 958 inv_error_t inv_get_external_sensor_data(long *data, int size) 959 { 960 #if defined CONFIG_MPU_SENSORS_MPU6050A2 || \ 961 defined CONFIG_MPU_SENSORS_MPU6050B1 962 int ii; 963 if (data == NULL) 964 return INV_ERROR_INVALID_PARAMETER; 965 966 if (!fifo_obj.data_config[CONFIG_RAW_EXTERNAL]) 967 return INV_ERROR_FEATURE_NOT_ENABLED; 968 969 for (ii = 0; ii < size && ii < 6; ii++) { 970 data[ii] = fifo_obj.decoded[REF_RAW_EXTERNAL + ii]; 971 } 972 973 return INV_SUCCESS; 974 #else 975 memset(data, 0, COMPASS_NUM_AXES * sizeof(long)); 976 return INV_ERROR_FEATURE_NOT_IMPLEMENTED; 977 #endif 978 } 979 980 /** 981 * Sends accelerometer data to the FIFO. 982 * 983 * @param[in] elements Which of the 3 elements to send. Use INV_ALL for 3 axis 984 * or INV_ELEMENT_1, INV_ELEMENT_2, INV_ELEMENT_3 or'd together 985 * for a subset. 986 * 987 * @param[in] accuracy Set to INV_32_BIT for 32-bit data, or INV_16_BIT for 16 988 * bit data. Set to zero to remove it from the FIFO. 989 */ 990 inv_error_t inv_send_accel(uint_fast16_t elements, uint_fast16_t accuracy) 991 { 992 INVENSENSE_FUNC_START; 993 unsigned char regs[4] = { DINAF8 + 1, DINA28, DINA30, DINA38 }; 994 inv_error_t result; 995 int kk; 996 997 if (inv_get_state() < INV_STATE_DMP_OPENED) 998 return INV_ERROR_SM_IMPROPER_STATE; 999 1000 result = inv_construct3_fifo(regs, elements, accuracy, REF_ACCEL, 1001 KEY_CFG_12, CONFIG_ACCEL); 1002 if (result) { 1003 LOG_RESULT_LOCATION(result); 1004 return result; 1005 } 1006 1007 for (kk = 0; kk < ACCEL_NUM_AXES; kk++) { 1008 fifo_scale[REF_ACCEL + kk] = 2 * inv_obj.accel_sens; 1009 } 1010 1011 return inv_set_footer(); 1012 } 1013 1014 /** 1015 * Sends control data to the FIFO. Control data is a 4 length vector of 32-bits. 1016 * 1017 * @param[in] elements Which of the 4 elements to send. Use INV_ALL for all 1018 * or INV_ELEMENT_1, INV_ELEMENT_2, INV_ELEMENT_3, INV_ELEMENT_4 or'd 1019 * together for a subset. 1020 * 1021 * @param[in] accuracy Set to INV_32_BIT for 32-bit data, or INV_16_BIT for 16 1022 * bit data. Set to zero to remove it from the FIFO. 1023 */ 1024 inv_error_t inv_send_cntrl_data(uint_fast16_t elements, uint_fast16_t accuracy) 1025 { 1026 INVENSENSE_FUNC_START; 1027 int_fast8_t kk; 1028 inv_error_t result; 1029 unsigned char regs[5] = { DINAF8 + 1, DINA20, DINA28, DINA30, DINA38 }; 1030 1031 if (inv_get_state() < INV_STATE_DMP_OPENED) 1032 return INV_ERROR_SM_IMPROPER_STATE; 1033 1034 elements = inv_set_fifo_reference(elements, accuracy, REF_CONTROL, 4); 1035 accuracy = inv_set_fifo_accuracy(elements, accuracy, CONFIG_CONTROL_DATA); 1036 1037 if (accuracy & INV_16_BIT) { 1038 regs[0] = DINAF8 + 2; 1039 } 1040 1041 fifo_obj.data_config[CONFIG_CONTROL_DATA] = elements | accuracy; 1042 1043 for (kk = 0; kk < 4; ++kk) { 1044 if ((elements & 1) == 0) 1045 regs[kk + 1] = DINAA0 + 3; 1046 elements >>= 1; 1047 } 1048 1049 result = inv_set_mpu_memory(KEY_CFG_1, 5, regs); 1050 if (result) { 1051 LOG_RESULT_LOCATION(result); 1052 return result; 1053 } 1054 1055 return inv_set_footer(); 1056 } 1057 1058 /** 1059 * Adds a rolling counter to the fifo packet. When used with the footer 1060 * the data comes out the first time: 1061 * 1062 * @code 1063 * <data0><data1>...<dataN><PacketNum0><PacketNum1> 1064 * @endcode 1065 * for every other packet it is 1066 * 1067 * @code 1068 * <FifoFooter0><FifoFooter1><data0><data1>...<dataN><PacketNum0><PacketNum1> 1069 * @endcode 1070 * 1071 * This allows for scanning of the fifo for packets 1072 * 1073 * @return INV_SUCCESS or error code 1074 */ 1075 inv_error_t inv_send_packet_number(uint_fast16_t accuracy) 1076 { 1077 INVENSENSE_FUNC_START; 1078 inv_error_t result; 1079 unsigned char regs; 1080 uint_fast16_t elements; 1081 1082 if (inv_get_state() < INV_STATE_DMP_OPENED) 1083 return INV_ERROR_SM_IMPROPER_STATE; 1084 1085 elements = inv_set_fifo_reference(1, accuracy, REF_DMP_PACKET, 1); 1086 if (elements & 1) { 1087 regs = DINA28; 1088 fifo_obj.data_config[CONFIG_DMP_PACKET_NUMBER] = 1089 INV_ELEMENT_1 | INV_16_BIT; 1090 } else { 1091 regs = DINAF8 + 3; 1092 fifo_obj.data_config[CONFIG_DMP_PACKET_NUMBER] = 0; 1093 } 1094 result = inv_set_mpu_memory(KEY_CFG_23, 1, ®s); 1095 if (result) { 1096 LOG_RESULT_LOCATION(result); 1097 return result; 1098 } 1099 1100 return inv_set_footer(); 1101 } 1102 1103 /** 1104 * @brief Send the computed gravity vectors into the FIFO. 1105 * The gravity vectors can be retrieved from the FIFO via 1106 * inv_get_gravity(), to have the gravitation vector expressed 1107 * in coordinates relative to the body. 1108 * 1109 * Gravity is a derived vector derived from the quaternion. 1110 * @param elements 1111 * the gravitation vectors components bitmask. 1112 * To send all compoents use INV_ALL. 1113 * @param accuracy 1114 * The number of bits the gravitation vector is expressed 1115 * into. 1116 * Set to INV_32_BIT for 32-bit data, or INV_16_BIT for 16 1117 * bit data. 1118 * Set to zero to remove it from the FIFO. 1119 * 1120 * @return INV_SUCCESS if successful, a non-zero error code otherwise. 1121 */ 1122 inv_error_t inv_send_gravity(uint_fast16_t elements, uint_fast16_t accuracy) 1123 { 1124 INVENSENSE_FUNC_START; 1125 inv_error_t result; 1126 1127 result = inv_send_quaternion(accuracy); 1128 if (result) { 1129 LOG_RESULT_LOCATION(result); 1130 return result; 1131 } 1132 1133 return inv_set_footer(); 1134 } 1135 1136 /** Sends gyro data to the FIFO. Gyro data is a 3 length vector 1137 * of 32-bits. Should be called once after inv_dmp_open() and before inv_dmp_start(). 1138 * @param[in] elements Which of the 3 elements to send. Use INV_ALL for all of them 1139 * or INV_ELEMENT_1, INV_ELEMENT_2, INV_ELEMENT_3 or'd together 1140 * for a subset. 1141 * @param[in] accuracy Set to INV_32_BIT for 32-bit data, or INV_16_BIT for 16 1142 * bit data. Set to zero to remove it from the FIFO. 1143 */ 1144 inv_error_t inv_send_gyro(uint_fast16_t elements, uint_fast16_t accuracy) 1145 { 1146 INVENSENSE_FUNC_START; 1147 unsigned char regs[4] = { DINAF8 + 1, DINA20, DINA28, DINA30 }; 1148 inv_error_t result; 1149 1150 if (inv_get_state() < INV_STATE_DMP_OPENED) 1151 return INV_ERROR_SM_IMPROPER_STATE; 1152 1153 if (fifo_obj.gyro_source == INV_GYRO_FROM_QUATERNION) { 1154 regs[0] = DINA90 + 5; 1155 result = inv_set_mpu_memory(KEY_CFG_GYRO_SOURCE, 1, regs); 1156 if (result) { 1157 LOG_RESULT_LOCATION(result); 1158 return result; 1159 } 1160 regs[0] = DINAF8 + 1; 1161 regs[1] = DINA20; 1162 regs[2] = DINA28; 1163 regs[3] = DINA30; 1164 } else { 1165 regs[0] = DINA90 + 10; 1166 result = inv_set_mpu_memory(KEY_CFG_GYRO_SOURCE, 1, regs); 1167 if (result) { 1168 LOG_RESULT_LOCATION(result); 1169 return result; 1170 } 1171 regs[0] = DINAF8 + 1; 1172 regs[1] = DINA28; 1173 regs[2] = DINA30; 1174 regs[3] = DINA38; 1175 } 1176 result = inv_construct3_fifo(regs, elements, accuracy, REF_GYROS, 1177 KEY_CFG_9, CONFIG_GYROS); 1178 1179 return inv_set_footer(); 1180 } 1181 1182 /** Sends linear accelerometer data to the FIFO. 1183 * 1184 * Linear accelerometer data is a 3 length vector of 32-bits. It is the 1185 * acceleration in the body frame with gravity removed. 1186 * 1187 * 1188 * @param[in] elements Which of the 3 elements to send. Use INV_ALL for all of 1189 * them or INV_ELEMENT_1, INV_ELEMENT_2, INV_ELEMENT_3 or'd together 1190 * for a subset. 1191 * 1192 * NOTE: Elements is ignored if the fifo rate is < INV_MAX_NUM_ACCEL_SAMPLES 1193 * @param[in] accuracy Set to INV_32_BIT for 32-bit data, or INV_16_BIT for 16 1194 * bit data. Set to zero to remove it from the FIFO. 1195 */ 1196 inv_error_t inv_send_linear_accel(uint_fast16_t elements, 1197 uint_fast16_t accuracy) 1198 { 1199 INVENSENSE_FUNC_START; 1200 inv_error_t result; 1201 unsigned char state = inv_get_state(); 1202 1203 if (state < INV_STATE_DMP_OPENED) 1204 return INV_ERROR_SM_IMPROPER_STATE; 1205 1206 result = inv_send_gravity(elements, accuracy); 1207 if (result) { 1208 LOG_RESULT_LOCATION(result); 1209 return result; 1210 } 1211 result = inv_send_accel(elements, accuracy); 1212 if (result) { 1213 LOG_RESULT_LOCATION(result); 1214 return result; 1215 } 1216 1217 return inv_set_footer(); 1218 } 1219 1220 /** Sends linear world accelerometer data to the FIFO. Linear world 1221 * accelerometer data is a 3 length vector of 32-bits. It is the acceleration 1222 * in the world frame with gravity removed. Should be called once after 1223 * inv_dmp_open() and before inv_dmp_start(). 1224 * 1225 * @param[in] elements Which of the 3 elements to send. Use INV_ALL for all of 1226 * them or INV_ELEMENT_1, INV_ELEMENT_2, INV_ELEMENT_3 or'd together 1227 * for a subset. 1228 * @param[in] accuracy Set to INV_32_BIT for 32-bit data, or INV_16_BIT for 16 1229 * bit data. 1230 */ 1231 inv_error_t inv_send_linear_accel_in_world(uint_fast16_t elements, 1232 uint_fast16_t accuracy) 1233 { 1234 INVENSENSE_FUNC_START; 1235 inv_error_t result; 1236 1237 result = inv_send_linear_accel(INV_ALL, accuracy); 1238 if (result) { 1239 LOG_RESULT_LOCATION(result); 1240 return result; 1241 } 1242 result = inv_send_quaternion(accuracy); 1243 1244 return inv_set_footer(); 1245 } 1246 1247 /** Sends quaternion data to the FIFO. Quaternion data is a 4 length vector 1248 * of 32-bits. Should be called once after inv_dmp_open() and before inv_dmp_start(). 1249 * @param[in] accuracy Set to INV_32_BIT for 32-bit data, or INV_16_BIT for 16 1250 * bit data. 1251 */ 1252 inv_error_t inv_send_quaternion(uint_fast16_t accuracy) 1253 { 1254 INVENSENSE_FUNC_START; 1255 unsigned char regs[5] = { DINAF8 + 1, DINA20, DINA28, 1256 DINA30, DINA38 1257 }; 1258 uint_fast16_t elements, kk; 1259 inv_error_t result; 1260 1261 if (inv_get_state() < INV_STATE_DMP_OPENED) 1262 return INV_ERROR_SM_IMPROPER_STATE; 1263 1264 elements = inv_set_fifo_reference(0xf, accuracy, REF_QUATERNION, 4); 1265 accuracy = inv_set_fifo_accuracy(elements, accuracy, CONFIG_QUAT); 1266 1267 if (accuracy & INV_16_BIT) { 1268 regs[0] = DINAF8 + 2; 1269 } 1270 1271 fifo_obj.data_config[CONFIG_QUAT] = elements | accuracy; 1272 1273 for (kk = 0; kk < 4; ++kk) { 1274 if ((elements & 1) == 0) 1275 regs[kk + 1] = DINAA0 + 3; 1276 elements >>= 1; 1277 } 1278 1279 result = inv_set_mpu_memory(KEY_CFG_8, 5, regs); 1280 if (result) { 1281 LOG_RESULT_LOCATION(result); 1282 return result; 1283 } 1284 1285 return inv_set_footer(); 1286 } 1287 1288 /** Sends raw data to the FIFO. 1289 * Should be called once after inv_dmp_open() and before inv_dmp_start(). 1290 * @param[in] elements Which of the 7 elements to send. Use INV_ALL for all of them 1291 * or INV_ELEMENT_1, INV_ELEMENT_2, INV_ELEMENT_3 ... INV_ELEMENT_7 or'd together 1292 * for a subset. The first element is temperature, the next 3 are gyro data, 1293 * and the last 3 accel data. 1294 * @param accuracy 1295 * The element's accuracy, can be INV_16_BIT, INV_32_BIT, or 0 to turn off. 1296 * @return 0 if successful, a non-zero error code otherwise. 1297 */ 1298 inv_error_t inv_send_sensor_data(uint_fast16_t elements, uint_fast16_t accuracy) 1299 { 1300 int result; 1301 #if defined CONFIG_MPU_SENSORS_MPU6050A2 || \ 1302 defined CONFIG_MPU_SENSORS_MPU6050B1 1303 unsigned char regs[7] = { DINAA0 + 3, DINAA0 + 3, DINAA0 + 3, 1304 DINAA0 + 3, DINAA0 + 3, DINAA0 + 3, 1305 DINAA0 + 3 1306 }; 1307 1308 if (inv_get_state() < INV_STATE_DMP_OPENED) 1309 return INV_ERROR_SM_IMPROPER_STATE; 1310 1311 if (accuracy) 1312 accuracy = INV_16_BIT; 1313 1314 elements = inv_set_fifo_reference(elements, accuracy, REF_RAW, 7); 1315 1316 if (elements & 1) 1317 fifo_obj.data_config[CONFIG_TEMPERATURE] = 1 | INV_16_BIT; 1318 else 1319 fifo_obj.data_config[CONFIG_TEMPERATURE] = 0; 1320 if (elements & 0x7e) 1321 fifo_obj.data_config[CONFIG_RAW_DATA] = 1322 (0x3f & (elements >> 1)) | INV_16_BIT; 1323 else 1324 fifo_obj.data_config[CONFIG_RAW_DATA] = 0; 1325 1326 if (elements & INV_ELEMENT_1) { 1327 regs[0] = DINACA; 1328 } 1329 if (elements & INV_ELEMENT_2) { 1330 regs[1] = DINBC4; 1331 } 1332 if (elements & INV_ELEMENT_3) { 1333 regs[2] = DINACC; 1334 } 1335 if (elements & INV_ELEMENT_4) { 1336 regs[3] = DINBC6; 1337 } 1338 if (elements & INV_ELEMENT_5) { 1339 regs[4] = DINBC0; 1340 } 1341 if (elements & INV_ELEMENT_6) { 1342 regs[5] = DINAC8; 1343 } 1344 if (elements & INV_ELEMENT_7) { 1345 regs[6] = DINBC2; 1346 } 1347 result = inv_set_mpu_memory(KEY_CFG_15, 7, regs); 1348 if (result) { 1349 LOG_RESULT_LOCATION(result); 1350 return result; 1351 } 1352 1353 return inv_set_footer(); 1354 1355 #else 1356 INVENSENSE_FUNC_START; 1357 unsigned char regs[4] = { DINAA0 + 3, 1358 DINAA0 + 3, 1359 DINAA0 + 3, 1360 DINAA0 + 3 1361 }; 1362 1363 if (inv_get_state() < INV_STATE_DMP_OPENED) 1364 return INV_ERROR_SM_IMPROPER_STATE; 1365 1366 if (accuracy) 1367 accuracy = INV_16_BIT; 1368 1369 elements = inv_set_fifo_reference(elements, accuracy, REF_RAW, 7); 1370 1371 if (elements & 0x03) { 1372 elements |= 0x03; 1373 regs[0] = DINA20; 1374 } 1375 if (elements & 0x0C) { 1376 elements |= 0x0C; 1377 regs[1] = DINA28; 1378 } 1379 if (elements & 0x30) { 1380 elements |= 0x30; 1381 regs[2] = DINA30; 1382 } 1383 if (elements & 0x40) { 1384 elements |= 0xC0; 1385 regs[3] = DINA38; 1386 } 1387 1388 result = inv_set_mpu_memory(KEY_CFG_15, 4, regs); 1389 if (result) { 1390 LOG_RESULT_LOCATION(result); 1391 return result; 1392 } 1393 1394 if (elements & 0x01) 1395 fifo_obj.data_config[CONFIG_TEMPERATURE] = 1 | INV_16_BIT; 1396 else 1397 fifo_obj.data_config[CONFIG_TEMPERATURE] = 0; 1398 if (elements & 0xfe) 1399 fifo_obj.data_config[CONFIG_RAW_DATA] = 1400 (0x7f & (elements >> 1)) | INV_16_BIT; 1401 else 1402 fifo_obj.data_config[CONFIG_RAW_DATA] = 0; 1403 1404 return inv_set_footer(); 1405 #endif 1406 } 1407 1408 /** Sends raw external data to the FIFO. 1409 * Should be called once after inv_dmp_open() and before inv_dmp_start(). 1410 * @param[in] elements Which of the 3 elements to send. Use INV_ALL for all of them 1411 * or INV_ELEMENT_1, INV_ELEMENT_2, INV_ELEMENT_3 or'd together 1412 * for a subset. 1413 * @param[in] accuracy INV_16_BIT to send data, 0 to stop sending this data. 1414 * Sending and Stop sending are reference counted, so data actually 1415 * stops when the reference reaches zero. 1416 */ 1417 inv_error_t inv_send_external_sensor_data(uint_fast16_t elements, 1418 uint_fast16_t accuracy) 1419 { 1420 #if defined CONFIG_MPU_SENSORS_MPU6050A2 || \ 1421 defined CONFIG_MPU_SENSORS_MPU6050B1 1422 int result; 1423 unsigned char regs[6] = { DINAA0 + 3, DINAA0 + 3, 1424 DINAA0 + 3, DINAA0 + 3, 1425 DINAA0 + 3, DINAA0 + 3 }; 1426 1427 if (inv_get_state() < INV_STATE_DMP_OPENED) 1428 return INV_ERROR_SM_IMPROPER_STATE; 1429 1430 if (accuracy) 1431 accuracy = INV_16_BIT; 1432 1433 elements = inv_set_fifo_reference(elements, accuracy, REF_RAW_EXTERNAL, 6); 1434 1435 if (elements) 1436 fifo_obj.data_config[CONFIG_RAW_EXTERNAL] = elements | INV_16_BIT; 1437 else 1438 fifo_obj.data_config[CONFIG_RAW_EXTERNAL] = 0; 1439 1440 if (elements & INV_ELEMENT_1) { 1441 regs[0] = DINBC2; 1442 } 1443 if (elements & INV_ELEMENT_2) { 1444 regs[1] = DINACA; 1445 } 1446 if (elements & INV_ELEMENT_3) { 1447 regs[2] = DINBC4; 1448 } 1449 if (elements & INV_ELEMENT_4) { 1450 regs[3] = DINBC0; 1451 } 1452 if (elements & INV_ELEMENT_5) { 1453 regs[4] = DINAC8; 1454 } 1455 if (elements & INV_ELEMENT_6) { 1456 regs[5] = DINACC; 1457 } 1458 1459 result = inv_set_mpu_memory(KEY_CFG_EXTERNAL, sizeof(regs), regs); 1460 if (result) { 1461 LOG_RESULT_LOCATION(result); 1462 return result; 1463 } 1464 1465 return inv_set_footer(); 1466 1467 #else 1468 return INV_ERROR_FEATURE_NOT_IMPLEMENTED; // Feature not supported 1469 #endif 1470 } 1471 1472 /** 1473 * @brief Send the Quantized Acceleromter data into the FIFO. The data can be 1474 * retrieved using inv_get_quantized_accel() or inv_get_unquantized_accel(). 1475 * 1476 * To be useful this should be set to fifo_rate + 1 if less than 1477 * INV_MAX_NUM_ACCEL_SAMPLES, otherwise it doesn't work. 1478 * 1479 * @param elements 1480 * the components bitmask. 1481 * To send all compoents use INV_ALL. 1482 * 1483 * @param accuracy 1484 * Use INV_32_BIT for 32-bit data or INV_16_BIT for 1485 * 16-bit data. 1486 * Set to zero to remove it from the FIFO. 1487 * 1488 * @return INV_SUCCESS if successful, a non-zero error code otherwise. 1489 */ 1490 inv_error_t inv_send_quantized_accel(uint_fast16_t elements, 1491 uint_fast16_t accuracy) 1492 { 1493 INVENSENSE_FUNC_START; 1494 unsigned char regs[5] = { DINAF8 + 1, DINA20, DINA28, 1495 DINA30, DINA38 1496 }; 1497 unsigned char regs2[4] = { DINA20, DINA28, 1498 DINA30, DINA38 1499 }; 1500 inv_error_t result; 1501 int_fast8_t kk; 1502 int_fast8_t ii; 1503 1504 if (inv_get_state() < INV_STATE_DMP_OPENED) 1505 return INV_ERROR_SM_IMPROPER_STATE; 1506 1507 elements = inv_set_fifo_reference(elements, accuracy, REF_QUANT_ACCEL, 8); 1508 1509 if (elements) { 1510 fifo_obj.data_config[CONFIG_DMP_QUANT_ACCEL] = (elements) | INV_32_BIT; 1511 } else { 1512 fifo_obj.data_config[CONFIG_DMP_QUANT_ACCEL] = 0; 1513 } 1514 1515 for (kk = 0; kk < INV_MAX_NUM_ACCEL_SAMPLES; ++kk) { 1516 fifo_obj.decoded[REF_QUANT_ACCEL + kk] = 0; 1517 for (ii = 0; ii < ACCEL_NUM_AXES; ii++) { 1518 fifo_obj.decoded_accel[kk][ii] = 0; 1519 } 1520 } 1521 1522 for (kk = 0; kk < 4; ++kk) { 1523 if ((elements & 1) == 0) 1524 regs[kk + 1] = DINAA0 + 3; 1525 elements >>= 1; 1526 } 1527 1528 result = inv_set_mpu_memory(KEY_CFG_TAP0, 5, regs); 1529 if (result) { 1530 LOG_RESULT_LOCATION(result); 1531 return result; 1532 } 1533 1534 for (kk = 0; kk < 4; ++kk) { 1535 if ((elements & 1) == 0) 1536 regs2[kk] = DINAA0 + 3; 1537 elements >>= 1; 1538 } 1539 1540 result = inv_set_mpu_memory(KEY_CFG_TAP4, 4, regs2); 1541 if (result) { 1542 LOG_RESULT_LOCATION(result); 1543 return result; 1544 } 1545 1546 return inv_set_footer(); 1547 } 1548 1549 inv_error_t inv_send_eis(uint_fast16_t elements, uint_fast16_t accuracy) 1550 { 1551 INVENSENSE_FUNC_START; 1552 int_fast8_t kk; 1553 unsigned char regs[3] = { DINA28, DINA30, DINA38 }; 1554 inv_error_t result; 1555 1556 if (inv_get_state() < INV_STATE_DMP_OPENED) 1557 return INV_ERROR_SM_IMPROPER_STATE; 1558 1559 if (accuracy) { 1560 accuracy = INV_32_BIT; 1561 } 1562 1563 elements = inv_set_fifo_reference(elements, accuracy, REF_EIS, 3); 1564 accuracy = inv_set_fifo_accuracy(elements, accuracy, CONFIG_EIS); 1565 1566 fifo_obj.data_config[CONFIG_EIS] = elements | accuracy; 1567 1568 for (kk = 0; kk < 3; ++kk) { 1569 if ((elements & 1) == 0) 1570 regs[kk] = DINAA0 + 7; 1571 elements >>= 1; 1572 } 1573 1574 result = inv_set_mpu_memory(KEY_P_EIS_FIFO_XSHIFT, 3, regs); 1575 1576 return inv_set_footer(); 1577 } 1578 1579 /** 1580 * @brief Returns 3-element vector of accelerometer data in body frame. 1581 * 1582 * @param[out] data 3-element vector of accelerometer data in body frame. 1583 * One gee = 2^16. 1584 * @return 0 on success or an error code. 1585 */ 1586 inv_error_t inv_get_accel(long *data) 1587 { 1588 int kk; 1589 struct mldl_cfg *mldl_cfg = inv_get_dl_config(); 1590 1591 if (data == NULL) 1592 return INV_ERROR_INVALID_PARAMETER; 1593 1594 if ((!fifo_obj.data_config[CONFIG_ACCEL] && 1595 (mldl_cfg->requested_sensors & INV_DMP_PROCESSOR)) 1596 || 1597 (!(mldl_cfg->requested_sensors & INV_DMP_PROCESSOR) && 1598 !inv_accel_present())) 1599 return INV_ERROR_FEATURE_NOT_ENABLED; 1600 1601 for (kk = 0; kk < ACCEL_NUM_AXES; ++kk) { 1602 data[kk] = fifo_obj.decoded[REF_ACCEL + kk]; 1603 } 1604 1605 return INV_SUCCESS; 1606 } 1607 1608 /** 1609 * @brief Returns 4-element quaternion vector derived from 6-axis or 1610 * 9-axis if 9-axis was implemented. 6-axis is gyros and accels. 9-axis is 1611 * gyros, accel and compass. 1612 * 1613 * @param[out] data 4-element quaternion vector. One is scaled to 2^30. 1614 * @return 0 on success or an error code. 1615 */ 1616 inv_error_t inv_get_quaternion(long *data) 1617 { 1618 int kk; 1619 1620 if (data == NULL) 1621 return INV_ERROR_INVALID_PARAMETER; 1622 1623 if (!fifo_obj.data_config[CONFIG_QUAT]) 1624 return INV_ERROR_FEATURE_NOT_ENABLED; 1625 1626 for (kk = 0; kk < 4; ++kk) { 1627 data[kk] = fifo_obj.decoded[REF_QUATERNION + kk]; 1628 } 1629 1630 return INV_SUCCESS; 1631 } 1632 1633 /** 1634 * @brief Returns 4-element quaternion vector derived from 6 1635 * axis sensors (gyros and accels). 1636 * @param[out] data 1637 * 4-element quaternion vector. One is scaled to 2^30. 1638 * @return 0 on success or an error code. 1639 */ 1640 inv_error_t inv_get_6axis_quaternion(long *data) 1641 { 1642 int kk; 1643 if (data == NULL) 1644 return INV_ERROR_INVALID_PARAMETER; 1645 1646 if (!fifo_obj.data_config[CONFIG_QUAT]) 1647 return INV_ERROR_FEATURE_NOT_ENABLED; 1648 1649 for (kk = 0; kk < 4; ++kk) { 1650 data[kk] = fifo_obj.decoded[REF_QUATERNION_6AXIS + kk]; 1651 } 1652 1653 return INV_SUCCESS; 1654 } 1655 1656 inv_error_t inv_get_relative_quaternion(long *data) 1657 { 1658 if (data == NULL) 1659 return INV_ERROR; 1660 data[0] = inv_obj.relative_quat[0]; 1661 data[1] = inv_obj.relative_quat[1]; 1662 data[2] = inv_obj.relative_quat[2]; 1663 data[3] = inv_obj.relative_quat[3]; 1664 return INV_SUCCESS; 1665 } 1666 1667 /** 1668 * @brief Returns 3-element vector of gyro data in body frame. 1669 * @param[out] data 1670 * 3-element vector of gyro data in body frame 1671 * with gravity removed. One degree per second = 2^16. 1672 * @return 0 on success or an error code. 1673 */ 1674 inv_error_t inv_get_gyro(long *data) 1675 { 1676 int kk; 1677 if (data == NULL) 1678 return INV_ERROR_INVALID_PARAMETER; 1679 1680 if (fifo_obj.data_config[CONFIG_GYROS]) { 1681 for (kk = 0; kk < 3; ++kk) { 1682 data[kk] = fifo_obj.decoded[REF_GYROS + kk]; 1683 } 1684 return INV_SUCCESS; 1685 } else { 1686 return INV_ERROR_FEATURE_NOT_ENABLED; 1687 } 1688 } 1689 1690 /** 1691 * @brief Get the 3-element gravity vector from the FIFO expressed 1692 * in coordinates relative to the body frame. 1693 * @param data 1694 * 3-element vector of gravity in body frame. 1695 * @return 0 on success or an error code. 1696 */ 1697 inv_error_t inv_get_gravity(long *data) 1698 { 1699 long quat[4]; 1700 int ii; 1701 inv_error_t result; 1702 1703 if (data == NULL) 1704 return INV_ERROR_INVALID_PARAMETER; 1705 1706 if (!fifo_obj.data_config[CONFIG_QUAT]) 1707 return INV_ERROR_FEATURE_NOT_ENABLED; 1708 1709 if ((fifo_obj.cache & FIFO_CACHE_GRAVITY_BODY) == 0) { 1710 fifo_obj.cache |= FIFO_CACHE_GRAVITY_BODY; 1711 1712 // Compute it from Quaternion 1713 result = inv_get_quaternion(quat); 1714 if (result) { 1715 LOG_RESULT_LOCATION(result); 1716 return result; 1717 } 1718 1719 data[0] = 1720 inv_q29_mult(quat[1], quat[3]) - inv_q29_mult(quat[2], quat[0]); 1721 data[1] = 1722 inv_q29_mult(quat[2], quat[3]) + inv_q29_mult(quat[1], quat[0]); 1723 data[2] = 1724 (inv_q29_mult(quat[3], quat[3]) + inv_q29_mult(quat[0], quat[0])) - 1725 1073741824L; 1726 1727 for (ii = 0; ii < ACCEL_NUM_AXES; ii++) { 1728 data[ii] >>= 14; 1729 fifo_obj.gravity_cache[ii] = data[ii]; 1730 } 1731 } else { 1732 data[0] = fifo_obj.gravity_cache[0]; 1733 data[1] = fifo_obj.gravity_cache[1]; 1734 data[2] = fifo_obj.gravity_cache[2]; 1735 } 1736 1737 return INV_SUCCESS; 1738 } 1739 1740 /** 1741 * @brief Sets the filter coefficent used for computing the acceleration 1742 * bias which is used to compute linear acceleration. 1743 * @param[in] coef Fitler coefficient. 0. means no filter, a small number means 1744 * a small cutoff frequency with an increasing number meaning 1745 * an increasing cutoff frequency. 1746 */ 1747 inv_error_t inv_set_linear_accel_filter_coef(float coef) 1748 { 1749 fifo_obj.acc_filter_coef = coef; 1750 return INV_SUCCESS; 1751 } 1752 1753 /** 1754 * @brief Returns 3-element vector of accelerometer data in body frame 1755 * with gravity removed. 1756 * @param[out] data 3-element vector of accelerometer data in body frame 1757 * with gravity removed. One g = 2^16. 1758 * @return 0 on success or an error code. data unchanged on error. 1759 */ 1760 inv_error_t inv_get_linear_accel(long *data) 1761 { 1762 int kk; 1763 long grav[3]; 1764 long la[3]; 1765 inv_error_t result; 1766 1767 if (data == NULL) 1768 return INV_ERROR_INVALID_PARAMETER; 1769 1770 result = inv_get_gravity(grav); 1771 if (result) { 1772 LOG_RESULT_LOCATION(result); 1773 return result; 1774 } 1775 result = inv_get_accel(la); 1776 if (result) { 1777 LOG_RESULT_LOCATION(result); 1778 return result; 1779 } 1780 1781 if ((fifo_obj.cache & FIFO_CACHE_ACC_BIAS) == 0) { 1782 fifo_obj.cache |= FIFO_CACHE_ACC_BIAS; 1783 1784 for (kk = 0; kk < ACCEL_NUM_AXES; ++kk) { 1785 long x; 1786 x = la[kk] - grav[kk]; 1787 fifo_obj.acc_bias_filt[kk] = (long)(x * fifo_obj.acc_filter_coef + 1788 fifo_obj.acc_bias_filt[kk] * 1789 (1.f - 1790 fifo_obj.acc_filter_coef)); 1791 data[kk] = x - fifo_obj.acc_bias_filt[kk]; 1792 } 1793 } else { 1794 for (kk = 0; kk < ACCEL_NUM_AXES; ++kk) { 1795 data[kk] = la[kk] - grav[kk] - fifo_obj.acc_bias_filt[kk]; 1796 } 1797 } 1798 return INV_SUCCESS; 1799 } 1800 1801 /** 1802 * @brief Returns 3-element vector of accelerometer data in world frame 1803 * with gravity removed. 1804 * @param[out] data 3-element vector of accelerometer data in world frame 1805 * with gravity removed. One g = 2^16. 1806 * @return 0 on success or an error code. 1807 */ 1808 inv_error_t inv_get_linear_accel_in_world(long *data) 1809 { 1810 int kk; 1811 if (data == NULL) 1812 return INV_ERROR_INVALID_PARAMETER; 1813 if (fifo_obj.data_config[CONFIG_ACCEL] && fifo_obj.data_config[CONFIG_QUAT]) { 1814 long wtemp[4], qi[4], wtemp2[4]; 1815 wtemp[0] = 0; 1816 inv_get_linear_accel(&wtemp[1]); 1817 inv_q_mult(&fifo_obj.decoded[REF_QUATERNION], wtemp, wtemp2); 1818 inv_q_invert(&fifo_obj.decoded[REF_QUATERNION], qi); 1819 inv_q_mult(wtemp2, qi, wtemp); 1820 for (kk = 0; kk < 3; ++kk) { 1821 data[kk] = wtemp[kk + 1]; 1822 } 1823 return INV_SUCCESS; 1824 } else { 1825 return INV_ERROR_FEATURE_NOT_ENABLED; 1826 } 1827 } 1828 1829 /** 1830 * @brief Returns 4-element vector of control data. 1831 * @param[out] data 4-element vector of control data. 1832 * @return 0 for succes or an error code. 1833 */ 1834 inv_error_t inv_get_cntrl_data(long *data) 1835 { 1836 int kk; 1837 if (data == NULL) 1838 return INV_ERROR_INVALID_PARAMETER; 1839 1840 if (!fifo_obj.data_config[CONFIG_CONTROL_DATA]) 1841 return INV_ERROR_FEATURE_NOT_ENABLED; 1842 1843 for (kk = 0; kk < 4; ++kk) { 1844 data[kk] = fifo_obj.decoded[REF_CONTROL + kk]; 1845 } 1846 1847 return INV_SUCCESS; 1848 1849 } 1850 1851 /** 1852 * @brief Returns 3-element vector of EIS shfit data 1853 * @param[out] data 3-element vector of EIS shift data. 1854 * @return 0 for succes or an error code. 1855 */ 1856 inv_error_t inv_get_eis(long *data) 1857 { 1858 int kk; 1859 if (data == NULL) 1860 return INV_ERROR_INVALID_PARAMETER; 1861 1862 if (!fifo_obj.data_config[CONFIG_EIS]) 1863 return INV_ERROR_FEATURE_NOT_ENABLED; 1864 1865 for (kk = 0; kk < 3; ++kk) { 1866 data[kk] = fifo_obj.decoded[REF_EIS + kk]; 1867 } 1868 1869 return INV_SUCCESS; 1870 1871 } 1872 1873 /** 1874 * @brief Returns 3-element vector of accelerometer data in body frame. 1875 * @param[out] data 3-element vector of accelerometer data in body frame in g's. 1876 * @return 0 for success or an error code. 1877 */ 1878 inv_error_t inv_get_accel_float(float *data) 1879 { 1880 long lData[3]; 1881 int kk; 1882 int result; 1883 1884 if (data == NULL) 1885 return INV_ERROR_INVALID_PARAMETER; 1886 1887 result = inv_get_accel(lData); 1888 if (result) { 1889 LOG_RESULT_LOCATION(result); 1890 return result; 1891 } 1892 1893 for (kk = 0; kk < ACCEL_NUM_AXES; ++kk) { 1894 data[kk] = lData[kk] / 65536.0f; 1895 } 1896 1897 return INV_SUCCESS; 1898 } 1899 1900 /** 1901 * @brief Returns 4-element quaternion vector. 1902 * @param[out] data 4-element quaternion vector. 1903 * @return 0 on success, an error code otherwise. 1904 */ 1905 inv_error_t inv_get_quaternion_float(float *data) 1906 { 1907 int kk; 1908 1909 if (data == NULL) 1910 return INV_ERROR_INVALID_PARAMETER; 1911 1912 if (!fifo_obj.data_config[CONFIG_QUAT]) 1913 return INV_ERROR_FEATURE_NOT_ENABLED; 1914 1915 for (kk = 0; kk < 4; ++kk) { 1916 data[kk] = fifo_obj.decoded[REF_QUATERNION + kk] / 1073741824.0f; 1917 } 1918 1919 return INV_SUCCESS; 1920 } 1921 1922 /** 1923 * @brief Command the MPU to put data in the FIFO at a particular rate. 1924 * 1925 * The DMP will add fifo entries every fifoRate + 1 MPU cycles. For 1926 * example if the MPU is running at 200Hz the following values apply: 1927 * 1928 * <TABLE> 1929 * <TR><TD>fifoRate</TD><TD>DMP Sample Rate</TD><TD>FIFO update frequency</TD></TR> 1930 * <TR><TD>0</TD><TD>200Hz</TD><TD>200Hz</TD></TR> 1931 * <TR><TD>1</TD><TD>200Hz</TD><TD>100Hz</TD></TR> 1932 * <TR><TD>2</TD><TD>200Hz</TD><TD>50Hz</TD></TR> 1933 * <TR><TD>4</TD><TD>200Hz</TD><TD>40Hz</TD></TR> 1934 * <TR><TD>9</TD><TD>200Hz</TD><TD>20Hz</TD></TR> 1935 * <TR><TD>19</TD><TD>200Hz</TD><TD>10Hz</TD></TR> 1936 * </TABLE> 1937 * 1938 * Note: if the DMP is running, (state == INV_STATE_DMP_STARTED) 1939 * then inv_run_state_callbacks() will be called to allow features 1940 * that depend upon fundamental constants to be updated. 1941 * 1942 * @pre inv_dmp_open() 1943 * @ifnot MPL_MF 1944 * or inv_open_low_power_pedometer() 1945 * or inv_eis_open_dmp() 1946 * @endif 1947 * and inv_dmp_start() 1948 * must <b>NOT</b> have been called. 1949 * 1950 * @param fifoRate Divider value - 1. Output rate is 1951 * (DMP Sample Rate) / (fifoRate + 1). 1952 * 1953 * @return INV_SUCCESS if successful, ML error code on any failure. 1954 */ 1955 inv_error_t inv_set_fifo_rate(unsigned short fifoRate) 1956 { 1957 INVENSENSE_FUNC_START; 1958 unsigned char regs[2]; 1959 unsigned char state; 1960 inv_error_t result = INV_SUCCESS; 1961 struct mldl_cfg *mldl_cfg = inv_get_dl_config(); 1962 1963 state = inv_get_state(); 1964 if (state != INV_STATE_DMP_OPENED && state != INV_STATE_DMP_STARTED) 1965 return INV_ERROR_SM_IMPROPER_STATE; 1966 1967 fifo_obj.fifo_rate = fifoRate; 1968 1969 if (mldl_cfg->requested_sensors & INV_DMP_PROCESSOR) { 1970 1971 regs[0] = (unsigned char)((fifoRate >> 8) & 0xff); 1972 regs[1] = (unsigned char)(fifoRate & 0xff); 1973 1974 result = inv_set_mpu_memory(KEY_D_0_22, 2, regs); 1975 if (result) { 1976 LOG_RESULT_LOCATION(result); 1977 return result; 1978 } 1979 fifo_obj.sample_step_size_ms = 1980 (unsigned short)(((long)fifoRate + 1) * 1981 (inv_mpu_get_sampling_period_us 1982 (mldl_cfg)) / 1000L); 1983 1984 if (state == INV_STATE_DMP_STARTED) 1985 result = inv_run_state_callbacks(state); 1986 } else if (mldl_cfg->requested_sensors & INV_THREE_AXIS_ACCEL) { 1987 struct ext_slave_config config; 1988 long data; 1989 config.key = MPU_SLAVE_CONFIG_ODR_RESUME; 1990 config.len = sizeof(long); 1991 config.apply = (state == INV_STATE_DMP_STARTED); 1992 config.data = &data; 1993 data = (1000 * inv_mpu_get_sampling_rate_hz(mldl_cfg)) / (fifoRate + 1); 1994 1995 /* Ask for the same frequency */ 1996 result = inv_mpu_config_accel(mldl_cfg, 1997 inv_get_serial_handle(), 1998 inv_get_serial_handle(), &config); 1999 if (result) { 2000 LOG_RESULT_LOCATION(result); 2001 return result; 2002 } 2003 result = inv_mpu_get_accel_config(mldl_cfg, 2004 inv_get_serial_handle(), 2005 inv_get_serial_handle(), &config); 2006 if (result) { 2007 LOG_RESULT_LOCATION(result); 2008 return result; 2009 } 2010 if(FIFO_DEBUG) 2011 MPL_LOGI("Actual ODR: %ld Hz\n", data / 1000); 2012 /* Record the actual frequency granted odr is in mHz */ 2013 fifo_obj.sample_step_size_ms = (unsigned short)((1000L * 1000L) / data); 2014 } 2015 return result; 2016 } 2017 2018 /** 2019 * @brief Retrieve the current FIFO update divider - 1. 2020 * See inv_set_fifo_rate() for how this value is used. 2021 * 2022 * The fifo rate when there is no fifo is the equivilent divider when 2023 * derived from the value set by SetSampleSteSizeMs() 2024 * 2025 * @return The value of the fifo rate divider or INV_INVALID_FIFO_RATE on error. 2026 */ 2027 unsigned short inv_get_fifo_rate(void) 2028 { 2029 return fifo_obj.fifo_rate; 2030 } 2031 2032 /** 2033 * @brief Returns the step size for quaternion type data. 2034 * 2035 * Typically the data rate for each FIFO packet. When the gryos are sleeping 2036 * this value will return the last value set by SetSampleStepSizeMs() 2037 * 2038 * @return step size for quaternion type data 2039 */ 2040 int_fast16_t inv_get_sample_step_size_ms(void) 2041 { 2042 struct mldl_cfg *mldl_cfg = inv_get_dl_config(); 2043 2044 if (mldl_cfg->requested_sensors & INV_DMP_PROCESSOR) 2045 return (fifo_obj.fifo_rate + 1) * 2046 (inv_mpu_get_sampling_period_us(mldl_cfg) / 1000); 2047 else 2048 return fifo_obj.sample_step_size_ms; 2049 } 2050 2051 /** 2052 * @brief Returns the step size for quaternion type data. 2053 * 2054 * Typically the data rate for each FIFO packet. When the gryos are sleeping 2055 * this value will return the last value set by SetSampleStepSizeMs() 2056 * 2057 * @return step size for quaternion type data 2058 */ 2059 int_fast16_t inv_get_sample_frequency(void) 2060 { 2061 struct mldl_cfg *mldl_cfg = inv_get_dl_config(); 2062 2063 if (mldl_cfg->requested_sensors & INV_DMP_PROCESSOR) 2064 return (inv_mpu_get_sampling_rate_hz(mldl_cfg) / 2065 (fifo_obj.fifo_rate + 1)); 2066 else 2067 return (1000 / fifo_obj.sample_step_size_ms); 2068 } 2069 2070 /** 2071 * @brief The gyro data magnitude squared : 2072 * (1 degree per second)^2 = 2^6 = 2^GYRO_MAG_SQR_SHIFT. 2073 * @return the computed magnitude squared output of the gyroscope. 2074 */ 2075 unsigned long inv_get_gyro_sum_of_sqr(void) 2076 { 2077 unsigned long gmag = 0; 2078 long temp; 2079 int kk; 2080 2081 for (kk = 0; kk < 3; ++kk) { 2082 temp = fifo_obj.decoded[REF_GYROS + kk] >> 2083 (16 - (GYRO_MAG_SQR_SHIFT / 2)); 2084 gmag += temp * temp; 2085 } 2086 2087 return gmag; 2088 } 2089 2090 /** 2091 * @brief The gyro data magnitude squared: 2092 * (1 g)^2 = 2^16 = 2^ACC_MAG_SQR_SHIFT. 2093 * @return the computed magnitude squared output of the accelerometer. 2094 */ 2095 unsigned long inv_accel_sum_of_sqr(void) 2096 { 2097 unsigned long amag = 0; 2098 long temp; 2099 int kk; 2100 long accel[3]; 2101 inv_error_t result; 2102 2103 result = inv_get_accel(accel); 2104 if (INV_SUCCESS != result) { 2105 return 0; 2106 } 2107 2108 for (kk = 0; kk < 3; ++kk) { 2109 temp = accel[kk] >> (16 - (ACC_MAG_SQR_SHIFT / 2)); 2110 amag += temp * temp; 2111 } 2112 return amag; 2113 } 2114 2115 /** 2116 * @internal 2117 */ 2118 void inv_override_quaternion(float *q) 2119 { 2120 int kk; 2121 for (kk = 0; kk < 4; ++kk) { 2122 fifo_obj.decoded[REF_QUATERNION + kk] = (long)(q[kk] * (1L << 30)); 2123 } 2124 } 2125 2126 /** 2127 * @internal 2128 * @brief This registers a function to be called for each set of 2129 * gyro/quaternion/rotation matrix/etc output. 2130 * @param[in] func The callback function to register 2131 * @param[in] priority The unique priority number of the callback. Lower numbers 2132 * are called first. 2133 * @return error code. 2134 */ 2135 inv_error_t inv_register_fifo_rate_process(inv_obj_func func, int priority) 2136 { 2137 INVENSENSE_FUNC_START; 2138 inv_error_t result; 2139 int kk, nn; 2140 2141 result = inv_lock_mutex(fifo_rate_obj.mutex); 2142 if (INV_SUCCESS != result) { 2143 return result; 2144 } 2145 // Make sure we haven't registered this function already 2146 // Or used the same priority 2147 for (kk = 0; kk < fifo_rate_obj.num_cb; ++kk) { 2148 if ((fifo_rate_obj.fifo_process_cb[kk] == func) || 2149 (fifo_rate_obj.priority[kk] == priority)) { 2150 inv_unlock_mutex(fifo_rate_obj.mutex); 2151 return INV_ERROR_INVALID_PARAMETER; 2152 } 2153 } 2154 2155 // Make sure we have not filled up our number of allowable callbacks 2156 if (fifo_rate_obj.num_cb <= MAX_HIGH_RATE_PROCESSES - 1) { 2157 kk = 0; 2158 if (fifo_rate_obj.num_cb != 0) { 2159 // set kk to be where this new callback goes in the array 2160 while ((kk < fifo_rate_obj.num_cb) && 2161 (fifo_rate_obj.priority[kk] < priority)) { 2162 kk++; 2163 } 2164 if (kk != fifo_rate_obj.num_cb) { 2165 // We need to move the others 2166 for (nn = fifo_rate_obj.num_cb; nn > kk; --nn) { 2167 fifo_rate_obj.fifo_process_cb[nn] = 2168 fifo_rate_obj.fifo_process_cb[nn - 1]; 2169 fifo_rate_obj.priority[nn] = fifo_rate_obj.priority[nn - 1]; 2170 } 2171 } 2172 } 2173 // Add new callback 2174 fifo_rate_obj.fifo_process_cb[kk] = func; 2175 fifo_rate_obj.priority[kk] = priority; 2176 fifo_rate_obj.num_cb++; 2177 } else { 2178 result = INV_ERROR_MEMORY_EXAUSTED; 2179 } 2180 2181 inv_unlock_mutex(fifo_rate_obj.mutex); 2182 return result; 2183 } 2184 2185 /** 2186 * @internal 2187 * @brief This unregisters a function to be called for each set of 2188 * gyro/quaternion/rotation matrix/etc output. 2189 * @return error code. 2190 */ 2191 inv_error_t inv_unregister_fifo_rate_process(inv_obj_func func) 2192 { 2193 INVENSENSE_FUNC_START; 2194 int kk, jj; 2195 inv_error_t result; 2196 2197 result = inv_lock_mutex(fifo_rate_obj.mutex); 2198 if (INV_SUCCESS != result) { 2199 return result; 2200 } 2201 // Make sure we haven't registered this function already 2202 result = INV_ERROR_INVALID_PARAMETER; 2203 for (kk = 0; kk < fifo_rate_obj.num_cb; ++kk) { 2204 if (fifo_rate_obj.fifo_process_cb[kk] == func) { 2205 for (jj = kk + 1; jj < fifo_rate_obj.num_cb; ++jj) { 2206 fifo_rate_obj.fifo_process_cb[jj - 1] = 2207 fifo_rate_obj.fifo_process_cb[jj]; 2208 fifo_rate_obj.priority[jj - 1] = 2209 fifo_rate_obj.priority[jj]; 2210 } 2211 fifo_rate_obj.fifo_process_cb[fifo_rate_obj.num_cb - 1] = NULL; 2212 fifo_rate_obj.priority[fifo_rate_obj.num_cb - 1] = 0; 2213 fifo_rate_obj.num_cb--; 2214 result = INV_SUCCESS; 2215 break; 2216 } 2217 } 2218 2219 inv_unlock_mutex(fifo_rate_obj.mutex); 2220 return result; 2221 2222 } 2223 #ifdef UMPL 2224 bool bFIFIDataAvailable = FALSE; 2225 bool isUmplDataInFIFO(void) 2226 { 2227 return bFIFIDataAvailable; 2228 } 2229 void setUmplDataInFIFOFlag(bool flag) 2230 { 2231 bFIFIDataAvailable = flag; 2232 } 2233 #endif 2234 inv_error_t inv_run_fifo_rate_processes(void) 2235 { 2236 int kk; 2237 inv_error_t result, result2; 2238 2239 result = inv_lock_mutex(fifo_rate_obj.mutex); 2240 if (INV_SUCCESS != result) { 2241 MPL_LOGE("MLOsLockMutex returned %d\n", result); 2242 return result; 2243 } 2244 // User callbacks take priority over the fifo_process_cb callback 2245 if (fifo_obj.fifo_process_cb) 2246 fifo_obj.fifo_process_cb(); 2247 2248 for (kk = 0; kk < fifo_rate_obj.num_cb; ++kk) { 2249 if (fifo_rate_obj.fifo_process_cb[kk]) { 2250 result2 = fifo_rate_obj.fifo_process_cb[kk] (&inv_obj); 2251 if (result == INV_SUCCESS) 2252 #ifdef UMPL 2253 setUmplDataInFIFOFlag(TRUE); 2254 #endif 2255 result = result2; 2256 } 2257 } 2258 2259 inv_unlock_mutex(fifo_rate_obj.mutex); 2260 return result; 2261 } 2262 2263 /*********************/ 2264 /** \}*//* defgroup */ 2265 /*********************/ 2266