AllenGregoryIV
18-10-2011, 02:36
Has any one successfully used the SPI bus in Java. I'm about to start a project and looking for sample code. I know about the tSPI class but I haven't looked in to it in depth yet.
Thanks,
Allen Gregory
charrisTTI
19-10-2011, 10:44
We tried SPI a couple of years ago using java. A lot of trial and error with the API if I remember correctly. Also needed some "glue hardware" since pins are either output or input on cRIO, but devices had single pin used for both.
First block is used to interface with optical mouse chip.
Second block shows how first was called.
Third block is used to interface with magnetic rotary encoder.
Hope this helps.
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package edu.wpi.first.frc623;
import edu.wpi.first.wpilibj.DigitalModule;
import edu.wpi.first.wpilibj.SensorBase;
import edu.wpi.first.wpilibj.Timer;
import edu.wpi.first.wpilibj.fpga.tSPI;
/**
*
* @author charris
*/
public class PAN3101OpticalMouse extends SensorBase {
// register map from datasheet
private static final char OPERATION_MODE_1 = 0x00;
private static final char PRODUCT_ID1 = 0x01;
private static final char DELTA_Y_1 = 0x02;
private static final char DELTA_X_1 = 0x03;
private static final char IMAGE_QUALITY_1 = 0x04;
private static final char PRODUCT_ID2_A = 0x14;
private static final char PRODUCT_ID2_B = 0x15;
private static final char MOTION_STATUS = 0x16;
private static final char DELTA_X_2 = 0x17;
private static final char DELTA_Y_2 = 0x18;
private static final char IMAGE_QUALITY_2 = 0x19;
private static final char OPERATION_MODE_2 = 0x1A;
private static final char CONFIGURATION = 0x1B;
private static final char OPERATION_MODE_3 = 0x40;
private static final char PRODUCT_ID3 = 0x41;
private static final char DELTA_Y_3 = 0x42;
private static final char DELTA_X_3 = 0x43;
private static final char IMAGE_QUALITY_3 = 0x44;
private static final char WRITE_REGISTER = 0x80;
private static final char RES_400_CPI = 0x80;
private static final char FULL_RESET = 0x80;
private static final char SLEEP_DISABLE = 0x01;
private static final char DEFAULT_MODE = 0x00;
tSPI spi;
DigitalModule module;
int slot;
int clockPin;
int dataOutPin;
int dataInPin;
int inhibitPin;
public PAN3101OpticalMouse( int slotParam, int clockPinParam, int dataOutPinParam, int dataInPinParam, int inhibitPinParam )
{
slot = slotParam;
clockPin = clockPinParam;
dataOutPin = dataOutPinParam;
dataInPin = dataInPinParam;
inhibitPin = inhibitPinParam;
// get our module
module = DigitalModule.getInstance(slot);
// create SPI instance
//spi = new tSPI();
// allocate our pins
module.allocateDIO(clockPin, false);
module.allocateDIO(dataOutPin, false);
module.allocateDIO(dataInPin, true);
module.allocateDIO(inhibitPin, false);
}
public void intialize()
{
// reset the chip
module.setDIO(clockPin, false);
Timer.delay(0.01);
module.setDIO(clockPin, true);
Timer.delay(0.001);
module.setDIO(clockPin, false);
Timer.delay(0.01);
// setup for SPI
tSPI.writeChannels_SCLK_Module(DigitalModule.slotT oIndex(slot));
tSPI.writeChannels_SCLK_Channel(DigitalModule.rema pDigitalChannel(clockPin-1));
tSPI.writeChannels_MOSI_Module(DigitalModule.slotT oIndex(slot));
tSPI.writeChannels_MOSI_Channel(DigitalModule.rema pDigitalChannel(dataOutPin-1));
tSPI.writeChannels_MISO_Module(DigitalModule.slotT oIndex(slot));
tSPI.writeChannels_MISO_Channel(DigitalModule.rema pDigitalChannel(dataInPin-1));
// set clock
tSPI.writeConfig_ClockPolarity(true);
//tSPI.writeConfig_FramePolarity(true);
tSPI.writeConfig_LatchLast(false);
tSPI.writeConfig_LatchFirst(false);
// set the width to 8
tSPI.writeConfig_BusBitWidth(8);
// data is valid on rising edge of clock
tSPI.writeConfig_DataOnFalling(false);
// set the bit order
tSPI.writeConfig_MSBfirst(true);
tSPI.strobeReset();
tSPI.strobeClearReceivedData();
// call for reset
putRegister( OPERATION_MODE_1, FULL_RESET );
Timer.delay(2.0);
// disable sleep
putRegister( OPERATION_MODE_1, SLEEP_DISABLE );
//Timer.delay(2.0);
// set resolution to 400 cpi
char configTemp = getRegister(CONFIGURATION);
//Timer.delay(2.0);
putRegister(CONFIGURATION, (char)(RES_400_CPI | configTemp ));
//Timer.delay(2.0);
}
public byte getDeltaX()
{
return (byte)getRegister(DELTA_X_1);
}
public byte getDeltaY()
{
return (byte)getRegister(DELTA_Y_1);
}
protected char getRegister( char addressParam )
{
// select for write
tSPI.writeChannels_SS_Module(DigitalModule.slotToI ndex(slot));
tSPI.writeChannels_SS_Channel(0);
// write the data to load
tSPI.writeDataToLoad(addressParam);
// strobe out the data
tSPI.strobeLoad();
// wait for completion
while( tSPI.readReceivedElements() == 0 )
{
java.lang.Thread.yield();
}
// set inhibit
//module.setDIO(inhibitPin, false);
tSPI.writeChannels_SS_Module(DigitalModule.slotToI ndex(slot));
tSPI.writeChannels_SS_Channel(DigitalModule.remapD igitalChannel(inhibitPin-1));
// clear the data to load
tSPI.writeDataToLoad(0x0);
// clear received data
tSPI.strobeClearReceivedData();
// strobe in the data
tSPI.strobeLoad();
// wait for completion
//while( !tSPI.readStatus_Idle() )
while( tSPI.readReceivedElements() == 0 )
{
java.lang.Thread.yield();
}
// strobe in the received data
tSPI.strobeReadReceivedData();
// read the data
long rawData = tSPI.readReceivedData();
return (char)(rawData & 0xFF);
}
protected void putRegister( char addressParam, char dataParam )
{
// clear select
tSPI.writeChannels_SS_Module(DigitalModule.slotToI ndex(slot));
tSPI.writeChannels_SS_Channel(0);
// get deltax
// write the adddrss to load
tSPI.writeDataToLoad(addressParam | WRITE_REGISTER);
// strobe out the data
tSPI.strobeLoad();
// wait for completion
while( tSPI.readReceivedElements() == 0 )
{
java.lang.Thread.yield();
}
tSPI.writeChannels_SS_Module(DigitalModule.slotToI ndex(slot));
tSPI.writeChannels_SS_Channel(0);
// write the data to load
tSPI.writeDataToLoad(dataParam);
// clear received data
tSPI.strobeClearReceivedData();
// strobe in the data
tSPI.strobeLoad();
// wait for completion
while( tSPI.readReceivedElements() == 0 )
{
java.lang.Thread.yield();
}
// strobe in the received data
tSPI.strobeReadReceivedData();
// read the data
long rawData = tSPI.readReceivedData();
}
}
Here is how it was used. Run called by timer thread at frequency sufficient to make sure we did not lose any counts. Optical mouse chip had maximum limit for movement speed. Had problems getting good mechanical mount close enough to the floor. We really needed a different lens to allow mounting further from the floor.
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package edu.wpi.first.frc623;
/**
*
* @author charris
*/
public class OpticalMouseEncoder extends Thread {
private PAN3101OpticalMouse mouse;
private long totalX;
private long totalY;
public OpticalMouseEncoder()
{
mouse = new PAN3101OpticalMouse( 4, 1, 2, 3, 4 );
totalX = 0;
totalY = 0;
}
public void run()
{
// initialize the sensor
mouse.intialize();
while( true )
{
byte deltaX = mouse.getDeltaX();
byte deltaY = mouse.getDeltaY();
synchronized( this )
{
totalX += deltaX;
totalY += deltaY;
}
try
{
this.sleep(10);
}
catch( InterruptedException e )
{
}
}
}
synchronized public void reset()
{
totalX = 0;
totalY = 0;
}
synchronized public void resetX()
{
totalX = 0;
}
synchronized public void resetY()
{
totalY = 0;
}
synchronized public long getXCounts()
{
return totalX;
}
synchronized public long getYCounts()
{
return totalY;
}
public double getXInches()
{
return ( (double) getXCounts() ) / 400.0;
}
public double getYInches()
{
return ( (double) getYCounts() ) / 400.0;
}
}
Here is class for the magnetic rotary encoder (we ultimately used two analog channels for this sensor to get best performance):
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package edu.wpi.first.frc623;
import edu.wpi.first.wpilibj.DigitalModule;
import edu.wpi.first.wpilibj.SensorBase;
import edu.wpi.first.wpilibj.fpga.tSPI;
/**
*
* @author charris
*/
public class AS5030FourWireSPI extends SensorBase {
public class AS5030Result
{
public double angle;
public int agc;
}
tSPI spi;
DigitalModule module;
int slot;
int clockPin;
int dataOutPin;
int dataInPin;
int chipSelectPin;
public AS5030FourWireSPI( int slotParam, int clockPinParam, int dataOutPinParam, int dataInPinParam, int chipSelectPinParam )
{
slot = slotParam;
clockPin = clockPinParam;
dataOutPin = dataOutPinParam;
dataInPin = dataInPinParam;
chipSelectPin = chipSelectPinParam;
// get our module
module = DigitalModule.getInstance(slot);
// create SPI instance
//spi = new tSPI();
// allocate our pins
module.allocateDIO(clockPin, false);
module.allocateDIO(dataOutPin, false);
module.allocateDIO(dataInPin, true);
module.allocateDIO(chipSelectPin, false);
// setup for SPI
tSPI.writeChannels_SCLK_Module(DigitalModule.slotT oIndex(slot));
tSPI.writeChannels_SCLK_Channel(DigitalModule.rema pDigitalChannel(clockPin-1));
tSPI.writeChannels_MOSI_Module(DigitalModule.slotT oIndex(slot));
tSPI.writeChannels_MOSI_Channel(DigitalModule.rema pDigitalChannel(dataOutPin-1));
tSPI.writeChannels_MISO_Module(DigitalModule.slotT oIndex(slot));
tSPI.writeChannels_MISO_Channel(DigitalModule.rema pDigitalChannel(dataInPin-1));
}
public void initialize()
{
// set chip select low to start
module.setDIO(chipSelectPin, true);
// data is valid on rising edge of clock
tSPI.writeConfig_DataOnFalling(false);
// set the bit order
tSPI.writeConfig_MSBfirst(true);
tSPI.strobeReset();
tSPI.strobeClearReceivedData();
}
public AS5030Result getData( )
{
// select the chip
module.setDIO(chipSelectPin, false);
// write the 5 bit command
// set the width
tSPI.writeConfig_BusBitWidth(5);
// write the data to load
tSPI.writeDataToLoad(0x1F);
// strobe out the data
tSPI.strobeLoad();
// wait for completion
while( !tSPI.readStatus_Idle() )
{
java.lang.Thread.yield();
}
// change back to 16 bits
tSPI.writeConfig_BusBitWidth(16);
// clear the data to load
tSPI.writeDataToLoad(0x0);
// clear received data
tSPI.strobeClearReceivedData();
// strobe in the data
tSPI.strobeLoad();
// wait for completion
//while( !tSPI.readStatus_Idle() )
while( tSPI.readReceivedElements() == 0 )
{
java.lang.Thread.yield();
}
// strobe in the received data
tSPI.strobeReadReceivedData();
// read the data
long rawData = tSPI.readReceivedData();
// deselect the chip
module.setDIO(chipSelectPin, true);
AS5030Result result = new AS5030Result();
long rawAngle = rawData & 0xFF;
int agc = (int)((rawData >> 8) & 0x3F);
result.angle = (double)rawAngle * 360.0 / 256.0;
result.agc = agc;
return result;
}
}
AllenGregoryIV
19-10-2011, 13:14
Thank you charrisTTI, that looks like it should help us out a lot.
vBulletin® v3.6.4, Copyright ©2000-2017, Jelsoft Enterprises Ltd.