Lab_interaccio/2013/dsPin_example/dSPIN_support.ino
2025-02-25 21:29:42 +01:00

168 lines
7.1 KiB
C++

//dSPIN_support.ino - Contains functions used to implement the high-level commands,
// as well as utility functions for converting real-world units (eg, steps/s) to
// values usable by the dsPIN controller. Also contains the specialized configuration
// function for the dsPIN chip and the onboard peripherals needed to use it.
// The value in the ACC register is [(steps/s/s)*(tick^2)]/(2^-40) where tick is
// 250ns (datasheet value)- 0x08A on boot.
// Multiply desired steps/s/s by .137438 to get an appropriate value for this register.
// This is a 12-bit value, so we need to make sure the value is at or below 0xFFF.
unsigned long AccCalc(float stepsPerSecPerSec)
{
float temp = stepsPerSecPerSec * 0.137438;
if( (unsigned long) long(temp) > 0x00000FFF) return 0x00000FFF;
else return (unsigned long) long(temp);
}
// The calculation for DEC is the same as for ACC. Value is 0x08A on boot.
// This is a 12-bit value, so we need to make sure the value is at or below 0xFFF.
unsigned long DecCalc(float stepsPerSecPerSec)
{
float temp = stepsPerSecPerSec * 0.137438;
if( (unsigned long) long(temp) > 0x00000FFF) return 0x00000FFF;
else return (unsigned long) long(temp);
}
// The value in the MAX_SPD register is [(steps/s)*(tick)]/(2^-18) where tick is
// 250ns (datasheet value)- 0x041 on boot.
// Multiply desired steps/s by .065536 to get an appropriate value for this register
// This is a 10-bit value, so we need to make sure it remains at or below 0x3FF
unsigned long MaxSpdCalc(float stepsPerSec)
{
float temp = stepsPerSec * .065536;
if( (unsigned long) long(temp) > 0x000003FF) return 0x000003FF;
else return (unsigned long) long(temp);
}
// The value in the MIN_SPD register is [(steps/s)*(tick)]/(2^-24) where tick is
// 250ns (datasheet value)- 0x000 on boot.
// Multiply desired steps/s by 4.1943 to get an appropriate value for this register
// This is a 12-bit value, so we need to make sure the value is at or below 0xFFF.
unsigned long MinSpdCalc(float stepsPerSec)
{
float temp = stepsPerSec * 4.1943;
if( (unsigned long) long(temp) > 0x00000FFF) return 0x00000FFF;
else return (unsigned long) long(temp);
}
// The value in the FS_SPD register is ([(steps/s)*(tick)]/(2^-18))-0.5 where tick is
// 250ns (datasheet value)- 0x027 on boot.
// Multiply desired steps/s by .065536 and subtract .5 to get an appropriate value for this register
// This is a 10-bit value, so we need to make sure the value is at or below 0x3FF.
unsigned long FSCalc(float stepsPerSec)
{
float temp = (stepsPerSec * .065536)-.5;
if( (unsigned long) long(temp) > 0x000003FF) return 0x000003FF;
else return (unsigned long) long(temp);
}
// The value in the INT_SPD register is [(steps/s)*(tick)]/(2^-24) where tick is
// 250ns (datasheet value)- 0x408 on boot.
// Multiply desired steps/s by 4.1943 to get an appropriate value for this register
// This is a 14-bit value, so we need to make sure the value is at or below 0x3FFF.
unsigned long IntSpdCalc(float stepsPerSec)
{
float temp = stepsPerSec * 4.1943;
if( (unsigned long) long(temp) > 0x00003FFF) return 0x00003FFF;
else return (unsigned long) long(temp);
}
// When issuing RUN command, the 20-bit speed is [(steps/s)*(tick)]/(2^-28) where tick is
// 250ns (datasheet value).
// Multiply desired steps/s by 67.106 to get an appropriate value for this register
// This is a 20-bit value, so we need to make sure the value is at or below 0xFFFFF.
unsigned long SpdCalc(float stepsPerSec)
{
float temp = stepsPerSec * 67.106;
if( (unsigned long) long(temp) > 0x000FFFFF) return 0x000FFFFF;
else return (unsigned long)temp;
}
// Generalization of the subsections of the register read/write functionality.
// We want the end user to just write the value without worrying about length,
// so we pass a bit length parameter from the calling function.
unsigned long dSPIN_Param(unsigned long value, byte bit_len)
{
unsigned long ret_val=0; // We'll return this to generalize this function
// for both read and write of registers.
byte byte_len = bit_len/8; // How many BYTES do we have?
if (bit_len%8 > 0) byte_len++; // Make sure not to lose any partial byte values.
// Let's make sure our value has no spurious bits set, and if the value was too
// high, max it out.
unsigned long mask = 0xffffffff >> (32-bit_len);
if (value > mask) value = mask;
// The following three if statements handle the various possible byte length
// transfers- it'll be no less than 1 but no more than 3 bytes of data.
// dSPIN_Xfer() sends a byte out through SPI and returns a byte received
// over SPI- when calling it, we typecast a shifted version of the masked
// value, then we shift the received value back by the same amount and
// store it until return time.
if (byte_len == 3) {
ret_val |= dSPIN_Xfer((byte)(value>>16)) << 16;
//Serial.println(ret_val, HEX);
}
if (byte_len >= 2) {
ret_val |= dSPIN_Xfer((byte)(value>>8)) << 8;
//Serial.println(ret_val, HEX);
}
if (byte_len >= 1) {
ret_val |= dSPIN_Xfer((byte)value);
//Serial.println(ret_val, HEX);
}
// Return the received values. Mask off any unnecessary bits, just for
// the sake of thoroughness- we don't EXPECT to see anything outside
// the bit length range but better to be safe than sorry.
return (ret_val & mask);
}
// This simple function shifts a byte out over SPI and receives a byte over
// SPI. Unusually for SPI devices, the dSPIN requires a toggling of the
// CS (slaveSelect) pin after each byte sent. That makes this function
// a bit more reasonable, because we can include more functionality in it.
byte dSPIN_Xfer(byte data)
{
byte data_out;
digitalWrite(SLAVE_SELECT_PIN,LOW);
// SPI.transfer() both shifts a byte out on the MOSI pin AND receives a
// byte in on the MISO pin.
data_out = SPI.transfer(data);
digitalWrite(SLAVE_SELECT_PIN,HIGH);
return data_out;
}
// This is the generic initialization function to set up the Arduino to
// communicate with the dSPIN chip.
void dSPIN_init()
{
// set up the input/output pins for the application.
pinMode(10, OUTPUT); // The SPI peripheral REQUIRES the hardware SS pin-
// pin 10- to be an output. This is in here just
// in case some future user makes something other
// than pin 10 the SS pin.
pinMode(SLAVE_SELECT_PIN, OUTPUT);
digitalWrite(SLAVE_SELECT_PIN, HIGH);
pinMode(MOSI, OUTPUT);
pinMode(MISO, INPUT);
pinMode(SCK, OUTPUT);
pinMode(dSPIN_BUSYN, INPUT);
pinMode(dSPIN_RESET, OUTPUT);
// reset the dSPIN chip. This could also be accomplished by
// calling the "dSPIN_ResetDev()" function after SPI is initialized.
digitalWrite(dSPIN_RESET, HIGH);
delay(1);
digitalWrite(dSPIN_RESET, LOW);
delay(1);
digitalWrite(dSPIN_RESET, HIGH);
delay(1);
// initialize SPI for the dSPIN chip's needs:
// most significant bit first,
// SPI clock not to exceed 5MHz,
// SPI_MODE3 (clock idle high, latch data on rising edge of clock)
SPI.begin();
SPI.setBitOrder(MSBFIRST);
SPI.setClockDivider(SPI_CLOCK_DIV16); // or 2, 8, 16, 32, 64
SPI.setDataMode(SPI_MODE3);
}