Author Topic: Wire.h vs. TinyWireM.h with the Arduino IDE  (Read 11205 times)

MichaelMeissner

  • Full Member
  • ***
  • Posts: 166
Wire.h vs. TinyWireM.h with the Arduino IDE
« on: October 10, 2013, 07:27:44 am »
I tend to be a diletant when it comes to microprocessors.  At the moment, I have an Uno R3, Teensy 3.0, Digispark, Gemma, 5v Trinket, and I am waiting for the DigiX.  I primarily use the Teensy, but I've been wanting to use the ATtiny85 processors for doing simple things like running the two Neopixel rings on my steampunk goggles.


At the moment, I am starting to add I2C devices.  On the Uno/Teensy I use Wire.h to talk to the i2c devices.  On the Digispark, you use TinyWireM.h.  However, I want to have sketches and libraries that can run on both the Uno/Teensy/DigiX as well as the ATtiny85 devices.  I can use #ifdef's to determine which pins to use, but the IDE is trying to be 'too' helpful, and it includes Wire.h even though I have it #ifdef'ed out.  Is there some way of having a Wire.h in the tiny directory that is a subset of the normal Wire.h, so I don't have to use #ifdef to select the right header.  Or can we convince the Arduino guys to fix their %#!$ IDE to allow #ifdef's with different headers.

For example, my main code is:

Code: [Select]

// Like blink, but turn on multiple lights, via I2c using a MCP23017 i2c chip with 16 digital input/outputs
//
// Pins: Left Right
// ===== ==== =====
// Pin 1: Port 8  (GPB0) Port 0 (GPA0)
// Pin 2: Port 9  (GPB1) Port 1 (GPA1)
// Pin 3: Port 10 (GPB2) Port 2 (GPA2)
// Pin 4: Port 11 (GPB3) Port 3 (GPA3)
// Pin 5: Port 12 (GPB4) Port 4 (GPA4)
// Pin 6: Port 13 (GPB5) Port 5 (GPA5)
// Pin 7: Port 14 (GPB6) Port 6 (GPA6)
// Pin 8: Port 15 (GPB7) Port 7 (GPA7)
// Pin 9: Power (2.7-5.5V) Interupt A
// Pin 10: Ground Interupt B
// Pin 11: Not connected Reset
// Pin 12: SCL (A5, blue) Adress 2
// Pin 13: SDA (A4, green) Address 1
// Pin 14: Not connected Address 0
//
// Reset (pin 11 left) must be wired to power.
// Default address begins at 0x20


#include <stddef.h>
#if defined(__AVR_ATtiny85__)
#include <TinyWireM.h>
#else
#include <Wire.h>
#endif


#include "Adafruit_MCP23017.h"

Adafruit_MCP23017 mcp;

const int i2c_addr = 0; // i2c address select bits of the MCP23008 i2c device
const int ms = 2000; // 2 seconds
const bool trace = true; // whether to trace to the serial port
const bool knight = true; // whether to do lights 'knight rider' style
const size_t first_led = 8; // first led to turn on
const size_t mirror_led = 0; // possibly mirror to second set of LEDs
const size_t n_leds = 8; // number of leds to write to
const unsigned int mask = (1U << n_leds) - 1; // mask of available leds
unsigned int state = 0; // cycle between 0 .. mask to turn on leds
bool kn_up = true; // whether knight rider is cycling up or down

// initialize the digital pins as outputs.
void setup() {               
  size_t i;

  mcp.begin (i2c_addr & 0xf); // pass in address bits for mcp23008

  for (i = 0; i < n_leds; i++)
    {
      mcp.pinMode (first_led + i, OUTPUT);
      if (mirror_led > 0)
mcp.pinMode (mirror_led + i, OUTPUT);
    }

  if (knight)
    state = 1;

#if !defined(__AVR_ATtiny85__)
  if (trace)
    {
      Serial.begin (9600);
      Serial.print ("Start, number of leds=");
      Serial.print (n_leds);
      Serial.print (", mask");
      Serial.print (mask);
      Serial.print (", First led=");
      Serial.print (first_led);
      if (mirror_led > 0)
{
  Serial.print (", Mirror led=");
  Serial.print (mirror_led);
}

      Serial.println ("");
      Serial.flush ();
    }
#endif
}


