Chief Delphi

Chief Delphi (http://www.chiefdelphi.com/forums/index.php)
-   Java (http://www.chiefdelphi.com/forums/forumdisplay.php?f=184)
-   -   Programming an SPI sensor in Java (http://www.chiefdelphi.com/forums/showthread.php?t=97885)

AllenGregoryIV 18-10-2011 02:36

Programming an SPI sensor in Java
 
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

Re: Programming an SPI sensor in Java
 
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.


Code:

/*
 * 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.slotToIndex(slot));
        tSPI.writeChannels_SCLK_Channel(DigitalModule.remapDigitalChannel(clockPin-1));

        tSPI.writeChannels_MOSI_Module(DigitalModule.slotToIndex(slot));
        tSPI.writeChannels_MOSI_Channel(DigitalModule.remapDigitalChannel(dataOutPin-1));

        tSPI.writeChannels_MISO_Module(DigitalModule.slotToIndex(slot));
        tSPI.writeChannels_MISO_Channel(DigitalModule.remapDigitalChannel(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.slotToIndex(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.slotToIndex(slot));
        tSPI.writeChannels_SS_Channel(DigitalModule.remapDigitalChannel(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.slotToIndex(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.slotToIndex(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.


Code:

/*
 * 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):

Code:

/*
 * 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.slotToIndex(slot));
        tSPI.writeChannels_SCLK_Channel(DigitalModule.remapDigitalChannel(clockPin-1));

        tSPI.writeChannels_MOSI_Module(DigitalModule.slotToIndex(slot));
        tSPI.writeChannels_MOSI_Channel(DigitalModule.remapDigitalChannel(dataOutPin-1));

        tSPI.writeChannels_MISO_Module(DigitalModule.slotToIndex(slot));
        tSPI.writeChannels_MISO_Channel(DigitalModule.remapDigitalChannel(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

Re: Programming an SPI sensor in Java
 
Thank you charrisTTI, that looks like it should help us out a lot.


All times are GMT -5. The time now is 11:42.

Powered by vBulletin® Version 3.6.4
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.
Copyright © Chief Delphi