user43136: TL;DR:

Arduinos are current hungry so I want to switch my microcontroller
code works on Uno, I change upload to ATtiny85, code doesn't compile
Wire.h breaks at the TWBR input
Should I keep trying to fix this or should I just use ATmega328P without the Arduino?




So I'm working on a project where I send data from an IMU (MPU6050) to a phone using Bluetooth LE (HC08) with a bit of signal filtering by a microcontroller in between. I've been using Pro Minis but the amperage consumption by these boards is ridiculous, so I'm trying to replace these with some ATtiny85's that I have laying around.
The problem is, the Wire.h library won't compile for the ATtiny85. It's also worth noting that the default MPU6050 code mandates use of an interrupt pin, which ATtiny's don't have, so I've modified the code to work without it (I'm not sure if that's part of the problem).
#include <SoftwareSerial.h>
#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps20.h"
#include "Wire.h"

//==============================================================================
// MPU6050 initialization code
MPU6050 mpu;
uint16_t packetSize;
uint16_t fifoCount;
uint8_t fifoBuffer[64];
Quaternion q;
VectorInt16 aa;
VectorInt16 aaReal;
VectorInt16 aaWorld;
VectorFloat gravity;

//==============================================================================
// microcontroller initialization code
int avg_counter = 0;
int pts_to_avg = 15;
int * x_array = (int*)malloc(sizeof(int) * 25);
int * y_array = (int*)malloc(sizeof(int) * 25);
int * z_array = (int*)malloc(sizeof(int) * 25);

//==============================================================================
// HC-08 initialization code
const byte rxPin = 3;
const byte txPin = 4;
SoftwareSerial bleSerial(rxPin, txPin);

//==============================================================================
void setup() {
  // MPU6050 setup code ========================================================
  Wire.begin();
  TWBR = 24;
  mpu.initialize();
  mpu.dmpInitialize();
  mpu.setXAccelOffset(-1343);
  mpu.setYAccelOffset(-1155);
  mpu.setZAccelOffset(1033);
  mpu.setXGyroOffset(19);
  mpu.setYGyroOffset(-27);
  mpu.setZGyroOffset(16);
  mpu.setDMPEnabled(true);
  packetSize = mpu.dmpGetFIFOPacketSize();
  fifoCount = mpu.getFIFOCount();

  // microcontroller setup code ================================================


  // HC-08 setup code ==========================================================
  // make sure your HC-08 is set to the same baud as below!
  bleSerial.begin(19200);
  delay(100);
}

//==============================================================================
void loop() {
  while(fifoCount < packetSize){
    fifoCount = mpu.getFIFOCount();
  }

  if(fifoCount == 1024){
    mpu.resetFIFO();
    bleSerial.println(F("FIFO overflow!"));
  }else{
    if(fifoCount % packetSize != 0){
      mpu.resetFIFO();
    }else{
      while(fifoCount >= packetSize){
        mpu.getFIFOBytes(fifoBuffer, packetSize);
        fifoCount -= packetSize;
      }

      mpu.dmpGetQuaternion(&q,fifoBuffer);
      mpu.dmpGetAccel(&aa, fifoBuffer);
      mpu.dmpGetGravity(&gravity, &q);
      mpu.dmpGetLinearAccel(&aaReal, &aa, &gravity);
      mpu.dmpGetLinearAccelInWorld(&aaWorld, &aaReal, &q);

      // points are averaged to keep the baud low w/o FIFO overflow
      if(avg_counter <= pts_to_avg){
        // add live data to this array and hold onto it to be averaged
        x_array[avg_counter] = aaWorld.x;
        y_array[avg_counter] = aaWorld.y;
        z_array[avg_counter] = aaWorld.z;
        avg_counter++;
      }else{
        // average data from the array
        int x_average=0;
        int y_average=0;
        int z_average=0;

        // sums the data in #_average
        for(int i = 0; i < avg_counter; i++){
          x_average += x_array[i];
          y_average += y_array[i];
          z_average += z_array[i];
        }

        // divides by avg_counter (which should == pts_to_avg)
        x_average /= avg_counter;
        y_average /= avg_counter;
        z_average /= avg_counter;

        // resets counter so the array data can be overwritten with future data
        avg_counter = 0;

        // prints data to serial port (if BT is connected, sends via BT)
        bleSerial.print(x_average);
        bleSerial.print(",");
        bleSerial.print(y_average);
        bleSerial.print(",");
        bleSerial.println(z_average);
      }
    }
  }
}

