Home | History | Annotate | Download | only in mllite
      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  *
     21  * $Id:$
     22  *
     23  *****************************************************************************/
     24 
     25 #include "mlBiasNoMotion.h"
     26 #include "ml.h"
     27 #include "mlinclude.h"
     28 #include "mlos.h"
     29 #include "mlFIFO.h"
     30 #include "dmpKey.h"
     31 #include "accel.h"
     32 #include "mlMathFunc.h"
     33 #include "mldl.h"
     34 #include "mlstates.h"
     35 #include "mlSetGyroBias.h"
     36 
     37 #include "log.h"
     38 #undef MPL_LOG_TAG
     39 #define MPL_LOG_TAG "MPL-BiasNoMot"
     40 
     41 
     42 #define _mlDebug(x)             //{x}
     43 
     44 /**
     45  *  @brief  inv_set_motion_callback is used to register a callback function that
     46  *          will trigger when a change of motion state is detected.
     47  *
     48  *  @pre    inv_dmp_open()
     49  *          @ifnot MPL_MF
     50  *              or inv_open_low_power_pedometer()
     51  *              or inv_eis_open_dmp()
     52  *          @endif
     53  *          and inv_dmp_start()
     54  *          must <b>NOT</b> have been called.
     55  *
     56  *  @param  func    A user defined callback function accepting a
     57  *                  motion_state parameter, the new motion state.
     58  *                  May be one of INV_MOTION or INV_NO_MOTION.
     59  *  @return INV_SUCCESS if successful or Non-zero error code otherwise.
     60  */
     61 inv_error_t inv_set_motion_callback(void (*func) (unsigned short motion_state))
     62 {
     63     INVENSENSE_FUNC_START;
     64 
     65     if ((inv_get_state() != INV_STATE_DMP_OPENED) &&
     66         (inv_get_state() != INV_STATE_DMP_STARTED))
     67         return INV_ERROR_SM_IMPROPER_STATE;
     68 
     69     inv_params_obj.motion_cb_func = func;
     70 
     71     return INV_SUCCESS;
     72 }
     73 
     74 #if defined CONFIG_MPU_SENSORS_MPU6050A2 || \
     75     defined CONFIG_MPU_SENSORS_MPU6050B1
     76 /** Turns on the feature to compute gyro bias from No Motion */
     77 inv_error_t inv_turn_on_bias_from_no_motion()
     78 {
     79     inv_error_t result;
     80     unsigned char regs[3] = { 0x0d, DINA35, 0x5d };
     81     inv_params_obj.bias_mode |= INV_BIAS_FROM_NO_MOTION;
     82     result = inv_set_mpu_memory(KEY_CFG_MOTION_BIAS, 3, regs);
     83     return result;
     84 }
     85 
     86 /** Turns off the feature to compute gyro bias from No Motion
     87 */
     88 inv_error_t inv_turn_off_bias_from_no_motion()
     89 {
     90     inv_error_t result;
     91     unsigned char regs[3] = { DINA90 + 8, DINA90 + 8, DINA90 + 8 };
     92     inv_params_obj.bias_mode &= ~INV_BIAS_FROM_NO_MOTION;
     93     result = inv_set_mpu_memory(KEY_CFG_MOTION_BIAS, 3, regs);
     94     return result;
     95 }
     96 #endif
     97 
     98 inv_error_t inv_update_bias(void)
     99 {
    100     INVENSENSE_FUNC_START;
    101     inv_error_t result;
    102     unsigned char regs[12];
    103     short bias[GYRO_NUM_AXES];
    104 
    105     if ((inv_params_obj.bias_mode & INV_BIAS_FROM_NO_MOTION)
    106         && inv_get_gyro_present()) {
    107 
    108         regs[0] = DINAA0 + 3;
    109         result = inv_set_mpu_memory(KEY_FCFG_6, 1, regs);
    110         if (result) {
    111             LOG_RESULT_LOCATION(result);
    112             return result;
    113         }
    114 
    115         result = inv_get_mpu_memory(KEY_D_1_244, 12, regs);
    116         if (result) {
    117             LOG_RESULT_LOCATION(result);
    118             return result;
    119         }
    120 
    121         inv_convert_bias(regs, bias);
    122 
    123         regs[0] = DINAA0 + 15;
    124         result = inv_set_mpu_memory(KEY_FCFG_6, 1, regs);
    125         if (result) {
    126             LOG_RESULT_LOCATION(result);
    127             return result;
    128         }
    129 
    130         result = inv_set_gyro_bias_in_hw_unit(bias, INV_SGB_NO_MOTION);
    131         if (result) {
    132             LOG_RESULT_LOCATION(result);
    133             return result;
    134         }
    135 
    136         result =
    137             inv_serial_read(inv_get_serial_handle(), inv_get_mpu_slave_addr(),
    138                             MPUREG_TEMP_OUT_H, 2, regs);
    139         if (result) {
    140             LOG_RESULT_LOCATION(result);
    141             return result;
    142         }
    143         result = inv_set_mpu_memory(KEY_DMP_PREVPTAT, 2, regs);
    144         if (result) {
    145             LOG_RESULT_LOCATION(result);
    146             return result;
    147         }
    148 
    149         inv_obj.got_no_motion_bias = TRUE;
    150     }
    151     return INV_SUCCESS;
    152 }
    153 
    154 inv_error_t MLAccelMotionDetection(struct inv_obj_t *inv_obj)
    155 {
    156     long gain;
    157     unsigned long timeChange;
    158     long rate;
    159     inv_error_t result;
    160     long accel[3], temp;
    161     long long accelMag;
    162     unsigned long currentTime;
    163     int kk;
    164 
    165     if (!inv_accel_present()) {
    166         return INV_SUCCESS;
    167     }
    168 
    169     currentTime = inv_get_tick_count();
    170 
    171     // We always run the accel low pass filter at the highest sample rate possible
    172     result = inv_get_accel(accel);
    173     if (result != INV_ERROR_FEATURE_NOT_ENABLED) {
    174         if (result) {
    175             LOG_RESULT_LOCATION(result);
    176             return result;
    177         }
    178         rate = inv_get_fifo_rate() * 5 + 5;
    179         if (rate > 200)
    180             rate = 200;
    181 
    182         gain = inv_obj->accel_lpf_gain * rate;
    183         timeChange = inv_get_fifo_rate();
    184 
    185         accelMag = 0;
    186         for (kk = 0; kk < ACCEL_NUM_AXES; ++kk) {
    187             inv_obj->accel_lpf[kk] =
    188                 inv_q30_mult(((1L << 30) - gain), inv_obj->accel_lpf[kk]);
    189             inv_obj->accel_lpf[kk] += inv_q30_mult(gain, accel[kk]);
    190             temp = accel[0] - inv_obj->accel_lpf[0];
    191             accelMag += (long long)temp *temp;
    192         }
    193 
    194         if (accelMag > inv_obj->no_motion_accel_threshold) {
    195             inv_obj->no_motion_accel_time = currentTime;
    196 
    197             // Check for change of state
    198             if (!inv_get_gyro_present())
    199                 inv_set_motion_state(INV_MOTION);
    200 
    201         } else if ((currentTime - inv_obj->no_motion_accel_time) >
    202                    5 * inv_obj->motion_duration) {
    203             // We have no motion according to accel
    204             // Check fsor change of state
    205             if (!inv_get_gyro_present())
    206                 inv_set_motion_state(INV_NO_MOTION);
    207         }
    208     }
    209     return INV_SUCCESS;
    210 }
    211 
    212 /**
    213  * @internal
    214  * @brief   Manually update the motion/no motion status.  This is a
    215  *          convienence function for implementations that do not wish to use
    216  *          inv_update_data.
    217  *          This function can be called periodically to check for the
    218  *          'no motion' state and update the internal motion status and bias
    219  *          calculations.
    220  */
    221 inv_error_t MLPollMotionStatus(struct inv_obj_t * inv_obj)
    222 {
    223     INVENSENSE_FUNC_START;
    224     unsigned char regs[3] = { 0 };
    225     unsigned short motionFlag = 0;
    226     unsigned long currentTime;
    227     inv_error_t result;
    228 
    229     result = MLAccelMotionDetection(inv_obj);
    230 
    231     currentTime = inv_get_tick_count();
    232 
    233     // If it is not time to poll for a no motion event, return
    234     if (((inv_obj->interrupt_sources & INV_INT_MOTION) == 0) &&
    235         ((currentTime - inv_obj->poll_no_motion) <= 1000))
    236         return INV_SUCCESS;
    237 
    238     inv_obj->poll_no_motion = currentTime;
    239 
    240 #if defined CONFIG_MPU_SENSORS_MPU3050
    241     if (inv_get_gyro_present()
    242         && ((inv_params_obj.bias_mode & INV_BIAS_FROM_FAST_NO_MOTION) == 0)) {
    243         static long repeatBiasUpdateTime = 0;
    244 
    245         result = inv_get_mpu_memory(KEY_D_1_98, 2, regs);
    246         if (result) {
    247             LOG_RESULT_LOCATION(result);
    248             return result;
    249         }
    250 
    251         motionFlag = (unsigned short)regs[0] * 256 + (unsigned short)regs[1];
    252 
    253         _mlDebug(MPL_LOGV("motionFlag from RAM : 0x%04X\n", motionFlag);
    254             )
    255             if (motionFlag == inv_obj->motion_duration) {
    256             if (inv_obj->motion_state == INV_MOTION) {
    257                 inv_update_bias();
    258                 repeatBiasUpdateTime = inv_get_tick_count();
    259 
    260                 regs[0] = DINAD8 + 1;
    261                 regs[1] = DINA0C;
    262                 regs[2] = DINAD8 + 2;
    263                 result = inv_set_mpu_memory(KEY_CFG_18, 3, regs);
    264                 if (result) {
    265                     LOG_RESULT_LOCATION(result);
    266                     return result;
    267                 }
    268 
    269                 regs[0] = 0;
    270                 regs[1] = 5;
    271                 result = inv_set_mpu_memory(KEY_D_1_106, 2, regs);
    272                 if (result) {
    273                     LOG_RESULT_LOCATION(result);
    274                     return result;
    275                 }
    276 
    277                 //Trigger no motion callback
    278                 inv_set_motion_state(INV_NO_MOTION);
    279             }
    280         }
    281         if (motionFlag == 5) {
    282             if (inv_obj->motion_state == INV_NO_MOTION) {
    283                 regs[0] = DINAD8 + 2;
    284                 regs[1] = DINA0C;
    285                 regs[2] = DINAD8 + 1;
    286                 result = inv_set_mpu_memory(KEY_CFG_18, 3, regs);
    287                 if (result) {
    288                     LOG_RESULT_LOCATION(result);
    289                     return result;
    290                 }
    291 
    292                 regs[0] =
    293                     (unsigned char)((inv_obj->motion_duration >> 8) & 0xff);
    294                 regs[1] = (unsigned char)(inv_obj->motion_duration & 0xff);
    295                 result = inv_set_mpu_memory(KEY_D_1_106, 2, regs);
    296                 if (result) {
    297                     LOG_RESULT_LOCATION(result);
    298                     return result;
    299                 }
    300 
    301                 //Trigger no motion callback
    302                 inv_set_motion_state(INV_MOTION);
    303             }
    304         }
    305         if (inv_obj->motion_state == INV_NO_MOTION) {
    306             if ((inv_get_tick_count() - repeatBiasUpdateTime) > 4000) {
    307                 inv_update_bias();
    308                 repeatBiasUpdateTime = inv_get_tick_count();
    309             }
    310         }
    311     }
    312 #else                           // CONFIG_MPU_SENSORS_MPU3050
    313     if (inv_get_gyro_present()
    314         && ((inv_params_obj.bias_mode & INV_BIAS_FROM_FAST_NO_MOTION) == 0)) {
    315         result = inv_get_mpu_memory(KEY_D_1_98, 2, regs);
    316         if (result) {
    317             LOG_RESULT_LOCATION(result);
    318             return result;
    319         }
    320 
    321         motionFlag = (unsigned short)regs[0] * 256 + (unsigned short)regs[1];
    322 
    323         _mlDebug(MPL_LOGV("motionFlag from RAM : 0x%04X\n", motionFlag);
    324             )
    325             if (motionFlag > 0) {
    326             unsigned char biasReg[12];
    327             long biasTmp2[3], biasTmp[3];
    328             int i;
    329 
    330             if (inv_obj->last_motion != motionFlag) {
    331                 result = inv_get_mpu_memory(KEY_D_2_96, 12, biasReg);
    332 
    333                 for (i = 0; i < 3; i++) {
    334                     biasTmp2[i] = inv_big8_to_int32(&biasReg[i * 4]);
    335                 }
    336                 // Rotate bias vector by the transpose of the orientation matrix
    337                 for (i = 0; i < 3; ++i) {
    338                     biasTmp[i] =
    339                         inv_q30_mult(biasTmp2[0],
    340                                      inv_obj->gyro_orient[i]) +
    341                         inv_q30_mult(biasTmp2[1],
    342                                      inv_obj->gyro_orient[i + 3]) +
    343                         inv_q30_mult(biasTmp2[2], inv_obj->gyro_orient[i + 6]);
    344                 }
    345                 inv_obj->gyro_bias[0] = inv_q30_mult(biasTmp[0], 1501974482L);
    346                 inv_obj->gyro_bias[1] = inv_q30_mult(biasTmp[1], 1501974482L);
    347                 inv_obj->gyro_bias[2] = inv_q30_mult(biasTmp[2], 1501974482L);
    348             }
    349             inv_set_motion_state(INV_NO_MOTION);
    350         } else {
    351             // We are in a motion state
    352             inv_set_motion_state(INV_MOTION);
    353         }
    354         inv_obj->last_motion = motionFlag;
    355 
    356     }
    357 #endif                          // CONFIG_MPU_SENSORS_MPU3050
    358     return INV_SUCCESS;
    359 }
    360 
    361 inv_error_t inv_enable_bias_no_motion(void)
    362 {
    363     inv_error_t result;
    364     inv_params_obj.bias_mode |= INV_BIAS_FROM_NO_MOTION;
    365     result =
    366         inv_register_fifo_rate_process(MLPollMotionStatus,
    367                                        INV_PRIORITY_BIAS_NO_MOTION);
    368 #if defined CONFIG_MPU_SENSORS_MPU6050A2 || \
    369     defined CONFIG_MPU_SENSORS_MPU6050B1
    370     if (result) {
    371         LOG_RESULT_LOCATION(result);
    372         return result;
    373     }
    374     result = inv_turn_on_bias_from_no_motion();
    375 #endif
    376     return result;
    377 }
    378 
    379 inv_error_t inv_disable_bias_no_motion(void)
    380 {
    381     inv_error_t result;
    382     inv_params_obj.bias_mode &= ~INV_BIAS_FROM_NO_MOTION;
    383     result = inv_unregister_fifo_rate_process(MLPollMotionStatus);
    384 #if defined CONFIG_MPU_SENSORS_MPU6050A2 || \
    385     defined CONFIG_MPU_SENSORS_MPU6050B1
    386     if (result) {
    387         LOG_RESULT_LOCATION(result);
    388         return result;
    389     }
    390     result = inv_turn_off_bias_from_no_motion();
    391 #endif
    392     return result;
    393 }
    394