blob: 64215354d4131228731e2a2977b6ae131b1281a6 [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>
Brian Silverman7be68ba2020-01-08 22:08:40 -080011#include <wpi/deprecated.h>
Austin Schuh9950f682021-11-06 15:27:58 -070012#include <wpi/span.h>
13#include "absl/types/span.h"
Parker Schuhd3b7a8872018-02-19 16:42:27 -080014
Tyler Chatowbf0609c2021-07-31 16:13:27 -070015#include <cstdint>
16#include <memory>
17
Parker Schuhd3b7a8872018-02-19 16:42:27 -080018namespace frc {
19
Brian Silverman7be68ba2020-01-08 22:08:40 -080020class DigitalSource;
Parker Schuhd3b7a8872018-02-19 16:42:27 -080021
22/**
23 * SPI bus interface class.
24 *
25 * This class is intended to be used by sensor (and other SPI device) drivers.
26 * It probably should not be used directly.
27 *
28 */
Brian Silverman7be68ba2020-01-08 22:08:40 -080029class SPI final {
Parker Schuhd3b7a8872018-02-19 16:42:27 -080030 public:
Brian Silverman7be68ba2020-01-08 22:08:40 -080031 enum Port { kOnboardCS0 = 0, kOnboardCS1, kOnboardCS2, kOnboardCS3, kMXP };
Parker Schuhd3b7a8872018-02-19 16:42:27 -080032
Brian Silverman7be68ba2020-01-08 22:08:40 -080033 /**
34 * Constructor
35 *
36 * @param port the physical SPI port
37 */
38 explicit SPI(Port port);
Parker Schuhd3b7a8872018-02-19 16:42:27 -080039
Brian Silverman7be68ba2020-01-08 22:08:40 -080040 ~SPI();
Parker Schuhd3b7a8872018-02-19 16:42:27 -080041
Tyler Chatowbf0609c2021-07-31 16:13:27 -070042 SPI(SPI &&) = default;
43 SPI &operator=(SPI &&) = default;
Brian Silverman7be68ba2020-01-08 22:08:40 -080044
45 /**
46 * Configure the rate of the generated clock signal.
47 *
48 * The default value is 500,000Hz.
49 * The maximum value is 4,000,000Hz.
50 *
51 * @param hz The clock rate in Hertz.
52 */
53 void SetClockRate(int hz);
54
55 /**
56 * Configure the order that bits are sent and received on the wire
57 * to be most significant bit first.
58 */
Parker Schuhd3b7a8872018-02-19 16:42:27 -080059 void SetMSBFirst();
Brian Silverman7be68ba2020-01-08 22:08:40 -080060
61 /**
62 * Configure the order that bits are sent and received on the wire
63 * to be least significant bit first.
64 */
Parker Schuhd3b7a8872018-02-19 16:42:27 -080065 void SetLSBFirst();
66
Brian Silverman7be68ba2020-01-08 22:08:40 -080067 /**
68 * Configure that the data is stable on the leading edge and the data
69 * changes on the trailing edge.
70 */
71 void SetSampleDataOnLeadingEdge();
72
73 /**
74 * Configure that the data is stable on the trailing edge and the data
75 * changes on the leading edge.
76 */
77 void SetSampleDataOnTrailingEdge();
78
79 /**
80 * Configure that the data is stable on the falling edge and the data
81 * changes on the rising edge.
82 */
83 WPI_DEPRECATED("Use SetSampleDataOnTrailingEdge in most cases.")
Parker Schuhd3b7a8872018-02-19 16:42:27 -080084 void SetSampleDataOnFalling();
Brian Silverman7be68ba2020-01-08 22:08:40 -080085
86 /**
87 * Configure that the data is stable on the rising edge and the data
88 * changes on the falling edge.
89 */
90 WPI_DEPRECATED("Use SetSampleDataOnLeadingEdge in most cases")
Parker Schuhd3b7a8872018-02-19 16:42:27 -080091 void SetSampleDataOnRising();
92
Brian Silverman7be68ba2020-01-08 22:08:40 -080093 /**
94 * Configure the clock output line to be active low.
95 * This is sometimes called clock polarity high or clock idle high.
96 */
Parker Schuhd3b7a8872018-02-19 16:42:27 -080097 void SetClockActiveLow();
Brian Silverman7be68ba2020-01-08 22:08:40 -080098
99 /**
100 * Configure the clock output line to be active high.
101 * This is sometimes called clock polarity low or clock idle low.
102 */
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800103 void SetClockActiveHigh();
104
Brian Silverman7be68ba2020-01-08 22:08:40 -0800105 /**
106 * Configure the chip select line to be active high.
107 */
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800108 void SetChipSelectActiveHigh();
Brian Silverman7be68ba2020-01-08 22:08:40 -0800109
110 /**
111 * Configure the chip select line to be active low.
112 */
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800113 void SetChipSelectActiveLow();
114
Brian Silverman7be68ba2020-01-08 22:08:40 -0800115 /**
116 * Write data to the slave device. Blocks until there is space in the
117 * output FIFO.
118 *
119 * If not running in output only mode, also saves the data received
120 * on the MISO input during the transfer into the receive FIFO.
121 */
Tyler Chatowbf0609c2021-07-31 16:13:27 -0700122 virtual int Write(uint8_t *data, int size);
Brian Silverman7be68ba2020-01-08 22:08:40 -0800123
124 /**
125 * Read a word from the receive FIFO.
126 *
127 * Waits for the current transfer to complete if the receive FIFO is empty.
128 *
129 * If the receive FIFO is empty, there is no active transfer, and initiate
130 * is false, errors.
131 *
132 * @param initiate If true, this function pushes "0" into the transmit buffer
133 * and initiates a transfer. If false, this function assumes
134 * that data is already in the receive FIFO from a previous
135 * write.
136 */
Tyler Chatowbf0609c2021-07-31 16:13:27 -0700137 virtual int Read(bool initiate, uint8_t *dataReceived, int size);
Brian Silverman7be68ba2020-01-08 22:08:40 -0800138
139 /**
140 * Perform a simultaneous read/write transaction with the device
141 *
142 * @param dataToSend The data to be written out to the device
143 * @param dataReceived Buffer to receive data from the device
144 * @param size The length of the transaction, in bytes
145 */
Tyler Chatowbf0609c2021-07-31 16:13:27 -0700146 virtual int Transaction(uint8_t *dataToSend, uint8_t *dataReceived, int size);
Brian Silverman7be68ba2020-01-08 22:08:40 -0800147
148 /**
149 * Initialize automatic SPI transfer engine.
150 *
151 * Only a single engine is available, and use of it blocks use of all other
152 * chip select usage on the same physical SPI port while it is running.
153 *
154 * @param bufferSize buffer size in bytes
155 */
156 void InitAuto(int bufferSize);
157
158 /**
159 * Frees the automatic SPI transfer engine.
160 */
161 void FreeAuto();
162
163 /**
164 * Set the data to be transmitted by the engine.
165 *
166 * Up to 16 bytes are configurable, and may be followed by up to 127 zero
167 * bytes.
168 *
169 * @param dataToSend data to send (maximum 16 bytes)
170 * @param zeroSize number of zeros to send after the data
171 */
Austin Schuh9950f682021-11-06 15:27:58 -0700172 void SetAutoTransmitData(absl::Span<const uint8_t> dataToSend, int zeroSize);
Brian Silverman7be68ba2020-01-08 22:08:40 -0800173
174 /**
175 * Start running the automatic SPI transfer engine at a periodic rate.
176 *
177 * InitAuto() and SetAutoTransmitData() must be called before calling this
178 * function.
179 *
180 * @param period period between transfers, in seconds (us resolution)
181 */
182 void StartAutoRate(double period);
183
184 /**
185 * Start running the automatic SPI transfer engine when a trigger occurs.
186 *
187 * InitAuto() and SetAutoTransmitData() must be called before calling this
188 * function.
189 *
190 * @param source digital source for the trigger (may be an analog trigger)
191 * @param rising trigger on the rising edge
192 * @param falling trigger on the falling edge
193 */
Tyler Chatowbf0609c2021-07-31 16:13:27 -0700194 void StartAutoTrigger(DigitalSource &source, bool rising, bool falling);
Brian Silverman7be68ba2020-01-08 22:08:40 -0800195
196 /**
197 * Stop running the automatic SPI transfer engine.
198 */
199 void StopAuto();
200
201 /**
202 * Force the engine to make a single transfer.
203 */
204 void ForceAutoRead();
205
206 /**
207 * Read data that has been transferred by the automatic SPI transfer engine.
208 *
209 * Transfers may be made a byte at a time, so it's necessary for the caller
210 * to handle cases where an entire transfer has not been completed.
211 *
212 * Each received data sequence consists of a timestamp followed by the
213 * received data bytes, one byte per word (in the least significant byte).
214 * The length of each received data sequence is the same as the combined
215 * size of the data and zeroSize set in SetAutoTransmitData().
216 *
217 * Blocks until numToRead words have been read or timeout expires.
218 * May be called with numToRead=0 to retrieve how many words are available.
219 *
220 * @param buffer buffer where read words are stored
221 * @param numToRead number of words to read
222 * @param timeout timeout in seconds (ms resolution)
223 * @return Number of words remaining to be read
224 */
Tyler Chatowbf0609c2021-07-31 16:13:27 -0700225 int ReadAutoReceivedData(uint32_t *buffer, int numToRead, double timeout);
Brian Silverman7be68ba2020-01-08 22:08:40 -0800226
227 /**
228 * Get the number of bytes dropped by the automatic SPI transfer engine due
229 * to the receive buffer being full.
230 *
231 * @return Number of bytes dropped
232 */
233 int GetAutoDroppedCount();
234
235 /**
236 * Configure the Auto SPI Stall time between reads.
237 *
238 * @param port The number of the port to use. 0-3 for Onboard CS0-CS2, 4 for
239 * MXP.
240 * @param csToSclkTicks the number of ticks to wait before asserting the cs
241 * pin
242 * @param stallTicks the number of ticks to stall for
243 * @param pow2BytesPerRead the number of bytes to read before stalling
244 */
James Kuszmaul47d07032020-01-18 17:58:49 -0800245 void ConfigureAutoStall(int csToSclkTicks, int stallTicks,
Brian Silverman7be68ba2020-01-08 22:08:40 -0800246 int pow2BytesPerRead);
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800247
248 protected:
Brian Silverman7be68ba2020-01-08 22:08:40 -0800249 hal::SPIPort m_port;
250 bool m_msbFirst = false; // Default little-endian
251 bool m_sampleOnTrailing = false; // Default data updated on falling edge
252 bool m_clockIdleHigh = false; // Default clock active high
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800253
254 private:
255 void Init();
256};
257
258} // namespace frc