// the loop routine runs over and over again forever:
void loop() {
#if !defined(__AVR_ATtiny85__)
  const char *sep = "";
#endif
  size_t i;

  if (!knight || n_leds < 3)
    {
      // do lights as a counter
      state = (state + 1) & mask;
    }
  else
    {
      // do lights 'knight rider' style where they cycle up and then down
      if (kn_up)
{
  state <<= 1;
  if (state == (1U << n_leds))
    {
      state >>= 1;
      kn_up = false;
    }
}
      else
{
  state >>= 1;
  if (state == 0)
    {
      state = 2;
      kn_up = true;
    }
}
    }

  for (i = 0; i < n_leds; i++)
    {
      int on_off = ((state & (1U << i)) != 0) ? HIGH : LOW;


#if !defined(__AVR_ATtiny85__)
      if (trace)
{
  Serial.print (sep);
  Serial.print ("led");
  Serial.print (first_led + i);
  Serial.print ("=");
  Serial.print (on_off);
  sep = ", ";
}
#endif


      mcp.digitalWrite (first_led + i, on_off);
      if (mirror_led > 0)
mcp.digitalWrite (mirror_led + i, on_off);
    }

#if !defined(__AVR_ATtiny85__)
  if (trace)
    Serial.println ("");
#endif

  delay (ms);
}

And I've modified the Adafruit MCP23017 library as follows:

Code: [Select]
/***************************************************
  This is a library for the MCP23017 i2c port expander

  These displays use I2C to communicate, 2 pins are required to 
  interface
  Adafruit invests time and resources providing this open source code,
  please support Adafruit and open-source hardware by purchasing
  products from Adafruit!

  Written by Limor Fried/Ladyada for Adafruit Industries. 
  BSD license, all text above must be included in any redistribution
 ****************************************************/

#if defined(__AVR_ATtiny85__)
#include <TinyWireM.h>
#else
#include <Wire.h>
#endif
#include <avr/pgmspace.h>
#include "Adafruit_MCP23017.h"

//#if defined(__AVR__) || defined(__MK20DX128__) || defined(__AVR_ATtiny85__) // meissner, teensy/digispark/gemma/trinket mod
 #define WIRE Wire
//#else // Arduino Due
// #define WIRE Wire1
//#endif


#if ARDUINO >= 100
 #include "Arduino.h"
#else
 #include "WProgram.h"
#endif

// minihelper
static inline void wiresend(uint8_t x) {
#if ARDUINO >= 100
  WIRE.write((uint8_t)x);
#else
  WIRE.send(x);
#endif
}

static inline uint8_t wirerecv(void) {
#if ARDUINO >= 100
  return WIRE.read();
#else
  return WIRE.receive();
#endif
}

////////////////////////////////////////////////////////////////////////////////

void Adafruit_MCP23017::begin(uint8_t addr) {
  if (addr > 7) {
    addr = 7;
  }
  i2caddr = addr;

  WIRE.begin();

  // set defaults!
  WIRE.beginTransmission(MCP23017_ADDRESS | i2caddr);
  wiresend(MCP23017_IODIRA);
  wiresend(0xFF);  // all inputs on port A
  WIRE.endTransmission();

  WIRE.beginTransmission(MCP23017_ADDRESS | i2caddr);
  wiresend(MCP23017_IODIRB);
  wiresend(0xFF);  // all inputs on port B
  WIRE.endTransmission();
}

void Adafruit_MCP23017::begin(void) {
  begin(0);
}

void Adafruit_MCP23017::pinMode(uint8_t p, uint8_t d) {
  uint8_t iodir;
  uint8_t iodiraddr;

  // only 16 bits!
  if (p > 15)
    return;

  if (p < 8)
    iodiraddr = MCP23017_IODIRA;
  else {
    iodiraddr = MCP23017_IODIRB;
    p -= 8;
  }

  // read the current IODIR
  WIRE.beginTransmission(MCP23017_ADDRESS | i2caddr);
  wiresend(iodiraddr);
  WIRE.endTransmission();
 
  WIRE.requestFrom(MCP23017_ADDRESS | i2caddr, 1);
  iodir = wirerecv();

  // set the pin and direction
  if (d == INPUT) {
    iodir |= 1 << p;
  } else {
    iodir &= ~(1 << p);
  }

  // write the new IODIR
  WIRE.beginTransmission(MCP23017_ADDRESS | i2caddr);
  wiresend(iodiraddr);
  wiresend(iodir);
  WIRE.endTransmission();
}

