blob: 35bcb06570c31e3bd09cf2eadb03bfc1f4ef2acb [file] [log] [blame]
Brian Silverman7be68ba2020-01-08 22:08:40 -08001#ifndef FRC971_WPILIB_ADIS16470_H_
2#define FRC971_WPILIB_ADIS16470_H_
3
4#include "absl/types/span.h"
5
6#include "aos/events/event_loop.h"
7#include "frc971/wpilib/ahal/DigitalInput.h"
8#include "frc971/wpilib/ahal/DigitalOutput.h"
9#include "frc971/wpilib/ahal/DigitalSource.h"
10#include "frc971/wpilib/ahal/SPI.h"
11#include "frc971/wpilib/fpga_time_conversion.h"
Austin Schuhac17fba2020-03-28 15:55:33 -070012#include "frc971/wpilib/imu_batch_generated.h"
Brian Silverman7be68ba2020-01-08 22:08:40 -080013#include "frc971/wpilib/imu_generated.h"
14
15namespace frc971 {
16namespace wpilib {
17
18// Handles interfacing with an Analog Devices ADIS16470 over SPI and sending the
19// resulting values out on a channel.
20//
21// This relies on the AutoRead functionality in the FPGA to read values when
22// data is ready. It then allows the FPGA to buffer those until right before the
23// relevant control loops run, at which point they are all sent out on the
24// relevant channel.
25class ADIS16470 {
26 public:
27 // event_loop's thread will be hijacked before processing any events.
28 // spi is how to talk to the sensor over SPI.
29 // data_ready is the Data Ready (DR) pin (J6).
30 // reset is the Reset (RST) pin (F3).
31 ADIS16470(aos::EventLoop *event_loop, frc::SPI *spi,
32 frc::DigitalInput *data_ready, frc::DigitalOutput *reset);
33
34 ADIS16470(const ADIS16470 &) = delete;
35 ADIS16470 &operator=(const ADIS16470 &) = delete;
36
37 // Reads all the queued-up data and sends out any complete readings.
38 void DoReads();
39
40 private:
41 enum class State {
42 kUninitialized,
43 kWaitForReset,
44 kRunning,
45 };
46
47 // Performs one (non-blocking) initialization step.
48 void DoInitializeStep();
49
50 // Processes a complete reading in read_data_.
Austin Schuhac17fba2020-03-28 15:55:33 -070051 flatbuffers::Offset<IMUValues> ProcessReading(
52 flatbuffers::FlatBufferBuilder *fbb);
Brian Silverman7be68ba2020-01-08 22:08:40 -080053
54 // Converts a 32-bit value at data to a scaled output value where a value of 1
55 // corresponds to lsb_per_output.
56 static double ConvertValue32(absl::Span<const uint32_t> data,
57 double lsb_per_output);
58 static double ConvertValue16(absl::Span<const uint32_t> data,
59 double lsb_per_output);
60
61 static flatbuffers::Offset<ADIS16470DiagStat> PackDiagStat(
62 flatbuffers::FlatBufferBuilder *fbb, uint16_t value);
63
64 static bool DiagStatHasError(const ADIS16470DiagStat &diag_stat);
65
66 // These may only be called during configuration, when spi_ is not in
67 // automatic mode.
68 uint16_t ReadRegister(uint8_t register_address,
69 uint8_t next_register_address);
70 void WriteRegister(uint8_t register_address, uint16_t value);
71
72 void BeginInitialization() {
73 state_ = State::kUninitialized;
Philipp Schradera6712522023-07-05 20:25:11 -070074 initialize_timer_->Schedule(event_loop_->monotonic_now() +
75 std::chrono::milliseconds(25));
Brian Silverman7be68ba2020-01-08 22:08:40 -080076 }
77
78 aos::EventLoop *const event_loop_;
Austin Schuhac17fba2020-03-28 15:55:33 -070079 aos::Sender<::frc971::IMUValuesBatch> imu_values_sender_;
Brian Silverman7be68ba2020-01-08 22:08:40 -080080 aos::TimerHandler *const initialize_timer_;
81
82 frc::SPI *const spi_;
83 frc::DigitalInput *const data_ready_;
84 frc::DigitalOutput *const reset_;
85
86 State state_ = State::kUninitialized;
87
88 // Data we've read from the FPGA.
89 std::array<uint32_t, 23> read_data_;
90 // Data that we need to read from the FPGA to get a complete reading.
91 absl::Span<uint32_t> to_read_;
92
93 FpgaTimeConverter time_converter_;
94};
95
96} // namespace wpilib
97} // namespace frc971
98
99#endif // FRC971_WPILIB_ADIS16470_H_