Shake, Rattle & Roll: The MMA8453Q & Arduino
So we finally finished putting the polish on our latest Arduino library designed for use with the MMA8453Q Accelerometer and its siblings the MMA8451 and MMA8452. This library gets you going with the basics on this accelerometer and it also allows you to dig in a little deeper in to some of the advanced features, like motion detection and shake detection without much effort. This little QFN chip is not only cheap but its packed with 3 Axis’ of flavorful features. It’s on board 10 bit ADC coupled to the I2C interface means fast and accurate 3 axis measurements as well as built in free fall, pulse and jolt detection on programmable interrupt pins. As illustrated below, it’s a 3.3 volt part requiring additional level shifting to interface a 5 volt Arduino, this can be accomplished with a logic level N channel FET and a schottky diode:
So lets first get the library setup. Go ahead and download n0m1-MMA8453 it. The next thing you will need to do is download the wonderful and necessary i2c master library which our library depends on. This library is not only faster then the regular Arduino Wire library, it also follows the proper I2C specifications and allows for the sending of a repeated start bit which is required by the MMA845x family. So after you got both those libraries downloaded place them in your Arduino Libraries folder, and we are ready to get started.
When you fire up your Arduino app you will notice a new set of 4 examples in your examples menu. The first example we will take a look at is the ultra simple DataMode example. When you up up this sketch you will see right away just how simple it is, lets break it down anyway though, just in case.
At the top you will see the include of the library and its dependency library, the i2C lib, and the instantiation of the accel object.
#include#include MMA8453_n0m1 accel;
In the setup function, you call the function dataMode to set the accelerometer into raw data output mode. This function has 2 parameters. A boolean, which is true for high resolution mode (10bit), and false for low resolution mode (8bit). The next parameter is to set the range of gravitational force the accelerometer will be sensitive to. These values, are +/-2g(waving your project around in your hand), +/-4g(your drag racing project), or +/-8g(your atmosphere re-entry vehicle project).
accel.dataMode(true, 2);
After that there is almost nothing left to do. Just call the update function at the top of your loop, which retrieves the latest values from the accelerometer, then use those values however you feel.
accel.update(); Serial.println(accel.x()); Serial.println(accel.y()); Serial.println(accel.z());
Well that’s it! Expecting some fancy complex gravitational voodoo, matrix math or pointer arithmetic? Sorry to disappoint. I’ll try to step it up a little in the next example then…however there’s a good chance it will be almost as simple.
Some tips if you are using the breakout board from http://www.sparkfun.com/products/10955 .
Hook up the SDA and SCL line to Analog input pins 4 and 5 respectfully, and the interrupt pins (I1 and I2) to pins 2 and 3.
If your script is failing at the line
accel.dataMode(true, 2);
add the lineI2c.begin();
somewhere before that.The other problem that I encountered is when using the breakout board is that the SA0 pin of the accelerometer is connected to VCC instead of ground which changes the I2c address. So find the line in MMA8453_n0m1.h that reads
const byte I2C_ADDR = 0x1C;
and change 0x1C to 0x1D.Other than those to caveats the library works wonderfully and I would like to thank NoMi for saving me a bunch of time.
I hope someone finds this useful.
Hi Kael,
Thanks for the feedback on the library! I updated the library to fix the
I2c.begin();
problem you mentioned. Strangely it works for me with or without theI2c.begin()
so there must be a hardware setup difference between our boards. Good catch though, it should probably be there anyway.Noah
Thx for your sharing. what i got is an MMA7455 accelerometer. I noticed your library aimed at MMA8453Q . Are these two accelerometers basically the same? So can i use your library working for my own acclerometer? Thanks a lot
The MMA7455 is not directly compatible but its seems fairly similar. I would say give it a run, you will probably need to change some register values in the .h file to match, and some of the data results might be different, but the library would certainly get you started. You might have more trouble getting the motionMode and ShakeMode working but the basic dataMode shouldn’t give you too many issues if you get the registers right.
Thank you very much!!!
I will have a try. If i manged it, i would like to share.
Sounds great, good luck and don’t be afraid to ask more questions if you run into trouble!
Are you going to release version for MMA8451 or should modify you library myself?
BTW.: great work
The MMA8451 and MMA8453Q have almost identical i2c command interfaces. So there is a very good chance that the library will work for the MMA8451 without any changes. However we have never tested it, let us know how it goes!
It needs some modification. I will try and update you with results.
Another issue:
Are you sure that low_res reading procedure is OK. In source I’ve found:
—
void MMA8451_n0m1::xyz(int& x, int& y, int& z)
{
if (highRes_)
{
…
else
{
I2c.read(I2CAddr, REG_OUT_X_MSB, 3, buf);
x = buf[0] << 2;
y = buf[1] << 2;
z = buf[2] << 2;
}
—
I thing it should be like:
—
x = buf[0];
y = buf[2];
z = buf[4];
—
???
OK, I’ve found F_Read meaning. Your code is correct. Sorry to bother you.
Hi again,
I’ve made a beta version of MMA8451. It needs a lot of polishing but it’c working. There is a lot of changes e.g. I’ve added interrupt driven data motion mode.
Question:
I thing that there is an error in your clearInterrupt() function. Am I right that these code:
I2c.read(I2CAddr,REG_TRANSIENT_SRC ,byte(1),&srcTrans);
if(srcTrans&0x02 == 0x02)
{
shakeAxisX_ = true;
}
if(srcTrans&0x08 == 0x08)
{
shakeAxisY_ = true;
}
if(srcTrans&0x20 == 0x20)
{
shakeAxisZ_ = true;
}
should be like this:
if((srcTrans&0x02) == 0x02)
{
shakeAxisX_ = true;
}
if((srcTrans&0x08) == 0x08)
{
shakeAxisY_ = true;
}
if((srcTrans&0x20) == 0x20)
{
shakeAxisZ_ = true;
}
?
BTW.: I’ve some provblems with converting “standard DS1307RTC” library to use i2c master library. Does someone have working example code using DS1307 and I2C.h?
Hi,
Great to hear you got the MMA8451 working! If you can send me your code I can merge your changes into the library and give you some credit. As for the coding error, I am not entirely sure. As far as I can remember this code worked fine before, however your code does look more correct. I will take a closer look at it. Have you verified that it makes a difference on the MMA8451?
Sorry never worked with the DS1307RTC library. If its using wire then usually its not TOO hard to convert to i2c.h. If you send me some specific problems maybe I can help you out.
Hey,
Thanks for this. This was a great help (along with the I2C library). I had one question regarding the units in which this will return the data. For example, I am using a MMA8452Q accelerometer breakout from sparkfun. I implemented the code and am getting values ranging from 0 to 255, in the stationary state.
It would be great if you could tell me how to convert this data in terms of g.
Thanks
Hi,
Glad you found the library useful. In order to convert to g, you would first need to see how high your gforce range was set. So with a 2g range, 255 should be equal to 2g. Also don’t forget. “A sensor stationary on a horizontal surface will measure 0g in X-axis and 0g in Y-axis whereas the Z-axis will measure 1g”. You will only get 0g on the Z-axis if the sensor is falling, or your in space. 😉 I hope that answers your question!
Thanks, helped a lot. By the way, is the relation between g and 255 a linear one?
Hello,
This is cool! I’m glad to found this site. I was worried how to start our project regarding Arduino MIni v328 and MMA8451 breakout board. Thank you very much for sharing the informations (^^)
Just curious, do you think it’s possible to connect 3 or more MMA8451 breakout board on Arduino MIni v328?
Thanks,
While riding the i2c bus, the MMA8451 only has a choice of two seats (0x1D, 0x1C) defined by the state of Pin SA0.
To get a third seat would require some back-of-the-bus trickery, either implement another i2c bus in software (bit bang) or use some switching…
Michael
Yes it is linear.
thank you krazatchu, i’ll start working on it.
btw, I tried uploading the example datamode code but it said :
avrdude: stk500_getsync(): not in sync: resp=0xf8
what does it mean? sorry to bother. I’m a total newbie and totally need to understand all of it or we’re doomed.
this occured when i tried to complie the MMA8453_n0m1_dataMode :
E:[D] Program FilesProgram Installerarduino-1.0-windowsarduino-1.0hardwaretoolsavrbinavr-ar: WInterrupts.c.o: No such file or directory
Hi,
I am using the above code for MMA8452Q and i am getting the constant o/p as 13. Can u please tell me why is it coming so and what should i do know.
What hardware are you using?
I am using arduino board now it is showing the correct values but getting stuck after 4 to 5 readings and showing the same value even if i move the accelerometer.
*MMA8452Q:Xtrinsic 3-Axis, 12-bit
*MMA8453Q:Xtrinsic 3-Axis, 10-bit Digital accelorometer.So what parameters do i need to vary in the MMA8453Q code to reflect the difference.
Thank u very much
Hi, I have my Arduino Uno hooked up in this fashion (SDA> A4, SCL> A5, I2 >D3, A1, D2). and when I run the program nothing happens on my serial monitor. However, when I pulled the SCL wire out the program ran and a stream of 12s showed up. Do you know why this is?
No idea…
*MMA8452Q:Xtrinsic 3-Axis, 12-bit
*MMA8453Q:Xtrinsic 3-Axis, 10-bit Digital accelorometer.So what parameters do i need to vary in the MMA8453Q code to reflect the difference.
Thank u very much
Gah! you’ve saved me. This I got the mma8452q running without problems.
I’ve been trying to figure out how to setup the high res for the 52. It should be 12 bit, but I’m only getting 8-bit, no matter how I change the datamode part.
Any tips?
Thanks!
I see! I’m sorry to make a new comment, but I think I understand what’s happening right now. I’m going to try and see if I can change the line in the library, but I’ve never done anything like that (noob here.)
But I noticed under 2G and static gravity I only ever max out at 255, i.e, 8 bit. But it must be truncated somehow, because in static gravity I should never have more than 1G (at least on earth!)
i hope I do not cause a spam concern now, but I have concluded I cannot figure out how to get 12-bit when running the 52Q. It seems that whatever communication to request high-res is not working, and it defaults on 8-bit. Or, I don’t know what’s happening.
:(.
I am using MMA8451 breakout board from dx.com (sku 140172). Board has 8 pins: VCC_IN, 3.3V, GND, SCL, SDA, SAO, INT2 and INT1. I have connected this board to my arduino Uno R3 board as follows: 3.3V to 3.3V, GND to GND, SCL to SCL, SDA to SDA. SCL and SDA have pull up resistors to 3.3V. I uploaded the xyz example (with default 0x1C address) and tested. X value changes when tilting the accelerometer forward/backward (top view), y value changes when tilting left/right, but z value does not change when rotating clockwise/ccw. Z value changes by tilting left/right/forward/backward. Is this problem with my accelerometer, or do I need to change the code? This is a big problem for me because in need to measure rotating cw/ccw for my 2WD robot platform.
Thanks for advice,
Den
I’m looking to create a project with multiple MMA8452 accelerometers connected to an Arduino. I’m trying to figure out where in these i2c libraries I can change the SDA and SCL pins. The libraries I’ve found don’t seem to be able to handle multiple accelerometers. Well that or the more likely scenario where I just don’t understand what’s going on lol. Any help would be much appreciated. Thanks.
Hi Ryan,
Most i2c implementations rely on the i2c hardware which connects to specific pins.
On the Arduino UNO and others, these are pins A4 & A5 (SDA & SCL).
For multiple accelerometers, you can often set a pin (on the accelerometer) that will change the address but the choice is limited to 2 or 3.
Alternatively, you can use a software i2c library to add more i2c buses…
Michael
Okay I think I understand the i2c interface a little better now. Would it be as simple as just making sure only one accelerometer is powered at a time? So if the interrupt goes high, shut off power to other accelerometers and put VDDIO high to gather accelerometer data.
On the other hand if I’m looking to just recognize when motion takes place in any of the accelerometers, is it as simple as just connecting all accelerometers to those pins suggested above for SDA and SCL. So they’d kind of be in parallel then. Appreciate the previous point, was very helpful.
Hi Ryan,
Selective powering may work, it depends on what happens to the accelerometer bus pins when the chip is switched off…
There might be information in the datasheet regarding this, else the manufacturer would know.
If they are all in parallel with the same address there would be no way to configure them, talking to one would result in a bus traffic collision.
Michael
How do you connect the jumper to the SA0. Looks like it’s the two parallel bars on the bottom of the chip, but not sure how to solder it together.
I am trying to use this code with the Arduino Leonardo (not sure if that’s relevant or not) and I am getting a constant reading of 17 for all three axis of measurement.
Any ideas what my issue could be? I have triple checked the connections, switched “0x1C” with “0x1D” and have had no luck.
Could you explain a little more in detail about the level shifting using the NFET and Schottky Diode? I’m not quite sure how this is suppose to work. Thanks in advance.
Hey, I plugged in my Arduino but all that shows up in the Serial Monitor is x:13 y:13 z:13, even when I move it… I am using 10k resistors in the SDA and SCL. Do you guys have any Idea why?
The Z value will not change when you are rotating it clockwise/ccw as the force in the Z direction does not change with rotation. If you want a sensor that can detect rotation about the vertical axis you need a magnetometer.
Or a gyroscope…
Try 2 things:
1. Check your wiring. (It sounds like you are shorting something out)
2. Just connect 3.3V, GND and SDA/SCL (This is the minimum). I ground my SAO pin too, but can get it to work if it floats.
3. Change accel.setI2CAddr(0x1C) to Change accel.setI2CAddr(0x1D)
I get a string of 13s if I disconnect the sensor completely or have the wrong adress. If I fiddle with the wires while it is running it freezes.
Is your SAO pin floating? It should be connected to 3.3V or ground. (3.3V and ground change the sensor’s addresses.)
Did you shake your sensor and check the data stream? If you just tilt your sensor you should not get more than 255, but it is not maxing out.
The pulses will be very quick, so you will need to record the data and plot it later.
Thanks for your info, was very helpfull!
Thanks n0m1, very good library!
Thanks for sharing the library. It definitely is faster!
Does it run I2C at 100Khz or 400Khz? If 100, what has to be done to change it to 400Khz? What do you think the performance change would be?
Hi
I’ve eventually got the I-1 output working with interrupting an Arduino on motion detect (I’m not a software guy!) and that now goes Hi to Lo but I can’t figure out how to reset the device to Hi again after I’ve actioned the interrupt…
I would guess I have to send it a byte or several but the datasheet has me very confused…
Thanks
Hi guys,
SA0 pin on my chip is floating (left unconnected) how would that be read? I’m guessing it’s read as one but would like to be sure.
Thanks
-Francisco