blob: d709ae41c0baf3b032de8f2b0e288a2a83da8cd7 [file] [log] [blame]
Brian Silverman41cdd3e2019-01-19 19:48:58 -08001/*----------------------------------------------------------------------------*/
2/* Copyright (c) 2008-2018 FIRST. All Rights Reserved. */
3/* 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
10#include <hal/HAL.h>
11
12#include "frc/DriverStation.h"
13#include "frc/smartdashboard/SendableBuilder.h"
14
15using namespace frc;
16
17static constexpr int kRegWrite = 0x0A;
18static constexpr int kRegRead = 0x0B;
19
20static constexpr int kPartIdRegister = 0x02;
21static constexpr int kDataRegister = 0x0E;
22static constexpr int kFilterCtlRegister = 0x2C;
23static constexpr int kPowerCtlRegister = 0x2D;
24
25// static constexpr int kFilterCtl_Range2G = 0x00;
26// static constexpr int kFilterCtl_Range4G = 0x40;
27// static constexpr int kFilterCtl_Range8G = 0x80;
28static constexpr int kFilterCtl_ODR_100Hz = 0x03;
29
30static constexpr int kPowerCtl_UltraLowNoise = 0x20;
31// static constexpr int kPowerCtl_AutoSleep = 0x04;
32static constexpr int kPowerCtl_Measure = 0x02;
33
34ADXL362::ADXL362(Range range) : ADXL362(SPI::Port::kOnboardCS1, range) {}
35
36ADXL362::ADXL362(SPI::Port port, Range range) : m_spi(port) {
37 m_spi.SetClockRate(3000000);
38 m_spi.SetMSBFirst();
39 m_spi.SetSampleDataOnTrailingEdge();
40 m_spi.SetClockActiveLow();
41 m_spi.SetChipSelectActiveLow();
42
43 // Validate the part ID
44 uint8_t commands[3];
45 commands[0] = kRegRead;
46 commands[1] = kPartIdRegister;
47 commands[2] = 0;
48 m_spi.Transaction(commands, commands, 3);
49 if (commands[2] != 0xF2) {
50 DriverStation::ReportError("could not find ADXL362");
51 m_gsPerLSB = 0.0;
52 return;
53 }
54
55 SetRange(range);
56
57 // Turn on the measurements
58 commands[0] = kRegWrite;
59 commands[1] = kPowerCtlRegister;
60 commands[2] = kPowerCtl_Measure | kPowerCtl_UltraLowNoise;
61 m_spi.Write(commands, 3);
62
63 HAL_Report(HALUsageReporting::kResourceType_ADXL362, port);
64
65 SetName("ADXL362", port);
66}
67
68void ADXL362::SetRange(Range range) {
69 if (m_gsPerLSB == 0.0) return;
70
71 uint8_t commands[3];
72
73 switch (range) {
74 case kRange_2G:
75 m_gsPerLSB = 0.001;
76 break;
77 case kRange_4G:
78 m_gsPerLSB = 0.002;
79 break;
80 case kRange_8G:
81 case kRange_16G: // 16G not supported; treat as 8G
82 m_gsPerLSB = 0.004;
83 break;
84 }
85
86 // Specify the data format to read
87 commands[0] = kRegWrite;
88 commands[1] = kFilterCtlRegister;
89 commands[2] =
90 kFilterCtl_ODR_100Hz | static_cast<uint8_t>((range & 0x03) << 6);
91 m_spi.Write(commands, 3);
92}
93
94double ADXL362::GetX() { return GetAcceleration(kAxis_X); }
95
96double ADXL362::GetY() { return GetAcceleration(kAxis_Y); }
97
98double ADXL362::GetZ() { return GetAcceleration(kAxis_Z); }
99
100double ADXL362::GetAcceleration(ADXL362::Axes axis) {
101 if (m_gsPerLSB == 0.0) return 0.0;
102
103 uint8_t buffer[4];
104 uint8_t command[4] = {0, 0, 0, 0};
105 command[0] = kRegRead;
106 command[1] = kDataRegister + static_cast<uint8_t>(axis);
107 m_spi.Transaction(command, buffer, 4);
108
109 // Sensor is little endian... swap bytes
110 int16_t rawAccel = buffer[3] << 8 | buffer[2];
111 return rawAccel * m_gsPerLSB;
112}
113
114ADXL362::AllAxes ADXL362::GetAccelerations() {
115 AllAxes data = AllAxes();
116 if (m_gsPerLSB == 0.0) {
117 data.XAxis = data.YAxis = data.ZAxis = 0.0;
118 return data;
119 }
120
121 uint8_t dataBuffer[8] = {0, 0, 0, 0, 0, 0, 0, 0};
122 int16_t rawData[3];
123
124 // Select the data address.
125 dataBuffer[0] = kRegRead;
126 dataBuffer[1] = kDataRegister;
127 m_spi.Transaction(dataBuffer, dataBuffer, 8);
128
129 for (int i = 0; i < 3; i++) {
130 // Sensor is little endian... swap bytes
131 rawData[i] = dataBuffer[i * 2 + 3] << 8 | dataBuffer[i * 2 + 2];
132 }
133
134 data.XAxis = rawData[0] * m_gsPerLSB;
135 data.YAxis = rawData[1] * m_gsPerLSB;
136 data.ZAxis = rawData[2] * m_gsPerLSB;
137
138 return data;
139}
140
141void ADXL362::InitSendable(SendableBuilder& builder) {
142 builder.SetSmartDashboardType("3AxisAccelerometer");
143 auto x = builder.GetEntry("X").GetHandle();
144 auto y = builder.GetEntry("Y").GetHandle();
145 auto z = builder.GetEntry("Z").GetHandle();
146 builder.SetUpdateTable([=]() {
147 auto data = GetAccelerations();
148 nt::NetworkTableEntry(x).SetDouble(data.XAxis);
149 nt::NetworkTableEntry(y).SetDouble(data.YAxis);
150 nt::NetworkTableEntry(z).SetDouble(data.ZAxis);
151 });
152}