uint16_t Adafruit_MCP23017::readGPIOAB() {
  uint16_t ba = 0;
  uint8_t a;

  // read the current GPIO output latches
  WIRE.beginTransmission(MCP23017_ADDRESS | i2caddr);
  wiresend(MCP23017_GPIOA);
  WIRE.endTransmission();
 
  WIRE.requestFrom(MCP23017_ADDRESS | i2caddr, 2);
  a = wirerecv();
  ba = wirerecv();
  ba <<= 8;
  ba |= a;

  return ba;
}

void Adafruit_MCP23017::writeGPIOAB(uint16_t ba) {
  WIRE.beginTransmission(MCP23017_ADDRESS | i2caddr);
  wiresend(MCP23017_GPIOA);
  wiresend(ba & 0xFF);
  wiresend(ba >> 8);
  WIRE.endTransmission();
}

void Adafruit_MCP23017::digitalWrite(uint8_t p, uint8_t d) {
  uint8_t gpio;
  uint8_t gpioaddr, olataddr;

  // only 16 bits!
  if (p > 15)
    return;

  if (p < 8) {
    olataddr = MCP23017_OLATA;
    gpioaddr = MCP23017_GPIOA;
  } else {
    olataddr = MCP23017_OLATB;
    gpioaddr = MCP23017_GPIOB;
    p -= 8;
  }

  // read the current GPIO output latches
  WIRE.beginTransmission(MCP23017_ADDRESS | i2caddr);
  wiresend(olataddr);
  WIRE.endTransmission();
 
  WIRE.requestFrom(MCP23017_ADDRESS | i2caddr, 1);
   gpio = wirerecv();

  // set the pin and direction
  if (d == HIGH) {
    gpio |= 1 << p;
  } else {
    gpio &= ~(1 << p);
  }

  // write the new GPIO
  WIRE.beginTransmission(MCP23017_ADDRESS | i2caddr);
  wiresend(gpioaddr);
  wiresend(gpio);
  WIRE.endTransmission();
}

void Adafruit_MCP23017::pullUp(uint8_t p, uint8_t d) {
  uint8_t gppu;
  uint8_t gppuaddr;

  // only 16 bits!
  if (p > 15)
    return;

  if (p < 8)
    gppuaddr = MCP23017_GPPUA;
  else {
    gppuaddr = MCP23017_GPPUB;
    p -= 8;
  }

  // read the current pullup resistor set
  WIRE.beginTransmission(MCP23017_ADDRESS | i2caddr);
  wiresend(gppuaddr);
  WIRE.endTransmission();
 
  WIRE.requestFrom(MCP23017_ADDRESS | i2caddr, 1);
  gppu = wirerecv();

  // set the pin and direction
  if (d == HIGH) {
    gppu |= 1 << p;
  } else {
    gppu &= ~(1 << p);
  }

  // write the new GPIO
  WIRE.beginTransmission(MCP23017_ADDRESS | i2caddr);
  wiresend(gppuaddr);
  wiresend(gppu);
  WIRE.endTransmission();
}

uint8_t Adafruit_MCP23017::digitalRead(uint8_t p) {
  uint8_t gpioaddr;

  // only 16 bits!
  if (p > 15)
    return 0;

  if (p < 8)
    gpioaddr = MCP23017_GPIOA;
  else {
    gpioaddr = MCP23017_GPIOB;
    p -= 8;
  }

  // read the current GPIO
  WIRE.beginTransmission(MCP23017_ADDRESS | i2caddr);
  wiresend(gpioaddr);
  WIRE.endTransmission();
 
  WIRE.requestFrom(MCP23017_ADDRESS | i2caddr, 1);
  return (wirerecv() >> p) & 0x1;
}

The Adafruit_MCP23017.h file is:

Code: [Select]
/***************************************************
  This is a library for the MCP23017 i2c port expander

  These displays use I2C to communicate, 2 pins are required to 
  interface
  Adafruit invests time and resources providing this open source code,
  please support Adafruit and open-source hardware by purchasing
  products from Adafruit!

  Written by Limor Fried/Ladyada for Adafruit Industries. 
  BSD license, all text above must be included in any redistribution
 ****************************************************/

