001 /*----------------------------------------------------------------------------*/ 002 /* Copyright (c) FIRST 2008-2012. All Rights Reserved. */ 003 /* Open Source Software - may be modified and shared by FRC teams. The code */ 004 /* must be accompanied by the FIRST BSD license file in the root directory of */ 005 /* the project. */ 006 /*----------------------------------------------------------------------------*/ 007 package edu.wpi.first.wpilibj; 008 009 010 /** 011 * 012 * @author dtjones 013 * @author mwills 014 */ 015 public class ADXL345_SPI extends SensorBase { 016 private static final int kPowerCtlRegister = 0x2D; 017 private static final int kDataFormatRegister = 0x31; 018 private static final int kDataRegister = 0x32; 019 private static final double kGsPerLSB = 0.00390625; 020 021 private static final int kAddress_Read = 0x80; 022 private static final int kAddress_MultiByte = 0x40; 023 024 private static final int kPowerCtl_Link=0x20; 025 private static final int kPowerCtl_AutoSleep=0x10; 026 private static final int kPowerCtl_Measure=0x08; 027 private static final int kPowerCtl_Sleep=0x04; 028 029 private static final int kDataFormat_SelfTest=0x80; 030 private static final int kDataFormat_SPI=0x40; 031 private static final int kDataFormat_IntInvert=0x20; 032 private static final int kDataFormat_FullRes=0x08; 033 private static final int kDataFormat_Justify=0x04; 034 035 036 public static class DataFormat_Range { 037 038 /** 039 * The integer value representing this enumeration 040 */ 041 public final byte value; 042 static final byte k2G_val = 0x00; 043 static final byte k4G_val = 0x01; 044 static final byte k8G_val = 0x02; 045 static final byte k16G_val = 0x03; 046 public static final ADXL345_SPI.DataFormat_Range k2G = new ADXL345_SPI.DataFormat_Range(k2G_val); 047 public static final ADXL345_SPI.DataFormat_Range k4G = new ADXL345_SPI.DataFormat_Range(k4G_val); 048 public static final ADXL345_SPI.DataFormat_Range k8G = new ADXL345_SPI.DataFormat_Range(k8G_val); 049 public static final ADXL345_SPI.DataFormat_Range k16G = new ADXL345_SPI.DataFormat_Range(k16G_val); 050 051 private DataFormat_Range(byte value) { 052 this.value = value; 053 } 054 } 055 056 public static class Axes { 057 058 /** 059 * The integer value representing this enumeration 060 */ 061 public final byte value; 062 static final byte kX_val = 0x00; 063 static final byte kY_val = 0x02; 064 static final byte kZ_val = 0x04; 065 public static final ADXL345_SPI.Axes kX = new ADXL345_SPI.Axes(kX_val); 066 public static final ADXL345_SPI.Axes kY = new ADXL345_SPI.Axes(kY_val); 067 public static final ADXL345_SPI.Axes kZ = new ADXL345_SPI.Axes(kZ_val); 068 069 private Axes(byte value) { 070 this.value = value; 071 } 072 } 073 074 public static class AllAxes { 075 076 public double XAxis; 077 public double YAxis; 078 public double ZAxis; 079 } 080 081 private SPIDevice spi; 082 083 /** 084 * Constructor. Use this when the device is the first/only device on the bus 085 * 086 * @param clk The clock channel 087 * @param mosi The mosi (output) channel 088 * @param miso The miso (input) channel 089 * @param cs The chip select channel 090 * @param range The range (+ or -) that the accelerometer will measure. 091 */ 092 public ADXL345_SPI(DigitalOutput clk, DigitalOutput mosi, DigitalInput miso, DigitalOutput cs, ADXL345_SPI.DataFormat_Range range) { 093 spi = new SPIDevice(clk, mosi, miso, cs, SPIDevice.CS_ACTIVE_HIGH); 094 init(range); 095 } 096 097 /** 098 * Constructor. Use this when the device is the first/only device on the bus 099 * 100 * @param slot The module of the digital IO for the device 101 * @param clkChannel The channel number for the clk channel 102 * @param mosiChannel The channel number for the mosi (output) channel 103 * @param misoChannel The channel number for the miso (input) channel 104 * @param csChannel The channel number for the chip select channel 105 * @param range The range (+ or -) that the accelerometer will measure. 106 */ 107 public ADXL345_SPI(int slot, int clkChannel, int mosiChannel, int misoChannel, int csChannel, ADXL345_SPI.DataFormat_Range range) { 108 spi = new SPIDevice(slot, clkChannel, mosiChannel, misoChannel, csChannel, SPIDevice.CS_ACTIVE_HIGH); 109 init(range); 110 } 111 112 /** 113 * Constructor. Use this constructor only if another SPI device has already 114 * been constructed with the clk, mosi and miso pins defined. 115 * 116 * @param cs the chip select line for the SPI bus 117 * @param range The range (+ or -) that the accelerometer will measure. 118 */ 119 public ADXL345_SPI(DigitalOutput cs, ADXL345_SPI.DataFormat_Range range) { 120 spi = new SPIDevice(cs, SPIDevice.CS_ACTIVE_HIGH); 121 init(range); 122 } 123 124 /** 125 * Constructor. Use this constructor only if another SPI device has already 126 * been constructed with the clk, mosi and miso pins defined. 127 * 128 * @param slot The module of the digital output for the device's chip select pin 129 * @param csChannel The channel for the digital output for the device's chip select pin 130 * @param range The range (+ or -) that the accelerometer will measure. 131 */ 132 public ADXL345_SPI(int slot, int csChannel, ADXL345_SPI.DataFormat_Range range) { 133 spi = new SPIDevice(slot, csChannel, SPIDevice.CS_ACTIVE_HIGH); 134 init(range); 135 } 136 137 public void free(){ 138 spi.free(); 139 } 140 141 /** 142 * Set SPI bus parameters, bring device out of sleep and set format 143 * 144 * @param range The range (+ or -) that the accelerometer will measure. 145 */ 146 private void init(ADXL345_SPI.DataFormat_Range range){ 147 spi.setBitOrder(SPIDevice.BIT_ORDER_MSB_FIRST); 148 spi.setClockPolarity(SPIDevice.CLOCK_POLARITY_ACTIVE_LOW); 149 spi.setDataOnTrailing(SPIDevice.DATA_ON_LEADING_EDGE); 150 151 // Turn on the measurements 152 spi.transfer((kPowerCtlRegister << 8) | kPowerCtl_Measure, 16); 153 // Specify the data format to read 154 spi.transfer((kDataFormatRegister << 8) | kDataFormat_FullRes | range.value, 16); 155 } 156 157 /** 158 * Get the acceleration of one axis in Gs. 159 * 160 * @param axis The axis to read from. 161 * @return Acceleration of the ADXL345 in Gs. 162 */ 163 public double getAcceleration(ADXL345_SPI.Axes axis) { 164 long rawAccelLong = spi.transfer( ((kAddress_Read | kAddress_MultiByte | kDataRegister) + axis.value) << 16, 24); 165 return accelFromBytes(rawAccelLong); 166 } 167 168 private double accelFromBytes(long value) { 169 // Sensor is little endian... swap bytes 170 short rawAccel = (short) (value&0xFF); 171 rawAccel <<= 8; 172 rawAccel |= ((value>>8)&0xFF); 173 return rawAccel * kGsPerLSB; 174 } 175 176 /** 177 * Get the acceleration of all axes in Gs. 178 * 179 * @return Acceleration measured on all axes of the ADXL345 in Gs. 180 */ 181 public ADXL345_SPI.AllAxes getAccelerations() { 182 ADXL345_SPI.AllAxes data = new ADXL345_SPI.AllAxes(); 183 long[] rawData = spi.transfer(new long[]{kAddress_Read | kAddress_MultiByte | kDataRegister, 0, 0, 0}, new int[]{8, 16, 16, 16}); 184 185 data.XAxis = accelFromBytes(rawData[1]); 186 data.YAxis = accelFromBytes(rawData[2]); 187 data.ZAxis = accelFromBytes(rawData[3]); 188 return data; 189 } 190 }