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  * $Id: mlFIFOHW.c 5653 2011-06-16 21:06:55Z nroyer $
     21  *
     22  *******************************************************************************/
     23 
     24 /**
     25  *  @defgroup MLFIFO_HW
     26  *  @brief  Motion Library - FIFO HW Driver.
     27  *          Provides facilities to interact with the FIFO.
     28  *
     29  *  @{
     30  *      @file   mlFIFOHW.c
     31  *      @brief  The Motion Library Fifo Hardware Layer.
     32  *
     33  */
     34 
     35 #include <string.h>
     36 
     37 #include "mpu.h"
     38 #if defined CONFIG_MPU_SENSORS_MPU6050A2
     39 #    include "mpu6050a2.h"
     40 #elif defined CONFIG_MPU_SENSORS_MPU6050B1
     41 #    include "mpu6050b1.h"
     42 #elif defined CONFIG_MPU_SENSORS_MPU3050
     43 #  include "mpu3050.h"
     44 #else
     45 #error Invalid or undefined CONFIG_MPU_SENSORS_MPUxxxx
     46 #endif
     47 #include "mlFIFOHW.h"
     48 #include "ml.h"
     49 #include "mldl.h"
     50 #include "mldl_cfg.h"
     51 
     52 #include "mlsl.h"
     53 
     54 #include "log.h"
     55 #undef MPL_LOG_TAG
     56 #define MPL_LOG_TAG "MPL-fifo"
     57 
     58 /*
     59     Defines
     60 */
     61 
     62 #define _fifoDebug(x)           //{x}
     63 
     64 /*
     65     Typedefs
     66 */
     67 
     68 struct fifo_hw_obj {
     69     short fifoCount;
     70     inv_error_t fifoError;
     71     unsigned char fifoOverflow;
     72     unsigned char fifoResetOnOverflow;
     73 };
     74 
     75 /*
     76     Global variables
     77 */
     78 const unsigned char gFifoFooter[FIFO_FOOTER_SIZE] = { 0xB2, 0x6A };
     79 
     80 /*
     81     Static variables
     82 */
     83 static struct fifo_hw_obj fifo_objHW;
     84 
     85 /*
     86     Definitions
     87 */
     88 
     89 /**
     90  *  @brief  Initializes the internal FIFO data structure.
     91  */
     92 void inv_init_fifo_hardare(void)
     93 {
     94     memset(&fifo_objHW, 0, sizeof(fifo_objHW));
     95     fifo_objHW.fifoResetOnOverflow = TRUE;
     96 }
     97 
     98 /**
     99  *  @internal
    100  *  @brief  used to get the FIFO data.
    101  *  @param  length
    102  *              Number of bytes to read from the FIFO.
    103  *  @param  buffer
    104  *              the bytes of FIFO data.
    105  *              Note that this buffer <b>must</b> be large enough
    106  *              to store and additional trailing FIFO footer when
    107  *              expected.  The callers must make sure enough space
    108  *              is allocated.
    109  *  @return number of valid bytes of data.
    110 **/
    111 uint_fast16_t inv_get_fifo(uint_fast16_t length, unsigned char *buffer)
    112 {
    113     INVENSENSE_FUNC_START;
    114     inv_error_t result;
    115     uint_fast16_t inFifo;
    116     uint_fast16_t toRead;
    117     int_fast8_t kk;
    118 
    119     toRead = length - FIFO_FOOTER_SIZE + fifo_objHW.fifoCount;
    120     /*---- make sure length is correct ----*/
    121     if (length > MAX_FIFO_LENGTH || toRead > length || NULL == buffer) {
    122         fifo_objHW.fifoError = INV_ERROR_INVALID_PARAMETER;
    123         return 0;
    124     }
    125 
    126     result = inv_get_fifo_length(&inFifo);
    127     if (INV_SUCCESS != result) {
    128         fifo_objHW.fifoError = result;
    129         return 0;
    130     }
    131     // fifo_objHW.fifoCount is the footer size left in the buffer, or
    132     //      0 if this is the first time reading the fifo since it was reset
    133     if (inFifo < length + fifo_objHW.fifoCount) {
    134         fifo_objHW.fifoError = INV_SUCCESS;
    135         return 0;
    136     }
    137     // if a trailing fifo count is expected - start storing data 2 bytes before
    138     result =
    139         inv_read_fifo(fifo_objHW.fifoCount >
    140                       0 ? buffer : buffer + FIFO_FOOTER_SIZE, toRead);
    141     if (INV_SUCCESS != result) {
    142         fifo_objHW.fifoError = result;
    143         return 0;
    144     }
    145     // Make sure the fifo didn't overflow before or during the read
    146     result = inv_serial_read(inv_get_serial_handle(), inv_get_mpu_slave_addr(),
    147                              MPUREG_INT_STATUS, 1, &fifo_objHW.fifoOverflow);
    148     if (INV_SUCCESS != result) {
    149         fifo_objHW.fifoError = result;
    150         return 0;
    151     }
    152 
    153     if (fifo_objHW.fifoOverflow & BIT_INT_STATUS_FIFO_OVERLOW) {
    154         MPL_LOGV("Resetting Fifo : Overflow\n");
    155         inv_reset_fifo();
    156         fifo_objHW.fifoError = INV_ERROR_FIFO_OVERFLOW;
    157         return 0;
    158     }
    159 
    160     /* Check the Footer value to give us a chance at making sure data
    161      * didn't get corrupted */
    162     for (kk = 0; kk < fifo_objHW.fifoCount; ++kk) {
    163         if (buffer[kk] != gFifoFooter[kk]) {
    164             MPL_LOGV("Resetting Fifo : Invalid footer : 0x%02x 0x%02x\n",
    165                      buffer[0], buffer[1]);
    166             _fifoDebug(char out[200];
    167                        MPL_LOGW("fifoCount : %d\n", fifo_objHW.fifoCount);
    168                        sprintf(out, "0x");
    169                        for (kk = 0; kk < (int)toRead; kk++) {
    170                        sprintf(out, "%s%02X", out, buffer[kk]);}
    171                        MPL_LOGW("%s\n", out);)
    172                 inv_reset_fifo();
    173             fifo_objHW.fifoError = INV_ERROR_FIFO_FOOTER;
    174             return 0;
    175         }
    176     }
    177 
    178     if (fifo_objHW.fifoCount == 0) {
    179         fifo_objHW.fifoCount = FIFO_FOOTER_SIZE;
    180     }
    181 
    182     return length - FIFO_FOOTER_SIZE;
    183 }
    184 
    185 /**
    186  *  @brief  Used to query the status of the FIFO.
    187  *  @return INV_SUCCESS if the fifo is OK. An error code otherwise.
    188 **/
    189 inv_error_t inv_get_fifo_status(void)
    190 {
    191     inv_error_t fifoError = fifo_objHW.fifoError;
    192     fifo_objHW.fifoError = 0;
    193     return fifoError;
    194 }
    195 
    196 /**
    197  * @internal
    198  * @brief   Get the length from the fifo
    199  *
    200  * @param[out] len amount of data currently stored in the fifo.
    201  *
    202  * @return INV_SUCCESS or non-zero error code.
    203 **/
    204 inv_error_t inv_get_fifo_length(uint_fast16_t * len)
    205 {
    206     INVENSENSE_FUNC_START;
    207     unsigned char fifoBuf[2];
    208     inv_error_t result;
    209 
    210     if (NULL == len)
    211         return INV_ERROR_INVALID_PARAMETER;
    212 
    213     /*---- read the 2 'count' registers and
    214       burst read the data from the FIFO ----*/
    215     result = inv_serial_read(inv_get_serial_handle(), inv_get_mpu_slave_addr(),
    216                              MPUREG_FIFO_COUNTH, 2, fifoBuf);
    217     if (INV_SUCCESS != result) {
    218         MPL_LOGE("ReadBurst failed %d\n", result);
    219         inv_reset_fifo();
    220         fifo_objHW.fifoError = INV_ERROR_FIFO_READ_COUNT;
    221         *len = 0;
    222         return result;
    223     }
    224 
    225     *len = (uint_fast16_t) (fifoBuf[0] << 8);
    226     *len += (uint_fast16_t) (fifoBuf[1]);
    227     return result;
    228 }
    229 
    230 /**
    231  *  @brief  inv_get_fifo_count is used to get the number of bytes left in the FIFO.
    232  *          This function returns the stored value and does not access the hardware.
    233  *          See inv_get_fifo_length().
    234  *  @return the number of bytes left in the FIFO
    235 **/
    236 short inv_get_fifo_count(void)
    237 {
    238     return fifo_objHW.fifoCount;
    239 }
    240 
    241 /**
    242  *  @internal
    243  *  @brief  Read data from the fifo
    244  *
    245  *  @param[out] data Location to store the date read from the fifo
    246  *  @param[in] len   Amount of data to read out of the fifo
    247  *
    248  *  @return INV_SUCCESS or non-zero error code
    249 **/
    250 inv_error_t inv_read_fifo(unsigned char *data, uint_fast16_t len)
    251 {
    252     INVENSENSE_FUNC_START;
    253     inv_error_t result;
    254     result = inv_serial_read_fifo(inv_get_serial_handle(),
    255                                   inv_get_mpu_slave_addr(),
    256                                   (unsigned short)len, data);
    257     if (INV_SUCCESS != result) {
    258         MPL_LOGE("inv_serial_readBurst failed %d\n", result);
    259         inv_reset_fifo();
    260         fifo_objHW.fifoError = INV_ERROR_FIFO_READ_DATA;
    261         return result;
    262     }
    263     return result;
    264 }
    265 
    266 /**
    267  *  @brief  Clears the FIFO status and its content.
    268  *  @note   Halt the DMP writing into the FIFO for the time
    269  *          needed to reset the FIFO.
    270  *  @return INV_SUCCESS if successful, a non-zero error code otherwise.
    271  */
    272 inv_error_t inv_reset_fifo(void)
    273 {
    274     INVENSENSE_FUNC_START;
    275     int len = FIFO_HW_SIZE;
    276     unsigned char fifoBuf[2];
    277     unsigned char tries = 0;
    278     unsigned char userCtrlReg;
    279     inv_error_t result;
    280     struct mldl_cfg *mldl_cfg = inv_get_dl_config();
    281 
    282     fifo_objHW.fifoCount = 0;
    283     if (mldl_cfg->gyro_is_suspended)
    284         return INV_SUCCESS;
    285 
    286     result = inv_serial_read(inv_get_serial_handle(), inv_get_mpu_slave_addr(),
    287                              MPUREG_USER_CTRL, 1, &userCtrlReg);
    288     if (result) {
    289         LOG_RESULT_LOCATION(result);
    290         return result;
    291     }
    292 
    293     while (len != 0 && tries < 6) {
    294         result =
    295             inv_serial_single_write(inv_get_serial_handle(),
    296                                     inv_get_mpu_slave_addr(), MPUREG_USER_CTRL,
    297                                     ((userCtrlReg & (~BIT_FIFO_EN)) |
    298                                      BIT_FIFO_RST));
    299         if (result) {
    300             LOG_RESULT_LOCATION(result);
    301             return result;
    302         }
    303         result =
    304             inv_serial_read(inv_get_serial_handle(), inv_get_mpu_slave_addr(),
    305                             MPUREG_FIFO_COUNTH, 2, fifoBuf);
    306         if (result) {
    307             LOG_RESULT_LOCATION(result);
    308             return result;
    309         }
    310         len = (unsigned short)fifoBuf[0] * 256 + (unsigned short)fifoBuf[1];
    311         tries++;
    312     }
    313 
    314     result =
    315         inv_serial_single_write(inv_get_serial_handle(),
    316                                 inv_get_mpu_slave_addr(), MPUREG_USER_CTRL,
    317                                 userCtrlReg);
    318     if (result) {
    319         LOG_RESULT_LOCATION(result);
    320         return result;
    321     }
    322 
    323     return INV_SUCCESS;
    324 }
    325 
    326 /**
    327  * @}
    328 **/
    329