MPU-6050: правильное считывание данных из регистра FIFO - PullRequest
0 голосов
/ 26 февраля 2020

Введение

MPU-6050 - это популярный модуль, который содержит датчик температуры, акселерометр и гироскоп. Пользователь может прочитать информацию датчика через I2 C или SPI. Два документа общедоступны для чтения данных из регистров I C. Это:

  1. Карта регистра и описания MPU-6000 и MPU-6050 Документ

  2. Спецификации продукции MPU-6000 и MPU-6050


Контекст

Чтение отдельных регистров IMU по I2 C искажает выборки во времени, поскольку задержка автобусной связи. Следовательно, последовательное считывание регистров оси X, Y и Z датчика не синхронизировано. Для решения этой проблемы устройство предоставляет внутреннюю очередь FIFO длиной 1024 байта. Данные, настроенные для отправки в очередь, объединяются с частотой дискретизации. Следовательно, чтение FIFO дает синхронизированные данные.

См. (2), раздел 7.17 :

MPU-60X0 содержит 1024-байтовый регистр FIFO, который доступен через последовательный интерфейс. Регистр конфигурации FIFO определяет, какие данные записываются в FIFO. Возможные варианты включают данные гироскопа, данные акселерометра, показания температуры, показания вспомогательного датчика и вход FSYN C. Счетчик FIFO отслеживает, сколько байтов допустимых данных содержится в FIFO. Регистр FIFO поддерживает пакетное чтение. Функция прерывания может использоваться для определения доступности новых данных


Проблема

В таблицах данных указано, что для чтения из FIFO необходимо выполнить следующее:

  1. Включить FIFO (бит 6, регистр 0x6A, Документ (1), раздел 4.29)
  2. Сконфигурировать FIFO с тем, какую информацию с датчиков для pu sh (зарегистрировать 0x23, Документ (1), Раздел 4.7). Я включаю XG_FIFO_EN, YG_FIFO_EN, ZG_FIFO_EN и ACCEL_FIFO_EN, устанавливая биты 6, 5, 4 и 3. соответственно.

Если вы выполнили эти шаги, то он утверждает (Документ (1), раздел 4.33), что:

Данные записываются в FIFO в порядке номера регистра (от самого низкого до самого высокого). Если все флаги включения FIFO (см. Ниже) включены и все регистры данных внешнего датчика (регистры с 73 по 96) связаны с ведомым устройством, содержимое регистров с 59 по 96 будет записано в порядке с частотой дискретизации. Содержимое регистров данных датчика (регистры 59–96) записываются в буфер FIFO, когда их соответствующие флаги включения FIFO установлены в 1 в FIFO_EN (регистр 35).

Однако я считаю, что это не так. Учитывая флаги, которые я включил в регистр конфигурации, я ожидаю, что следующая последовательность будет поступать из 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         *
 * ----------------------------------------------------------- *

Тем не менее, чтение 12 байтов из FIFO не соответствует тем же данным при чтении отдельные регистры . Это также, кажется, не имеет особого смысла, когда я ускоряю IMU или поворачиваю его. Поэтому я не уверен, как именно читать FIFO. С этой проблемой я сталкиваюсь


Q & A

  1. Вы уверены, что правильно записываете в регистры? : Да, я могу установить различные такие конфигурации, как частота дискретизации, прерывания и т. д. c. Я уверен, что правильно могу читать из FIFO
  2. Вы уверены, что в FIFO есть что-то, что можно прочитать? : Да, я включил прерывания переполнения FIFO. В настоящее время я жду прерывания и затем читаю из регистра FIFO.
  3. Проверяете ли вы регистр длины FIFO перед чтением? Да, он содержит 1024 байта (максимальная емкость), когда FIFO происходит прерывание переполнения.
  4. Разве другие люди не делали этого раньше? : Ни у кого нет конкретного объяснения, как читать FIFO (например: этот похожий вопрос на другом форуме, который получает RTFM ). Большинство доступных для поиска вопросов, связанных с чтением FIFO: (а) без ответа, (б) велено использовать библиотеку generi c XYZ Arduino (я не могу ее использовать), (c) велено читать лист данных (у меня есть ).

1 Ответ

1 голос
/ 02 марта 2020

Хорошо, я понял проблему. Проблема заключалась в том, что мне не удавалось сбросить FIFO до его чтения - в противном случае все было более или менее в порядке. Я покажу вам точно, как я сейчас настраиваю IMU.


Исходные файлы

Я создал исходный файл для чтения регистров MPU-6050. Я привел их сюда для справки в следующем объяснении:


Настройка

Чтобы настроить IMU, я выполнил следующие шаги в рамках задачи FreeRTOS (до основного l oop).

// 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;
}
...