2013-12-15 18:30:16 -05:00
|
|
|
/*----------------------------------------------------------------------------*/
|
2018-01-02 09:20:21 -08:00
|
|
|
/* Copyright (c) 2008-2018 FIRST. All Rights Reserved. */
|
2013-12-15 18:30:16 -05:00
|
|
|
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
2016-01-02 03:02:34 -08:00
|
|
|
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
|
|
|
|
/* the project. */
|
2013-12-15 18:30:16 -05:00
|
|
|
/*----------------------------------------------------------------------------*/
|
2016-01-02 03:02:34 -08:00
|
|
|
|
2014-05-02 17:54:01 -04:00
|
|
|
#pragma once
|
2013-12-15 18:30:16 -05:00
|
|
|
|
2017-06-25 09:05:49 -07:00
|
|
|
#include <stdint.h>
|
|
|
|
|
|
2017-12-13 23:41:37 -08:00
|
|
|
#include <memory>
|
|
|
|
|
|
2018-04-29 23:33:19 -07:00
|
|
|
#include <wpi/ArrayRef.h>
|
2018-05-14 18:16:36 -07:00
|
|
|
#include <wpi/deprecated.h>
|
2017-12-13 23:41:37 -08:00
|
|
|
|
2017-12-04 23:28:33 -08:00
|
|
|
#include "ErrorBase.h"
|
2013-12-15 18:30:16 -05:00
|
|
|
|
2017-05-09 12:12:46 -07:00
|
|
|
enum HAL_SPIPort : int32_t;
|
|
|
|
|
|
2016-11-01 22:33:12 -07:00
|
|
|
namespace frc {
|
|
|
|
|
|
2017-12-13 23:41:37 -08:00
|
|
|
class DigitalSource;
|
|
|
|
|
|
2013-12-15 18:30:16 -05:00
|
|
|
/**
|
|
|
|
|
* SPI bus interface class.
|
|
|
|
|
*
|
|
|
|
|
* This class is intended to be used by sensor (and other SPI device) drivers.
|
|
|
|
|
* It probably should not be used directly.
|
|
|
|
|
*
|
|
|
|
|
*/
|
2017-12-04 23:28:33 -08:00
|
|
|
class SPI : public ErrorBase {
|
2015-06-25 15:07:55 -04:00
|
|
|
public:
|
2017-05-09 12:12:46 -07:00
|
|
|
enum Port { kOnboardCS0 = 0, kOnboardCS1, kOnboardCS2, kOnboardCS3, kMXP };
|
2017-11-16 00:33:51 -08:00
|
|
|
|
2018-05-31 20:47:15 -07:00
|
|
|
/**
|
|
|
|
|
* Constructor
|
|
|
|
|
*
|
|
|
|
|
* @param port the physical SPI port
|
|
|
|
|
*/
|
2017-05-09 12:12:46 -07:00
|
|
|
explicit SPI(Port port);
|
2018-05-31 20:47:15 -07:00
|
|
|
|
2017-12-04 23:28:33 -08:00
|
|
|
~SPI() override;
|
2013-12-15 18:30:16 -05:00
|
|
|
|
2015-07-21 01:23:34 -07:00
|
|
|
SPI(const SPI&) = delete;
|
|
|
|
|
SPI& operator=(const SPI&) = delete;
|
|
|
|
|
|
2018-05-31 20:47:15 -07:00
|
|
|
/**
|
|
|
|
|
* Configure the rate of the generated clock signal.
|
|
|
|
|
*
|
|
|
|
|
* The default value is 500,000Hz.
|
|
|
|
|
* The maximum value is 4,000,000Hz.
|
|
|
|
|
*
|
|
|
|
|
* @param hz The clock rate in Hertz.
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
void SetClockRate(double hz);
|
2013-12-15 18:30:16 -05:00
|
|
|
|
2018-05-31 20:47:15 -07:00
|
|
|
/**
|
|
|
|
|
* Configure the order that bits are sent and received on the wire
|
|
|
|
|
* to be most significant bit first.
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
void SetMSBFirst();
|
2018-05-31 20:47:15 -07:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Configure the order that bits are sent and received on the wire
|
|
|
|
|
* to be least significant bit first.
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
void SetLSBFirst();
|
2013-12-15 18:30:16 -05:00
|
|
|
|
2018-05-31 20:47:15 -07:00
|
|
|
/**
|
|
|
|
|
* Configure that the data is stable on the leading edge and the data
|
|
|
|
|
* changes on the trailing edge.
|
|
|
|
|
*/
|
2018-05-14 18:16:36 -07:00
|
|
|
void SetSampleDataOnLeadingEdge();
|
2018-05-31 20:47:15 -07:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Configure that the data is stable on the trailing edge and the data
|
|
|
|
|
* changes on the leading edge.
|
|
|
|
|
*/
|
2018-05-14 18:16:36 -07:00
|
|
|
void SetSampleDataOnTrailingEdge();
|
|
|
|
|
|
2018-05-31 20:47:15 -07:00
|
|
|
/**
|
|
|
|
|
* Configure that the data is stable on the falling edge and the data
|
|
|
|
|
* changes on the rising edge.
|
|
|
|
|
*/
|
2018-05-14 18:16:36 -07:00
|
|
|
WPI_DEPRECATED("Use SetSampleDataOnTrailingEdge in most cases.")
|
2015-06-25 15:07:55 -04:00
|
|
|
void SetSampleDataOnFalling();
|
2018-05-31 20:47:15 -07:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Configure that the data is stable on the rising edge and the data
|
|
|
|
|
* changes on the falling edge.
|
|
|
|
|
*/
|
2018-05-14 18:16:36 -07:00
|
|
|
WPI_DEPRECATED("Use SetSampleDataOnLeadingEdge in most cases")
|
2015-06-25 15:07:55 -04:00
|
|
|
void SetSampleDataOnRising();
|
2013-12-15 18:30:16 -05:00
|
|
|
|
2018-05-31 20:47:15 -07:00
|
|
|
/**
|
|
|
|
|
* Configure the clock output line to be active low.
|
|
|
|
|
* This is sometimes called clock polarity high or clock idle high.
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
void SetClockActiveLow();
|
2018-05-31 20:47:15 -07:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Configure the clock output line to be active high.
|
|
|
|
|
* This is sometimes called clock polarity low or clock idle low.
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
void SetClockActiveHigh();
|
2013-12-15 18:30:16 -05:00
|
|
|
|
2018-05-31 20:47:15 -07:00
|
|
|
/**
|
|
|
|
|
* Configure the chip select line to be active high.
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
void SetChipSelectActiveHigh();
|
2018-05-31 20:47:15 -07:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Configure the chip select line to be active low.
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
void SetChipSelectActiveLow();
|
2013-12-15 18:30:16 -05:00
|
|
|
|
2018-05-31 20:47:15 -07:00
|
|
|
/**
|
|
|
|
|
* Write data to the slave device. Blocks until there is space in the
|
|
|
|
|
* output FIFO.
|
|
|
|
|
*
|
|
|
|
|
* If not running in output only mode, also saves the data received
|
|
|
|
|
* on the MISO input during the transfer into the receive FIFO.
|
|
|
|
|
*/
|
2016-09-06 00:01:45 -07:00
|
|
|
virtual int Write(uint8_t* data, int size);
|
2018-05-31 20:47:15 -07:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Read a word from the receive FIFO.
|
|
|
|
|
*
|
|
|
|
|
* Waits for the current transfer to complete if the receive FIFO is empty.
|
|
|
|
|
*
|
|
|
|
|
* If the receive FIFO is empty, there is no active transfer, and initiate
|
|
|
|
|
* is false, errors.
|
|
|
|
|
*
|
|
|
|
|
* @param initiate If true, this function pushes "0" into the transmit buffer
|
|
|
|
|
* and initiates a transfer. If false, this function assumes
|
|
|
|
|
* that data is already in the receive FIFO from a previous
|
|
|
|
|
* write.
|
|
|
|
|
*/
|
2016-09-06 00:01:45 -07:00
|
|
|
virtual int Read(bool initiate, uint8_t* dataReceived, int size);
|
2018-05-31 20:47:15 -07:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Perform a simultaneous read/write transaction with the device
|
|
|
|
|
*
|
|
|
|
|
* @param dataToSend The data to be written out to the device
|
|
|
|
|
* @param dataReceived Buffer to receive data from the device
|
|
|
|
|
* @param size The length of the transaction, in bytes
|
|
|
|
|
*/
|
2016-09-06 00:01:45 -07:00
|
|
|
virtual int Transaction(uint8_t* dataToSend, uint8_t* dataReceived, int size);
|
2013-12-15 18:30:16 -05:00
|
|
|
|
2018-05-31 20:47:15 -07:00
|
|
|
/**
|
|
|
|
|
* Initialize automatic SPI transfer engine.
|
|
|
|
|
*
|
|
|
|
|
* Only a single engine is available, and use of it blocks use of all other
|
|
|
|
|
* chip select usage on the same physical SPI port while it is running.
|
|
|
|
|
*
|
|
|
|
|
* @param bufferSize buffer size in bytes
|
|
|
|
|
*/
|
2017-12-13 23:41:37 -08:00
|
|
|
void InitAuto(int bufferSize);
|
2018-05-31 20:47:15 -07:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Frees the automatic SPI transfer engine.
|
|
|
|
|
*/
|
2017-12-13 23:41:37 -08:00
|
|
|
void FreeAuto();
|
2018-05-31 20:47:15 -07:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Set the data to be transmitted by the engine.
|
|
|
|
|
*
|
|
|
|
|
* Up to 16 bytes are configurable, and may be followed by up to 127 zero
|
|
|
|
|
* bytes.
|
|
|
|
|
*
|
|
|
|
|
* @param dataToSend data to send (maximum 16 bytes)
|
|
|
|
|
* @param zeroSize number of zeros to send after the data
|
|
|
|
|
*/
|
2018-04-29 23:33:19 -07:00
|
|
|
void SetAutoTransmitData(wpi::ArrayRef<uint8_t> dataToSend, int zeroSize);
|
2018-05-31 20:47:15 -07:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Start running the automatic SPI transfer engine at a periodic rate.
|
|
|
|
|
*
|
|
|
|
|
* InitAuto() and SetAutoTransmitData() must be called before calling this
|
|
|
|
|
* function.
|
|
|
|
|
*
|
|
|
|
|
* @param period period between transfers, in seconds (us resolution)
|
|
|
|
|
*/
|
2017-12-13 23:41:37 -08:00
|
|
|
void StartAutoRate(double period);
|
2018-05-31 20:47:15 -07:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Start running the automatic SPI transfer engine when a trigger occurs.
|
|
|
|
|
*
|
|
|
|
|
* InitAuto() and SetAutoTransmitData() must be called before calling this
|
|
|
|
|
* function.
|
|
|
|
|
*
|
|
|
|
|
* @param source digital source for the trigger (may be an analog trigger)
|
|
|
|
|
* @param rising trigger on the rising edge
|
|
|
|
|
* @param falling trigger on the falling edge
|
|
|
|
|
*/
|
2017-12-13 23:41:37 -08:00
|
|
|
void StartAutoTrigger(DigitalSource& source, bool rising, bool falling);
|
2018-05-31 20:47:15 -07:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Stop running the automatic SPI transfer engine.
|
|
|
|
|
*/
|
2017-12-13 23:41:37 -08:00
|
|
|
void StopAuto();
|
2018-05-31 20:47:15 -07:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Force the engine to make a single transfer.
|
|
|
|
|
*/
|
2017-12-13 23:41:37 -08:00
|
|
|
void ForceAutoRead();
|
2018-05-31 20:47:15 -07:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Read data that has been transferred by the automatic SPI transfer engine.
|
|
|
|
|
*
|
|
|
|
|
* Transfers may be made a byte at a time, so it's necessary for the caller
|
|
|
|
|
* to handle cases where an entire transfer has not been completed.
|
|
|
|
|
*
|
|
|
|
|
* Blocks until numToRead bytes have been read or timeout expires.
|
|
|
|
|
* May be called with numToRead=0 to retrieve how many bytes are available.
|
|
|
|
|
*
|
|
|
|
|
* @param buffer buffer where read bytes are stored
|
|
|
|
|
* @param numToRead number of bytes to read
|
|
|
|
|
* @param timeout timeout in seconds (ms resolution)
|
|
|
|
|
* @return Number of bytes remaining to be read
|
|
|
|
|
*/
|
2017-12-13 23:41:37 -08:00
|
|
|
int ReadAutoReceivedData(uint8_t* buffer, int numToRead, double timeout);
|
2018-05-31 20:47:15 -07:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get the number of bytes dropped by the automatic SPI transfer engine due
|
|
|
|
|
* to the receive buffer being full.
|
|
|
|
|
*
|
|
|
|
|
* @return Number of bytes dropped
|
|
|
|
|
*/
|
2017-12-13 23:41:37 -08:00
|
|
|
int GetAutoDroppedCount();
|
|
|
|
|
|
2018-05-31 20:47:15 -07:00
|
|
|
/**
|
|
|
|
|
* Initialize the accumulator.
|
|
|
|
|
*
|
|
|
|
|
* @param period Time between reads
|
|
|
|
|
* @param cmd SPI command to send to request data
|
|
|
|
|
* @param xferSize SPI transfer size, in bytes
|
|
|
|
|
* @param validMask Mask to apply to received data for validity checking
|
|
|
|
|
* @param validData After valid_mask is applied, required matching value for
|
|
|
|
|
* validity checking
|
|
|
|
|
* @param dataShift Bit shift to apply to received data to get actual data
|
|
|
|
|
* value
|
|
|
|
|
* @param dataSize Size (in bits) of data field
|
|
|
|
|
* @param isSigned Is data field signed?
|
|
|
|
|
* @param bigEndian Is device big endian?
|
|
|
|
|
*/
|
2017-11-22 17:06:57 -08:00
|
|
|
void InitAccumulator(double period, int cmd, int xferSize, int validMask,
|
|
|
|
|
int validValue, int dataShift, int dataSize,
|
|
|
|
|
bool isSigned, bool bigEndian);
|
2018-05-31 20:47:15 -07:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Frees the accumulator.
|
|
|
|
|
*/
|
2015-11-22 11:50:49 -08:00
|
|
|
void FreeAccumulator();
|
2018-05-31 20:47:15 -07:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Resets the accumulator to zero.
|
|
|
|
|
*/
|
2015-11-22 11:50:49 -08:00
|
|
|
void ResetAccumulator();
|
2018-05-31 20:47:15 -07:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Set the center value of the accumulator.
|
|
|
|
|
*
|
|
|
|
|
* The center value is subtracted from each value before it is added to the
|
|
|
|
|
* accumulator. This is used for the center value of devices like gyros and
|
|
|
|
|
* accelerometers to make integration work and to take the device offset into
|
|
|
|
|
* account when integrating.
|
|
|
|
|
*/
|
2016-09-06 00:01:45 -07:00
|
|
|
void SetAccumulatorCenter(int center);
|
2018-05-31 20:47:15 -07:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Set the accumulator's deadband.
|
|
|
|
|
*/
|
2016-09-06 00:01:45 -07:00
|
|
|
void SetAccumulatorDeadband(int deadband);
|
2018-05-31 20:47:15 -07:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Read the last value read by the accumulator engine.
|
|
|
|
|
*/
|
2016-09-06 00:01:45 -07:00
|
|
|
int GetAccumulatorLastValue() const;
|
2018-05-31 20:47:15 -07:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Read the accumulated value.
|
|
|
|
|
*
|
|
|
|
|
* @return The 64-bit value accumulated since the last Reset().
|
|
|
|
|
*/
|
2015-11-22 11:50:49 -08:00
|
|
|
int64_t GetAccumulatorValue() const;
|
2018-05-31 20:47:15 -07:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Read the number of accumulated values.
|
|
|
|
|
*
|
|
|
|
|
* Read the count of the accumulated values since the accumulator was last
|
|
|
|
|
* Reset().
|
|
|
|
|
*
|
|
|
|
|
* @return The number of times samples from the channel were accumulated.
|
|
|
|
|
*/
|
2016-07-12 10:45:14 -07:00
|
|
|
int64_t GetAccumulatorCount() const;
|
2018-05-31 20:47:15 -07:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Read the average of the accumulated value.
|
|
|
|
|
*
|
|
|
|
|
* @return The accumulated average value (value / count).
|
|
|
|
|
*/
|
2015-11-22 11:50:49 -08:00
|
|
|
double GetAccumulatorAverage() const;
|
2018-05-31 20:47:15 -07:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Read the accumulated value and the number of accumulated values atomically.
|
|
|
|
|
*
|
|
|
|
|
* This function reads the value and count atomically.
|
|
|
|
|
* This can be used for averaging.
|
|
|
|
|
*
|
|
|
|
|
* @param value Pointer to the 64-bit accumulated output.
|
|
|
|
|
* @param count Pointer to the number of accumulation cycles.
|
|
|
|
|
*/
|
2016-07-12 10:45:14 -07:00
|
|
|
void GetAccumulatorOutput(int64_t& value, int64_t& count) const;
|
2015-11-22 11:50:49 -08:00
|
|
|
|
2015-06-25 15:07:55 -04:00
|
|
|
protected:
|
2017-05-09 12:12:46 -07:00
|
|
|
HAL_SPIPort m_port;
|
2017-11-16 00:33:51 -08:00
|
|
|
bool m_msbFirst = false; // Default little-endian
|
|
|
|
|
bool m_sampleOnTrailing = false; // Default data updated on falling edge
|
|
|
|
|
bool m_clk_idle_high = false; // Default clock active high
|
2013-12-15 18:30:16 -05:00
|
|
|
|
2015-06-25 15:07:55 -04:00
|
|
|
private:
|
|
|
|
|
void Init();
|
2017-12-13 23:41:37 -08:00
|
|
|
|
|
|
|
|
class Accumulator;
|
|
|
|
|
std::unique_ptr<Accumulator> m_accum;
|
2013-12-15 18:30:16 -05:00
|
|
|
};
|
2016-11-01 22:33:12 -07:00
|
|
|
|
|
|
|
|
} // namespace frc
|