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: mldl.c 5653 2011-06-16 21:06:55Z nroyer $ 21 * 22 *****************************************************************************/ 23 24 /** 25 * @defgroup MLDL 26 * @brief Motion Library - Driver Layer. 27 * The Motion Library Driver Layer provides the intrface to the 28 * system drivers that are used by the Motion Library. 29 * 30 * @{ 31 * @file mldl.c 32 * @brief The Motion Library Driver Layer. 33 */ 34 35 /* ------------------ */ 36 /* - Include Files. - */ 37 /* ------------------ */ 38 39 #include <string.h> 40 41 #include "mpu.h" 42 #if defined CONFIG_MPU_SENSORS_MPU6050A2 43 # include "mpu6050a2.h" 44 #elif defined CONFIG_MPU_SENSORS_MPU6050B1 45 # include "mpu6050b1.h" 46 #elif defined CONFIG_MPU_SENSORS_MPU3050 47 # include "mpu3050.h" 48 #else 49 #error Invalid or undefined CONFIG_MPU_SENSORS_MPUxxxx 50 #endif 51 #include "mldl.h" 52 #include "mldl_cfg.h" 53 #include "compass.h" 54 #include "mlsl.h" 55 #include "mlos.h" 56 #include "mlinclude.h" 57 #include "ml.h" 58 #include "dmpKey.h" 59 #include "mlFIFOHW.h" 60 #include "compass.h" 61 #include "pressure.h" 62 63 #include "log.h" 64 #undef MPL_LOG_TAG 65 #define MPL_LOG_TAG "MPL-mldl" 66 67 #define _mldlDebug(x) //{x} 68 69 /* --------------------- */ 70 /* - Variables. - */ 71 /* --------------------- */ 72 73 #define MAX_LOAD_WRITE_SIZE (MPU_MEM_BANK_SIZE/2) /* 128 */ 74 75 /*---- structure containing control variables used by MLDL ----*/ 76 static struct mldl_cfg mldlCfg; 77 struct ext_slave_descr gAccel; 78 struct ext_slave_descr gCompass; 79 struct ext_slave_descr gPressure; 80 struct mpu_platform_data gPdata; 81 static void *sMLSLHandle; 82 int_fast8_t intTrigger[NUM_OF_INTSOURCES]; 83 84 /******************************************************************************* 85 * Functions for accessing the DMP memory via keys 86 ******************************************************************************/ 87 88 unsigned short (*sGetAddress) (unsigned short key) = NULL; 89 static const unsigned char *localDmpMemory = NULL; 90 static unsigned short localDmpMemorySize = 0; 91 92 /** 93 * @internal 94 * @brief Sets the function to use to convert keys to addresses. This 95 * will changed for each DMP code loaded. 96 * @param func 97 * Function used to convert keys to addresses. 98 * @endif 99 */ 100 void inv_set_get_address(unsigned short (*func) (unsigned short key)) 101 { 102 INVENSENSE_FUNC_START; 103 _mldlDebug(MPL_LOGV("setGetAddress %d", (int)func); 104 ) 105 sGetAddress = func; 106 } 107 108 /** 109 * @internal 110 * @brief Check if the feature is supported in the currently loaded 111 * DMP code basing on the fact that the key is assigned a 112 * value or not. 113 * @param key the DMP key 114 * @return whether the feature associated with the key is supported 115 * or not. 116 */ 117 uint_fast8_t inv_dmpkey_supported(unsigned short key) 118 { 119 unsigned short memAddr; 120 121 if (sGetAddress == NULL) { 122 MPL_LOGE("%s : sGetAddress is NULL\n", __func__); 123 return FALSE; 124 } 125 126 memAddr = sGetAddress(key); 127 if (memAddr >= 0xffff) { 128 MPL_LOGV("inv_set_mpu_memory unsupported key\n"); 129 return FALSE; 130 } 131 132 return TRUE; 133 } 134 135 /** 136 * @internal 137 * @brief used to get the specified number of bytes from the original 138 * MPU memory location specified by the key. 139 * Reads the specified number of bytes from the MPU location 140 * that was used to program the MPU specified by the key. Each 141 * set of code specifies a function that changes keys into 142 * addresses. This function is set with setGetAddress(). 143 * 144 * @param key The key to use when looking up the address. 145 * @param length Number of bytes to read. 146 * @param buffer Result for data. 147 * 148 * @return INV_SUCCESS if the command is successful, INV_ERROR otherwise. The key 149 * not corresponding to a memory address will result in INV_ERROR. 150 * @endif 151 */ 152 inv_error_t inv_get_mpu_memory_original(unsigned short key, 153 unsigned short length, 154 unsigned char *buffer) 155 { 156 unsigned short offset; 157 158 if (sGetAddress == NULL) { 159 return INV_ERROR_NOT_OPENED; 160 } 161 162 offset = sGetAddress(key); 163 if (offset >= localDmpMemorySize || (offset + length) > localDmpMemorySize) { 164 return INV_ERROR_INVALID_PARAMETER; 165 } 166 167 memcpy(buffer, &localDmpMemory[offset], length); 168 169 return INV_SUCCESS; 170 } 171 172 unsigned short inv_dl_get_address(unsigned short key) 173 { 174 unsigned short offset; 175 if (sGetAddress == NULL) { 176 return INV_ERROR_NOT_OPENED; 177 } 178 179 offset = sGetAddress(key); 180 return offset; 181 } 182 183 /* ---------------------- */ 184 /* - Static Functions. - */ 185 /* ---------------------- */ 186 187 /** 188 * @brief Open the driver layer and resets the internal 189 * gyroscope, accelerometer, and compass data 190 * structures. 191 * @param mlslHandle 192 * the serial handle. 193 * @return INV_SUCCESS if successful, a non-zero error code otherwise. 194 */ 195 inv_error_t inv_dl_open(void *mlslHandle) 196 { 197 inv_error_t result; 198 memset(&mldlCfg, 0, sizeof(mldlCfg)); 199 memset(intTrigger, INT_CLEAR, sizeof(intTrigger)); 200 201 sMLSLHandle = mlslHandle; 202 203 mldlCfg.addr = 0x68; /* default incase the driver doesn't set it */ 204 mldlCfg.accel = &gAccel; 205 mldlCfg.compass = &gCompass; 206 mldlCfg.pressure = &gPressure; 207 mldlCfg.pdata = &gPdata; 208 209 result = (inv_error_t) inv_mpu_open(&mldlCfg, sMLSLHandle, 210 sMLSLHandle, sMLSLHandle, sMLSLHandle); 211 return result; 212 } 213 214 /** 215 * @brief Closes/Cleans up the ML Driver Layer. 216 * Put the device in sleep mode. 217 * @return INV_SUCCESS or non-zero error code. 218 */ 219 inv_error_t inv_dl_close(void) 220 { 221 INVENSENSE_FUNC_START; 222 inv_error_t result = INV_SUCCESS; 223 224 result = (inv_error_t) inv_mpu_suspend(&mldlCfg, 225 sMLSLHandle, 226 sMLSLHandle, 227 sMLSLHandle, 228 sMLSLHandle, 229 INV_ALL_SENSORS); 230 231 result = (inv_error_t) inv_mpu_close(&mldlCfg, sMLSLHandle, 232 sMLSLHandle, sMLSLHandle, sMLSLHandle); 233 /* Clear all previous settings */ 234 memset(&mldlCfg, 0, sizeof(mldlCfg)); 235 sMLSLHandle = NULL; 236 sGetAddress = NULL; 237 return result; 238 } 239 240 /** 241 * @brief Sets the requested_sensors 242 * 243 * Accessor to set the requested_sensors field of the mldl_cfg structure. 244 * Typically set at initialization. 245 * 246 * @param sensors 247 * Bitfield of the sensors that are going to be used. Combination of the 248 * following: 249 * - INV_X_GYRO 250 * - INV_Y_GYRO 251 * - INV_Z_GYRO 252 * - INV_DMP_PROCESSOR 253 * - INV_X_ACCEL 254 * - INV_Y_ACCEL 255 * - INV_Z_ACCEL 256 * - INV_X_COMPASS 257 * - INV_Y_COMPASS 258 * - INV_Z_COMPASS 259 * - INV_X_PRESSURE 260 * - INV_Y_PRESSURE 261 * - INV_Z_PRESSURE 262 * - INV_THREE_AXIS_GYRO 263 * - INV_THREE_AXIS_ACCEL 264 * - INV_THREE_AXIS_COMPASS 265 * - INV_THREE_AXIS_PRESSURE 266 * 267 * @return INV_SUCCESS or non-zero error code 268 */ 269 inv_error_t inv_init_requested_sensors(unsigned long sensors) 270 { 271 mldlCfg.requested_sensors = sensors; 272 273 return INV_SUCCESS; 274 } 275 276 /** 277 * @brief Starts the DMP running 278 * 279 * Resumes the sensor if any of the sensor axis or components are requested 280 * 281 * @param sensors 282 * Bitfield of the sensors to turn on. Combination of the following: 283 * - INV_X_GYRO 284 * - INV_Y_GYRO 285 * - INV_Z_GYRO 286 * - INV_DMP_PROCESSOR 287 * - INV_X_ACCEL 288 * - INV_Y_ACCEL 289 * - INV_Z_ACCEL 290 * - INV_X_COMPASS 291 * - INV_Y_COMPASS 292 * - INV_Z_COMPASS 293 * - INV_X_PRESSURE 294 * - INV_Y_PRESSURE 295 * - INV_Z_PRESSURE 296 * - INV_THREE_AXIS_GYRO 297 * - INV_THREE_AXIS_ACCEL 298 * - INV_THREE_AXIS_COMPASS 299 * - INV_THREE_AXIS_PRESSURE 300 * 301 * @return INV_SUCCESS or non-zero error code 302 */ 303 inv_error_t inv_dl_start(unsigned long sensors) 304 { 305 INVENSENSE_FUNC_START; 306 inv_error_t result = INV_SUCCESS; 307 308 mldlCfg.requested_sensors = sensors; 309 result = inv_mpu_resume(&mldlCfg, 310 sMLSLHandle, 311 sMLSLHandle, 312 sMLSLHandle, 313 sMLSLHandle, 314 sensors); 315 return result; 316 } 317 318 /** 319 * @brief Stops the DMP running and puts it in low power as requested 320 * 321 * Suspends each sensor according to the bitfield, if all axis and components 322 * of the sensor is off. 323 * 324 * @param sensors Bitfiled of the sensors to leave on. Combination of the 325 * following: 326 * - INV_X_GYRO 327 * - INV_Y_GYRO 328 * - INV_Z_GYRO 329 * - INV_X_ACCEL 330 * - INV_Y_ACCEL 331 * - INV_Z_ACCEL 332 * - INV_X_COMPASS 333 * - INV_Y_COMPASS 334 * - INV_Z_COMPASS 335 * - INV_X_PRESSURE 336 * - INV_Y_PRESSURE 337 * - INV_Z_PRESSURE 338 * - INV_THREE_AXIS_GYRO 339 * - INV_THREE_AXIS_ACCEL 340 * - INV_THREE_AXIS_COMPASS 341 * - INV_THREE_AXIS_PRESSURE 342 * 343 * 344 * @return INV_SUCCESS or non-zero error code 345 */ 346 inv_error_t inv_dl_stop(unsigned long sensors) 347 { 348 INVENSENSE_FUNC_START; 349 inv_error_t result = INV_SUCCESS; 350 351 result = inv_mpu_suspend(&mldlCfg, 352 sMLSLHandle, 353 sMLSLHandle, 354 sMLSLHandle, 355 sMLSLHandle, 356 sensors); 357 return result; 358 } 359 360 /** 361 * @brief Get a pointer to the internal data structure 362 * storing the configuration for the MPU, the accelerometer 363 * and the compass in use. 364 * @return a pointer to the data structure of type 'struct mldl_cfg'. 365 */ 366 struct mldl_cfg *inv_get_dl_config(void) 367 { 368 return &mldlCfg; 369 } 370 371 /** 372 * @brief Query the MPU slave address. 373 * @return The 7-bit mpu slave address. 374 */ 375 unsigned char inv_get_mpu_slave_addr(void) 376 { 377 INVENSENSE_FUNC_START; 378 return mldlCfg.addr; 379 } 380 381 /** 382 * @internal 383 * @brief MLDLCfgDMP configures the Digital Motion Processor internal to 384 * the MPU. The DMP can be enabled or disabled and the start address 385 * can be set. 386 * 387 * @param enableRun Enables the DMP processing if set to TRUE. 388 * @param enableFIFO Enables DMP output to the FIFO if set to TRUE. 389 * @param startAddress start address 390 * 391 * @return Zero if the command is successful, an error code otherwise. 392 */ 393 inv_error_t inv_get_dl_ctrl_dmp(unsigned char enableRun, 394 unsigned char enableFIFO) 395 { 396 INVENSENSE_FUNC_START; 397 398 mldlCfg.dmp_enable = enableRun; 399 mldlCfg.fifo_enable = enableFIFO; 400 mldlCfg.gyro_needs_reset = TRUE; 401 402 return INV_SUCCESS; 403 } 404 405 /** 406 * @brief inv_get_dl_cfg_int configures the interrupt function on the specified pin. 407 * The basic interrupt signal characteristics can be set 408 * (i.e. active high/low, open drain/push pull, etc.) and the 409 * triggers can be set. 410 * Currently only INTPIN_MPU is supported. 411 * 412 * @param triggers 413 * bitmask of triggers to enable for interrupt. 414 * The available triggers are: 415 * - BIT_MPU_RDY_EN 416 * - BIT_DMP_INT_EN 417 * - BIT_RAW_RDY_EN 418 * 419 * @return Zero if the command is successful, an error code otherwise. 420 */ 421 inv_error_t inv_get_dl_cfg_int(unsigned char triggers) 422 { 423 inv_error_t result = INV_SUCCESS; 424 425 #if defined CONFIG_MPU_SENSORS_MPU3050 426 /* Mantis has 8 bits of interrupt config bits */ 427 if (triggers & !(BIT_MPU_RDY_EN | BIT_DMP_INT_EN | BIT_RAW_RDY_EN)) { 428 return INV_ERROR_INVALID_PARAMETER; 429 } 430 #endif 431 432 mldlCfg.int_config = triggers; 433 if (!mldlCfg.gyro_is_suspended) { 434 result = inv_serial_single_write(sMLSLHandle, mldlCfg.addr, 435 MPUREG_INT_CFG, 436 (mldlCfg.int_config | mldlCfg.pdata-> 437 int_config)); 438 } else { 439 mldlCfg.gyro_needs_reset = TRUE; 440 } 441 442 return result; 443 } 444 445 /** 446 * @brief configures the output sampling rate on the MPU. 447 * Three parameters control the sampling: 448 * 449 * 1) Low pass filter bandwidth, and 450 * 2) output sampling divider. 451 * 452 * The output sampling rate is determined by the divider and the low 453 * pass filter setting. If the low pass filter is set to 454 * 'MPUFILTER_256HZ_NOLPF2', then the sample rate going into the 455 * divider is 8kHz; for all other settings it is 1kHz. 456 * The 8-bit divider will divide this frequency to get the resulting 457 * sample frequency. 458 * For example, if the filter setting is not 256Hz and the divider is 459 * set to 7, then the sample rate is as follows: 460 * sample rate = internal sample rate / div = 1kHz / 8 = 125Hz (or 8ms). 461 * 462 * The low pass filter selection codes control both the cutoff frequency of 463 * the internal low pass filter and internal analog sampling rate. The 464 * latter, in turn, affects the final output sampling rate according to the 465 * sample rate divider settig. 466 * 0 -> 256 Hz cutoff BW, 8 kHz analog sample rate, 467 * 1 -> 188 Hz cutoff BW, 1 kHz analog sample rate, 468 * 2 -> 98 Hz cutoff BW, 1 kHz analog sample rate, 469 * 3 -> 42 Hz cutoff BW, 1 kHz analog sample rate, 470 * 4 -> 20 Hz cutoff BW, 1 kHz analog sample rate, 471 * 5 -> 10 Hz cutoff BW, 1 kHz analog sample rate, 472 * 6 -> 5 Hz cutoff BW, 1 kHz analog sample rate, 473 * 7 -> 2.1 kHz cutoff BW, 8 kHz analog sample rate. 474 * 475 * @param lpf low pass filter, 0 to 7. 476 * @param divider Output sampling rate divider, 0 to 255. 477 * 478 * @return ML_SUCESS if successful; a non-zero error code otherwise. 479 **/ 480 inv_error_t inv_dl_cfg_sampling(unsigned char lpf, unsigned char divider) 481 { 482 /*---- do range checking ----*/ 483 if (lpf >= NUM_MPU_FILTER) { 484 return INV_ERROR_INVALID_PARAMETER; 485 } 486 487 mldlCfg.lpf = lpf; 488 mldlCfg.divider = divider; 489 mldlCfg.gyro_needs_reset = TRUE; 490 491 return INV_SUCCESS; 492 } 493 494 /** 495 * @brief set the full scale range for the gyros. 496 * The full scale selection codes correspond to: 497 * 0 -> 250 dps, 498 * 1 -> 500 dps, 499 * 2 -> 1000 dps, 500 * 3 -> 2000 dps. 501 * Full scale range affect the MPU's measurement 502 * sensitivity. 503 * 504 * @param fullScale 505 * the gyro full scale range in dps. 506 * 507 * @return INV_SUCCESS or non-zero error code. 508 **/ 509 inv_error_t inv_set_full_scale(float fullScale) 510 { 511 if (fullScale == 250.f) 512 mldlCfg.full_scale = MPU_FS_250DPS; 513 else if (fullScale == 500.f) 514 mldlCfg.full_scale = MPU_FS_500DPS; 515 else if (fullScale == 1000.f) 516 mldlCfg.full_scale = MPU_FS_1000DPS; 517 else if (fullScale == 2000.f) 518 mldlCfg.full_scale = MPU_FS_2000DPS; 519 else { // not a valid setting 520 MPL_LOGE("Invalid full scale range specification for gyros : %f\n", 521 fullScale); 522 MPL_LOGE 523 ("\tAvailable values : +/- 250 dps, +/- 500 dps, +/- 1000 dps, +/- 2000 dps\n"); 524 return INV_ERROR_INVALID_PARAMETER; 525 } 526 mldlCfg.gyro_needs_reset = TRUE; 527 528 return INV_SUCCESS; 529 } 530 531 /** 532 * @brief This function sets the external sync for the MPU sampling. 533 * It can be synchronized on the LSB of any of the gyros, any of the 534 * external accels, or on the temp readings. 535 * 536 * @param extSync External sync selection, 0 to 7. 537 * @return Zero if the command is successful; an error code otherwise. 538 **/ 539 inv_error_t inv_set_external_sync(unsigned char extSync) 540 { 541 INVENSENSE_FUNC_START; 542 543 /*---- do range checking ----*/ 544 if (extSync >= NUM_MPU_EXT_SYNC) { 545 return INV_ERROR_INVALID_PARAMETER; 546 } 547 mldlCfg.ext_sync = extSync; 548 mldlCfg.gyro_needs_reset = TRUE; 549 550 return INV_SUCCESS; 551 } 552 553 inv_error_t inv_set_ignore_system_suspend(unsigned char ignore) 554 { 555 INVENSENSE_FUNC_START; 556 557 mldlCfg.ignore_system_suspend = ignore; 558 559 return INV_SUCCESS; 560 } 561 562 /** 563 * @brief inv_clock_source function sets the clock source for the MPU gyro 564 * processing. 565 * The source can be any of the following: 566 * - Internal 8MHz oscillator, 567 * - PLL with X gyro as reference, 568 * - PLL with Y gyro as reference, 569 * - PLL with Z gyro as reference, 570 * - PLL with external 32.768Mhz reference, or 571 * - PLL with external 19.2MHz reference 572 * 573 * For best accuracy and timing, it is highly recommended to use one 574 * of the gyros as the clock source; however this gyro must be 575 * enabled to use its clock (see 'MLDLPowerMgmtMPU()'). 576 * 577 * @param clkSource Clock source selection. 578 * Can be one of: 579 * - CLK_INTERNAL, 580 * - CLK_PLLGYROX, 581 * - CLK_PLLGYROY, 582 * - CLK_PLLGYROZ, 583 * - CLK_PLLEXT32K, or 584 * - CLK_PLLEXT19M. 585 * 586 * @return Zero if the command is successful; an error code otherwise. 587 **/ 588 inv_error_t inv_clock_source(unsigned char clkSource) 589 { 590 INVENSENSE_FUNC_START; 591 592 /*---- do range checking ----*/ 593 if (clkSource >= NUM_CLK_SEL) { 594 return INV_ERROR_INVALID_PARAMETER; 595 } 596 597 mldlCfg.clk_src = clkSource; 598 mldlCfg.gyro_needs_reset = TRUE; 599 600 return INV_SUCCESS; 601 } 602 603 /** 604 * @brief Set the Temperature Compensation offset. 605 * @param tc 606 * a pointer to the temperature compensations offset 607 * for the 3 gyro axes. 608 * @return INV_SUCCESS if successful, a non-zero error code otherwise. 609 */ 610 inv_error_t inv_set_offsetTC(const unsigned char *tc) 611 { 612 int ii; 613 inv_error_t result; 614 615 for (ii = 0; ii < ARRAY_SIZE(mldlCfg.offset_tc); ii++) { 616 mldlCfg.offset_tc[ii] = tc[ii]; 617 } 618 619 if (!mldlCfg.gyro_is_suspended) { 620 #ifdef CONFIG_MPU_SENSORS_MPU3050 621 result = inv_serial_single_write(sMLSLHandle, mldlCfg.addr, 622 MPUREG_XG_OFFS_TC, tc[0]); 623 if (result) { 624 LOG_RESULT_LOCATION(result); 625 return result; 626 } 627 result = inv_serial_single_write(sMLSLHandle, mldlCfg.addr, 628 MPUREG_YG_OFFS_TC, tc[1]); 629 if (result) { 630 LOG_RESULT_LOCATION(result); 631 return result; 632 } 633 result = inv_serial_single_write(sMLSLHandle, mldlCfg.addr, 634 MPUREG_ZG_OFFS_TC, tc[2]); 635 if (result) { 636 LOG_RESULT_LOCATION(result); 637 return result; 638 } 639 #else 640 unsigned char reg; 641 result = inv_serial_single_write(sMLSLHandle, mldlCfg.addr, 642 MPUREG_XG_OFFS_TC, 643 ((mldlCfg.offset_tc[0] << 1) 644 & BITS_XG_OFFS_TC)); 645 if (result) { 646 LOG_RESULT_LOCATION(result); 647 return result; 648 } 649 reg = ((mldlCfg.offset_tc[1] << 1) & BITS_YG_OFFS_TC); 650 #ifdef CONFIG_MPU_SENSORS_MPU6050B1 651 if (mldlCfg.pdata->level_shifter) 652 reg |= BIT_I2C_MST_VDDIO; 653 #endif 654 result = inv_serial_single_write(sMLSLHandle, mldlCfg.addr, 655 MPUREG_YG_OFFS_TC, reg); 656 if (result) { 657 LOG_RESULT_LOCATION(result); 658 return result; 659 } 660 result = inv_serial_single_write(sMLSLHandle, mldlCfg.addr, 661 MPUREG_ZG_OFFS_TC, 662 ((mldlCfg.offset_tc[2] << 1) 663 & BITS_ZG_OFFS_TC)); 664 if (result) { 665 LOG_RESULT_LOCATION(result); 666 return result; 667 } 668 #endif 669 } else { 670 mldlCfg.gyro_needs_reset = TRUE; 671 } 672 return INV_SUCCESS; 673 } 674 675 /** 676 * @brief Set the gyro offset. 677 * @param offset 678 * a pointer to the gyro offset for the 3 gyro axes. This is scaled 679 * as it would be written to the hardware registers. 680 * @return INV_SUCCESS if successful, a non-zero error code otherwise. 681 */ 682 inv_error_t inv_set_offset(const short *offset) 683 { 684 inv_error_t result; 685 unsigned char regs[7]; 686 int ii; 687 long sf; 688 689 sf = (2000L * 131) / mldlCfg.gyro_sens_trim; 690 for (ii = 0; ii < ARRAY_SIZE(mldlCfg.offset); ii++) { 691 // Record the bias in the units the register uses 692 mldlCfg.offset[ii] = offset[ii]; 693 // Convert the bias to 1 dps = 1<<16 694 inv_obj.gyro_bias[ii] = -offset[ii] * sf; 695 regs[1 + ii * 2] = (unsigned char)(offset[ii] >> 8) & 0xff; 696 regs[1 + ii * 2 + 1] = (unsigned char)(offset[ii] & 0xff); 697 } 698 699 if (!mldlCfg.gyro_is_suspended) { 700 regs[0] = MPUREG_X_OFFS_USRH; 701 result = inv_serial_write(sMLSLHandle, mldlCfg.addr, 7, regs); 702 if (result) { 703 LOG_RESULT_LOCATION(result); 704 return result; 705 } 706 } else { 707 mldlCfg.gyro_needs_reset = TRUE; 708 } 709 return INV_SUCCESS; 710 } 711 712 /** 713 * @internal 714 * @brief used to get the specified number of bytes in the specified MPU 715 * memory bank. 716 * The memory bank is one of the following: 717 * - MPUMEM_RAM_BANK_0, 718 * - MPUMEM_RAM_BANK_1, 719 * - MPUMEM_RAM_BANK_2, or 720 * - MPUMEM_RAM_BANK_3. 721 * 722 * @param bank Memory bank to write. 723 * @param memAddr Starting address for write. 724 * @param length Number of bytes to write. 725 * @param buffer Result for data. 726 * 727 * @return zero if the command is successful, an error code otherwise. 728 * @endif 729 */ 730 inv_error_t 731 inv_get_mpu_memory_one_bank(unsigned char bank, 732 unsigned char memAddr, 733 unsigned short length, unsigned char *buffer) 734 { 735 inv_error_t result; 736 737 if ((bank >= MPU_MEM_NUM_RAM_BANKS) || 738 //(memAddr >= MPU_MEM_BANK_SIZE) || always 0, memAddr is an u_char, therefore limited to 255 739 ((memAddr + length) > MPU_MEM_BANK_SIZE) || (NULL == buffer)) { 740 return INV_ERROR_INVALID_PARAMETER; 741 } 742 743 if (mldlCfg.gyro_is_suspended) { 744 memcpy(buffer, &mldlCfg.ram[bank][memAddr], length); 745 result = INV_SUCCESS; 746 } else { 747 result = inv_serial_read_mem(sMLSLHandle, mldlCfg.addr, 748 ((bank << 8) | memAddr), length, buffer); 749 if (result) { 750 LOG_RESULT_LOCATION(result); 751 return result; 752 } 753 } 754 755 return result; 756 } 757 758 /** 759 * @internal 760 * @brief used to set the specified number of bytes in the specified MPU 761 * memory bank. 762 * The memory bank is one of the following: 763 * - MPUMEM_RAM_BANK_0, 764 * - MPUMEM_RAM_BANK_1, 765 * - MPUMEM_RAM_BANK_2, or 766 * - MPUMEM_RAM_BANK_3. 767 * 768 * @param bank Memory bank to write. 769 * @param memAddr Starting address for write. 770 * @param length Number of bytes to write. 771 * @param buffer Result for data. 772 * 773 * @return zero if the command is successful, an error code otherwise. 774 * @endif 775 */ 776 inv_error_t inv_set_mpu_memory_one_bank(unsigned char bank, 777 unsigned short memAddr, 778 unsigned short length, 779 const unsigned char *buffer) 780 { 781 inv_error_t result = INV_SUCCESS; 782 int different; 783 784 if ((bank >= MPU_MEM_NUM_RAM_BANKS) || (memAddr >= MPU_MEM_BANK_SIZE) || 785 ((memAddr + length) > MPU_MEM_BANK_SIZE) || (NULL == buffer)) { 786 return INV_ERROR_INVALID_PARAMETER; 787 } 788 789 different = memcmp(&mldlCfg.ram[bank][memAddr], buffer, length); 790 memcpy(&mldlCfg.ram[bank][memAddr], buffer, length); 791 if (!mldlCfg.gyro_is_suspended) { 792 result = inv_serial_write_mem(sMLSLHandle, mldlCfg.addr, 793 ((bank << 8) | memAddr), length, buffer); 794 if (result) { 795 LOG_RESULT_LOCATION(result); 796 return result; 797 } 798 } else if (different) { 799 mldlCfg.gyro_needs_reset = TRUE; 800 } 801 802 return result; 803 } 804 805 /** 806 * @internal 807 * @brief used to get the specified number of bytes from the MPU location 808 * specified by the key. 809 * Reads the specified number of bytes from the MPU location 810 * specified by the key. Each set of code specifies a function 811 * that changes keys into addresses. This function is set with 812 * setGetAddress(). 813 * 814 * @param key The key to use when looking up the address. 815 * @param length Number of bytes to read. 816 * @param buffer Result for data. 817 * 818 * @return INV_SUCCESS if the command is successful, INV_ERROR otherwise. The key 819 * not corresponding to a memory address will result in INV_ERROR. 820 * @endif 821 */ 822 inv_error_t inv_get_mpu_memory(unsigned short key, 823 unsigned short length, unsigned char *buffer) 824 { 825 unsigned char bank; 826 inv_error_t result; 827 unsigned short memAddr; 828 829 if (sGetAddress == NULL) { 830 return INV_ERROR_NOT_OPENED; 831 } 832 833 memAddr = sGetAddress(key); 834 if (memAddr >= 0xffff) 835 return INV_ERROR_FEATURE_NOT_IMPLEMENTED; 836 bank = memAddr >> 8; // Get Bank 837 memAddr &= 0xff; 838 839 while (memAddr + length > MPU_MEM_BANK_SIZE) { 840 // We cross a bank in the middle 841 unsigned short sub_length = MPU_MEM_BANK_SIZE - memAddr; 842 result = inv_get_mpu_memory_one_bank(bank, (unsigned char)memAddr, 843 sub_length, buffer); 844 if (INV_SUCCESS != result) 845 return result; 846 bank++; 847 length -= sub_length; 848 buffer += sub_length; 849 memAddr = 0; 850 } 851 result = inv_get_mpu_memory_one_bank(bank, (unsigned char)memAddr, 852 length, buffer); 853 854 if (result) { 855 LOG_RESULT_LOCATION(result); 856 return result; 857 } 858 859 return result; 860 } 861 862 /** 863 * @internal 864 * @brief used to set the specified number of bytes from the MPU location 865 * specified by the key. 866 * Set the specified number of bytes from the MPU location 867 * specified by the key. Each set of DMP code specifies a function 868 * that changes keys into addresses. This function is set with 869 * setGetAddress(). 870 * 871 * @param key The key to use when looking up the address. 872 * @param length Number of bytes to write. 873 * @param buffer Result for data. 874 * 875 * @return INV_SUCCESS if the command is successful, INV_ERROR otherwise. The key 876 * not corresponding to a memory address will result in INV_ERROR. 877 * @endif 878 */ 879 inv_error_t inv_set_mpu_memory(unsigned short key, 880 unsigned short length, 881 const unsigned char *buffer) 882 { 883 inv_error_t result = INV_SUCCESS; 884 unsigned short memAddr; 885 unsigned char bank; 886 887 if (sGetAddress == NULL) { 888 MPL_LOGE("MLDSetMemoryMPU sGetAddress is NULL\n"); 889 return INV_ERROR_INVALID_MODULE; 890 } 891 memAddr = sGetAddress(key); 892 893 if (memAddr >= 0xffff) { 894 MPL_LOGE("inv_set_mpu_memory unsupported key\n"); 895 return INV_ERROR_INVALID_MODULE; // This key not supported 896 } 897 898 bank = (unsigned char)(memAddr >> 8); 899 memAddr &= 0xff; 900 901 while (memAddr + length > MPU_MEM_BANK_SIZE) { 902 // We cross a bank in the middle 903 unsigned short sub_length = MPU_MEM_BANK_SIZE - memAddr; 904 905 result = inv_set_mpu_memory_one_bank(bank, memAddr, sub_length, buffer); 906 if (result) { 907 LOG_RESULT_LOCATION(result); 908 return result; 909 } 910 911 bank++; 912 length -= sub_length; 913 buffer += sub_length; 914 memAddr = 0; 915 } 916 result = inv_set_mpu_memory_one_bank(bank, memAddr, length, buffer); 917 if (result) { 918 LOG_RESULT_LOCATION(result); 919 return result; 920 } 921 return result; 922 } 923 924 /** 925 * @brief Load the DMP with the given code and configuration. 926 * @param buffer 927 * the DMP data. 928 * @param length 929 * the length in bytes of the DMP data. 930 * @param config 931 * the DMP configuration. 932 * @return INV_SUCCESS if successful, a non-zero error code otherwise. 933 */ 934 inv_error_t inv_load_dmp(const unsigned char *buffer, 935 unsigned short length, unsigned short config) 936 { 937 INVENSENSE_FUNC_START; 938 939 inv_error_t result = INV_SUCCESS; 940 unsigned short toWrite; 941 unsigned short memAddr = 0; 942 localDmpMemory = buffer; 943 localDmpMemorySize = length; 944 945 mldlCfg.dmp_cfg1 = (config >> 8); 946 mldlCfg.dmp_cfg2 = (config & 0xff); 947 948 while (length > 0) { 949 toWrite = length; 950 if (toWrite > MAX_LOAD_WRITE_SIZE) 951 toWrite = MAX_LOAD_WRITE_SIZE; 952 953 result = 954 inv_set_mpu_memory_one_bank(memAddr >> 8, memAddr & 0xff, toWrite, 955 buffer); 956 if (result) { 957 LOG_RESULT_LOCATION(result); 958 return result; 959 } 960 961 buffer += toWrite; 962 memAddr += toWrite; 963 length -= toWrite; 964 } 965 966 return result; 967 } 968 969 /** 970 * @brief Get the silicon revision ID. 971 * @return The silicon revision ID 972 * (0 will be read if inv_mpu_open returned an error) 973 */ 974 unsigned char inv_get_silicon_rev(void) 975 { 976 return mldlCfg.silicon_revision; 977 } 978 979 /** 980 * @brief Get the product revision ID. 981 * @return The product revision ID 982 * (0 will be read if inv_mpu_open returned an error) 983 */ 984 unsigned char inv_get_product_rev(void) 985 { 986 return mldlCfg.product_revision; 987 } 988 989 /******************************************************************************* 990 ******************************************************************************* 991 ******************************************************************************* 992 * @todo these belong with an interface to the kernel driver layer 993 ******************************************************************************* 994 ******************************************************************************* 995 ******************************************************************************/ 996 997 /** 998 * @brief inv_get_interrupt_status returns the interrupt status from the specified 999 * interrupt pin. 1000 * @param intPin 1001 * Currently only the value INTPIN_MPU is supported. 1002 * @param status 1003 * The available statuses are: 1004 * - BIT_MPU_RDY_EN 1005 * - BIT_DMP_INT_EN 1006 * - BIT_RAW_RDY_EN 1007 * 1008 * @return INV_SUCCESS or a non-zero error code. 1009 */ 1010 inv_error_t inv_get_interrupt_status(unsigned char intPin, 1011 unsigned char *status) 1012 { 1013 INVENSENSE_FUNC_START; 1014 1015 inv_error_t result; 1016 1017 switch (intPin) { 1018 1019 case INTPIN_MPU: 1020 /*---- return the MPU interrupt status ----*/ 1021 result = inv_serial_read(sMLSLHandle, mldlCfg.addr, 1022 MPUREG_INT_STATUS, 1, status); 1023 break; 1024 1025 default: 1026 result = INV_ERROR_INVALID_PARAMETER; 1027 break; 1028 } 1029 1030 return result; 1031 } 1032 1033 /** 1034 * @brief query the current status of an interrupt source. 1035 * @param srcIndex 1036 * index of the interrupt source. 1037 * Currently the only source supported is INTPIN_MPU. 1038 * 1039 * @return 1 if the interrupt has been triggered. 1040 */ 1041 unsigned char inv_get_interrupt_trigger(unsigned char srcIndex) 1042 { 1043 INVENSENSE_FUNC_START; 1044 return intTrigger[srcIndex]; 1045 } 1046 1047 /** 1048 * @brief clear the 'triggered' status for an interrupt source. 1049 * @param srcIndex 1050 * index of the interrupt source. 1051 * Currently only INTPIN_MPU is supported. 1052 */ 1053 void inv_clear_interrupt_trigger(unsigned char srcIndex) 1054 { 1055 INVENSENSE_FUNC_START; 1056 intTrigger[srcIndex] = 0; 1057 } 1058 1059 /** 1060 * @brief inv_interrupt_handler function should be called when an interrupt is 1061 * received. The source parameter identifies which interrupt source 1062 * caused the interrupt. Note that this routine should not be called 1063 * directly from the interrupt service routine. 1064 * 1065 * @param intSource MPU, AUX1, AUX2, or timer. Can be one of: INTSRC_MPU, INTSRC_AUX1, 1066 * INTSRC_AUX2, or INT_SRC_TIMER. 1067 * 1068 * @return Zero if the command is successful; an error code otherwise. 1069 */ 1070 inv_error_t inv_interrupt_handler(unsigned char intSource) 1071 { 1072 INVENSENSE_FUNC_START; 1073 /*---- range check ----*/ 1074 if (intSource >= NUM_OF_INTSOURCES) { 1075 return INV_ERROR; 1076 } 1077 1078 /*---- save source of interrupt ----*/ 1079 intTrigger[intSource] = INT_TRIGGERED; 1080 1081 #ifdef ML_USE_DMP_SIM 1082 if (intSource == INTSRC_AUX1 || intSource == INTSRC_TIMER) { 1083 MLSimHWDataInput(); 1084 } 1085 #endif 1086 1087 return INV_SUCCESS; 1088 } 1089 1090 /***************************/ 1091 /**@}*//* end of defgroup */ 1092 /***************************/ 1093