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: ml.c 5642 2011-06-14 02:26:20Z mcaramello $ 21 * 22 *****************************************************************************/ 23 24 /** 25 * @defgroup ML 26 * @brief Motion Library APIs. 27 * The Motion Library processes gyroscopes, accelerometers, and 28 * compasses to provide a physical model of the movement for the 29 * sensors. 30 * The results of this processing may be used to control objects 31 * within a user interface environment, detect gestures, track 3D 32 * movement for gaming applications, and analyze the blur created 33 * due to hand movement while taking a picture. 34 * 35 * @{ 36 * @file ml.c 37 * @brief The Motion Library APIs. 38 */ 39 40 /* ------------------ */ 41 /* - Include Files. - */ 42 /* ------------------ */ 43 44 #include <string.h> 45 46 #include "ml.h" 47 #include "mldl.h" 48 #include "mltypes.h" 49 #include "mlinclude.h" 50 #include "compass.h" 51 #include "dmpKey.h" 52 #include "dmpDefault.h" 53 #include "mlstates.h" 54 #include "mlFIFO.h" 55 #include "mlFIFOHW.h" 56 #include "mlMathFunc.h" 57 #include "mlsupervisor.h" 58 #include "mlmath.h" 59 #include "mlcontrol.h" 60 #include "mldl_cfg.h" 61 #include "mpu.h" 62 #include "accel.h" 63 #include "mlos.h" 64 #include "mlsl.h" 65 #include "mlos.h" 66 #include "mlBiasNoMotion.h" 67 #include "log.h" 68 #undef MPL_LOG_TAG 69 #define MPL_LOG_TAG "MPL-ml" 70 71 #define ML_MOT_TYPE_NONE 0 72 #define ML_MOT_TYPE_NO_MOTION 1 73 #define ML_MOT_TYPE_MOTION_DETECTED 2 74 75 #define ML_MOT_STATE_MOVING 0 76 #define ML_MOT_STATE_NO_MOTION 1 77 #define ML_MOT_STATE_BIAS_IN_PROG 2 78 79 #define _mlDebug(x) //{x} 80 81 /* Global Variables */ 82 const unsigned char mlVer[] = { INV_VERSION }; 83 84 struct inv_params_obj inv_params_obj = { 85 INV_BIAS_UPDATE_FUNC_DEFAULT, // bias_mode 86 INV_ORIENTATION_MASK_DEFAULT, // orientation_mask 87 INV_PROCESSED_DATA_CALLBACK_DEFAULT, // fifo_processed_func 88 INV_ORIENTATION_CALLBACK_DEFAULT, // orientation_cb_func 89 INV_MOTION_CALLBACK_DEFAULT, // motion_cb_func 90 INV_STATE_SERIAL_CLOSED // starting state 91 }; 92 93 struct inv_obj_t inv_obj; 94 void *g_mlsl_handle; 95 96 typedef struct { 97 // These describe callbacks happening everythime a DMP interrupt is processed 98 int_fast8_t numInterruptProcesses; 99 // Array of function pointers, function being void function taking void 100 inv_obj_func processInterruptCb[MAX_INTERRUPT_PROCESSES]; 101 102 } tMLXCallbackInterrupt; // MLX_callback_t 103 104 tMLXCallbackInterrupt mlxCallbackInterrupt; 105 106 /* --------------- */ 107 /* - Functions. - */ 108 /* --------------- */ 109 110 inv_error_t inv_freescale_sensor_fusion_16bit(unsigned short orient); 111 inv_error_t inv_freescale_sensor_fusion_8bit(unsigned short orient); 112 unsigned short inv_orientation_matrix_to_scalar(const signed char *mtx); 113 114 /** 115 * @brief Open serial connection with the MPU device. 116 * This is the entry point of the MPL and must be 117 * called prior to any other function call. 118 * 119 * @param port System handle for 'port' MPU device is found on. 120 * The significance of this parameter varies by 121 * platform. It is passed as 'port' to MLSLSerialOpen. 122 * 123 * @return INV_SUCCESS or error code. 124 */ 125 inv_error_t inv_serial_start(char const *port) 126 { 127 INVENSENSE_FUNC_START; 128 inv_error_t result; 129 130 if (inv_get_state() >= INV_STATE_SERIAL_OPENED) 131 return INV_SUCCESS; 132 133 result = inv_state_transition(INV_STATE_SERIAL_OPENED); 134 if (result) { 135 LOG_RESULT_LOCATION(result); 136 return result; 137 } 138 139 result = inv_serial_open(port, &g_mlsl_handle); 140 if (INV_SUCCESS != result) { 141 (void)inv_state_transition(INV_STATE_SERIAL_CLOSED); 142 } 143 144 return result; 145 } 146 147 /** 148 * @brief Close the serial communication. 149 * This function needs to be called explicitly to shut down 150 * the communication with the device. Calling inv_dmp_close() 151 * won't affect the established serial communication. 152 * @return INV_SUCCESS; non-zero error code otherwise. 153 */ 154 inv_error_t inv_serial_stop(void) 155 { 156 INVENSENSE_FUNC_START; 157 inv_error_t result = INV_SUCCESS; 158 159 if (inv_get_state() == INV_STATE_SERIAL_CLOSED) 160 return INV_SUCCESS; 161 162 result = inv_state_transition(INV_STATE_SERIAL_CLOSED); 163 if (INV_SUCCESS != result) { 164 MPL_LOGE("State Transition Failure in %s: %d\n", __func__, result); 165 } 166 result = inv_serial_close(g_mlsl_handle); 167 if (INV_SUCCESS != result) { 168 MPL_LOGE("Unable to close Serial Handle %s: %d\n", __func__, result); 169 } 170 return result; 171 } 172 173 /** 174 * @brief Get the serial file handle to the device. 175 * @return The serial file handle. 176 */ 177 void *inv_get_serial_handle(void) 178 { 179 INVENSENSE_FUNC_START; 180 return g_mlsl_handle; 181 } 182 183 /** 184 * @brief apply the choosen orientation and full scale range 185 * for gyroscopes, accelerometer, and compass. 186 * @return INV_SUCCESS if successful, a non-zero code otherwise. 187 */ 188 inv_error_t inv_apply_calibration(void) 189 { 190 INVENSENSE_FUNC_START; 191 signed char gyroCal[9] = { 0 }; 192 signed char accelCal[9] = { 0 }; 193 signed char magCal[9] = { 0 }; 194 float gyroScale = 2000.f; 195 float accelScale = 0.f; 196 float magScale = 0.f; 197 198 inv_error_t result; 199 int ii; 200 struct mldl_cfg *mldl_cfg = inv_get_dl_config(); 201 202 for (ii = 0; ii < 9; ii++) { 203 gyroCal[ii] = mldl_cfg->pdata->orientation[ii]; 204 if (NULL != mldl_cfg->accel){ 205 accelCal[ii] = mldl_cfg->pdata->accel.orientation[ii]; 206 } 207 if (NULL != mldl_cfg->compass){ 208 magCal[ii] = mldl_cfg->pdata->compass.orientation[ii]; 209 } 210 } 211 212 switch (mldl_cfg->full_scale) { 213 case MPU_FS_250DPS: 214 gyroScale = 250.f; 215 break; 216 case MPU_FS_500DPS: 217 gyroScale = 500.f; 218 break; 219 case MPU_FS_1000DPS: 220 gyroScale = 1000.f; 221 break; 222 case MPU_FS_2000DPS: 223 gyroScale = 2000.f; 224 break; 225 default: 226 MPL_LOGE("Unrecognized full scale setting for gyros : %02X\n", 227 mldl_cfg->full_scale); 228 return INV_ERROR_INVALID_PARAMETER; 229 break; 230 } 231 232 if (NULL != mldl_cfg->accel){ 233 RANGE_FIXEDPOINT_TO_FLOAT(mldl_cfg->accel->range, accelScale); 234 inv_obj.accel_sens = (long)(accelScale * 65536L); 235 /* sensitivity adjustment, typically = 2 (for +/- 2 gee) */ 236 #if defined CONFIG_MPU_SENSORS_MPU6050A2 || \ 237 defined CONFIG_MPU_SENSORS_MPU6050B1 238 inv_obj.accel_sens /= 32768 / mldl_cfg->accel_sens_trim; 239 #else 240 inv_obj.accel_sens /= 2; 241 #endif 242 } 243 if (NULL != mldl_cfg->compass){ 244 RANGE_FIXEDPOINT_TO_FLOAT(mldl_cfg->compass->range, magScale); 245 inv_obj.compass_sens = (long)(magScale * 32768); 246 } 247 248 if (inv_get_state() == INV_STATE_DMP_OPENED) { 249 result = inv_set_gyro_calibration(gyroScale, gyroCal); 250 if (INV_SUCCESS != result) { 251 MPL_LOGE("Unable to set Gyro Calibration\n"); 252 return result; 253 } 254 if (NULL != mldl_cfg->accel){ 255 result = inv_set_accel_calibration(accelScale, accelCal); 256 if (INV_SUCCESS != result) { 257 MPL_LOGE("Unable to set Accel Calibration\n"); 258 return result; 259 } 260 } 261 if (NULL != mldl_cfg->compass){ 262 result = inv_set_compass_calibration(magScale, magCal); 263 if (INV_SUCCESS != result) { 264 MPL_LOGE("Unable to set Mag Calibration\n"); 265 return result; 266 } 267 } 268 } 269 return INV_SUCCESS; 270 } 271 272 /** 273 * @brief Setup the DMP to handle the accelerometer endianess. 274 * @return INV_SUCCESS if successful, a non-zero error code otherwise. 275 */ 276 inv_error_t inv_apply_endian_accel(void) 277 { 278 INVENSENSE_FUNC_START; 279 unsigned char regs[4] = { 0 }; 280 struct mldl_cfg *mldl_cfg = inv_get_dl_config(); 281 int endian = mldl_cfg->accel->endian; 282 283 if (mldl_cfg->pdata->accel.bus != EXT_SLAVE_BUS_SECONDARY) { 284 endian = EXT_SLAVE_BIG_ENDIAN; 285 } 286 switch (endian) { 287 case EXT_SLAVE_FS8_BIG_ENDIAN: 288 case EXT_SLAVE_FS16_BIG_ENDIAN: 289 case EXT_SLAVE_LITTLE_ENDIAN: 290 regs[0] = 0; 291 regs[1] = 64; 292 regs[2] = 0; 293 regs[3] = 0; 294 break; 295 case EXT_SLAVE_BIG_ENDIAN: 296 default: 297 regs[0] = 0; 298 regs[1] = 0; 299 regs[2] = 64; 300 regs[3] = 0; 301 } 302 303 return inv_set_mpu_memory(KEY_D_1_236, 4, regs); 304 } 305 306 /** 307 * @internal 308 * @brief Initialize MLX data. This should be called to setup the mlx 309 * output buffers before any motion processing is done. 310 */ 311 void inv_init_ml(void) 312 { 313 INVENSENSE_FUNC_START; 314 int ii; 315 long tmp[COMPASS_NUM_AXES]; 316 // Set all values to zero by default 317 memset(&inv_obj, 0, sizeof(struct inv_obj_t)); 318 memset(&mlxCallbackInterrupt, 0, sizeof(tMLXCallbackInterrupt)); 319 320 inv_obj.compass_correction[0] = 1073741824L; 321 inv_obj.compass_correction_relative[0] = 1073741824L; 322 inv_obj.compass_disturb_correction[0] = 1073741824L; 323 inv_obj.compass_correction_offset[0] = 1073741824L; 324 inv_obj.relative_quat[0] = 1073741824L; 325 326 //Not used with the ST accelerometer 327 inv_obj.no_motion_threshold = 20; // noMotionThreshold 328 //Not used with the ST accelerometer 329 inv_obj.motion_duration = 1536; // motionDuration 330 331 inv_obj.motion_state = INV_MOTION; // Motion state 332 333 inv_obj.bias_update_time = 8000; 334 inv_obj.bias_calc_time = 2000; 335 336 inv_obj.internal_motion_state = ML_MOT_STATE_MOVING; 337 338 inv_obj.start_time = inv_get_tick_count(); 339 340 inv_obj.compass_cal[0] = 322122560L; 341 inv_obj.compass_cal[4] = 322122560L; 342 inv_obj.compass_cal[8] = 322122560L; 343 inv_obj.compass_sens = 322122560L; // Should only change when the sensor full-scale range (FSR) is changed. 344 345 for (ii = 0; ii < COMPASS_NUM_AXES; ii++) { 346 inv_obj.compass_scale[ii] = 65536L; 347 inv_obj.compass_test_scale[ii] = 65536L; 348 inv_obj.compass_bias_error[ii] = P_INIT; 349 inv_obj.init_compass_bias[ii] = 0; 350 inv_obj.compass_asa[ii] = (1L << 30); 351 } 352 if (inv_compass_read_scale(tmp) == INV_SUCCESS) { 353 for (ii = 0; ii < COMPASS_NUM_AXES; ii++) 354 inv_obj.compass_asa[ii] = tmp[ii]; 355 } 356 inv_obj.got_no_motion_bias = 0; 357 inv_obj.got_compass_bias = 0; 358 inv_obj.compass_state = SF_UNCALIBRATED; 359 inv_obj.acc_state = SF_STARTUP_SETTLE; 360 361 inv_obj.got_init_compass_bias = 0; 362 inv_obj.resetting_compass = 0; 363 364 inv_obj.external_slave_callback = NULL; 365 inv_obj.compass_accuracy = 0; 366 367 inv_obj.factory_temp_comp = 0; 368 inv_obj.got_coarse_heading = 0; 369 370 inv_obj.compass_bias_ptr[0] = P_INIT; 371 inv_obj.compass_bias_ptr[4] = P_INIT; 372 inv_obj.compass_bias_ptr[8] = P_INIT; 373 374 inv_obj.gyro_bias_err = 1310720; 375 376 inv_obj.accel_lpf_gain = 1073744L; 377 inv_obj.no_motion_accel_threshold = 7000000L; 378 } 379 380 /** 381 * @internal 382 * @brief This registers a function to be called for each time the DMP 383 * generates an an interrupt. 384 * It will be called after inv_register_fifo_rate_process() which gets called 385 * every time the FIFO data is processed. 386 * The FIFO does not have to be on for this callback. 387 * @param func Function to be called when a DMP interrupt occurs. 388 * @return INV_SUCCESS or non-zero error code. 389 */ 390 inv_error_t inv_register_dmp_interupt_cb(inv_obj_func func) 391 { 392 INVENSENSE_FUNC_START; 393 // Make sure we have not filled up our number of allowable callbacks 394 if (mlxCallbackInterrupt.numInterruptProcesses <= 395 MAX_INTERRUPT_PROCESSES - 1) { 396 int kk; 397 // Make sure we haven't registered this function already 398 for (kk = 0; kk < mlxCallbackInterrupt.numInterruptProcesses; ++kk) { 399 if (mlxCallbackInterrupt.processInterruptCb[kk] == func) { 400 return INV_ERROR_INVALID_PARAMETER; 401 } 402 } 403 // Add new callback 404 mlxCallbackInterrupt.processInterruptCb[mlxCallbackInterrupt. 405 numInterruptProcesses] = func; 406 mlxCallbackInterrupt.numInterruptProcesses++; 407 return INV_SUCCESS; 408 } 409 return INV_ERROR_MEMORY_EXAUSTED; 410 } 411 412 /** 413 * @internal 414 * @brief This unregisters a function to be called for each DMP interrupt. 415 * @return INV_SUCCESS or non-zero error code. 416 */ 417 inv_error_t inv_unregister_dmp_interupt_cb(inv_obj_func func) 418 { 419 INVENSENSE_FUNC_START; 420 int kk, jj; 421 // Make sure we haven't registered this function already 422 for (kk = 0; kk < mlxCallbackInterrupt.numInterruptProcesses; ++kk) { 423 if (mlxCallbackInterrupt.processInterruptCb[kk] == func) { 424 // FIXME, we may need a thread block here 425 for (jj = kk + 1; jj < mlxCallbackInterrupt.numInterruptProcesses; 426 ++jj) { 427 mlxCallbackInterrupt.processInterruptCb[jj - 1] = 428 mlxCallbackInterrupt.processInterruptCb[jj]; 429 } 430 mlxCallbackInterrupt.numInterruptProcesses--; 431 return INV_SUCCESS; 432 } 433 } 434 return INV_ERROR_INVALID_PARAMETER; 435 } 436 437 /** 438 * @internal 439 * @brief Run the recorded interrupt process callbacks in the event 440 * of an interrupt. 441 */ 442 void inv_run_dmp_interupt_cb(void) 443 { 444 int kk; 445 for (kk = 0; kk < mlxCallbackInterrupt.numInterruptProcesses; ++kk) { 446 if (mlxCallbackInterrupt.processInterruptCb[kk]) 447 mlxCallbackInterrupt.processInterruptCb[kk] (&inv_obj); 448 } 449 } 450 451 /** @internal 452 * Resets the Motion/No Motion state which should be called at startup and resume. 453 */ 454 inv_error_t inv_reset_motion(void) 455 { 456 unsigned char regs[8]; 457 inv_error_t result; 458 459 inv_obj.motion_state = INV_MOTION; 460 inv_obj.flags[INV_MOTION_STATE_CHANGE] = INV_MOTION; 461 inv_obj.no_motion_accel_time = inv_get_tick_count(); 462 #if defined CONFIG_MPU_SENSORS_MPU3050 463 regs[0] = DINAD8 + 2; 464 regs[1] = DINA0C; 465 regs[2] = DINAD8 + 1; 466 result = inv_set_mpu_memory(KEY_CFG_18, 3, regs); 467 if (result) { 468 LOG_RESULT_LOCATION(result); 469 return result; 470 } 471 #else 472 #endif 473 regs[0] = (unsigned char)((inv_obj.motion_duration >> 8) & 0xff); 474 regs[1] = (unsigned char)(inv_obj.motion_duration & 0xff); 475 result = inv_set_mpu_memory(KEY_D_1_106, 2, regs); 476 if (result) { 477 LOG_RESULT_LOCATION(result); 478 return result; 479 } 480 memset(regs, 0, 8); 481 result = inv_set_mpu_memory(KEY_D_1_96, 8, regs); 482 if (result) { 483 LOG_RESULT_LOCATION(result); 484 return result; 485 } 486 487 result = 488 inv_set_mpu_memory(KEY_D_0_96, 4, inv_int32_to_big8(0x40000000, regs)); 489 if (result) { 490 LOG_RESULT_LOCATION(result); 491 return result; 492 } 493 494 inv_set_motion_state(INV_MOTION); 495 return result; 496 } 497 498 /** 499 * @internal 500 * @brief inv_start_bias_calc starts the bias calculation on the MPU. 501 */ 502 void inv_start_bias_calc(void) 503 { 504 INVENSENSE_FUNC_START; 505 506 inv_obj.suspend = 1; 507 } 508 509 /** 510 * @internal 511 * @brief inv_stop_bias_calc stops the bias calculation on the MPU. 512 */ 513 void inv_stop_bias_calc(void) 514 { 515 INVENSENSE_FUNC_START; 516 517 inv_obj.suspend = 0; 518 } 519 520 /** 521 * @brief inv_update_data fetches data from the fifo and updates the 522 * motion algorithms. 523 * 524 * @pre inv_dmp_open() 525 * @ifnot MPL_MF 526 * or inv_open_low_power_pedometer() 527 * or inv_eis_open_dmp() 528 * @endif 529 * and inv_dmp_start() must have been called. 530 * 531 * @note Motion algorithm data is constant between calls to inv_update_data 532 * 533 * @return 534 * - INV_SUCCESS 535 * - Non-zero error code 536 */ 537 inv_error_t inv_update_data(void) 538 { 539 INVENSENSE_FUNC_START; 540 inv_error_t result = INV_SUCCESS; 541 int_fast8_t got, ftry; 542 uint_fast8_t mpu_interrupt; 543 struct mldl_cfg *mldl_cfg = inv_get_dl_config(); 544 545 if (inv_get_state() != INV_STATE_DMP_STARTED) 546 return INV_ERROR_SM_IMPROPER_STATE; 547 548 // Set the maximum number of FIFO packets we want to process 549 if (mldl_cfg->requested_sensors & INV_DMP_PROCESSOR) { 550 ftry = 100; // Large enough to process all packets 551 } else { 552 ftry = 1; 553 } 554 555 // Go and process at most ftry number of packets, probably less than ftry 556 result = inv_read_and_process_fifo(ftry, &got); 557 if (result) { 558 LOG_RESULT_LOCATION(result); 559 return result; 560 } 561 562 // Process all interrupts 563 mpu_interrupt = inv_get_interrupt_trigger(INTSRC_AUX1); 564 if (mpu_interrupt) { 565 inv_clear_interrupt_trigger(INTSRC_AUX1); 566 } 567 // Check if interrupt was from MPU 568 mpu_interrupt = inv_get_interrupt_trigger(INTSRC_MPU); 569 if (mpu_interrupt) { 570 inv_clear_interrupt_trigger(INTSRC_MPU); 571 } 572 // Take care of the callbacks that want to be notified when there was an MPU interrupt 573 if (mpu_interrupt) { 574 inv_run_dmp_interupt_cb(); 575 } 576 577 result = inv_get_fifo_status(); 578 return result; 579 } 580 581 /** 582 * @brief inv_check_flag returns the value of a flag. 583 * inv_check_flag can be used to check a number of flags, 584 * allowing users to poll flags rather than register callback 585 * functions. If a flag is set to True when inv_check_flag is called, 586 * the flag is automatically reset. 587 * The flags are: 588 * - INV_RAW_DATA_READY 589 * Indicates that new raw data is available. 590 * - INV_PROCESSED_DATA_READY 591 * Indicates that new processed data is available. 592 * - INV_GOT_GESTURE 593 * Indicates that a gesture has been detected by the gesture engine. 594 * - INV_MOTION_STATE_CHANGE 595 * Indicates that a change has been made from motion to no motion, 596 * or vice versa. 597 * 598 * @pre inv_dmp_open() 599 * @ifnot MPL_MF 600 * or inv_open_low_power_pedometer() 601 * or inv_eis_open_dmp() 602 * @endif 603 * and inv_dmp_start() must have been called. 604 * 605 * @param flag The flag to check. 606 * 607 * @return TRUE or FALSE state of the flag 608 */ 609 int inv_check_flag(int flag) 610 { 611 INVENSENSE_FUNC_START; 612 int flagReturn = inv_obj.flags[flag]; 613 614 inv_obj.flags[flag] = 0; 615 return flagReturn; 616 } 617 618 /** 619 * @brief Enable generation of the DMP interrupt when Motion or no-motion 620 * is detected 621 * @param on 622 * Boolean to turn the interrupt on or off. 623 * @return INV_SUCCESS or non-zero error code. 624 */ 625 inv_error_t inv_set_motion_interrupt(unsigned char on) 626 { 627 INVENSENSE_FUNC_START; 628 inv_error_t result; 629 unsigned char regs[2] = { 0 }; 630 631 if (inv_get_state() < INV_STATE_DMP_OPENED) 632 return INV_ERROR_SM_IMPROPER_STATE; 633 634 if (on) { 635 result = inv_get_dl_cfg_int(BIT_DMP_INT_EN); 636 if (result) { 637 LOG_RESULT_LOCATION(result); 638 return result; 639 } 640 inv_obj.interrupt_sources |= INV_INT_MOTION; 641 } else { 642 inv_obj.interrupt_sources &= ~INV_INT_MOTION; 643 if (!inv_obj.interrupt_sources) { 644 result = inv_get_dl_cfg_int(0); 645 if (result) { 646 LOG_RESULT_LOCATION(result); 647 return result; 648 } 649 } 650 } 651 652 if (on) { 653 regs[0] = DINAFE; 654 } else { 655 regs[0] = DINAD8; 656 } 657 result = inv_set_mpu_memory(KEY_CFG_7, 1, regs); 658 if (result) { 659 LOG_RESULT_LOCATION(result); 660 return result; 661 } 662 return result; 663 } 664 665 /** 666 * Enable generation of the DMP interrupt when a FIFO packet is ready 667 * 668 * @param on Boolean to turn the interrupt on or off 669 * 670 * @return INV_SUCCESS or non-zero error code 671 */ 672 inv_error_t inv_set_fifo_interrupt(unsigned char on) 673 { 674 INVENSENSE_FUNC_START; 675 inv_error_t result; 676 unsigned char regs[2] = { 0 }; 677 678 if (inv_get_state() < INV_STATE_DMP_OPENED) 679 return INV_ERROR_SM_IMPROPER_STATE; 680 681 if (on) { 682 result = inv_get_dl_cfg_int(BIT_DMP_INT_EN); 683 if (result) { 684 LOG_RESULT_LOCATION(result); 685 return result; 686 } 687 inv_obj.interrupt_sources |= INV_INT_FIFO; 688 } else { 689 inv_obj.interrupt_sources &= ~INV_INT_FIFO; 690 if (!inv_obj.interrupt_sources) { 691 result = inv_get_dl_cfg_int(0); 692 if (result) { 693 LOG_RESULT_LOCATION(result); 694 return result; 695 } 696 } 697 } 698 699 if (on) { 700 regs[0] = DINAFE; 701 } else { 702 regs[0] = DINAD8; 703 } 704 result = inv_set_mpu_memory(KEY_CFG_6, 1, regs); 705 if (result) { 706 LOG_RESULT_LOCATION(result); 707 return result; 708 } 709 return result; 710 } 711 712 /** 713 * @brief Get the current set of DMP interrupt sources. 714 * These interrupts are generated by the DMP and can be 715 * routed to the MPU interrupt line via internal 716 * settings. 717 * 718 * @pre inv_dmp_open() 719 * @ifnot MPL_MF 720 * or inv_open_low_power_pedometer() 721 * or inv_eis_open_dmp() 722 * @endif 723 * must have been called. 724 * 725 * @return Currently enabled interrupt sources. The possible interrupts are: 726 * - INV_INT_FIFO, 727 * - INV_INT_MOTION, 728 * - INV_INT_TAP 729 */ 730 int inv_get_interrupts(void) 731 { 732 INVENSENSE_FUNC_START; 733 734 if (inv_get_state() < INV_STATE_DMP_OPENED) 735 return 0; // error 736 737 return inv_obj.interrupt_sources; 738 } 739 740 /** 741 * @brief Sets up the Accelerometer calibration and scale factor. 742 * 743 * Please refer to the provided "9-Axis Sensor Fusion Application 744 * Note" document provided. Section 5, "Sensor Mounting Orientation" 745 * offers a good coverage on the mounting matrices and explains how 746 * to use them. 747 * 748 * @pre inv_dmp_open() 749 * @ifnot MPL_MF 750 * or inv_open_low_power_pedometer() 751 * or inv_eis_open_dmp() 752 * @endif 753 * must have been called. 754 * @pre inv_dmp_start() must <b>NOT</b> have been called. 755 * 756 * @see inv_set_gyro_calibration(). 757 * @see inv_set_compass_calibration(). 758 * 759 * @param[in] range 760 * The range of the accelerometers in g's. An accelerometer 761 * that has a range of +2g's to -2g's should pass in 2. 762 * @param[in] orientation 763 * A 9 element matrix that represents how the accelerometers 764 * are oriented with respect to the device they are mounted 765 * in and the reference axis system. 766 * A typical set of values are {1, 0, 0, 0, 1, 0, 0, 0, 1}. 767 * This example corresponds to a 3 x 3 identity matrix. 768 * 769 * @return INV_SUCCESS if successful; a non-zero error code otherwise. 770 */ 771 inv_error_t inv_set_accel_calibration(float range, signed char *orientation) 772 { 773 INVENSENSE_FUNC_START; 774 float cal[9]; 775 float scale = range / 32768.f; 776 int kk; 777 unsigned long sf; 778 inv_error_t result; 779 unsigned char regs[4] = { 0, 0, 0, 0 }; 780 struct mldl_cfg *mldl_cfg = inv_get_dl_config(); 781 782 if (inv_get_state() != INV_STATE_DMP_OPENED) 783 return INV_ERROR_SM_IMPROPER_STATE; 784 785 /* Apply zero g-offset values */ 786 if (ACCEL_ID_KXSD9 == mldl_cfg->accel->id) { 787 regs[0] = 0x80; 788 regs[1] = 0x0; 789 regs[2] = 0x80; 790 regs[3] = 0x0; 791 } 792 793 if (inv_dmpkey_supported(KEY_D_1_152)) { 794 result = inv_set_mpu_memory(KEY_D_1_152, 4, ®s[0]); 795 if (result) { 796 LOG_RESULT_LOCATION(result); 797 return result; 798 } 799 } 800 801 if (scale == 0) { 802 inv_obj.accel_sens = 0; 803 } 804 805 if (mldl_cfg->accel->id) { 806 #if defined CONFIG_MPU_SENSORS_MPU6050A2 || \ 807 defined CONFIG_MPU_SENSORS_MPU6050B1 808 unsigned char tmp[3] = { DINA0C, DINAC9, DINA2C }; 809 #else 810 unsigned char tmp[3] = { DINA4C, DINACD, DINA6C }; 811 #endif 812 struct mldl_cfg *mldl_cfg = inv_get_dl_config(); 813 unsigned char regs[3]; 814 unsigned short orient; 815 816 for (kk = 0; kk < 9; ++kk) { 817 cal[kk] = scale * orientation[kk]; 818 inv_obj.accel_cal[kk] = (long)(cal[kk] * (float)(1L << 30)); 819 } 820 821 orient = inv_orientation_matrix_to_scalar(orientation); 822 regs[0] = tmp[orient & 3]; 823 regs[1] = tmp[(orient >> 3) & 3]; 824 regs[2] = tmp[(orient >> 6) & 3]; 825 result = inv_set_mpu_memory(KEY_FCFG_2, 3, regs); 826 if (result) { 827 LOG_RESULT_LOCATION(result); 828 return result; 829 } 830 831 regs[0] = DINA26; 832 regs[1] = DINA46; 833 #if defined CONFIG_MPU_SENSORS_MPU3050 || defined CONFIG_MPU_SENSORS_MPU6050A2 834 regs[2] = DINA66; 835 #else 836 if (MPL_PROD_KEY(mldl_cfg->product_id, mldl_cfg->product_revision) 837 == MPU_PRODUCT_KEY_B1_E1_5) 838 regs[2] = DINA76; 839 else 840 regs[2] = DINA66; 841 #endif 842 if (orient & 4) 843 regs[0] |= 1; 844 if (orient & 0x20) 845 regs[1] |= 1; 846 if (orient & 0x100) 847 regs[2] |= 1; 848 849 result = inv_set_mpu_memory(KEY_FCFG_7, 3, regs); 850 if (result) { 851 LOG_RESULT_LOCATION(result); 852 return result; 853 } 854 855 if (mldl_cfg->accel->id == ACCEL_ID_MMA845X) { 856 result = inv_freescale_sensor_fusion_16bit(orient); 857 if (result) { 858 LOG_RESULT_LOCATION(result); 859 return result; 860 } 861 } else if (mldl_cfg->accel->id == ACCEL_ID_MMA8450) { 862 result = inv_freescale_sensor_fusion_8bit(orient); 863 if (result) { 864 LOG_RESULT_LOCATION(result); 865 return result; 866 } 867 } 868 } 869 870 if (inv_obj.accel_sens != 0) { 871 sf = (1073741824L / inv_obj.accel_sens); 872 } else { 873 sf = 0; 874 } 875 regs[0] = (unsigned char)((sf >> 8) & 0xff); 876 regs[1] = (unsigned char)(sf & 0xff); 877 result = inv_set_mpu_memory(KEY_D_0_108, 2, regs); 878 if (result) { 879 LOG_RESULT_LOCATION(result); 880 return result; 881 } 882 883 return result; 884 } 885 886 /** 887 * @brief Sets up the Gyro calibration and scale factor. 888 * 889 * Please refer to the provided "9-Axis Sensor Fusion Application 890 * Note" document provided. Section 5, "Sensor Mounting Orientation" 891 * offers a good coverage on the mounting matrices and explains 892 * how to use them. 893 * 894 * @pre inv_dmp_open() 895 * @ifnot MPL_MF 896 * or inv_open_low_power_pedometer() 897 * or inv_eis_open_dmp() 898 * @endif 899 * must have been called. 900 * @pre inv_dmp_start() must have <b>NOT</b> been called. 901 * 902 * @see inv_set_accel_calibration(). 903 * @see inv_set_compass_calibration(). 904 * 905 * @param[in] range 906 * The range of the gyros in degrees per second. A gyro 907 * that has a range of +2000 dps to -2000 dps should pass in 908 * 2000. 909 * @param[in] orientation 910 * A 9 element matrix that represents how the gyro are oriented 911 * with respect to the device they are mounted in. A typical 912 * set of values are {1, 0, 0, 0, 1, 0, 0, 0, 1}. This 913 * example corresponds to a 3 x 3 identity matrix. 914 * 915 * @return INV_SUCCESS if successful or Non-zero error code otherwise. 916 */ 917 inv_error_t inv_set_gyro_calibration(float range, signed char *orientation) 918 { 919 INVENSENSE_FUNC_START; 920 921 struct mldl_cfg *mldl_cfg = inv_get_dl_config(); 922 int kk; 923 float scale; 924 inv_error_t result; 925 926 unsigned char regs[12] = { 0 }; 927 unsigned char maxVal = 0; 928 unsigned char tmpPtr = 0; 929 unsigned char tmpSign = 0; 930 unsigned char i = 0; 931 int sf = 0; 932 933 if (inv_get_state() != INV_STATE_DMP_OPENED) 934 return INV_ERROR_SM_IMPROPER_STATE; 935 936 if (mldl_cfg->gyro_sens_trim != 0) { 937 /* adjust the declared range to consider the gyro_sens_trim 938 of this part when different from the default (first dividend) */ 939 range *= (32768.f / 250) / mldl_cfg->gyro_sens_trim; 940 } 941 942 scale = range / 32768.f; // inverse of sensitivity for the given full scale range 943 inv_obj.gyro_sens = (long)(range * 32768L); 944 945 for (kk = 0; kk < 9; ++kk) { 946 inv_obj.gyro_cal[kk] = (long)(scale * orientation[kk] * (1L << 30)); 947 inv_obj.gyro_orient[kk] = (long)((double)orientation[kk] * (1L << 30)); 948 } 949 950 { 951 #if defined CONFIG_MPU_SENSORS_MPU6050A2 || \ 952 defined CONFIG_MPU_SENSORS_MPU6050B1 953 unsigned char tmpD = DINA4C; 954 unsigned char tmpE = DINACD; 955 unsigned char tmpF = DINA6C; 956 #else 957 unsigned char tmpD = DINAC9; 958 unsigned char tmpE = DINA2C; 959 unsigned char tmpF = DINACB; 960 #endif 961 regs[3] = DINA36; 962 regs[4] = DINA56; 963 regs[5] = DINA76; 964 965 for (i = 0; i < 3; i++) { 966 maxVal = 0; 967 tmpSign = 0; 968 if (inv_obj.gyro_orient[0 + 3 * i] < 0) 969 tmpSign = 1; 970 if (ABS(inv_obj.gyro_orient[1 + 3 * i]) > 971 ABS(inv_obj.gyro_orient[0 + 3 * i])) { 972 maxVal = 1; 973 if (inv_obj.gyro_orient[1 + 3 * i] < 0) 974 tmpSign = 1; 975 } 976 if (ABS(inv_obj.gyro_orient[2 + 3 * i]) > 977 ABS(inv_obj.gyro_orient[1 + 3 * i])) { 978 tmpSign = 0; 979 maxVal = 2; 980 if (inv_obj.gyro_orient[2 + 3 * i] < 0) 981 tmpSign = 1; 982 } 983 if (maxVal == 0) { 984 regs[tmpPtr++] = tmpD; 985 if (tmpSign) 986 regs[tmpPtr + 2] |= 0x01; 987 } else if (maxVal == 1) { 988 regs[tmpPtr++] = tmpE; 989 if (tmpSign) 990 regs[tmpPtr + 2] |= 0x01; 991 } else { 992 regs[tmpPtr++] = tmpF; 993 if (tmpSign) 994 regs[tmpPtr + 2] |= 0x01; 995 } 996 } 997 result = inv_set_mpu_memory(KEY_FCFG_1, 3, regs); 998 if (result) { 999 LOG_RESULT_LOCATION(result); 1000 return result; 1001 } 1002 result = inv_set_mpu_memory(KEY_FCFG_3, 3, ®s[3]); 1003 if (result) { 1004 LOG_RESULT_LOCATION(result); 1005 return result; 1006 } 1007 1008 //sf = (gyroSens) * (0.5 * (pi/180) / 200.0) * 16384 1009 inv_obj.gyro_sf = 1010 (long)(((long long)inv_obj.gyro_sens * 767603923LL) / 1073741824LL); 1011 result = 1012 inv_set_mpu_memory(KEY_D_0_104, 4, 1013 inv_int32_to_big8(inv_obj.gyro_sf, regs)); 1014 if (result) { 1015 LOG_RESULT_LOCATION(result); 1016 return result; 1017 } 1018 1019 if (inv_obj.gyro_sens != 0) { 1020 sf = (long)((long long)23832619764371LL / inv_obj.gyro_sens); 1021 } else { 1022 sf = 0; 1023 } 1024 1025 result = inv_set_mpu_memory(KEY_D_0_24, 4, inv_int32_to_big8(sf, regs)); 1026 if (result) { 1027 LOG_RESULT_LOCATION(result); 1028 return result; 1029 } 1030 } 1031 return INV_SUCCESS; 1032 } 1033 1034 /** 1035 * @brief Sets up the Compass calibration and scale factor. 1036 * 1037 * Please refer to the provided "9-Axis Sensor Fusion Application 1038 * Note" document provided. Section 5, "Sensor Mounting Orientation" 1039 * offers a good coverage on the mounting matrices and explains 1040 * how to use them. 1041 * 1042 * @pre inv_dmp_open() 1043 * @ifnot MPL_MF 1044 * or inv_open_low_power_pedometer() 1045 * or inv_eis_open_dmp() 1046 * @endif 1047 * must have been called. 1048 * @pre inv_dmp_start() must have <b>NOT</b> been called. 1049 * 1050 * @see inv_set_gyro_calibration(). 1051 * @see inv_set_accel_calibration(). 1052 * 1053 * @param[in] range 1054 * The range of the compass. 1055 * @param[in] orientation 1056 * A 9 element matrix that represents how the compass is 1057 * oriented with respect to the device they are mounted in. 1058 * A typical set of values are {1, 0, 0, 0, 1, 0, 0, 0, 1}. 1059 * This example corresponds to a 3 x 3 identity matrix. 1060 * The matrix describes how to go from the chip mounting to 1061 * the body of the device. 1062 * 1063 * @return INV_SUCCESS if successful or Non-zero error code otherwise. 1064 */ 1065 inv_error_t inv_set_compass_calibration(float range, signed char *orientation) 1066 { 1067 INVENSENSE_FUNC_START; 1068 float cal[9]; 1069 float scale = range / 32768.f; 1070 int kk; 1071 unsigned short compassId = 0; 1072 1073 compassId = inv_get_compass_id(); 1074 1075 if ((compassId == COMPASS_ID_YAS529) || (compassId == COMPASS_ID_HMC5883) 1076 || (compassId == COMPASS_ID_LSM303M)) { 1077 scale /= 32.0f; 1078 } 1079 1080 for (kk = 0; kk < 9; ++kk) { 1081 cal[kk] = scale * orientation[kk]; 1082 inv_obj.compass_cal[kk] = (long)(cal[kk] * (float)(1L << 30)); 1083 } 1084 1085 inv_obj.compass_sens = (long)(scale * 1073741824L); 1086 1087 if (inv_dmpkey_supported(KEY_CPASS_MTX_00)) { 1088 unsigned char reg0[4] = { 0, 0, 0, 0 }; 1089 unsigned char regp[4] = { 64, 0, 0, 0 }; 1090 unsigned char regn[4] = { 64 + 128, 0, 0, 0 }; 1091 unsigned char *reg; 1092 int_fast8_t kk; 1093 unsigned short keyList[9] = 1094 { KEY_CPASS_MTX_00, KEY_CPASS_MTX_01, KEY_CPASS_MTX_02, 1095 KEY_CPASS_MTX_10, KEY_CPASS_MTX_11, KEY_CPASS_MTX_12, 1096 KEY_CPASS_MTX_20, KEY_CPASS_MTX_21, KEY_CPASS_MTX_22 1097 }; 1098 1099 for (kk = 0; kk < 9; ++kk) { 1100 1101 if (orientation[kk] == 1) 1102 reg = regp; 1103 else if (orientation[kk] == -1) 1104 reg = regn; 1105 else 1106 reg = reg0; 1107 inv_set_mpu_memory(keyList[kk], 4, reg); 1108 } 1109 } 1110 1111 return INV_SUCCESS; 1112 } 1113 1114 /** 1115 * @internal 1116 * @brief Sets the Gyro Dead Zone based upon LPF filter settings and Control setup. 1117 */ 1118 inv_error_t inv_set_dead_zone(void) 1119 { 1120 unsigned char reg; 1121 inv_error_t result; 1122 extern struct control_params cntrl_params; 1123 1124 if (cntrl_params.functions & INV_DEAD_ZONE) { 1125 reg = 0x08; 1126 } else { 1127 #if defined CONFIG_MPU_SENSORS_MPU6050A2 || \ 1128 defined CONFIG_MPU_SENSORS_MPU6050B1 1129 reg = 0; 1130 #else 1131 if (inv_params_obj.bias_mode & INV_BIAS_FROM_LPF) { 1132 reg = 0x2; 1133 } else { 1134 reg = 0; 1135 } 1136 #endif 1137 } 1138 1139 result = inv_set_mpu_memory(KEY_D_0_163, 1, ®); 1140 if (result) { 1141 LOG_RESULT_LOCATION(result); 1142 return result; 1143 } 1144 return result; 1145 } 1146 1147 /** 1148 * @brief inv_set_bias_update is used to register which algorithms will be 1149 * used to automatically reset the gyroscope bias. 1150 * The engine INV_BIAS_UPDATE must be enabled for these algorithms to 1151 * run. 1152 * 1153 * @pre inv_dmp_open() 1154 * @ifnot MPL_MF 1155 * or inv_open_low_power_pedometer() 1156 * or inv_eis_open_dmp() 1157 * @endif 1158 * and inv_dmp_start() 1159 * must <b>NOT</b> have been called. 1160 * 1161 * @param function A function or bitwise OR of functions that determine 1162 * how the gyroscope bias will be automatically updated. 1163 * Functions include: 1164 * - INV_NONE or 0, 1165 * - INV_BIAS_FROM_NO_MOTION, 1166 * - INV_BIAS_FROM_GRAVITY, 1167 * - INV_BIAS_FROM_TEMPERATURE, 1168 \ifnot UMPL 1169 * - INV_BIAS_FROM_LPF, 1170 * - INV_MAG_BIAS_FROM_MOTION, 1171 * - INV_MAG_BIAS_FROM_GYRO, 1172 * - INV_ALL. 1173 * \endif 1174 * @return INV_SUCCESS if successful or Non-zero error code otherwise. 1175 */ 1176 inv_error_t inv_set_bias_update(unsigned short function) 1177 { 1178 INVENSENSE_FUNC_START; 1179 unsigned char regs[4]; 1180 long tmp[3] = { 0, 0, 0 }; 1181 inv_error_t result = INV_SUCCESS; 1182 struct mldl_cfg *mldl_cfg = inv_get_dl_config(); 1183 1184 if (inv_get_state() != INV_STATE_DMP_OPENED) 1185 return INV_ERROR_SM_IMPROPER_STATE; 1186 1187 /* do not allow progressive no motion bias tracker to run - 1188 it's not fully debugged */ 1189 function &= ~INV_PROGRESSIVE_NO_MOTION; // FIXME, workaround 1190 MPL_LOGV("forcing disable of PROGRESSIVE_NO_MOTION bias tracker\n"); 1191 1192 // You must use EnableFastNoMotion() to get this feature 1193 function &= ~INV_BIAS_FROM_FAST_NO_MOTION; 1194 1195 // You must use DisableFastNoMotion() to turn this feature off 1196 if (inv_params_obj.bias_mode & INV_BIAS_FROM_FAST_NO_MOTION) 1197 function |= INV_BIAS_FROM_FAST_NO_MOTION; 1198 1199 /*--- remove magnetic components from bias tracking 1200 if there is no compass ---*/ 1201 if (!inv_compass_present()) { 1202 function &= ~(INV_MAG_BIAS_FROM_GYRO | INV_MAG_BIAS_FROM_MOTION); 1203 } else { 1204 function &= ~(INV_BIAS_FROM_LPF); 1205 } 1206 1207 // Enable function sets bias from no motion 1208 inv_params_obj.bias_mode = function & (~INV_BIAS_FROM_NO_MOTION); 1209 1210 if (function & INV_BIAS_FROM_NO_MOTION) { 1211 inv_enable_bias_no_motion(); 1212 } else { 1213 inv_disable_bias_no_motion(); 1214 } 1215 1216 if (inv_params_obj.bias_mode & INV_BIAS_FROM_LPF) { 1217 regs[0] = DINA80 + 2; 1218 regs[1] = DINA2D; 1219 regs[2] = DINA55; 1220 regs[3] = DINA7D; 1221 } else { 1222 regs[0] = DINA80 + 7; 1223 regs[1] = DINA2D; 1224 regs[2] = DINA35; 1225 regs[3] = DINA3D; 1226 } 1227 result = inv_set_mpu_memory(KEY_FCFG_5, 4, regs); 1228 if (result) { 1229 LOG_RESULT_LOCATION(result); 1230 return result; 1231 } 1232 result = inv_set_dead_zone(); 1233 if (result) { 1234 LOG_RESULT_LOCATION(result); 1235 return result; 1236 } 1237 1238 if ((inv_params_obj.bias_mode & INV_BIAS_FROM_GRAVITY) && 1239 !inv_compass_present()) { 1240 result = inv_set_gyro_data_source(INV_GYRO_FROM_QUATERNION); 1241 if (result) { 1242 LOG_RESULT_LOCATION(result); 1243 return result; 1244 } 1245 } else { 1246 result = inv_set_gyro_data_source(INV_GYRO_FROM_RAW); 1247 if (result) { 1248 LOG_RESULT_LOCATION(result); 1249 return result; 1250 } 1251 } 1252 1253 inv_obj.factory_temp_comp = 0; // FIXME, workaround 1254 if ((mldl_cfg->offset_tc[0] != 0) || 1255 (mldl_cfg->offset_tc[1] != 0) || (mldl_cfg->offset_tc[2] != 0)) { 1256 inv_obj.factory_temp_comp = 1; 1257 } 1258 1259 if (inv_obj.factory_temp_comp == 0) { 1260 if (inv_params_obj.bias_mode & INV_BIAS_FROM_TEMPERATURE) { 1261 result = inv_set_gyro_temp_slope(inv_obj.temp_slope); 1262 if (result) { 1263 LOG_RESULT_LOCATION(result); 1264 return result; 1265 } 1266 } else { 1267 result = inv_set_gyro_temp_slope(tmp); 1268 if (result) { 1269 LOG_RESULT_LOCATION(result); 1270 return result; 1271 } 1272 } 1273 } else { 1274 inv_params_obj.bias_mode &= ~INV_LEARN_BIAS_FROM_TEMPERATURE; 1275 MPL_LOGV("factory temperature compensation coefficients available - " 1276 "disabling INV_LEARN_BIAS_FROM_TEMPERATURE\n"); 1277 } 1278 1279 /*---- hard requirement for using bias tracking BIAS_FROM_GRAVITY, relying on 1280 compass and accel data, is to have accelerometer data delivered in the 1281 FIFO ----*/ 1282 if (((inv_params_obj.bias_mode & INV_BIAS_FROM_GRAVITY) 1283 && inv_compass_present()) 1284 || (inv_params_obj.bias_mode & INV_MAG_BIAS_FROM_GYRO) 1285 || (inv_params_obj.bias_mode & INV_MAG_BIAS_FROM_MOTION)) { 1286 inv_send_accel(INV_ALL, INV_32_BIT); 1287 inv_send_gyro(INV_ALL, INV_32_BIT); 1288 } 1289 1290 return result; 1291 } 1292 1293 /** 1294 * @brief inv_get_motion_state is used to determine if the device is in 1295 * a 'motion' or 'no motion' state. 1296 * inv_get_motion_state returns INV_MOTION of the device is moving, 1297 * or INV_NO_MOTION if the device is not moving. 1298 * 1299 * @pre inv_dmp_open() 1300 * @ifnot MPL_MF 1301 * or inv_open_low_power_pedometer() 1302 * or inv_eis_open_dmp() 1303 * @endif 1304 * and inv_dmp_start() 1305 * must have been called. 1306 * 1307 * @return INV_SUCCESS if successful or Non-zero error code otherwise. 1308 */ 1309 int inv_get_motion_state(void) 1310 { 1311 INVENSENSE_FUNC_START; 1312 return inv_obj.motion_state; 1313 } 1314 1315 /** 1316 * @brief inv_set_no_motion_thresh is used to set the threshold for 1317 * detecting INV_NO_MOTION 1318 * 1319 * @pre inv_dmp_open() 1320 * @ifnot MPL_MF 1321 * or inv_open_low_power_pedometer() 1322 * or inv_eis_open_dmp() 1323 * @endif 1324 * must have been called. 1325 * 1326 * @param thresh A threshold scaled in degrees per second. 1327 * 1328 * @return INV_SUCCESS if successful or Non-zero error code otherwise. 1329 */ 1330 inv_error_t inv_set_no_motion_thresh(float thresh) 1331 { 1332 inv_error_t result = INV_SUCCESS; 1333 unsigned char regs[4] = { 0 }; 1334 long tmp; 1335 INVENSENSE_FUNC_START; 1336 1337 tmp = (long)(thresh * thresh * 2.045f); 1338 if (tmp < 0) { 1339 return INV_ERROR; 1340 } else if (tmp > 8180000L) { 1341 return INV_ERROR; 1342 } 1343 inv_obj.no_motion_threshold = tmp; 1344 1345 regs[0] = (unsigned char)(tmp >> 24); 1346 regs[1] = (unsigned char)((tmp >> 16) & 0xff); 1347 regs[2] = (unsigned char)((tmp >> 8) & 0xff); 1348 regs[3] = (unsigned char)(tmp & 0xff); 1349 1350 result = inv_set_mpu_memory(KEY_D_1_108, 4, regs); 1351 if (result) { 1352 LOG_RESULT_LOCATION(result); 1353 return result; 1354 } 1355 result = inv_reset_motion(); 1356 return result; 1357 } 1358 1359 /** 1360 * @brief inv_set_no_motion_threshAccel is used to set the threshold for 1361 * detecting INV_NO_MOTION with accelerometers when Gyros have 1362 * been turned off 1363 * 1364 * @pre inv_dmp_open() 1365 * @ifnot MPL_MF 1366 * or inv_open_low_power_pedometer() 1367 * or inv_eis_open_dmp() 1368 * @endif 1369 * must have been called. 1370 * 1371 * @param thresh A threshold in g's scaled by 2^32 1372 * 1373 * @return INV_SUCCESS if successful or Non-zero error code otherwise. 1374 */ 1375 inv_error_t inv_set_no_motion_threshAccel(long thresh) 1376 { 1377 INVENSENSE_FUNC_START; 1378 1379 inv_obj.no_motion_accel_threshold = thresh; 1380 1381 return INV_SUCCESS; 1382 } 1383 1384 /** 1385 * @brief inv_set_no_motion_time is used to set the time required for 1386 * detecting INV_NO_MOTION 1387 * 1388 * @pre inv_dmp_open() 1389 * @ifnot MPL_MF 1390 * or inv_open_low_power_pedometer() 1391 * or inv_eis_open_dmp() 1392 * @endif 1393 * must have been called. 1394 * 1395 * @param time A time in seconds. 1396 * 1397 * @return INV_SUCCESS if successful or Non-zero error code otherwise. 1398 */ 1399 inv_error_t inv_set_no_motion_time(float time) 1400 { 1401 inv_error_t result = INV_SUCCESS; 1402 unsigned char regs[2] = { 0 }; 1403 long tmp; 1404 1405 INVENSENSE_FUNC_START; 1406 1407 tmp = (long)(time * 200); 1408 if (tmp < 0) { 1409 return INV_ERROR; 1410 } else if (tmp > 65535L) { 1411 return INV_ERROR; 1412 } 1413 inv_obj.motion_duration = (unsigned short)tmp; 1414 1415 regs[0] = (unsigned char)((inv_obj.motion_duration >> 8) & 0xff); 1416 regs[1] = (unsigned char)(inv_obj.motion_duration & 0xff); 1417 result = inv_set_mpu_memory(KEY_D_1_106, 2, regs); 1418 if (result) { 1419 LOG_RESULT_LOCATION(result); 1420 return result; 1421 } 1422 result = inv_reset_motion(); 1423 return result; 1424 } 1425 1426 /** 1427 * @brief inv_get_version is used to get the ML version. 1428 * 1429 * @pre inv_get_version can be called at any time. 1430 * 1431 * @param version inv_get_version writes the ML version 1432 * string pointer to version. 1433 * 1434 * @return INV_SUCCESS if successful or Non-zero error code otherwise. 1435 */ 1436 inv_error_t inv_get_version(unsigned char **version) 1437 { 1438 INVENSENSE_FUNC_START; 1439 1440 *version = (unsigned char *)mlVer; //fixme we are wiping const 1441 1442 return INV_SUCCESS; 1443 } 1444 1445 /** 1446 * @brief Check for the presence of the gyro sensor. 1447 * 1448 * This is not a physical check but a logical check and the value can change 1449 * dynamically based on calls to inv_set_mpu_sensors(). 1450 * 1451 * @return TRUE if the gyro is enabled FALSE otherwise. 1452 */ 1453 int inv_get_gyro_present(void) 1454 { 1455 return inv_get_dl_config()->requested_sensors & (INV_X_GYRO | INV_Y_GYRO | 1456 INV_Z_GYRO); 1457 } 1458 1459 static unsigned short inv_row_2_scale(const signed char *row) 1460 { 1461 unsigned short b; 1462 1463 if (row[0] > 0) 1464 b = 0; 1465 else if (row[0] < 0) 1466 b = 4; 1467 else if (row[1] > 0) 1468 b = 1; 1469 else if (row[1] < 0) 1470 b = 5; 1471 else if (row[2] > 0) 1472 b = 2; 1473 else if (row[2] < 0) 1474 b = 6; 1475 else 1476 b = 7; // error 1477 return b; 1478 } 1479 1480 unsigned short inv_orientation_matrix_to_scalar(const signed char *mtx) 1481 { 1482 unsigned short scalar; 1483 /* 1484 XYZ 010_001_000 Identity Matrix 1485 XZY 001_010_000 1486 YXZ 010_000_001 1487 YZX 000_010_001 1488 ZXY 001_000_010 1489 ZYX 000_001_010 1490 */ 1491 1492 scalar = inv_row_2_scale(mtx); 1493 scalar |= inv_row_2_scale(mtx + 3) << 3; 1494 scalar |= inv_row_2_scale(mtx + 6) << 6; 1495 1496 return scalar; 1497 } 1498 1499 /* Setups up the Freescale 16-bit accel for Sensor Fusion 1500 * @param[in] orient A scalar representation of the orientation 1501 * that describes how to go from the Chip Orientation 1502 * to the Board Orientation often times called the Body Orientation in Invensense Documentation. 1503 * inv_orientation_matrix_to_scalar() will turn the transformation matrix into this scalar. 1504 */ 1505 inv_error_t inv_freescale_sensor_fusion_16bit(unsigned short orient) 1506 { 1507 unsigned char rr[3]; 1508 inv_error_t result; 1509 1510 orient = orient & 0xdb; 1511 switch (orient) { 1512 default: 1513 // Typically 0x88 1514 rr[0] = DINACC; 1515 rr[1] = DINACF; 1516 rr[2] = DINA0E; 1517 break; 1518 case 0x50: 1519 rr[0] = DINACE; 1520 rr[1] = DINA0E; 1521 rr[2] = DINACD; 1522 break; 1523 case 0x81: 1524 rr[0] = DINACE; 1525 rr[1] = DINACB; 1526 rr[2] = DINA0E; 1527 break; 1528 case 0x11: 1529 rr[0] = DINACC; 1530 rr[1] = DINA0E; 1531 rr[2] = DINACB; 1532 break; 1533 case 0x42: 1534 rr[0] = DINA0A; 1535 rr[1] = DINACF; 1536 rr[2] = DINACB; 1537 break; 1538 case 0x0a: 1539 rr[0] = DINA0A; 1540 rr[1] = DINACB; 1541 rr[2] = DINACD; 1542 break; 1543 } 1544 result = inv_set_mpu_memory(KEY_FCFG_AZ, 3, rr); 1545 return result; 1546 } 1547 1548 /* Setups up the Freescale 8-bit accel for Sensor Fusion 1549 * @param[in] orient A scalar representation of the orientation 1550 * that describes how to go from the Chip Orientation 1551 * to the Board Orientation often times called the Body Orientation in Invensense Documentation. 1552 * inv_orientation_matrix_to_scalar() will turn the transformation matrix into this scalar. 1553 */ 1554 inv_error_t inv_freescale_sensor_fusion_8bit(unsigned short orient) 1555 { 1556 unsigned char regs[27]; 1557 inv_error_t result; 1558 uint_fast8_t kk; 1559 1560 orient = orient & 0xdb; 1561 kk = 0; 1562 1563 regs[kk++] = DINAC3; 1564 regs[kk++] = DINA90 + 14; 1565 regs[kk++] = DINAA0 + 9; 1566 regs[kk++] = DINA3E; 1567 regs[kk++] = DINA5E; 1568 regs[kk++] = DINA7E; 1569 1570 regs[kk++] = DINAC2; 1571 regs[kk++] = DINAA0 + 9; 1572 regs[kk++] = DINA90 + 9; 1573 regs[kk++] = DINAF8 + 2; 1574 1575 switch (orient) { 1576 default: 1577 // Typically 0x88 1578 regs[kk++] = DINACB; 1579 1580 regs[kk++] = DINA54; 1581 regs[kk++] = DINA50; 1582 regs[kk++] = DINA50; 1583 regs[kk++] = DINA50; 1584 regs[kk++] = DINA50; 1585 regs[kk++] = DINA50; 1586 regs[kk++] = DINA50; 1587 regs[kk++] = DINA50; 1588 1589 regs[kk++] = DINACD; 1590 break; 1591 case 0x50: 1592 regs[kk++] = DINACB; 1593 1594 regs[kk++] = DINACF; 1595 1596 regs[kk++] = DINA7C; 1597 regs[kk++] = DINA78; 1598 regs[kk++] = DINA78; 1599 regs[kk++] = DINA78; 1600 regs[kk++] = DINA78; 1601 regs[kk++] = DINA78; 1602 regs[kk++] = DINA78; 1603 regs[kk++] = DINA78; 1604 break; 1605 case 0x81: 1606 regs[kk++] = DINA2C; 1607 regs[kk++] = DINA28; 1608 regs[kk++] = DINA28; 1609 regs[kk++] = DINA28; 1610 regs[kk++] = DINA28; 1611 regs[kk++] = DINA28; 1612 regs[kk++] = DINA28; 1613 regs[kk++] = DINA28; 1614 1615 regs[kk++] = DINACD; 1616 1617 regs[kk++] = DINACB; 1618 break; 1619 case 0x11: 1620 regs[kk++] = DINA2C; 1621 regs[kk++] = DINA28; 1622 regs[kk++] = DINA28; 1623 regs[kk++] = DINA28; 1624 regs[kk++] = DINA28; 1625 regs[kk++] = DINA28; 1626 regs[kk++] = DINA28; 1627 regs[kk++] = DINA28; 1628 regs[kk++] = DINACB; 1629 regs[kk++] = DINACF; 1630 break; 1631 case 0x42: 1632 regs[kk++] = DINACF; 1633 regs[kk++] = DINACD; 1634 1635 regs[kk++] = DINA7C; 1636 regs[kk++] = DINA78; 1637 regs[kk++] = DINA78; 1638 regs[kk++] = DINA78; 1639 regs[kk++] = DINA78; 1640 regs[kk++] = DINA78; 1641 regs[kk++] = DINA78; 1642 regs[kk++] = DINA78; 1643 break; 1644 case 0x0a: 1645 regs[kk++] = DINACD; 1646 1647 regs[kk++] = DINA54; 1648 regs[kk++] = DINA50; 1649 regs[kk++] = DINA50; 1650 regs[kk++] = DINA50; 1651 regs[kk++] = DINA50; 1652 regs[kk++] = DINA50; 1653 regs[kk++] = DINA50; 1654 regs[kk++] = DINA50; 1655 1656 regs[kk++] = DINACF; 1657 break; 1658 } 1659 1660 regs[kk++] = DINA90 + 7; 1661 regs[kk++] = DINAF8 + 3; 1662 regs[kk++] = DINAA0 + 9; 1663 regs[kk++] = DINA0E; 1664 regs[kk++] = DINA0E; 1665 regs[kk++] = DINA0E; 1666 1667 regs[kk++] = DINAF8 + 1; // filler 1668 1669 result = inv_set_mpu_memory(KEY_FCFG_FSCALE, kk, regs); 1670 if (result) { 1671 LOG_RESULT_LOCATION(result); 1672 return result; 1673 } 1674 1675 return result; 1676 } 1677 1678 /** 1679 * Controlls each sensor and each axis when the motion processing unit is 1680 * running. When it is not running, simply records the state for later. 1681 * 1682 * NOTE: In this version only full sensors controll is allowed. Independent 1683 * axis control will return an error. 1684 * 1685 * @param sensors Bit field of each axis desired to be turned on or off 1686 * 1687 * @return INV_SUCCESS or non-zero error code 1688 */ 1689 inv_error_t inv_set_mpu_sensors(unsigned long sensors) 1690 { 1691 INVENSENSE_FUNC_START; 1692 unsigned char state = inv_get_state(); 1693 struct mldl_cfg *mldl_cfg = inv_get_dl_config(); 1694 inv_error_t result = INV_SUCCESS; 1695 unsigned short fifoRate; 1696 1697 if (state < INV_STATE_DMP_OPENED) 1698 return INV_ERROR_SM_IMPROPER_STATE; 1699 1700 if (((sensors & INV_THREE_AXIS_ACCEL) != INV_THREE_AXIS_ACCEL) && 1701 ((sensors & INV_THREE_AXIS_ACCEL) != 0)) { 1702 return INV_ERROR_FEATURE_NOT_IMPLEMENTED; 1703 } 1704 if (((sensors & INV_THREE_AXIS_ACCEL) != 0) && 1705 (mldl_cfg->pdata->accel.get_slave_descr == 0)) { 1706 return INV_ERROR_SERIAL_DEVICE_NOT_RECOGNIZED; 1707 } 1708 1709 if (((sensors & INV_THREE_AXIS_COMPASS) != INV_THREE_AXIS_COMPASS) && 1710 ((sensors & INV_THREE_AXIS_COMPASS) != 0)) { 1711 return INV_ERROR_FEATURE_NOT_IMPLEMENTED; 1712 } 1713 if (((sensors & INV_THREE_AXIS_COMPASS) != 0) && 1714 (mldl_cfg->pdata->compass.get_slave_descr == 0)) { 1715 return INV_ERROR_SERIAL_DEVICE_NOT_RECOGNIZED; 1716 } 1717 1718 if (((sensors & INV_THREE_AXIS_PRESSURE) != INV_THREE_AXIS_PRESSURE) && 1719 ((sensors & INV_THREE_AXIS_PRESSURE) != 0)) { 1720 return INV_ERROR_FEATURE_NOT_IMPLEMENTED; 1721 } 1722 if (((sensors & INV_THREE_AXIS_PRESSURE) != 0) && 1723 (mldl_cfg->pdata->pressure.get_slave_descr == 0)) { 1724 return INV_ERROR_SERIAL_DEVICE_NOT_RECOGNIZED; 1725 } 1726 1727 /* DMP was off, and is turning on */ 1728 if (sensors & INV_DMP_PROCESSOR && 1729 !(mldl_cfg->requested_sensors & INV_DMP_PROCESSOR)) { 1730 struct ext_slave_config config; 1731 long odr; 1732 config.key = MPU_SLAVE_CONFIG_ODR_RESUME; 1733 config.len = sizeof(long); 1734 config.apply = (state == INV_STATE_DMP_STARTED); 1735 config.data = &odr; 1736 1737 odr = (inv_mpu_get_sampling_rate_hz(mldl_cfg) * 1000); 1738 result = inv_mpu_config_accel(mldl_cfg, 1739 inv_get_serial_handle(), 1740 inv_get_serial_handle(), &config); 1741 if (result) { 1742 LOG_RESULT_LOCATION(result); 1743 return result; 1744 } 1745 1746 config.key = MPU_SLAVE_CONFIG_IRQ_RESUME; 1747 odr = MPU_SLAVE_IRQ_TYPE_NONE; 1748 result = inv_mpu_config_accel(mldl_cfg, 1749 inv_get_serial_handle(), 1750 inv_get_serial_handle(), &config); 1751 if (result) { 1752 LOG_RESULT_LOCATION(result); 1753 return result; 1754 } 1755 inv_init_fifo_hardare(); 1756 } 1757 1758 if (inv_obj.mode_change_func) { 1759 result = inv_obj.mode_change_func(mldl_cfg->requested_sensors, sensors); 1760 if (result) { 1761 LOG_RESULT_LOCATION(result); 1762 return result; 1763 } 1764 } 1765 1766 /* Get the fifo rate before changing sensors so if we need to match it */ 1767 fifoRate = inv_get_fifo_rate(); 1768 mldl_cfg->requested_sensors = sensors; 1769 1770 /* inv_dmp_start will turn the sensors on */ 1771 if (state == INV_STATE_DMP_STARTED) { 1772 result = inv_dl_start(sensors); 1773 if (result) { 1774 LOG_RESULT_LOCATION(result); 1775 return result; 1776 } 1777 result = inv_reset_motion(); 1778 if (result) { 1779 LOG_RESULT_LOCATION(result); 1780 return result; 1781 } 1782 result = inv_dl_stop(~sensors); 1783 if (result) { 1784 LOG_RESULT_LOCATION(result); 1785 return result; 1786 } 1787 } 1788 1789 inv_set_fifo_rate(fifoRate); 1790 1791 if (!(sensors & INV_DMP_PROCESSOR) && (sensors & INV_THREE_AXIS_ACCEL)) { 1792 struct ext_slave_config config; 1793 long data; 1794 1795 config.len = sizeof(long); 1796 config.key = MPU_SLAVE_CONFIG_IRQ_RESUME; 1797 config.apply = (state == INV_STATE_DMP_STARTED); 1798 config.data = &data; 1799 data = MPU_SLAVE_IRQ_TYPE_DATA_READY; 1800 result = inv_mpu_config_accel(mldl_cfg, 1801 inv_get_serial_handle(), 1802 inv_get_serial_handle(), &config); 1803 if (result) { 1804 LOG_RESULT_LOCATION(result); 1805 return result; 1806 } 1807 } 1808 1809 return result; 1810 } 1811 1812 void inv_set_mode_change(inv_error_t(*mode_change_func) 1813 (unsigned long, unsigned long)) 1814 { 1815 inv_obj.mode_change_func = mode_change_func; 1816 } 1817 1818 /** 1819 * Mantis setup 1820 */ 1821 #ifdef CONFIG_MPU_SENSORS_MPU6050B1 1822 inv_error_t inv_set_mpu_6050_config() 1823 { 1824 long temp; 1825 inv_error_t result; 1826 unsigned char big8[4]; 1827 unsigned char atc[4]; 1828 long s[3], s2[3]; 1829 int kk; 1830 struct mldl_cfg *mldlCfg = inv_get_dl_config(); 1831 1832 result = inv_serial_read(inv_get_serial_handle(), inv_get_mpu_slave_addr(), 1833 0x0d, 4, atc); 1834 if (result) { 1835 LOG_RESULT_LOCATION(result); 1836 return result; 1837 } 1838 1839 temp = atc[3] & 0x3f; 1840 if (temp >= 32) 1841 temp = temp - 64; 1842 temp = (temp << 21) | 0x100000; 1843 temp += (1L << 29); 1844 temp = -temp; 1845 result = inv_set_mpu_memory(KEY_D_ACT0, 4, inv_int32_to_big8(temp, big8)); 1846 if (result) { 1847 LOG_RESULT_LOCATION(result); 1848 return result; 1849 } 1850 1851 for (kk = 0; kk < 3; ++kk) { 1852 s[kk] = atc[kk] & 0x3f; 1853 if (s[kk] > 32) 1854 s[kk] = s[kk] - 64; 1855 s[kk] *= 2516582L; 1856 } 1857 1858 for (kk = 0; kk < 3; ++kk) { 1859 s2[kk] = mldlCfg->pdata->orientation[kk * 3] * s[0] + 1860 mldlCfg->pdata->orientation[kk * 3 + 1] * s[1] + 1861 mldlCfg->pdata->orientation[kk * 3 + 2] * s[2]; 1862 } 1863 result = inv_set_mpu_memory(KEY_D_ACSX, 4, inv_int32_to_big8(s2[0], big8)); 1864 if (result) { 1865 LOG_RESULT_LOCATION(result); 1866 return result; 1867 } 1868 result = inv_set_mpu_memory(KEY_D_ACSY, 4, inv_int32_to_big8(s2[1], big8)); 1869 if (result) { 1870 LOG_RESULT_LOCATION(result); 1871 return result; 1872 } 1873 result = inv_set_mpu_memory(KEY_D_ACSZ, 4, inv_int32_to_big8(s2[2], big8)); 1874 if (result) { 1875 LOG_RESULT_LOCATION(result); 1876 return result; 1877 } 1878 1879 return result; 1880 } 1881 #endif 1882 1883 /** 1884 * @} 1885 */ 1886