Multiple MPU-6050 connected to TCA9548A Multiplexer

Hi,

I'm working on a project where I need 8 GY-521 accelerometers (MPU-6050) attached to an aero-elastic bridge model. In order to this i understand that a TCA9548A multiplexer is nessesary to achieve individual addresses for each of the MPU-6050s.

The MPU-6050 only have a high and a low adress (0x68 and 0x69), I'm not sure have I can expand this range of adresses.

I'm currently using a Arduino Mega 2560 board.

Hope that you can help with a simple script thanks.

Best regards
J. Jørgensen

You don't need to use a multiplexer, if you have enough I/O pins. Just use an I/O pin to control the address inputs of the MPU-6050 sensors, so that only one has the base address (0x68) at any time.

Only the one sensor addressed will respond to the I2C bus.

But I only have two

Two what?

Do you have a code for this setup (more than two MPU-6050s?
Thanks

Just assign and connect a digital output pin to each address input on the sensors.

digitalWrite(pin, HIGH) sets the address of that sensor to 0x69. Only the sensor with address pin set to LOW will respond to the I2C bus at address 0x68.

I managed to create a script with 3 running MPU-6050's on a TCA9548A Multiplexer, attached code below.

I need 8 MPU-5060 in total however I can already tell that the sampling freq. will decrease significantly see graph below.

Can I somehow increase the sampling frequency?

PLOTTER:

#include <Wire.h>
#include <MPU6050.h>

#define TCA_ADDRESS 0x70 // Address of the TCA9548A multiplexer
#define NUM_MPU 3

MPU6050 mpu[NUM_MPU];
int16_t accelX[NUM_MPU], accelY[NUM_MPU], accelZ[NUM_MPU];

void setup() {
  Wire.begin();
  Serial.begin(115200);
  delay(1000);
  Serial.println("Begin");

  // Initialize all MPU sensors
  for (int i = 0; i < NUM_MPU; i++) {
    TCASelect(TCA_ADDRESS, i);
    mpu[i].initialize();
  }
}

void loop() {
  // Read accelerometer data from all connected MPU sensors
  for (int i = 0; i < NUM_MPU; i++) {
    TCASelect(TCA_ADDRESS, i); // Select the channel for the current MPU
    readAccelData(mpu[i], accelX[i], accelY[i], accelZ[i]);
  }

  // Print the acceleration values for all sensors on the same line with tabs
  for (int i = 0; i < NUM_MPU; i++) {
    Serial.print("Sensor ");
    Serial.print(i + 1);
    Serial.print(":\t");
    printWithPrecision(accelX[i] / 16384.0, 6);
    printWithPrecision(accelY[i] / 16384.0, 6);
    printWithPrecision(accelZ[i] / 16384.0, 6);

    if (i < NUM_MPU - 1) {
      Serial.print("\t| ");
    }
  }

  Serial.println(); // Move to the next line for the next set of readings
  delay(100);        // Adjust the delay based on your application
}

void TCASelect(uint8_t i2c_address, uint8_t bus) {
  Wire.beginTransmission(i2c_address);
  Wire.write(1 << bus);
  Wire.endTransmission();
}

void readAccelData(MPU6050& mpu, int16_t& accelX, int16_t& accelY, int16_t& accelZ) {
  mpu.getAcceleration(&accelX, &accelY, &accelZ);
}

void printWithPrecision(float value, int digits) {
  Serial.print(value, digits);
  Serial.print("\t");
}

LOGDATA:

#include <Wire.h>
#include <MPU6050.h>
#include <SD.h>

#define TCA_ADDRESS 0x70 // Address of the TCA9548A multiplexer
#define NUM_MPU 1

MPU6050 mpu[NUM_MPU];
int16_t accelX[NUM_MPU], accelY[NUM_MPU], accelZ[NUM_MPU];

const int CS_PIN = 53; // Chip Select pin for SD card module
File dataFile; // File object to write data to SD card

uint32_t counter = 0;
unsigned long startTime;
const unsigned long loggingDuration = 10 * 1000000; // Logging duration in microseconds (10 seconds)
bool loggingStarted = false;

void setup() {
  Wire.begin();
  Serial.begin(115200);

  // Initialize SD card
  if (!SD.begin(CS_PIN)) { // Use the CS (Chip Select) pin number you have connected to on your Arduino
    Serial.println("SD initialization failed!");
    while (1); // Stop further execution if SD initialization fails
  }

  // Initialize all MPU sensors
  for (int i = 0; i < NUM_MPU; i++) {
    TCASelect(TCA_ADDRESS, i);
    mpu[i].initialize();
  }
  
  delay(1000);
  Serial.println("Type 'Start' to begin data collection.");
  delay(1000);
}

void loop() {
  if (!loggingStarted) {
    if (Serial.available() > 0) {
      String input = Serial.readStringUntil('\n');
      if (input == "Start") {
        startDataCollection();
      }
    }
  } else {
    // Read accelerometer data from all connected MPU sensors
    for (int i = 0; i < NUM_MPU; i++) {
      TCASelect(TCA_ADDRESS, i); // Select the channel for the current MPU
      readAccelData(mpu[i], accelX[i], accelY[i], accelZ[i]);
    }

    // Open the file in append mode
    dataFile = SD.open("data.txt", FILE_WRITE);

    if (dataFile) {
      // Print the acceleration values for all sensors along with the current time to the file
      dataFile.print(micros() - startTime);
      dataFile.print("\t");

      for (int i = 0; i < NUM_MPU; i++) {
        dataFile.print(accelX[i] / 16384.0, 6);
        dataFile.print("\t");
        dataFile.print(accelY[i] / 16384.0, 6);
        dataFile.print("\t");
        dataFile.print(accelZ[i] / 16384.0, 6);

        if (i < NUM_MPU - 1) {
          dataFile.print("\t ");
        }
      }

      dataFile.println();
      dataFile.close();
    } else {
      Serial.println("Error writing to data.txt");
    }

    // Check if the logging duration has been reached
    if (micros() - startTime >= loggingDuration) {
      Serial.println("Logging complete. Exiting...");
      while (1); // Stop further execution
    }
  }
  delay(0.001); // Adjust the delay based on your application
}

void TCASelect(uint8_t i2c_address, uint8_t bus) {
  Wire.beginTransmission(i2c_address);
  Wire.write(1 << bus);
  Wire.endTransmission();
}

void readAccelData(MPU6050& mpu, int16_t& accelX, int16_t& accelY, int16_t& accelZ) {
  mpu.getAcceleration(&accelX, &accelY, &accelZ);
}

void startDataCollection() {
  Serial.println("Recording data...");
  dataFile = SD.open("data.txt", FILE_WRITE);

  // Check if the file opened successfully
  if (dataFile) {
    dataFile.println("Time \t AccelX1 \t AccelY1 \t AccelZ1 \t AccelX2 \t AccelY2 \t AccelZ2 \t AccelX3 \t AccelY3 \t AccelZ3");
    dataFile.close();
    loggingStarted = true;
    startTime = micros(); // Record the start time in microseconds
  } else {
    Serial.println("Error opening data.txt");
  }
}

Use of the serial multiplexer greatly slows down the sample frequency. Also, opening the SD card file, writing one line of data, and closing it again, is even worse, as that takes a large amount of time, and greatly increases both the SD card error rate and current draw.

How can I work around this?

Don't use the serial multiplexer, as described above, and open the SD file once in setup().

Close the file only when you are done collecting data.

Can you describe how the MPU-6050s should be connected to the Mega 2560 board?
Thanks

See posts #2 and #6. Choose any free digital pins for the address control.

And this I can do for 8 MPU's on the Mega2560?

Yes, but note that the Mega2560 is a 5V device and the MPU-6050 is a 3.3V device. You need logic level shifters between the I/O pins, if your MPU-6050 modules do not already have them.

Much better to use a 3.3V Arduino.

You could add

Wire.setClock(400000); //  or even 500000 or 600000 - test when it fails and go 50K below that

I2C at 400K is about 2.5 faster than 100K (default) for most devices.

Don't know the max speed of the MPU-6050 (check datasheet)

Serial.begin(115200);

you might set the baud rate to 500000 so less time is spend for Serial communication.

Hi again,
I made some changes, increased baud rate and wire.setClock(); see below:

#include <Wire.h>
#include <MPU6050.h>
#include <SD.h>

#define TCA_ADDRESS 0x70 // Address of the TCA9548A multiplexer
#define NUM_MPU 8

MPU6050 mpu[NUM_MPU];
int16_t accelX[NUM_MPU], accelY[NUM_MPU], accelZ[NUM_MPU];

const int CS_PIN = 53; // Chip Select pin for SD card module
File dataFile; // File object to write data to SD card

uint32_t counter = 0;
unsigned long startTime;
const unsigned long loggingDuration = 10 * 1000000; // Logging duration in microseconds (10 seconds)
bool loggingStarted = false;

void setup() {
  Wire.begin();
  Wire.setClock(800000);
  Serial.begin(500000);
  
  // Initialize SD card
  if (!SD.begin(CS_PIN)) { // Use the CS (Chip Select) pin number you have connected to on your Arduino
    Serial.println("SD initialization failed!");
    while (1); // Stop further execution if SD initialization fails
  }

  // Initialize all MPU sensors
  for (int i = 0; i < NUM_MPU; i++) {
    TCASelect(TCA_ADDRESS, i);
    mpu[i].initialize();
  }
  
  delay(100);
  Serial.println("Type 'Start' to begin data collection.");
  delay(100);
}

void loop() {
  if (!loggingStarted) {
    if (Serial.available() > 0) {
      String input = Serial.readStringUntil('\n');
      if (input == "Start") {
        startDataCollection();
      }
    }
  } else {
    // Read accelerometer data from all connected MPU sensors
    for (int i = 0; i < NUM_MPU; i++) {
      TCASelect(TCA_ADDRESS, i); // Select the channel for the current MPU
      readAccelData(mpu[i], accelX[i], accelY[i], accelZ[i]);
    }

    // Open the file in append mode
    dataFile = SD.open("data.txt", FILE_WRITE);

    if (dataFile) {
      // Print the acceleration values for all sensors along with the current time to the file
      dataFile.print(micros() - startTime);
      dataFile.print("\t");

      for (int i = 0; i < NUM_MPU; i++) {
        dataFile.print(accelX[i] / 16384.0, 6);
        dataFile.print("\t");
        dataFile.print(accelY[i] / 16384.0, 6);
        dataFile.print("\t");
        dataFile.print(accelZ[i] / 16384.0, 6);

        if (i < NUM_MPU - 1) {
          dataFile.print("\t ");
        }
      }

      dataFile.println();
      dataFile.close();
    } else {
      Serial.println("Error writing to data.txt");
    }

    // Check if the logging duration has been reached
    if (micros() - startTime >= loggingDuration) {
      Serial.println("Logging complete. Exiting...");
      while (1); // Stop further execution
    }
  }
}

void TCASelect(uint8_t i2c_address, uint8_t bus) {
  Wire.beginTransmission(i2c_address);
  Wire.write(1 << bus);
  Wire.endTransmission();
}

void readAccelData(MPU6050& mpu, int16_t& accelX, int16_t& accelY, int16_t& accelZ) {
  mpu.getAcceleration(&accelX, &accelY, &accelZ);
}

void startDataCollection() {
  Serial.println("Recording data...");
  dataFile = SD.open("data.txt", FILE_WRITE);

  // Check if the file opened successfully
  if (dataFile) {
    dataFile.println("Time \t AccelX1 \t AccelY1 \t AccelZ1 \t AccelX2 \t AccelY2 \t AccelZ2 \t AccelX3 \t AccelY3 \t AccelZ3");
    dataFile.close();
    loggingStarted = true;
    startTime = micros(); // Record the start time in microseconds
  } else {
    Serial.println("Error opening data.txt");
  }
}

How can I increase the sampling rate even more? currently it is 20.981Hz for 8 MPU-6050s.

I don't know how to collect the data to the SD module outside of the loop?

Thanks

dataBuffer[i].accelZ / 16384.0  ===>  dataBuffer[i].accelZ * 6.103515625e-5

multiplication is much faster than division on many processors


Collecting every line in a (String) buffer and then print it in one go to the SD card
is probably faster.


dataFile.print("\t");    ===>  dataFile.print('\t') 

using single quote == char
using double quote == char array (with \0 at the end) more expensive


      if (i < bufferIndex - 1) {
        dataFile.print("\t ");

if you don't care that there is a \t at the end of every line , you can remove the condition.

@jakob1314

Maximum achievable data rate for 8 MPU:
I2C frequency = 400kHz
Number of bytes transferred to select MUX channel = 2
Number of bytes transferred to read the acceleration data = 9
Total number of bits transferred (9+2) x 8 + 6 overhead bits = 94 bits
Max sampling rate = 400kHz/94 = 4255 Hz per MPU
For 8 MPUs: 4255/8 = 532Hz

So if you stripped down your code to nothing but selecting the MUX channel and reading the acceleration data for 8 MPUs the maximum sampling rate will be 532Hz
If you want more than that, forget about it.

Thank you.

532Hz is more than enough! but somehow I only manage to get around 20Hz. How can this be?

#include <Wire.h>
#include <MPU6050.h>
#include <SD.h>

#define TCA_ADDRESS 0x70 // Address of the TCA9548A multiplexer
#define NUM_MPU 8

MPU6050 mpu[NUM_MPU];
int16_t accelX[NUM_MPU], accelY[NUM_MPU], accelZ[NUM_MPU];

const int CS_PIN = 53; // Chip Select pin for SD card module
File dataFile; // File object to write data to SD card

uint32_t counter = 0;
unsigned long startTime;
const unsigned long loggingDuration = 10 * 1000000; // Logging duration in microseconds (10 seconds)
bool loggingStarted = false;

void setup() {
  Wire.begin();
  Serial.begin(500000);
  Wire.setClock(532000);
    
  // Initialize SD card
  if (!SD.begin(CS_PIN)) { // Use the CS (Chip Select) pin number you have connected to on your Arduino
    Serial.println("SD initialization failed!");
    while (1); // Stop further execution if SD initialization fails
  }

  // Initialize all MPU sensors
  for (int i = 0; i < NUM_MPU; i++) {
    TCASelect(TCA_ADDRESS, i);
    mpu[i].initialize();
  }
  
  Serial.println("Type 'Start' to begin data collection.");
}

void loop() {
  if (!loggingStarted) {
    if (Serial.available() > 0) {
      String input = Serial.readStringUntil('\n');
      if (input == "Start") {
        startDataCollection();
      }
    }
  } else {
    // Read accelerometer data from all connected MPU sensors
    for (int i = 0; i < NUM_MPU; i++) {
      TCASelect(TCA_ADDRESS, i); // Select the channel for the current MPU
      readAccelData(mpu[i], accelX[i], accelY[i], accelZ[i]);
    }

    // Open the file in append mode
    dataFile = SD.open("data.txt", FILE_WRITE);

    if (dataFile) {
      // Print the acceleration values for all sensors along with the current time to the file
      dataFile.print(micros() - startTime);
      dataFile.print("\t");

      for (int i = 0; i < NUM_MPU; i++) {
        dataFile.print(accelX[i] / 16384.0, 6);
        dataFile.print("\t");
        dataFile.print(accelY[i] / 16384.0, 6);
        dataFile.print("\t");
        dataFile.print(accelZ[i] / 16384.0, 6);

        if (i < NUM_MPU - 1) {
          dataFile.print("\t ");
        }
      }

      dataFile.println();
      dataFile.close();
    } else {
      Serial.println("Error writing to data.txt");
    }

    // Check if the logging duration has been reached
    if (micros() - startTime >= loggingDuration) {
      Serial.println("Logging complete. Exiting...");
      while (1); // Stop further execution
    }
  }
}

void TCASelect(uint8_t i2c_address, uint8_t bus) {
  Wire.beginTransmission(i2c_address);
  Wire.write(1 << bus);
  Wire.endTransmission();
}

void readAccelData(MPU6050& mpu, int16_t& accelX, int16_t& accelY, int16_t& accelZ) {
  mpu.getAcceleration(&accelX, &accelY, &accelZ);
}

void startDataCollection() {
  Serial.println("Recording data...");
  dataFile = SD.open("data.txt", FILE_WRITE);

  // Check if the file opened successfully
  if (dataFile) {
    dataFile.println("Time \t AccelX1 \t AccelY1 \t AccelZ1 \t AccelX2 \t AccelY2 \t AccelZ2 \t AccelX3 \t AccelY3 \t AccelZ3");
    dataFile.close();
    loggingStarted = true;
    startTime = micros(); // Record the start time in microseconds
  } else {
    Serial.println("Error opening data.txt");
  }
}


Here is a little sample of the data file

8464	0.011963	-0.097412	1.031494	 -0.010986	-0.047852	0.945312	 0.010498	-0.081055	1.023926	 0.012451	-0.031250	0.933105	 -0.029297	0.003662	0.990723	 0.061523	0.038818	0.967529	 0.016113	0.052246	1.016113	 -0.018066	0.071777	0.893799
53932	0.014160	-0.071777	1.019775	 -0.019775	-0.022461	0.944580	 0.000488	-0.053955	1.036377	 0.013672	-0.012695	0.923828	 -0.030762	0.017822	1.000244	 0.055420	0.050049	0.975342	 0.018311	0.066162	1.007568	 -0.012939	0.082275	0.905029
102456	0.013428	-0.090332	1.037598	 -0.007813	-0.033203	0.939697	 0.009033	-0.067139	1.026855	 0.019043	-0.026123	0.937256	 -0.030762	0.012939	0.998047	 0.055420	0.043945	0.983643	 0.017822	0.061523	1.007568	 -0.020752	0.077637	0.902100
147952	0.014404	-0.085449	1.011475	 -0.015625	-0.039795	0.941162	 0.005859	-0.064209	1.026123	 0.013916	-0.026855	0.933350	 -0.029785	0.012695	1.005371	 0.051025	0.046875	0.983398	 0.012207	0.057617	1.012939	 -0.017578	0.076660	0.892090
196568	0.011719	-0.091797	1.027344	 -0.010010	-0.035156	0.931152	 0.010010	-0.068359	1.035645	 0.011963	-0.021973	0.936035	 -0.030518	0.003418	0.997070	 0.058838	0.041992	0.979736	 0.014404	0.055176	1.003418	 -0.012451	0.079346	0.895996
242076	0.016357	-0.086426	1.018555	 -0.021729	-0.032715	0.938965	 0.002441	-0.064697	1.034668	 0.020264	-0.021729	0.934326	 -0.032471	0.004395	1.000000	 0.058350	0.043701	0.980713	 0.012695	0.056885	1.020020	 -0.012207	0.075195	0.894775
287592	0.019531	-0.089844	1.009766	 -0.009033	-0.038818	0.942383	 0.003906	-0.065918	1.033203	 0.013184	-0.031250	0.932617	 -0.025635	0.006348	1.008789	 0.058350	0.047607	0.973145	 0.010254	0.059082	1.002441	 -0.016602	0.076172	0.904541
336144	0.012695	-0.087158	1.022217	 -0.008545	-0.040039	0.943603	 0.006104	-0.066406	1.025146	 0.018311	-0.021484	0.932617	 -0.029785	0.010498	1.002197	 0.052246	0.042969	0.982178	 0.012939	0.060547	1.003174	 -0.006348	0.075684	0.906982
381624	0.016357	-0.083008	1.026855	 -0.013184	-0.039551	0.945557	 0.002197	-0.072510	1.024170	 0.022705	-0.025879	0.925537	 -0.029053	0.005859	1.010010	 0.056641	0.045898	0.985107	 0.017090	0.059570	1.019043	 -0.012939	0.070801	0.896240
430180	0.016357	-0.087158	1.017334	 -0.010986	-0.032227	0.945068	 0.004639	-0.065186	1.029541	 0.014160	-0.029053	0.936279	 -0.025635	0.017334	0.999756	 0.056641	0.045410	0.977295	 0.015381	0.064209	1.005371	 -0.014648	0.079102	0.897217
475832	0.014160	-0.080322	1.035889	 -0.015137	-0.030518	0.945557	 0.003662	-0.068115	1.028320	 0.017090	-0.024658	0.931152	 -0.022461	0.013428	0.994141	 0.056641	0.041016	0.982178	 0.009277	0.058105	1.013672	 -0.018066	0.077393	0.900146
524412	0.010986	-0.081543	1.036377	 -0.015137	-0.036133	0.940430	 0.011230	-0.072510	1.028564	 0.016113	-0.018799	0.930176	 -0.028809	0.007813	1.015625	 0.055176	0.038818	0.973633	 0.012451	0.062012	1.005615	 -0.005615	0.081299	0.895508
569944	0.012207	-0.085937	1.024658	 -0.016113	-0.039307	0.945312	 0.003662	-0.065430	1.036377	 0.010254	-0.028809	0.934570	 -0.030518	0.010010	0.997559	 0.053955	0.041504	0.982422	 0.017090	0.062256	1.004639	 -0.013428	0.066650	0.897705
618524	0.015625	-0.083984	1.024902	 -0.007324	-0.035645	0.947754	 0.011719	-0.065186	1.025146	 0.008545	-0.029785	0.921387	 -0.027344	0.012695	1.000244	 0.053711	0.040527	0.982910	 0.015381	0.056641	1.010498	 -0.009277	0.080811	0.900146
664040	0.020508	-0.089600	1.025391	 -0.011963	-0.033447	0.935791	 0.017090	-0.065674	1.034668	 0.012939	-0.026611	0.937744	 -0.029053	0.005615	1.000000	 0.052979	0.041992	0.978516	 0.021240	0.052002	1.004639	 -0.005127	0.075684	0.899414
712768	0.010986	-0.088867	1.026367	 -0.012695	-0.031494	0.931641	 0.006592	-0.066406	1.021973	 0.010986	-0.024414	0.938477	 -0.035156	0.012939	1.002441	 0.061523	0.047119	0.981689	 0.013184	0.057861	1.015869	 -0.016357	0.084473	0.904785
758460	0.019775	-0.089111	1.018555	 -0.010742	-0.036133	0.939697	 0.005127	-0.062012	1.034180	 0.005859	-0.023437	0.937500	 -0.032227	0.012939	1.009033	 0.052734	0.042969	0.980713	 0.014648	0.062500	1.010010	 -0.016113	0.075439	0.896728
807192	0.018311	-0.083252	1.020508	 -0.013672	-0.032959	0.947510	 0.007568	-0.064697	1.031250	 0.019531	-0.017822	0.931152	 -0.032959	0.012451	0.997314	 0.056885	0.045410	0.978027	 0.011963	0.058838	1.003418	 -0.018799	0.082275	0.903076