blob: 1d439b23da5317bb543d086ca9ba78df9b79d870 [file] [log] [blame]
Parker Schuhd3b7a8872018-02-19 16:42:27 -08001/*----------------------------------------------------------------------------*/
Brian Silverman7be68ba2020-01-08 22:08:40 -08002/* Copyright (c) 2008-2019 FIRST. All Rights Reserved. */
Parker Schuhd3b7a8872018-02-19 16:42:27 -08003/* Open Source Software - may be modified and shared by FRC teams. The code */
4/* must be accompanied by the FIRST BSD license file in the root directory of */
5/* the project. */
6/*----------------------------------------------------------------------------*/
7
8#pragma once
9
Brian Silverman7be68ba2020-01-08 22:08:40 -080010#include <hal/SPITypes.h>
11#include <wpi/ArrayRef.h>
12#include <wpi/deprecated.h>
Parker Schuhd3b7a8872018-02-19 16:42:27 -080013
Tyler Chatowbf0609c2021-07-31 16:13:27 -070014#include <cstdint>
15#include <memory>
16
Parker Schuhd3b7a8872018-02-19 16:42:27 -080017namespace frc {
18
Brian Silverman7be68ba2020-01-08 22:08:40 -080019class DigitalSource;
Parker Schuhd3b7a8872018-02-19 16:42:27 -080020
21/**
22 * SPI bus interface class.
23 *
24 * This class is intended to be used by sensor (and other SPI device) drivers.
25 * It probably should not be used directly.
26 *
27 */
Brian Silverman7be68ba2020-01-08 22:08:40 -080028class SPI final {
Parker Schuhd3b7a8872018-02-19 16:42:27 -080029 public:
Brian Silverman7be68ba2020-01-08 22:08:40 -080030 enum Port { kOnboardCS0 = 0, kOnboardCS1, kOnboardCS2, kOnboardCS3, kMXP };
Parker Schuhd3b7a8872018-02-19 16:42:27 -080031
Brian Silverman7be68ba2020-01-08 22:08:40 -080032 /**
33 * Constructor
34 *
35 * @param port the physical SPI port
36 */
37 explicit SPI(Port port);
Parker Schuhd3b7a8872018-02-19 16:42:27 -080038
Brian Silverman7be68ba2020-01-08 22:08:40 -080039 ~SPI();
Parker Schuhd3b7a8872018-02-19 16:42:27 -080040
Tyler Chatowbf0609c2021-07-31 16:13:27 -070041 SPI(SPI &&) = default;
42 SPI &operator=(SPI &&) = default;
Brian Silverman7be68ba2020-01-08 22:08:40 -080043
44 /**
45 * Configure the rate of the generated clock signal.
46 *
47 * The default value is 500,000Hz.
48 * The maximum value is 4,000,000Hz.
49 *
50 * @param hz The clock rate in Hertz.
51 */
52 void SetClockRate(int hz);
53
54 /**
55 * Configure the order that bits are sent and received on the wire
56 * to be most significant bit first.
57 */
Parker Schuhd3b7a8872018-02-19 16:42:27 -080058 void SetMSBFirst();
Brian Silverman7be68ba2020-01-08 22:08:40 -080059
60 /**
61 * Configure the order that bits are sent and received on the wire
62 * to be least significant bit first.
63 */
Parker Schuhd3b7a8872018-02-19 16:42:27 -080064 void SetLSBFirst();
65
Brian Silverman7be68ba2020-01-08 22:08:40 -080066 /**
67 * Configure that the data is stable on the leading edge and the data
68 * changes on the trailing edge.
69 */
70 void SetSampleDataOnLeadingEdge();
71
72 /**
73 * Configure that the data is stable on the trailing edge and the data
74 * changes on the leading edge.
75 */
76 void SetSampleDataOnTrailingEdge();
77
78 /**
79 * Configure that the data is stable on the falling edge and the data
80 * changes on the rising edge.
81 */
82 WPI_DEPRECATED("Use SetSampleDataOnTrailingEdge in most cases.")
Parker Schuhd3b7a8872018-02-19 16:42:27 -080083 void SetSampleDataOnFalling();
Brian Silverman7be68ba2020-01-08 22:08:40 -080084
85 /**
86 * Configure that the data is stable on the rising edge and the data
87 * changes on the falling edge.
88 */
89 WPI_DEPRECATED("Use SetSampleDataOnLeadingEdge in most cases")
Parker Schuhd3b7a8872018-02-19 16:42:27 -080090 void SetSampleDataOnRising();
91
Brian Silverman7be68ba2020-01-08 22:08:40 -080092 /**
93 * Configure the clock output line to be active low.
94 * This is sometimes called clock polarity high or clock idle high.
95 */
Parker Schuhd3b7a8872018-02-19 16:42:27 -080096 void SetClockActiveLow();
Brian Silverman7be68ba2020-01-08 22:08:40 -080097
98 /**
99 * Configure the clock output line to be active high.
100 * This is sometimes called clock polarity low or clock idle low.
101 */
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800102 void SetClockActiveHigh();
103
Brian Silverman7be68ba2020-01-08 22:08:40 -0800104 /**
105 * Configure the chip select line to be active high.
106 */
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800107 void SetChipSelectActiveHigh();
Brian Silverman7be68ba2020-01-08 22:08:40 -0800108
109 /**
110 * Configure the chip select line to be active low.
111 */
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800112 void SetChipSelectActiveLow();
113
Brian Silverman7be68ba2020-01-08 22:08:40 -0800114 /**
115 * Write data to the slave device. Blocks until there is space in the
116 * output FIFO.
117 *
118 * If not running in output only mode, also saves the data received
119 * on the MISO input during the transfer into the receive FIFO.
120 */
Tyler Chatowbf0609c2021-07-31 16:13:27 -0700121 virtual int Write(uint8_t *data, int size);
Brian Silverman7be68ba2020-01-08 22:08:40 -0800122
123 /**
124 * Read a word from the receive FIFO.
125 *
126 * Waits for the current transfer to complete if the receive FIFO is empty.
127 *
128 * If the receive FIFO is empty, there is no active transfer, and initiate
129 * is false, errors.
130 *
131 * @param initiate If true, this function pushes "0" into the transmit buffer
132 * and initiates a transfer. If false, this function assumes
133 * that data is already in the receive FIFO from a previous
134 * write.
135 */
Tyler Chatowbf0609c2021-07-31 16:13:27 -0700136 virtual int Read(bool initiate, uint8_t *dataReceived, int size);
Brian Silverman7be68ba2020-01-08 22:08:40 -0800137
138 /**
139 * Perform a simultaneous read/write transaction with the device
140 *
141 * @param dataToSend The data to be written out to the device
142 * @param dataReceived Buffer to receive data from the device
143 * @param size The length of the transaction, in bytes
144 */
Tyler Chatowbf0609c2021-07-31 16:13:27 -0700145 virtual int Transaction(uint8_t *dataToSend, uint8_t *dataReceived, int size);
Brian Silverman7be68ba2020-01-08 22:08:40 -0800146
147 /**
148 * Initialize automatic SPI transfer engine.
149 *
150 * Only a single engine is available, and use of it blocks use of all other
151 * chip select usage on the same physical SPI port while it is running.
152 *
153 * @param bufferSize buffer size in bytes
154 */
155 void InitAuto(int bufferSize);
156
157 /**
158 * Frees the automatic SPI transfer engine.
159 */
160 void FreeAuto();
161
162 /**
163 * Set the data to be transmitted by the engine.
164 *
165 * Up to 16 bytes are configurable, and may be followed by up to 127 zero
166 * bytes.
167 *
168 * @param dataToSend data to send (maximum 16 bytes)
169 * @param zeroSize number of zeros to send after the data
170 */
171 void SetAutoTransmitData(wpi::ArrayRef<uint8_t> dataToSend, int zeroSize);
172
173 /**
174 * Start running the automatic SPI transfer engine at a periodic rate.
175 *
176 * InitAuto() and SetAutoTransmitData() must be called before calling this
177 * function.
178 *
179 * @param period period between transfers, in seconds (us resolution)
180 */
181 void StartAutoRate(double period);
182
183 /**
184 * Start running the automatic SPI transfer engine when a trigger occurs.
185 *
186 * InitAuto() and SetAutoTransmitData() must be called before calling this
187 * function.
188 *
189 * @param source digital source for the trigger (may be an analog trigger)
190 * @param rising trigger on the rising edge
191 * @param falling trigger on the falling edge
192 */
Tyler Chatowbf0609c2021-07-31 16:13:27 -0700193 void StartAutoTrigger(DigitalSource &source, bool rising, bool falling);
Brian Silverman7be68ba2020-01-08 22:08:40 -0800194
195 /**
196 * Stop running the automatic SPI transfer engine.
197 */
198 void StopAuto();
199
200 /**
201 * Force the engine to make a single transfer.
202 */
203 void ForceAutoRead();
204
205 /**
206 * Read data that has been transferred by the automatic SPI transfer engine.
207 *
208 * Transfers may be made a byte at a time, so it's necessary for the caller
209 * to handle cases where an entire transfer has not been completed.
210 *
211 * Each received data sequence consists of a timestamp followed by the
212 * received data bytes, one byte per word (in the least significant byte).
213 * The length of each received data sequence is the same as the combined
214 * size of the data and zeroSize set in SetAutoTransmitData().
215 *
216 * Blocks until numToRead words have been read or timeout expires.
217 * May be called with numToRead=0 to retrieve how many words are available.
218 *
219 * @param buffer buffer where read words are stored
220 * @param numToRead number of words to read
221 * @param timeout timeout in seconds (ms resolution)
222 * @return Number of words remaining to be read
223 */
Tyler Chatowbf0609c2021-07-31 16:13:27 -0700224 int ReadAutoReceivedData(uint32_t *buffer, int numToRead, double timeout);
Brian Silverman7be68ba2020-01-08 22:08:40 -0800225
226 /**
227 * Get the number of bytes dropped by the automatic SPI transfer engine due
228 * to the receive buffer being full.
229 *
230 * @return Number of bytes dropped
231 */
232 int GetAutoDroppedCount();
233
234 /**
235 * Configure the Auto SPI Stall time between reads.
236 *
237 * @param port The number of the port to use. 0-3 for Onboard CS0-CS2, 4 for
238 * MXP.
239 * @param csToSclkTicks the number of ticks to wait before asserting the cs
240 * pin
241 * @param stallTicks the number of ticks to stall for
242 * @param pow2BytesPerRead the number of bytes to read before stalling
243 */
James Kuszmaul47d07032020-01-18 17:58:49 -0800244 void ConfigureAutoStall(int csToSclkTicks, int stallTicks,
Brian Silverman7be68ba2020-01-08 22:08:40 -0800245 int pow2BytesPerRead);
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800246
247 protected:
Brian Silverman7be68ba2020-01-08 22:08:40 -0800248 hal::SPIPort m_port;
249 bool m_msbFirst = false; // Default little-endian
250 bool m_sampleOnTrailing = false; // Default data updated on falling edge
251 bool m_clockIdleHigh = false; // Default clock active high
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800252
253 private:
254 void Init();
255};
256
257} // namespace frc