ATtiny85 8MHz and ADXL345 via I2C with Arduino code
This is a small setup based on the ATtiny85 to make use of the advanced features of the ADXL345 accelerometer.
Parts
- Adafruit Trinket 3V ATtiny85 board
- No need for level shifting for ADXL345 I2C
- Comes with [Trinket Bootloader] to upload binary with USB during the first 10 seconds of power-up/reset
- Red LED on #1/PB1 is handy for debugging
- GY-291 ADXL345 Digital 3-Axis accelerometer breakout
- On-board 3.3V LDO for ADXL345
- I2C 4.7k pull-ups
- CS 4.7k pull-up - enable I2C, not SPI
- SDO 4.7k pull-down - I2C address 0x53
- Comes with 2.54mm pin header
Wiring
- ATtiny -> ADXL345
- USB (point) -> VCC
- GND -> GND
- #0/PB0 -> SDA
- #2/PB2 -> SCL
Libraries
- TinyWireM - Using the USI on ATtiny to emulate TWI/I2C, improved by Adafruit
Speed
Add this section to the hardware.txt in the attiny folder to enable 1MHz and 4MHz processing speed.
trinket1.name=Adafruit Trinket 1MHz
trinket1.bootloader.low_fuses=0xF1
trinket1.bootloader.high_fuses=0xD5
trinket1.bootloader.extended_fuses=0xFE
trinket1.upload.maximum_size=5310
trinket1.build.mcu=attiny85
trinket1.build.f_cpu=1000000L
trinket1.build.core=arduino:arduino
trinket1.build.variant=tiny8
trinket2.name=Adafruit Trinket 4MHz
trinket2.bootloader.low_fuses=0xF1
trinket2.bootloader.high_fuses=0xD5
trinket2.bootloader.extended_fuses=0xFE
trinket2.upload.maximum_size=5310
trinket2.build.mcu=attiny85
trinket2.build.f_cpu=4000000L
trinket2.build.core=arduino:arduino
trinket2.build.variant=tiny8
Code
Save both files in the same folder, called arduino_adxl345 and open arduino_adxl345.ino
arduino_adxl345.ino:
/* ATtiny85 and ADXL345 demo code by ivc <ivc at x-pec.com> 2015 This sensor test will enable the red LED on the Trinket board when the y-axis is positive, e.g. tilted to one side, and turn off when tilted the other way. The TWI/I2C speed is determined by the F_CPU speed selected during compiling (Tools -> Board -> Adafruit Trinket 1/8/16MHz). Due to inherent instability of the internal RC oscillator in the ATtiny, 8MHz does not always work - try 1MHz. Also, a pull-up higher than 4.7K Ohm will introduce slew on the rising edge, causing the signal fail to be recognized. Try 2K Ohm pull-ups on 3.3V setups, and 4.7K on 5V (3.3V/1.5mA = 2K Ohm). Beware: ADXL345 sensor can easily be damaged if handled improperly. Always keep a couple extras to swap out and for testing. */ #include <TinyWireM.h> #include <avr/power.h> float x, y, z; void setup(void) { // Dynamically change processing speed - use Tools -> Board -> Adafruit Trinket 1/8/16MHz to adjust if (F_CPU == 16000000) { clock_prescale_set(clock_div_1); } else if (F_CPU == 8000000) { clock_prescale_set(clock_div_1); } else if (F_CPU == 4000000) { clock_prescale_set(clock_div_2); } else if (F_CPU == 2000000) { clock_prescale_set(clock_div_4); } else if (F_CPU == 1000000) { clock_prescale_set(clock_div_8); } // On-board Red LED pinMode(PB1, OUTPUT); digitalWrite(PB1, LOW); // Setup ADXL345 adxl345_init(); } void loop(void) { // Update accelerometer values readAccel(&x, &y, &z); // Enable LED of tilted over mid-point of y-axis if (y > 0) digitalWrite(PB1, HIGH); else digitalWrite(PB1, LOW); // Wait a small period to update delay(100); }
adxl345_sensor.ino:
/************************************************************************ * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU License V2. * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License, version 2 for more details * * * * Bare bones ADXL345 i2c example for Arduino 1.0 * * by Jens C Brynildsen <http://www.flashgamer.com> * * This version is not reliant of any external lib * * (Adapted for Arduino 1.0 from http://code.google.com/p/adxl345driver)* * * * Demonstrates use of ADXL345 (using the Sparkfun ADXL345 breakout) * * with i2c communication. Datasheet: * * http://www.sparkfun.com/datasheets/Sensors/Accelerometer/ADXL345.pdf * * If you need more advanced features such as freefall and tap * * detection, check out: * * https://github.com/jenschr/Arduino-libraries * ***********************************************************************/ #include <TinyWireM.h> #define DEVICE (0x53) // Device address as specified in datasheet #define SENSORS_GRAVITY_STANDARD (9.80665F) // Const float #define MG2G_MULTIPLIER (0.004) // 1 LSB represents about 3.9 mg byte _buff[2]; // Buffer array char POWER_CTL = 0x2D; //Power Control Register char DATA_FORMAT = 0x31; // Data format control char DATAX0 = 0x32; // X-Axis Data 0 char DATAX1 = 0x33; // X-Axis Data 1 char DATAY0 = 0x34; // Y-Axis Data 0 char DATAY1 = 0x35; // Y-Axis Data 1 char DATAZ0 = 0x36; // Z-Axis Data 0 char DATAZ1 = 0x37; // Z-Axis Data 1 char BW_RATE = 0x2C; // Data rate and power mode control void adxl345_init() { TinyWireM.begin(); // Join i2c bus (address optional for master) // Setup ADXL345 registers, see datahsheet to configure for your liking writeTo(DATA_FORMAT, B00001000); // Enable full resolution 10-bit, B3, and most sensitive 2g range, B1B0 writeTo(BW_RATE, B00001100); // Set 400Hz output update rate - not I2C but data update rate, B4B3B2B1 writeTo(POWER_CTL, 0); // Always be sure to zero out register, don't asume it's zero writeTo(POWER_CTL, B00001000); // Enter measurement mode, B4 } void readAccel(float *x, float *y, float *z) { // How many bytes to request from ADXL345 - it seems there are problems doing more than 4 bytes, keep it at 2 bytes. uint8_t howManyBytesToRead = 2; // Each axis reading comes in 10 bit resolution, i.e. 2 bytes, least significat byte first!! // Thus we are converting both bytes in to one int - shift bytes to align like DATAX1DATAX0 // If the bytes seem switched from the sensor, change [1] to [0] and verse visa //readFrom( DATAX0, howManyBytesToRead, _buff); //read the acceleration data from the ADXL345 //*x = ((((int)_buff[0]) << 8) | _buff[1]) * MG2G_MULTIPLIER * SENSORS_GRAVITY_STANDARD; *x = read16(DATAX0) * MG2G_MULTIPLIER * SENSORS_GRAVITY_STANDARD; //readFrom( DATAY0, howManyBytesToRead, _buff); //read the acceleration data from the ADXL345 //*y = ((((int)_buff[0]) << 8) | _buff[1]) * MG2G_MULTIPLIER * SENSORS_GRAVITY_STANDARD; *y = read16(DATAY0) * MG2G_MULTIPLIER * SENSORS_GRAVITY_STANDARD; //readFrom( DATAZ0, howManyBytesToRead, _buff); //read the acceleration data from the ADXL345 //*z = ((((int)_buff[0]) << 8) | _buff[1]) * MG2G_MULTIPLIER * SENSORS_GRAVITY_STANDARD; // Does not always seem to work - some units have a defective z-component I've noticed *z = read16(DATAZ0) * MG2G_MULTIPLIER * SENSORS_GRAVITY_STANDARD; // Test single bit //if ( (_buff[0] & 0B10000000) ) digitalWrite(PB1, HIGH); //else digitalWrite(PB1, LOW); } // Write vale to register address void writeTo(byte address, byte val) { TinyWireM.beginTransmission(DEVICE); // start transmission to device TinyWireM.write(address); // send register address TinyWireM.write(val); // send value to write TinyWireM.endTransmission(); // end transmission } // Reads num bytes starting from address register on device in to _buff array void readFrom(byte address, int num, byte _buff[]) { TinyWireM.beginTransmission(DEVICE); // start transmission to device TinyWireM.write(address); // sends address to read from TinyWireM.endTransmission(); // end transmission //TinyWireM.beginTransmission(DEVICE); // start transmission to device TinyWireM.requestFrom(DEVICE, num); // request 6 bytes from device int i = 0; while(TinyWireM.available()) // device may send less than requested (abnormal) { _buff[i] = TinyWireM.read(); // receive a byte i++; } //TinyWireM.endTransmission(); // end transmission } // Reads 2 bytes (16bits) from first x, y, or z register int16_t read16(byte address) { TinyWireM.beginTransmission(DEVICE); TinyWireM.write(address); // sends address to read from TinyWireM.endTransmission(); TinyWireM.requestFrom(DEVICE, 2); // request 2 bytes from device //return (uint16_t)(TinyWireM.read() << 8) | (TinyWireM.read()); // DATAx0DATAx1 return (uint16_t)(TinyWireM.read() | (TinyWireM.read() << 8)); // DATAx1DATAx0 }