Arduino Accelerometer Success On Second Try: Mozzi + MMA7660

When we left off earlier, Emily and I determined that getting her MMA7660 I2C accelerometer breakout board to work with Mozzi on an Arduino will require more work than it looked at first glance, and probably not worth the trouble. Emily has since moved on to a different accelerometer module, one which communicates via analog voltage values. But I had a harder time letting go. Some helpful comments on Twitter plus Randy Glenn’s comment on the previous blog post motivated me to take another run with different objectives.

The first change was a reduction in problem scope: I originally thought I’d update the MMA7660 library using fragments from Mozzi’s non-blocking I2C example. This time I’m going the other way: I’m modifying Mozzi’s non-blocking I2C example by pulling fragments from the MMA7660 library. This is a tiny subset of capability and coding. Notably absent are any sort of error-handling… not even that wacky use of goto that make seasoned programmer eyes twitch.

The second change was a change in attitude: I see a lot of violations of good coding conventions, and I wanted to fix them all. Especially problems horrible for code robustness such as poor error-handling. But talking with others who have played with Arduino longer than I have, I learned code quality has not exactly been a barrier for people putting Arduino code online. As I’m starting with a piece of Mozzi example code, all I had to do is make sure I don’t make that code worse, and I should be good to go.

Easing those two constraints (a.k.a. lowering expectations) made for a much easier task, one which was ultimately successful! The Mozzi example chirped at one of three different pitches depending on if the ADXL345 reported X, Y, Z value over half of its range. (And stays silent if none of them were.) Now it chirps in response to MMA7660 data instead. Here’s the short demonstration video I tweeted. (Be sure to turn on sound.)

There was one technical challenge in capturing that video clip: I didn’t have an audio amplifier on hand, so the tiny speaker was powered directly by the Arduino Nano and thus extremely quiet. To capture the chirps, I plugged in a wired earbud headphone with mic to my cell phone for filming. Its microphone module was placed next to the quietly chirping speaker and visible in the picture/video. I prefer not to have such items in the field of view, but it’s what I had to do.

It turns out the MMA7660 is not appropriate for what Emily had in mind anyway. This module was designed for detecting portrait/landscape orientation and had very poor resolution: 5 bits, or values from zero to 63 to cover a range +/- 1.5G. Moving through an 180 degree arc under normal gravity, we see about 40 out of those 64 values. This translates to one tick every ~4.5 degrees. A gently swinging pendulum like what Emily had in mind would only ever see four or five different values through its entire range of motion and not nearly enough to make interesting sounds.

But that’s OK, I’m sure it’ll be useful for something else in the future. I’ve made my modified Mozzi example available on Github in case Emily or I or anyone else decide to put the MMA7660 accelerometer in a Mozzi sketch. And if someone is less interested in that specific module but more curious about how to adapt from one I2C peripheral to another, they can look at this commit to see every line I changed.

Aborted Attempt At Arduino Accelerometer: Mozzi + MMA7660

Every tool has its use, and for quick prototype of electronic ideas, it’s hard to beat an Arduino. A huge community of users has generated an equally huge selection of libraries to get any hardware up and running quickly. The downside is that there’s no way to ensure they all work together. Playing with a single library is easy, but getting more than one to play nicely together is a hit-or-miss affair. Today’s story is a miss.

Mozzi is an Arduino library for sound synthesis. It allows Arduino creations to audibly react to external input, and is the brains behind the Rackety Raccoon project. Its inputs were potentiometers connected to an Arduino’s analog pins. To follow up that project, Rackety Raccoon creator Emily wanted to use an accelerometer chip as input.

The device Emily had on hand was a small breakout board for the MMA7660FC. It communicates via I2C and there’s an Arduino library available. But when it was added into a Mozzi sketch, verification fails with the following error:

libraries/Wire/utility/twi.c.o (symbol from plugin): In function `twi_init':
(.text+0x0): multiple definition of `__vector_24'
libraries/Mozzi/twi_nonblock.cpp.o (symbol from plugin):(.text+0x0): first defined here
collect2: error: ld returned 1 exit status
exit status 1

This error message is spectacularly unhelpful even though it is technically correct on all counts. There is indeed a collision in defining interrupt vector table entries, but Arduino’s target user demographic would have no idea what that means. At a higher level, the problem is that we have two chunks of code both trying to perform I2C communication. MMA7660 sample code uses the standard Arduino Wire library, Mozzi has its own I2C communication library. They both use the same hardware resources and hence the collision. Only one of them may exist in an Arduino sketch.

Why would Mozzi have its own I2C library? The hint comes from the name: “twi_nonblock“. Mozzi is an audio library and it is critically important for Mozzi to run nonstop. Any interruptions would become audible glitches! This is a problem for receiving I2C data using the Wire library because it would wait (“block”) for the I2C peripheral (accelerometer in this case) to respond.

Mozzi can’t wait, hence the twi_nonblock I2C communication library as a replacement for Arduino’s standard Wire library. In order to use MMA7660 with Mozzi on an Arduino, the portions dependent on Wire library must be replaced with counterparts in Mozzi’s twi_nonblock. Mozzi includes sample code to communicate with another I2C accelerometer, the ADXL345.

Examining the sample, we see it is a straightforward line-by-line replacement when sending I2C data. The sample function acc_writeTo() includes comments explaining the Wire equivalent for each line.

// Writes val to address register on device
void acc_writeTo(byte address, byte val) {
  // Wire.beginTransmission(ADXL345_DEVICE); // start transmission to device
  twowire_beginTransmission(ADXL345_DEVICE); // start transmission to device
  // Wire.send(address); // send register address
  twowire_send( address );
  // Wire.send(val); // send value to write
  twowire_send( val );
  // Wire.endTransmission(); // end transmission
  twowire_endTransmission();
}

Which would serve as an excellent guide to rewrite MMA7660::write() from its current Wire format.

void MMA7660::write(uint8_t _register, uint8_t _data) {
  Wire.begin();
  Wire.beginTransmission(MMA7660_ADDR);
  Wire.write(_register);
  Wire.write(_data);
  Wire.endTransmission();
}

In contrast, receiving I2C data would not be a trivial line-by-line replacement. The nature of twi_nonblock meant we have to change a lot more code in order to convert it from a simple synchronous blocking procedure to an asynchronous non-blocking process. If the MMA7660 module and associated library were well-executed, it would not be technically challenging, just time-consuming. And it might be something good we can do to contribute back to the Arduino community.

MMA7660 demo code says it is bad and uses goto

Sadly it was not a shining example of excellence. A comment saying “it is bad” raised warning flags about weird behavior from the chip. Then a few lines later, we see a goto statement as an ugly hack around the chip’s behavior. This is when we decided to “Nope!” out of there and abort this particular investigation.

UPDATE: A week later I took another look, and the second try was successful.