blob: 889e326bb35a1f09ca7ce971ae705fc9a5e44099 [file] [log] [blame]
Brian Silverman26e4e522015-12-17 01:56:40 -05001/*----------------------------------------------------------------------------*/
Brian Silverman1a675112016-02-20 20:42:49 -05002/* Copyright (c) FIRST 2008-2016. All Rights Reserved. */
Brian Silverman26e4e522015-12-17 01:56:40 -05003/* Open Source Software - may be modified and shared by FRC teams. The code */
Brian Silverman1a675112016-02-20 20:42:49 -05004/* must be accompanied by the FIRST BSD license file in the root directory of */
5/* the project. */
Brian Silverman26e4e522015-12-17 01:56:40 -05006/*----------------------------------------------------------------------------*/
7
8#include "ADXL362.h"
9#include "DigitalInput.h"
10#include "DigitalOutput.h"
11#include "DriverStation.h"
12#include "LiveWindow/LiveWindow.h"
13
14static uint8_t kRegWrite = 0x0A;
15static uint8_t kRegRead = 0x0B;
16
17static uint8_t kPartIdRegister = 0x02;
18static uint8_t kDataRegister = 0x0E;
19static uint8_t kFilterCtlRegister = 0x2C;
20static uint8_t kPowerCtlRegister = 0x2D;
21
22//static uint8_t kFilterCtl_Range2G = 0x00;
23//static uint8_t kFilterCtl_Range4G = 0x40;
24//static uint8_t kFilterCtl_Range8G = 0x80;
25static uint8_t kFilterCtl_ODR_100Hz = 0x03;
26
27static uint8_t kPowerCtl_UltraLowNoise = 0x20;
28//static uint8_t kPowerCtl_AutoSleep = 0x04;
29static uint8_t kPowerCtl_Measure = 0x02;
30
31/**
32 * Constructor. Uses the onboard CS1.
33 *
34 * @param range The range (+ or -) that the accelerometer will measure.
35 */
36ADXL362::ADXL362(Range range) : ADXL362(SPI::Port::kOnboardCS1, range) {}
37
38/**
39 * Constructor.
40 *
41 * @param port The SPI port the accelerometer is attached to
42 * @param range The range (+ or -) that the accelerometer will measure.
43 */
44ADXL362::ADXL362(SPI::Port port, Range range) : m_spi(port) {
45 m_spi.SetClockRate(3000000);
46 m_spi.SetMSBFirst();
47 m_spi.SetSampleDataOnFalling();
48 m_spi.SetClockActiveLow();
49 m_spi.SetChipSelectActiveLow();
50
51 // Validate the part ID
52 uint8_t commands[3];
53 commands[0] = kRegRead;
54 commands[1] = kPartIdRegister;
55 commands[2] = 0;
56 m_spi.Transaction(commands, commands, 3);
57 if (commands[2] != 0xF2) {
58 DriverStation::ReportError("could not find ADXL362");
59 m_gsPerLSB = 0.0;
60 return;
61 }
62
63 SetRange(range);
64
65 // Turn on the measurements
66 commands[0] = kRegWrite;
67 commands[1] = kPowerCtlRegister;
68 commands[2] = kPowerCtl_Measure | kPowerCtl_UltraLowNoise;
69 m_spi.Write(commands, 3);
70
71 HALReport(HALUsageReporting::kResourceType_ADXL362, port);
72
73 LiveWindow::GetInstance()->AddSensor("ADXL362", port, this);
74}
75
76/** {@inheritdoc} */
77void ADXL362::SetRange(Range range) {
78 if (m_gsPerLSB == 0.0) return;
79
80 uint8_t commands[3];
81
82 switch (range) {
83 case kRange_2G:
84 m_gsPerLSB = 0.001;
85 break;
86 case kRange_4G:
87 m_gsPerLSB = 0.002;
88 break;
89 case kRange_8G:
90 case kRange_16G: // 16G not supported; treat as 8G
91 m_gsPerLSB = 0.004;
92 break;
93 }
94
95 // Specify the data format to read
96 commands[0] = kRegWrite;
97 commands[1] = kFilterCtlRegister;
98 commands[2] = kFilterCtl_ODR_100Hz | (uint8_t)((range & 0x03) << 6);
99 m_spi.Write(commands, 3);
100}
101
102/** {@inheritdoc} */
103double ADXL362::GetX() { return GetAcceleration(kAxis_X); }
104
105/** {@inheritdoc} */
106double ADXL362::GetY() { return GetAcceleration(kAxis_Y); }
107
108/** {@inheritdoc} */
109double ADXL362::GetZ() { return GetAcceleration(kAxis_Z); }
110
111/**
112 * Get the acceleration of one axis in Gs.
113 *
114 * @param axis The axis to read from.
115 * @return Acceleration of the ADXL362 in Gs.
116 */
117double ADXL362::GetAcceleration(ADXL362::Axes axis) {
118 if (m_gsPerLSB == 0.0) return 0.0;
119
120 uint8_t buffer[4];
121 uint8_t command[4] = {0, 0, 0, 0};
122 command[0] = kRegRead;
123 command[1] = kDataRegister + (uint8_t)axis;
124 m_spi.Transaction(command, buffer, 4);
125
126 // Sensor is little endian... swap bytes
127 int16_t rawAccel = buffer[3] << 8 | buffer[2];
128 return rawAccel * m_gsPerLSB;
129}
130
131/**
132 * Get the acceleration of all axes in Gs.
133 *
134 * @return An object containing the acceleration measured on each axis of the
135 * ADXL362 in Gs.
136 */
137ADXL362::AllAxes ADXL362::GetAccelerations() {
138 AllAxes data = AllAxes();
139 if (m_gsPerLSB == 0.0) {
140 data.XAxis = data.YAxis = data.ZAxis = 0.0;
141 return data;
142 }
143
144 uint8_t dataBuffer[8] = {0, 0, 0, 0, 0, 0, 0, 0};
145 int16_t rawData[3];
146
147 // Select the data address.
148 dataBuffer[0] = kRegRead;
149 dataBuffer[1] = kDataRegister;
150 m_spi.Transaction(dataBuffer, dataBuffer, 8);
151
152 for (int32_t i = 0; i < 3; i++) {
153 // Sensor is little endian... swap bytes
154 rawData[i] = dataBuffer[i * 2 + 3] << 8 | dataBuffer[i * 2 + 2];
155 }
156
157 data.XAxis = rawData[0] * m_gsPerLSB;
158 data.YAxis = rawData[1] * m_gsPerLSB;
159 data.ZAxis = rawData[2] * m_gsPerLSB;
160
161 return data;
162}
163
164std::string ADXL362::GetSmartDashboardType() const {
165 return "3AxisAccelerometer";
166}
167
168void ADXL362::InitTable(std::shared_ptr<ITable> subtable) {
169 m_table = subtable;
170 UpdateTable();
171}
172
173void ADXL362::UpdateTable() {
174 if (m_table != nullptr) {
175 m_table->PutNumber("X", GetX());
176 m_table->PutNumber("Y", GetY());
177 m_table->PutNumber("Z", GetZ());
178 }
179}
180
181std::shared_ptr<ITable> ADXL362::GetTable() const { return m_table; }