| /* |
| $License: |
| Copyright 2011 InvenSense, Inc. |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| $ |
| */ |
| /****************************************************************************** |
| * |
| * $Id: mldl.c 5653 2011-06-16 21:06:55Z nroyer $ |
| * |
| *****************************************************************************/ |
| |
| /** |
| * @defgroup MLDL |
| * @brief Motion Library - Driver Layer. |
| * The Motion Library Driver Layer provides the intrface to the |
| * system drivers that are used by the Motion Library. |
| * |
| * @{ |
| * @file mldl.c |
| * @brief The Motion Library Driver Layer. |
| */ |
| |
| /* ------------------ */ |
| /* - Include Files. - */ |
| /* ------------------ */ |
| |
| #include <string.h> |
| |
| #include "mpu.h" |
| #if defined CONFIG_MPU_SENSORS_MPU6050A2 |
| # include "mpu6050a2.h" |
| #elif defined CONFIG_MPU_SENSORS_MPU6050B1 |
| # include "mpu6050b1.h" |
| #elif defined CONFIG_MPU_SENSORS_MPU3050 |
| # include "mpu3050.h" |
| #else |
| #error Invalid or undefined CONFIG_MPU_SENSORS_MPUxxxx |
| #endif |
| #include "mldl.h" |
| #include "mldl_cfg.h" |
| #include "compass.h" |
| #include "mlsl.h" |
| #include "mlos.h" |
| #include "mlinclude.h" |
| #include "ml.h" |
| #include "dmpKey.h" |
| #include "mlFIFOHW.h" |
| #include "compass.h" |
| #include "pressure.h" |
| |
| #include "log.h" |
| #undef MPL_LOG_TAG |
| #define MPL_LOG_TAG "MPL-mldl" |
| |
| #define _mldlDebug(x) //{x} |
| |
| /* --------------------- */ |
| /* - Variables. - */ |
| /* --------------------- */ |
| |
| #define MAX_LOAD_WRITE_SIZE (MPU_MEM_BANK_SIZE/2) /* 128 */ |
| |
| /*---- structure containing control variables used by MLDL ----*/ |
| static struct mldl_cfg mldlCfg; |
| struct ext_slave_descr gAccel; |
| struct ext_slave_descr gCompass; |
| struct ext_slave_descr gPressure; |
| struct mpu_platform_data gPdata; |
| static void *sMLSLHandle; |
| int_fast8_t intTrigger[NUM_OF_INTSOURCES]; |
| |
| /******************************************************************************* |
| * Functions for accessing the DMP memory via keys |
| ******************************************************************************/ |
| |
| unsigned short (*sGetAddress) (unsigned short key) = NULL; |
| static const unsigned char *localDmpMemory = NULL; |
| static unsigned short localDmpMemorySize = 0; |
| |
| /** |
| * @internal |
| * @brief Sets the function to use to convert keys to addresses. This |
| * will changed for each DMP code loaded. |
| * @param func |
| * Function used to convert keys to addresses. |
| * @endif |
| */ |
| void inv_set_get_address(unsigned short (*func) (unsigned short key)) |
| { |
| INVENSENSE_FUNC_START; |
| _mldlDebug(MPL_LOGV("setGetAddress %d", (int)func); |
| ) |
| sGetAddress = func; |
| } |
| |
| /** |
| * @internal |
| * @brief Check if the feature is supported in the currently loaded |
| * DMP code basing on the fact that the key is assigned a |
| * value or not. |
| * @param key the DMP key |
| * @return whether the feature associated with the key is supported |
| * or not. |
| */ |
| uint_fast8_t inv_dmpkey_supported(unsigned short key) |
| { |
| unsigned short memAddr; |
| |
| if (sGetAddress == NULL) { |
| MPL_LOGE("%s : sGetAddress is NULL\n", __func__); |
| return FALSE; |
| } |
| |
| memAddr = sGetAddress(key); |
| if (memAddr >= 0xffff) { |
| MPL_LOGV("inv_set_mpu_memory unsupported key\n"); |
| return FALSE; |
| } |
| |
| return TRUE; |
| } |
| |
| /** |
| * @internal |
| * @brief used to get the specified number of bytes from the original |
| * MPU memory location specified by the key. |
| * Reads the specified number of bytes from the MPU location |
| * that was used to program the MPU specified by the key. Each |
| * set of code specifies a function that changes keys into |
| * addresses. This function is set with setGetAddress(). |
| * |
| * @param key The key to use when looking up the address. |
| * @param length Number of bytes to read. |
| * @param buffer Result for data. |
| * |
| * @return INV_SUCCESS if the command is successful, INV_ERROR otherwise. The key |
| * not corresponding to a memory address will result in INV_ERROR. |
| * @endif |
| */ |
| inv_error_t inv_get_mpu_memory_original(unsigned short key, |
| unsigned short length, |
| unsigned char *buffer) |
| { |
| unsigned short offset; |
| |
| if (sGetAddress == NULL) { |
| return INV_ERROR_NOT_OPENED; |
| } |
| |
| offset = sGetAddress(key); |
| if (offset >= localDmpMemorySize || (offset + length) > localDmpMemorySize) { |
| return INV_ERROR_INVALID_PARAMETER; |
| } |
| |
| memcpy(buffer, &localDmpMemory[offset], length); |
| |
| return INV_SUCCESS; |
| } |
| |
| unsigned short inv_dl_get_address(unsigned short key) |
| { |
| unsigned short offset; |
| if (sGetAddress == NULL) { |
| return INV_ERROR_NOT_OPENED; |
| } |
| |
| offset = sGetAddress(key); |
| return offset; |
| } |
| |
| /* ---------------------- */ |
| /* - Static Functions. - */ |
| /* ---------------------- */ |
| |
| /** |
| * @brief Open the driver layer and resets the internal |
| * gyroscope, accelerometer, and compass data |
| * structures. |
| * @param mlslHandle |
| * the serial handle. |
| * @return INV_SUCCESS if successful, a non-zero error code otherwise. |
| */ |
| inv_error_t inv_dl_open(void *mlslHandle) |
| { |
| inv_error_t result; |
| memset(&mldlCfg, 0, sizeof(mldlCfg)); |
| memset(intTrigger, INT_CLEAR, sizeof(intTrigger)); |
| |
| sMLSLHandle = mlslHandle; |
| |
| mldlCfg.addr = 0x68; /* default incase the driver doesn't set it */ |
| mldlCfg.accel = &gAccel; |
| mldlCfg.compass = &gCompass; |
| mldlCfg.pressure = &gPressure; |
| mldlCfg.pdata = &gPdata; |
| |
| result = (inv_error_t) inv_mpu_open(&mldlCfg, sMLSLHandle, |
| sMLSLHandle, sMLSLHandle, sMLSLHandle); |
| return result; |
| } |
| |
| /** |
| * @brief Closes/Cleans up the ML Driver Layer. |
| * Put the device in sleep mode. |
| * @return INV_SUCCESS or non-zero error code. |
| */ |
| inv_error_t inv_dl_close(void) |
| { |
| INVENSENSE_FUNC_START; |
| inv_error_t result = INV_SUCCESS; |
| |
| result = (inv_error_t) inv_mpu_suspend(&mldlCfg, |
| sMLSLHandle, |
| sMLSLHandle, |
| sMLSLHandle, |
| sMLSLHandle, |
| INV_ALL_SENSORS); |
| |
| result = (inv_error_t) inv_mpu_close(&mldlCfg, sMLSLHandle, |
| sMLSLHandle, sMLSLHandle, sMLSLHandle); |
| /* Clear all previous settings */ |
| memset(&mldlCfg, 0, sizeof(mldlCfg)); |
| sMLSLHandle = NULL; |
| sGetAddress = NULL; |
| return result; |
| } |
| |
| /** |
| * @brief Sets the requested_sensors |
| * |
| * Accessor to set the requested_sensors field of the mldl_cfg structure. |
| * Typically set at initialization. |
| * |
| * @param sensors |
| * Bitfield of the sensors that are going to be used. Combination of the |
| * following: |
| * - INV_X_GYRO |
| * - INV_Y_GYRO |
| * - INV_Z_GYRO |
| * - INV_DMP_PROCESSOR |
| * - INV_X_ACCEL |
| * - INV_Y_ACCEL |
| * - INV_Z_ACCEL |
| * - INV_X_COMPASS |
| * - INV_Y_COMPASS |
| * - INV_Z_COMPASS |
| * - INV_X_PRESSURE |
| * - INV_Y_PRESSURE |
| * - INV_Z_PRESSURE |
| * - INV_THREE_AXIS_GYRO |
| * - INV_THREE_AXIS_ACCEL |
| * - INV_THREE_AXIS_COMPASS |
| * - INV_THREE_AXIS_PRESSURE |
| * |
| * @return INV_SUCCESS or non-zero error code |
| */ |
| inv_error_t inv_init_requested_sensors(unsigned long sensors) |
| { |
| mldlCfg.requested_sensors = sensors; |
| |
| return INV_SUCCESS; |
| } |
| |
| /** |
| * @brief Starts the DMP running |
| * |
| * Resumes the sensor if any of the sensor axis or components are requested |
| * |
| * @param sensors |
| * Bitfield of the sensors to turn on. Combination of the following: |
| * - INV_X_GYRO |
| * - INV_Y_GYRO |
| * - INV_Z_GYRO |
| * - INV_DMP_PROCESSOR |
| * - INV_X_ACCEL |
| * - INV_Y_ACCEL |
| * - INV_Z_ACCEL |
| * - INV_X_COMPASS |
| * - INV_Y_COMPASS |
| * - INV_Z_COMPASS |
| * - INV_X_PRESSURE |
| * - INV_Y_PRESSURE |
| * - INV_Z_PRESSURE |
| * - INV_THREE_AXIS_GYRO |
| * - INV_THREE_AXIS_ACCEL |
| * - INV_THREE_AXIS_COMPASS |
| * - INV_THREE_AXIS_PRESSURE |
| * |
| * @return INV_SUCCESS or non-zero error code |
| */ |
| inv_error_t inv_dl_start(unsigned long sensors) |
| { |
| INVENSENSE_FUNC_START; |
| inv_error_t result = INV_SUCCESS; |
| |
| mldlCfg.requested_sensors = sensors; |
| result = inv_mpu_resume(&mldlCfg, |
| sMLSLHandle, |
| sMLSLHandle, |
| sMLSLHandle, |
| sMLSLHandle, |
| sensors); |
| return result; |
| } |
| |
| /** |
| * @brief Stops the DMP running and puts it in low power as requested |
| * |
| * Suspends each sensor according to the bitfield, if all axis and components |
| * of the sensor is off. |
| * |
| * @param sensors Bitfiled of the sensors to leave on. Combination of the |
| * following: |
| * - INV_X_GYRO |
| * - INV_Y_GYRO |
| * - INV_Z_GYRO |
| * - INV_X_ACCEL |
| * - INV_Y_ACCEL |
| * - INV_Z_ACCEL |
| * - INV_X_COMPASS |
| * - INV_Y_COMPASS |
| * - INV_Z_COMPASS |
| * - INV_X_PRESSURE |
| * - INV_Y_PRESSURE |
| * - INV_Z_PRESSURE |
| * - INV_THREE_AXIS_GYRO |
| * - INV_THREE_AXIS_ACCEL |
| * - INV_THREE_AXIS_COMPASS |
| * - INV_THREE_AXIS_PRESSURE |
| * |
| * |
| * @return INV_SUCCESS or non-zero error code |
| */ |
| inv_error_t inv_dl_stop(unsigned long sensors) |
| { |
| INVENSENSE_FUNC_START; |
| inv_error_t result = INV_SUCCESS; |
| |
| result = inv_mpu_suspend(&mldlCfg, |
| sMLSLHandle, |
| sMLSLHandle, |
| sMLSLHandle, |
| sMLSLHandle, |
| sensors); |
| return result; |
| } |
| |
| /** |
| * @brief Get a pointer to the internal data structure |
| * storing the configuration for the MPU, the accelerometer |
| * and the compass in use. |
| * @return a pointer to the data structure of type 'struct mldl_cfg'. |
| */ |
| struct mldl_cfg *inv_get_dl_config(void) |
| { |
| return &mldlCfg; |
| } |
| |
| /** |
| * @brief Query the MPU slave address. |
| * @return The 7-bit mpu slave address. |
| */ |
| unsigned char inv_get_mpu_slave_addr(void) |
| { |
| INVENSENSE_FUNC_START; |
| return mldlCfg.addr; |
| } |
| |
| /** |
| * @internal |
| * @brief MLDLCfgDMP configures the Digital Motion Processor internal to |
| * the MPU. The DMP can be enabled or disabled and the start address |
| * can be set. |
| * |
| * @param enableRun Enables the DMP processing if set to TRUE. |
| * @param enableFIFO Enables DMP output to the FIFO if set to TRUE. |
| * @param startAddress start address |
| * |
| * @return Zero if the command is successful, an error code otherwise. |
| */ |
| inv_error_t inv_get_dl_ctrl_dmp(unsigned char enableRun, |
| unsigned char enableFIFO) |
| { |
| INVENSENSE_FUNC_START; |
| |
| mldlCfg.dmp_enable = enableRun; |
| mldlCfg.fifo_enable = enableFIFO; |
| mldlCfg.gyro_needs_reset = TRUE; |
| |
| return INV_SUCCESS; |
| } |
| |
| /** |
| * @brief inv_get_dl_cfg_int configures the interrupt function on the specified pin. |
| * The basic interrupt signal characteristics can be set |
| * (i.e. active high/low, open drain/push pull, etc.) and the |
| * triggers can be set. |
| * Currently only INTPIN_MPU is supported. |
| * |
| * @param triggers |
| * bitmask of triggers to enable for interrupt. |
| * The available triggers are: |
| * - BIT_MPU_RDY_EN |
| * - BIT_DMP_INT_EN |
| * - BIT_RAW_RDY_EN |
| * |
| * @return Zero if the command is successful, an error code otherwise. |
| */ |
| inv_error_t inv_get_dl_cfg_int(unsigned char triggers) |
| { |
| inv_error_t result = INV_SUCCESS; |
| |
| #if defined CONFIG_MPU_SENSORS_MPU3050 |
| /* Mantis has 8 bits of interrupt config bits */ |
| if (triggers & !(BIT_MPU_RDY_EN | BIT_DMP_INT_EN | BIT_RAW_RDY_EN)) { |
| return INV_ERROR_INVALID_PARAMETER; |
| } |
| #endif |
| |
| mldlCfg.int_config = triggers; |
| if (!mldlCfg.gyro_is_suspended) { |
| result = inv_serial_single_write(sMLSLHandle, mldlCfg.addr, |
| MPUREG_INT_CFG, |
| (mldlCfg.int_config | mldlCfg.pdata-> |
| int_config)); |
| } else { |
| mldlCfg.gyro_needs_reset = TRUE; |
| } |
| |
| return result; |
| } |
| |
| /** |
| * @brief configures the output sampling rate on the MPU. |
| * Three parameters control the sampling: |
| * |
| * 1) Low pass filter bandwidth, and |
| * 2) output sampling divider. |
| * |
| * The output sampling rate is determined by the divider and the low |
| * pass filter setting. If the low pass filter is set to |
| * 'MPUFILTER_256HZ_NOLPF2', then the sample rate going into the |
| * divider is 8kHz; for all other settings it is 1kHz. |
| * The 8-bit divider will divide this frequency to get the resulting |
| * sample frequency. |
| * For example, if the filter setting is not 256Hz and the divider is |
| * set to 7, then the sample rate is as follows: |
| * sample rate = internal sample rate / div = 1kHz / 8 = 125Hz (or 8ms). |
| * |
| * The low pass filter selection codes control both the cutoff frequency of |
| * the internal low pass filter and internal analog sampling rate. The |
| * latter, in turn, affects the final output sampling rate according to the |
| * sample rate divider settig. |
| * 0 -> 256 Hz cutoff BW, 8 kHz analog sample rate, |
| * 1 -> 188 Hz cutoff BW, 1 kHz analog sample rate, |
| * 2 -> 98 Hz cutoff BW, 1 kHz analog sample rate, |
| * 3 -> 42 Hz cutoff BW, 1 kHz analog sample rate, |
| * 4 -> 20 Hz cutoff BW, 1 kHz analog sample rate, |
| * 5 -> 10 Hz cutoff BW, 1 kHz analog sample rate, |
| * 6 -> 5 Hz cutoff BW, 1 kHz analog sample rate, |
| * 7 -> 2.1 kHz cutoff BW, 8 kHz analog sample rate. |
| * |
| * @param lpf low pass filter, 0 to 7. |
| * @param divider Output sampling rate divider, 0 to 255. |
| * |
| * @return ML_SUCESS if successful; a non-zero error code otherwise. |
| **/ |
| inv_error_t inv_dl_cfg_sampling(unsigned char lpf, unsigned char divider) |
| { |
| /*---- do range checking ----*/ |
| if (lpf >= NUM_MPU_FILTER) { |
| return INV_ERROR_INVALID_PARAMETER; |
| } |
| |
| mldlCfg.lpf = lpf; |
| mldlCfg.divider = divider; |
| mldlCfg.gyro_needs_reset = TRUE; |
| |
| return INV_SUCCESS; |
| } |
| |
| /** |
| * @brief set the full scale range for the gyros. |
| * The full scale selection codes correspond to: |
| * 0 -> 250 dps, |
| * 1 -> 500 dps, |
| * 2 -> 1000 dps, |
| * 3 -> 2000 dps. |
| * Full scale range affect the MPU's measurement |
| * sensitivity. |
| * |
| * @param fullScale |
| * the gyro full scale range in dps. |
| * |
| * @return INV_SUCCESS or non-zero error code. |
| **/ |
| inv_error_t inv_set_full_scale(float fullScale) |
| { |
| if (fullScale == 250.f) |
| mldlCfg.full_scale = MPU_FS_250DPS; |
| else if (fullScale == 500.f) |
| mldlCfg.full_scale = MPU_FS_500DPS; |
| else if (fullScale == 1000.f) |
| mldlCfg.full_scale = MPU_FS_1000DPS; |
| else if (fullScale == 2000.f) |
| mldlCfg.full_scale = MPU_FS_2000DPS; |
| else { // not a valid setting |
| MPL_LOGE("Invalid full scale range specification for gyros : %f\n", |
| fullScale); |
| MPL_LOGE |
| ("\tAvailable values : +/- 250 dps, +/- 500 dps, +/- 1000 dps, +/- 2000 dps\n"); |
| return INV_ERROR_INVALID_PARAMETER; |
| } |
| mldlCfg.gyro_needs_reset = TRUE; |
| |
| return INV_SUCCESS; |
| } |
| |
| /** |
| * @brief This function sets the external sync for the MPU sampling. |
| * It can be synchronized on the LSB of any of the gyros, any of the |
| * external accels, or on the temp readings. |
| * |
| * @param extSync External sync selection, 0 to 7. |
| * @return Zero if the command is successful; an error code otherwise. |
| **/ |
| inv_error_t inv_set_external_sync(unsigned char extSync) |
| { |
| INVENSENSE_FUNC_START; |
| |
| /*---- do range checking ----*/ |
| if (extSync >= NUM_MPU_EXT_SYNC) { |
| return INV_ERROR_INVALID_PARAMETER; |
| } |
| mldlCfg.ext_sync = extSync; |
| mldlCfg.gyro_needs_reset = TRUE; |
| |
| return INV_SUCCESS; |
| } |
| |
| inv_error_t inv_set_ignore_system_suspend(unsigned char ignore) |
| { |
| INVENSENSE_FUNC_START; |
| |
| mldlCfg.ignore_system_suspend = ignore; |
| |
| return INV_SUCCESS; |
| } |
| |
| /** |
| * @brief inv_clock_source function sets the clock source for the MPU gyro |
| * processing. |
| * The source can be any of the following: |
| * - Internal 8MHz oscillator, |
| * - PLL with X gyro as reference, |
| * - PLL with Y gyro as reference, |
| * - PLL with Z gyro as reference, |
| * - PLL with external 32.768Mhz reference, or |
| * - PLL with external 19.2MHz reference |
| * |
| * For best accuracy and timing, it is highly recommended to use one |
| * of the gyros as the clock source; however this gyro must be |
| * enabled to use its clock (see 'MLDLPowerMgmtMPU()'). |
| * |
| * @param clkSource Clock source selection. |
| * Can be one of: |
| * - CLK_INTERNAL, |
| * - CLK_PLLGYROX, |
| * - CLK_PLLGYROY, |
| * - CLK_PLLGYROZ, |
| * - CLK_PLLEXT32K, or |
| * - CLK_PLLEXT19M. |
| * |
| * @return Zero if the command is successful; an error code otherwise. |
| **/ |
| inv_error_t inv_clock_source(unsigned char clkSource) |
| { |
| INVENSENSE_FUNC_START; |
| |
| /*---- do range checking ----*/ |
| if (clkSource >= NUM_CLK_SEL) { |
| return INV_ERROR_INVALID_PARAMETER; |
| } |
| |
| mldlCfg.clk_src = clkSource; |
| mldlCfg.gyro_needs_reset = TRUE; |
| |
| return INV_SUCCESS; |
| } |
| |
| /** |
| * @brief Set the Temperature Compensation offset. |
| * @param tc |
| * a pointer to the temperature compensations offset |
| * for the 3 gyro axes. |
| * @return INV_SUCCESS if successful, a non-zero error code otherwise. |
| */ |
| inv_error_t inv_set_offsetTC(const unsigned char *tc) |
| { |
| int ii; |
| inv_error_t result; |
| |
| for (ii = 0; ii < ARRAY_SIZE(mldlCfg.offset_tc); ii++) { |
| mldlCfg.offset_tc[ii] = tc[ii]; |
| } |
| |
| if (!mldlCfg.gyro_is_suspended) { |
| #ifdef CONFIG_MPU_SENSORS_MPU3050 |
| result = inv_serial_single_write(sMLSLHandle, mldlCfg.addr, |
| MPUREG_XG_OFFS_TC, tc[0]); |
| if (result) { |
| LOG_RESULT_LOCATION(result); |
| return result; |
| } |
| result = inv_serial_single_write(sMLSLHandle, mldlCfg.addr, |
| MPUREG_YG_OFFS_TC, tc[1]); |
| if (result) { |
| LOG_RESULT_LOCATION(result); |
| return result; |
| } |
| result = inv_serial_single_write(sMLSLHandle, mldlCfg.addr, |
| MPUREG_ZG_OFFS_TC, tc[2]); |
| if (result) { |
| LOG_RESULT_LOCATION(result); |
| return result; |
| } |
| #else |
| unsigned char reg; |
| result = inv_serial_single_write(sMLSLHandle, mldlCfg.addr, |
| MPUREG_XG_OFFS_TC, |
| ((mldlCfg.offset_tc[0] << 1) |
| & BITS_XG_OFFS_TC)); |
| if (result) { |
| LOG_RESULT_LOCATION(result); |
| return result; |
| } |
| reg = ((mldlCfg.offset_tc[1] << 1) & BITS_YG_OFFS_TC); |
| #ifdef CONFIG_MPU_SENSORS_MPU6050B1 |
| if (mldlCfg.pdata->level_shifter) |
| reg |= BIT_I2C_MST_VDDIO; |
| #endif |
| result = inv_serial_single_write(sMLSLHandle, mldlCfg.addr, |
| MPUREG_YG_OFFS_TC, reg); |
| if (result) { |
| LOG_RESULT_LOCATION(result); |
| return result; |
| } |
| result = inv_serial_single_write(sMLSLHandle, mldlCfg.addr, |
| MPUREG_ZG_OFFS_TC, |
| ((mldlCfg.offset_tc[2] << 1) |
| & BITS_ZG_OFFS_TC)); |
| if (result) { |
| LOG_RESULT_LOCATION(result); |
| return result; |
| } |
| #endif |
| } else { |
| mldlCfg.gyro_needs_reset = TRUE; |
| } |
| return INV_SUCCESS; |
| } |
| |
| /** |
| * @brief Set the gyro offset. |
| * @param offset |
| * a pointer to the gyro offset for the 3 gyro axes. This is scaled |
| * as it would be written to the hardware registers. |
| * @return INV_SUCCESS if successful, a non-zero error code otherwise. |
| */ |
| inv_error_t inv_set_offset(const short *offset) |
| { |
| inv_error_t result; |
| unsigned char regs[7]; |
| int ii; |
| long sf; |
| |
| sf = (2000L * 131) / mldlCfg.gyro_sens_trim; |
| for (ii = 0; ii < ARRAY_SIZE(mldlCfg.offset); ii++) { |
| // Record the bias in the units the register uses |
| mldlCfg.offset[ii] = offset[ii]; |
| // Convert the bias to 1 dps = 1<<16 |
| inv_obj.gyro_bias[ii] = -offset[ii] * sf; |
| regs[1 + ii * 2] = (unsigned char)(offset[ii] >> 8) & 0xff; |
| regs[1 + ii * 2 + 1] = (unsigned char)(offset[ii] & 0xff); |
| } |
| |
| if (!mldlCfg.gyro_is_suspended) { |
| regs[0] = MPUREG_X_OFFS_USRH; |
| result = inv_serial_write(sMLSLHandle, mldlCfg.addr, 7, regs); |
| if (result) { |
| LOG_RESULT_LOCATION(result); |
| return result; |
| } |
| } else { |
| mldlCfg.gyro_needs_reset = TRUE; |
| } |
| return INV_SUCCESS; |
| } |
| |
| /** |
| * @internal |
| * @brief used to get the specified number of bytes in the specified MPU |
| * memory bank. |
| * The memory bank is one of the following: |
| * - MPUMEM_RAM_BANK_0, |
| * - MPUMEM_RAM_BANK_1, |
| * - MPUMEM_RAM_BANK_2, or |
| * - MPUMEM_RAM_BANK_3. |
| * |
| * @param bank Memory bank to write. |
| * @param memAddr Starting address for write. |
| * @param length Number of bytes to write. |
| * @param buffer Result for data. |
| * |
| * @return zero if the command is successful, an error code otherwise. |
| * @endif |
| */ |
| inv_error_t |
| inv_get_mpu_memory_one_bank(unsigned char bank, |
| unsigned char memAddr, |
| unsigned short length, unsigned char *buffer) |
| { |
| inv_error_t result; |
| |
| if ((bank >= MPU_MEM_NUM_RAM_BANKS) || |
| //(memAddr >= MPU_MEM_BANK_SIZE) || always 0, memAddr is an u_char, therefore limited to 255 |
| ((memAddr + length) > MPU_MEM_BANK_SIZE) || (NULL == buffer)) { |
| return INV_ERROR_INVALID_PARAMETER; |
| } |
| |
| if (mldlCfg.gyro_is_suspended) { |
| memcpy(buffer, &mldlCfg.ram[bank][memAddr], length); |
| result = INV_SUCCESS; |
| } else { |
| result = inv_serial_read_mem(sMLSLHandle, mldlCfg.addr, |
| ((bank << 8) | memAddr), length, buffer); |
| if (result) { |
| LOG_RESULT_LOCATION(result); |
| return result; |
| } |
| } |
| |
| return result; |
| } |
| |
| /** |
| * @internal |
| * @brief used to set the specified number of bytes in the specified MPU |
| * memory bank. |
| * The memory bank is one of the following: |
| * - MPUMEM_RAM_BANK_0, |
| * - MPUMEM_RAM_BANK_1, |
| * - MPUMEM_RAM_BANK_2, or |
| * - MPUMEM_RAM_BANK_3. |
| * |
| * @param bank Memory bank to write. |
| * @param memAddr Starting address for write. |
| * @param length Number of bytes to write. |
| * @param buffer Result for data. |
| * |
| * @return zero if the command is successful, an error code otherwise. |
| * @endif |
| */ |
| inv_error_t inv_set_mpu_memory_one_bank(unsigned char bank, |
| unsigned short memAddr, |
| unsigned short length, |
| const unsigned char *buffer) |
| { |
| inv_error_t result = INV_SUCCESS; |
| int different; |
| |
| if ((bank >= MPU_MEM_NUM_RAM_BANKS) || (memAddr >= MPU_MEM_BANK_SIZE) || |
| ((memAddr + length) > MPU_MEM_BANK_SIZE) || (NULL == buffer)) { |
| return INV_ERROR_INVALID_PARAMETER; |
| } |
| |
| different = memcmp(&mldlCfg.ram[bank][memAddr], buffer, length); |
| memcpy(&mldlCfg.ram[bank][memAddr], buffer, length); |
| if (!mldlCfg.gyro_is_suspended) { |
| result = inv_serial_write_mem(sMLSLHandle, mldlCfg.addr, |
| ((bank << 8) | memAddr), length, buffer); |
| if (result) { |
| LOG_RESULT_LOCATION(result); |
| return result; |
| } |
| } else if (different) { |
| mldlCfg.gyro_needs_reset = TRUE; |
| } |
| |
| return result; |
| } |
| |
| /** |
| * @internal |
| * @brief used to get the specified number of bytes from the MPU location |
| * specified by the key. |
| * Reads the specified number of bytes from the MPU location |
| * specified by the key. Each set of code specifies a function |
| * that changes keys into addresses. This function is set with |
| * setGetAddress(). |
| * |
| * @param key The key to use when looking up the address. |
| * @param length Number of bytes to read. |
| * @param buffer Result for data. |
| * |
| * @return INV_SUCCESS if the command is successful, INV_ERROR otherwise. The key |
| * not corresponding to a memory address will result in INV_ERROR. |
| * @endif |
| */ |
| inv_error_t inv_get_mpu_memory(unsigned short key, |
| unsigned short length, unsigned char *buffer) |
| { |
| unsigned char bank; |
| inv_error_t result; |
| unsigned short memAddr; |
| |
| if (sGetAddress == NULL) { |
| return INV_ERROR_NOT_OPENED; |
| } |
| |
| memAddr = sGetAddress(key); |
| if (memAddr >= 0xffff) |
| return INV_ERROR_FEATURE_NOT_IMPLEMENTED; |
| bank = memAddr >> 8; // Get Bank |
| memAddr &= 0xff; |
| |
| while (memAddr + length > MPU_MEM_BANK_SIZE) { |
| // We cross a bank in the middle |
| unsigned short sub_length = MPU_MEM_BANK_SIZE - memAddr; |
| result = inv_get_mpu_memory_one_bank(bank, (unsigned char)memAddr, |
| sub_length, buffer); |
| if (INV_SUCCESS != result) |
| return result; |
| bank++; |
| length -= sub_length; |
| buffer += sub_length; |
| memAddr = 0; |
| } |
| result = inv_get_mpu_memory_one_bank(bank, (unsigned char)memAddr, |
| length, buffer); |
| |
| if (result) { |
| LOG_RESULT_LOCATION(result); |
| return result; |
| } |
| |
| return result; |
| } |
| |
| /** |
| * @internal |
| * @brief used to set the specified number of bytes from the MPU location |
| * specified by the key. |
| * Set the specified number of bytes from the MPU location |
| * specified by the key. Each set of DMP code specifies a function |
| * that changes keys into addresses. This function is set with |
| * setGetAddress(). |
| * |
| * @param key The key to use when looking up the address. |
| * @param length Number of bytes to write. |
| * @param buffer Result for data. |
| * |
| * @return INV_SUCCESS if the command is successful, INV_ERROR otherwise. The key |
| * not corresponding to a memory address will result in INV_ERROR. |
| * @endif |
| */ |
| inv_error_t inv_set_mpu_memory(unsigned short key, |
| unsigned short length, |
| const unsigned char *buffer) |
| { |
| inv_error_t result = INV_SUCCESS; |
| unsigned short memAddr; |
| unsigned char bank; |
| |
| if (sGetAddress == NULL) { |
| MPL_LOGE("MLDSetMemoryMPU sGetAddress is NULL\n"); |
| return INV_ERROR_INVALID_MODULE; |
| } |
| memAddr = sGetAddress(key); |
| |
| if (memAddr >= 0xffff) { |
| MPL_LOGE("inv_set_mpu_memory unsupported key\n"); |
| return INV_ERROR_INVALID_MODULE; // This key not supported |
| } |
| |
| bank = (unsigned char)(memAddr >> 8); |
| memAddr &= 0xff; |
| |
| while (memAddr + length > MPU_MEM_BANK_SIZE) { |
| // We cross a bank in the middle |
| unsigned short sub_length = MPU_MEM_BANK_SIZE - memAddr; |
| |
| result = inv_set_mpu_memory_one_bank(bank, memAddr, sub_length, buffer); |
| if (result) { |
| LOG_RESULT_LOCATION(result); |
| return result; |
| } |
| |
| bank++; |
| length -= sub_length; |
| buffer += sub_length; |
| memAddr = 0; |
| } |
| result = inv_set_mpu_memory_one_bank(bank, memAddr, length, buffer); |
| if (result) { |
| LOG_RESULT_LOCATION(result); |
| return result; |
| } |
| return result; |
| } |
| |
| /** |
| * @brief Load the DMP with the given code and configuration. |
| * @param buffer |
| * the DMP data. |
| * @param length |
| * the length in bytes of the DMP data. |
| * @param config |
| * the DMP configuration. |
| * @return INV_SUCCESS if successful, a non-zero error code otherwise. |
| */ |
| inv_error_t inv_load_dmp(const unsigned char *buffer, |
| unsigned short length, unsigned short config) |
| { |
| INVENSENSE_FUNC_START; |
| |
| inv_error_t result = INV_SUCCESS; |
| unsigned short toWrite; |
| unsigned short memAddr = 0; |
| localDmpMemory = buffer; |
| localDmpMemorySize = length; |
| |
| mldlCfg.dmp_cfg1 = (config >> 8); |
| mldlCfg.dmp_cfg2 = (config & 0xff); |
| |
| while (length > 0) { |
| toWrite = length; |
| if (toWrite > MAX_LOAD_WRITE_SIZE) |
| toWrite = MAX_LOAD_WRITE_SIZE; |
| |
| result = |
| inv_set_mpu_memory_one_bank(memAddr >> 8, memAddr & 0xff, toWrite, |
| buffer); |
| if (result) { |
| LOG_RESULT_LOCATION(result); |
| return result; |
| } |
| |
| buffer += toWrite; |
| memAddr += toWrite; |
| length -= toWrite; |
| } |
| |
| return result; |
| } |
| |
| /** |
| * @brief Get the silicon revision ID. |
| * @return The silicon revision ID |
| * (0 will be read if inv_mpu_open returned an error) |
| */ |
| unsigned char inv_get_silicon_rev(void) |
| { |
| return mldlCfg.silicon_revision; |
| } |
| |
| /** |
| * @brief Get the product revision ID. |
| * @return The product revision ID |
| * (0 will be read if inv_mpu_open returned an error) |
| */ |
| unsigned char inv_get_product_rev(void) |
| { |
| return mldlCfg.product_revision; |
| } |
| |
| /******************************************************************************* |
| ******************************************************************************* |
| ******************************************************************************* |
| * @todo these belong with an interface to the kernel driver layer |
| ******************************************************************************* |
| ******************************************************************************* |
| ******************************************************************************/ |
| |
| /** |
| * @brief inv_get_interrupt_status returns the interrupt status from the specified |
| * interrupt pin. |
| * @param intPin |
| * Currently only the value INTPIN_MPU is supported. |
| * @param status |
| * The available statuses are: |
| * - BIT_MPU_RDY_EN |
| * - BIT_DMP_INT_EN |
| * - BIT_RAW_RDY_EN |
| * |
| * @return INV_SUCCESS or a non-zero error code. |
| */ |
| inv_error_t inv_get_interrupt_status(unsigned char intPin, |
| unsigned char *status) |
| { |
| INVENSENSE_FUNC_START; |
| |
| inv_error_t result; |
| |
| switch (intPin) { |
| |
| case INTPIN_MPU: |
| /*---- return the MPU interrupt status ----*/ |
| result = inv_serial_read(sMLSLHandle, mldlCfg.addr, |
| MPUREG_INT_STATUS, 1, status); |
| break; |
| |
| default: |
| result = INV_ERROR_INVALID_PARAMETER; |
| break; |
| } |
| |
| return result; |
| } |
| |
| /** |
| * @brief query the current status of an interrupt source. |
| * @param srcIndex |
| * index of the interrupt source. |
| * Currently the only source supported is INTPIN_MPU. |
| * |
| * @return 1 if the interrupt has been triggered. |
| */ |
| unsigned char inv_get_interrupt_trigger(unsigned char srcIndex) |
| { |
| INVENSENSE_FUNC_START; |
| return intTrigger[srcIndex]; |
| } |
| |
| /** |
| * @brief clear the 'triggered' status for an interrupt source. |
| * @param srcIndex |
| * index of the interrupt source. |
| * Currently only INTPIN_MPU is supported. |
| */ |
| void inv_clear_interrupt_trigger(unsigned char srcIndex) |
| { |
| INVENSENSE_FUNC_START; |
| intTrigger[srcIndex] = 0; |
| } |
| |
| /** |
| * @brief inv_interrupt_handler function should be called when an interrupt is |
| * received. The source parameter identifies which interrupt source |
| * caused the interrupt. Note that this routine should not be called |
| * directly from the interrupt service routine. |
| * |
| * @param intSource MPU, AUX1, AUX2, or timer. Can be one of: INTSRC_MPU, INTSRC_AUX1, |
| * INTSRC_AUX2, or INT_SRC_TIMER. |
| * |
| * @return Zero if the command is successful; an error code otherwise. |
| */ |
| inv_error_t inv_interrupt_handler(unsigned char intSource) |
| { |
| INVENSENSE_FUNC_START; |
| /*---- range check ----*/ |
| if (intSource >= NUM_OF_INTSOURCES) { |
| return INV_ERROR; |
| } |
| |
| /*---- save source of interrupt ----*/ |
| intTrigger[intSource] = INT_TRIGGERED; |
| |
| #ifdef ML_USE_DMP_SIM |
| if (intSource == INTSRC_AUX1 || intSource == INTSRC_TIMER) { |
| MLSimHWDataInput(); |
| } |
| #endif |
| |
| return INV_SUCCESS; |
| } |
| |
| /***************************/ |
| /**@}*//* end of defgroup */ |
| /***************************/ |