diff options
author | Scott Warner <Tortel1210@gmail.com> | 2015-10-11 08:30:01 -0400 |
---|---|---|
committer | Scott Warner <Tortel1210@gmail.com> | 2015-10-12 09:40:33 -0400 |
commit | 901b63272e2eb758fe2f4a588e6e9f308fe50f6c (patch) | |
tree | eefd9603dc5f829b80bc7bb116e9de5ba4297714 /60xx/mlsdk/mlutils/mputest.c | |
parent | e0c1691f695f828608c36315fa405db2fa8d153e (diff) | |
download | android_hardware_invensense-901b63272e2eb758fe2f4a588e6e9f308fe50f6c.tar.gz android_hardware_invensense-901b63272e2eb758fe2f4a588e6e9f308fe50f6c.tar.bz2 android_hardware_invensense-901b63272e2eb758fe2f4a588e6e9f308fe50f6c.zip |
Revert "Remove files for unsupported devices."
This reverts commit f5f584ee173faef40f226c6e0e8580a2ecbe079b.
Change-Id: I4e1b41922b5ccaac2314dac7f43df5740e2e9361
Diffstat (limited to '60xx/mlsdk/mlutils/mputest.c')
-rw-r--r-- | 60xx/mlsdk/mlutils/mputest.c | 1396 |
1 files changed, 1396 insertions, 0 deletions
diff --git a/60xx/mlsdk/mlutils/mputest.c b/60xx/mlsdk/mlutils/mputest.c new file mode 100644 index 0000000..ac0fa30 --- /dev/null +++ b/60xx/mlsdk/mlutils/mputest.c @@ -0,0 +1,1396 @@ +/* + $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: mputest.c 5637 2011-06-14 01:13:53Z mcaramello $ + * + *****************************************************************************/ + +/* + * MPU Self Test functions + * Version 2.4 + * May 13th, 2011 + */ + +/** + * @defgroup MPU_SELF_TEST + * @brief MPU Self Test functions + * + * These functions provide an in-site test of the MPU 3xxx chips. The main + * entry point is the inv_mpu_test function. + * This runs the tests (as described in the accompanying documentation) and + * writes a configuration file containing initial calibration data. + * inv_mpu_test returns INV_SUCCESS if the chip passes the tests. + * Otherwise, an error code is returned. + * The functions in this file rely on MLSL and MLOS: refer to the MPL + * documentation for more information regarding the system interface + * files. + * + * @{ + * @file mputest.c + * @brief MPU Self Test routines for assessing gyro sensor status + * after surface mount has happened on the target host platform. + */ + +#include <stdio.h> +#include <time.h> +#include <string.h> +#include <math.h> +#include <stdlib.h> +#ifdef LINUX +#include <unistd.h> +#endif + +#include "mpu.h" +#include "mldl.h" +#include "mldl_cfg.h" +#include "accel.h" +#include "mlFIFO.h" +#include "slave.h" +#include "ml.h" +#include "ml_stored_data.h" +#include "checksum.h" + +#include "mlsl.h" +#include "mlos.h" + +#include "log.h" +#undef MPL_LOG_TAG +#define MPL_LOG_TAG "MPL-mpust" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + Defines +*/ + +#define VERBOSE_OUT 0 + +/*#define TRACK_IDS*/ + +/*--- Test parameters defaults. See set_test_parameters for more details ---*/ + +#define DEF_MPU_ADDR (0x68) /* I2C address of the mpu */ + +#if (USE_SENSE_PATH_TEST == 1) /* gyro full scale dps */ +#define DEF_GYRO_FULLSCALE (2000) +#else +#define DEF_GYRO_FULLSCALE (250) +#endif + +#define DEF_GYRO_SENS (32768.f / DEF_GYRO_FULLSCALE) + /* gyro sensitivity LSB/dps */ +#define DEF_PACKET_THRESH (75) /* 600 ms / 8ms / sample */ +#define DEF_TOTAL_TIMING_TOL (.03f) /* 3% = 2 pkts + 1% proc tol. */ +#define DEF_BIAS_THRESH (40 * DEF_GYRO_SENS) + /* 40 dps in LSBs */ +#define DEF_RMS_THRESH (0.4f * DEF_GYRO_SENS) + /* 0.4 dps-rms in LSB-rms */ +#define DEF_SP_SHIFT_THRESH_CUST (.05f) /* 5% */ +#define DEF_TEST_TIME_PER_AXIS (600) /* ms of time spent collecting + data for each axis, + multiple of 600ms */ +#define DEF_N_ACCEL_SAMPLES (20) /* num of accel samples to + average from, if applic. */ + +#define ML_INIT_CAL_LEN (36) /* length in bytes of + calibration data file */ + +/* + Macros +*/ + +#define CHECK_TEST_ERROR(x) \ + if (x) { \ + MPL_LOGI("error %d @ %s|%d\n", x, __func__, __LINE__); \ + return (-1); \ + } + +#define SHORT_TO_TEMP_C(shrt) (((shrt+13200.f)/280.f)+35.f) + +#define USHORT_TO_CHARS(chr,shrt) (chr)[0]=(unsigned char)(shrt>>8); \ + (chr)[1]=(unsigned char)(shrt); + +#define UINT_TO_CHARS(chr,ui) (chr)[0]=(unsigned char)(ui>>24); \ + (chr)[1]=(unsigned char)(ui>>16); \ + (chr)[2]=(unsigned char)(ui>>8); \ + (chr)[3]=(unsigned char)(ui); + +#define FLOAT_TO_SHORT(f) ( \ + (fabs(f-(short)f)>=0.5) ? ( \ + ((short)f)+(f<0?(-1):(+1))) : \ + ((short)f) \ + ) + +#define CHARS_TO_SHORT(d) ((((short)(d)[0])<<8)+(d)[1]) +#define CHARS_TO_SHORT_SWAPPED(d) ((((short)(d)[1])<<8)+(d)[0]) + +#define ACCEL_UNPACK(d) d[0], d[1], d[2], d[3], d[4], d[5] + +#define CHECK_NACKS(d) ( \ + d[0]==0xff && d[1]==0xff && \ + d[2]==0xff && d[3]==0xff && \ + d[4]==0xff && d[5]==0xff \ + ) + +/* + Prototypes +*/ + +static inv_error_t test_get_data( + void *mlsl_handle, + struct mldl_cfg *mputestCfgPtr, + short *vals); + +/* + Types +*/ +typedef struct { + float gyro_sens; + int gyro_fs; + int packet_thresh; + float total_timing_tol; + int bias_thresh; + float rms_threshSq; + float sp_shift_thresh; + unsigned int test_time_per_axis; + unsigned short accel_samples; +} tTestSetup; + +/* + Global variables +*/ +static unsigned char dataout[20]; +static unsigned char dataStore[ML_INIT_CAL_LEN]; + +static tTestSetup test_setup = { + DEF_GYRO_SENS, + DEF_GYRO_FULLSCALE, + DEF_PACKET_THRESH, + DEF_TOTAL_TIMING_TOL, + (int)DEF_BIAS_THRESH, + DEF_RMS_THRESH * DEF_RMS_THRESH, + DEF_SP_SHIFT_THRESH_CUST, + DEF_TEST_TIME_PER_AXIS, + DEF_N_ACCEL_SAMPLES +}; + +static float adjGyroSens; +static char a_name[3][2] = {"X", "Y", "Z"}; + +/* + NOTE : modify get_slave_descr parameter below to reflect + the DEFAULT accelerometer in use. The accelerometer in use + can be modified at run-time using the inv_test_setup_accel API. + NOTE : modify the expected z axis orientation (Z axis pointing + upward or downward) +*/ + +signed char g_z_sign = +1; +struct mldl_cfg *mputestCfgPtr = NULL; + +#ifndef LINUX +/** + * @internal + * @brief usec precision sleep function. + * @param number of micro seconds (us) to sleep for. + */ +static void usleep(unsigned long t) +{ + unsigned long start = inv_get_tick_count(); + while (inv_get_tick_count()-start < t / 1000); +} +#endif + +/** + * @brief Modify the self test limits from their default values. + * + * @param slave_addr + * the slave address the MPU device is setup to respond at. + * The default is DEF_MPU_ADDR = 0x68. + * @param sensitivity + * the read sensitivity of the device in LSB/dps as it is trimmed. + * NOTE : if using the self test as part of the MPL, the + * sensitivity the different sensitivity trims are already + * taken care of. + * @param p_thresh + * number of packets expected to be received in a 600 ms period. + * Depends on the sampling frequency of choice (set by default to + * 125 Hz) and low pass filter cut-off frequency selection (set + * to 42 Hz). + * The default is DEF_PACKET_THRESH = 75 packets. + * @param total_time_tol + * time skew tolerance, taking into account imprecision in turning + * the FIFO on and off and the processor time imprecision (for + * 1 GHz processor). + * The default is DEF_TOTAL_TIMING_TOL = 3 %, about 2 packets. + * @param bias_thresh + * bias level threshold, the maximun acceptable no motion bias + * for a production quality part. + * The default is DEF_BIAS_THRESH = 40 dps. + * @param rms_thresh + * the limit standard deviation (=~ RMS) set to assess whether + * the noise level on the part is acceptable. + * The default is DEF_RMS_THRESH = 0.2 dps-rms. + * @param sp_shift_thresh + * the limit shift applicable to the Sense Path self test + * calculation. + */ +void inv_set_test_parameters(unsigned int slave_addr, float sensitivity, + int p_thresh, float total_time_tol, + int bias_thresh, float rms_thresh, + float sp_shift_thresh, + unsigned short accel_samples) +{ + mputestCfgPtr->addr = slave_addr; + test_setup.gyro_sens = sensitivity; + test_setup.gyro_fs = (int)(32768.f / sensitivity); + test_setup.packet_thresh = p_thresh; + test_setup.total_timing_tol = total_time_tol; + test_setup.bias_thresh = bias_thresh; + test_setup.rms_threshSq = rms_thresh * rms_thresh; + test_setup.sp_shift_thresh = sp_shift_thresh; + test_setup.accel_samples = accel_samples; +} + +#define X (0) +#define Y (1) +#define Z (2) + +#ifdef CONFIG_MPU_SENSORS_MPU3050 +/** + * @brief Test the gyroscope sensor. + * Implements the core logic of the MPU Self Test. + * Produces the PASS/FAIL result. Loads the calculated gyro biases + * and temperature datum into the corresponding pointers. + * @param mlsl_handle + * serial interface handle to allow serial communication with the + * device, both gyro and accelerometer. + * @param gyro_biases + * output pointer to store the initial bias calculation provided + * by the MPU Self Test. Requires 3 elements for gyro X, Y, + * and Z. + * @param temp_avg + * output pointer to store the initial average temperature as + * provided by the MPU Self Test. + * @param perform_full_test + * If 1: + * calculates offset, drive frequency, and noise and compare it + * against set thresholds. + * Report also the final result using a bit-mask like error code + * as explained in return value description. + * When 0: + * skip the noise and drive frequency calculation and pass/fail + * assessment; simply calculates the gyro biases. + * + * @return 0 on success. + * On error, the return value is a bitmask representing: + * 0, 1, 2 Failures with PLLs on X, Y, Z gyros respectively + * (decimal values will be 1, 2, 4 respectively). + * 3, 4, 5 Excessive offset with X, Y, Z gyros respectively + * (decimal values will be 8, 16, 32 respectively). + * 6, 7, 8 Excessive noise with X, Y, Z gyros respectively + * (decimal values will be 64, 128, 256 respectively). + * 9 If any of the RMS noise values is zero, it could be + * due to a non-functional gyro or FIFO/register failure. + * (decimal value will be 512). + * (decimal values will be 1024, 2048, 4096 respectively). + */ +int inv_test_gyro_3050(void *mlsl_handle, + short gyro_biases[3], short *temp_avg, + uint_fast8_t perform_full_test) +{ + int retVal = 0; + inv_error_t result; + + int total_count = 0; + int total_count_axis[3] = {0, 0, 0}; + int packet_count; + short x[DEF_TEST_TIME_PER_AXIS / 8 * 4] = {0}; + short y[DEF_TEST_TIME_PER_AXIS / 8 * 4] = {0}; + short z[DEF_TEST_TIME_PER_AXIS / 8 * 4] = {0}; + unsigned char regs[7]; + + int temperature; + float Avg[3]; + float RMS[3]; + int i, j, tmp; + char tmpStr[200]; + + temperature = 0; + + /* sample rate = 8ms */ + result = inv_serial_single_write( + mlsl_handle, mputestCfgPtr->addr, + MPUREG_SMPLRT_DIV, 0x07); + CHECK_TEST_ERROR(result); + + regs[0] = 0x03; /* filter = 42Hz, analog_sample rate = 1 KHz */ + switch (DEF_GYRO_FULLSCALE) { + case 2000: + regs[0] |= 0x18; + break; + case 1000: + regs[0] |= 0x10; + break; + case 500: + regs[0] |= 0x08; + break; + case 250: + default: + regs[0] |= 0x00; + break; + } + result = inv_serial_single_write( + mlsl_handle, mputestCfgPtr->addr, + MPUREG_DLPF_FS_SYNC, regs[0]); + CHECK_TEST_ERROR(result); + result = inv_serial_single_write( + mlsl_handle, mputestCfgPtr->addr, + MPUREG_INT_CFG, 0x00); + CHECK_TEST_ERROR(result); + + /* 1st, timing test */ + for (j = 0; j < 3; j++) { + + MPL_LOGI("Collecting gyro data from %s gyro PLL\n", a_name[j]); + + /* turn on all gyros, use gyro X for clocking + Set to Y and Z for 2nd and 3rd iteration */ + result = inv_serial_single_write( + mlsl_handle, mputestCfgPtr->addr, + MPUREG_PWR_MGM, j + 1); + CHECK_TEST_ERROR(result); + + /* wait for 2 ms after switching clock source */ + usleep(2000); + + /* we will enable XYZ gyro in FIFO and nothing else */ + result = inv_serial_single_write( + mlsl_handle, mputestCfgPtr->addr, + MPUREG_FIFO_EN2, 0x00); + CHECK_TEST_ERROR(result); + /* enable/reset FIFO */ + result = inv_serial_single_write( + mlsl_handle, mputestCfgPtr->addr, + MPUREG_USER_CTRL, BIT_FIFO_EN | BIT_FIFO_RST); + CHECK_TEST_ERROR(result); + + tmp = (int)(test_setup.test_time_per_axis / 600); + while (tmp-- > 0) { + /* enable XYZ gyro in FIFO and nothing else */ + result = inv_serial_single_write(mlsl_handle, + mputestCfgPtr->addr, MPUREG_FIFO_EN1, + BIT_GYRO_XOUT | BIT_GYRO_YOUT | BIT_GYRO_ZOUT); + CHECK_TEST_ERROR(result); + + /* wait for 600 ms for data */ + usleep(600000); + + /* stop storing gyro in the FIFO */ + result = inv_serial_single_write( + mlsl_handle, mputestCfgPtr->addr, + MPUREG_FIFO_EN1, 0x00); + CHECK_TEST_ERROR(result); + + /* Getting number of bytes in FIFO */ + result = inv_serial_read( + mlsl_handle, mputestCfgPtr->addr, + MPUREG_FIFO_COUNTH, 2, dataout); + CHECK_TEST_ERROR(result); + /* number of 6 B packets in the FIFO */ + packet_count = CHARS_TO_SHORT(dataout) / 6; + sprintf(tmpStr, "Packet Count: %d - ", packet_count); + + if ( abs(packet_count - test_setup.packet_thresh) + <= /* Within +/- total_timing_tol % range */ + test_setup.total_timing_tol * test_setup.packet_thresh) { + for (i = 0; i < packet_count; i++) { + /* getting FIFO data */ + result = inv_serial_read_fifo(mlsl_handle, + mputestCfgPtr->addr, 6, dataout); + CHECK_TEST_ERROR(result); + x[total_count + i] = CHARS_TO_SHORT(&dataout[0]); + y[total_count + i] = CHARS_TO_SHORT(&dataout[2]); + z[total_count + i] = CHARS_TO_SHORT(&dataout[4]); + if (VERBOSE_OUT) { + MPL_LOGI("Gyros %-4d : %+13d %+13d %+13d\n", + total_count + i, x[total_count + i], + y[total_count + i], z[total_count + i]); + } + } + total_count += packet_count; + total_count_axis[j] += packet_count; + sprintf(tmpStr, "%sOK", tmpStr); + } else { + if (perform_full_test) + retVal |= 1 << j; + sprintf(tmpStr, "%sNOK - samples ignored", tmpStr); + } + MPL_LOGI("%s\n", tmpStr); + } + + /* remove gyros from FIFO */ + result = inv_serial_single_write( + mlsl_handle, mputestCfgPtr->addr, + MPUREG_FIFO_EN1, 0x00); + CHECK_TEST_ERROR(result); + + /* Read Temperature */ + result = inv_serial_read(mlsl_handle, mputestCfgPtr->addr, + MPUREG_TEMP_OUT_H, 2, dataout); + CHECK_TEST_ERROR(result); + temperature += (short)CHARS_TO_SHORT(dataout); + } + + MPL_LOGI("\n"); + MPL_LOGI("Total %d samples\n", total_count); + MPL_LOGI("\n"); + + /* 2nd, check bias from X and Y PLL clock source */ + tmp = total_count != 0 ? total_count : 1; + for (i = 0, + Avg[X] = .0f, Avg[Y] = .0f, Avg[Z] = .0f; + i < total_count; i++) { + Avg[X] += 1.f * x[i] / tmp; + Avg[Y] += 1.f * y[i] / tmp; + Avg[Z] += 1.f * z[i] / tmp; + } + MPL_LOGI("bias : %+13.3f %+13.3f %+13.3f (LSB)\n", + Avg[X], Avg[Y], Avg[Z]); + if (VERBOSE_OUT) { + MPL_LOGI(" : %+13.3f %+13.3f %+13.3f (dps)\n", + Avg[X] / adjGyroSens, + Avg[Y] / adjGyroSens, + Avg[Z] / adjGyroSens); + } + if(perform_full_test) { + for (j = 0; j < 3; j++) { + if (fabs(Avg[j]) > test_setup.bias_thresh) { + MPL_LOGI("%s-Gyro bias (%.0f) exceeded threshold " + "(threshold = %d)\n", + a_name[j], Avg[j], test_setup.bias_thresh); + retVal |= 1 << (3+j); + } + } + } + + /* 3rd, check RMS */ + if (perform_full_test) { + for (i = 0, + RMS[X] = 0.f, RMS[Y] = 0.f, RMS[Z] = 0.f; + i < total_count; i++) { + RMS[X] += (x[i] - Avg[X]) * (x[i] - Avg[X]); + RMS[Y] += (y[i] - Avg[Y]) * (y[i] - Avg[Y]); + RMS[Z] += (z[i] - Avg[Z]) * (z[i] - Avg[Z]); + } + for (j = 0; j < 3; j++) { + if (RMS[j] > test_setup.rms_threshSq * total_count) { + MPL_LOGI("%s-Gyro RMS (%.2f) exceeded threshold " + "(threshold = %.2f)\n", + a_name[j], sqrt(RMS[j] / total_count), + sqrt(test_setup.rms_threshSq)); + retVal |= 1 << (6+j); + } + } + + MPL_LOGI("RMS : %+13.3f %+13.3f %+13.3f (LSB-rms)\n", + sqrt(RMS[X] / total_count), + sqrt(RMS[Y] / total_count), + sqrt(RMS[Z] / total_count)); + if (VERBOSE_OUT) { + MPL_LOGI("RMS ^ 2 : %+13.3f %+13.3f %+13.3f\n", + RMS[X] / total_count, + RMS[Y] / total_count, + RMS[Z] / total_count); + } + + if (RMS[X] == 0 || RMS[Y] == 0 || RMS[Z] == 0) { + /* If any of the RMS noise value returns zero, + then we might have dead gyro or FIFO/register failure, + the part is sleeping, or the part is not responsive */ + retVal |= 1 << 9; + } + } + + /* 4th, temperature average */ + temperature /= 3; + if (VERBOSE_OUT) + MPL_LOGI("Temperature : %+13.3f %13s %13s (deg. C)\n", + SHORT_TO_TEMP_C(temperature), "", ""); + + /* load into final storage */ + *temp_avg = (short)temperature; + gyro_biases[X] = FLOAT_TO_SHORT(Avg[X]); + gyro_biases[Y] = FLOAT_TO_SHORT(Avg[Y]); + gyro_biases[Z] = FLOAT_TO_SHORT(Avg[Z]); + + return retVal; +} + +#else /* CONFIG_MPU_SENSORS_MPU3050 */ + +/** + * @brief Test the gyroscope sensor. + * Implements the core logic of the MPU Self Test but does not provide + * a PASS/FAIL output as in the MPU-3050 implementation. + * @param mlsl_handle + * serial interface handle to allow serial communication with the + * device, both gyro and accelerometer. + * @param gyro_biases + * output pointer to store the initial bias calculation provided + * by the MPU Self Test. Requires 3 elements for gyro X, Y, + * and Z. + * @param temp_avg + * output pointer to store the initial average temperature as + * provided by the MPU Self Test. + * + * @return 0 on success. + * A non-zero error code on error. + */ +int inv_test_gyro_6050(void *mlsl_handle, + short gyro_biases[3], short *temp_avg) +{ + inv_error_t result; + + int total_count = 0; + int total_count_axis[3] = {0, 0, 0}; + int packet_count; + short x[DEF_TEST_TIME_PER_AXIS / 8 * 4] = {0}; + short y[DEF_TEST_TIME_PER_AXIS / 8 * 4] = {0}; + short z[DEF_TEST_TIME_PER_AXIS / 8 * 4] = {0}; + unsigned char regs[7]; + + int temperature = 0; + float Avg[3]; + int i, j, tmp; + char tmpStr[200]; + + /* sample rate = 8ms */ + result = inv_serial_single_write( + mlsl_handle, mputestCfgPtr->addr, + MPUREG_SMPLRT_DIV, 0x07); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + regs[0] = 0x03; /* filter = 42Hz, analog_sample rate = 1 KHz */ + switch (DEF_GYRO_FULLSCALE) { + case 2000: + regs[0] |= 0x18; + break; + case 1000: + regs[0] |= 0x10; + break; + case 500: + regs[0] |= 0x08; + break; + case 250: + default: + regs[0] |= 0x00; + break; + } + result = inv_serial_single_write( + mlsl_handle, mputestCfgPtr->addr, + MPUREG_CONFIG, regs[0]); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = inv_serial_single_write( + mlsl_handle, mputestCfgPtr->addr, + MPUREG_INT_ENABLE, 0x00); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + /* 1st, timing test */ + for (j = 0; j < 3; j++) { + MPL_LOGI("Collecting gyro data from %s gyro PLL\n", a_name[j]); + + /* turn on all gyros, use gyro X for clocking + Set to Y and Z for 2nd and 3rd iteration */ +#ifdef CONFIG_MPU_SENSORS_MPU6050A2 + result = inv_serial_single_write( + mlsl_handle, mputestCfgPtr->addr, + MPUREG_PWR_MGMT_1, BITS_PWRSEL | (j + 1)); +#else + result = inv_serial_single_write( + mlsl_handle, mputestCfgPtr->addr, + MPUREG_PWR_MGMT_1, j + 1); +#endif + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + /* wait for 2 ms after switching clock source */ + usleep(2000); + + /* enable/reset FIFO */ + result = inv_serial_single_write( + mlsl_handle, mputestCfgPtr->addr, + MPUREG_USER_CTRL, BIT_FIFO_EN | BIT_FIFO_RST); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + tmp = (int)(test_setup.test_time_per_axis / 600); + while (tmp-- > 0) { + /* enable XYZ gyro in FIFO and nothing else */ + result = inv_serial_single_write(mlsl_handle, + mputestCfgPtr->addr, MPUREG_FIFO_EN, + BIT_GYRO_XOUT | BIT_GYRO_YOUT | BIT_GYRO_ZOUT); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + /* wait for 600 ms for data */ + usleep(600000); + /* stop storing gyro in the FIFO */ + result = inv_serial_single_write( + mlsl_handle, mputestCfgPtr->addr, + MPUREG_FIFO_EN, 0x00); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + /* Getting number of bytes in FIFO */ + result = inv_serial_read( + mlsl_handle, mputestCfgPtr->addr, + MPUREG_FIFO_COUNTH, 2, dataout); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + /* number of 6 B packets in the FIFO */ + packet_count = CHARS_TO_SHORT(dataout) / 6; + sprintf(tmpStr, "Packet Count: %d - ", packet_count); + + if (abs(packet_count - test_setup.packet_thresh) + <= /* Within +/- total_timing_tol % range */ + test_setup.total_timing_tol * test_setup.packet_thresh) { + for (i = 0; i < packet_count; i++) { + /* getting FIFO data */ + result = inv_serial_read_fifo(mlsl_handle, + mputestCfgPtr->addr, 6, dataout); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + x[total_count + i] = CHARS_TO_SHORT(&dataout[0]); + y[total_count + i] = CHARS_TO_SHORT(&dataout[2]); + z[total_count + i] = CHARS_TO_SHORT(&dataout[4]); + if (VERBOSE_OUT) { + MPL_LOGI("Gyros %-4d : %+13d %+13d %+13d\n", + total_count + i, x[total_count + i], + y[total_count + i], z[total_count + i]); + } + } + total_count += packet_count; + total_count_axis[j] += packet_count; + sprintf(tmpStr, "%sOK", tmpStr); + } else { + sprintf(tmpStr, "%sNOK - samples ignored", tmpStr); + } + MPL_LOGI("%s\n", tmpStr); + } + + /* remove gyros from FIFO */ + result = inv_serial_single_write( + mlsl_handle, mputestCfgPtr->addr, + MPUREG_FIFO_EN, 0x00); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + /* Read Temperature */ + result = inv_serial_read(mlsl_handle, mputestCfgPtr->addr, + MPUREG_TEMP_OUT_H, 2, dataout); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + temperature += (short)CHARS_TO_SHORT(dataout); + } + + MPL_LOGI("\n"); + MPL_LOGI("Total %d samples\n", total_count); + MPL_LOGI("\n"); + + /* 2nd, check bias from X and Y PLL clock source */ + tmp = total_count != 0 ? total_count : 1; + for (i = 0, + Avg[X] = .0f, Avg[Y] = .0f, Avg[Z] = .0f; + i < total_count; i++) { + Avg[X] += 1.f * x[i] / tmp; + Avg[Y] += 1.f * y[i] / tmp; + Avg[Z] += 1.f * z[i] / tmp; + } + MPL_LOGI("bias : %+13.3f %+13.3f %+13.3f (LSB)\n", + Avg[X], Avg[Y], Avg[Z]); + if (VERBOSE_OUT) { + MPL_LOGI(" : %+13.3f %+13.3f %+13.3f (dps)\n", + Avg[X] / adjGyroSens, + Avg[Y] / adjGyroSens, + Avg[Z] / adjGyroSens); + } + + temperature /= 3; + if (VERBOSE_OUT) + MPL_LOGI("Temperature : %+13.3f %13s %13s (deg. C)\n", + SHORT_TO_TEMP_C(temperature), "", ""); + + /* load into final storage */ + *temp_avg = (short)temperature; + gyro_biases[X] = FLOAT_TO_SHORT(Avg[X]); + gyro_biases[Y] = FLOAT_TO_SHORT(Avg[Y]); + gyro_biases[Z] = FLOAT_TO_SHORT(Avg[Z]); + + return INV_SUCCESS; +} + +#endif /* CONFIG_MPU_SENSORS_MPU3050 */ + +#ifdef TRACK_IDS +/** + * @internal + * @brief Retrieve the unique MPU device identifier from the internal OTP + * bank 0 memory. + * @param mlsl_handle + * serial interface handle to allow serial communication with the + * device, both gyro and accelerometer. + * @return 0 on success, a non-zero error code from the serial layer on error. + */ +static inv_error_t test_get_mpu_id(void *mlsl_handle) +{ + inv_error_t result; + unsigned char otp0[8]; + + + result = + inv_serial_read_mem(mlsl_handle, mputestCfgPtr->addr, + (BIT_PRFTCH_EN | BIT_CFG_USER_BANK | MPU_MEM_OTP_BANK_0) << 8 | + 0x00, 6, otp0); + if (result) + goto close; + + MPL_LOGI("\n"); + MPL_LOGI("DIE_ID : %06X\n", + ((int)otp0[1] << 8 | otp0[0]) & 0x1fff); + MPL_LOGI("WAFER_ID : %06X\n", + (((int)otp0[2] << 8 | otp0[1]) & 0x03ff ) >> 5); + MPL_LOGI("A_LOT_ID : %06X\n", + ( ((int)otp0[4] << 16 | (int)otp0[3] << 8 | + otp0[2]) & 0x3ffff) >> 2); + MPL_LOGI("W_LOT_ID : %06X\n", + ( ((int)otp0[5] << 8 | otp0[4]) & 0x3fff) >> 2); + MPL_LOGI("WP_ID : %06X\n", + ( ((int)otp0[6] << 8 | otp0[5]) & 0x03ff) >> 7); + MPL_LOGI("REV_ID : %06X\n", otp0[6] >> 2); + MPL_LOGI("\n"); + +close: + result = + inv_serial_single_write(mlsl_handle, mputestCfgPtr->addr, MPUREG_BANK_SEL, 0x00); + return result; +} +#endif /* TRACK_IDS */ + +/** + * @brief If requested via inv_test_setup_accel(), test the accelerometer biases + * and calculate the necessary bias correction. + * @param mlsl_handle + * serial interface handle to allow serial communication with the + * device, both gyro and accelerometer. + * @param bias + * output pointer to store the initial bias calculation provided + * by the MPU Self Test. Requires 3 elements to store accel X, Y, + * and Z axis bias. + * @param perform_full_test + * If 1: + * calculates offsets and noise and compare it against set + * thresholds. The final exist status will reflect if any of the + * value is outside of the expected range. + * When 0; + * skip the noise calculation and pass/fail assessment; simply + * calculates the accel biases. + * + * @return 0 on success. A non-zero error code on error. + */ +int inv_test_accel(void *mlsl_handle, + short *bias, long gravity, + uint_fast8_t perform_full_test) +{ + int i; + + short *p_vals; + float x = 0.f, y = 0.f, z = 0.f, zg = 0.f; + float RMS[3]; + float accelRmsThresh = 1000000.f; /* enourmous so that the test always + passes - future deployment */ + unsigned short res; + unsigned long orig_requested_sensors; + struct mpu_platform_data *mputestPData = mputestCfgPtr->pdata; + + p_vals = (short*)inv_malloc(sizeof(short) * 3 * test_setup.accel_samples); + + /* load the slave descr from the getter */ + if (mputestPData->accel.get_slave_descr == NULL) { + MPL_LOGI("\n"); + MPL_LOGI("No accelerometer configured\n"); + return 0; + } + if (mputestCfgPtr->accel == NULL) { + MPL_LOGI("\n"); + MPL_LOGI("No accelerometer configured\n"); + return 0; + } + + /* resume the accel */ + orig_requested_sensors = mputestCfgPtr->requested_sensors; + mputestCfgPtr->requested_sensors = INV_THREE_AXIS_ACCEL | INV_THREE_AXIS_GYRO; + res = inv_mpu_resume(mputestCfgPtr, + mlsl_handle, NULL, NULL, NULL, + mputestCfgPtr->requested_sensors); + if(res != INV_SUCCESS) + goto accel_error; + + /* wait at least a sample cycle for the + accel data to be retrieved by MPU */ + inv_sleep(inv_mpu_get_sampling_period_us(mputestCfgPtr) / 1000); + + /* collect the samples */ + for(i = 0; i < test_setup.accel_samples; i++) { + short *vals = &p_vals[3 * i]; + if (test_get_data(mlsl_handle, mputestCfgPtr, vals)) { + goto accel_error; + } + x += 1.f * vals[X] / test_setup.accel_samples; + y += 1.f * vals[Y] / test_setup.accel_samples; + z += 1.f * vals[Z] / test_setup.accel_samples; + } + + mputestCfgPtr->requested_sensors = orig_requested_sensors; + res = inv_mpu_suspend(mputestCfgPtr, + mlsl_handle, NULL, NULL, NULL, + INV_ALL_SENSORS); + if (res != INV_SUCCESS) + goto accel_error; + + MPL_LOGI("Accel biases : %+13.3f %+13.3f %+13.3f (LSB)\n", x, y, z); + if (VERBOSE_OUT) { + MPL_LOGI("Accel biases : %+13.3f %+13.3f %+13.3f (gee)\n", + x / gravity, y / gravity, z / gravity); + } + + bias[0] = FLOAT_TO_SHORT(x); + bias[1] = FLOAT_TO_SHORT(y); + zg = z - g_z_sign * gravity; + bias[2] = FLOAT_TO_SHORT(zg); + + MPL_LOGI("Accel correct.: %+13d %+13d %+13d (LSB)\n", + bias[0], bias[1], bias[2]); + if (VERBOSE_OUT) { + MPL_LOGI("Accel correct.: " + "%+13.3f %+13.3f %+13.3f (gee)\n", + 1.f * bias[0] / gravity, + 1.f * bias[1] / gravity, + 1.f * bias[2] / gravity); + } + + if (perform_full_test) { + /* accel RMS - for now the threshold is only indicative */ + for (i = 0, + RMS[X] = 0.f, RMS[Y] = 0.f, RMS[Z] = 0.f; + i < test_setup.accel_samples; i++) { + short *vals = &p_vals[3 * i]; + RMS[X] += (vals[X] - x) * (vals[X] - x); + RMS[Y] += (vals[Y] - y) * (vals[Y] - y); + RMS[Z] += (vals[Z] - z) * (vals[Z] - z); + } + for (i = 0; i < 3; i++) { + if (RMS[i] > accelRmsThresh * accelRmsThresh + * test_setup.accel_samples) { + MPL_LOGI("%s-Accel RMS (%.2f) exceeded threshold " + "(threshold = %.2f)\n", + a_name[i], sqrt(RMS[i] / test_setup.accel_samples), + accelRmsThresh); + goto accel_error; + } + } + MPL_LOGI("RMS : %+13.3f %+13.3f %+13.3f (LSB-rms)\n", + sqrt(RMS[X] / DEF_N_ACCEL_SAMPLES), + sqrt(RMS[Y] / DEF_N_ACCEL_SAMPLES), + sqrt(RMS[Z] / DEF_N_ACCEL_SAMPLES)); + } + + return 0; /* success */ + +accel_error: /* error */ + bias[0] = bias[1] = bias[2] = 0; + return 1; +} + +/** + * @brief an user-space substitute of the power management function(s) + * in mldl_cfg.c for self test usage. + * Wake up and sleep the device, whether that is MPU3050, MPU6050A2, + * or MPU6050B1. + * @param mlsl_handle + * a file handle for the serial communication port used to + * communicate with the MPU device. + * @param power_level + * the power state to change the device into. Currently only 0 or + * 1 are supported, for sleep and full-power respectively. + * @return 0 on success; a non-zero error code on error. + */ +static inv_error_t inv_device_power_mgmt(void *mlsl_handle, + uint_fast8_t power_level) +{ + inv_error_t result; + static unsigned char pwr_mgm; + unsigned char b; + + if (power_level != 0 && power_level != 1) { + return INV_ERROR_INVALID_PARAMETER; + } + + if (power_level) { + result = inv_serial_read( + mlsl_handle, mputestCfgPtr->addr, + MPUREG_PWR_MGM, 1, &pwr_mgm); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + /* reset */ + result = inv_serial_single_write( + mlsl_handle, mputestCfgPtr->addr, + MPUREG_PWR_MGM, pwr_mgm | BIT_H_RESET); +#ifndef CONFIG_MPU_SENSORS_MPU6050A2 + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } +#endif + inv_sleep(5); + + /* re-read power mgmt reg - + it may have reset after H_RESET is applied */ + result = inv_serial_read( + mlsl_handle, mputestCfgPtr->addr, + MPUREG_PWR_MGM, 1, &b); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + /* wake up */ +#ifdef CONFIG_MPU_SENSORS_MPU6050A2 + if ((b & BITS_PWRSEL) != BITS_PWRSEL) { + result = inv_serial_single_write( + mlsl_handle, mputestCfgPtr->addr, + MPUREG_PWR_MGM, BITS_PWRSEL); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } +#else + if (pwr_mgm & BIT_SLEEP) { + result = inv_serial_single_write( + mlsl_handle, mputestCfgPtr->addr, + MPUREG_PWR_MGM, 0x00); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } +#endif + inv_sleep(60); + +#if defined(CONFIG_MPU_SENSORS_MPU6050A2) || \ + defined(CONFIG_MPU_SENSORS_MPU6050B1) + result = inv_serial_single_write( + mlsl_handle, mputestCfgPtr->addr, + MPUREG_INT_PIN_CFG, BIT_BYPASS_EN); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } +#endif + } else { + /* restore the power state the part was found in */ +#ifdef CONFIG_MPU_SENSORS_MPU6050A2 + if ((pwr_mgm & BITS_PWRSEL) != BITS_PWRSEL) { + result = inv_serial_single_write( + mlsl_handle, mputestCfgPtr->addr, + MPUREG_PWR_MGM, pwr_mgm); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } +#else + if (pwr_mgm & BIT_SLEEP) { + result = inv_serial_single_write( + mlsl_handle, mputestCfgPtr->addr, + MPUREG_PWR_MGM, pwr_mgm); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } +#endif + } + + return INV_SUCCESS; +} + +/** + * @brief The main entry point of the MPU Self Test, triggering the run of + * the single tests, for gyros and accelerometers. + * Prepares the MPU for the test, taking the device out of low power + * state if necessary, switching the MPU secondary I2C interface into + * bypass mode and restoring the original power state at the end of + * the test. + * This function is also responsible for encoding the output of each + * test in the correct format as it is stored on the file/medium of + * choice (according to inv_serial_write_cal() function). + * The format needs to stay perfectly consistent with the one expected + * by the corresponding loader in ml_stored_data.c; currectly the + * loaded in use is inv_load_cal_V1 (record type 1 - initial + * calibration). + * + * @param mlsl_handle + * serial interface handle to allow serial communication with the + * device, both gyro and accelerometer. + * @param provide_result + * If 1: + * perform and analyze the offset, drive frequency, and noise + * calculation and compare it against set threshouds. Report + * also the final result using a bit-mask like error code as + * described in the inv_test_gyro() function. + * When 0: + * skip the noise and drive frequency calculation and pass/fail + * assessment. It simply calculates the gyro and accel biases. + * NOTE: for MPU6050 devices, this parameter is currently + * ignored. + * + * @return 0 on success. A non-zero error code on error. + * Propagates the errors from the tests up to the caller. + */ +int inv_mpu_test(void *mlsl_handle, uint_fast8_t provide_result) +{ + int result = 0; + + short temp_avg; + short gyro_biases[3] = {0, 0, 0}; + short accel_biases[3] = {0, 0, 0}; + + unsigned long testStart = inv_get_tick_count(); + long accelSens[3] = {0}; + int ptr; + int tmp; + long long lltmp; + uint32_t chk; + + MPL_LOGI("Collecting %d groups of 600 ms samples for each axis\n", + DEF_TEST_TIME_PER_AXIS / 600); + MPL_LOGI("\n"); + + result = inv_device_power_mgmt(mlsl_handle, TRUE); + +#ifdef TRACK_IDS + result = test_get_mpu_id(mlsl_handle); + if (result != INV_SUCCESS) { + MPL_LOGI("Could not read the device's unique ID\n"); + MPL_LOGI("\n"); + return result; + } +#endif + + /* adjust the gyro sensitivity according to the gyro_sens_trim value */ + adjGyroSens = test_setup.gyro_sens * mputestCfgPtr->gyro_sens_trim / 131.f; + test_setup.gyro_fs = (int)(32768.f / adjGyroSens); + + /* collect gyro and temperature data */ +#ifdef CONFIG_MPU_SENSORS_MPU3050 + result = inv_test_gyro_3050(mlsl_handle, + gyro_biases, &temp_avg, provide_result); +#else + MPL_LOGW_IF(provide_result, + "Self Test for MPU-6050 devices is for bias correction only: " + "no test PASS/FAIL result will be provided\n"); + result = inv_test_gyro_6050(mlsl_handle, gyro_biases, &temp_avg); +#endif + + MPL_LOGI("\n"); + MPL_LOGI("Test time : %ld ms\n", inv_get_tick_count() - testStart); + if (result) + return result; + + /* collect accel data. if this step is skipped, + ensure the array still contains zeros. */ + if (mputestCfgPtr->accel != NULL) { + float fs; + RANGE_FIXEDPOINT_TO_FLOAT(mputestCfgPtr->accel->range, fs); + accelSens[0] = (long)(32768L / fs); + accelSens[1] = (long)(32768L / fs); + accelSens[2] = (long)(32768L / fs); +#if defined CONFIG_MPU_SENSORS_MPU6050B1 + if (MPL_PROD_KEY(mputestCfgPtr->product_id, + mputestCfgPtr->product_revision) == MPU_PRODUCT_KEY_B1_E1_5) { + accelSens[2] /= 2; + } else { + unsigned short trim_corr = 16384 / mputestCfgPtr->accel_sens_trim; + accelSens[0] /= trim_corr; + accelSens[1] /= trim_corr; + accelSens[2] /= trim_corr; + } +#endif + } else { + /* would be 0, but 1 to avoid divide-by-0 below */ + accelSens[0] = accelSens[1] = accelSens[2] = 1; + } +#ifdef CONFIG_MPU_SENSORS_MPU3050 + result = inv_test_accel(mlsl_handle, accel_biases, accelSens[2], + provide_result); +#else + result = inv_test_accel(mlsl_handle, accel_biases, accelSens[2], + FALSE); +#endif + if (result) + return result; + + result = inv_device_power_mgmt(mlsl_handle, FALSE); + if (result) + return result; + + ptr = 0; + dataStore[ptr++] = 0; /* total len of factory cal */ + dataStore[ptr++] = 0; + dataStore[ptr++] = 0; + dataStore[ptr++] = ML_INIT_CAL_LEN; + dataStore[ptr++] = 0; + dataStore[ptr++] = 5; /* record type 5 - initial calibration */ + + tmp = temp_avg; /* temperature */ + if (tmp < 0) tmp += 2 << 16; + USHORT_TO_CHARS(&dataStore[ptr], tmp); + ptr += 2; + + /* NOTE : 2 * test_setup.gyro_fs == 65536 / (32768 / test_setup.gyro_fs) */ + lltmp = (long)gyro_biases[0] * 2 * test_setup.gyro_fs; /* x gyro avg */ + if (lltmp < 0) lltmp += 1LL << 32; + UINT_TO_CHARS(&dataStore[ptr], (uint32_t)lltmp); + ptr += 4; + lltmp = (long)gyro_biases[1] * 2 * test_setup.gyro_fs; /* y gyro avg */ + if (lltmp < 0) lltmp += 1LL << 32; + UINT_TO_CHARS(&dataStore[ptr], (uint32_t)lltmp); + ptr += 4; + lltmp = (long)gyro_biases[2] * 2 * test_setup.gyro_fs; /* z gyro avg */ + if (lltmp < 0) lltmp += 1LL << 32; + UINT_TO_CHARS(&dataStore[ptr], (uint32_t)lltmp); + ptr += 4; + + lltmp = (long)accel_biases[0] * 65536L / accelSens[0]; /* x accel avg */ + if (lltmp < 0) lltmp += 1LL << 32; + UINT_TO_CHARS(&dataStore[ptr], (uint32_t)lltmp); + ptr += 4; + lltmp = (long)accel_biases[1] * 65536L / accelSens[1]; /* y accel avg */ + if (lltmp < 0) lltmp += 1LL << 32; + UINT_TO_CHARS(&dataStore[ptr], (uint32_t)lltmp); + ptr += 4; + lltmp = (long)accel_biases[2] * 65536L / accelSens[2]; /* z accel avg */ + if (lltmp < 0) lltmp += 1LL << 32; + UINT_TO_CHARS(&dataStore[ptr], (uint32_t)lltmp); + ptr += 4; + + /* add a checksum for data */ + chk = inv_checksum( + dataStore + INV_CAL_HDR_LEN, + ML_INIT_CAL_LEN - INV_CAL_HDR_LEN - INV_CAL_CHK_LEN); + UINT_TO_CHARS(&dataStore[ptr], chk); + ptr += 4; + + if (ptr != ML_INIT_CAL_LEN) { + MPL_LOGI("Invalid calibration data length: exp %d, got %d\n", + ML_INIT_CAL_LEN, ptr); + return -1; + } + + return result; +} + +/** + * @brief The main test API. Runs the MPU Self Test and, if successful, + * stores the encoded initial calibration data on the final storage + * medium of choice (cfr. inv_serial_write_cal() and the MLCAL_FILE + * define in your mlsl implementation). + * + * @param mlsl_handle + * serial interface handle to allow serial communication with the + * device, both gyro and accelerometer. + * @param provide_result + * If 1: + * perform and analyze the offset, drive frequency, and noise + * calculation and compare it against set threshouds. Report + * also the final result using a bit-mask like error code as + * described in the inv_test_gyro() function. + * When 0: + * skip the noise and drive frequency calculation and pass/fail + * assessment. It simply calculates the gyro and accel biases. + * + * @return 0 on success or a non-zero error code from the callees on error. + */ +inv_error_t inv_factory_calibrate(void *mlsl_handle, + uint_fast8_t provide_result) +{ + int result; + + result = inv_mpu_test(mlsl_handle, provide_result); + if (provide_result) { + MPL_LOGI("\n"); + if (result == 0) { + MPL_LOGI("Test : PASSED\n"); + } else { + MPL_LOGI("Test : FAILED %d/%04X - Biases NOT stored\n", result, result); + return result; /* abort writing the calibration if the + test is not successful */ + } + MPL_LOGI("\n"); + } else { + MPL_LOGI("\n"); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + + result = inv_serial_write_cal(dataStore, ML_INIT_CAL_LEN); + if (result) { + MPL_LOGI("Error : cannot write calibration on file - error %d\n", + result); + return result; + } + + return INV_SUCCESS; +} + + + +/* ----------------------------------------------------------------------- + accel interface functions + -----------------------------------------------------------------------*/ + +/** + * @internal + * @brief Reads data for X, Y, and Z axis from the accelerometer device. + * Used only if an accelerometer has been setup using the + * inv_test_setup_accel() API. + * Takes care of the accelerometer endianess according to how the + * device has been described in the corresponding accelerometer driver + * file. + * @param mlsl_handle + * serial interface handle to allow serial communication with the + * device, both gyro and accelerometer. + * @param slave + * a pointer to the descriptor of the slave accelerometer device + * in use. Contains the necessary information to operate, read, + * and communicate with the accelerometer device of choice. + * See the declaration of struct ext_slave_descr in mpu.h. + * @param pdata + * a pointer to the platform info of the slave accelerometer + * device in use. Describes how the device is oriented and + * mounted on host platform's PCB. + * @param vals + * output pointer to return the accelerometer's X, Y, and Z axis + * sensor data collected. + * @return 0 on success or a non-zero error code on error. + */ +static inv_error_t test_get_data( + void *mlsl_handle, + struct mldl_cfg *mputestCfgPtr, + short *vals) +{ + inv_error_t result; + unsigned char data[20]; + struct ext_slave_descr *slave = mputestCfgPtr->accel; +#ifndef CONFIG_MPU_SENSORS_MPU3050 + struct ext_slave_platform_data *pdata = &mputestCfgPtr->pdata->accel; +#endif + +#ifdef CONFIG_MPU_SENSORS_MPU3050 + result = inv_serial_read(mlsl_handle, mputestCfgPtr->addr, 0x23, + 6, data); +#else + result = inv_serial_read(mlsl_handle, pdata->address, slave->read_reg, + slave->read_len, data); +#endif + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + if (VERBOSE_OUT) { + MPL_LOGI("Accel : 0x%02X%02X 0x%02X%02X 0x%02X%02X (raw)\n", + ACCEL_UNPACK(data)); + } + + if (CHECK_NACKS(data)) { + MPL_LOGI("Error fetching data from the accelerometer : " + "all bytes read 0xff\n"); + return INV_ERROR_SERIAL_READ; + } + + if (slave->endian == EXT_SLAVE_BIG_ENDIAN) { + vals[0] = CHARS_TO_SHORT(&data[0]); + vals[1] = CHARS_TO_SHORT(&data[2]); + vals[2] = CHARS_TO_SHORT(&data[4]); + } else { + vals[0] = CHARS_TO_SHORT_SWAPPED(&data[0]); + vals[1] = CHARS_TO_SHORT_SWAPPED(&data[2]); + vals[2] = CHARS_TO_SHORT_SWAPPED(&data[4]); + } + + if (VERBOSE_OUT) { + MPL_LOGI("Accel : %+13d %+13d %+13d (LSB)\n", + vals[0], vals[1], vals[2]); + } + return INV_SUCCESS; +} + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + |