-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathdSPIN_support.c
202 lines (171 loc) · 7.28 KB
/
dSPIN_support.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
#include <cstdio>
#include <errno.h>
#include "dSPIN.h"
//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.
// 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.
// This is SPI_MODE3 (clock idle high, latch data on rising edge of clock)
// MSB is first.
byte dSPIN_Xfer(byte data)
{
digitalWrite(dSPIN_CS, LOW);
for(int i=0; i<8; i++){
digitalWrite(dSPIN_CLK, LOW);
if(data & 0x80){
digitalWrite(dSPIN_MOSI, HIGH);
}else{
digitalWrite(dSPIN_MOSI, LOW);
}
delayMicroseconds( dSPIN_SPI_CLOCK_DELAY/2 );
data <<= 1;
if(digitalRead(dSPIN_MISO))
data |= 1;
digitalWrite(dSPIN_CLK, HIGH);
delayMicroseconds( dSPIN_SPI_CLOCK_DELAY/2 );
}
digitalWrite(dSPIN_CS, HIGH);
delayMicroseconds( dSPIN_SPI_CLOCK_DELAY );
return data;
}
// 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 is the generic initialization function to set up the Arduino to
// communicate with the dSPIN chip.
int dSPIN_init()
{
int err = 0;
err = wiringPiSetupGpio();
// set up the input/output pins for the application.
pinMode(dSPIN_BUSYN, INPUT);
pinMode(dSPIN_RESET, OUTPUT);
pinMode(dSPIN_CS, OUTPUT);
digitalWrite(dSPIN_CS, HIGH);
if( err !=0){
fprintf(stderr, "wiringPi Setup failed with Error %x\n", err);
return dSPIN_STATUS_FATAL;
}
// initialize SPI for the dSPIN chip's needs:
// most significant bit first,
// SPI clock not to exceed 5MHz,
pinMode(dSPIN_MOSI, OUTPUT);
pinMode(dSPIN_MISO, INPUT);
pinMode(dSPIN_CLK, OUTPUT);
//SPI_MODE3 (clock idle high, latch data on rising edge of clock)
digitalWrite(dSPIN_CLK, HIGH);
// reset the dSPIN chip. This could also be accomplished by
// calling the "dSPIN_ResetDev()" function after SPI is initialized.
digitalWrite(dSPIN_RESET, HIGH);
delay(2);
digitalWrite(dSPIN_RESET, LOW);
delay(2);
digitalWrite(dSPIN_RESET, HIGH);
delay(2);
return 0;
}