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.