How do people deal with different Arduino-like machines for i2c/spi/etc.?

I have several machines that use the Arduino IDE that I want to share common code that I develop among the machines. The machines I currently have (or have on order) are:

  • Arduino Uno R3
  • Teensy 3.0
  • Digispark (ATtiny85 chip)
  • 5v Trinket (ATtiny85 chip)
  • Gemma (ATtiny85 chip)
  • DigiX (on order, superset of the Due)

These machines work great if I limit myself to digitalWrite, analogWrite, etc. However, if I want to add i2c devices, it all comes apart, since there are different implementations of i2c. The Uno uses the Wire library.

The Teensy provides the Wire library, but there is also a faster version (i2c_t3) that I would like to use instead of the standard Wire library.

The Digispark includes the TinyWireM library instead. The Trinket/Gemma don’t provide a distribution, but I can easily add the TinyWireM library.

Outside of the IDE, it is fairly simple. You use conditional compilation to pull in the right library:

#if defined (__AVR_ATtiny85__)
// Digispark, Trinket, Gemma
#include <TinyWireM.h>
// various other macros to make things look compatible

#elif defined (__MK20DX128__)
// Teensy 3.0
#include <i2c_t3.h>
// various glue

// Everybody else
#include <Wire.h>

However, that doesn’t work with the IDE. The IDE is trying to be helpful, and it sees references to i2c_t3.h, TinyWireM.h and includes these in the build, but these headers don’t exist in the standard Uno release, and in the ATtiny85 chips, it causes compilation errors.

I see similar things with Serial, where the ATtiny85 chips don’t have a real serial driver, and if you wanted to use it, you would need to use SoftwareSerial.h, or if it is just debug information, not generate it in the first place.

I haven’t yet used SPI, but I believe that has the same problems.

Now, one option is to ditch the IDE all together, and just use raw Makefiles, and use Gnu emacs make mode to build things, and it is tempting, since I only use the IDE to run the compilers, download, and use the serial monitor for the chips that have it. But, I do enough of that in my day job. I would prefer not to have to dig in enough to replicate the build procedure that the IDE uses.

Another option is to combine all three Wire implementations into my own single .cpp/.h files, and just pretend the standard Wire.h, etc. don’t exist. While it is doable, I’m not terribly enthused about having my own variant of these standard functions, and I would have to keep track and import new versions from time to time.

I could just keep separate libraries of my functions, with a Wire version, a TinyWireM.h version, etc. and change things in parallel. Bleh.

Are there other options that I can use?