| #include "frc971/wpilib/gyro_interface.h" |
| |
| #include <inttypes.h> |
| #include <chrono> |
| |
| #include "aos/logging/logging.h" |
| #include "aos/time/time.h" |
| |
| #ifndef M_PI |
| #define M_PI 3.14159265358979323846 |
| #endif |
| |
| namespace frc971 { |
| namespace wpilib { |
| |
| GyroInterface::GyroInterface() : gyro_(new frc::SPI(frc::SPI::kOnboardCS0)) { |
| // The gyro goes up to 8.08MHz. |
| // The myRIO goes up to 4MHz, so the roboRIO probably does too. |
| gyro_->SetClockRate(4e6); |
| gyro_->SetChipSelectActiveLow(); |
| gyro_->SetClockActiveHigh(); |
| gyro_->SetSampleDataOnRising(); |
| gyro_->SetMSBFirst(); |
| } |
| |
| bool GyroInterface::InitializeGyro() { |
| uint32_t result; |
| if (!DoTransaction(0x20000003, &result)) { |
| AOS_LOG(WARNING, "failed to start a self-check\n"); |
| return false; |
| } |
| if (result != 1) { |
| // We might have hit a parity error or something and are now retrying, so |
| // this isn't a very big deal. |
| AOS_LOG(INFO, "gyro unexpected initial response 0x%" PRIx32 "\n", result); |
| } |
| |
| // Wait for it to assert the fault conditions before reading them. |
| ::std::this_thread::sleep_for(::std::chrono::milliseconds(50)); |
| |
| if (!DoTransaction(0x20000000, &result)) { |
| AOS_LOG(WARNING, "failed to clear latched non-fault data\n"); |
| return false; |
| } |
| AOS_LOG(DEBUG, "gyro dummy response is 0x%" PRIx32 "\n", result); |
| |
| if (!DoTransaction(0x20000000, &result)) { |
| AOS_LOG(WARNING, "failed to read self-test data\n"); |
| return false; |
| } |
| if (ExtractStatus(result) != 2) { |
| AOS_LOG(WARNING, "gyro first value 0x%" PRIx32 " not self-test data\n", |
| result); |
| return false; |
| } |
| if (ExtractErrors(result) != 0x7F) { |
| AOS_LOG(WARNING, |
| "gyro first value 0x%" PRIx32 " does not have all errors\n", |
| result); |
| return false; |
| } |
| |
| if (!DoTransaction(0x20000000, &result)) { |
| AOS_LOG(WARNING, "failed to clear latched self-test data\n"); |
| return false; |
| } |
| if (ExtractStatus(result) != 2) { |
| AOS_LOG(WARNING, "gyro second value 0x%" PRIx32 " not self-test data\n", |
| result); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| bool GyroInterface::DoTransaction(uint32_t to_write, uint32_t *result) { |
| static const uint8_t kBytes = 4; |
| static_assert(kBytes == sizeof(to_write), |
| "need the same number of bytes as sizeof(the data)"); |
| |
| if (__builtin_parity(to_write & ~1) == 0) { |
| to_write |= 1; |
| } else { |
| to_write &= ~1; |
| } |
| |
| uint8_t to_send[kBytes], to_receive[kBytes]; |
| const uint32_t to_write_flipped = __builtin_bswap32(to_write); |
| memcpy(to_send, &to_write_flipped, kBytes); |
| |
| switch (gyro_->Transaction(to_send, to_receive, kBytes)) { |
| case -1: |
| AOS_LOG(INFO, "SPI::Transaction failed\n"); |
| return false; |
| case kBytes: |
| break; |
| default: |
| AOS_LOG(FATAL, "SPI::Transaction returned something weird\n"); |
| } |
| |
| memcpy(result, to_receive, kBytes); |
| if (__builtin_parity(*result & 0xFFFF) != 1) { |
| AOS_LOG(INFO, "high byte parity failure\n"); |
| return false; |
| } |
| if (__builtin_parity(*result) != 1) { |
| AOS_LOG(INFO, "whole value parity failure\n"); |
| return false; |
| } |
| |
| *result = __builtin_bswap32(*result); |
| return true; |
| } |
| |
| uint16_t GyroInterface::DoRead(uint8_t address) { |
| const uint32_t command = (0x8 << 28) | (address << 17); |
| uint32_t response; |
| while (true) { |
| if (!DoTransaction(command, &response)) { |
| AOS_LOG(WARNING, "reading 0x%" PRIx8 " failed\n", address); |
| continue; |
| } |
| if ((response & 0xEFE00000) != 0x4E000000) { |
| AOS_LOG(WARNING, |
| "gyro read from 0x%" PRIx8 " gave unexpected response 0x%" PRIx32 |
| "\n", |
| address, response); |
| continue; |
| } |
| return (response >> 5) & 0xFFFF; |
| } |
| } |
| |
| double GyroInterface::ExtractAngle(uint32_t value) { |
| const int16_t reading = -static_cast<int16_t>(value >> 10 & 0xFFFF); |
| return static_cast<double>(reading) * 2.0 * M_PI / 360.0 / 80.0; |
| } |
| |
| uint32_t GyroInterface::ReadPartID() { |
| return (DoRead(0x0E) << 16) | DoRead(0x10); |
| } |
| |
| uint32_t GyroInterface::GetReading() { |
| uint32_t result; |
| if (!DoTransaction(0x20000000, &result)) { |
| return 0; |
| } |
| return result; |
| } |
| |
| } // namespace wpilib |
| } // namespace frc971 |