#ifndef _Adafruit_MCP23017_H_
#define _Adafruit_MCP23017_H_

// Don't forget the Wire library
class Adafruit_MCP23017 {
public:
  void begin(uint8_t addr);
  void begin(void);

  void pinMode(uint8_t p, uint8_t d);
  void digitalWrite(uint8_t p, uint8_t d);
  void pullUp(uint8_t p, uint8_t d);
  uint8_t digitalRead(uint8_t p);

  void writeGPIOAB(uint16_t);
  uint16_t readGPIOAB();

 private:
  uint8_t i2caddr;
};

#define MCP23017_ADDRESS 0x20

// registers
#define MCP23017_IODIRA 0x00
#define MCP23017_IPOLA 0x02
#define MCP23017_GPINTENA 0x04
#define MCP23017_DEFVALA 0x06
#define MCP23017_INTCONA 0x08
#define MCP23017_IOCONA 0x0A
#define MCP23017_GPPUA 0x0C
#define MCP23017_INTFA 0x0E
#define MCP23017_INTCAPA 0x10
#define MCP23017_GPIOA 0x12
#define MCP23017_OLATA 0x14

#define MCP23017_IODIRB 0x01
#define MCP23017_IPOLB 0x03
#define MCP23017_GPINTENB 0x05
#define MCP23017_DEFVALB 0x07
#define MCP23017_INTCONB 0x09
#define MCP23017_IOCONB 0x0B
#define MCP23017_GPPUB 0x0D
#define MCP23017_INTFB 0x0F
#define MCP23017_INTCAPB 0x11
#define MCP23017_GPIOB 0x13
#define MCP23017_OLATB 0x15
#endif

The errors I get are:

Code: [Select]
/data/shared/arduino/digispark-1.0.4-2013-10-10/hardware/tools/avr/bin/avr-g++ -c -g -Os -Wall -fno-exceptions -ffunction-sections -fdata-sections -mmcu=attiny85 -DF_CPU=16500000L -MMD -DUSB_VID=null -DUSB_PID=null -DARDUINO=104 -I/data/shared/arduino/digispark-1.0.4-2013-10-10/hardware/digispark/cores/tiny -I/data/shared/arduino/digispark-1.0.4-2013-10-10/libraries/TinyWireM_Digispark -I/data/shared/arduino/digispark-1.0.4-2013-10-10/libraries/Wire -I/home/meissner/sketchbook/libraries/Adafruit_MCP23017 /tmp/build847613151344621352.tmp/Blink_Mcp23017.cpp -o /tmp/build847613151344621352.tmp/Blink_Mcp23017.cpp.o
In file included from /data/shared/arduino/digispark-1.0.4-2013-10-10/hardware/digispark/cores/tiny/Stream.h:24,
                 from /data/shared/arduino/digispark-1.0.4-2013-10-10/hardware/digispark/cores/tiny/TinyDebugSerial.h:31,
                 from /data/shared/arduino/digispark-1.0.4-2013-10-10/hardware/digispark/cores/tiny/WProgram.h:18,
                 from /data/shared/arduino/digispark-1.0.4-2013-10-10/hardware/digispark/cores/tiny/Arduino.h:4,
                 from Blink_Mcp23017.ino:32:
/data/shared/arduino/digispark-1.0.4-2013-10-10/hardware/digispark/cores/tiny/Print.h:37:1: warning: "BIN" redefined
In file included from /data/shared/arduino/digispark-1.0.4-2013-10-10/hardware/tools/avr/bin/../lib/gcc/avr/4.3.2/../../../avr/include/avr/iotn85.h:38,
                 from /data/shared/arduino/digispark-1.0.4-2013-10-10/hardware/tools/avr/bin/../lib/gcc/avr/4.3.2/../../../avr/include/avr/io.h:284,
                 from /data/shared/arduino/digispark-1.0.4-2013-10-10/hardware/tools/avr/bin/../lib/gcc/avr/4.3.2/../../../avr/include/avr/interrupt.h:38,
                 from /data/shared/arduino/digispark-1.0.4-2013-10-10/hardware/digispark/cores/tiny/WProgram.h:8,
                 from /data/shared/arduino/digispark-1.0.4-2013-10-10/hardware/digispark/cores/tiny/Arduino.h:4,
                 from Blink_Mcp23017.ino:32:
