blob: 6151ded8c7bc0b05302938af9b4f8de8279f0dde [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>
Parker Schuhd3b7a8872018-02-19 16:42:27 -080011
Tyler Chatowbf0609c2021-07-31 16:13:27 -070012#include <cstdint>
13#include <memory>
James Kuszmaul9776b392023-01-14 14:08:08 -080014#include <span>
15
16#include "absl/types/span.h"
Philipp Schrader790cb542023-07-05 21:06:52 -070017#include <wpi/deprecated.h>
Tyler Chatowbf0609c2021-07-31 16:13:27 -070018
Parker Schuhd3b7a8872018-02-19 16:42:27 -080019namespace frc {
20
Brian Silverman7be68ba2020-01-08 22:08:40 -080021class DigitalSource;
Parker Schuhd3b7a8872018-02-19 16:42:27 -080022
23/**
24 * SPI bus interface class.
25 *
26 * This class is intended to be used by sensor (and other SPI device) drivers.
27 * It probably should not be used directly.
28 *
29 */
Brian Silverman7be68ba2020-01-08 22:08:40 -080030class SPI final {
Parker Schuhd3b7a8872018-02-19 16:42:27 -080031 public:
Brian Silverman7be68ba2020-01-08 22:08:40 -080032 enum Port { kOnboardCS0 = 0, kOnboardCS1, kOnboardCS2, kOnboardCS3, kMXP };
James Kuszmaul9776b392023-01-14 14:08:08 -080033 enum Mode {
34 kMode0 = HAL_SPI_kMode0,
35 kMode1 = HAL_SPI_kMode1,
36 kMode2 = HAL_SPI_kMode2,
37 kMode3 = HAL_SPI_kMode3
38 };
Parker Schuhd3b7a8872018-02-19 16:42:27 -080039
Brian Silverman7be68ba2020-01-08 22:08:40 -080040 /**
41 * Constructor
42 *
43 * @param port the physical SPI port
44 */
45 explicit SPI(Port port);
Parker Schuhd3b7a8872018-02-19 16:42:27 -080046
Brian Silverman7be68ba2020-01-08 22:08:40 -080047 ~SPI();
Parker Schuhd3b7a8872018-02-19 16:42:27 -080048
Tyler Chatowbf0609c2021-07-31 16:13:27 -070049 SPI(SPI &&) = default;
50 SPI &operator=(SPI &&) = default;
Brian Silverman7be68ba2020-01-08 22:08:40 -080051
52 /**
53 * Configure the rate of the generated clock signal.
54 *
55 * The default value is 500,000Hz.
56 * The maximum value is 4,000,000Hz.
57 *
58 * @param hz The clock rate in Hertz.
59 */
60 void SetClockRate(int hz);
61
62 /**
63 * Configure the order that bits are sent and received on the wire
64 * to be most significant bit first.
James Kuszmaul9776b392023-01-14 14:08:08 -080065 *
66 * @deprecated Does not work, will be removed.
Brian Silverman7be68ba2020-01-08 22:08:40 -080067 */
James Kuszmaul9776b392023-01-14 14:08:08 -080068 WPI_DEPRECATED("Not supported by roboRIO.")
Parker Schuhd3b7a8872018-02-19 16:42:27 -080069 void SetMSBFirst();
Brian Silverman7be68ba2020-01-08 22:08:40 -080070
71 /**
72 * Configure the order that bits are sent and received on the wire
73 * to be least significant bit first.
James Kuszmaul9776b392023-01-14 14:08:08 -080074 *
75 * @deprecated Does not work, will be removed.
Brian Silverman7be68ba2020-01-08 22:08:40 -080076 */
James Kuszmaul9776b392023-01-14 14:08:08 -080077 WPI_DEPRECATED("Not supported by roboRIO.")
Parker Schuhd3b7a8872018-02-19 16:42:27 -080078 void SetLSBFirst();
79
Brian Silverman7be68ba2020-01-08 22:08:40 -080080 /**
81 * Configure that the data is stable on the leading edge and the data
82 * changes on the trailing edge.
James Kuszmaul9776b392023-01-14 14:08:08 -080083 *
84 * @deprecated Use SetMode() instead.
Brian Silverman7be68ba2020-01-08 22:08:40 -080085 */
James Kuszmaul9776b392023-01-14 14:08:08 -080086 WPI_DEPRECATED("Use SetMode() instead")
Brian Silverman7be68ba2020-01-08 22:08:40 -080087 void SetSampleDataOnLeadingEdge();
88
89 /**
90 * Configure that the data is stable on the trailing edge and the data
91 * changes on the leading edge.
James Kuszmaul9776b392023-01-14 14:08:08 -080092 *
93 * @deprecated Use SetMode() instead.
Brian Silverman7be68ba2020-01-08 22:08:40 -080094 */
James Kuszmaul9776b392023-01-14 14:08:08 -080095 WPI_DEPRECATED("Use SetMode() instead")
Brian Silverman7be68ba2020-01-08 22:08:40 -080096 void SetSampleDataOnTrailingEdge();
97
98 /**
Brian Silverman7be68ba2020-01-08 22:08:40 -080099 * Configure the clock output line to be active low.
100 * This is sometimes called clock polarity high or clock idle high.
James Kuszmaul9776b392023-01-14 14:08:08 -0800101 *
102 * @deprecated Use SetMode() instead.
Brian Silverman7be68ba2020-01-08 22:08:40 -0800103 */
James Kuszmaul9776b392023-01-14 14:08:08 -0800104 WPI_DEPRECATED("Use SetMode() instead")
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800105 void SetClockActiveLow();
Brian Silverman7be68ba2020-01-08 22:08:40 -0800106
107 /**
108 * Configure the clock output line to be active high.
109 * This is sometimes called clock polarity low or clock idle low.
James Kuszmaul9776b392023-01-14 14:08:08 -0800110 *
111 * @deprecated Use SetMode() instead.
Brian Silverman7be68ba2020-01-08 22:08:40 -0800112 */
James Kuszmaul9776b392023-01-14 14:08:08 -0800113 WPI_DEPRECATED("Use SetMode() instead")
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800114 void SetClockActiveHigh();
115
Brian Silverman7be68ba2020-01-08 22:08:40 -0800116 /**
James Kuszmaul9776b392023-01-14 14:08:08 -0800117 * Sets the mode for the SPI device.
118 *
119 * <p>Mode 0 is Clock idle low, data sampled on rising edge
120 *
121 * <p>Mode 1 is Clock idle low, data sampled on falling edge
122 *
123 * <p>Mode 2 is Clock idle high, data sampled on falling edge
124 *
125 * <p>Mode 3 is Clock idle high, data sampled on rising edge
126 *
127 * @param mode The mode to set.
128 */
129 void SetMode(Mode mode);
130
131 /**
Brian Silverman7be68ba2020-01-08 22:08:40 -0800132 * Configure the chip select line to be active high.
133 */
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800134 void SetChipSelectActiveHigh();
Brian Silverman7be68ba2020-01-08 22:08:40 -0800135
136 /**
137 * Configure the chip select line to be active low.
138 */
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800139 void SetChipSelectActiveLow();
140
Brian Silverman7be68ba2020-01-08 22:08:40 -0800141 /**
142 * Write data to the slave device. Blocks until there is space in the
143 * output FIFO.
144 *
145 * If not running in output only mode, also saves the data received
146 * on the MISO input during the transfer into the receive FIFO.
147 */
Tyler Chatowbf0609c2021-07-31 16:13:27 -0700148 virtual int Write(uint8_t *data, int size);
Brian Silverman7be68ba2020-01-08 22:08:40 -0800149
150 /**
151 * Read a word from the receive FIFO.
152 *
153 * Waits for the current transfer to complete if the receive FIFO is empty.
154 *
155 * If the receive FIFO is empty, there is no active transfer, and initiate
156 * is false, errors.
157 *
158 * @param initiate If true, this function pushes "0" into the transmit buffer
159 * and initiates a transfer. If false, this function assumes
160 * that data is already in the receive FIFO from a previous
161 * write.
162 */
Tyler Chatowbf0609c2021-07-31 16:13:27 -0700163 virtual int Read(bool initiate, uint8_t *dataReceived, int size);
Brian Silverman7be68ba2020-01-08 22:08:40 -0800164
165 /**
166 * Perform a simultaneous read/write transaction with the device
167 *
168 * @param dataToSend The data to be written out to the device
169 * @param dataReceived Buffer to receive data from the device
170 * @param size The length of the transaction, in bytes
171 */
Tyler Chatowbf0609c2021-07-31 16:13:27 -0700172 virtual int Transaction(uint8_t *dataToSend, uint8_t *dataReceived, int size);
Brian Silverman7be68ba2020-01-08 22:08:40 -0800173
174 /**
175 * Initialize automatic SPI transfer engine.
176 *
177 * Only a single engine is available, and use of it blocks use of all other
178 * chip select usage on the same physical SPI port while it is running.
179 *
180 * @param bufferSize buffer size in bytes
181 */
182 void InitAuto(int bufferSize);
183
184 /**
185 * Frees the automatic SPI transfer engine.
186 */
187 void FreeAuto();
188
189 /**
190 * Set the data to be transmitted by the engine.
191 *
192 * Up to 16 bytes are configurable, and may be followed by up to 127 zero
193 * bytes.
194 *
195 * @param dataToSend data to send (maximum 16 bytes)
196 * @param zeroSize number of zeros to send after the data
197 */
Austin Schuh9950f682021-11-06 15:27:58 -0700198 void SetAutoTransmitData(absl::Span<const uint8_t> dataToSend, int zeroSize);
Brian Silverman7be68ba2020-01-08 22:08:40 -0800199
200 /**
201 * Start running the automatic SPI transfer engine at a periodic rate.
202 *
203 * InitAuto() and SetAutoTransmitData() must be called before calling this
204 * function.
205 *
206 * @param period period between transfers, in seconds (us resolution)
207 */
208 void StartAutoRate(double period);
209
210 /**
211 * Start running the automatic SPI transfer engine when a trigger occurs.
212 *
213 * InitAuto() and SetAutoTransmitData() must be called before calling this
214 * function.
215 *
216 * @param source digital source for the trigger (may be an analog trigger)
217 * @param rising trigger on the rising edge
218 * @param falling trigger on the falling edge
219 */
Tyler Chatowbf0609c2021-07-31 16:13:27 -0700220 void StartAutoTrigger(DigitalSource &source, bool rising, bool falling);
Brian Silverman7be68ba2020-01-08 22:08:40 -0800221
222 /**
223 * Stop running the automatic SPI transfer engine.
224 */
225 void StopAuto();
226
227 /**
228 * Force the engine to make a single transfer.
229 */
230 void ForceAutoRead();
231
232 /**
233 * Read data that has been transferred by the automatic SPI transfer engine.
234 *
235 * Transfers may be made a byte at a time, so it's necessary for the caller
236 * to handle cases where an entire transfer has not been completed.
237 *
238 * Each received data sequence consists of a timestamp followed by the
239 * received data bytes, one byte per word (in the least significant byte).
240 * The length of each received data sequence is the same as the combined
241 * size of the data and zeroSize set in SetAutoTransmitData().
242 *
243 * Blocks until numToRead words have been read or timeout expires.
244 * May be called with numToRead=0 to retrieve how many words are available.
245 *
246 * @param buffer buffer where read words are stored
247 * @param numToRead number of words to read
248 * @param timeout timeout in seconds (ms resolution)
249 * @return Number of words remaining to be read
250 */
Tyler Chatowbf0609c2021-07-31 16:13:27 -0700251 int ReadAutoReceivedData(uint32_t *buffer, int numToRead, double timeout);
Brian Silverman7be68ba2020-01-08 22:08:40 -0800252
253 /**
254 * Get the number of bytes dropped by the automatic SPI transfer engine due
255 * to the receive buffer being full.
256 *
257 * @return Number of bytes dropped
258 */
259 int GetAutoDroppedCount();
260
261 /**
262 * Configure the Auto SPI Stall time between reads.
263 *
264 * @param port The number of the port to use. 0-3 for Onboard CS0-CS2, 4 for
265 * MXP.
266 * @param csToSclkTicks the number of ticks to wait before asserting the cs
267 * pin
268 * @param stallTicks the number of ticks to stall for
269 * @param pow2BytesPerRead the number of bytes to read before stalling
270 */
James Kuszmaul47d07032020-01-18 17:58:49 -0800271 void ConfigureAutoStall(int csToSclkTicks, int stallTicks,
Brian Silverman7be68ba2020-01-08 22:08:40 -0800272 int pow2BytesPerRead);
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800273
274 protected:
Brian Silverman7be68ba2020-01-08 22:08:40 -0800275 hal::SPIPort m_port;
James Kuszmaul9776b392023-01-14 14:08:08 -0800276 HAL_SPIMode m_mode = HAL_SPIMode::HAL_SPI_kMode0;
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800277
278 private:
279 void Init();
280};
281
282} // namespace frc