The GY-9255 sensor uses MPU-9255 chip. The MPU9255 is a 9-axis sensor which packages the accelerometer, gyroscope, magnetometer together each provides data for x, y and z axes. Other than the three mentioned sensors, it also has other features like Pedometer, Motion and Tap detection, and Temperature (if I recall correctly).
Explanation of the pins:
- VCC: This pin goes to 3.3 volt pin of the Arduino
- GND: This pin goes to GND pin
- SCL: Clock line for I2C or SPI communication. I use it as I2C which connects to pin 5 of the Arduino or pin 21 of the Mega 2560. In SPI mode this is the clock line.
- SDA: Data line for I2C or SPI. For I2C it connects to Arduino pin 4 or Mega 2560 pin 20. For SPI it is data input line.
- EDA and ECL: These two pins are for serial communication to external sensor or device.
- ADO: In I2C mode, it is used to define the address of the sensor. In SPI mode, this is data output line.
- INT: Interrupt line where the sensor can notify the Arduino when data is ready or motion is detected, depending on the configuration.
- nCS: Chip select pin, used in SPI mode.
- FSYNC: Can be used for different purposes depending on the configuration.
Summing up on the pins, to get this device working in I2C mode, pins VCC, GND, SCL, SDA, ADO and FSYNC are used. Before going into programming, I want to briefly mention a little information about the device. There are two specification for the MPU-9255 that you may want to read. The first one is the MPU-9255 Product Specification (PS-MPU-9255) and the second one is the MPU-9255 Register Map and Description (RM-MPU-92551). In general you would need the Register Map document most but there are scattered information in the Product Specification that you would need. First lets look at the block diagram of the MPU-9255:
There is one thing I want to point out in the diagram above. It has the master I2C and Slave I2C. The master I2C connects to the AUX_CL and AUX_DA (which are the ECL and EDA pins) through the Serial Interface Bypass Mux. When enabled, the master I2C talks to the external sensor that is connected to AUX_CL and AUX_DA, feed to data register to be read from the SCL and SDA lines. When disabled, aka the Serial Interface Bypass Mux is set to bypass mode, the external sensor's data go directly to the SDA line. The compass sensor is really the "external sensor" according to the block diagram. In this tutorial, I will disable the master I2C and have the Arduino or Mega board talking to the magnetometer directly. In the I2C mode, the ADO pin is used as part of the sensor address designation. When ADO grounded (LOW) the sensor address is 0x68 and when pulled up to VDD (HIGH) the address is 0x69.
Steps to configure the sensor:
- Initialize the Power Management Register 0x6B
- Configure User Control Register 0x6A to disable master I2C
- Configure Interrup Configuration Register 0x37 to bypass master I2C
- Setup magnetic sensor's Control Register 0x0A to take continuous measurement.
Arduino has the I2C library called Wire that does all of the heavy labor. To read the sensor you need to specify the address of the sensor and the register where data to be read. To write to the sensor you will need address of the sensor, the register to write to and the value. Here I write the two functions so that they can be used in the code.
byte read(int reg)
{
Wire.beginTransmission(0x68); // starting the transmission to sensor address 0x68
Wire.write(reg);
Wire.endTransmission(false);
Wire.requestFrom(0x68, 1, false); // requestone byte of data
byte val = Wire.read();
Wire.endTransmission(true);
return val;
}
void write(int reg, int data)
{
Wire.beginTransmission(0x68); // starting the transmission to sensor address 0x68
Wire.write(reg);
Wire.write(data);
Wire.endTransmission(true);
}
Since I use bypass mode, the Arduino will talk to the magnetic sensor directly. Thus I need the read and write for the magnetic sensor also. The magnetic sensor address is 0x0C (from the Product Specification).
byte readMag(int reg)
{
Wire.beginTransmission(0x0C);
Wire.write(reg);
Wire.endTransmission(false);
Wire.requestFrom(0x0C, 1, false); // requestone byte of data
byte val = Wire.read();
Wire.endTransmission(true);
return val;
}
void writeMag(int reg, int data)
{
Wire.beginTransmission(0x0C);
Wire.write(reg);
Wire.write(data);
Wire.endTransmission(true);
}
The main code:
#include <Wire.h>readMag(0x09); //This tells the Mag Module to take another measurement.
void setup()
{
Serial.begin(115200); // Setup serial output to 115.2k
Wire.begin(); // Initialize I2C communication
write(0x6B, 0); //Initialize Power Manager Register to 0
write(0x6A, 0); // Disable master I2C, enable value is 0x20, so disable it should be just bit 5 = 0, since I don't use other bits and they are all 0.
write(0x37, 0x02); // Enable bypass mode
writeMag(0x0A, 0x12); // Setup magnetic sensor to measure contiuously.
}
void loop()
{
int xh = readMag(0x04); // read x axis, high byte
int xl = readMag(0x03); // read x axis, lowbyte
int yh = readMag(0x06);
int yl = readMag(0x05);
int zh = readMag(0x08);
int zl = readMag(0x07);
// Combine the valuesGoodluck on your project!
int x = (xh << 8) | (xl & 0xff);
int y = (yh << 8) | (yl & 0xff);
int z = (zh << 8) | (zl & 0xff);
// Print out
Serial.print("X,Y,Z=");
Serial.print(x);
Serial.print(",");
Serial.print(y);
Serial.print(",");
Serial.println(z);
// delay(1000);
}
hi there
ReplyDeletethank you for tutorial
can you complete this code for acc and gyro ,please??
we are trying add this module to multiwii platform but there is no source code about acc and gyro for this module...
best regards
Sorry for the late response. I was so busy and forgot to go back to check for this. If you still has problem with the acc and gyro let me know.
DeleteHi,
ReplyDeletein setup function you write the code like this:
write(0x68, 0x6B, 0);
write(0x68, 0x6A, 0);
it must be like this, right??
write(0x6B, 0);
write(0x6A, 0);
Yes, I added another parameter later and I forgot to correct it. Basically 0x68 is the address of the module, which was hardcoded in the write() function.
DeleteThanks for pointing it out.
Hi. thanks for your writing, But i have one problem. When I followed your code and run it, the value of X, Y, Z showed the value and never changed when i moved the sensor. For example, When Serial shows like X,Y,Z=-96,-72,16 , It never changed and print the same value again and again when i moved the sensor. I saw some videos that when user move the megnetometer sensor, the X, Y, Z values changed. But I can't find the solution to get the proper answer. Would you answer it for me?
ReplyDeleteHi, Can you post your code here and your pin connectivity if you don't mind.
DeleteTry to add this to your X, Y and Z values:
if (val < 0)
return -(((float)(val*-1)) / 6.825);
else
return ((float)val) / 6.825;
Where val is the X, Y or Z. I remember I had this problem before but forgot what I did to solve it.
Thank you for answering. I solved it.
DeleteThis comment has been removed by the author.
Deletemy pin SDA=A4, SCL=A5 and vcc=3.33 gnd=gnd that my configuration pin
Deletewoosung kim can you show you program because i cant solve it , my problem same with you
ReplyDeleteIsmoyo,
ReplyDeleteAdd readMag(0x09); after reading the x,y,z.
Also add:
if (val < 0)
return -(((float)(val*-1)) / 6.825);
else
return ((float)val) / 6.825;
to the x,y,z value to convert to uT. val is the x, y, z.
sorry sir, where actually program if (val<0)...... added,in void setup or void loop ,because i add in readMag function its same
ReplyDeletesorry sir yhis my program
#include
byte read(int reg)
{
Wire.beginTransmission(0x68); // starting the transmission to sensor address 0x68
Wire.write(reg);
Wire.endTransmission(false);
Wire.requestFrom(0x68, 1, false); // requestone byte of data
byte val = Wire.read();
Wire.endTransmission(true);
return val;
}
void write(int reg, int data)
{
Wire.beginTransmission(0x68); // starting the transmission to sensor address 0x68
Wire.write(reg);
Wire.write(data);
Wire.endTransmission(true);
}
byte readMag(int reg)
{
Wire.beginTransmission(0x0C);
Wire.write(reg);
Wire.endTransmission(false);
Wire.requestFrom(0x0C, 1, false); // requestone byte of data
byte val = Wire.read();
Wire.endTransmission(true);
if (val < 0)
return -(((float)(val*-1)) / 6.825);
else
return ((float)val) / 6.825;
}
void writeMag(int reg, int data)
{
Wire.beginTransmission(0x0C);
Wire.write(reg);
Wire.write(data);
Wire.endTransmission(true);
}
void setup()
{
Serial.begin(115200); // Setup serial output to 115.2k
Wire.begin(); // Initialize I2C communication
write(0x6B, 0); //Initialize Power Manager Register to 0
write(0x6A, 0); // Disable master I2C, enable value is 0x20, so disable it should be just bit 5 = 0, since I don't use other bits and they are all 0.
write(0x37, 0x02); // Enable bypass mode
writeMag(0x0A, 0x12); // Setup magnetic sensor to measure contiuously.
}
void loop()
{
int xh = readMag(0x04); // read x axis, high byte
int xl = readMag(0x03); // read x axis, lowbyte
int yh = readMag(0x06);
int yl = readMag(0x05);
int zh = readMag(0x08);
int zl = readMag(0x07);
readMag(0x09); //This tells the Mag Module to take another measurement.
// Combine the values
int x = (xh << 8) | (xl & 0xff);
int y = (yh << 8) | (yl & 0xff);
int z = (zh << 8) | (zl & 0xff);
readMag(0x09); //This tells the Mag Module to take another measurement.
Serial.print("X,Y,Z=");
Serial.print(x);
Serial.print(",");
Serial.print(y);
Serial.print(",");
Serial.println(z);
// delay(1000);
}
Replace val with x, y or z
Deleteoh ok thx sir
ReplyDeleteHi Phuc Ly , this is really helpful. did you get a chance to try on Teensy3.6 because many are moving to teensy for smart applications. please let us know if you try mpu-9255 on teensy3.6. I am working on teensy and facing issues..
ReplyDeleteThanks,
Satya.
Hi Satya,
DeleteAt the moment I have no plan to use teensy. I will definitely try in the future to see what capability it has.
Thanks,
Phuc
Hello Phuc Ly,
ReplyDeleteThank you for post,it is very useful but I have a question for you,
are these X,Y,Z values in degrees or raw values.
This post really helped me! Thank you!
ReplyDeleteHei Phuc Ly!
ReplyDeleteI tried your code here but i only get heading from ca 200 to 350 degress. Can you please help me out?
#include
void setup()
{
Serial.begin(9600); // Setup serial output to 115.2k
Wire.begin(); // Initialize I2C communication
write(0x6B, 0); //Initialize Power Manager Register to 0
write(0x6A, 0); // Disable master I2C, enable value is 0x20, so disable it should be just bit 5 = 0, since I don't use other bits and they are all 0.
write(0x37, 0x02); // Enable bypass mode
writeMag(0x0A, 0x12); // Setup magnetic sensor to measure contiuously.
}
void loop()
{
int xh = readMag(0x04); // read x axis, high byte
int xl = readMag(0x03); // read x axis, lowbyte
int yh = readMag(0x06);
int yl = readMag(0x05);
int zh = readMag(0x08);
int zl = readMag(0x07);
readMag(0x09); //This tells the Mag Module to take another measurement.
// Combine the values
int x = (xh << 8) | (xl & 0xff);
int y = (yh << 8) | (yl & 0xff);
int z = (zh << 8) | (zl & 0xff);
// Print out
Serial.print("X,Y,Z=");
Serial.print(x);
Serial.print(",");
Serial.print(y);
Serial.print(",");
Serial.print(z);
// gjore om til grader:
float grader=atan2(y,x);
if(grader<0)
{
grader+=2*PI;
Serial.print(" Grader: ");
Serial.println(grader*180/PI);
//delay(1000);
}
}
byte read(int reg)
{
Wire.beginTransmission(0x68); // starting the transmission to sensor address 0x68
Wire.write(reg);
Wire.endTransmission(false);
Wire.requestFrom(0x68, 1, false); // requestone byte of data
byte val = Wire.read();
Wire.endTransmission(true);
return val;
}
void write(int reg, int data)
{
Wire.beginTransmission(0x68); // starting the transmission to sensor address 0x68
Wire.write(reg);
Wire.write(data);
Wire.endTransmission(true);
}
byte readMag(int reg)
{
Wire.beginTransmission(0x0C);
Wire.write(reg);
Wire.endTransmission(false);
Wire.requestFrom(0x0C, 1, false); // requestone byte of data
byte val = Wire.read();
Wire.endTransmission(true);
return val;
}
void writeMag(int reg, int data)
{
Wire.beginTransmission(0x0C);
Wire.write(reg);
Wire.write(data);
Wire.endTransmission(true);
}
Thank you, thank you very much! Thanks to your logic to read the magnetic value, I finally can write a MATLAB code with i2cdev to read and process the raw data. I cannot thank you enough ^^
ReplyDeleteAnd it seems like you're a Vietnamese too :D
Hi,
ReplyDeleteCan you tell me where mpu-9255 FSYNC is connected on Arduino? You wrote that it is used but I could not find out where it is connected.
Thanks,
Zoltan