/data/shared/arduino/digispark-1.0.4-2013-10-10/hardware/tools/avr/bin/../lib/gcc/avr/4.3.2/../../../avr/include/avr/iotnx5.h:55:1: warning: this is the location of the previous definition
/data/shared/arduino/digispark-1.0.4-2013-10-10/hardware/tools/avr/bin/avr-g++ -c -g -Os -Wall -fno-exceptions -ffunction-sections -fdata-sections -mmcu=attiny85 -DF_CPU=16500000L -MMD -DUSB_VID=null -DUSB_PID=null -DARDUINO=104 -I/data/shared/arduino/digispark-1.0.4-2013-10-10/hardware/digispark/cores/tiny -I/data/shared/arduino/digispark-1.0.4-2013-10-10/libraries/TinyWireM_Digispark -I/data/shared/arduino/digispark-1.0.4-2013-10-10/libraries/Wire -I/home/meissner/sketchbook/libraries/Adafruit_MCP23017 -I/data/shared/arduino/digispark-1.0.4-2013-10-10/libraries/TinyWireM_Digispark/utility /data/shared/arduino/digispark-1.0.4-2013-10-10/libraries/TinyWireM_Digispark/USI_TWI_Master.cpp -o /tmp/build847613151344621352.tmp/TinyWireM_Digispark/USI_TWI_Master.cpp.o
/data/shared/arduino/digispark-1.0.4-2013-10-10/libraries/TinyWireM_Digispark/USI_TWI_Master.cpp:23:1: warning: "F_CPU" redefined
<command-line>: warning: this is the location of the previous definition
/data/shared/arduino/digispark-1.0.4-2013-10-10/hardware/tools/avr/bin/avr-g++ -c -g -Os -Wall -fno-exceptions -ffunction-sections -fdata-sections -mmcu=attiny85 -DF_CPU=16500000L -MMD -DUSB_VID=null -DUSB_PID=null -DARDUINO=104 -I/data/shared/arduino/digispark-1.0.4-2013-10-10/hardware/digispark/cores/tiny -I/data/shared/arduino/digispark-1.0.4-2013-10-10/libraries/TinyWireM_Digispark -I/data/shared/arduino/digispark-1.0.4-2013-10-10/libraries/Wire -I/home/meissner/sketchbook/libraries/Adafruit_MCP23017 -I/data/shared/arduino/digispark-1.0.4-2013-10-10/libraries/TinyWireM_Digispark/utility /data/shared/arduino/digispark-1.0.4-2013-10-10/libraries/TinyWireM_Digispark/TinyWireM.cpp -o /tmp/build847613151344621352.tmp/TinyWireM_Digispark/TinyWireM.cpp.o
/data/shared/arduino/digispark-1.0.4-2013-10-10/hardware/tools/avr/bin/avr-g++ -c -g -Os -Wall -fno-exceptions -ffunction-sections -fdata-sections -mmcu=attiny85 -DF_CPU=16500000L -MMD -DUSB_VID=null -DUSB_PID=null -DARDUINO=104 -I/data/shared/arduino/digispark-1.0.4-2013-10-10/hardware/digispark/cores/tiny -I/data/shared/arduino/digispark-1.0.4-2013-10-10/libraries/TinyWireM_Digispark -I/data/shared/arduino/digispark-1.0.4-2013-10-10/libraries/Wire -I/home/meissner/sketchbook/libraries/Adafruit_MCP23017 -I/data/shared/arduino/digispark-1.0.4-2013-10-10/libraries/Wire/utility /data/shared/arduino/digispark-1.0.4-2013-10-10/libraries/Wire/Wire.cpp -o /tmp/build847613151344621352.tmp/Wire/Wire.cpp.o
In file included from /data/shared/arduino/digispark-1.0.4-2013-10-10/hardware/digispark/cores/tiny/Stream.h:24,
                 from /data/shared/arduino/digispark-1.0.4-2013-10-10/libraries/Wire/Wire.h:26,
                 from /data/shared/arduino/digispark-1.0.4-2013-10-10/libraries/Wire/Wire.cpp:29:
