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 }