blob: eb23b4819bef62c66eeed1096750e83ba46e3d78 [file] [log] [blame]
Brian Silverman07ec88e2014-12-28 00:13:08 -08001#include "frc971/wpilib/gyro_interface.h"
2
Austin Schuhf2a50ba2016-12-24 16:16:26 -08003#include <chrono>
Tyler Chatowbf0609c2021-07-31 16:13:27 -07004#include <cinttypes>
Brian Silverman07ec88e2014-12-28 00:13:08 -08005
John Park33858a32018-09-28 23:05:48 -07006#include "aos/logging/logging.h"
7#include "aos/time/time.h"
Brian Silverman07ec88e2014-12-28 00:13:08 -08008
9#ifndef M_PI
10#define M_PI 3.14159265358979323846
11#endif
12
Stephan Pleinesf63bde82024-01-13 15:59:33 -080013namespace frc971::wpilib {
Brian Silverman07ec88e2014-12-28 00:13:08 -080014
Parker Schuhd3b7a8872018-02-19 16:42:27 -080015GyroInterface::GyroInterface() : gyro_(new frc::SPI(frc::SPI::kOnboardCS0)) {
Brian Silverman07ec88e2014-12-28 00:13:08 -080016 // The gyro goes up to 8.08MHz.
17 // The myRIO goes up to 4MHz, so the roboRIO probably does too.
18 gyro_->SetClockRate(4e6);
19 gyro_->SetChipSelectActiveLow();
James Kuszmaul9776b392023-01-14 14:08:08 -080020 gyro_->SetMode(frc::SPI::Mode::kMode3);
Brian Silverman07ec88e2014-12-28 00:13:08 -080021}
22
23bool GyroInterface::InitializeGyro() {
24 uint32_t result;
25 if (!DoTransaction(0x20000003, &result)) {
Austin Schuhf257f3c2019-10-27 21:00:43 -070026 AOS_LOG(WARNING, "failed to start a self-check\n");
Brian Silverman07ec88e2014-12-28 00:13:08 -080027 return false;
28 }
29 if (result != 1) {
30 // We might have hit a parity error or something and are now retrying, so
31 // this isn't a very big deal.
Austin Schuhf257f3c2019-10-27 21:00:43 -070032 AOS_LOG(INFO, "gyro unexpected initial response 0x%" PRIx32 "\n", result);
Brian Silverman07ec88e2014-12-28 00:13:08 -080033 }
34
35 // Wait for it to assert the fault conditions before reading them.
Austin Schuhf2a50ba2016-12-24 16:16:26 -080036 ::std::this_thread::sleep_for(::std::chrono::milliseconds(50));
Brian Silverman07ec88e2014-12-28 00:13:08 -080037
38 if (!DoTransaction(0x20000000, &result)) {
Austin Schuhf257f3c2019-10-27 21:00:43 -070039 AOS_LOG(WARNING, "failed to clear latched non-fault data\n");
Brian Silverman07ec88e2014-12-28 00:13:08 -080040 return false;
41 }
Austin Schuhf257f3c2019-10-27 21:00:43 -070042 AOS_LOG(DEBUG, "gyro dummy response is 0x%" PRIx32 "\n", result);
Brian Silverman07ec88e2014-12-28 00:13:08 -080043
44 if (!DoTransaction(0x20000000, &result)) {
Austin Schuhf257f3c2019-10-27 21:00:43 -070045 AOS_LOG(WARNING, "failed to read self-test data\n");
Brian Silverman07ec88e2014-12-28 00:13:08 -080046 return false;
47 }
48 if (ExtractStatus(result) != 2) {
Austin Schuhf257f3c2019-10-27 21:00:43 -070049 AOS_LOG(WARNING, "gyro first value 0x%" PRIx32 " not self-test data\n",
50 result);
Brian Silverman07ec88e2014-12-28 00:13:08 -080051 return false;
52 }
53 if (ExtractErrors(result) != 0x7F) {
Austin Schuhf257f3c2019-10-27 21:00:43 -070054 AOS_LOG(WARNING,
55 "gyro first value 0x%" PRIx32 " does not have all errors\n",
56 result);
Brian Silverman07ec88e2014-12-28 00:13:08 -080057 return false;
58 }
59
60 if (!DoTransaction(0x20000000, &result)) {
Austin Schuhf257f3c2019-10-27 21:00:43 -070061 AOS_LOG(WARNING, "failed to clear latched self-test data\n");
Brian Silverman07ec88e2014-12-28 00:13:08 -080062 return false;
63 }
64 if (ExtractStatus(result) != 2) {
Austin Schuhf257f3c2019-10-27 21:00:43 -070065 AOS_LOG(WARNING, "gyro second value 0x%" PRIx32 " not self-test data\n",
66 result);
Brian Silverman07ec88e2014-12-28 00:13:08 -080067 return false;
68 }
69
70 return true;
71}
72
73bool GyroInterface::DoTransaction(uint32_t to_write, uint32_t *result) {
74 static const uint8_t kBytes = 4;
75 static_assert(kBytes == sizeof(to_write),
76 "need the same number of bytes as sizeof(the data)");
77
Brian Silverman5f17a972016-02-28 01:49:32 -050078 if (__builtin_parity(to_write & ~1) == 0) {
79 to_write |= 1;
80 } else {
81 to_write &= ~1;
82 }
Brian Silverman07ec88e2014-12-28 00:13:08 -080083
84 uint8_t to_send[kBytes], to_receive[kBytes];
85 const uint32_t to_write_flipped = __builtin_bswap32(to_write);
86 memcpy(to_send, &to_write_flipped, kBytes);
87
88 switch (gyro_->Transaction(to_send, to_receive, kBytes)) {
89 case -1:
Austin Schuhf257f3c2019-10-27 21:00:43 -070090 AOS_LOG(INFO, "SPI::Transaction failed\n");
Brian Silverman07ec88e2014-12-28 00:13:08 -080091 return false;
92 case kBytes:
93 break;
94 default:
Austin Schuhf257f3c2019-10-27 21:00:43 -070095 AOS_LOG(FATAL, "SPI::Transaction returned something weird\n");
Brian Silverman07ec88e2014-12-28 00:13:08 -080096 }
97
98 memcpy(result, to_receive, kBytes);
99 if (__builtin_parity(*result & 0xFFFF) != 1) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700100 AOS_LOG(INFO, "high byte parity failure\n");
Brian Silverman07ec88e2014-12-28 00:13:08 -0800101 return false;
102 }
103 if (__builtin_parity(*result) != 1) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700104 AOS_LOG(INFO, "whole value parity failure\n");
Brian Silverman07ec88e2014-12-28 00:13:08 -0800105 return false;
106 }
107
108 *result = __builtin_bswap32(*result);
109 return true;
110}
111
112uint16_t GyroInterface::DoRead(uint8_t address) {
113 const uint32_t command = (0x8 << 28) | (address << 17);
114 uint32_t response;
115 while (true) {
116 if (!DoTransaction(command, &response)) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700117 AOS_LOG(WARNING, "reading 0x%" PRIx8 " failed\n", address);
Brian Silverman07ec88e2014-12-28 00:13:08 -0800118 continue;
119 }
120 if ((response & 0xEFE00000) != 0x4E000000) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700121 AOS_LOG(WARNING,
122 "gyro read from 0x%" PRIx8 " gave unexpected response 0x%" PRIx32
123 "\n",
124 address, response);
Brian Silverman07ec88e2014-12-28 00:13:08 -0800125 continue;
126 }
127 return (response >> 5) & 0xFFFF;
128 }
129}
130
131double GyroInterface::ExtractAngle(uint32_t value) {
Brian Silverman5f17a972016-02-28 01:49:32 -0500132 const int16_t reading = -static_cast<int16_t>(value >> 10 & 0xFFFF);
Brian Silverman07ec88e2014-12-28 00:13:08 -0800133 return static_cast<double>(reading) * 2.0 * M_PI / 360.0 / 80.0;
134}
135
136uint32_t GyroInterface::ReadPartID() {
137 return (DoRead(0x0E) << 16) | DoRead(0x10);
138}
139
140uint32_t GyroInterface::GetReading() {
141 uint32_t result;
142 if (!DoTransaction(0x20000000, &result)) {
143 return 0;
144 }
145 return result;
146}
147
Stephan Pleinesf63bde82024-01-13 15:59:33 -0800148} // namespace frc971::wpilib