简体   繁体   English

MPU-6050:正确从 FIFO 寄存器读取数据

[英]MPU-6050: Correctly reading data from the FIFO register

Introduction介绍

The MPU-6050 is a popular module that contains a temperature sensor, accelerometer, and gyroscope. MPU-6050 是一种流行的模块,包含温度传感器、加速度计和陀螺仪。 A user may read the sensor information over I2C or SPI.用户可以通过 I2C 或 SPI 读取传感器信息。 Two documents are publicly available for reading data out of the IC registers.有两个文件可公开用于从 IC 寄存器中读取数据。 These are:这些是:

  1. The MPU-6000 and MPU-6050 Register Map and Descriptions Document MPU-6000 和 MPU-6050 寄存器映射和描述文档

  2. The MPU-6000 and MPU-6050 Product Specification MPU-6000 和 MPU-6050 产品规格


Context语境

Reading individual registers of the IMU over I2C skews samples across time because of bus communication latency.由于总线通信延迟,通过 I2C 读取 IMU 的各个寄存器会使样本随时间偏移。 Consequently, a sequential read of the X, Y, and Z axis registers of a sensor are not synchronized.因此,传感器的 X、Y 和 Z 轴寄存器的顺序读取不同步。 To address this, the device provides a 1024-byte internal FIFO queue.为了解决这个问题,该器件提供了一个 1024 字节的内部 FIFO 队列。 Data configured to be pushed to the queue are pushed together at the sample rate.配置为推送到队列的数据以采样率推送到一起。 Hence reading the FIFO yields synchronized data.因此读取 FIFO 会产生同步数据。

See (2), section 7.17 :见(2),第 7.17 节

The MPU-60X0 contains a 1024-byte FIFO register that is accessible via the Serial Interface. MPU-60X0 包含一个 1024 字节的 FIFO 寄存器,可通过串行接口访问。 The FIFO configuration register determines which data is written into the FIFO. FIFO 配置寄存器决定将哪些数据写入 FIFO。 Possible choices include gyro data, accelerometer data, temperature readings, auxiliary sensor readings, and FSYNC input.可能的选择包括陀螺仪数据、加速度计数据、温度读数、辅助传感器读数和 FSYNC 输入。 A FIFO counter keeps track of how many bytes of valid data are contained in the FIFO. FIFO 计数器会跟踪 FIFO 中包含多少字节的有效数据。 The FIFO register supports burst reads. FIFO 寄存器支持突发读取。 The interrupt function may be used to determine when new data is available中断函数可用于确定新数据何时可用


Problem问题

The datasheets specify that in order to read from the FIFO, you must perform the following:数据表指定为了从 FIFO 读取,您必须执行以下操作:

  1. Enable the FIFO (bit 6, register 0x6A , Document (1), Section 4.29)启用 FIFO(位 6,寄存器0x6A ,文档 (1),第 4.29 节)
  2. Configure the FIFO with what sensor information to push (register 0x23 , Document (1), Section 4.7).使用要推送的传感器信息配置 FIFO(寄存器0x23 ,文档 (1),第 4.7 节)。 I enable XG_FIFO_EN , YG_FIFO_EN , ZG_FIFO_EN , and ACCEL_FIFO_EN by setting bits 6, 5, 4, and 3 respectively.我通过分别设置第ACCEL_FIFO_EN和 3 位来启用XG_FIFO_ENYG_FIFO_ENZG_FIFO_ENACCEL_FIFO_EN

If you have performed these steps, then it claims (Document (1), Section 4.33) that:如果您已执行这些步骤,则它声称(文档 (1),第 4.33 节):

Data is written to the FIFO in order of register number (from lowest to highest).数据按寄存器编号的顺序(从低到高)写入 FIFO。 If all the FIFO enable flags (see below) are enabled and all External Sensor Data registers (Registers 73 to 96) are associated with a Slave device, the contents of registers 59 through 96 will be written in order at the Sample Rate.如果所有 FIFO 启用标志(见下文)都启用且所有外部传感器数据寄存器(寄存器 73 至 96)都与从设备关联,则寄存器 59 至 96 的内容将以采样率按顺序写入。 The contents of the sensor data registers (Registers 59 to 96) are written into the FIFO buffer when their corresponding FIFO enable flags are set to 1 in FIFO_EN (Register 35).当传感器数据寄存器(寄存器 59 至 96)的内容在 FIFO_EN(寄存器 35)中相应的 FIFO 使能标志设置为 1 时,它们将被写入 FIFO 缓冲区。

