From 17f504f5481a2e1a665d3283f0c1d8ae4566e332 Mon Sep 17 00:00:00 2001 From: Thad House Date: Sat, 24 Sep 2022 00:11:37 -0700 Subject: [PATCH] [hal,wpilib] Fix SPI Mode Setting (#4434) SPI Mode setting was very broken. MSB and LSB sets did not work (MSB is the only one supported) and if LSB was set (which was the default) the ioct to set clock phase would fail. This deprecates all the individual functions, the LSB/MSB functions, and adds an SPI mode selection function. This is usually more understandable, and shows up in a lot more documentation --- .../main/java/edu/wpi/first/hal/SPIJNI.java | 17 +++- hal/src/main/native/athena/SPI.cpp | 22 +++-- hal/src/main/native/cpp/jni/SPIJNI.cpp | 46 ++++++++-- hal/src/main/native/include/hal/SPI.h | 26 +++--- hal/src/main/native/include/hal/SPITypes.h | 9 ++ hal/src/main/native/sim/SPI.cpp | 6 +- wpilibc/src/main/native/cpp/ADIS16448_IMU.cpp | 4 +- wpilibc/src/main/native/cpp/ADIS16470_IMU.cpp | 4 +- wpilibc/src/main/native/cpp/ADXL345_SPI.cpp | 4 +- wpilibc/src/main/native/cpp/ADXL362.cpp | 4 +- wpilibc/src/main/native/cpp/ADXRS450_Gyro.cpp | 4 +- wpilibc/src/main/native/cpp/SPI.cpp | 38 +++++--- wpilibc/src/main/native/include/frc/SPI.h | 44 ++++++++- .../edu/wpi/first/wpilibj/ADIS16448_IMU.java | 4 +- .../edu/wpi/first/wpilibj/ADIS16470_IMU.java | 4 +- .../edu/wpi/first/wpilibj/ADXL345_SPI.java | 4 +- .../java/edu/wpi/first/wpilibj/ADXL362.java | 4 +- .../edu/wpi/first/wpilibj/ADXRS450_Gyro.java | 4 +- .../main/java/edu/wpi/first/wpilibj/SPI.java | 90 ++++++++++++++----- 19 files changed, 243 insertions(+), 95 deletions(-) diff --git a/hal/src/main/java/edu/wpi/first/hal/SPIJNI.java b/hal/src/main/java/edu/wpi/first/hal/SPIJNI.java index 05ac08af9b..0652c3fa4a 100644 --- a/hal/src/main/java/edu/wpi/first/hal/SPIJNI.java +++ b/hal/src/main/java/edu/wpi/first/hal/SPIJNI.java @@ -8,6 +8,18 @@ import java.nio.ByteBuffer; @SuppressWarnings("AbbreviationAsWordInName") public class SPIJNI extends JNIWrapper { + public static final int INVALID_PORT = -1; + public static final int ONBOARD_CS0_PORT = 0; + public static final int ONBOARD_CS1_PORT = 1; + public static final int ONBOARD_CS2_PORT = 2; + public static final int ONBOARD_CS3_PORT = 3; + public static final int MXP_PORT = 4; + + public static final int SPI_MODE0 = 0; + public static final int SPI_MODE1 = 1; + public static final int SPI_MODE2 = 2; + public static final int SPI_MODE3 = 3; + public static native void spiInitialize(int port); public static native int spiTransaction( @@ -28,8 +40,9 @@ public class SPIJNI extends JNIWrapper { public static native void spiSetSpeed(int port, int speed); - public static native void spiSetOpts( - int port, int msbFirst, int sampleOnTrailing, int clkIdleHigh); + public static native void spiSetMode(int port, int mode); + + public static native int spiGetMode(int port); public static native void spiSetChipSelectActiveHigh(int port); diff --git a/hal/src/main/native/athena/SPI.cpp b/hal/src/main/native/athena/SPI.cpp index 0df6fdb824..e2f5f98e49 100644 --- a/hal/src/main/native/athena/SPI.cpp +++ b/hal/src/main/native/athena/SPI.cpp @@ -364,19 +364,27 @@ void HAL_SetSPISpeed(HAL_SPIPort port, int32_t speed) { ioctl(HAL_GetSPIHandle(port), SPI_IOC_WR_MAX_SPEED_HZ, &speed); } -void HAL_SetSPIOpts(HAL_SPIPort port, HAL_Bool msbFirst, - HAL_Bool sampleOnTrailing, HAL_Bool clkIdleHigh) { +void HAL_SetSPIMode(HAL_SPIPort port, HAL_SPIMode mode) { if (port < 0 || port >= kSpiMaxHandles) { return; } - uint8_t mode = 0; - mode |= (!msbFirst ? 8 : 0); - mode |= (clkIdleHigh ? 2 : 0); - mode |= (sampleOnTrailing ? 1 : 0); + uint8_t mode8 = mode & SPI_MODE_3; std::scoped_lock lock(spiApiMutexes[port]); - ioctl(HAL_GetSPIHandle(port), SPI_IOC_WR_MODE, &mode); + ioctl(HAL_GetSPIHandle(port), SPI_IOC_WR_MODE, &mode8); +} + +HAL_SPIMode HAL_GetSPIMode(HAL_SPIPort port) { + if (port < 0 || port >= kSpiMaxHandles) { + return HAL_SPI_kMode0; + } + + uint8_t mode8 = 0; + + std::scoped_lock lock(spiApiMutexes[port]); + ioctl(HAL_GetSPIHandle(port), SPI_IOC_RD_MODE, &mode8); + return static_cast(mode8 & SPI_MODE_3); } void HAL_SetSPIChipSelectActiveHigh(HAL_SPIPort port, int32_t* status) { diff --git a/hal/src/main/native/cpp/jni/SPIJNI.cpp b/hal/src/main/native/cpp/jni/SPIJNI.cpp index 3c9143bbb4..4f1e5568ef 100644 --- a/hal/src/main/native/cpp/jni/SPIJNI.cpp +++ b/hal/src/main/native/cpp/jni/SPIJNI.cpp @@ -15,6 +15,27 @@ using namespace hal; using namespace wpi::java; +static_assert(HAL_SPIPort::HAL_SPI_kInvalid == + edu_wpi_first_hal_SPIJNI_INVALID_PORT); +static_assert(HAL_SPIPort::HAL_SPI_kOnboardCS0 == + edu_wpi_first_hal_SPIJNI_ONBOARD_CS0_PORT); +static_assert(HAL_SPIPort::HAL_SPI_kOnboardCS1 == + edu_wpi_first_hal_SPIJNI_ONBOARD_CS1_PORT); +static_assert(HAL_SPIPort::HAL_SPI_kOnboardCS2 == + edu_wpi_first_hal_SPIJNI_ONBOARD_CS2_PORT); +static_assert(HAL_SPIPort::HAL_SPI_kOnboardCS3 == + edu_wpi_first_hal_SPIJNI_ONBOARD_CS3_PORT); +static_assert(HAL_SPIPort::HAL_SPI_kMXP == edu_wpi_first_hal_SPIJNI_MXP_PORT); + +static_assert(HAL_SPIMode::HAL_SPI_kMode0 == + edu_wpi_first_hal_SPIJNI_SPI_MODE0); +static_assert(HAL_SPIMode::HAL_SPI_kMode1 == + edu_wpi_first_hal_SPIJNI_SPI_MODE1); +static_assert(HAL_SPIMode::HAL_SPI_kMode2 == + edu_wpi_first_hal_SPIJNI_SPI_MODE2); +static_assert(HAL_SPIMode::HAL_SPI_kMode3 == + edu_wpi_first_hal_SPIJNI_SPI_MODE3); + extern "C" { /* @@ -202,16 +223,27 @@ Java_edu_wpi_first_hal_SPIJNI_spiSetSpeed /* * Class: edu_wpi_first_hal_SPIJNI - * Method: spiSetOpts - * Signature: (IIII)V + * Method: spiSetMode + * Signature: (II)V */ JNIEXPORT void JNICALL -Java_edu_wpi_first_hal_SPIJNI_spiSetOpts - (JNIEnv*, jclass, jint port, jint msb_first, jint sample_on_trailing, - jint clk_idle_high) +Java_edu_wpi_first_hal_SPIJNI_spiSetMode + (JNIEnv*, jclass, jint port, jint mode) { - HAL_SetSPIOpts(static_cast(port), msb_first, sample_on_trailing, - clk_idle_high); + HAL_SetSPIMode(static_cast(port), + static_cast(mode)); +} + +/* + * Class: edu_wpi_first_hal_SPIJNI + * Method: spiGetMode + * Signature: (I)I + */ +JNIEXPORT jint JNICALL +Java_edu_wpi_first_hal_SPIJNI_spiGetMode + (JNIEnv*, jclass, jint port) +{ + return static_cast(HAL_GetSPIMode(static_cast(port))); } /* diff --git a/hal/src/main/native/include/hal/SPI.h b/hal/src/main/native/include/hal/SPI.h index 84cec5ddb9..f3c7fdca09 100644 --- a/hal/src/main/native/include/hal/SPI.h +++ b/hal/src/main/native/include/hal/SPI.h @@ -90,23 +90,27 @@ void HAL_CloseSPI(HAL_SPIPort port); * * @param port The number of the port to use. 0-3 for Onboard CS0-CS2, 4 for * MXP - * @param speed The speed in Hz (0-1MHz) + * @param speed The speed in Hz (500KHz-10MHz) */ void HAL_SetSPISpeed(HAL_SPIPort port, int32_t speed); /** - * Sets the SPI options. + * Sets the SPI Mode. * - * @param port The number of the port to use. 0-3 for Onboard - * CS0-CS2, 4 for MXP - * @param msbFirst True to write the MSB first, False for LSB first - * @param sampleOnTrailing True to sample on the trailing edge, False to sample - * on the leading edge - * @param clkIdleHigh True to set the clock to active low, False to set the - * clock active high + * @param port The number of the port to use. 0-3 for Onboard CS0-CS2, 4 for + * MXP + * @param mode The SPI mode to use */ -void HAL_SetSPIOpts(HAL_SPIPort port, HAL_Bool msbFirst, - HAL_Bool sampleOnTrailing, HAL_Bool clkIdleHigh); +void HAL_SetSPIMode(HAL_SPIPort port, HAL_SPIMode mode); + +/** + * Gets the SPI Mode. + * + * @param port The number of the port to use. 0-3 for Onboard CS0-CS2, 4 for + * MXP + * @returns The SPI mode currently set + */ +HAL_SPIMode HAL_GetSPIMode(HAL_SPIPort port); /** * Sets the CS Active high for a SPI port. diff --git a/hal/src/main/native/include/hal/SPITypes.h b/hal/src/main/native/include/hal/SPITypes.h index de6622682e..34b5d618d6 100644 --- a/hal/src/main/native/include/hal/SPITypes.h +++ b/hal/src/main/native/include/hal/SPITypes.h @@ -25,6 +25,15 @@ HAL_ENUM(HAL_SPIPort) { }; // clang-format on +// clang-format off +HAL_ENUM(HAL_SPIMode) { + HAL_SPI_kMode0 = 0, + HAL_SPI_kMode1 = 1, + HAL_SPI_kMode2 = 2, + HAL_SPI_kMode3 = 3, +}; +// clang-format on + #ifdef __cplusplus namespace hal { diff --git a/hal/src/main/native/sim/SPI.cpp b/hal/src/main/native/sim/SPI.cpp index bf362a80bd..70e2bde1dd 100644 --- a/hal/src/main/native/sim/SPI.cpp +++ b/hal/src/main/native/sim/SPI.cpp @@ -34,8 +34,10 @@ void HAL_CloseSPI(HAL_SPIPort port) { SimSPIData[port].initialized = false; } void HAL_SetSPISpeed(HAL_SPIPort port, int32_t speed) {} -void HAL_SetSPIOpts(HAL_SPIPort port, HAL_Bool msbFirst, - HAL_Bool sampleOnTrailing, HAL_Bool clkIdleHigh) {} +void HAL_SetSPIMode(HAL_SPIPort port, HAL_SPIMode mode) {} +HAL_SPIMode HAL_GetSPIMode(HAL_SPIPort port) { + return HAL_SPI_kMode0; +} void HAL_SetSPIChipSelectActiveHigh(HAL_SPIPort port, int32_t* status) {} void HAL_SetSPIChipSelectActiveLow(HAL_SPIPort port, int32_t* status) {} int32_t HAL_GetSPIHandle(HAL_SPIPort port) { diff --git a/wpilibc/src/main/native/cpp/ADIS16448_IMU.cpp b/wpilibc/src/main/native/cpp/ADIS16448_IMU.cpp index eb31386746..72d0630549 100644 --- a/wpilibc/src/main/native/cpp/ADIS16448_IMU.cpp +++ b/wpilibc/src/main/native/cpp/ADIS16448_IMU.cpp @@ -197,9 +197,7 @@ bool ADIS16448_IMU::SwitchToStandardSPI() { if (m_spi == nullptr) { m_spi = new SPI(m_spi_port); m_spi->SetClockRate(1000000); - m_spi->SetMSBFirst(); - m_spi->SetSampleDataOnTrailingEdge(); - m_spi->SetClockActiveLow(); + m_spi->SetMode(frc::SPI::Mode::kMode3); m_spi->SetChipSelectActiveLow(); ReadRegister(PROD_ID); // Dummy read diff --git a/wpilibc/src/main/native/cpp/ADIS16470_IMU.cpp b/wpilibc/src/main/native/cpp/ADIS16470_IMU.cpp index 7127fa82ee..f2ff744aa1 100644 --- a/wpilibc/src/main/native/cpp/ADIS16470_IMU.cpp +++ b/wpilibc/src/main/native/cpp/ADIS16470_IMU.cpp @@ -194,9 +194,7 @@ bool ADIS16470_IMU::SwitchToStandardSPI() { if (m_spi == nullptr) { m_spi = new SPI(m_spi_port); m_spi->SetClockRate(2000000); - m_spi->SetMSBFirst(); - m_spi->SetSampleDataOnTrailingEdge(); - m_spi->SetClockActiveLow(); + m_spi->SetMode(frc::SPI::Mode::kMode3); m_spi->SetChipSelectActiveLow(); ReadRegister(PROD_ID); // Dummy read diff --git a/wpilibc/src/main/native/cpp/ADXL345_SPI.cpp b/wpilibc/src/main/native/cpp/ADXL345_SPI.cpp index 9a95bcc163..d3df40017a 100644 --- a/wpilibc/src/main/native/cpp/ADXL345_SPI.cpp +++ b/wpilibc/src/main/native/cpp/ADXL345_SPI.cpp @@ -21,9 +21,7 @@ ADXL345_SPI::ADXL345_SPI(SPI::Port port, ADXL345_SPI::Range range) m_simZ = m_simDevice.CreateDouble("z", hal::SimDevice::kInput, 0.0); } m_spi.SetClockRate(500000); - m_spi.SetMSBFirst(); - m_spi.SetSampleDataOnTrailingEdge(); - m_spi.SetClockActiveLow(); + m_spi.SetMode(frc::SPI::Mode::kMode3); m_spi.SetChipSelectActiveHigh(); uint8_t commands[2]; diff --git a/wpilibc/src/main/native/cpp/ADXL362.cpp b/wpilibc/src/main/native/cpp/ADXL362.cpp index deda965465..be4afb7b9c 100644 --- a/wpilibc/src/main/native/cpp/ADXL362.cpp +++ b/wpilibc/src/main/native/cpp/ADXL362.cpp @@ -43,9 +43,7 @@ ADXL362::ADXL362(SPI::Port port, Range range) } m_spi.SetClockRate(3000000); - m_spi.SetMSBFirst(); - m_spi.SetSampleDataOnTrailingEdge(); - m_spi.SetClockActiveLow(); + m_spi.SetMode(frc::SPI::Mode::kMode3); m_spi.SetChipSelectActiveLow(); uint8_t commands[3]; diff --git a/wpilibc/src/main/native/cpp/ADXRS450_Gyro.cpp b/wpilibc/src/main/native/cpp/ADXRS450_Gyro.cpp index 5a2f62543e..542d1ae314 100644 --- a/wpilibc/src/main/native/cpp/ADXRS450_Gyro.cpp +++ b/wpilibc/src/main/native/cpp/ADXRS450_Gyro.cpp @@ -38,9 +38,7 @@ ADXRS450_Gyro::ADXRS450_Gyro(SPI::Port port) } m_spi.SetClockRate(3000000); - m_spi.SetMSBFirst(); - m_spi.SetSampleDataOnLeadingEdge(); - m_spi.SetClockActiveHigh(); + m_spi.SetMode(frc::SPI::Mode::kMode0); m_spi.SetChipSelectActiveLow(); if (!m_simDevice) { diff --git a/wpilibc/src/main/native/cpp/SPI.cpp b/wpilibc/src/main/native/cpp/SPI.cpp index bbc82fd729..a629d4de59 100644 --- a/wpilibc/src/main/native/cpp/SPI.cpp +++ b/wpilibc/src/main/native/cpp/SPI.cpp @@ -158,6 +158,7 @@ void SPI::Accumulator::Update() { SPI::SPI(Port port) : m_port(static_cast(port)) { int32_t status = 0; HAL_InitializeSPI(m_port, &status); + HAL_SetSPIMode(m_port, m_mode); FRC_CheckErrorStatus(status, "Port {}", static_cast(m_port)); HAL_Report(HALUsageReporting::kResourceType_SPI, @@ -177,33 +178,46 @@ void SPI::SetClockRate(int hz) { } void SPI::SetMSBFirst() { - m_msbFirst = true; - HAL_SetSPIOpts(m_port, m_msbFirst, m_sampleOnTrailing, m_clockIdleHigh); + FRC_ReportError(1, "SetMSBFirst not supported by roboRIO {}", + static_cast(m_port)); } void SPI::SetLSBFirst() { - m_msbFirst = false; - HAL_SetSPIOpts(m_port, m_msbFirst, m_sampleOnTrailing, m_clockIdleHigh); + FRC_ReportError(1, "SetLSBFirst not supported by roboRIO {}", + static_cast(m_port)); } void SPI::SetSampleDataOnLeadingEdge() { - m_sampleOnTrailing = false; - HAL_SetSPIOpts(m_port, m_msbFirst, m_sampleOnTrailing, m_clockIdleHigh); + int mode = m_mode; + mode &= 2; + m_mode = static_cast(mode); + HAL_SetSPIMode(m_port, m_mode); } void SPI::SetSampleDataOnTrailingEdge() { - m_sampleOnTrailing = true; - HAL_SetSPIOpts(m_port, m_msbFirst, m_sampleOnTrailing, m_clockIdleHigh); + int mode = m_mode; + mode |= 2; + m_mode = static_cast(mode); + HAL_SetSPIMode(m_port, m_mode); } void SPI::SetClockActiveLow() { - m_clockIdleHigh = true; - HAL_SetSPIOpts(m_port, m_msbFirst, m_sampleOnTrailing, m_clockIdleHigh); + int mode = m_mode; + mode |= 1; + m_mode = static_cast(mode); + HAL_SetSPIMode(m_port, m_mode); } void SPI::SetClockActiveHigh() { - m_clockIdleHigh = false; - HAL_SetSPIOpts(m_port, m_msbFirst, m_sampleOnTrailing, m_clockIdleHigh); + int mode = m_mode; + mode &= 1; + m_mode = static_cast(mode); + HAL_SetSPIMode(m_port, m_mode); +} + +void SPI::SetMode(Mode mode) { + m_mode = static_cast(mode & 0x3); + HAL_SetSPIMode(m_port, m_mode); } void SPI::SetChipSelectActiveHigh() { diff --git a/wpilibc/src/main/native/include/frc/SPI.h b/wpilibc/src/main/native/include/frc/SPI.h index fb0e6f50d0..3f51595194 100644 --- a/wpilibc/src/main/native/include/frc/SPI.h +++ b/wpilibc/src/main/native/include/frc/SPI.h @@ -10,6 +10,7 @@ #include #include +#include #include namespace frc { @@ -26,6 +27,12 @@ class DigitalSource; class SPI { public: enum Port { kOnboardCS0 = 0, kOnboardCS1, kOnboardCS2, kOnboardCS3, kMXP }; + enum Mode { + kMode0 = HAL_SPI_kMode0, + kMode1 = HAL_SPI_kMode1, + kMode2 = HAL_SPI_kMode2, + kMode3 = HAL_SPI_kMode3 + }; /** * Constructor @@ -54,39 +61,72 @@ class SPI { /** * Configure the order that bits are sent and received on the wire * to be most significant bit first. + * + * @deprecated Does not work, will be removed. */ + WPI_DEPRECATED("Not supported by roboRIO.") void SetMSBFirst(); /** * Configure the order that bits are sent and received on the wire * to be least significant bit first. + * + * @deprecated Does not work, will be removed. */ + WPI_DEPRECATED("Not supported by roboRIO.") void SetLSBFirst(); /** * Configure that the data is stable on the leading edge and the data * changes on the trailing edge. + * + * @deprecated Use SetMode() instead. */ + WPI_DEPRECATED("Use SetMode() instead") void SetSampleDataOnLeadingEdge(); /** * Configure that the data is stable on the trailing edge and the data * changes on the leading edge. + * + * @deprecated Use SetMode() instead. */ + WPI_DEPRECATED("Use SetMode() instead") void SetSampleDataOnTrailingEdge(); /** * Configure the clock output line to be active low. * This is sometimes called clock polarity high or clock idle high. + * + * @deprecated Use SetMode() instead. */ + WPI_DEPRECATED("Use SetMode() instead") void SetClockActiveLow(); /** * Configure the clock output line to be active high. * This is sometimes called clock polarity low or clock idle low. + * + * @deprecated Use SetMode() instead. */ + WPI_DEPRECATED("Use SetMode() instead") void SetClockActiveHigh(); + /** + * Sets the mode for the SPI device. + * + *

Mode 0 is Clock idle low, data sampled on rising edge + * + *

Mode 1 is Clock idle low, data sampled on falling edge + * + *

Mode 2 is Clock idle high, data sampled on falling edge + * + *

Mode 3 is Clock idle high, data sampled on rising edge + * + * @param mode The mode to set. + */ + void SetMode(Mode mode); + /** * Configure the chip select line to be active high. */ @@ -345,9 +385,7 @@ class SPI { protected: hal::SPIPort m_port; - bool m_msbFirst = false; // Default little-endian - bool m_sampleOnTrailing = false; // Default data updated on falling edge - bool m_clockIdleHigh = false; // Default clock active high + HAL_SPIMode m_mode = HAL_SPIMode::HAL_SPI_kMode0; private: void Init(); diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/ADIS16448_IMU.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/ADIS16448_IMU.java index cc14a77c97..cbb43e8545 100644 --- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/ADIS16448_IMU.java +++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/ADIS16448_IMU.java @@ -395,9 +395,7 @@ public class ADIS16448_IMU implements AutoCloseable, NTSendable { System.out.println("Setting up a new SPI port."); m_spi = new SPI(m_spi_port); m_spi.setClockRate(1000000); - m_spi.setMSBFirst(); - m_spi.setSampleDataOnTrailingEdge(); - m_spi.setClockActiveLow(); + m_spi.setMode(SPI.Mode.kMode3); m_spi.setChipSelectActiveLow(); readRegister(PROD_ID); // Dummy read diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/ADIS16470_IMU.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/ADIS16470_IMU.java index 7741d0118b..b0f90c91bd 100644 --- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/ADIS16470_IMU.java +++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/ADIS16470_IMU.java @@ -438,9 +438,7 @@ public class ADIS16470_IMU implements AutoCloseable, NTSendable { System.out.println("Setting up a new SPI port."); m_spi = new SPI(m_spi_port); m_spi.setClockRate(2000000); - m_spi.setMSBFirst(); - m_spi.setSampleDataOnTrailingEdge(); - m_spi.setClockActiveLow(); + m_spi.setMode(SPI.Mode.kMode3); m_spi.setChipSelectActiveLow(); readRegister(PROD_ID); // Dummy read diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/ADXL345_SPI.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/ADXL345_SPI.java index fa8b7d808d..ddf38e1c5c 100644 --- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/ADXL345_SPI.java +++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/ADXL345_SPI.java @@ -118,9 +118,7 @@ public class ADXL345_SPI implements Accelerometer, NTSendable, AutoCloseable { */ private void init(Range range) { m_spi.setClockRate(500000); - m_spi.setMSBFirst(); - m_spi.setSampleDataOnTrailingEdge(); - m_spi.setClockActiveLow(); + m_spi.setMode(SPI.Mode.kMode3); m_spi.setChipSelectActiveHigh(); // Turn on the measurements diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/ADXL362.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/ADXL362.java index 2a9c2fe788..19abf05a50 100644 --- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/ADXL362.java +++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/ADXL362.java @@ -106,9 +106,7 @@ public class ADXL362 implements Accelerometer, NTSendable, AutoCloseable { } m_spi.setClockRate(3000000); - m_spi.setMSBFirst(); - m_spi.setSampleDataOnTrailingEdge(); - m_spi.setClockActiveLow(); + m_spi.setMode(SPI.Mode.kMode3); m_spi.setChipSelectActiveLow(); ByteBuffer transferBuffer = ByteBuffer.allocate(3); diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/ADXRS450_Gyro.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/ADXRS450_Gyro.java index 5a826def27..e12d8b9270 100644 --- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/ADXRS450_Gyro.java +++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/ADXRS450_Gyro.java @@ -71,9 +71,7 @@ public class ADXRS450_Gyro implements Gyro, Sendable { } m_spi.setClockRate(3000000); - m_spi.setMSBFirst(); - m_spi.setSampleDataOnLeadingEdge(); - m_spi.setClockActiveHigh(); + m_spi.setMode(SPI.Mode.kMode0); m_spi.setChipSelectActiveLow(); if (m_simDevice == null) { diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/SPI.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/SPI.java index 2f073d20ae..f93a9f0b4e 100644 --- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/SPI.java +++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/SPI.java @@ -15,11 +15,11 @@ import java.nio.IntBuffer; /** Represents a SPI bus port. */ public class SPI implements AutoCloseable { public enum Port { - kOnboardCS0(0), - kOnboardCS1(1), - kOnboardCS2(2), - kOnboardCS3(3), - kMXP(4); + kOnboardCS0(SPIJNI.ONBOARD_CS0_PORT), + kOnboardCS1(SPIJNI.ONBOARD_CS0_PORT), + kOnboardCS2(SPIJNI.ONBOARD_CS0_PORT), + kOnboardCS3(SPIJNI.ONBOARD_CS0_PORT), + kMXP(SPIJNI.MXP_PORT); public final int value; @@ -28,10 +28,21 @@ public class SPI implements AutoCloseable { } } + public enum Mode { + kMode0(SPIJNI.SPI_MODE0), + kMode1(SPIJNI.SPI_MODE1), + kMode2(SPIJNI.SPI_MODE2), + kMode3(SPIJNI.SPI_MODE3); + + public final int value; + + Mode(int value) { + this.value = value; + } + } + private int m_port; - private int m_msbFirst; - private int m_clockIdleHigh; - private int m_sampleOnTrailing; + private int m_mode; /** * Constructor. @@ -39,10 +50,13 @@ public class SPI implements AutoCloseable { * @param port the physical SPI port */ public SPI(Port port) { - m_port = (byte) port.value; + m_port = port.value; SPIJNI.spiInitialize(m_port); + m_mode = 0; + SPIJNI.spiSetMode(m_port, m_mode); + HAL.report(tResourceType.kResourceType_SPI, port.value + 1); } @@ -72,55 +86,89 @@ public class SPI implements AutoCloseable { /** * Configure the order that bits are sent and received on the wire to be most significant bit * first. + * + * @deprecated Does not work, will be removed. */ + @Deprecated(since = "2023", forRemoval = true) public final void setMSBFirst() { - m_msbFirst = 1; - SPIJNI.spiSetOpts(m_port, m_msbFirst, m_sampleOnTrailing, m_clockIdleHigh); + DriverStation.reportWarning("setMSBFirst not supported by roboRIO", false); } /** * Configure the order that bits are sent and received on the wire to be least significant bit * first. + * + * @deprecated Does not work, will be removed. */ + @Deprecated(since = "2023", forRemoval = true) public final void setLSBFirst() { - m_msbFirst = 0; - SPIJNI.spiSetOpts(m_port, m_msbFirst, m_sampleOnTrailing, m_clockIdleHigh); + DriverStation.reportWarning("setLSBFirst not supported by roboRIO", false); } /** * Configure the clock output line to be active low. This is sometimes called clock polarity high * or clock idle high. + * + * @deprecated Use setMode() instead. */ + @Deprecated(since = "2023", forRemoval = true) public final void setClockActiveLow() { - m_clockIdleHigh = 1; - SPIJNI.spiSetOpts(m_port, m_msbFirst, m_sampleOnTrailing, m_clockIdleHigh); + m_mode |= 1; + SPIJNI.spiSetMode(m_port, m_mode); } /** * Configure the clock output line to be active high. This is sometimes called clock polarity low * or clock idle low. + * + * @deprecated Use setMode() instead. */ + @Deprecated(since = "2023", forRemoval = true) public final void setClockActiveHigh() { - m_clockIdleHigh = 0; - SPIJNI.spiSetOpts(m_port, m_msbFirst, m_sampleOnTrailing, m_clockIdleHigh); + m_mode &= 1; + SPIJNI.spiSetMode(m_port, m_mode); } /** * Configure that the data is stable on the leading edge and the data changes on the trailing * edge. + * + * @deprecated Use setMode() instead. */ + @Deprecated(since = "2023", forRemoval = true) public final void setSampleDataOnLeadingEdge() { - m_sampleOnTrailing = 0; - SPIJNI.spiSetOpts(m_port, m_msbFirst, m_sampleOnTrailing, m_clockIdleHigh); + m_mode &= 2; + SPIJNI.spiSetMode(m_port, m_mode); } /** * Configure that the data is stable on the trailing edge and the data changes on the leading * edge. + * + * @deprecated Use setMode() instead. */ + @Deprecated(since = "2023", forRemoval = true) public final void setSampleDataOnTrailingEdge() { - m_sampleOnTrailing = 1; - SPIJNI.spiSetOpts(m_port, m_msbFirst, m_sampleOnTrailing, m_clockIdleHigh); + m_mode |= 2; + SPIJNI.spiSetMode(m_port, m_mode); + } + + /** + * Sets the mode for the SPI device. + * + *

Mode 0 is Clock idle low, data sampled on rising edge. + * + *

Mode 1 is Clock idle low, data sampled on falling edge. + * + *

Mode 2 is Clock idle high, data sampled on falling edge. + * + *

Mode 3 is Clock idle high, data sampled on rising edge. + * + * @param mode The mode to set. + */ + public final void setMode(Mode mode) { + m_mode = mode.value & 0x3; + SPIJNI.spiSetMode(m_port, m_mode); } /** Configure the chip select line to be active high. */