Here's my setup:
I have a master arduino (using a Pro Mini 5V) and it addresses a slave. What I want the slave to do is read four pressure sensors and get IMU data from an MPU9250. I want to be able to have the master talk to the slave and the slave talk to the IMU all on the same I2C bus. The problem comes after the master talks to the slave. The slave then wants to talk to the IMU, but the clock signal (SCL) disappears because it is generated by the master not the slave. I tried to use a switch that would disconnect the master SDA line from the slave SDA line and connect the slave SDA line to the IMU SDA line.
Here's the Master code:
#include <Wire.h>
byte Buf[14];
byte Mag[6];
byte pressure[8];
void setup()
{
Wire.begin();
Serial.begin(250000);
}
void loop()
{
//Serial.print("hey");
Wire.requestFrom(8, 8);
if(!Wire.available())
{
Serial.print("wire not available");
}
while(Wire.available())
{
for(int i=0; i<sizeof(Buf); i++)
{
Buf[i] = Wire.read();
}
for(int i=0; i<sizeof(Mag); i++)
{
Mag[i] = Wire.read();
}
for(int i=0; i<sizeof(pressure); i++)
{
pressure[i] = Wire.read();
}
}
// ____________________________________
// ::: accelerometer and gyroscope :::
// Create 16 bits values from 8 bits data
// Accelerometer
int16_t ax=Buf[0]<<8 | Buf[1];
int16_t ay=Buf[2]<<8 | Buf[3];
int16_t az=Buf[4]<<8 | Buf[5];
// Gyroscope
int16_t gx=Buf[8]<<8 | Buf[9];
int16_t gy=Buf[10]<<8 | Buf[11];
int16_t gz=Buf[12]<<8 | Buf[13];
// _____________________
// ::: Magnetometer :::
// Create 16 bits values from 8 bits data
// Magnetometer
int16_t mx=Mag[1]<<8 | Mag[0];
int16_t my=Mag[3]<<8 | Mag[2];
int16_t mz=Mag[5]<<8 | Mag[4];
// _________________
// ::: Pressure :::
// Create 16 bits values from 8 bits data
int16_t p1 = pressure[0]<<8 | pressure[1];
int16_t p2 = pressure[2]<<8 | pressure[3];
int16_t p3 = pressure[4]<<8 | pressure[5];
int16_t p4 = pressure[6]<<8 | pressure[7];
Serial.print("Accel = ");
Serial.print(ax);
Serial.print(",");
Serial.print(ay);
Serial.print(",");
Serial.println(az);
Serial.print("Gyro = ");
Serial.print(gx);
Serial.print(",");
Serial.print(gy);
Serial.print(",");
Serial.println(gz);
Serial.print("mag = ");
Serial.print(mx);
Serial.print(",");
Serial.print(my);
Serial.print(",");
Serial.println(mz);
Serial.print("pressure = ");
Serial.print(p1);
Serial.print(",");
Serial.print(p2);
Serial.print(",");
Serial.print(p3);
Serial.print(",");
Serial.println(p4);
}
And here's the Slave code:
#include <Wire.h>
#define MPU9250_ADDRESS 0x69
#define MAG_ADDRESS 0x0C
#define GYRO_FULL_SCALE_250_DPS 0x00
#define GYRO_FULL_SCALE_500_DPS 0x08
#define GYRO_FULL_SCALE_1000_DPS 0x10
#define GYRO_FULL_SCALE_2000_DPS 0x18
#define ACC_FULL_SCALE_2_G 0x00
#define ACC_FULL_SCALE_4_G 0x08
#define ACC_FULL_SCALE_8_G 0x10
#define ACC_FULL_SCALE_16_G 0x18
byte pressure[8];
int analog[4] = {A0, A1, A2, A3};
bool configure = true;
//
//// This function read Nbytes bytes from I2C device at address Address.
//// Put read bytes starting at register Register in the Data array.
void I2Cread(uint8_t Address, uint8_t Register, uint8_t Nbytes, uint8_t* Data)
{
// Set register address
Wire.beginTransmission(Address);
Wire.write(Register);
Wire.endTransmission();
// Read Nbytes
Wire.requestFrom(Address, Nbytes);
uint8_t index=0;
while (Wire.available())
Data[index++]=Wire.read();
}
// Write a byte (Data) in device (Address) at register (Register)
void I2CwriteByte(uint8_t Address, uint8_t Register, uint8_t Data)
{
// Set register address
Wire.beginTransmission(Address);
Wire.write(Register);
Wire.write(Data);
Wire.endTransmission();
}
void read_ADC(byte *input)
{
int j = 0;
int ADC;
for(int i=0; i<4; i++)
{
ADC = analogRead(analog[i]);
input[j]=highByte(ADC);
input[j+1]=lowByte(ADC);
j=j+2;
}
}
void setup()
{
pinMode(13, OUTPUT);
pinMode(0, OUTPUT);
pinMode(8, OUTPUT);
//configure ADC pins
pinMode(A0, INPUT);
pinMode(A1, INPUT);
pinMode(A2, INPUT);
pinMode(A3, INPUT);
pinMode(A4, OUTPUT);
pinMode(A5, OUTPUT);
Wire.begin(8);
Wire.onRequest(run_event);
}
void loop()
{
}
void run_event()
{
//turn pin 2 high to switch the data line to the MPU9250
digitalWrite(0, HIGH);
// digitalWrite(8, HIGH);
if(configure == true)
{
digitalWrite(8, HIGH);
// Configure gyroscope range
I2CwriteByte(MPU9250_ADDRESS,27,GYRO_FULL_SCALE_2000_DPS);
// Configure accelerometers range
I2CwriteByte(MPU9250_ADDRESS,28,ACC_FULL_SCALE_16_G);
// Set by pass mode for the magnetometers
I2CwriteByte(MPU9250_ADDRESS,0x37,0x02);
// Request first magnetometer single measurement
I2CwriteByte(MAG_ADDRESS,0x0A,0x01);
configure = false;
digitalWrite(8, LOW);
}
// ____________________________________
// ::: accelerometer and gyroscope :::
// Read accelerometer and gyroscope
byte Buf[14];
I2Cread(MPU9250_ADDRESS,0x3B,14,Buf);
// Create 16 bits values from 8 bits data
// Accelerometer
int16_t ax=Buf[0]<<8 | Buf[1];
int16_t ay=Buf[2]<<8 | Buf[3];
int16_t az=Buf[4]<<8 | Buf[5];
// Gyroscope
int16_t gx=Buf[8]<<8 | Buf[9];
int16_t gy=Buf[10]<<8 | Buf[11];
int16_t gz=Buf[12]<<8 | Buf[13];
// _____________________
// ::: Magnetometer :::
// Read register Status 1 and wait for the DRDY: Data Ready
uint8_t ST1;
do
{
I2Cread(MAG_ADDRESS,0x02,1,&ST1);
}
while (!(ST1&0x01));
// Read magnetometer data
byte Mag[6];
I2Cread(MAG_ADDRESS,0x03,6,Mag);
// Request next magnetometer single measurement
I2CwriteByte(MAG_ADDRESS,0x0A,0x01);
// Create 16 bits values from 8 bits data
// // Magnetometer
int16_t mx=Mag[1]<<8 | Mag[0];
int16_t my=Mag[3]<<8 | Mag[2];
int16_t mz=Mag[5]<<8 | Mag[4];
read_ADC(pressure);
//turn pin 13 low to switch data line back to master arduino
digitalWrite(0, LOW);
for(int i=0; i<sizeof(Buf); i++)
{
Wire.write(Buf[i]);
}
for(int i=0; i<sizeof(Mag); i++)
{
Wire.write(Mag[i]);
}
for(int i=0; i<sizeof(pressure); i++)
{
Wire.write(pressure[i]);
}
}
The digitalWrite(0, HIGH) is for the switch on the SDA line. When the switch is activated, it switches the SDA line on the slave from the master to the IMU. The clock does not keep running though, which was what I hoped for. I think there is something I am misunderstanding about how the clock works.
Any help would be greatly appreciated.