However, I find that this does not hold true.然而,我发现这并不成立。 Given the flags I have enabled in the configuration register, I expect the following sequence to come from the FIFO:鉴于我在配置寄存器中启用的标志,我希望以下序列来自 FIFO:

 * ----------------------------------------------------------- *
 *     BYTE #    |         VALUE          |    Register (dec)  *
 * ----------------------------------------------------------- *
 *       0       |     ACCEL_XOUT[15:8]   |         59         *
 *       1       |     ACCEL_XOUT[7:0]    |         60         *
 * ----------------------------------------------------------- *
 *       2       |     ACCEL_YOUT[15:8]   |         61         *
 *       3       |     ACCEL_YOUT[7:0]    |         62         *
 * ----------------------------------------------------------- *
 *       4       |     ACCEL_ZOUT[15:8]   |         63         *
 *       5       |     ACCEL_ZOUT[7:0]    |         64         *
 * ----------------------------------------------------------- *
 *       6       |     GYRO_XOUT[15:8]    |         67         *
 *       7       |     GYRO_XOUT[7:0]     |         68         *
 * ----------------------------------------------------------- *
 *       8       |     GYRO_YOUT[15:8]    |         69         *
 *       9       |     GYRO_YOUT[7:0]     |         70         *
 * ----------------------------------------------------------- *
 *      10       |     GYRO_ZOUT[15:8]    |         71         *
 *      11       |     GYRO_ZOUT[7:0]     |         72         *
 * ----------------------------------------------------------- *

Yet reading 12 bytes from the FIFO does not correspond with the same data when reading individual registers .然而,读取单个寄存器时,从 FIFO 读取 12 个字节并不对应于相同的数据 It also doesn't seem to make much sense when I accelerate the IMU, or rotate it.当我加速 IMU 或旋转它时,它似乎也没有多大意义。 I therefore am not sure how exactly to read the FIFO.因此,我不确定如何准确读取 FIFO。 This is the problem I face这是我面临的问题


Q&A问答

  1. Are you sure you are correctly writing to registers?您确定正确写入寄存器吗? : Yes, I am able to set various configurations such as the sampling rate, interrupts, etc. I am confident I am correctly able to read from the FIFO : 是的,我可以设置各种配置,例如采样率、中断等。我相信我能够正确地从 FIFO 中读取
  2. Are you sure there is anything in the FIFO to read?您确定 FIFO 中有任何内容要读取吗? : Yes, I have enabled FIFO overflow interrupts. : 是的,我启用了 FIFO 溢出中断。 I currently wait for an interrupt, and then read from the FIFO register.我目前等待中断,然后从 FIFO 寄存器中读取。
  3. Are you checking the FIFO length register before reading?读取前是否检查FIFO长度寄存器? Yes, it contains 1024 bytes (maximum capacity) when the FIFO-overflow interrupt occurs.是的,当发生 FIFO 溢出中断时,它包含 1024 字节(最大容量)。
  4. Haven't other people done this before?其他人以前没有这样做过吗? : Nobody has a concrete explanation on how to read the FIFO (eg: this similar question on another forum that gets an RTFM ). :没有人对如何读取 FIFO 有具体的解释(例如:另一个获得 RTFM 的论坛上的类似问题)。 A majority of searchable questions related to reading the FIFO are (a) unanswered, (b) told to use generic XYZ Arduino library (I cannot use it), (c) told to read the data sheet (I have).大多数与读取 FIFO 相关的可搜索问题是 (a) 未回答,(b) 被告知使用通用 XYZ Arduino 库(我不能使用它),(c)被告知阅读数据表(我有)。

Okay, so I've figured out the problem.好的,所以我已经找到了问题所在。 The issue was that I was failing to reset the FIFO prior to reading it - otherwise everything was more or less okay.问题是我在读取之前未能重置FIFO - 否则一切都或多或少没问题。 I'll show you exactly how I setup the IMU now.我将向您展示我现在如何设置 IMU。


Source Files源文件

I created a source file to read the MPU-6050 registers.我创建了一个源文件来读取 MPU-6050 寄存器。 I've attached them here for reference in the following explanation:我已将它们附在此处以供在以下解释中参考:


Setup设置

In order to setup the IMU, I performed the following steps within a FreeRTOS task (prior to the main loop).为了设置 IMU,我在 FreeRTOS 任务中(在主循环之前)执行了以下步骤。

