blob: 6b3ab4079994c658bec5698663f0bfa99b61086a [file] [log] [blame]
Brian Silverman07ec88e2014-12-28 00:13:08 -08001#include "frc971/wpilib/gyro_interface.h"
2
3#include <inttypes.h>
4
5#include "aos/common/logging/logging.h"
6#include "aos/common/time.h"
7
8#ifndef M_PI
9#define M_PI 3.14159265358979323846
10#endif
11
12namespace frc971 {
13namespace wpilib {
14
15GyroInterface::GyroInterface() : gyro_(new SPI(SPI::kOnboardCS0)) {
16 // 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();
20 gyro_->SetClockActiveHigh();
21 gyro_->SetSampleDataOnRising();
22 gyro_->SetMSBFirst();
23}
24
25bool GyroInterface::InitializeGyro() {
26 uint32_t result;
27 if (!DoTransaction(0x20000003, &result)) {
28 LOG(WARNING, "failed to start a self-check\n");
29 return false;
30 }
31 if (result != 1) {
32 // We might have hit a parity error or something and are now retrying, so
33 // this isn't a very big deal.
34 LOG(INFO, "gyro unexpected initial response 0x%" PRIx32 "\n", result);
35 }
36
37 // Wait for it to assert the fault conditions before reading them.
38 ::aos::time::SleepFor(::aos::time::Time::InMS(50));
39
40 if (!DoTransaction(0x20000000, &result)) {
41 LOG(WARNING, "failed to clear latched non-fault data\n");
42 return false;
43 }
44 LOG(DEBUG, "gyro dummy response is 0x%" PRIx32 "\n", result);
45
46 if (!DoTransaction(0x20000000, &result)) {
47 LOG(WARNING, "failed to read self-test data\n");
48 return false;
49 }
50 if (ExtractStatus(result) != 2) {
51 LOG(WARNING, "gyro first value 0x%" PRIx32 " not self-test data\n", result);
52 return false;
53 }
54 if (ExtractErrors(result) != 0x7F) {
55 LOG(WARNING, "gyro first value 0x%" PRIx32 " does not have all errors\n",
56 result);
57 return false;
58 }
59
60 if (!DoTransaction(0x20000000, &result)) {
61 LOG(WARNING, "failed to clear latched self-test data\n");
62 return false;
63 }
64 if (ExtractStatus(result) != 2) {
65 LOG(WARNING, "gyro second value 0x%" PRIx32 " not self-test data\n",
66 result);
67 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:
90 LOG(INFO, "SPI::Transaction failed\n");
91 return false;
92 case kBytes:
93 break;
94 default:
95 LOG(FATAL, "SPI::Transaction returned something weird\n");
96 }
97
98 memcpy(result, to_receive, kBytes);
99 if (__builtin_parity(*result & 0xFFFF) != 1) {
100 LOG(INFO, "high byte parity failure\n");
101 return false;
102 }
103 if (__builtin_parity(*result) != 1) {
104 LOG(INFO, "whole value parity failure\n");
105 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)) {
117 LOG(WARNING, "reading 0x%" PRIx8 " failed\n", address);
118 continue;
119 }
120 if ((response & 0xEFE00000) != 0x4E000000) {
121 LOG(WARNING, "gyro read from 0x%" PRIx8
122 " gave unexpected response 0x%" PRIx32 "\n",
123 address, response);
124 continue;
125 }
126 return (response >> 5) & 0xFFFF;
127 }
128}
129
130double GyroInterface::ExtractAngle(uint32_t value) {
Brian Silverman5f17a972016-02-28 01:49:32 -0500131 const int16_t reading = -static_cast<int16_t>(value >> 10 & 0xFFFF);
Brian Silverman07ec88e2014-12-28 00:13:08 -0800132 return static_cast<double>(reading) * 2.0 * M_PI / 360.0 / 80.0;
133}
134
135uint32_t GyroInterface::ReadPartID() {
136 return (DoRead(0x0E) << 16) | DoRead(0x10);
137}
138
139uint32_t GyroInterface::GetReading() {
140 uint32_t result;
141 if (!DoTransaction(0x20000000, &result)) {
142 return 0;
143 }
144 return result;
145}
146
147} // namespace wpilib
148} // namespace frc971