/data/shared/arduino/digispark-1.0.4-2013-10-10/hardware/digispark/cores/tiny/Print.h:37:1: warning: "BIN" redefined
In file included from /data/shared/arduino/digispark-1.0.4-2013-10-10/hardware/tools/avr/bin/../lib/gcc/avr/4.3.2/../../../avr/include/avr/iotn85.h:38,
                 from /data/shared/arduino/digispark-1.0.4-2013-10-10/hardware/tools/avr/bin/../lib/gcc/avr/4.3.2/../../../avr/include/avr/io.h:284,
                 from /data/shared/arduino/digispark-1.0.4-2013-10-10/hardware/tools/avr/bin/../lib/gcc/avr/4.3.2/../../../avr/include/avr/pgmspace.h:82,
                 from /data/shared/arduino/digispark-1.0.4-2013-10-10/hardware/digispark/cores/tiny/Print.h:30,
                 from /data/shared/arduino/digispark-1.0.4-2013-10-10/hardware/digispark/cores/tiny/Stream.h:24,
                 from /data/shared/arduino/digispark-1.0.4-2013-10-10/libraries/Wire/Wire.h:26,
                 from /data/shared/arduino/digispark-1.0.4-2013-10-10/libraries/Wire/Wire.cpp:29:
/data/shared/arduino/digispark-1.0.4-2013-10-10/hardware/tools/avr/bin/../lib/gcc/avr/4.3.2/../../../avr/include/avr/iotnx5.h:55:1: warning: this is the location of the previous definition
In file included from /data/shared/arduino/digispark-1.0.4-2013-10-10/libraries/Wire/Wire.cpp:29:
/data/shared/arduino/digispark-1.0.4-2013-10-10/libraries/Wire/Wire.h:61: error: conflicting return type specified for ‘virtual size_t TwoWire::write(const uint8_t*, size_t)’
/data/shared/arduino/digispark-1.0.4-2013-10-10/hardware/digispark/cores/tiny/Print.h:75: error:   overriding ‘virtual void Print::write(const uint8_t*, size_t)’
« Last Edit: October 10, 2013, 07:34:03 am by MichaelMeissner »

digistump

  • Administrator
  • Hero Member
  • *****
  • Posts: 1465
Re: Wire.h vs. TinyWireM.h with the Arduino IDE
« Reply #1 on: October 10, 2013, 11:06:37 am »
I'm working on some major changes for the next Digistump Modified IDE release (1.5.x) - since 1.5.x has proper support for multiple uploaders, etc we get some more flexibility and can easily do things like make TinyWireM replace Wire by default when that board is used - and that is an excellent idea! I expect to finish the new IDE version in the next week give or take. I also want to upgrade TinyWireM to support both send and write, and receive and read.


MichaelMeissner

  • Full Member
  • ***
  • Posts: 166
Re: Wire.h vs. TinyWireM.h with the Arduino IDE
« Reply #2 on: October 10, 2013, 11:25:08 am »
Great, it is good to hear that.  Two other obvious candidates would be Serial -> SoftwareSerial, and Servo -> SoftwareServo.


Hopefully the Arduino side of 1.5.x has stabilized, as I've seen various complaints that it is hard to track the moving target to add 3rd party board support.

awidaai

  • Newbie
  • *
  • Posts: 1
Re: Wire.h vs. TinyWireM.h with the Arduino IDE
« Reply #3 on: January 31, 2014, 09:12:59 am »
I'm working on some major changes for the next Digistump Modified IDE release (1.5.x) - since 1.5.x has proper support for multiple uploaders, etc we get some more flexibility and can easily do things like make TinyWireM replace Wire by default when that board is used - and that is an excellent idea! I expect to finish the new IDE version in the next week give or take. I also want to upgrade TinyWireM to support both send and write, and receive and read.

Hello Digistump,

I am just following up on this post you left a while back.
I am unable to find the Digispark IDE release 1.0.5 or 1.5.x anywhere and I would very much like to use the feature which replaces Wire.h with TinyWireM.h as I am having some real trouble getting an altitude sensor code to run on the Digispark over I2C.

Can you please advise me on where I can get a copy of this IDE or a status update?

Thanks in advance! :)