I spent the better part of a day looking at the magnetic encoder I/O options. We ruled out the analog angle output because of the slow response at the rollover point. I did not give the PWM output much thought. I tried two different approaches for which I am including code samples. The first reads the data digitally using the SPI support and the second uses two analog channels to read the sin/cos outputs (be sure to remove the solder jumper to enable these ports).
Here is the digital one using SPI:
Code:
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package edu.wpi.first.wpilibj;
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;
}
}
Here is the dual analog input approach:
Code:
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package edu.wpi.first.wpilibj;
import com.sun.squawk.util.MathUtils;
/**
*
* @author charris
*/
public class AS5030DualAnalog extends SensorBase implements PIDSource {
private static final double biasVoltage = 2.25;
private AnalogChannel sinChannel;
private AnalogChannel cosChannel;
public AS5030DualAnalog( int slotParam, int sinChannelParam, int cosChannelParam)
{
sinChannel = new AnalogChannel( slotParam, sinChannelParam );
cosChannel = new AnalogChannel( slotParam, cosChannelParam );
}
protected double getCos()
{
return cosChannel.getVoltage() - biasVoltage;
}
protected double getSin()
{
return sinChannel.getVoltage() - biasVoltage;
}
public double getAngle()
{
// calculate the angle
double theta = MathUtils.atan2( getSin(), getCos() );
// convert to degrees
return Math.toDegrees(theta) + 180.0;
}
/**
* Get the angle of the encoder for use with PIDControllers
* @return the current angle according to the encoder
*/
public double pidGet() {
return getAngle();
}
}
Give them a try.