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)