mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-20 00:51:42 +00:00
Merge "Port SPI to roboRIO. Java SPIDevice renamed to SPI and rewritten to match C++ API."
This commit is contained in:
@@ -0,0 +1,165 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2008-2012. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
package edu.wpi.first.wpilibj;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author dtjones
|
||||
* @author mwills
|
||||
*/
|
||||
public class ADXL345_SPI extends SensorBase {
|
||||
private static final int kPowerCtlRegister = 0x2D;
|
||||
private static final int kDataFormatRegister = 0x31;
|
||||
private static final int kDataRegister = 0x32;
|
||||
private static final double kGsPerLSB = 0.00390625;
|
||||
|
||||
private static final int kAddress_Read = 0x80;
|
||||
private static final int kAddress_MultiByte = 0x40;
|
||||
|
||||
private static final int kPowerCtl_Link=0x20;
|
||||
private static final int kPowerCtl_AutoSleep=0x10;
|
||||
private static final int kPowerCtl_Measure=0x08;
|
||||
private static final int kPowerCtl_Sleep=0x04;
|
||||
|
||||
private static final int kDataFormat_SelfTest=0x80;
|
||||
private static final int kDataFormat_SPI=0x40;
|
||||
private static final int kDataFormat_IntInvert=0x20;
|
||||
private static final int kDataFormat_FullRes=0x08;
|
||||
private static final int kDataFormat_Justify=0x04;
|
||||
|
||||
|
||||
public static class DataFormat_Range {
|
||||
|
||||
/**
|
||||
* The integer value representing this enumeration
|
||||
*/
|
||||
public final byte value;
|
||||
static final byte k2G_val = 0x00;
|
||||
static final byte k4G_val = 0x01;
|
||||
static final byte k8G_val = 0x02;
|
||||
static final byte k16G_val = 0x03;
|
||||
public static final ADXL345_SPI.DataFormat_Range k2G = new ADXL345_SPI.DataFormat_Range(k2G_val);
|
||||
public static final ADXL345_SPI.DataFormat_Range k4G = new ADXL345_SPI.DataFormat_Range(k4G_val);
|
||||
public static final ADXL345_SPI.DataFormat_Range k8G = new ADXL345_SPI.DataFormat_Range(k8G_val);
|
||||
public static final ADXL345_SPI.DataFormat_Range k16G = new ADXL345_SPI.DataFormat_Range(k16G_val);
|
||||
|
||||
private DataFormat_Range(byte value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Axes {
|
||||
|
||||
/**
|
||||
* The integer value representing this enumeration
|
||||
*/
|
||||
public final byte value;
|
||||
static final byte kX_val = 0x00;
|
||||
static final byte kY_val = 0x02;
|
||||
static final byte kZ_val = 0x04;
|
||||
public static final ADXL345_SPI.Axes kX = new ADXL345_SPI.Axes(kX_val);
|
||||
public static final ADXL345_SPI.Axes kY = new ADXL345_SPI.Axes(kY_val);
|
||||
public static final ADXL345_SPI.Axes kZ = new ADXL345_SPI.Axes(kZ_val);
|
||||
|
||||
private Axes(byte value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
public static class AllAxes {
|
||||
|
||||
public double XAxis;
|
||||
public double YAxis;
|
||||
public double ZAxis;
|
||||
}
|
||||
|
||||
private SPI m_spi;
|
||||
|
||||
/**
|
||||
* Constructor. Use this when the device is the first/only device on the bus
|
||||
*
|
||||
* @param clk The clock channel
|
||||
* @param mosi The mosi (output) channel
|
||||
* @param miso The miso (input) channel
|
||||
* @param cs The chip select channel
|
||||
* @param range The range (+ or -) that the accelerometer will measure.
|
||||
*/
|
||||
public ADXL345_SPI(SPI.Port port, ADXL345_SPI.DataFormat_Range range) {
|
||||
m_spi = new SPI(port);
|
||||
init(range);
|
||||
}
|
||||
|
||||
public void free(){
|
||||
m_spi.free();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set SPI bus parameters, bring device out of sleep and set format
|
||||
*
|
||||
* @param range The range (+ or -) that the accelerometer will measure.
|
||||
*/
|
||||
private void init(ADXL345_SPI.DataFormat_Range range){
|
||||
m_spi.setClockRate(500000);
|
||||
m_spi.setMSBFirst();
|
||||
m_spi.setSampleDataOnFalling();
|
||||
m_spi.setClockActiveLow();
|
||||
m_spi.setChipSelectActiveHigh();
|
||||
|
||||
// Turn on the measurements
|
||||
byte[] commands = new byte[2];
|
||||
commands[0] = kPowerCtlRegister;
|
||||
commands[1] = kPowerCtl_Measure;
|
||||
m_spi.write(commands, 2);
|
||||
// Specify the data format to read
|
||||
commands[0] = kDataFormatRegister;
|
||||
commands[1] = (byte)(kDataFormat_FullRes | range.value);
|
||||
m_spi.write(commands, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the acceleration of one axis in Gs.
|
||||
*
|
||||
* @param axis The axis to read from.
|
||||
* @return Acceleration of the ADXL345 in Gs.
|
||||
*/
|
||||
public double getAcceleration(ADXL345_SPI.Axes axis) {
|
||||
byte[] transferBuffer = new byte[3];
|
||||
transferBuffer[0] = (byte)((kAddress_Read | kAddress_MultiByte | kDataRegister) + axis.value);
|
||||
m_spi.transaction(transferBuffer, transferBuffer, 3);
|
||||
//Sensor is little endian... swap bytes
|
||||
int rawAccel = transferBuffer[2] << 8 | transferBuffer[1];
|
||||
return rawAccel * kGsPerLSB;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the acceleration of all axes in Gs.
|
||||
*
|
||||
* @return Acceleration measured on all axes of the ADXL345 in Gs.
|
||||
*/
|
||||
public ADXL345_SPI.AllAxes getAccelerations() {
|
||||
ADXL345_SPI.AllAxes data = new ADXL345_SPI.AllAxes();
|
||||
byte dataBuffer[] = new byte[7];
|
||||
int[] rawData = new int[3];
|
||||
if (m_spi != null)
|
||||
{
|
||||
// Select the data address.
|
||||
dataBuffer[0] = (byte)(kAddress_Read | kAddress_MultiByte | kDataRegister);
|
||||
m_spi.transaction(dataBuffer, dataBuffer, 7);
|
||||
|
||||
for (int i=0; i<3; i++)
|
||||
{
|
||||
//Sensor is little endian... swap bytes
|
||||
rawData[i] = dataBuffer[i*2+2] << 8 | dataBuffer[i*2+1];
|
||||
}
|
||||
|
||||
data.XAxis = rawData[0] * kGsPerLSB;
|
||||
data.YAxis = rawData[1] * kGsPerLSB;
|
||||
data.ZAxis = rawData[2] * kGsPerLSB;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
||||
215
wpilibj/wpilibJava/src/main/java/edu/wpi/first/wpilibj/SPI.java
Normal file
215
wpilibj/wpilibJava/src/main/java/edu/wpi/first/wpilibj/SPI.java
Normal file
@@ -0,0 +1,215 @@
|
||||
package edu.wpi.first.wpilibj;
|
||||
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.IntBuffer;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import edu.wpi.first.wpilibj.communication.FRCNetworkCommunicationsLibrary.tResourceType;
|
||||
import edu.wpi.first.wpilibj.communication.UsageReporting;
|
||||
import edu.wpi.first.wpilibj.hal.HALLibrary;
|
||||
import edu.wpi.first.wpilibj.hal.HALUtil;
|
||||
import edu.wpi.first.wpilibj.hal.SPIJNI;
|
||||
|
||||
/**
|
||||
*
|
||||
* Represents a SPI bus port
|
||||
|
||||
* @author koconnor
|
||||
*/
|
||||
public class SPI extends SensorBase {
|
||||
|
||||
public enum Port {
|
||||
kOnboardCS0(0),
|
||||
kOnboardCS1(1),
|
||||
kOnboardCS2(2),
|
||||
kOnboardCS3(3),
|
||||
kMXP(4);
|
||||
|
||||
private int value;
|
||||
|
||||
private Port(int value){
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int getValue(){
|
||||
return this.value;
|
||||
}
|
||||
};
|
||||
|
||||
private static int devices = 0;
|
||||
|
||||
private byte m_port;
|
||||
private int bitOrder;
|
||||
private int clockPolarity;
|
||||
private int dataOnTrailing;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param SPIport the physical SPI port
|
||||
*/
|
||||
public SPI(Port port) {
|
||||
ByteBuffer status = ByteBuffer.allocateDirect(4);
|
||||
status.order(ByteOrder.LITTLE_ENDIAN);
|
||||
|
||||
m_port = (byte)port.getValue();
|
||||
devices++;
|
||||
|
||||
SPIJNI.spiInitialize(m_port, status.asIntBuffer());
|
||||
HALUtil.checkStatus(status.asIntBuffer());
|
||||
|
||||
UsageReporting.report(tResourceType.kResourceType_SPI, devices);
|
||||
}
|
||||
|
||||
/**
|
||||
* Free the resources used by this object
|
||||
*/
|
||||
public void free(){
|
||||
SPIJNI.spiClose(m_port);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the rate of the generated clock signal.
|
||||
* The default and maximum value is 500,000 Hz.
|
||||
*
|
||||
* @param hz The clock rate in Hertz.
|
||||
*/
|
||||
public final void setClockRate(int hz) {
|
||||
SPIJNI.spiSetSpeed(m_port, hz);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the order that bits are sent and received on the wire
|
||||
* to be most significant bit first.
|
||||
*/
|
||||
public final void setMSBFirst() {
|
||||
this.bitOrder = 1;
|
||||
SPIJNI.spiSetOpts(m_port, this.bitOrder, this.dataOnTrailing, this.clockPolarity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the order that bits are sent and received on the wire
|
||||
* to be least significant bit first.
|
||||
*/
|
||||
public final void setLSBFirst() {
|
||||
this.bitOrder = 0;
|
||||
SPIJNI.spiSetOpts(m_port, this.bitOrder, this.dataOnTrailing, this.clockPolarity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the clock output line to be active low.
|
||||
* This is sometimes called clock polarity high or clock idle high.
|
||||
*/
|
||||
public final void setClockActiveLow() {
|
||||
this.clockPolarity = 1;
|
||||
SPIJNI.spiSetOpts(m_port, this.bitOrder, this.dataOnTrailing, this.clockPolarity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the clock output line to be active high.
|
||||
* This is sometimes called clock polarity low or clock idle low.
|
||||
*/
|
||||
public final void setClockActiveHigh() {
|
||||
this.clockPolarity = 0;
|
||||
SPIJNI.spiSetOpts(m_port, this.bitOrder, this.dataOnTrailing, this.clockPolarity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure that the data is stable on the falling edge and the data
|
||||
* changes on the rising edge.
|
||||
*/
|
||||
public final void setSampleDataOnFalling() {
|
||||
this.dataOnTrailing = 1;
|
||||
SPIJNI.spiSetOpts(m_port, this.bitOrder, this.dataOnTrailing, this.clockPolarity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure that the data is stable on the rising edge and the data
|
||||
* changes on the falling edge.
|
||||
*/
|
||||
public final void setSampleDataOnRising() {
|
||||
this.dataOnTrailing = 0;
|
||||
SPIJNI.spiSetOpts(m_port, this.bitOrder, this.dataOnTrailing, this.clockPolarity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the chip select line to be active high.
|
||||
*/
|
||||
public final void setChipSelectActiveHigh() {
|
||||
ByteBuffer status = ByteBuffer.allocateDirect(4);
|
||||
status.order(ByteOrder.LITTLE_ENDIAN);
|
||||
|
||||
SPIJNI.spiSetChipSelectActiveHigh(m_port, status.asIntBuffer());
|
||||
|
||||
HALUtil.checkStatus(status.asIntBuffer());
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the chip select line to be active low.
|
||||
*/
|
||||
public final void setChipSelectActiveLow() {
|
||||
ByteBuffer status = ByteBuffer.allocateDirect(4);
|
||||
status.order(ByteOrder.LITTLE_ENDIAN);
|
||||
|
||||
SPIJNI.spiSetChipSelectActiveLow(m_port, status.asIntBuffer());
|
||||
|
||||
HALUtil.checkStatus(status.asIntBuffer());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public int write(byte[] dataToSend, int size) {
|
||||
int retVal = 0;
|
||||
ByteBuffer dataToSendBuffer = ByteBuffer.allocateDirect(size);
|
||||
dataToSendBuffer.put(dataToSend);
|
||||
retVal = SPIJNI.spiWrite(m_port, dataToSendBuffer, (byte) size);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public int read(boolean initiate, byte[] dataReceived, int size) {
|
||||
int retVal = 0;
|
||||
ByteBuffer dataReceivedBuffer = ByteBuffer.allocateDirect(size);
|
||||
ByteBuffer dataToSendBuffer = ByteBuffer.allocateDirect(size);
|
||||
if(initiate)
|
||||
retVal = SPIJNI.spiTransaction(m_port, dataToSendBuffer, dataReceivedBuffer, (byte) size);
|
||||
else
|
||||
retVal = SPIJNI.spiRead(m_port, dataReceivedBuffer, (byte) size);
|
||||
dataReceivedBuffer.get(dataReceived);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public int transaction(byte[] dataToSend, byte[] dataReceived, int size) {
|
||||
int retVal = 0;
|
||||
ByteBuffer dataToSendBuffer = ByteBuffer.allocateDirect(size);
|
||||
dataToSendBuffer.put(dataToSend);
|
||||
ByteBuffer dataReceivedBuffer = ByteBuffer.allocateDirect(size);
|
||||
retVal = SPIJNI.spiTransaction(m_port, dataToSendBuffer, dataReceivedBuffer, (byte) size);
|
||||
dataReceivedBuffer.get(dataReceived);
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
@@ -4,29 +4,14 @@ import java.nio.ByteBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
|
||||
public class SPIJNI extends JNIWrapper {
|
||||
public static native ByteBuffer initializeSPI(byte sclk_routing_module, int sclk_routing_pin, byte mosi_routing_module, int mosi_routing_pin, byte miso_routing_module, int miso_routing_pin, IntBuffer status);
|
||||
public static native void cleanSPI(ByteBuffer spi_pointer, IntBuffer status);
|
||||
public static native void setSPIBitsPerWord(ByteBuffer spi_pointer, int bits, IntBuffer status);
|
||||
public static native int getSPIBitsPerWord(ByteBuffer spi_pointer, IntBuffer status);
|
||||
public static native void setSPIClockRate(ByteBuffer spi_pointer, double hz, IntBuffer status);
|
||||
public static native void setSPIMSBFirst(ByteBuffer spi_pointer, IntBuffer status);
|
||||
public static native void setSPILSBFirst(ByteBuffer spi_pointer, IntBuffer status);
|
||||
public static native void setSPISampleDataOnFalling(ByteBuffer spi_pointer, IntBuffer status);
|
||||
public static native void setSPISampleDataOnRising(ByteBuffer spi_pointer, IntBuffer status);
|
||||
public static native void setSPISlaveSelect(ByteBuffer spi_pointer, byte ss_routing_module, int ss_routing_pin, IntBuffer status);
|
||||
public static native void setSPILatchMode(ByteBuffer spi_pointer, int mode, IntBuffer status);
|
||||
public static native int getSPILatchMode(ByteBuffer spi_pointer, IntBuffer status);
|
||||
public static native void setSPIFramePolarity(ByteBuffer spi_pointer, byte activeLow, IntBuffer status);
|
||||
public static native byte getSPIFramePolarity(ByteBuffer spi_pointer, IntBuffer status);
|
||||
public static native void setSPIClockActiveLow(ByteBuffer spi_pointer, IntBuffer status);
|
||||
public static native void setSPIClockActiveHigh(ByteBuffer spi_pointer, IntBuffer status);
|
||||
public static native void applySPIConfig(ByteBuffer spi_pointer, IntBuffer status);
|
||||
public static native short getSPIOutputFIFOAvailable(ByteBuffer spi_pointer, IntBuffer status);
|
||||
public static native short getSPINumReceived(ByteBuffer spi_pointer, IntBuffer status);
|
||||
public static native byte isSPIDone(ByteBuffer spi_pointer, IntBuffer status);
|
||||
public static native byte hadSPIReceiveOverflow(ByteBuffer spi_pointer, IntBuffer status);
|
||||
public static native void writeSPI(ByteBuffer spi_pointer, int data, IntBuffer status);
|
||||
public static native int readSPI(ByteBuffer spi_pointer, byte initiate, IntBuffer status);
|
||||
public static native void resetSPI(ByteBuffer spi_pointer, IntBuffer status);
|
||||
public static native void clearSPIReceivedData(ByteBuffer spi_pointer, IntBuffer status);
|
||||
public static native void spiInitialize(byte port, IntBuffer status);
|
||||
public static native int spiTransaction(byte port, ByteBuffer dataToSend, ByteBuffer dataReceived, byte size);
|
||||
public static native int spiWrite(byte port, ByteBuffer dataToSend, byte sendSize);
|
||||
public static native int spiRead(byte port, ByteBuffer dataReceived, byte size);
|
||||
public static native void spiClose(byte port);
|
||||
public static native void spiSetSpeed(byte port, int speed);
|
||||
public static native void spiSetBitsPerWord(byte port, byte bpw);
|
||||
public static native void spiSetOpts(byte port, int msb_first, int sample_on_trailing, int clk_idle_high);
|
||||
public static native void spiSetChipSelectActiveHigh(byte port, IntBuffer status);
|
||||
public static native void spiSetChipSelectActiveLow(byte port, IntBuffer status);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user