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