blob: 9b7bb8b140c0a9dd552475f4b4dcd4cf0358680a [file] [log] [blame]
Brian Silverman07ec88e2014-12-28 00:13:08 -08001#include "frc971/wpilib/gyro_interface.h"
2
3#include <inttypes.h>
Austin Schuhf2a50ba2016-12-24 16:16:26 -08004#include <chrono>
Brian Silverman07ec88e2014-12-28 00:13:08 -08005
6#include "aos/common/logging/logging.h"
7#include "aos/common/time.h"
8
9#ifndef M_PI
10#define M_PI 3.14159265358979323846
11#endif
12
13namespace frc971 {
14namespace wpilib {
15
16GyroInterface::GyroInterface() : gyro_(new SPI(SPI::kOnboardCS0)) {
17 // The gyro goes up to 8.08MHz.
18 // The myRIO goes up to 4MHz, so the roboRIO probably does too.
19 gyro_->SetClockRate(4e6);
20 gyro_->SetChipSelectActiveLow();
21 gyro_->SetClockActiveHigh();
22 gyro_->SetSampleDataOnRising();
23 gyro_->SetMSBFirst();
24}
25
26bool GyroInterface::InitializeGyro() {
27 uint32_t result;
28 if (!DoTransaction(0x20000003, &result)) {
29 LOG(WARNING, "failed to start a self-check\n");
30 return false;
31 }
32 if (result != 1) {
33 // We might have hit a parity error or something and are now retrying, so
34 // this isn't a very big deal.
35 LOG(INFO, "gyro unexpected initial response 0x%" PRIx32 "\n", result);
36 }
37
38 // Wait for it to assert the fault conditions before reading them.
Austin Schuhf2a50ba2016-12-24 16:16:26 -080039 ::std::this_thread::sleep_for(::std::chrono::milliseconds(50));
Brian Silverman07ec88e2014-12-28 00:13:08 -080040
41 if (!DoTransaction(0x20000000, &result)) {
42 LOG(WARNING, "failed to clear latched non-fault data\n");
43 return false;
44 }
45 LOG(DEBUG, "gyro dummy response is 0x%" PRIx32 "\n", result);
46
47 if (!DoTransaction(0x20000000, &result)) {
48 LOG(WARNING, "failed to read self-test data\n");
49 return false;
50 }
51 if (ExtractStatus(result) != 2) {
52 LOG(WARNING, "gyro first value 0x%" PRIx32 " not self-test data\n", result);
53 return false;
54 }
55 if (ExtractErrors(result) != 0x7F) {
56 LOG(WARNING, "gyro first value 0x%" PRIx32 " does not have all errors\n",
57 result);
58 return false;
59 }
60
61 if (!DoTransaction(0x20000000, &result)) {
62 LOG(WARNING, "failed to clear latched self-test data\n");
63 return false;
64 }
65 if (ExtractStatus(result) != 2) {
66 LOG(WARNING, "gyro second value 0x%" PRIx32 " not self-test data\n",
67 result);
68 return false;
69 }
70
71 return true;
72}
73
74bool GyroInterface::DoTransaction(uint32_t to_write, uint32_t *result) {
75 static const uint8_t kBytes = 4;
76 static_assert(kBytes == sizeof(to_write),
77 "need the same number of bytes as sizeof(the data)");
78
Brian Silverman5f17a972016-02-28 01:49:32 -050079 if (__builtin_parity(to_write & ~1) == 0) {
80 to_write |= 1;
81 } else {
82 to_write &= ~1;
83 }
Brian Silverman07ec88e2014-12-28 00:13:08 -080084
85 uint8_t to_send[kBytes], to_receive[kBytes];
86 const uint32_t to_write_flipped = __builtin_bswap32(to_write);
87 memcpy(to_send, &to_write_flipped, kBytes);
88
89 switch (gyro_->Transaction(to_send, to_receive, kBytes)) {
90 case -1:
91 LOG(INFO, "SPI::Transaction failed\n");
92 return false;
93 case kBytes:
94 break;
95 default:
96 LOG(FATAL, "SPI::Transaction returned something weird\n");
97 }
98
99 memcpy(result, to_receive, kBytes);
100 if (__builtin_parity(*result & 0xFFFF) != 1) {
101 LOG(INFO, "high byte parity failure\n");
102 return false;
103 }
104 if (__builtin_parity(*result) != 1) {
105 LOG(INFO, "whole value parity failure\n");
106 return false;
107 }
108
109 *result = __builtin_bswap32(*result);
110 return true;
111}
112
113uint16_t GyroInterface::DoRead(uint8_t address) {
114 const uint32_t command = (0x8 << 28) | (address << 17);
115 uint32_t response;
116 while (true) {
117 if (!DoTransaction(command, &response)) {
118 LOG(WARNING, "reading 0x%" PRIx8 " failed\n", address);
119 continue;
120 }
121 if ((response & 0xEFE00000) != 0x4E000000) {
122 LOG(WARNING, "gyro read from 0x%" PRIx8
123 " gave unexpected response 0x%" PRIx32 "\n",
124 address, response);
125 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
148} // namespace wpilib
149} // namespace frc971