blob: 6ed8c8cc485bb9c593c2fb47f8524136fee3400e [file] [log] [blame]
Brian Silverman41cdd3e2019-01-19 19:48:58 -08001/*----------------------------------------------------------------------------*/
James Kuszmaul4f3ad3c2019-12-01 16:35:21 -08002/* Copyright (c) 2008-2019 FIRST. All Rights Reserved. */
Brian Silverman41cdd3e2019-01-19 19:48:58 -08003/* Open Source Software - may be modified and shared by FRC teams. The code */
4/* must be accompanied by the FIRST BSD license file in the root directory of */
5/* the project. */
6/*----------------------------------------------------------------------------*/
7
8#include "frc/ADXL362.h"
9
James Kuszmaul4b81d302019-12-14 20:53:14 -080010#include <hal/FRCUsageReporting.h>
Brian Silverman41cdd3e2019-01-19 19:48:58 -080011
12#include "frc/DriverStation.h"
13#include "frc/smartdashboard/SendableBuilder.h"
James Kuszmaul4f3ad3c2019-12-01 16:35:21 -080014#include "frc/smartdashboard/SendableRegistry.h"
Brian Silverman41cdd3e2019-01-19 19:48:58 -080015
16using namespace frc;
17
18static constexpr int kRegWrite = 0x0A;
19static constexpr int kRegRead = 0x0B;
20
21static constexpr int kPartIdRegister = 0x02;
22static constexpr int kDataRegister = 0x0E;
23static constexpr int kFilterCtlRegister = 0x2C;
24static constexpr int kPowerCtlRegister = 0x2D;
25
26// static constexpr int kFilterCtl_Range2G = 0x00;
27// static constexpr int kFilterCtl_Range4G = 0x40;
28// static constexpr int kFilterCtl_Range8G = 0x80;
29static constexpr int kFilterCtl_ODR_100Hz = 0x03;
30
31static constexpr int kPowerCtl_UltraLowNoise = 0x20;
32// static constexpr int kPowerCtl_AutoSleep = 0x04;
33static constexpr int kPowerCtl_Measure = 0x02;
34
35ADXL362::ADXL362(Range range) : ADXL362(SPI::Port::kOnboardCS1, range) {}
36
James Kuszmaul4f3ad3c2019-12-01 16:35:21 -080037ADXL362::ADXL362(SPI::Port port, Range range)
38 : m_spi(port), m_simDevice("ADXL362", port) {
39 if (m_simDevice) {
40 m_simRange =
41 m_simDevice.CreateEnum("Range", true, {"2G", "4G", "8G", "16G"}, 0);
42 m_simX = m_simDevice.CreateDouble("X Accel", false, 0.0);
43 m_simX = m_simDevice.CreateDouble("Y Accel", false, 0.0);
44 m_simZ = m_simDevice.CreateDouble("Z Accel", false, 0.0);
45 }
46
Brian Silverman41cdd3e2019-01-19 19:48:58 -080047 m_spi.SetClockRate(3000000);
48 m_spi.SetMSBFirst();
49 m_spi.SetSampleDataOnTrailingEdge();
50 m_spi.SetClockActiveLow();
51 m_spi.SetChipSelectActiveLow();
52
Brian Silverman41cdd3e2019-01-19 19:48:58 -080053 uint8_t commands[3];
James Kuszmaul4f3ad3c2019-12-01 16:35:21 -080054 if (!m_simDevice) {
55 // Validate the part ID
56 commands[0] = kRegRead;
57 commands[1] = kPartIdRegister;
58 commands[2] = 0;
59 m_spi.Transaction(commands, commands, 3);
60 if (commands[2] != 0xF2) {
61 DriverStation::ReportError("could not find ADXL362");
62 m_gsPerLSB = 0.0;
63 return;
64 }
Brian Silverman41cdd3e2019-01-19 19:48:58 -080065 }
66
67 SetRange(range);
68
69 // Turn on the measurements
70 commands[0] = kRegWrite;
71 commands[1] = kPowerCtlRegister;
72 commands[2] = kPowerCtl_Measure | kPowerCtl_UltraLowNoise;
73 m_spi.Write(commands, 3);
74
James Kuszmaul4b81d302019-12-14 20:53:14 -080075 HAL_Report(HALUsageReporting::kResourceType_ADXL362, port + 1);
Brian Silverman41cdd3e2019-01-19 19:48:58 -080076
James Kuszmaul4f3ad3c2019-12-01 16:35:21 -080077 SendableRegistry::GetInstance().AddLW(this, "ADXL362", port);
Brian Silverman41cdd3e2019-01-19 19:48:58 -080078}
79
80void ADXL362::SetRange(Range range) {
81 if (m_gsPerLSB == 0.0) return;
82
83 uint8_t commands[3];
84
85 switch (range) {
86 case kRange_2G:
87 m_gsPerLSB = 0.001;
88 break;
89 case kRange_4G:
90 m_gsPerLSB = 0.002;
91 break;
92 case kRange_8G:
93 case kRange_16G: // 16G not supported; treat as 8G
94 m_gsPerLSB = 0.004;
95 break;
96 }
97
98 // Specify the data format to read
99 commands[0] = kRegWrite;
100 commands[1] = kFilterCtlRegister;
101 commands[2] =
102 kFilterCtl_ODR_100Hz | static_cast<uint8_t>((range & 0x03) << 6);
103 m_spi.Write(commands, 3);
James Kuszmaul4f3ad3c2019-12-01 16:35:21 -0800104
105 if (m_simRange) m_simRange.Set(range);
Brian Silverman41cdd3e2019-01-19 19:48:58 -0800106}
107
108double ADXL362::GetX() { return GetAcceleration(kAxis_X); }
109
110double ADXL362::GetY() { return GetAcceleration(kAxis_Y); }
111
112double ADXL362::GetZ() { return GetAcceleration(kAxis_Z); }
113
114double ADXL362::GetAcceleration(ADXL362::Axes axis) {
115 if (m_gsPerLSB == 0.0) return 0.0;
116
James Kuszmaul4f3ad3c2019-12-01 16:35:21 -0800117 if (axis == kAxis_X && m_simX) return m_simX.Get();
118 if (axis == kAxis_Y && m_simY) return m_simY.Get();
119 if (axis == kAxis_Z && m_simZ) return m_simZ.Get();
120
Brian Silverman41cdd3e2019-01-19 19:48:58 -0800121 uint8_t buffer[4];
122 uint8_t command[4] = {0, 0, 0, 0};
123 command[0] = kRegRead;
124 command[1] = kDataRegister + static_cast<uint8_t>(axis);
125 m_spi.Transaction(command, buffer, 4);
126
127 // Sensor is little endian... swap bytes
128 int16_t rawAccel = buffer[3] << 8 | buffer[2];
129 return rawAccel * m_gsPerLSB;
130}
131
132ADXL362::AllAxes ADXL362::GetAccelerations() {
James Kuszmaul4f3ad3c2019-12-01 16:35:21 -0800133 AllAxes data;
Brian Silverman41cdd3e2019-01-19 19:48:58 -0800134 if (m_gsPerLSB == 0.0) {
135 data.XAxis = data.YAxis = data.ZAxis = 0.0;
136 return data;
137 }
James Kuszmaul4f3ad3c2019-12-01 16:35:21 -0800138 if (m_simX && m_simY && m_simZ) {
139 data.XAxis = m_simX.Get();
140 data.YAxis = m_simY.Get();
141 data.ZAxis = m_simZ.Get();
142 return data;
143 }
Brian Silverman41cdd3e2019-01-19 19:48:58 -0800144
145 uint8_t dataBuffer[8] = {0, 0, 0, 0, 0, 0, 0, 0};
146 int16_t rawData[3];
147
148 // Select the data address.
149 dataBuffer[0] = kRegRead;
150 dataBuffer[1] = kDataRegister;
151 m_spi.Transaction(dataBuffer, dataBuffer, 8);
152
153 for (int i = 0; i < 3; i++) {
154 // Sensor is little endian... swap bytes
155 rawData[i] = dataBuffer[i * 2 + 3] << 8 | dataBuffer[i * 2 + 2];
156 }
157
158 data.XAxis = rawData[0] * m_gsPerLSB;
159 data.YAxis = rawData[1] * m_gsPerLSB;
160 data.ZAxis = rawData[2] * m_gsPerLSB;
161
162 return data;
163}
164
165void ADXL362::InitSendable(SendableBuilder& builder) {
166 builder.SetSmartDashboardType("3AxisAccelerometer");
167 auto x = builder.GetEntry("X").GetHandle();
168 auto y = builder.GetEntry("Y").GetHandle();
169 auto z = builder.GetEntry("Z").GetHandle();
170 builder.SetUpdateTable([=]() {
171 auto data = GetAccelerations();
172 nt::NetworkTableEntry(x).SetDouble(data.XAxis);
173 nt::NetworkTableEntry(y).SetDouble(data.YAxis);
174 nt::NetworkTableEntry(z).SetDouble(data.ZAxis);
175 });
176}