ATtiny85 8MHz and ADXL345 via I2C with Arduino code

From ivc wiki
Revision as of 00:31, 14 May 2015 by Ivc (talk | contribs)
Jump to navigationJump to search

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 -> 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.

     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

Code

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.
  • /
  1. include <TinyWireM.h>
  2. 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
 if (x > 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 *
                                                                                                                                              • /
  1. include <TinyWireM.h>
  1. define DEVICE (0x53) // Device address as specified in datasheet
  2. define SENSORS_GRAVITY_STANDARD (9.80665F) // Const float
  3. define MG2G_MULTIPLIER (0.004) // 4mg/LSB

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, B00000000); // Enable most sensitive 2g range, B1B0
 writeTo(BW_RATE, B00001100); // Set 400Hz output update rate - not I2C but data output, 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.
 // Z-axis DATAZ1 register is sometimes is bad, only first DATAZ1 register return valid data
 uint8_t howManyBytesToRead = 2; 
 // Zero buffer array
 memset(_buff, 0, 6);
 
 // 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;   
 // Zero buffer array
 memset(_buff, 0, 6);
 readFrom( DATAY0, howManyBytesToRead, _buff); //read the acceleration data from the ADXL345
 *y = ((((int)_buff[0]) << 8) | _buff[1]) * MG2G_MULTIPLIER * SENSORS_GRAVITY_STANDARD;   
 // Zero buffer array
 memset(_buff, 0, 6);
 readFrom( DATAZ0, howManyBytesToRead, _buff); //read the acceleration data from the ADXL345
 *z = ((((int)_buff[1]) << 8) | _buff[0]) * 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

}