When using Arduino as ISP, selecting "Board: ATtiny25/45/85", "Processor: ATtiny85", & "Clock: Internal 1MHz", the following error showed up:
exit status 1
'TWBR' was not declared in this scope

this error did not occur when compiling for the Uno. If you comment out TWBR, then you get an enormous error message (I'll only paste a bit):
In file included from c:\users\auphynne\appdata\local\arduino15\packages\arduino\tools\avr-gcc\4.9.2-atmel3.5.4-arduino2\avr\include\avr\io.h:99:0,

                 from C:\Users\auPhynne\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.21\libraries\Wire\src\utility\twi.c:25:

C:\Users\auPhynne\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.21\libraries\Wire\src\utility\twi.c:426:15: error: 'TWINT' undeclared (first use in this function)

    TWCR = _BV(TWINT) | _BV(TWSTA)| _BV(TWEN) ;

               ^

C:\Users\auPhynne\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.21\libraries\Wire\src\utility\twi.c:426:28: error: 'TWSTA' undeclared (first use in this function)

    TWCR = _BV(TWINT) | _BV(TWSTA)| _BV(TWEN) ;

                            ^

C:\Users\auPhynne\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.21\libraries\Wire\src\utility\twi.c:426:40: error: 'TWEN' undeclared (first use in this function)

    TWCR = _BV(TWINT) | _BV(TWSTA)| _BV(TWEN) ;

                                        ^

exit status 1
Error compiling for board ATtiny25/45/85.

To try to remedy this, I went into
C:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\Wire\src\utility\twi.c

and hardcoded this line from
// initialize twi prescaler and bit rate
cbi(TWSR, TWPS0);
cbi(TWSR, TWPS1);
TWBR = ((F_CPU / TWI_FREQ) - 16) / 2;

to
// initialize twi prescaler and bit rate
cbi(TWSR, TWPS0);
cbi(TWSR, TWPS1);
TWBR = 24;

and I still got the same gruesome error message.
Pins are what you'd expect, 5v power to both modules and grounded, plus:

Uno D4 -> HC08 RXD
Uno D3 -> HC08 TXD
Uno SCL -> MPU6050 SCL
Uno SDA -> MPU6050 SDA

(again note that the interrupt pin is not used, and this worked quite well when building on the Uno! I got data on my phone's BT serial terminal app so that doesn't seem to be the problem)
Any ideas on how I can get Wire.h to compile on my ATtiny85?
Or... should I just abort and go with the ATmega328P (without the accompanying Uno) since it comes in the Quad Flat SMD package? (footprint matters for the long term)

user77676: If you want Wire.h library to work on attiny85 use:
https://github.com/SpenceKonde/ATTinyCore
I did and it compiles.

user42015: You get this error, because the ATTiny85 doesn't have full I2C hardware. It only as an USI (Universal Serial Interface). This can be utilized to do the rest of the I2C protocol via software. There are some libraries out there to do that, most of them are somewhat named TinyWire. There were dedicated libraries for master and slave operation named TinyWireM and TinyWireS. And I composed one library with both functionalities (and some more) in TinyWire. The last one - I think - is not usable for you, because theSoftwareSerial library needs the PinChangeInterrupt to work, but TinyWire uses it for detecting stop conditions on the I2C bus.
So for your case you can use the TinyWireM library. Note that the master operations need exact timing. Using to much interrupts in this time can cause problems in transmission. Test it and disable interrupts, if it is needed.

43136: <p><strong>TL;DR:</strong></p>

<ul>
<li>Arduinos are current hungry so I want to switch my microcontroller</li>
<li>code works on Uno, I change upload to ATtiny85, code doesn't compile</li>
<li>Wire.h breaks at the TWBR input</li>
<li>Should I keep trying to fix this or should I just use ATmega328P without the Arduino?</li>
</ul>

<hr>

<hr>

<hr>

<p>So I'm working on a project where I send data from an IMU (MPU6050) to a phone using Bluetooth LE (HC08) with a bit of signal filtering by a microcontroller in between. I've been using Pro Minis but the amperage consumption by these boards is ridiculous, so I'm trying to replace these with some ATtiny85's that I have laying around.</p>

<p>The problem is, the Wire.h library won't compile for the ATtiny85. It's also worth noting that the default MPU6050 code mandates use of an interrupt pin, which ATtiny's don't have, so I've modified the code to work without it (I'm not sure if that's part of the problem).</p>

<pre><code>#include &lt;SoftwareSerial.h&gt;
#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps20.h"
#include "Wire.h"

//==============================================================================
// MPU6050 initialization code
MPU6050 mpu;
uint16_t packetSize;
uint16_t fifoCount;
uint8_t fifoBuffer[64];
Quaternion q;
VectorInt16 aa;
VectorInt16 aaReal;
VectorInt16 aaWorld;
VectorFloat gravity;

//==============================================================================
// microcontroller initialization code
int avg_counter = 0;
int pts_to_avg = 15;
int * x_array = (int*)malloc(sizeof(int) * 25);
int * y_array = (int*)malloc(sizeof(int) * 25);
int * z_array = (int*)malloc(sizeof(int) * 25);

//==============================================================================
// HC-08 initialization code
const byte rxPin = 3;
const byte txPin = 4;
SoftwareSerial bleSerial(rxPin, txPin);

//==============================================================================
void setup() {
  // MPU6050 setup code ========================================================
  Wire.begin();
  TWBR = 24;
  mpu.initialize();
  mpu.dmpInitialize();
  mpu.setXAccelOffset(-1343);
  mpu.setYAccelOffset(-1155);
  mpu.setZAccelOffset(1033);
  mpu.setXGyroOffset(19);
  mpu.setYGyroOffset(-27);
  mpu.setZGyroOffset(16);
  mpu.setDMPEnabled(true);
  packetSize = mpu.dmpGetFIFOPacketSize();
  fifoCount = mpu.getFIFOCount();

  // microcontroller setup code ================================================


  // HC-08 setup code ==========================================================
  // make sure your HC-08 is set to the same baud as below!
  bleSerial.begin(19200);
  delay(100);
}

//==============================================================================
void loop() {
  while(fifoCount &lt; packetSize){
    fifoCount = mpu.getFIFOCount();
  }

  if(fifoCount == 1024){
    mpu.resetFIFO();
    bleSerial.println(F("FIFO overflow!"));
  }else{
    if(fifoCount % packetSize != 0){
      mpu.resetFIFO();
    }else{
      while(fifoCount &gt;= packetSize){
        mpu.getFIFOBytes(fifoBuffer, packetSize);
        fifoCount -= packetSize;
      }

      mpu.dmpGetQuaternion(&amp;q,fifoBuffer);
      mpu.dmpGetAccel(&amp;aa, fifoBuffer);
      mpu.dmpGetGravity(&amp;gravity, &amp;q);
      mpu.dmpGetLinearAccel(&amp;aaReal, &amp;aa, &amp;gravity);
      mpu.dmpGetLinearAccelInWorld(&amp;aaWorld, &amp;aaReal, &amp;q);

      // points are averaged to keep the baud low w/o FIFO overflow
      if(avg_counter &lt;= pts_to_avg){
        // add live data to this array and hold onto it to be averaged
        x_array[avg_counter] = aaWorld.x;
        y_array[avg_counter] = aaWorld.y;
        z_array[avg_counter] = aaWorld.z;
        avg_counter++;
      }else{
        // average data from the array
        int x_average=0;
        int y_average=0;
        int z_average=0;

        // sums the data in #_average
        for(int i = 0; i &lt; avg_counter; i++){
          x_average += x_array[i];
          y_average += y_array[i];
          z_average += z_array[i];
        }

        // divides by avg_counter (which should == pts_to_avg)
        x_average /= avg_counter;
        y_average /= avg_counter;
        z_average /= avg_counter;

        // resets counter so the array data can be overwritten with future data
        avg_counter = 0;

        // prints data to serial port (if BT is connected, sends via BT)
        bleSerial.print(x_average);
        bleSerial.print(",");
        bleSerial.print(y_average);
        bleSerial.print(",");
        bleSerial.println(z_average);
      }
    }
  }
}
</code></pre>

<p>When using Arduino as ISP, selecting "Board: ATtiny25/45/85", "Processor: ATtiny85", &amp; "Clock: Internal 1MHz", the following error showed up:</p>

<pre><code>exit status 1
'TWBR' was not declared in this scope
</code></pre>

<p>this error did <em>not</em> occur when compiling for the Uno. If you comment out TWBR, then you get an enormous error message (I'll only paste a bit):</p>

<pre><code>In file included from c:\users\auphynne\appdata\local\arduino15\packages\arduino\tools\avr-gcc\4.9.2-atmel3.5.4-arduino2\avr\include\avr\io.h:99:0,

                 from C:\Users\auPhynne\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.21\libraries\Wire\src\utility\twi.c:25:

C:\Users\auPhynne\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.21\libraries\Wire\src\utility\twi.c:426:15: error: 'TWINT' undeclared (first use in this function)

    TWCR = _BV(TWINT) | _BV(TWSTA)| _BV(TWEN) ;

               ^

C:\Users\auPhynne\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.21\libraries\Wire\src\utility\twi.c:426:28: error: 'TWSTA' undeclared (first use in this function)

    TWCR = _BV(TWINT) | _BV(TWSTA)| _BV(TWEN) ;

                            ^

C:\Users\auPhynne\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.21\libraries\Wire\src\utility\twi.c:426:40: error: 'TWEN' undeclared (first use in this function)

    TWCR = _BV(TWINT) | _BV(TWSTA)| _BV(TWEN) ;

                                        ^

exit status 1
Error compiling for board ATtiny25/45/85.
</code></pre>

<p>To try to remedy this, I went into</p>

<pre><code>C:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\Wire\src\utility\twi.c
</code></pre>

<p>and hardcoded this line from</p>

<pre><code>// initialize twi prescaler and bit rate
cbi(TWSR, TWPS0);
cbi(TWSR, TWPS1);
TWBR = ((F_CPU / TWI_FREQ) - 16) / 2;
</code></pre>

<p>to</p>

<pre><code>// initialize twi prescaler and bit rate
cbi(TWSR, TWPS0);
cbi(TWSR, TWPS1);
TWBR = 24;
</code></pre>

<p>and I still got the same gruesome error message.</p>

<p>Pins are what you'd expect, 5v power to both modules and grounded, plus:</p>

<ul>
<li>Uno D4 -> HC08 RXD</li>
<li>Uno D3 -> HC08 TXD</li>
<li>Uno SCL -> MPU6050 SCL</li>
<li>Uno SDA -> MPU6050 SDA</li>
</ul>

<p>(again note that the interrupt pin is not used, and this worked quite well when building on the Uno! I got data on my phone's BT serial terminal app so that doesn't seem to be the problem)</p>

<p><strong>Any ideas on how I can get Wire.h to compile on my ATtiny85?</strong></p>

<p><strong>Or... should I just abort and go with the ATmega328P</strong> (without the accompanying Uno) since it comes in the Quad Flat SMD package? (footprint matters for the long term)</p>
 77676: <p>If you want Wire.h library to work on attiny85 use:</p>
<p><a href="https://github.com/SpenceKonde/ATTinyCore" rel="nofollow noreferrer">https://github.com/SpenceKonde/ATTinyCore</a></p>
<p>I did and it compiles.</p>
 42015: <p>You get this error, because the ATTiny85 doesn't have full I2C hardware. It only as an USI (Universal Serial Interface). This can be utilized to do the rest of the I2C protocol via software. There are some libraries out there to do that, most of them are somewhat named <code>TinyWire</code>. There were dedicated libraries for master and slave operation named <code>TinyWireM</code> and <code>TinyWireS</code>. And I composed one library with both functionalities (and some more) in <a href="https://github.com/lucullusTheOnly/TinyWire" rel="noreferrer">TinyWire</a>. The last one - I think - is not usable for you, because the<code>SoftwareSerial</code> library needs the PinChangeInterrupt to work, but TinyWire uses it for detecting stop conditions on the I2C bus.</p>

<p>So for your case you can use the <a href="https://github.com/adafruit/TinyWireM" rel="noreferrer">TinyWireM</a> library. Note that the master operations need exact timing. Using to much interrupts in this time can cause problems in transmission. Test it and disable interrupts, if it is needed.</p>
