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

Posted

技术标签:

【中文标题】MPU-6050:从 FIFO 寄存器正确读取数据【英文标题】:MPU-6050: Correctly reading data from the FIFO register 【发布时间】:2020-06-10 15:34:57 【问题描述】:

简介

MPU-6050 是一种流行的模块,包含温度传感器、加速度计和陀螺仪。用户可以通过 I2C 或 SPI 读取传感器信息。有两个文档可公开获得,用于从 IC 寄存器中读取数据。它们是:

    The MPU-6000 and MPU-6050 Register Map and Descriptions Document

    The MPU-6000 and MPU-6050 Product Specification


上下文

由于总线通信延迟,通过 I2C 读取 IMU 的各个寄存器会使样本随时间发生偏差。因此,传感器的 X、Y 和 Z 轴寄存器的顺序读取是不同步的。为了解决这个问题,该器件提供了一个 1024 字节的内部 FIFO 队列。配置为推送到队列的数据以采样率推送到一起。因此读取 FIFO 会产生同步数据。

参见 (2),第 7.17 节

MPU-60X0 包含一个 1024 字节的 FIFO 寄存器,可通过串行接口访问。 FIFO 配置寄存器决定将哪些数据写入 FIFO。可能的选择包括陀螺仪数据、加速度计数据、温度读数、辅助传感器读数和 FSYNC 输入。 FIFO 计数器跟踪 FIFO 中包含的有效数据字节数。 FIFO 寄存器支持突发读取。中断函数可用于确定何时有新数据可用


问题

数据表规定,为了从 FIFO 中读取数据,您必须执行以下操作:

    启用 FIFO(第 6 位,寄存器 0x6A,文档 (1),第 4.29 节) 使用要推送的传感器信息配置 FIFO(寄存器 0x23,文档 (1),第 4.7 节)。我通过分别设置位 6、5、4 和 3 来启用 XG_FIFO_ENYG_FIFO_ENZG_FIFO_ENACCEL_FIFO_EN

如果您已执行这些步骤,则它声称(文档 (1),第 4.33 节):

数据按寄存器编号的顺序(从最低到最高)写入 FIFO。如果所有 FIFO 启用标志(见下文)均已启用并且所有外部传感器数据寄存器(寄存器 73 至 96)都与从设备相关联,则寄存器 59 至 96 的内容将以采样率顺序写入。 当 FIFO_EN(寄存器 35)中相应的 FIFO 使能标志设置为 1 时,传感器数据寄存器(寄存器 59 到 96)的内容被写入 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         *
 * ----------------------------------------------------------- *

然而,从 FIFO 读取 12 个字节并在读取单个寄存器时不对应相同的数据。当我加速 IMU 或旋转它时,它似乎也没有多大意义。因此,我不确定如何准确读取 FIFO。这是我面临的问题


问答

    您确定您正确写入寄存器吗?:是的,我能够设置各种配置,例如采样率、中断等。我确信我能够正确地从 FIFO 中读取数据 您确定 FIFO 中有什么要读取的吗?:是的,我已启用 FIFO 溢出中断。我目前在等待中断,然后从 FIFO 寄存器中读取。 读取前是否检查 FIFO 长度寄存器? 是的,发生 FIFO 溢出中断时它包含 1024 字节(最大容量)。 其他人以前没有这样做过吗?:没有人具体解释如何读取 FIFO(例如:this similar question on another forum that gets an RTFM)。大多数与读取 FIFO 相关的可搜索问题是(a)未回答,(b)被告知使用通用 XYZ Arduino 库(我不能使用它),(c)被告知阅读数据表(我有)。

【问题讨论】:

你看过Linux内核驱动实现吗? @0andriy 我不知道这个 MPU 的 Linux 内核驱动程序。它通常用于小型嵌入式项目。你知道一个吗?也许我只是对此一无所知。 驱动在这里:elixir.bootlin.com/linux/latest/source/drivers/iio/imu/… AFAICS 它使用 FIFO:elixir.bootlin.com/linux/latest/source/drivers/iio/imu/… 等 【参考方案1】:

好的,我已经找到了问题所在。问题是我在读取 FIFO 之前未能重置 - 否则一切都或多或少没问题。我将向您展示我现在是如何设置 IMU 的。


源文件

我创建了一个源文件来读取 MPU-6050 寄存器。我已将它们附在此处以供以下说明参考:

Header File Source File

设置

为了设置 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;

如果您按照我的描述进行配置,那么它应该工作。当然,您可能正在为设备使用不同的库或包装器,但您可以启用的功能应该可以类似地访问。完成所有这些后,我就可以在每次中断时读取 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;

【讨论】:

以上是关于MPU-6050:从 FIFO 寄存器正确读取数据的主要内容,如果未能解决你的问题,请参考以下文章

c_cpp 打开MPU6050的DMP功能,MPU6050能以400K的速率输出姿态数据(FIFO,一共42个字节); DMP有个好处,不需要经过复杂的滤波过程,出来的数据,特别是四位元和YRP数据,

Aduino ESP9266通过I2C接口读取MPU6050模块数据

ESP8266 读取MPU-6050数据OLED显示

STC8单片机基于开源库读取mpu6050数据

MPU6050数值没变化?

Aduino ESP9266通过I2C接口读取MPU6050模块数据+OLED显示