1

MPU6050 datasheet says that maximum accelerometer data output is 1Khz, so in theory when measuring time it takes to receive 1000 data samples through I2C, so I should receive all data in no less than 1 second, but somehow i always get sub 0.3 seconds.


Does CPU clock halts when waiting for data incoming from I2C slave?
How to have constant MPU6050 1khz output data rate, and measure it?

#include <wiringPi.h>
#include <wiringPiI2C.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define Device_Address 0x68 /* i2c-MPU6050*/

#define PWR_MGMT_1   0x6B
#define SMPLRT_DIV   0x19
#define CONFIG       0x1A
#define GYRO_CONFIG  0x1B
#define INT_ENABLE   0x38
#define ACCEL_XOUT_H 0x3B
#define ACCEL_YOUT_H 0x3D
#define ACCEL_ZOUT_H 0x3F
#define GYRO_XOUT_H  0x43
#define GYRO_YOUT_H  0x45
#define GYRO_ZOUT_H  0x47


int fd;

void MPU6050_Init(){

    wiringPiI2CWriteReg8 (fd, PWR_MGMT_1, 0x00);    /* Disable sleep mode*/
    wiringPiI2CWriteReg8 (fd, SMPLRT_DIV, 0x07);    /* 8khz/(1+7)=1khz */
    wiringPiI2CWriteReg8 (fd, CONFIG, 0x00);        /* FSYNC and DLPG_CFG disabled for maximum bandwith*/
    wiringPiI2CWriteReg8 (fd, GYRO_CONFIG, 0x00);   /* +- 200°/s, and acc by default +-2g's*/

    } 
short read_raw_data(int addr){
    short high_byte,low_byte,value;
    high_byte = wiringPiI2CReadReg8(fd, addr);
    low_byte = wiringPiI2CReadReg8(fd, addr+1);
    value = (high_byte << 8) | low_byte;
    return value;
}
void passtime(int uSeconds)
{


    // Storing start time 
    clock_t start_time = clock();  //time in microseconds. 

    // looping till required time is not achieved 
    while (clock() < start_time +uSeconds);


}

int main(){
    double time_spent = 0.0;


    float Acc_x,Acc_y,Acc_z;
    float Gyro_x,Gyro_y,Gyro_z;
    float Ax=0, Ay=0, Az=0;
    float Gx=0, Gy=0, Gz=0;
    fd = wiringPiI2CSetup(Device_Address);   /*Initializes I2C with device Address*/
    MPU6050_Init();                          /* Initializes MPU6050 */
    int count =0;
    passtime(10000);

    clock_t begin = clock();

    while(count<1000)
    {

        //Maximum output rate of MPU6050 is Accelerometer+Gyroscope = 1khz => 1 data read per milisecond 
        /*Read raw value of Accelerometer and gyroscope from MPU6050*/


        Acc_x = read_raw_data(ACCEL_XOUT_H);
        Acc_y = read_raw_data(ACCEL_YOUT_H);
        Acc_z = read_raw_data(ACCEL_ZOUT_H);

        Gyro_x = read_raw_data(GYRO_XOUT_H);
        Gyro_y = read_raw_data(GYRO_YOUT_H);
        Gyro_z = read_raw_data(GYRO_ZOUT_H);

        /* Divide raw value by sensitivity scale factor for +-2g's, and +-250/s */

        Ax = Acc_x/16384.0;
        Ay = Acc_y/16384.0;
        Az = Acc_z/16384.0;

        Gx = Gyro_x/131;
        Gy = Gyro_y/131;
        Gz = Gyro_z/131;



        //printf("\n Gx=%.3f \tGy=%.3f \tGz=%.3f \tAx=%.3f g\tAy=%.3f g\tAz=%.3f g\n",Gx,Gy,Gz,Ax,Ay,Az);

        count++;

    }


        clock_t end = clock();

        time_spent += (double)(end-begin)/CLOCKS_PER_SEC;

        printf("Time spent %lf after %d data reads\n",time_spent,count);

    getchar();    
    return 0;
}
/* OUTPUT:
 * Time spent 0.2312s after 1000data reads*/
eimvs
  • 45
  • 10

3 Answers3

2

First of all, my time measuring was faulty. I've noticed that during data sampling intervals systemcalls do not increase my measured overall time, wallclock time was much higher. After raising i2c port speed from 100khz to 400hz i was able to get 4 times as much samples. So i assume,that I've encountered i2c bottleneck

eimvs
  • 45
  • 10
1

The data output rate refers to the rate at which data are accumulated in the MPU6050's FIFO. This is different to the rate at which the data can be read out of the FIFO, which is what you are measuring.

In the datasheet, it says:

An on-chip 1024 Byte FIFO buffer helps lower system power consumption by allowing the system processor to read the sensor data in bursts and then enter a low-power mode as the MPU collects more data.

The MPU6050 is sampling data at 1 kHz (set by you) and stores that in it's FIFO. Then, you read that out when convenient. It is a power saving feature, as the system processor doesn't haven't to be awake constantly, it just has to wake up and quickly grab the data that was accummulated while it was in low power sleep. The MPU6050 has I2C and SPI interfaces, so you can "download" the data even faster than you are already.

EDIT - not using FIFO...

In the while (count < 1000) loop, you are not waiting for new data to be sampled by the MPU6050. You should use the data ready interrupt on the INT pin (pin 12), which will be asserted when new data are ready. Assuming you've set it active high, you could put a stall in with while (INT == 0), or put it in an ISR depending on your application.

awjlogan
  • 7,879
  • 2
  • 29
  • 45
  • Thanks for the help, but i don't think that i enabled FIFO anywhere. Plus i have tried adding this to MPU6050 init(); function: Writing to register 0x6A, value 0x5 //Clears and disables FIFO + Sensor Data registers. and writing to register 0x23 value 0x0) //Disables all sensor write in a FIFO buffer and i still get the same results. – eimvs Mar 22 '19 at 13:16
  • Ah - you're not accummulating in the FIFO then, but you're just reading out the same data from the registers (I will change the answer). You should use the interrupt pin (INT, 12) to trigger your read out. – awjlogan Mar 22 '19 at 13:24
1

In addition to awjlogan answer - you don't have to use INT pin of MPU6050 to watch for a new data - the INT_STATUS register shows the interrupt and cleared once data registers are read. Of course mcu time will be spent on reading the status register over the I2C link. Also, seems your reading from mpu6050 is a bit inefficient - it uses 16 bits reading (guessed as no source for read_raw_data() is present in OP. Better to read data in burst for all 14 registers (temp included) at once in one single sequence. Each read from mpu6050 results in sending of start condition + slave address + register address + repeated start + slave address then actual data. When reading data in burst there will only be one such sequence followed by all 14 registers. The drawback is - 2 temperature sensor registers read in the middle of the burst sequence. For fast reading from mpu6050 arduino must handle mpu's INT connection as awjlogan said. If there is a need to go even faster and to gain time to process the data - ISR for I2C including state machine transition logic (the standard ISR handling for I2C is bulky due to many conditions to check from TWI status register) for 14 register read sequence. Note that the purpose of INT pin or interrupt status pin in mpu6050 is to differentiate between different samples. If you don't check for that then you may get 2 reads for the same sample. of course you may compare accelerometer values from sequential reads (thanks to noisy mpu6050) and drops those whose measurement are same. But if the job you are doing requires strict timing related to sample rate - the mpu6050's INT pin interrupt handling is the ONLY way to go.

Asaf Sirin
  • 11
  • 1