Difference between revisions of "ATtiny85 8MHz and ADXL345 via I2C with Arduino code"

From ivc wiki
Jump to navigationJump to search
Line 19: Line 19:
* #0/PB0 -> SDA
* #0/PB0 -> SDA
* #2/PB2 -> SCL
* #2/PB2 -> SCL
== Libraries ==
* [https://github.com/adafruit/TinyWireM 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.
<code>
      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>


== Code ==
== Code ==
arduino_adxl345.ino:


<code>
<code>
/* 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
  if (x > 0) digitalWrite(PB1, HIGH);
  else digitalWrite(PB1, LOW);
  // Wait a small period to update
  delay(100);
}
</code>
adxl345_sensor.ino:
<code>
/************************************************************************
* 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) // 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


Code
  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
}
</code>
</code>

Revision as of 01:31, 14 May 2015

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

}