// Performs the I2C configuration for the MPU-6050 IMU. Saves handle
static mpu6050_err_t init_imu (mpu6050_i2c_cfg_t **handle) {
    mpu6050_err_t err = MPU6050_ERR_OK;
    uint8_t flags;

    // Configure the MPU-6050 I2C data structure
    static mpu6050_i2c_cfg_t i2c_cfg = (mpu6050_i2c_cfg_t) {
        .sda_pin        = I2C_SDA_PIN,
        .scl_pin        = I2C_SCL_PIN,
        .slave_addr     = I2C_IMU_SLAVE_ADDR,
        .i2c_port       = I2C_IMU_PORT_NUM,
        .clk_speed      = I2C_APB_CLK_FREQ / 200,    // Requires 400kHz
        .sda_pullup_en  = IMU_ENABLE_INTERNAL_PULLUPS,
        .scl_pullup_en  = IMU_ENABLE_INTERNAL_PULLUPS
    };

    // Initialize I2C
    if ((err = mpu6050_init(&i2c_cfg)) != MPU6050_ERR_OK) {
        return err;
    }

    // Configure Power Management 1 to wake the IMU (don't reset)
    flags = 0x0;
    if ((err = mpu6050_configure_power(&i2c_cfg, flags)) != MPU6050_ERR_OK) {
        return err;
    }

    // Configure accelerometer sensitivity
    flags = A_CFG_8G;
    if ((err = mpu6050_configure_accelerometer(&i2c_cfg, flags)) 
        != MPU6050_ERR_OK) {
        return err;
    }

    // Configure gyro sensitivity
    flags = G_CFG_500;
    if ((err = mpu6050_configure_gyroscope(&i2c_cfg, flags)) 
        != MPU6050_ERR_OK) {
        return err;
    }

    // Configure the Digital-Low-Pass-Filter
    flags = DLFP_CFG_FILTER_2;
    if ((err = mpu6050_configure_dlfp(&i2c_cfg, flags)) 
        != MPU6050_ERR_OK) {
        return err;
    }

    // Set the sampling rate to ~50Hz
    flags = 19;
    if ((err = mpu6050_set_sample_rate_divider(&i2c_cfg, flags)) 
        != MPU6050_ERR_OK) {
        return err;
    }

    // Configure interrupt behavior
    flags = 0x0;
    if ((err = mpu6050_configure_interrupt(&i2c_cfg, flags)) 
        != MPU6050_ERR_OK) {
        return err;
    }

    // Enable interrupts after every sensor refresh
    flags = INTR_EN_DATA_RDY;
    if ((err = mpu6050_enable_interrupt(&i2c_cfg, flags)) 
        != MPU6050_ERR_OK) {
        return err;
    }

    // Enable + Reset the FIFO
    flags = USER_CTRL_FIFO_EN | USER_CTRL_FIFO_RST;
    if ((err = mpu6050_enable_fifo(&i2c_cfg, flags)) 
        != MPU6050_ERR_OK) {
        return err;
    }

    // Configure the data pushed to the FIFO
    flags = FIFO_CFG_GX | FIFO_CFG_GY | FIFO_CFG_GZ | FIFO_CFG_AXYZ;
    if ((err = mpu6050_configure_fifo(&i2c_cfg, flags)) != MPU6050_ERR_OK) {
        return err;
    }

    // Save the configuration
    *handle = &i2c_cfg;

    return err;
}

If you configure as I described, then it should work.如果您按照我的描述进行配置,那么它应该可以工作。 Of course, you may be using a different library or wrapper for the device, but the functions you can enable should be similarly accessible.当然,您可能正在为设备使用不同的库或包装器,但您可以启用的功能应该可以类似地访问。 Once I had done all this, I was able to read the FIFO at each interrupt as follows:完成所有这些后,我可以在每个中断处读取 FIFO,如下所示:

// Read the FIFO length
if (mpu6050_get_fifo_length(i2c_cfg_p, &len) != MPU6050_ERR_OK) {
    ERR("FIFO length fetch error!");
    break;
} 

// Check if enough samples are ready - else continue (check later)
if (len < FIFO_BURST_LEN) {
    continue;
}

// Fetch data from FIFO
if (mpu6050_receive_fifo(i2c_cfg_p, &data) != MPU6050_ERR_OK) {
    ERR("FIFO data fetch error!");
    break;
}

Sorry to reopen a closed thread but have you tried reading larger bursts?很抱歉重新打开一个关闭的线程,但您是否尝试过阅读更大的爆发? I'm currently trying to read the buffer when it's full (1024 bytes), to do that i use the fifo overflow interrupt but i think that I don't read the buffer fast enough to read the right data before it's overflowed.我目前正在尝试在缓冲区已满(1024 字节)时读取缓冲区,为此我使用了 fifo 溢出中断,但我认为我读取缓冲区的速度不够快,无法在溢出之前读取正确的数据。 Do you know if there are other ways to send interrupts?不知道还有没有其他的发送中断的方式? For example when the fifo buffer is half full (512 bytes), because in the datasheet i only found the interrupt can be fired after every measurement or after fifo overflow.例如,当 fifo 缓冲区半满(512 字节)时,因为在数据表中我只发现可以在每次测量或 fifo 溢出后触发中断。 Thanks.谢谢。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM