├── .gitignore ├── README.md ├── examples ├── SparkFunGetSetParamTest │ └── SparkFunGetSetParamTest.ino ├── SparkFunLibraryTest │ ├── SparkFunLibraryTest.ino │ ├── SparkFunnotes.h │ ├── SparkFunsupportFunctions.ino │ └── SparkFunwantYouGone.ino ├── SparkFundSPINexample │ ├── SparkFunL6470.h │ ├── SparkFundSPINcommands.ino │ ├── SparkFundSPINexample.ino │ └── SparkFundSPINsupport.ino └── gantry │ └── gantry.ino ├── keywords.txt ├── library.properties └── src ├── .vimproject ├── SparkFunAutoDriver.cpp ├── SparkFunAutoDriver.h ├── SparkFunAutoDriverCommands.cpp ├── SparkFunAutoDriverConfig.cpp ├── SparkFunAutoDriverSupport.cpp └── SparkFundSPINConstants.h /.gitignore: -------------------------------------------------------------------------------- 1 | # EAGLE created backup files # 2 | *.s#? 3 | *.b#? 4 | *.ods 5 | *.csv 6 | *.epf -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | SparkFun AutoDriver Arduino Library 2 | ========== 3 | [![AutoDriver](https://dlnmh9ip6v2uc.cloudfront.net/images/products/1/1/6/1/1/11611-01_medium.jpg) 4 | *AutoDriver (BOB-13752)*](https://www.sparkfun.com/products/13752) 5 | 6 | The AutoDriver is a bipolar stepper driver based on the ST Micro L6470 chip. 7 | It allows a processor to control a single 3A bipolar stepper motor across an 8-45V supply range. 8 | 9 | Repository Contents 10 | ------------------- 11 | * **src** - Contains the source for the Arduino library. 12 | * **Examples** - Example sketches demonstrating the use of the library 13 | * **keywords.txt** - List of words to be highlighted by the Arduino IDE 14 | * **library.properties** - Used by the Arduino package manager 15 | 16 | Documentation 17 | ------------------- 18 | * **[Installing an Arduino Library Guide](https://learn.sparkfun.com/tutorials/installing-an-arduino-library)** - Basic information on how to install an Arduino library. 19 | * **[Product Repository](https://github.com/sparkfun/L6470-AutoDriver)** - Main repository (including hardware files) for the AutoDriver board. 20 | * **[Hookup Guide](https://learn.sparkfun.com/tutorials/getting-started-with-the-autodriver---v13)** - Basic hookup guide for the AutoDriver board. 21 | 22 | Version History 23 | ------------------- 24 | 25 | * [v 1.0.0](https://github.com/sparkfun/SparkFun_AutoDriver_Arduino_Library/tree/V_1.0.0) - Initial release 26 | * [v 1.3.0](https://github.com/sparkfun/SparkFun_AutoDriver_Arduino_Library/tree/V_1.3.0) - Library release for V 1.3 27 | 28 | License Information 29 | ------------------- 30 | This product is open source! 31 | The code is beerware; if you see me (or any other SparkFun employee) at the local, and you've found our code helpful, please buy us a round! 32 | Please use, reuse, and modify these files as you see fit. Please maintain attribution to SparkFun Electronics and release anything derivative under the same license. 33 | 34 | Distributed as-is; no warranty is given. 35 | 36 | - Your friends at SparkFun. 37 | 38 | -------------------------------------------------------------------------------- /examples/SparkFunGetSetParamTest/SparkFunGetSetParamTest.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | /* Test sketch that just gets and sets values on a L6470 AutoDriver 5 | * 6 | * This is mainly a test to make sure that getting a value after setting returns 7 | * the same result. This is a useful test that should be run whenever the library is changed. 8 | */ 9 | 10 | AutoDriver board(0, 10, 6); 11 | String name = ""; 12 | unsigned long temp; 13 | boolean tempBool; 14 | byte tempByte; 15 | float tempFloat; 16 | int tempInt; 17 | int tempInt2; 18 | boolean pass = true; 19 | 20 | void setup() 21 | { 22 | Serial.begin(9600); 23 | // Start by setting up the pins and the SPI peripheral. 24 | // The library doesn't do this for you! 25 | pinMode(6, OUTPUT); 26 | pinMode(MOSI, OUTPUT); 27 | pinMode(MISO, INPUT); 28 | pinMode(13, OUTPUT); 29 | pinMode(10, OUTPUT); 30 | digitalWrite(10, HIGH); 31 | digitalWrite(6, LOW); 32 | digitalWrite(6, HIGH); 33 | SPI.begin(); 34 | SPI.setDataMode(SPI_MODE3); 35 | 36 | // Tell the Autodriver object which SPI port you want to use. Some 37 | // devices may have more than one. 38 | board.SPIPortConnect(&SPI); 39 | 40 | // first check board config register, should be 0x2E88 on bootup 41 | temp = board.getParam(CONFIG); 42 | Serial.print("Config reg value: "); 43 | Serial.println(temp, HEX); 44 | 45 | // Now check the status of the board. Should be 0x7c03 46 | temp = board.getStatus(); 47 | Serial.print("Status reg value: "); 48 | Serial.println(temp, HEX); 49 | 50 | // set and get all configuration values here to make sure the 51 | // conversions are working and comms are up properly. 52 | name = "LoSpdOpt"; 53 | tempBool = board.getLoSpdOpt(); 54 | pv(tempBool); 55 | tempBool = ~tempBool; 56 | board.setLoSpdOpt(tempBool); 57 | test(tempBool, board.getLoSpdOpt()); 58 | 59 | name = "MinSpeed"; 60 | tempFloat = board.getMinSpeed(); 61 | pv(tempFloat); 62 | // be careful about rounding 63 | tempFloat = (tempFloat == 23.8418788909) ? 47.6837577818 : 23.8418788909; 64 | board.setMinSpeed(tempFloat); 65 | test(tempFloat, board.getMinSpeed()); 66 | 67 | name = "StepMode"; 68 | tempByte = board.getStepMode(); 69 | pv(tempByte); 70 | tempByte = (tempByte == 0) ? 1 : 0; 71 | board.configStepMode(tempByte); 72 | test(tempByte, board.getStepMode()); 73 | 74 | name = "MaxSpeed"; 75 | tempFloat = board.getMaxSpeed(); 76 | pv(tempFloat); 77 | // be careful about rounding 78 | tempFloat = (tempFloat == 152.587890625) ? 305.17578125 : 152.587890625; 79 | board.setMaxSpeed(tempFloat); 80 | test(tempFloat, board.getMaxSpeed()); 81 | 82 | name = "FullSpeed"; 83 | tempFloat = board.getFullSpeed(); 84 | pv(tempFloat); 85 | // be careful about rounding 86 | tempFloat = (tempFloat == 160.21728515625) ? 312.80517578125 : 160.21728515625; 87 | board.setFullSpeed(tempFloat); 88 | test(tempFloat, board.getFullSpeed()); 89 | 90 | name = "Acc"; 91 | tempFloat = board.getAcc(); 92 | pv(tempFloat); 93 | // be careful about rounding 94 | tempFloat = (tempFloat == 72.76008090920998) ? 145.52016181841995 : 72.76008090920998; 95 | board.setAcc(tempFloat); 96 | test(tempFloat, board.getAcc()); 97 | 98 | name = "Dec"; 99 | tempFloat = board.getDec(); 100 | pv(tempFloat); 101 | // be careful about rounding 102 | tempFloat = (tempFloat == 72.76008090920998) ? 145.52016181841995 : 72.76008090920998; 103 | board.setDec(tempFloat); 104 | test(tempFloat, board.getDec()); 105 | 106 | name = "OCThreshold"; 107 | tempByte = board.getOCThreshold(); 108 | pv(tempByte); 109 | tempByte = (tempByte == OC_375mA) ? OC_750mA : OC_375mA; 110 | board.setOCThreshold(tempByte); 111 | test(tempByte, board.getOCThreshold()); 112 | 113 | name = "PWMFreqDivisor"; 114 | tempInt = board.getPWMFreqDivisor(); 115 | tempInt2 = board.getPWMFreqMultiplier(); 116 | pv(tempInt); 117 | tempInt = (tempInt == PWM_DIV_1) ? PWM_DIV_2 : PWM_DIV_1; 118 | board.setPWMFreq(tempInt, tempInt2); 119 | test(tempInt, board.getPWMFreqDivisor()); 120 | 121 | name = "PWMFreqMultiplier"; 122 | pv(tempInt2); 123 | tempInt2 = (tempInt2 == PWM_MUL_1) ? PWM_MUL_2 : PWM_MUL_1; 124 | board.setPWMFreq(tempInt, tempInt2); 125 | test(tempInt2, board.getPWMFreqMultiplier()); 126 | 127 | name = "SlewRate"; 128 | tempInt = board.getSlewRate(); 129 | pv(tempInt); 130 | tempInt = (tempInt == SR_180V_us) ? SR_290V_us : SR_180V_us; 131 | board.setSlewRate(tempInt); 132 | test(tempInt, board.getSlewRate()); 133 | 134 | name = "OCShutdown"; 135 | tempInt = board.getOCShutdown(); 136 | pv(tempInt); 137 | tempInt = (tempInt == OC_SD_ENABLE) ? OC_SD_DISABLE : OC_SD_ENABLE; 138 | board.setOCShutdown(tempInt); 139 | test(tempInt, board.getOCShutdown()); 140 | 141 | name = "VoltageComp"; 142 | tempInt = board.getVoltageComp(); 143 | pv(tempInt); 144 | tempInt = (tempInt == VS_COMP_ENABLE) ? VS_COMP_DISABLE : VS_COMP_ENABLE; 145 | board.setVoltageComp(tempInt); 146 | test(tempInt, board.getVoltageComp()); 147 | 148 | name = "SwitchMode"; 149 | tempInt = board.getSwitchMode(); 150 | pv(tempInt); 151 | tempInt = (tempInt == SW_USER) ? VS_COMP_DISABLE : SW_HARD_STOP; 152 | board.setSwitchMode(tempInt); 153 | test(tempInt, board.getSwitchMode()); 154 | 155 | name = "OscMode"; 156 | tempInt = board.getOscMode(); 157 | pv(tempInt); 158 | tempInt = (tempInt == INT_16MHZ) ? INT_16MHZ_OSCOUT_2MHZ : INT_16MHZ; 159 | board.setOscMode(tempInt); 160 | test(tempInt, board.getOscMode()); 161 | 162 | name = "AccK"; 163 | tempByte = board.getAccKVAL(); 164 | pv(tempByte); 165 | tempByte = (tempByte == 0) ? 1 : 0; 166 | board.setAccKVAL(tempByte); 167 | test(tempByte, board.getAccKVAL()); 168 | 169 | name = "DecK"; 170 | tempByte = board.getDecKVAL(); 171 | pv(tempByte); 172 | tempByte = (tempByte == 0) ? 1 : 0; 173 | board.setDecKVAL(tempByte); 174 | test(tempByte, board.getDecKVAL()); 175 | 176 | name = "RunK"; 177 | tempByte = board.getRunKVAL(); 178 | pv(tempByte); 179 | tempByte = (tempByte == 0) ? 1 : 0; 180 | board.setRunKVAL(tempByte); 181 | test(tempByte, board.getRunKVAL()); 182 | 183 | name = "HoldK"; 184 | tempByte = board.getHoldKVAL(); 185 | pv(tempByte); 186 | tempByte = (tempByte == 0) ? 1 : 0; 187 | board.setHoldKVAL(tempByte); 188 | test(tempByte, board.getHoldKVAL()); 189 | 190 | Serial.print("Passed? "); 191 | Serial.println(pass); 192 | } 193 | 194 | void loop() 195 | { 196 | // do nothing 197 | } 198 | 199 | void pv(float v) 200 | { 201 | Serial.print(name + " "); 202 | Serial.println(v, DEC); 203 | } 204 | 205 | void pv(bool v) 206 | { 207 | Serial.print(name + " "); 208 | Serial.println(v); 209 | } 210 | 211 | void pv(byte v) 212 | { 213 | Serial.print(name + " "); 214 | Serial.println(v, DEC); 215 | } 216 | 217 | void pv(unsigned long v) 218 | { 219 | Serial.print(name + " "); 220 | Serial.println(v, DEC); 221 | } 222 | 223 | void pv(int v) 224 | { 225 | Serial.print(name + " "); 226 | Serial.println(v, DEC); 227 | } 228 | 229 | void test(float v1, float v2) 230 | { 231 | if (abs(v1-v2) > 0.1) 232 | { 233 | Serial.println("!!! " + name + " failed"); 234 | Serial.print("Expected "); 235 | Serial.println(v1, DEC); 236 | Serial.print("Got "); 237 | Serial.println(v2, DEC); 238 | pass = false; 239 | } 240 | else 241 | { 242 | Serial.println(name + " passed r/w test!"); 243 | } 244 | } 245 | 246 | void test(int v1, int v2) 247 | { 248 | if (v1 != v2) 249 | { 250 | Serial.println("!!! " + name + " failed"); 251 | Serial.print("Expected "); 252 | Serial.println(v1, DEC); 253 | Serial.print("Got "); 254 | Serial.println(v2, DEC); 255 | pass = false; 256 | } 257 | else 258 | { 259 | Serial.println(name + " passed r/w test!"); 260 | } 261 | } 262 | 263 | void test(bool v1, bool v2) 264 | { 265 | if (v1 != v2) 266 | { 267 | Serial.println("!!! " + name + " failed"); 268 | Serial.print("Expected "); 269 | Serial.println(v1); 270 | Serial.print("Got "); 271 | Serial.println(v2); 272 | pass = false; 273 | } 274 | else 275 | { 276 | Serial.println(name + " passed r/w test!"); 277 | } 278 | } 279 | 280 | 281 | 282 | -------------------------------------------------------------------------------- /examples/SparkFunLibraryTest/SparkFunLibraryTest.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "SparkFunnotes.h" 4 | 5 | // Test sketch for the L6470 AutoDriver library. This program instantiates three 6 | // AutoDriver boards and uses them to play Jonathon Coulton's "Want You Gone" from 7 | // the Portal 2 soundtrack. In a more general sense, it adds support for playing 8 | // music with stepper motors. Not all notes can be played, of course- at too high 9 | // a steps/sec rate, the motors will slip and dogs and cats will live together. 10 | 11 | 12 | // Create our AutoDriver instances. The parameters are the position in the chain of 13 | // boards (with board 0 being located at the end of the chain, farthest from the 14 | // controlling processor), CS pin, and reset pin. 15 | AutoDriver boardA(0, 10, 6); 16 | AutoDriver boardB(1, 10, 6); 17 | 18 | void setup() 19 | { 20 | Serial.begin(9600); 21 | Serial.println("Hello world"); 22 | // Start by setting up the SPI port and pins. The 23 | // Autodriver library does not do this for you! 24 | pinMode(6, OUTPUT); 25 | pinMode(MOSI, OUTPUT); 26 | pinMode(MISO, INPUT); 27 | pinMode(13, OUTPUT); 28 | pinMode(10, OUTPUT); 29 | digitalWrite(10, HIGH); 30 | digitalWrite(6, LOW); // This low/high is a reset of the L6470 chip on the 31 | digitalWrite(6, HIGH); // Autodriver board, and is a good thing to do at 32 | // the start of any Autodriver sketch, to be sure 33 | // you're starting the Autodriver from a known state. 34 | SPI.begin(); 35 | SPI.setDataMode(SPI_MODE3); 36 | dSPINConfig(); 37 | } 38 | 39 | // loop() waits for a character- any character- and then plays the song. 40 | void loop() 41 | { 42 | if (Serial.available() !=0) 43 | { 44 | Serial.read(); 45 | Serial.println("Play it!"); 46 | wantYouGone(); 47 | Serial.println("Done playing!"); 48 | } 49 | } 50 | 51 | 52 | -------------------------------------------------------------------------------- /examples/SparkFunLibraryTest/SparkFunnotes.h: -------------------------------------------------------------------------------- 1 | // Frequencies for pretty much an entire piano keyboard. 2 | 3 | #define noteC0 16 4 | #define noteCs0 17 5 | #define noteDb0 17 6 | #define noteD0 18 7 | #define noteDs0 19 8 | #define noteEb0 19 9 | #define noteE0 21 10 | #define noteF0 22 11 | #define noteFs0 23 12 | #define noteGb0 23 13 | #define noteG0 25 14 | #define noteGs0 26 15 | #define noteAb0 26 16 | #define noteA0 28 17 | #define noteAs0 29 18 | #define noteBb0 29 19 | #define noteB0 31 20 | #define noteC1 33 21 | #define noteCs1 35 22 | #define noteDb1 35 23 | #define noteD1 37 24 | #define noteDs1 39 25 | #define noteEb1 39 26 | #define noteE1 41 27 | #define noteF1 44 28 | #define noteFs1 46 29 | #define noteGb1 46 30 | #define noteG1 49 31 | #define noteGs1 52 32 | #define noteAb1 52 33 | #define noteA1 55 34 | #define noteAs1 58 35 | #define noteBb1 58 36 | #define noteB1 62 37 | #define noteC2 65 38 | #define noteCs2 69 39 | #define noteDb2 69 40 | #define noteD2 73 41 | #define noteDs2 78 42 | #define noteEb2 78 43 | #define noteE2 82 44 | #define noteF2 87 45 | #define noteFs2 93 46 | #define noteGb2 93 47 | #define noteG2 98 48 | #define noteGs2 104 49 | #define noteAb2 104 50 | #define noteA2 110 51 | #define noteAs2 117 52 | #define noteBb2 117 53 | #define noteB2 123 54 | #define noteC3 131 55 | #define noteCs3 139 56 | #define noteDb3 139 57 | #define noteD3 147 58 | #define noteDs3 156 59 | #define noteEb3 156 60 | #define noteE3 165 61 | #define noteF3 175 62 | #define noteFs3 185 63 | #define noteGb3 185 64 | #define noteG3 196 65 | #define noteGs3 208 66 | #define noteAb3 208 67 | #define noteA3 220 68 | #define noteAs3 233 69 | #define noteBb3 233 70 | #define noteB3 247 71 | #define noteC4 262 72 | #define noteCs4 277 73 | #define noteDb4 277 74 | #define noteD4 294 75 | #define noteDs4 311 76 | #define noteEb4 311 77 | #define noteE4 330 78 | #define noteF4 349 79 | #define noteFs4 370 80 | #define noteGb4 370 81 | #define noteG4 392 82 | #define noteGs4 415 83 | #define noteAb4 415 84 | #define noteA4 440 85 | #define noteAs4 466 86 | #define noteBb4 466 87 | #define noteB4 494 88 | #define noteC5 523 89 | #define noteCs5 554 90 | #define noteDb5 554 91 | #define noteD5 587 92 | #define noteDs5 622 93 | #define noteEb5 622 94 | #define noteE5 659 95 | #define noteF5 698 96 | #define noteFs5 740 97 | #define noteGb5 740 98 | #define noteG5 784 99 | #define noteGs5 831 100 | #define noteAb5 831 101 | #define noteA5 880 102 | #define noteAs5 932 103 | #define noteBb5 932 104 | #define noteB5 988 105 | #define noteC6 1047 106 | #define noteCs6 1109 107 | #define noteDb6 1109 108 | #define noteD6 1175 109 | #define noteDs6 1245 110 | #define noteEb6 1245 111 | #define noteE6 1319 112 | #define noteF6 1397 113 | #define noteFs6 1480 114 | #define noteGb6 1480 115 | #define noteG6 1568 116 | #define noteGs6 1661 117 | #define noteAb6 1661 118 | #define noteA6 1760 119 | #define noteAs6 1865 120 | #define noteBb6 1865 121 | #define noteB6 1976 122 | #define noteC7 2093 123 | #define noteCs7 2217 124 | #define noteDb7 2217 125 | #define noteD7 2349 126 | #define noteDs7 2489 127 | #define noteEb7 2489 128 | #define noteE7 2637 129 | #define noteF7 2794 130 | #define noteFs7 2960 131 | #define noteGb7 2960 132 | #define noteG7 3136 133 | #define noteGs7 3322 134 | #define noteAb7 3322 135 | #define noteA7 3520 136 | #define noteAs7 3729 137 | #define noteBb7 3729 138 | #define noteB7 3951 139 | #define noteC8 4186 140 | #define noteCs8 4435 141 | #define noteDb8 4435 142 | #define noteD8 4699 143 | #define noteDs8 4978 144 | #define noteEb8 4978 145 | -------------------------------------------------------------------------------- /examples/SparkFunLibraryTest/SparkFunsupportFunctions.ino: -------------------------------------------------------------------------------- 1 | // Support functions. 2 | 3 | #define NOTE_DIVISOR 2 // My cheesy way of reducing the note frequencies to a range 4 | // that doesn't cause the motor to slip. I *could* rewrite 5 | // the wantYouGone() function to change the notes, but that 6 | // would be a lot of work. 7 | 8 | int stepDir = 1; // Direction flipping bit. Rather than all going one way, 9 | // they change directions. It looks cooler. 10 | 11 | // To play a note, we start the motor spinning at the note's frequency in steps/s. 12 | // The run() function automagically calculates the appropriate value to feed to the 13 | // dSPIN part based on the desired steps/s. 14 | void playNote(int note, int duration) 15 | { 16 | if (stepDir == 1) boardA.run(FWD, note/NOTE_DIVISOR); 17 | else boardA.run(REV, note/NOTE_DIVISOR); 18 | if (stepDir == 1) boardB.run(REV, note/NOTE_DIVISOR); 19 | else boardB.run(FWD, note/NOTE_DIVISOR); 20 | delay(duration); 21 | stepDir*=-1; 22 | boardA.softStop(); 23 | boardB.softStop(); 24 | while (boardA.busyCheck()); 25 | } 26 | 27 | // This is the configuration function for the two dSPIN parts. Read the inline 28 | // comments for more info. 29 | void dSPINConfig(void) 30 | { 31 | boardA.SPIPortConnect(&SPI); // Before doing anything else, we need to 32 | boardB.SPIPortConnect(&SPI); // tell the objects which SPI port to use. 33 | // Some devices may have more than one. 34 | 35 | boardA.configSyncPin(BUSY_PIN, 0);// BUSY pin low during operations; 36 | // second paramter ignored. 37 | boardA.configStepMode(STEP_FS); // 0 microsteps per step 38 | boardA.setMaxSpeed(10000); // 10000 steps/s max 39 | boardA.setFullSpeed(10000); // microstep below 10000 steps/s 40 | boardA.setAcc(10000); // accelerate at 10000 steps/s/s 41 | boardA.setDec(10000); 42 | boardA.setSlewRate(SR_530V_us); // Upping the edge speed increases torque. 43 | boardA.setOCThreshold(OC_750mA); // OC threshold 750mA 44 | boardA.setPWMFreq(PWM_DIV_2, PWM_MUL_2); // 31.25kHz PWM freq 45 | boardA.setOCShutdown(OC_SD_DISABLE); // don't shutdown on OC 46 | boardA.setVoltageComp(VS_COMP_DISABLE); // don't compensate for motor V 47 | boardA.setSwitchMode(SW_USER); // Switch is not hard stop 48 | boardA.setOscMode(EXT_16MHZ_OSCOUT_INVERT); // for boardA, we want 16MHz 49 | // external osc, 16MHz out. boardB 50 | // will be the same in all respects 51 | // but this, as it will generate the 52 | // clock. 53 | boardA.setAccKVAL(128); // We'll tinker with these later, if needed. 54 | boardA.setDecKVAL(128); 55 | boardA.setRunKVAL(128); 56 | boardA.setHoldKVAL(32); // This controls the holding current; keep it low. 57 | 58 | boardB.configSyncPin(BUSY_PIN, 0);// BUSY pin low during operations; 59 | // second paramter ignored. 60 | boardB.configStepMode(STEP_FS); // 0 microsteps per step 61 | boardB.setMaxSpeed(10000); // 10000 steps/s max 62 | boardB.setFullSpeed(10000); // microstep below 10000 steps/s 63 | boardB.setAcc(10000); // accelerate at 10000 steps/s/s 64 | boardB.setDec(10000); 65 | boardB.setSlewRate(SR_530V_us); // Upping the edge speed increases torque. 66 | boardB.setOCThreshold(OC_750mA); // OC threshold 750mA 67 | boardB.setPWMFreq(PWM_DIV_2, PWM_MUL_2); // 31.25kHz PWM freq 68 | boardB.setOCShutdown(OC_SD_DISABLE); // don't shutdown on OC 69 | boardB.setVoltageComp(VS_COMP_DISABLE); // don't compensate for motor V 70 | boardB.setSwitchMode(SW_USER); // Switch is not hard stop 71 | boardB.setOscMode(INT_16MHZ_OSCOUT_16MHZ); // for boardB, we want 16MHz 72 | // internal osc, 16MHz out. boardA 73 | // will be the same in all respects 74 | // but this, as it will bring in and 75 | // output the clock to keep them 76 | // voth in phase. 77 | boardB.setAccKVAL(128); // We'll tinker with these later, if needed. 78 | boardB.setDecKVAL(128); 79 | boardB.setRunKVAL(128); 80 | boardB.setHoldKVAL(32); // This controls the holding current; keep it low. 81 | } 82 | 83 | -------------------------------------------------------------------------------- /examples/SparkFunLibraryTest/SparkFunwantYouGone.ino: -------------------------------------------------------------------------------- 1 | // Note defines for our song. wantYouGone() should be played uptempo, 100bpm, so 2 | // each beat is 600ms long. Note lengths derive from that, and rests can be 3 | // accomplished by a delay of appropriate length. 4 | 5 | #define beatLength 600 6 | #define WN beatLength*4 7 | #define HN beatLength*2 8 | #define QN beatLength 9 | #define EN beatLength/2 10 | #define SN beatLength/4 11 | 12 | void wantYouGone(void) 13 | { 14 | delay(EN); 15 | playNote(noteE5, EN); 16 | playNote(noteA5, EN); 17 | playNote(noteB5, EN); 18 | playNote(noteCs6, EN+SN); 19 | playNote(noteD6, SN); 20 | playNote(noteCs6, QN); 21 | 22 | delay(EN); 23 | playNote(noteA5, EN); 24 | playNote(noteA5, EN); 25 | playNote(noteE5, EN); 26 | playNote(noteB5, EN); 27 | playNote(noteA5, EN); 28 | playNote(noteG5, EN); 29 | playNote(noteA5, EN); 30 | 31 | delay(EN+SN); 32 | playNote(noteE5, SN); 33 | playNote(noteA5, EN); 34 | playNote(noteB5, EN); 35 | playNote(noteCs6, EN); 36 | playNote(noteD6, EN); 37 | playNote(noteCs6, EN); 38 | playNote(noteB5, EN); 39 | 40 | playNote(noteA5, QN); 41 | playNote(noteB5, EN); 42 | playNote(noteG5, EN); 43 | playNote(noteG5, QN); 44 | delay(HN); 45 | 46 | delay(EN); 47 | playNote(noteE5, EN); 48 | playNote(noteA5, EN); 49 | playNote(noteB5, EN); 50 | playNote(noteCs6,EN+SN); 51 | playNote(noteD6,SN); 52 | playNote(noteCs6, QN); 53 | 54 | delay(EN); 55 | playNote(noteA5, EN); 56 | playNote(noteA5, EN); 57 | playNote(noteE5, EN); 58 | playNote(noteB5, EN); 59 | playNote(noteA5, EN); 60 | playNote(noteG5, EN); 61 | playNote(noteA5, EN); 62 | 63 | delay(EN); 64 | playNote(noteE5, EN); 65 | playNote(noteA5, EN); 66 | playNote(noteB5, EN); 67 | playNote(noteCs6, EN); 68 | playNote(noteD6, EN); 69 | playNote(noteCs6, EN); 70 | playNote(noteB5, EN); 71 | 72 | playNote(noteA5, QN); 73 | playNote(noteFs6, QN); 74 | playNote(noteE6, EN); 75 | playNote(noteCs6, EN); 76 | playNote(noteB5, EN); 77 | playNote(noteAs5, EN+SN); 78 | } 79 | -------------------------------------------------------------------------------- /examples/SparkFundSPINexample/SparkFunL6470.h: -------------------------------------------------------------------------------- 1 | 2 | // constant definitions for overcurrent thresholds. Write these values to 3 | // register dSPIN_OCD_TH to set the level at which an overcurrent even occurs. 4 | #define dSPIN_OCD_TH_375mA 0x00 5 | #define dSPIN_OCD_TH_750mA 0x01 6 | #define dSPIN_OCD_TH_1125mA 0x02 7 | #define dSPIN_OCD_TH_1500mA 0x03 8 | #define dSPIN_OCD_TH_1875mA 0x04 9 | #define dSPIN_OCD_TH_2250mA 0x05 10 | #define dSPIN_OCD_TH_2625mA 0x06 11 | #define dSPIN_OCD_TH_3000mA 0x07 12 | #define dSPIN_OCD_TH_3375mA 0x08 13 | #define dSPIN_OCD_TH_3750mA 0x09 14 | #define dSPIN_OCD_TH_4125mA 0x0A 15 | #define dSPIN_OCD_TH_4500mA 0x0B 16 | #define dSPIN_OCD_TH_4875mA 0x0C 17 | #define dSPIN_OCD_TH_5250mA 0x0D 18 | #define dSPIN_OCD_TH_5625mA 0x0E 19 | #define dSPIN_OCD_TH_6000mA 0x0F 20 | 21 | // STEP_MODE option values. 22 | // First comes the "microsteps per step" options... 23 | #define dSPIN_STEP_MODE_STEP_SEL 0x07 // Mask for these bits only. 24 | #define dSPIN_STEP_SEL_1 0x00 25 | #define dSPIN_STEP_SEL_1_2 0x01 26 | #define dSPIN_STEP_SEL_1_4 0x02 27 | #define dSPIN_STEP_SEL_1_8 0x03 28 | #define dSPIN_STEP_SEL_1_16 0x04 29 | #define dSPIN_STEP_SEL_1_32 0x05 30 | #define dSPIN_STEP_SEL_1_64 0x06 31 | #define dSPIN_STEP_SEL_1_128 0x07 32 | 33 | // ...next, define the SYNC_EN bit. When set, the BUSYN pin will instead 34 | // output a clock related to the full-step frequency as defined by the 35 | // SYNC_SEL bits below. 36 | #define dSPIN_STEP_MODE_SYNC_EN 0x80 // Mask for this bit 37 | #define dSPIN_SYNC_EN 0x80 38 | 39 | // ...last, define the SYNC_SEL modes. The clock output is defined by 40 | // the full-step frequency and the value in these bits- see the datasheet 41 | // for a matrix describing that relationship (page 46). 42 | #define dSPIN_STEP_MODE_SYNC_SEL 0x70 43 | #define dSPIN_SYNC_SEL_1_2 0x00 44 | #define dSPIN_SYNC_SEL_1 0x10 45 | #define dSPIN_SYNC_SEL_2 0x20 46 | #define dSPIN_SYNC_SEL_4 0x30 47 | #define dSPIN_SYNC_SEL_8 0x40 48 | #define dSPIN_SYNC_SEL_16 0x50 49 | #define dSPIN_SYNC_SEL_32 0x60 50 | #define dSPIN_SYNC_SEL_64 0x70 51 | 52 | // Bit names for the ALARM_EN register. 53 | // Each of these bits defines one potential alarm condition. 54 | // When one of these conditions occurs and the respective bit in ALARM_EN is set, 55 | // the FLAG pin will go low. The register must be queried to determine which event 56 | // caused the alarm. 57 | #define dSPIN_ALARM_EN_OVERCURRENT 0x01 58 | #define dSPIN_ALARM_EN_THERMAL_SHUTDOWN 0x02 59 | #define dSPIN_ALARM_EN_THERMAL_WARNING 0x04 60 | #define dSPIN_ALARM_EN_UNDER_VOLTAGE 0x08 61 | #define dSPIN_ALARM_EN_STALL_DET_A 0x10 62 | #define dSPIN_ALARM_EN_STALL_DET_B 0x20 63 | #define dSPIN_ALARM_EN_SW_TURN_ON 0x40 64 | #define dSPIN_ALARM_EN_WRONG_NPERF_CMD 0x80 65 | 66 | // CONFIG register renames. 67 | 68 | // Oscillator options. 69 | // The dSPIN needs to know what the clock frequency is because it uses that for some 70 | // calculations during operation. 71 | #define dSPIN_CONFIG_OSC_SEL 0x000F // Mask for this bit field. 72 | #define dSPIN_CONFIG_INT_16MHZ 0x0000 // Internal 16MHz, no output 73 | #define dSPIN_CONFIG_INT_16MHZ_OSCOUT_2MHZ 0x0008 // Default; internal 16MHz, 2MHz output 74 | #define dSPIN_CONFIG_INT_16MHZ_OSCOUT_4MHZ 0x0009 // Internal 16MHz, 4MHz output 75 | #define dSPIN_CONFIG_INT_16MHZ_OSCOUT_8MHZ 0x000A // Internal 16MHz, 8MHz output 76 | #define dSPIN_CONFIG_INT_16MHZ_OSCOUT_16MHZ 0x000B // Internal 16MHz, 16MHz output 77 | #define dSPIN_CONFIG_EXT_8MHZ_XTAL_DRIVE 0x0004 // External 8MHz crystal 78 | #define dSPIN_CONFIG_EXT_16MHZ_XTAL_DRIVE 0x0005 // External 16MHz crystal 79 | #define dSPIN_CONFIG_EXT_24MHZ_XTAL_DRIVE 0x0006 // External 24MHz crystal 80 | #define dSPIN_CONFIG_EXT_32MHZ_XTAL_DRIVE 0x0007 // External 32MHz crystal 81 | #define dSPIN_CONFIG_EXT_8MHZ_OSCOUT_INVERT 0x000C // External 8MHz crystal, output inverted 82 | #define dSPIN_CONFIG_EXT_16MHZ_OSCOUT_INVERT 0x000D // External 16MHz crystal, output inverted 83 | #define dSPIN_CONFIG_EXT_24MHZ_OSCOUT_INVERT 0x000E // External 24MHz crystal, output inverted 84 | #define dSPIN_CONFIG_EXT_32MHZ_OSCOUT_INVERT 0x000F // External 32MHz crystal, output inverted 85 | 86 | // Configure the functionality of the external switch input 87 | #define dSPIN_CONFIG_SW_MODE 0x0010 // Mask for this bit. 88 | #define dSPIN_CONFIG_SW_HARD_STOP 0x0000 // Default; hard stop motor on switch. 89 | #define dSPIN_CONFIG_SW_USER 0x0010 // Tie to the GoUntil and ReleaseSW 90 | // commands to provide jog function. 91 | // See page 25 of datasheet. 92 | 93 | // Configure the motor voltage compensation mode (see page 34 of datasheet) 94 | #define dSPIN_CONFIG_EN_VSCOMP 0x0020 // Mask for this bit. 95 | #define dSPIN_CONFIG_VS_COMP_DISABLE 0x0000 // Disable motor voltage compensation. 96 | #define dSPIN_CONFIG_VS_COMP_ENABLE 0x0020 // Enable motor voltage compensation. 97 | 98 | // Configure overcurrent detection event handling 99 | #define dSPIN_CONFIG_OC_SD 0x0080 // Mask for this bit. 100 | #define dSPIN_CONFIG_OC_SD_DISABLE 0x0000 // Bridges do NOT shutdown on OC detect 101 | #define dSPIN_CONFIG_OC_SD_ENABLE 0x0080 // Bridges shutdown on OC detect 102 | 103 | // Configure the slew rate of the power bridge output 104 | #define dSPIN_CONFIG_POW_SR 0x0300 // Mask for this bit field. 105 | #define dSPIN_CONFIG_SR_180V_us 0x0000 // 180V/us 106 | #define dSPIN_CONFIG_SR_290V_us 0x0200 // 290V/us 107 | #define dSPIN_CONFIG_SR_530V_us 0x0300 // 530V/us 108 | 109 | // Integer divisors for PWM sinewave generation 110 | // See page 32 of the datasheet for more information on this. 111 | #define dSPIN_CONFIG_F_PWM_DEC 0x1C00 // mask for this bit field 112 | #define dSPIN_CONFIG_PWM_MUL_0_625 (0x00)<<10 113 | #define dSPIN_CONFIG_PWM_MUL_0_75 (0x01)<<10 114 | #define dSPIN_CONFIG_PWM_MUL_0_875 (0x02)<<10 115 | #define dSPIN_CONFIG_PWM_MUL_1 (0x03)<<10 116 | #define dSPIN_CONFIG_PWM_MUL_1_25 (0x04)<<10 117 | #define dSPIN_CONFIG_PWM_MUL_1_5 (0x05)<<10 118 | #define dSPIN_CONFIG_PWM_MUL_1_75 (0x06)<<10 119 | #define dSPIN_CONFIG_PWM_MUL_2 (0x07)<<10 120 | 121 | // Multiplier for the PWM sinewave frequency 122 | #define dSPIN_CONFIG_F_PWM_INT 0xE000 // mask for this bit field. 123 | #define dSPIN_CONFIG_PWM_DIV_1 (0x00)<<13 124 | #define dSPIN_CONFIG_PWM_DIV_2 (0x01)<<13 125 | #define dSPIN_CONFIG_PWM_DIV_3 (0x02)<<13 126 | #define dSPIN_CONFIG_PWM_DIV_4 (0x03)<<13 127 | #define dSPIN_CONFIG_PWM_DIV_5 (0x04)<<13 128 | #define dSPIN_CONFIG_PWM_DIV_6 (0x05)<<13 129 | #define dSPIN_CONFIG_PWM_DIV_7 (0x06)<<13 130 | 131 | // Status register bit renames- read-only bits conferring information about the 132 | // device to the user. 133 | #define dSPIN_STATUS_HIZ 0x0001 // high when bridges are in HiZ mode 134 | #define dSPIN_STATUS_BUSY 0x0002 // mirrors BUSY pin 135 | #define dSPIN_STATUS_SW_F 0x0004 // low when switch open, high when closed 136 | #define dSPIN_STATUS_SW_EVN 0x0008 // active high, set on switch falling edge, 137 | // cleared by reading STATUS 138 | #define dSPIN_STATUS_DIR 0x0010 // Indicates current motor direction. 139 | // High is FWD, Low is REV. 140 | #define dSPIN_STATUS_NOTPERF_CMD 0x0080 // Last command not performed. 141 | #define dSPIN_STATUS_WRONG_CMD 0x0100 // Last command not valid. 142 | #define dSPIN_STATUS_UVLO 0x0200 // Undervoltage lockout is active 143 | #define dSPIN_STATUS_TH_WRN 0x0400 // Thermal warning 144 | #define dSPIN_STATUS_TH_SD 0x0800 // Thermal shutdown 145 | #define dSPIN_STATUS_OCD 0x1000 // Overcurrent detected 146 | #define dSPIN_STATUS_STEP_LOSS_A 0x2000 // Stall detected on A bridge 147 | #define dSPIN_STATUS_STEP_LOSS_B 0x4000 // Stall detected on B bridge 148 | #define dSPIN_STATUS_SCK_MOD 0x8000 // Step clock mode is active 149 | 150 | // Status register motor status field 151 | #define dSPIN_STATUS_MOT_STATUS 0x0060 // field mask 152 | #define dSPIN_STATUS_MOT_STATUS_STOPPED (0x0000)<<13 // Motor stopped 153 | #define dSPIN_STATUS_MOT_STATUS_ACCELERATION (0x0001)<<13 // Motor accelerating 154 | #define dSPIN_STATUS_MOT_STATUS_DECELERATION (0x0002)<<13 // Motor decelerating 155 | #define dSPIN_STATUS_MOT_STATUS_CONST_SPD (0x0003)<<13 // Motor at constant speed 156 | 157 | // Register address redefines. 158 | // See the dSPIN_Param_Handler() function for more info about these. 159 | #define dSPIN_ABS_POS 0x01 160 | #define dSPIN_EL_POS 0x02 161 | #define dSPIN_MARK 0x03 162 | #define dSPIN_SPEED 0x04 163 | #define dSPIN_ACC 0x05 164 | #define dSPIN_DEC 0x06 165 | #define dSPIN_MAX_SPEED 0x07 166 | #define dSPIN_MIN_SPEED 0x08 167 | #define dSPIN_FS_SPD 0x15 168 | #define dSPIN_KVAL_HOLD 0x09 169 | #define dSPIN_KVAL_RUN 0x0A 170 | #define dSPIN_KVAL_ACC 0x0B 171 | #define dSPIN_KVAL_DEC 0x0C 172 | #define dSPIN_INT_SPD 0x0D 173 | #define dSPIN_ST_SLP 0x0E 174 | #define dSPIN_FN_SLP_ACC 0x0F 175 | #define dSPIN_FN_SLP_DEC 0x10 176 | #define dSPIN_K_THERM 0x11 177 | #define dSPIN_ADC_OUT 0x12 178 | #define dSPIN_OCD_TH 0x13 179 | #define dSPIN_STALL_TH 0x14 180 | #define dSPIN_STEP_MODE 0x16 181 | #define dSPIN_ALARM_EN 0x17 182 | #define dSPIN_CONFIG 0x18 183 | #define dSPIN_STATUS 0x19 184 | 185 | //dSPIN commands 186 | #define dSPIN_NOP 0x00 187 | #define dSPIN_SET_PARAM 0x00 188 | #define dSPIN_GET_PARAM 0x20 189 | #define dSPIN_RUN 0x50 190 | #define dSPIN_STEP_CLOCK 0x58 191 | #define dSPIN_MOVE 0x40 192 | #define dSPIN_GOTO 0x60 193 | #define dSPIN_GOTO_DIR 0x68 194 | #define dSPIN_GO_UNTIL 0x82 195 | #define dSPIN_RELEASE_SW 0x92 196 | #define dSPIN_GO_HOME 0x70 197 | #define dSPIN_GO_MARK 0x78 198 | #define dSPIN_RESET_POS 0xD8 199 | #define dSPIN_RESET_DEVICE 0xC0 200 | #define dSPIN_SOFT_STOP 0xB0 201 | #define dSPIN_HARD_STOP 0xB8 202 | #define dSPIN_SOFT_HIZ 0xA0 203 | #define dSPIN_HARD_HIZ 0xA8 204 | #define dSPIN_GET_STATUS 0xD0 205 | 206 | /* dSPIN direction options */ 207 | #define FWD 0x01 208 | #define REV 0x00 209 | 210 | /* dSPIN action options */ 211 | #define ACTION_RESET 0x00 212 | #define ACTION_COPY 0x01 213 | -------------------------------------------------------------------------------- /examples/SparkFundSPINexample/SparkFundSPINcommands.ino: -------------------------------------------------------------------------------- 1 | //dSPIN_commands.ino - Contains high-level command implementations- movement 2 | // and configuration commands, for example. 3 | 4 | // Realize the "set parameter" function, to write to the various registers in 5 | // the dSPIN chip. 6 | void dSPIN_SetParam(byte param, unsigned long value) 7 | { 8 | dSPIN_Xfer(dSPIN_SET_PARAM | param); 9 | dSPIN_ParamHandler(param, value); 10 | } 11 | 12 | // Realize the "get parameter" function, to read from the various registers in 13 | // the dSPIN chip. 14 | unsigned long dSPIN_GetParam(byte param) 15 | { 16 | dSPIN_Xfer(dSPIN_GET_PARAM | param); 17 | return dSPIN_ParamHandler(param, 0); 18 | } 19 | 20 | // Much of the functionality between "get parameter" and "set parameter" is 21 | // very similar, so we deal with that by putting all of it in one function 22 | // here to save memory space and simplify the program. 23 | unsigned long dSPIN_ParamHandler(byte param, unsigned long value) 24 | { 25 | unsigned long ret_val = 0; // This is a temp for the value to return. 26 | // This switch structure handles the appropriate action for each register. 27 | // This is necessary since not all registers are of the same length, either 28 | // bit-wise or byte-wise, so we want to make sure we mask out any spurious 29 | // bits and do the right number of transfers. That is handled by the dSPIN_Param() 30 | // function, in most cases, but for 1-byte or smaller transfers, we call 31 | // dSPIN_Xfer() directly. 32 | switch (param) 33 | { 34 | // ABS_POS is the current absolute offset from home. It is a 22 bit number expressed 35 | // in two's complement. At power up, this value is 0. It cannot be written when 36 | // the motor is running, but at any other time, it can be updated to change the 37 | // interpreted position of the motor. 38 | case dSPIN_ABS_POS: 39 | ret_val = dSPIN_Param(value, 22); 40 | break; 41 | // EL_POS is the current electrical position in the step generation cycle. It can 42 | // be set when the motor is not in motion. Value is 0 on power up. 43 | case dSPIN_EL_POS: 44 | ret_val = dSPIN_Param(value, 9); 45 | break; 46 | // MARK is a second position other than 0 that the motor can be told to go to. As 47 | // with ABS_POS, it is 22-bit two's complement. Value is 0 on power up. 48 | case dSPIN_MARK: 49 | ret_val = dSPIN_Param(value, 22); 50 | break; 51 | // SPEED contains information about the current speed. It is read-only. It does 52 | // NOT provide direction information. 53 | case dSPIN_SPEED: 54 | ret_val = dSPIN_Param(0, 20); 55 | break; 56 | // ACC and DEC set the acceleration and deceleration rates. Set ACC to 0xFFF 57 | // to get infinite acceleration/decelaeration- there is no way to get infinite 58 | // deceleration w/o infinite acceleration (except the HARD STOP command). 59 | // Cannot be written while motor is running. Both default to 0x08A on power up. 60 | // AccCalc() and DecCalc() functions exist to convert steps/s/s values into 61 | // 12-bit values for these two registers. 62 | case dSPIN_ACC: 63 | ret_val = dSPIN_Param(value, 12); 64 | break; 65 | case dSPIN_DEC: 66 | ret_val = dSPIN_Param(value, 12); 67 | break; 68 | // MAX_SPEED is just what it says- any command which attempts to set the speed 69 | // of the motor above this value will simply cause the motor to turn at this 70 | // speed. Value is 0x041 on power up. 71 | // MaxSpdCalc() function exists to convert steps/s value into a 10-bit value 72 | // for this register. 73 | case dSPIN_MAX_SPEED: 74 | ret_val = dSPIN_Param(value, 10); 75 | break; 76 | // MIN_SPEED controls two things- the activation of the low-speed optimization 77 | // feature and the lowest speed the motor will be allowed to operate at. LSPD_OPT 78 | // is the 13th bit, and when it is set, the minimum allowed speed is automatically 79 | // set to zero. This value is 0 on startup. 80 | // MinSpdCalc() function exists to convert steps/s value into a 12-bit value for this 81 | // register. SetLSPDOpt() function exists to enable/disable the optimization feature. 82 | case dSPIN_MIN_SPEED: 83 | ret_val = dSPIN_Param(value, 12); 84 | break; 85 | // FS_SPD register contains a threshold value above which microstepping is disabled 86 | // and the dSPIN operates in full-step mode. Defaults to 0x027 on power up. 87 | // FSCalc() function exists to convert steps/s value into 10-bit integer for this 88 | // register. 89 | case dSPIN_FS_SPD: 90 | ret_val = dSPIN_Param(value, 10); 91 | break; 92 | // KVAL is the maximum voltage of the PWM outputs. These 8-bit values are ratiometric 93 | // representations: 255 for full output voltage, 128 for half, etc. Default is 0x29. 94 | // The implications of different KVAL settings is too complex to dig into here, but 95 | // it will usually work to max the value for RUN, ACC, and DEC. Maxing the value for 96 | // HOLD may result in excessive power dissipation when the motor is not running. 97 | case dSPIN_KVAL_HOLD: 98 | ret_val = dSPIN_Xfer((byte)value); 99 | break; 100 | case dSPIN_KVAL_RUN: 101 | ret_val = dSPIN_Xfer((byte)value); 102 | break; 103 | case dSPIN_KVAL_ACC: 104 | ret_val = dSPIN_Xfer((byte)value); 105 | break; 106 | case dSPIN_KVAL_DEC: 107 | ret_val = dSPIN_Xfer((byte)value); 108 | break; 109 | // INT_SPD, ST_SLP, FN_SLP_ACC and FN_SLP_DEC are all related to the back EMF 110 | // compensation functionality. Please see the datasheet for details of this 111 | // function- it is too complex to discuss here. Default values seem to work 112 | // well enough. 113 | case dSPIN_INT_SPD: 114 | ret_val = dSPIN_Param(value, 14); 115 | break; 116 | case dSPIN_ST_SLP: 117 | ret_val = dSPIN_Xfer((byte)value); 118 | break; 119 | case dSPIN_FN_SLP_ACC: 120 | ret_val = dSPIN_Xfer((byte)value); 121 | break; 122 | case dSPIN_FN_SLP_DEC: 123 | ret_val = dSPIN_Xfer((byte)value); 124 | break; 125 | // K_THERM is motor winding thermal drift compensation. Please see the datasheet 126 | // for full details on operation- the default value should be okay for most users. 127 | case dSPIN_K_THERM: 128 | ret_val = dSPIN_Xfer((byte)value & 0x0F); 129 | break; 130 | // ADC_OUT is a read-only register containing the result of the ADC measurements. 131 | // This is less useful than it sounds; see the datasheet for more information. 132 | case dSPIN_ADC_OUT: 133 | ret_val = dSPIN_Xfer(0); 134 | break; 135 | // Set the overcurrent threshold. Ranges from 375mA to 6A in steps of 375mA. 136 | // A set of defined constants is provided for the user's convenience. Default 137 | // value is 3.375A- 0x08. This is a 4-bit value. 138 | case dSPIN_OCD_TH: 139 | ret_val = dSPIN_Xfer((byte)value & 0x0F); 140 | break; 141 | // Stall current threshold. Defaults to 0x40, or 2.03A. Value is from 31.25mA to 142 | // 4A in 31.25mA steps. This is a 7-bit value. 143 | case dSPIN_STALL_TH: 144 | ret_val = dSPIN_Xfer((byte)value & 0x7F); 145 | break; 146 | // STEP_MODE controls the microstepping settings, as well as the generation of an 147 | // output signal from the dSPIN. Bits 2:0 control the number of microsteps per 148 | // step the part will generate. Bit 7 controls whether the BUSY/SYNC pin outputs 149 | // a BUSY signal or a step synchronization signal. Bits 6:4 control the frequency 150 | // of the output signal relative to the full-step frequency; see datasheet for 151 | // that relationship as it is too complex to reproduce here. 152 | // Most likely, only the microsteps per step value will be needed; there is a set 153 | // of constants provided for ease of use of these values. 154 | case dSPIN_STEP_MODE: 155 | ret_val = dSPIN_Xfer((byte)value); 156 | break; 157 | // ALARM_EN controls which alarms will cause the FLAG pin to fall. A set of constants 158 | // is provided to make this easy to interpret. By default, ALL alarms will trigger the 159 | // FLAG pin. 160 | case dSPIN_ALARM_EN: 161 | ret_val = dSPIN_Xfer((byte)value); 162 | break; 163 | // CONFIG contains some assorted configuration bits and fields. A fairly comprehensive 164 | // set of reasonably self-explanatory constants is provided, but users should refer 165 | // to the datasheet before modifying the contents of this register to be certain they 166 | // understand the implications of their modifications. Value on boot is 0x2E88; this 167 | // can be a useful way to verify proper start up and operation of the dSPIN chip. 168 | case dSPIN_CONFIG: 169 | ret_val = dSPIN_Param(value, 16); 170 | break; 171 | // STATUS contains read-only information about the current condition of the chip. A 172 | // comprehensive set of constants for masking and testing this register is provided, but 173 | // users should refer to the datasheet to ensure that they fully understand each one of 174 | // the bits in the register. 175 | case dSPIN_STATUS: // STATUS is a read-only register 176 | ret_val = dSPIN_Param(0, 16); 177 | break; 178 | default: 179 | ret_val = dSPIN_Xfer((byte)(value)); 180 | break; 181 | } 182 | return ret_val; 183 | } 184 | 185 | // Enable or disable the low-speed optimization option. If enabling, 186 | // the other 12 bits of the register will be automatically zero. 187 | // When disabling, the value will have to be explicitly written by 188 | // the user with a SetParam() call. See the datasheet for further 189 | // information about low-speed optimization. 190 | void SetLSPDOpt(boolean enable) 191 | { 192 | dSPIN_Xfer(dSPIN_SET_PARAM | dSPIN_MIN_SPEED); 193 | if (enable) dSPIN_Param(0x1000, 13); 194 | else dSPIN_Param(0, 13); 195 | } 196 | 197 | // RUN sets the motor spinning in a direction (defined by the constants 198 | // FWD and REV). Maximum speed and minimum speed are defined 199 | // by the MAX_SPEED and MIN_SPEED registers; exceeding the FS_SPD value 200 | // will switch the device into full-step mode. 201 | // The SpdCalc() function is provided to convert steps/s values into 202 | // appropriate integer values for this function. 203 | void dSPIN_Run(byte dir, unsigned long spd) 204 | { 205 | dSPIN_Xfer(dSPIN_RUN | dir); 206 | if (spd > 0xFFFFF) spd = 0xFFFFF; 207 | dSPIN_Xfer((byte)(spd >> 16)); 208 | dSPIN_Xfer((byte)(spd >> 8)); 209 | dSPIN_Xfer((byte)(spd)); 210 | } 211 | 212 | // STEP_CLOCK puts the device in external step clocking mode. When active, 213 | // pin 25, STCK, becomes the step clock for the device, and steps it in 214 | // the direction (set by the FWD and REV constants) imposed by the call 215 | // of this function. Motion commands (RUN, MOVE, etc) will cause the device 216 | // to exit step clocking mode. 217 | void dSPIN_Step_Clock(byte dir) 218 | { 219 | dSPIN_Xfer(dSPIN_STEP_CLOCK | dir); 220 | } 221 | 222 | // MOVE will send the motor n_step steps (size based on step mode) in the 223 | // direction imposed by dir (FWD or REV constants may be used). The motor 224 | // will accelerate according the acceleration and deceleration curves, and 225 | // will run at MAX_SPEED. Stepping mode will adhere to FS_SPD value, as well. 226 | void dSPIN_Move(byte dir, unsigned long n_step) 227 | { 228 | dSPIN_Xfer(dSPIN_MOVE | dir); 229 | if (n_step > 0x3FFFFF) n_step = 0x3FFFFF; 230 | dSPIN_Xfer((byte)(n_step >> 16)); 231 | dSPIN_Xfer((byte)(n_step >> 8)); 232 | dSPIN_Xfer((byte)(n_step)); 233 | } 234 | 235 | // GOTO operates much like MOVE, except it produces absolute motion instead 236 | // of relative motion. The motor will be moved to the indicated position 237 | // in the shortest possible fashion. 238 | void dSPIN_GoTo(unsigned long pos) 239 | { 240 | 241 | dSPIN_Xfer(dSPIN_GOTO); 242 | if (pos > 0x3FFFFF) pos = 0x3FFFFF; 243 | dSPIN_Xfer((byte)(pos >> 16)); 244 | dSPIN_Xfer((byte)(pos >> 8)); 245 | dSPIN_Xfer((byte)(pos)); 246 | } 247 | 248 | // Same as GOTO, but with user constrained rotational direction. 249 | void dSPIN_GoTo_DIR(byte dir, unsigned long pos) 250 | { 251 | 252 | dSPIN_Xfer(dSPIN_GOTO_DIR); 253 | if (pos > 0x3FFFFF) pos = 0x3FFFFF; 254 | dSPIN_Xfer((byte)(pos >> 16)); 255 | dSPIN_Xfer((byte)(pos >> 8)); 256 | dSPIN_Xfer((byte)(pos)); 257 | } 258 | 259 | // GoUntil will set the motor running with direction dir (REV or 260 | // FWD) until a falling edge is detected on the SW pin. Depending 261 | // on bit SW_MODE in CONFIG, either a hard stop or a soft stop is 262 | // performed at the falling edge, and depending on the value of 263 | // act (either RESET or COPY) the value in the ABS_POS register is 264 | // either RESET to 0 or COPY-ed into the MARK register. 265 | void dSPIN_GoUntil(byte act, byte dir, unsigned long spd) 266 | { 267 | dSPIN_Xfer(dSPIN_GO_UNTIL | act | dir); 268 | if (spd > 0x3FFFFF) spd = 0x3FFFFF; 269 | dSPIN_Xfer((byte)(spd >> 16)); 270 | dSPIN_Xfer((byte)(spd >> 8)); 271 | dSPIN_Xfer((byte)(spd)); 272 | } 273 | 274 | // Similar in nature to GoUntil, ReleaseSW produces motion at the 275 | // higher of two speeds: the value in MIN_SPEED or 5 steps/s. 276 | // The motor continues to run at this speed until a rising edge 277 | // is detected on the switch input, then a hard stop is performed 278 | // and the ABS_POS register is either COPY-ed into MARK or RESET to 279 | // 0, depending on whether RESET or COPY was passed to the function 280 | // for act. 281 | void dSPIN_ReleaseSW(byte act, byte dir) 282 | { 283 | dSPIN_Xfer(dSPIN_RELEASE_SW | act | dir); 284 | } 285 | 286 | // GoHome is equivalent to GoTo(0), but requires less time to send. 287 | // Note that no direction is provided; motion occurs through shortest 288 | // path. If a direction is required, use GoTo_DIR(). 289 | void dSPIN_GoHome() 290 | { 291 | dSPIN_Xfer(dSPIN_GO_HOME); 292 | } 293 | 294 | // GoMark is equivalent to GoTo(MARK), but requires less time to send. 295 | // Note that no direction is provided; motion occurs through shortest 296 | // path. If a direction is required, use GoTo_DIR(). 297 | void dSPIN_GoMark() 298 | { 299 | dSPIN_Xfer(dSPIN_GO_MARK); 300 | } 301 | 302 | // Sets the ABS_POS register to 0, effectively declaring the current 303 | // position to be "HOME". 304 | void dSPIN_ResetPos() 305 | { 306 | dSPIN_Xfer(dSPIN_RESET_POS); 307 | } 308 | 309 | // Reset device to power up conditions. Equivalent to toggling the STBY 310 | // pin or cycling power. 311 | void dSPIN_ResetDev() 312 | { 313 | dSPIN_Xfer(dSPIN_RESET_DEVICE); 314 | } 315 | 316 | // Bring the motor to a halt using the deceleration curve. 317 | void dSPIN_SoftStop() 318 | { 319 | dSPIN_Xfer(dSPIN_SOFT_STOP); 320 | } 321 | 322 | // Stop the motor with infinite deceleration. 323 | void dSPIN_HardStop() 324 | { 325 | dSPIN_Xfer(dSPIN_HARD_STOP); 326 | } 327 | 328 | // Decelerate the motor and put the bridges in Hi-Z state. 329 | void dSPIN_SoftHiZ() 330 | { 331 | dSPIN_Xfer(dSPIN_SOFT_HIZ); 332 | } 333 | 334 | // Put the bridges in Hi-Z state immediately with no deceleration. 335 | void dSPIN_HardHiZ() 336 | { 337 | dSPIN_Xfer(dSPIN_HARD_HIZ); 338 | } 339 | 340 | // Fetch and return the 16-bit value in the STATUS register. Resets 341 | // any warning flags and exits any error states. Using GetParam() 342 | // to read STATUS does not clear these values. 343 | int dSPIN_GetStatus() 344 | { 345 | int temp = 0; 346 | dSPIN_Xfer(dSPIN_GET_STATUS); 347 | temp = dSPIN_Xfer(0)<<8; 348 | temp |= dSPIN_Xfer(0); 349 | return temp; 350 | } 351 | 352 | -------------------------------------------------------------------------------- /examples/SparkFundSPINexample/SparkFundSPINexample.ino: -------------------------------------------------------------------------------- 1 | /***************************************************************** 2 | Example code for the STMicro L6470 dSPIN stepper motor driver. 3 | This code is public domain beerware/Sunny-D-ware. If you find it 4 | useful and run into me someday, I'd appreciate a cold one. 5 | 6 | 12/12/2011- Mike Hord, SparkFun Electronics 7 | 8 | The breakout board for the dSPIN chip has 7 data lines: 9 | BSYN- this line is LOW when the chip is busy; busy generally means 10 | things like executing a move command. 11 | STBY- drag low to reset the device to default conditions. Also 12 | should be performed after power up to ensure a known-good 13 | initial state. 14 | FLGN- when the dSPIN raises a flag it usually means an error has 15 | occurred 16 | STCK- used as a step clock input; the direction (and activation of 17 | this input) is done by setting registers on the chip. 18 | SDI- SPI data FROM the uC TO the dSPIN 19 | SDO- SPI data TO the uC FROM the dSPIN 20 | CSN- active-low slave select for the SPI bus 21 | CK- data clock for the SPI bus 22 | 23 | A note about connecting motors: 24 | It's unclear from the datasheet what gets connected to which 25 | terminal. Bridge one (terminals 01A and 01B) gets one coil, and 26 | bridge two gets the other coil. For our mid-small stepper 27 | (ROB-9238), that translates to 28 | 01A -> RED 29 | 01B -> GREEN 30 | 02A -> BLUE 31 | 02B -> YELLOW 32 | 33 | ERRATA: IMPORTANT!!! READ THIS!!! 34 | There are several errors in the datasheet for the L6470: 35 | - the internal oscillator is specified as 16MHz +/- 3%. 36 | Experimentally, it seems to be more like a 6% tolerance. 37 | - when transitioning from one movement command to another, it may 38 | be necessary to include a dSPIN_SoftStop() between the two to 39 | ensure proper operation. For example, if dSPIN_Move(FWD, 800) 40 | is used to move 800 steps FWD, and immediately after that, 41 | with no soft stop between them, a dSPIN_Run(FWD, 200) command 42 | is issued, the 'run' command will execute with a speed based 43 | on the value in the 'MAX_SPEED' register, the way the 'move' 44 | command did, and NOT with the speed passed to it by the 45 | function call. 46 | 47 | v2.0- 5 Dec 2012- Purely cosmetic changes. I wanted to move the 48 | setup() and loop() functions into the first file, and make a 49 | real .h header file for the L6470 register definitions, to 50 | make sure the project works properly for everyone. 51 | 52 | 53 | 54 | FILENAMES 55 | dSPIN_example.ino - This file. Pin redefinition constants, setup() 56 | and loop(). 57 | dSPIN_commands.ino - High-level command implementations- movement 58 | and configuration commands, for example. 59 | dSPIN_support.ino - Functions used to implement the high-level 60 | commands, as well as utility functions for converting 61 | real-world units (eg, steps/s) to values usable by the dSPIN 62 | controller. Also contains the specialized configuration 63 | function for the dsPIN chip and the onboard peripherals needed 64 | to use it. 65 | L6470.h - Register and pin definitions and descriptions for use 66 | with the L6470. 67 | *****************************************************************/ 68 | 69 | #include // include the SPI library: 70 | #include "SparkFunL6470.h" // include the register and bit definitions 71 | 72 | #define SLAVE_SELECT_PIN 10 // Wire this to the CSN pin 73 | #define MOSI 11 // Wire this to the SDI pin 74 | #define MISO 12 // Wire this to the SDO pin 75 | #define SCK 13 // Wire this to the CK pin 76 | #define dSPIN_RESET 17 // Wire this to the STBY line 77 | #define dSPIN_BUSYN 16 // Wire this to the BSYN line 78 | 79 | #define STAT1 14 // Hooked to an LED on the test jig 80 | #define STAT2 15 // Hooked to an LED on the test jig 81 | #define SWITCH 8 // Hooked to the switch input and a 82 | // pB on the jig 83 | 84 | float testSpeed = 25; 85 | 86 | void setup() 87 | { 88 | // Standard serial port initialization for debugging. 89 | Serial.begin(9600); 90 | 91 | // pin configurations for the test jig 92 | pinMode(STAT1, OUTPUT); 93 | pinMode(STAT2, OUTPUT); 94 | pinMode(SWITCH, INPUT); 95 | pinMode(5, INPUT); 96 | digitalWrite(STAT1, LOW); 97 | digitalWrite(STAT2, LOW); 98 | 99 | // dSPIN_init() is implemented in the dSPIN_support.ino file. 100 | // It includes all the necessary port setup and SPI setup to 101 | // allow the Arduino to control the dSPIN chip and relies 102 | // entirely upon the pin redefinitions 103 | // in dSPIN_example.ino 104 | dSPIN_init(); 105 | 106 | // First things first: let's check communications. The CONFIG 107 | // register should power up to 0x2E88, so we can use that to 108 | // check the communications. On the test jig, this causes an 109 | // LED to light up. 110 | if (dSPIN_GetParam(dSPIN_CONFIG) == 0x2E88) 111 | digitalWrite(STAT1, HIGH); 112 | 113 | // The following function calls are for this demo application- 114 | // you will need to adjust them for your particular 115 | // application, and you may need to configure additional 116 | // registers. 117 | 118 | // First, let's set the step mode register: 119 | // - dSPIN_SYNC_EN controls whether the BUSY/SYNC pin reflects 120 | // the step frequency or the BUSY status of the chip. We 121 | // want it to be the BUSY status. 122 | // - dSPIN_STEP_SEL_x is the microstepping rate- we'll go full 123 | // step. 124 | // - dSPIN_SYNC_SEL_x is the ratio of (micro)steps to toggles 125 | // on the BUSY/SYNC pin (when that pin is used for SYNC). 126 | // Make it 1:1, despite not using that pin. 127 | dSPIN_SetParam(dSPIN_STEP_MODE, 128 | !dSPIN_SYNC_EN | 129 | dSPIN_STEP_SEL_1_16 | 130 | dSPIN_SYNC_SEL_1); 131 | 132 | // Configure the MAX_SPEED register- this is the maximum number 133 | // of (micro)steps per second allowed. You'll want to mess 134 | // around with your desired application to see how far you can 135 | // push it before the motor starts to slip. The ACTUAL 136 | // parameter passed to this function is in steps/tick; 137 | // MaxSpdCalc() will convert a number of steps/s into an 138 | // appropriate value for this function. Note that for any move 139 | // or goto type function where no speed is specified, this 140 | // value will be used. 141 | dSPIN_SetParam(dSPIN_MAX_SPEED, MaxSpdCalc(400)); 142 | 143 | // Configure the FS_SPD register- this is the speed at which the 144 | // driver ceases microstepping and goes to full stepping. 145 | // FSCalc() converts a value in steps/s to a value suitable for 146 | // this register; to disable full-step switching, you can pass 147 | // 0x3FF to this register. 148 | dSPIN_SetParam(dSPIN_FS_SPD, FSCalc(50)); 149 | 150 | // Configure the acceleration rate, in steps/tick/tick. There is 151 | // also a DEC register; both of them have a function (AccCalc() 152 | // and DecCalc() respectively) that convert from steps/s/s into 153 | // the appropriate value for the register. Writing ACC to 0xfff 154 | // sets the acceleration and deceleration to 'infinite' (or as 155 | // near as the driver can manage). If ACC is set to 0xfff, DEC 156 | // is ignored. To get infinite deceleration without infinite 157 | // acceleration, only hard stop will work. 158 | dSPIN_SetParam(dSPIN_ACC, 0xfff); 159 | 160 | // Configure the overcurrent detection threshold. The constants 161 | // for this are defined in the L6470.h file. 162 | dSPIN_SetParam(dSPIN_OCD_TH, dSPIN_OCD_TH_6000mA); 163 | 164 | // Set up the CONFIG register as follows: 165 | // PWM frequency divisor = 1 166 | // PWM frequency multiplier = 2 (62.5kHz PWM frequency) 167 | // Slew rate is 290V/us 168 | // Do NOT shut down bridges on overcurrent 169 | // Disable motor voltage compensation 170 | // Hard stop on switch low 171 | // 16MHz internal oscillator, nothing on output 172 | dSPIN_SetParam(dSPIN_CONFIG, 173 | dSPIN_CONFIG_PWM_DIV_1 | 174 | dSPIN_CONFIG_PWM_MUL_2 | 175 | dSPIN_CONFIG_SR_180V_us | 176 | dSPIN_CONFIG_OC_SD_DISABLE | 177 | dSPIN_CONFIG_VS_COMP_DISABLE | 178 | dSPIN_CONFIG_SW_HARD_STOP | 179 | dSPIN_CONFIG_INT_16MHZ); 180 | 181 | // Configure the RUN KVAL. This defines the duty cycle of the 182 | // PWM of the bridges during running. 0xFF means that they are 183 | // essentially NOT PWMed during run; this MAY result in more 184 | // power being dissipated than you actually need for the task. 185 | // Setting this value too low may result in failure to turn. 186 | // There are ACC, DEC, and HOLD KVAL registers as well; you may 187 | // need to play with those values to get acceptable performance 188 | // for a given application. 189 | dSPIN_SetParam(dSPIN_KVAL_RUN, 0xFF); 190 | 191 | // Calling GetStatus() clears the UVLO bit in the status 192 | // register, which is set by default on power-up. The driver 193 | // may not run without that bit cleared by this read operation. 194 | dSPIN_GetStatus(); 195 | 196 | // Now we're going to set up a counter to track pulses from an 197 | // encoder, to verify against the expected values. 198 | TCCR1A = 0; // No waveform generation stuff. 199 | TCCR1B = B00000110; // Clock on falling edge, T1 pin. 200 | TCNT1 = 0; // Clear the count. 201 | } 202 | 203 | void loop() 204 | { 205 | dSPIN_Move(FWD, 25600); 206 | while (digitalRead(dSPIN_BUSYN) == LOW); // Until the movement completes, the 207 | // BUSYN pin will be low. 208 | dSPIN_SoftStop(); // Inserting a soft stop between 209 | // motions ensures that the driver 210 | // will execute the next motion with 211 | // the right speed. 212 | while (digitalRead(dSPIN_BUSYN) == LOW); // Wait for the soft stop to complete. 213 | Serial.println(TCNT1, DEC); 214 | while(1); 215 | } 216 | 217 | 218 | 219 | -------------------------------------------------------------------------------- /examples/SparkFundSPINexample/SparkFundSPINsupport.ino: -------------------------------------------------------------------------------- 1 | //dSPIN_support.ino - Contains functions used to implement the high-level commands, 2 | // as well as utility functions for converting real-world units (eg, steps/s) to 3 | // values usable by the dsPIN controller. Also contains the specialized configuration 4 | // function for the dsPIN chip and the onboard peripherals needed to use it. 5 | 6 | // The value in the ACC register is [(steps/s/s)*(tick^2)]/(2^-40) where tick is 7 | // 250ns (datasheet value)- 0x08A on boot. 8 | // Multiply desired steps/s/s by .137438 to get an appropriate value for this register. 9 | // This is a 12-bit value, so we need to make sure the value is at or below 0xFFF. 10 | unsigned long AccCalc(float stepsPerSecPerSec) 11 | { 12 | float temp = stepsPerSecPerSec * 0.137438; 13 | if( (unsigned long) long(temp) > 0x00000FFF) return 0x00000FFF; 14 | else return (unsigned long) long(temp); 15 | } 16 | 17 | // The calculation for DEC is the same as for ACC. Value is 0x08A on boot. 18 | // This is a 12-bit value, so we need to make sure the value is at or below 0xFFF. 19 | unsigned long DecCalc(float stepsPerSecPerSec) 20 | { 21 | float temp = stepsPerSecPerSec * 0.137438; 22 | if( (unsigned long) long(temp) > 0x00000FFF) return 0x00000FFF; 23 | else return (unsigned long) long(temp); 24 | } 25 | 26 | // The value in the MAX_SPD register is [(steps/s)*(tick)]/(2^-18) where tick is 27 | // 250ns (datasheet value)- 0x041 on boot. 28 | // Multiply desired steps/s by .065536 to get an appropriate value for this register 29 | // This is a 10-bit value, so we need to make sure it remains at or below 0x3FF 30 | unsigned long MaxSpdCalc(float stepsPerSec) 31 | { 32 | float temp = stepsPerSec * .065536; 33 | if( (unsigned long) long(temp) > 0x000003FF) return 0x000003FF; 34 | else return (unsigned long) long(temp); 35 | } 36 | 37 | // The value in the MIN_SPD register is [(steps/s)*(tick)]/(2^-24) where tick is 38 | // 250ns (datasheet value)- 0x000 on boot. 39 | // Multiply desired steps/s by 4.1943 to get an appropriate value for this register 40 | // This is a 12-bit value, so we need to make sure the value is at or below 0xFFF. 41 | unsigned long MinSpdCalc(float stepsPerSec) 42 | { 43 | float temp = stepsPerSec * 4.1943; 44 | if( (unsigned long) long(temp) > 0x00000FFF) return 0x00000FFF; 45 | else return (unsigned long) long(temp); 46 | } 47 | 48 | // The value in the FS_SPD register is ([(steps/s)*(tick)]/(2^-18))-0.5 where tick is 49 | // 250ns (datasheet value)- 0x027 on boot. 50 | // Multiply desired steps/s by .065536 and subtract .5 to get an appropriate value for this register 51 | // This is a 10-bit value, so we need to make sure the value is at or below 0x3FF. 52 | unsigned long FSCalc(float stepsPerSec) 53 | { 54 | float temp = (stepsPerSec * .065536)-.5; 55 | if( (unsigned long) long(temp) > 0x000003FF) return 0x000003FF; 56 | else return (unsigned long) long(temp); 57 | } 58 | 59 | // The value in the INT_SPD register is [(steps/s)*(tick)]/(2^-24) where tick is 60 | // 250ns (datasheet value)- 0x408 on boot. 61 | // Multiply desired steps/s by 4.1943 to get an appropriate value for this register 62 | // This is a 14-bit value, so we need to make sure the value is at or below 0x3FFF. 63 | unsigned long IntSpdCalc(float stepsPerSec) 64 | { 65 | float temp = stepsPerSec * 4.1943; 66 | if( (unsigned long) long(temp) > 0x00003FFF) return 0x00003FFF; 67 | else return (unsigned long) long(temp); 68 | } 69 | 70 | // When issuing RUN command, the 20-bit speed is [(steps/s)*(tick)]/(2^-28) where tick is 71 | // 250ns (datasheet value). 72 | // Multiply desired steps/s by 67.106 to get an appropriate value for this register 73 | // This is a 20-bit value, so we need to make sure the value is at or below 0xFFFFF. 74 | unsigned long SpdCalc(float stepsPerSec) 75 | { 76 | float temp = stepsPerSec * 67.106; 77 | if( (unsigned long) long(temp) > 0x000FFFFF) return 0x000FFFFF; 78 | else return (unsigned long)temp; 79 | } 80 | 81 | // Generalization of the subsections of the register read/write functionality. 82 | // We want the end user to just write the value without worrying about length, 83 | // so we pass a bit length parameter from the calling function. 84 | unsigned long dSPIN_Param(unsigned long value, byte bit_len) 85 | { 86 | unsigned long ret_val=0; // We'll return this to generalize this function 87 | // for both read and write of registers. 88 | byte byte_len = bit_len/8; // How many BYTES do we have? 89 | if (bit_len%8 > 0) byte_len++; // Make sure not to lose any partial byte values. 90 | // Let's make sure our value has no spurious bits set, and if the value was too 91 | // high, max it out. 92 | unsigned long mask = 0xffffffff >> (32-bit_len); 93 | if (value > mask) value = mask; 94 | // The following three if statements handle the various possible byte length 95 | // transfers- it'll be no less than 1 but no more than 3 bytes of data. 96 | // dSPIN_Xfer() sends a byte out through SPI and returns a byte received 97 | // over SPI- when calling it, we typecast a shifted version of the masked 98 | // value, then we shift the received value back by the same amount and 99 | // store it until return time. 100 | if (byte_len == 3) { 101 | ret_val |= dSPIN_Xfer((byte)(value>>16)) << 16; 102 | //Serial.println(ret_val, HEX); 103 | } 104 | if (byte_len >= 2) { 105 | ret_val |= dSPIN_Xfer((byte)(value>>8)) << 8; 106 | //Serial.println(ret_val, HEX); 107 | } 108 | if (byte_len >= 1) { 109 | ret_val |= dSPIN_Xfer((byte)value); 110 | //Serial.println(ret_val, HEX); 111 | } 112 | // Return the received values. Mask off any unnecessary bits, just for 113 | // the sake of thoroughness- we don't EXPECT to see anything outside 114 | // the bit length range but better to be safe than sorry. 115 | return (ret_val & mask); 116 | } 117 | 118 | // This simple function shifts a byte out over SPI and receives a byte over 119 | // SPI. Unusually for SPI devices, the dSPIN requires a toggling of the 120 | // CS (slaveSelect) pin after each byte sent. That makes this function 121 | // a bit more reasonable, because we can include more functionality in it. 122 | byte dSPIN_Xfer(byte data) 123 | { 124 | byte data_out; 125 | digitalWrite(SLAVE_SELECT_PIN,LOW); 126 | // SPI.transfer() both shifts a byte out on the MOSI pin AND receives a 127 | // byte in on the MISO pin. 128 | data_out = SPI.transfer(data); 129 | digitalWrite(SLAVE_SELECT_PIN,HIGH); 130 | return data_out; 131 | } 132 | 133 | // This is the generic initialization function to set up the Arduino to 134 | // communicate with the dSPIN chip. 135 | void dSPIN_init() 136 | { 137 | // set up the input/output pins for the application. 138 | pinMode(10, OUTPUT); // The SPI peripheral REQUIRES the hardware SS pin- 139 | // pin 10- to be an output. This is in here just 140 | // in case some future user makes something other 141 | // than pin 10 the SS pin. 142 | pinMode(SLAVE_SELECT_PIN, OUTPUT); 143 | digitalWrite(SLAVE_SELECT_PIN, HIGH); 144 | pinMode(MOSI, OUTPUT); 145 | pinMode(MISO, INPUT); 146 | pinMode(SCK, OUTPUT); 147 | pinMode(dSPIN_BUSYN, INPUT); 148 | pinMode(dSPIN_RESET, OUTPUT); 149 | 150 | // reset the dSPIN chip. This could also be accomplished by 151 | // calling the "dSPIN_ResetDev()" function after SPI is initialized. 152 | digitalWrite(dSPIN_RESET, HIGH); 153 | delay(1); 154 | digitalWrite(dSPIN_RESET, LOW); 155 | delay(1); 156 | digitalWrite(dSPIN_RESET, HIGH); 157 | delay(1); 158 | 159 | // initialize SPI for the dSPIN chip's needs: 160 | // most significant bit first, 161 | // SPI clock not to exceed 5MHz, 162 | // SPI_MODE3 (clock idle high, latch data on rising edge of clock) 163 | SPI.begin(); 164 | SPI.setBitOrder(MSBFIRST); 165 | SPI.setClockDivider(SPI_CLOCK_DIV16); // or 2, 8, 16, 32, 64 166 | SPI.setDataMode(SPI_MODE3); 167 | } 168 | -------------------------------------------------------------------------------- /examples/gantry/gantry.ino: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * gantry.ino 3 | * Five-axis gantry example for Autodriver 4 | * Mike Hord @ SparkFun Electronics 5 | * 16 Aug 2016 6 | * https://github.com/sparkfun/SparkFun_AutoDriver_Arduino_Library 7 | * 8 | * This file demonstrates the use of five Autodriver boards in one sketch, to 9 | * control a five-axis gantry system such as one might find on a 3D printer. 10 | * 11 | * Development environment specifics: 12 | * Arduino 1.6.9 13 | * SparkFun Arduino Pro board, Autodriver V13 14 | * 15 | * This code is beerware; if you see me (or any other SparkFun employee) at the 16 | * local, and you've found our code helpful, please buy us a round! 17 | * ****************************************************************************/ 18 | 19 | #include 20 | #include 21 | 22 | #define NUM_BOARDS 5 23 | 24 | // The gantry we're using has five autodriver boards, but 25 | // only four of them are in use. The board in position 3 26 | // is reserved for future use. 27 | 28 | // Numbering starts from the board farthest from the 29 | // controller and counts up from 0. Thus, board "4" is the 30 | // board which is plugged directly into the controller 31 | // and board "0" is the farthest away. 32 | AutoDriver YAxis(4, 10, 6); 33 | AutoDriver Unused(3, 10, 6); 34 | AutoDriver ZAAxis(2, 10, 6); 35 | AutoDriver ZBAxis(1, 10, 6); 36 | AutoDriver XAxis(0, 10, 6); 37 | 38 | // It may be useful to index over the drivers, say, to set 39 | // the values that should be all the same across all the 40 | // boards. Let's make an array of pointers to AutoDriver 41 | // objects so we can do just that. 42 | AutoDriver *boardIndex[NUM_BOARDS]; 43 | 44 | void setup() 45 | { 46 | Serial.begin(115200); 47 | Serial.println("Hello world!"); 48 | 49 | // Start by setting up the SPI port and pins. The 50 | // Autodriver library does not do this for you! 51 | pinMode(6, OUTPUT); 52 | pinMode(MOSI, OUTPUT); 53 | pinMode(MISO, INPUT); 54 | pinMode(13, OUTPUT); 55 | pinMode(10, OUTPUT); 56 | digitalWrite(10, HIGH); 57 | digitalWrite(6, LOW); 58 | digitalWrite(6, HIGH); 59 | SPI.begin(); 60 | SPI.setDataMode(SPI_MODE3); 61 | 62 | // Set the pointers in our global AutoDriver array to 63 | // the objects we've created. 64 | boardIndex[4] = &YAxis; 65 | boardIndex[3] = &Unused; 66 | boardIndex[2] = &ZAAxis; 67 | boardIndex[1] = &ZBAxis; 68 | boardIndex[0] = &XAxis; 69 | 70 | // Configure the boards to the settings we wish to use 71 | // for them. See below for more information about the 72 | // settings applied. 73 | configureBoards(); 74 | } 75 | 76 | // loop() is going to wait to receive a character from the 77 | // host, then do something based on that character. 78 | void loop() 79 | { 80 | char rxChar = 0; 81 | if (Serial.available()) 82 | { 83 | rxChar = Serial.read(); 84 | // This switch statement handles the various cases 85 | // that may come from the host via the serial port. 86 | // Do note that not all terminal programs will 87 | // encode e.g. Page Up as 0x0B. I'm using CoolTerm 88 | // in Windows and this is what CoolTerm sends when 89 | // I strike these respective keys. 90 | switch(rxChar) 91 | { 92 | case 0x0B: // Page Up 93 | ZAAxis.run(1, 600); 94 | ZBAxis.run(1, 600); 95 | delay(500); 96 | ZAAxis.run(1, 0); 97 | ZBAxis.run(1, 0); 98 | break; 99 | case 0x0C: // Page Down 100 | ZAAxis.run(0, 600); 101 | ZBAxis.run(0, 600); 102 | delay(500); 103 | ZAAxis.run(0, 0); 104 | ZBAxis.run(0, 0); 105 | break; 106 | case 0x1E: // Up Arrow 107 | YAxis.run(1,200); 108 | delay(500); 109 | YAxis.run(0,0); 110 | break; 111 | case 0x1F: // Down Arrow 112 | YAxis.run(0,200); 113 | delay(500); 114 | YAxis.run(0,0); 115 | break; 116 | case 0x1C: // Left Arrow 117 | XAxis.run(1,200); 118 | delay(500); 119 | XAxis.run(1,0); 120 | break; 121 | case 0x1D: // Right Arrow 122 | XAxis.run(0,200); 123 | delay(500); 124 | XAxis.run(0,0); 125 | break; 126 | case 'g': 127 | getBoardConfigurations(); 128 | break; 129 | case 'c': 130 | break; 131 | default: 132 | Serial.println("Command not found."); 133 | } 134 | } 135 | } 136 | 137 | // For ease of reading, we're just going to configure all the boards 138 | // to the same settings. It's working okay for me. 139 | void configureBoards() 140 | { 141 | int paramValue; 142 | Serial.println("Configuring boards..."); 143 | for (int i = 0; i < NUM_BOARDS; i++) 144 | { 145 | // Before we do anything, we need to tell each board which SPI 146 | // port we're using. Most of the time, there's only the one, 147 | // but it's possible for some larger Arduino boards to have more 148 | // than one, so don't take it for granted. 149 | boardIndex[i]->SPIPortConnect(&SPI); 150 | 151 | // Set the Overcurrent Threshold to 6A. The OC detect circuit 152 | // is quite sensitive; even if the current is only momentarily 153 | // exceeded during acceleration or deceleration, the driver 154 | // will shutdown. This is a per channel value; it's useful to 155 | // consider worst case, which is startup. These motors have a 156 | // 1.8 ohm static winding resistance; at 12V, the current will 157 | // exceed this limit, so we need to use the KVAL settings (see 158 | // below) to trim that value back to a safe level. 159 | boardIndex[i]->setOCThreshold(OCD_TH_6000mA); 160 | 161 | // KVAL is a modifier that sets the effective voltage applied 162 | // to the motor. KVAL/255 * Vsupply = effective motor voltage. 163 | // This lets us hammer the motor harder during some phases 164 | // than others, and to use a higher voltage to achieve better 165 | // torqure performance even if a motor isn't rated for such a 166 | // high current. This system has 3V motors and a 12V supply. 167 | boardIndex[i]->setRunKVAL(192); // 128/255 * 12V = 6V 168 | boardIndex[i]->setAccKVAL(192); // 192/255 * 12V = 9V 169 | boardIndex[i]->setDecKVAL(192); 170 | boardIndex[i]->setHoldKVAL(32); // 32/255 * 12V = 1.5V 171 | 172 | // When a move command is issued, max speed is the speed the 173 | // motor tops out at while completing the move, in steps/s 174 | boardIndex[i]->setMaxSpeed(300); 175 | 176 | // Acceleration and deceleration in steps/s/s. Increasing this 177 | // value makes the motor reach its full speed more quickly, 178 | // at the cost of possibly causing it to slip and miss steps. 179 | boardIndex[i]->setAcc(400); 180 | boardIndex[i]->setDec(400); 181 | } 182 | } 183 | 184 | // Reads back the "config" register from each board in the series. 185 | // This should be 0x2e88 after a reset of the Autodriver board, or 186 | // of the control board (as it resets the Autodriver at startup). 187 | // A reading of 0x0000 means something is wrong with your hardware. 188 | void getBoardConfigurations() 189 | { 190 | int paramValue; 191 | Serial.println("Board configurations:"); 192 | for (int i = 0; i < NUM_BOARDS ; i++) 193 | { 194 | // It's nice to know if our board is connected okay. We can read 195 | // the config register and print the result; it should be 0x2e88 196 | // on startup. 197 | paramValue = boardIndex[i]->getParam(CONFIG); 198 | Serial.print("Config value: "); 199 | Serial.println(paramValue, HEX); 200 | } 201 | } 202 | 203 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | # Constants 2 | FWD LITERAL1 3 | REV LITERAL1 4 | RESET_ABSPOS LITERAL1 5 | COPY_ABSPOS LITERAL1 6 | BUSY_PIN LITERAL1 7 | SYNC_PIN LITERAL1 8 | SYNC_FS_2 LITERAL1 9 | SYNC_FS LITERAL1 10 | SYNC_2FS LITERAL1 11 | SYNC_4FS LITERAL1 12 | SYNC_8FS LITERAL1 13 | SYNC_16FS LITERAL1 14 | SYNC_32FS LITERAL1 15 | SYNC_64FS LITERAL1 16 | STEP_FS LITERAL1 17 | STEP_FS_2 LITERAL1 18 | STEP_FS_4 LITERAL1 19 | STEP_FS_8 LITERAL1 20 | STEP_FS_16 LITERAL1 21 | STEP_FS_32 LITERAL1 22 | STEP_FS_64 LITERAL1 23 | STEP_FS_128 LITERAL1 24 | OC_375mA LITERAL1 25 | OC_750mA LITERAL1 26 | OC_1125mA LITERAL1 27 | OC_1500mA LITERAL1 28 | OC_1875mA LITERAL1 29 | OC_2250mA LITERAL1 30 | OC_2625mA LITERAL1 31 | OC_3000mA LITERAL1 32 | OC_3375mA LITERAL1 33 | OC_3750mA LITERAL1 34 | OC_4125mA LITERAL1 35 | OC_4500mA LITERAL1 36 | OC_4875mA LITERAL1 37 | OC_5250mA LITERAL1 38 | OC_5625mA LITERAL1 39 | OC_6000mA LITERAL1 40 | PWM_MUL_0_625 LITERAL1 41 | PWM_MUL_0_75 LITERAL1 42 | PWM_MUL_0_875 LITERAL1 43 | PWM_MUL_1 LITERAL1 44 | PWM_MUL_1_25 LITERAL1 45 | PWM_MUL_1_5 LITERAL1 46 | PWM_MUL_1_75 LITERAL1 47 | PWM_MUL_2 LITERAL1 48 | PWM_DIV_1 LITERAL1 49 | PWM_DIV_2 LITERAL1 50 | PWM_DIV_3 LITERAL1 51 | PWM_DIV_4 LITERAL1 52 | PWM_DIV_5 LITERAL1 53 | PWM_DIV_6 LITERAL1 54 | PWM_DIV_7 LITERAL1 55 | SR_180V_us LITERAL1 56 | SR_290V_us LITERAL1 57 | SR_530V_us LITERAL1 58 | OC_SD_DISABLE LITERAL1 59 | OC_SD_ENABLE LITERAL1 60 | VS_COMP_DISABLE LITERAL1 61 | VS_COMP_ENABLE LITERAL1 62 | SW_HARD_STOP LITERAL1 63 | SW_USER LITERAL1 64 | INT_16MHZ LITERAL1 65 | INT_16MHZ_OSCOUT_2MHZ LITERAL1 66 | INT_16MHZ_OSCOUT_4MHZ LITERAL1 67 | INT_16MHZ_OSCOUT_8MHZ LITERAL1 68 | INT_16MHZ_OSCOUT_16MHZ LITERAL1 69 | EXT_8MHZ_XTAL_DRIVE LITERAL1 70 | EXT_16MHZ_XTAL_DRIVE LITERAL1 71 | EXT_24MHZ_XTAL_DRIVE LITERAL1 72 | EXT_32MHZ_XTAL_DRIVE LITERAL1 73 | EXT_8MHZ_OSCOUT_INVERT LITERAL1 74 | EXT_16MHZ_OSCOUT_INVERT LITERAL1 75 | EXT_24MHZ_OSCOUT_INVERT LITERAL1 76 | EXT_32MHZ_OSCOUT_INVERT LITERAL1 77 | 78 | 79 | # Public functions 80 | AutoDriver KEYWORD2 81 | SPIPortConnect KEYWORD2 82 | busyCheck KEYWORD2 83 | getStatus KEYWORD2 84 | setParam KEYWORD2 85 | getParam KEYWORD2 86 | setLoSpdOpt KEYWORD2 87 | configSyncPin KEYWORD2 88 | configStepMode KEYWORD2 89 | setMaxSpeed KEYWORD2 90 | setMinSpeed KEYWORD2 91 | setFullSpeed KEYWORD2 92 | setAcc KEYWORD2 93 | setDec KEYWORD2 94 | setOCThreshold KEYWORD2 95 | setPWMFreq KEYWORD2 96 | setSlewRate KEYWORD2 97 | setOCShutdown KEYWORD2 98 | setVoltageComp KEYWORD2 99 | setSwitchMode KEYWORD2 100 | setOscMode KEYWORD2 101 | setAccKVAL KEYWORD2 102 | setDecKVAL KEYWORD2 103 | setRunKVAL KEYWORD2 104 | setHoldKVAL KEYWORD2 105 | getLoSpdOpt KEYWORD2 106 | getStepMode KEYWORD2 107 | getMaxSpeed KEYWORD2 108 | getMinSpeed KEYWORD2 109 | getFullSpeed KEYWORD2 110 | getAcc KEYWORD2 111 | getDec KEYWORD2 112 | getOCThreshold KEYWORD2 113 | getPWMFreqDivisor KEYWORD2 114 | getPWMFreqMultiplier KEYWORD2 115 | getSlewRate KEYWORD2 116 | getOCShutdown KEYWORD2 117 | getVoltageComp KEYWORD2 118 | getSwitchMode KEYWORD2 119 | getOscMode KEYWORD2 120 | getAccKVAL KEYWORD2 121 | getDecKVAL KEYWORD2 122 | getRunKVAL KEYWORD2 123 | getHoldKVAL KEYWORD2 124 | getPos KEYWORD2 125 | getMark KEYWORD2 126 | run KEYWORD2 127 | stepClock KEYWORD2 128 | move KEYWORD2 129 | goTo KEYWORD2 130 | goToDir KEYWORD2 131 | goUntil KEYWORD2 132 | releaseSw KEYWORD2 133 | goHome KEYWORD2 134 | goMark KEYWORD2 135 | setMark KEYWORD2 136 | setPos KEYWORD2 137 | resetPos KEYWORD2 138 | resetDev KEYWORD2 139 | softStop KEYWORD2 140 | hardStop KEYWORD2 141 | softHiZ KEYWORD2 142 | hardHiZ KEYWORD2 143 | 144 | 145 | # Class names and data types 146 | AutoDriver KEYWORD1 147 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=SparkFun L6470 AutoDriver 2 | version=1.3.3 3 | author=SparkFun Electronics 4 | maintainer=SparkFun Electronics 5 | sentence=AutoDriver stepper board. SPI driven 3A 8-45V, based on L6470 part from Linear 6 | paragraph=AutoDriver stepper board. SPI driven 3A 8-45V, based on L6470 part from Linear 7 | category=Other 8 | url=https://github.com/sparkfun/SparkFun_AutoDriver_Arduino_Library 9 | architectures=* 10 | -------------------------------------------------------------------------------- /src/.vimproject: -------------------------------------------------------------------------------- 1 | 2 | AutodriverLib=/cygdrive/c/dropbox/projects/libraries/SparkFun_AutoDriver_Arduino_Library CD=. filter="*.c *.cpp *.h *.ino" { 3 | examples=examples { 4 | SparkFundSPINexample=SparkFundSPINexample { 5 | SparkFunL6470.h 6 | SparkFundSPINcommands.ino 7 | SparkFundSPINexample.ino 8 | SparkFundSPINsupport.ino 9 | } 10 | SparkFunGetSetParamTest=SparkFunGetSetParamTest { 11 | SparkFunGetSetParamTest.ino 12 | } 13 | SparkFunLibraryTest=SparkFunLibraryTest { 14 | SparkFunnotes.h 15 | SparkFunLibraryTest.ino 16 | SparkFunsupportFunctions.ino 17 | SparkFunwantYouGone.ino 18 | } 19 | } 20 | src=src { 21 | SparkFunAutoDriver.cpp 22 | SparkFunAutoDriverCommands.cpp 23 | SparkFunAutoDriverConfig.cpp 24 | SparkFunAutoDriverSupport.cpp 25 | SparkFunAutoDriver.h 26 | SparkFundSPINConstants.h 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/SparkFunAutoDriver.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "SparkFunAutoDriver.h" 3 | 4 | int AutoDriver::_numBoards; 5 | 6 | // Constructors 7 | AutoDriver::AutoDriver(int position, int CSPin, int resetPin, int busyPin) 8 | { 9 | _CSPin = CSPin; 10 | _position = position; 11 | _resetPin = resetPin; 12 | _busyPin = busyPin; 13 | _numBoards++; 14 | _SPI = &SPI; 15 | } 16 | 17 | AutoDriver::AutoDriver(int position, int CSPin, int resetPin) 18 | { 19 | _CSPin = CSPin; 20 | _position = position; 21 | _resetPin = resetPin; 22 | _busyPin = -1; 23 | _numBoards++; 24 | _SPI = &SPI; 25 | } 26 | 27 | void AutoDriver::SPIPortConnect(SPIClass *SPIPort) 28 | { 29 | _SPI = SPIPort; 30 | } 31 | 32 | int AutoDriver::busyCheck(void) 33 | { 34 | if (_busyPin == -1) 35 | { 36 | if (getParam(STATUS) & 0x0002) return 0; 37 | else return 1; 38 | } 39 | else 40 | { 41 | if (digitalRead(_busyPin) == HIGH) return 0; 42 | else return 1; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/SparkFunAutoDriver.h: -------------------------------------------------------------------------------- 1 | #ifndef AutoDriver_h 2 | #define AutoDriver_h 3 | 4 | #include "Arduino.h" 5 | #include 6 | #include "SparkFundSPINConstants.h" 7 | 8 | class AutoDriver 9 | { 10 | public: 11 | // Constructors. We'll ALWAYS want a CS pin and a reset pin, but we may 12 | // not want a busy pin. By using two constructors, we make it easy to 13 | // allow that. 14 | AutoDriver(int position, int CSPin, int resetPin, int busyPin); 15 | AutoDriver(int position, int CSPin, int resetPin); 16 | 17 | void SPIPortConnect(SPIClass *SPIPort); 18 | 19 | // These are super-common things to do: checking if the device is busy, 20 | // and checking the status of the device. We make a couple of functions 21 | // for that. 22 | int busyCheck(); 23 | int getStatus(); 24 | 25 | // Some users will want to do things other than what we explicitly provide 26 | // nice functions for; give them unrestricted access to the parameter 27 | // registers. 28 | void setParam(byte param, unsigned long value); 29 | long getParam(byte param); 30 | 31 | // Lots of people just want Commands That Work; let's provide them! 32 | // Start with some configuration commands 33 | void setLoSpdOpt(boolean enable); 34 | void configSyncPin(byte pinFunc, byte syncSteps); 35 | void configStepMode(byte stepMode); 36 | void setMaxSpeed(float stepsPerSecond); 37 | void setMinSpeed(float stepsPerSecond); 38 | void setFullSpeed(float stepsPerSecond); 39 | void setAcc(float stepsPerSecondPerSecond); 40 | void setDec(float stepsPerSecondPerSecond); 41 | void setOCThreshold(byte threshold); 42 | void setPWMFreq(int divisor, int multiplier); 43 | void setSlewRate(int slewRate); 44 | void setOCShutdown(int OCShutdown); 45 | void setVoltageComp(int vsCompMode); 46 | void setSwitchMode(int switchMode); 47 | void setOscMode(int oscillatorMode); 48 | void setAccKVAL(byte kvalInput); 49 | void setDecKVAL(byte kvalInput); 50 | void setRunKVAL(byte kvalInput); 51 | void setHoldKVAL(byte kvalInput); 52 | 53 | boolean getLoSpdOpt(); 54 | // getSyncPin 55 | byte getStepMode(); 56 | float getMaxSpeed(); 57 | float getMinSpeed(); 58 | float getFullSpeed(); 59 | float getAcc(); 60 | float getDec(); 61 | byte getOCThreshold(); 62 | int getPWMFreqDivisor(); 63 | int getPWMFreqMultiplier(); 64 | int getSlewRate(); 65 | int getOCShutdown(); 66 | int getVoltageComp(); 67 | int getSwitchMode(); 68 | int getOscMode(); 69 | byte getAccKVAL(); 70 | byte getDecKVAL(); 71 | byte getRunKVAL(); 72 | byte getHoldKVAL(); 73 | 74 | // ...and now, operational commands. 75 | long getPos(); 76 | long getMark(); 77 | void run(byte dir, float stepsPerSec); 78 | void stepClock(byte dir); 79 | void move(byte dir, unsigned long numSteps); 80 | void goTo(long pos); 81 | void goToDir(byte dir, long pos); 82 | void goUntil(byte action, byte dir, float stepsPerSec); 83 | void releaseSw(byte action, byte dir); 84 | void goHome(); 85 | void goMark(); 86 | void setMark(long newMark); 87 | void setPos(long newPos); 88 | void resetPos(); 89 | void resetDev(); 90 | void softStop(); 91 | void hardStop(); 92 | void softHiZ(); 93 | void hardHiZ(); 94 | 95 | 96 | private: 97 | byte SPIXfer(byte data); 98 | long xferParam(unsigned long value, byte bitLen); 99 | long paramHandler(byte param, unsigned long value); 100 | 101 | // Support functions for converting from user units to L6470 units 102 | unsigned long accCalc(float stepsPerSecPerSec); 103 | unsigned long decCalc(float stepsPerSecPerSec); 104 | unsigned long minSpdCalc(float stepsPerSec); 105 | unsigned long maxSpdCalc(float stepsPerSec); 106 | unsigned long FSCalc(float stepsPerSec); 107 | unsigned long intSpdCalc(float stepsPerSec); 108 | unsigned long spdCalc(float stepsPerSec); 109 | 110 | // Support functions for converting from L6470 to user units 111 | float accParse(unsigned long stepsPerSecPerSec); 112 | float decParse(unsigned long stepsPerSecPerSec); 113 | float minSpdParse(unsigned long stepsPerSec); 114 | float maxSpdParse(unsigned long stepsPerSec); 115 | float FSParse(unsigned long stepsPerSec); 116 | float intSpdParse(unsigned long stepsPerSec); 117 | float spdParse(unsigned long stepsPerSec); 118 | 119 | int _CSPin; 120 | int _resetPin; 121 | int _busyPin; 122 | int _position; 123 | static int _numBoards; 124 | SPIClass *_SPI; 125 | }; 126 | 127 | // User constants for public functions. 128 | 129 | // dSPIN direction options: functions that accept dir as an argument can be 130 | // passed one of these constants. These functions are: 131 | // run() 132 | // stepClock() 133 | // move() 134 | // goToDir() 135 | // goUntil() 136 | // releaseSw() 137 | #define FWD 0x01 138 | #define REV 0x00 139 | 140 | // dSPIN action options: functions that accept action as an argument can be 141 | // passed one of these constants. The contents of ABSPOS will either be 142 | // reset or copied to MARK, depending on the value sent. These functions are: 143 | // goUntil() 144 | // releaseSw() 145 | #define RESET_ABSPOS 0x00 146 | #define COPY_ABSPOS 0x08 147 | 148 | // configSyncPin() options: the !BUSY/SYNC pin can be configured to be low when 149 | // the chip is executing a command, *or* to output a pulse on each full step 150 | // clock (with some divisor). These 151 | #define BUSY_PIN 0x00 // !BUSY/SYNC pin set to !BUSY mode 152 | #define SYNC_PIN 0x80 // pin set to SYNC mode 153 | 154 | // divisors for SYNC pulse outputs 155 | #define SYNC_FS_2 0x00 // two per full step 156 | #define SYNC_FS 0x10 // one per full step 157 | #define SYNC_2FS 0x20 // one per two full steps 158 | #define SYNC_4FS 0x30 // one per four full steps 159 | #define SYNC_8FS 0x40 // one per eight full steps 160 | #define SYNC_16FS 0x50 // one per 16 full steps 161 | #define SYNC_32FS 0x60 // one per 32 full steps 162 | #define SYNC_64FS 0x70 // one per 64 full steps 163 | 164 | // configStepMode() options: select the microsteps per full step. 165 | #define STEP_FS 0x00 // one step per full step 166 | #define STEP_FS_2 0x01 // two microsteps per full step 167 | #define STEP_FS_4 0x02 // four microsteps per full step 168 | #define STEP_FS_8 0x03 // etc. 169 | #define STEP_FS_16 0x04 170 | #define STEP_FS_32 0x05 171 | #define STEP_FS_64 0x06 172 | #define STEP_FS_128 0x07 173 | 174 | // setOCThreshold() options 175 | #define OC_375mA 0x00 176 | #define OC_750mA 0x01 177 | #define OC_1125mA 0x02 178 | #define OC_1500mA 0x03 179 | #define OC_1875mA 0x04 180 | #define OC_2250mA 0x05 181 | #define OC_2625mA 0x06 182 | #define OC_3000mA 0x07 183 | #define OC_3375mA 0x08 184 | #define OC_3750mA 0x09 185 | #define OC_4125mA 0x0A 186 | #define OC_4500mA 0x0B 187 | #define OC_4875mA 0x0C 188 | #define OC_5250mA 0x0D 189 | #define OC_5625mA 0x0E 190 | #define OC_6000mA 0x0F 191 | 192 | // PWM Multiplier and divisor options 193 | #define PWM_MUL_0_625 (0x00)<<10 194 | #define PWM_MUL_0_75 (0x01)<<10 195 | #define PWM_MUL_0_875 (0x02)<<10 196 | #define PWM_MUL_1 (0x03)<<10 197 | #define PWM_MUL_1_25 (0x04)<<10 198 | #define PWM_MUL_1_5 (0x05)<<10 199 | #define PWM_MUL_1_75 (0x06)<<10 200 | #define PWM_MUL_2 (0x07)<<10 201 | #define PWM_DIV_1 (0x00)<<13 202 | #define PWM_DIV_2 (0x01)<<13 203 | #define PWM_DIV_3 (0x02)<<13 204 | #define PWM_DIV_4 (0x03)<<13 205 | #define PWM_DIV_5 (0x04)<<13 206 | #define PWM_DIV_6 (0x05)<<13 207 | #define PWM_DIV_7 (0x06)<<13 208 | 209 | // Slew rate options 210 | #define SR_180V_us 0x0000 // 180V/us 211 | #define SR_290V_us 0x0200 // 290V/us 212 | #define SR_530V_us 0x0300 // 530V/us 213 | 214 | // Overcurrent bridge shutdown options 215 | #define OC_SD_DISABLE 0x0000 // Bridges do NOT shutdown on OC detect 216 | #define OC_SD_ENABLE 0x0080 // Bridges shutdown on OC detect 217 | 218 | // Voltage compensation settings. See p 34 of datasheet. 219 | #define VS_COMP_DISABLE 0x0000 // Disable motor voltage compensation. 220 | #define VS_COMP_ENABLE 0x0020 // Enable motor voltage compensation. 221 | 222 | // External switch input functionality. 223 | #define SW_HARD_STOP 0x0000 // Default; hard stop motor on switch. 224 | #define SW_USER 0x0010 // Tie to the GoUntil and ReleaseSW 225 | // commands to provide jog function. 226 | // See page 25 of datasheet. 227 | 228 | // Clock functionality 229 | #define INT_16MHZ 0x0000 // Internal 16MHz, no output 230 | #define INT_16MHZ_OSCOUT_2MHZ 0x0008 // Default; internal 16MHz, 2MHz output 231 | #define INT_16MHZ_OSCOUT_4MHZ 0x0009 // Internal 16MHz, 4MHz output 232 | #define INT_16MHZ_OSCOUT_8MHZ 0x000A // Internal 16MHz, 8MHz output 233 | #define INT_16MHZ_OSCOUT_16MHZ 0x000B // Internal 16MHz, 16MHz output 234 | #define EXT_8MHZ_XTAL_DRIVE 0x0004 // External 8MHz crystal 235 | #define EXT_16MHZ_XTAL_DRIVE 0x0005 // External 16MHz crystal 236 | #define EXT_24MHZ_XTAL_DRIVE 0x0006 // External 24MHz crystal 237 | #define EXT_32MHZ_XTAL_DRIVE 0x0007 // External 32MHz crystal 238 | #define EXT_8MHZ_OSCOUT_INVERT 0x000C // External 8MHz crystal, output inverted 239 | #define EXT_16MHZ_OSCOUT_INVERT 0x000D // External 16MHz crystal, output inverted 240 | #define EXT_24MHZ_OSCOUT_INVERT 0x000E // External 24MHz crystal, output inverted 241 | #define EXT_32MHZ_OSCOUT_INVERT 0x000F // External 32MHz crystal, output inverted 242 | #endif 243 | 244 | -------------------------------------------------------------------------------- /src/SparkFunAutoDriverCommands.cpp: -------------------------------------------------------------------------------- 1 | #include "SparkFunAutoDriver.h" 2 | 3 | //commands.ino - Contains high-level command implementations- movement 4 | // and configuration commands, for example. 5 | 6 | // Realize the "set parameter" function, to write to the various registers in 7 | // the dSPIN chip. 8 | void AutoDriver::setParam(byte param, unsigned long value) 9 | { 10 | param |= SET_PARAM; 11 | SPIXfer((byte)param); 12 | paramHandler(param, value); 13 | } 14 | 15 | // Realize the "get parameter" function, to read from the various registers in 16 | // the dSPIN chip. 17 | long AutoDriver::getParam(byte param) 18 | { 19 | SPIXfer(param | GET_PARAM); 20 | return paramHandler(param, 0); 21 | } 22 | 23 | // Returns the content of the ABS_POS register, which is a signed 22-bit number 24 | // indicating the number of steps the motor has traveled from the HOME 25 | // position. HOME is defined by zeroing this register, and it is zero on 26 | // startup. 27 | long AutoDriver::getPos() 28 | { 29 | long temp = getParam(ABS_POS); 30 | 31 | // Since ABS_POS is a 22-bit 2's comp value, we need to check bit 21 and, if 32 | // it's set, set all the bits ABOVE 21 in order for the value to maintain 33 | // its appropriate sign. 34 | if (temp & 0x00200000) temp |= 0xffc00000; 35 | return temp; 36 | } 37 | 38 | // Just like getPos(), but for MARK. 39 | long AutoDriver::getMark() 40 | { 41 | long temp = getParam(MARK); 42 | 43 | // Since ABS_POS is a 22-bit 2's comp value, we need to check bit 21 and, if 44 | // it's set, set all the bits ABOVE 21 in order for the value to maintain 45 | // its appropriate sign. 46 | if (temp & 0x00200000) temp |= 0xffC00000; 47 | return temp; 48 | } 49 | 50 | // RUN sets the motor spinning in a direction (defined by the constants 51 | // FWD and REV). Maximum speed and minimum speed are defined 52 | // by the MAX_SPEED and MIN_SPEED registers; exceeding the FS_SPD value 53 | // will switch the device into full-step mode. 54 | // The spdCalc() function is provided to convert steps/s values into 55 | // appropriate integer values for this function. 56 | void AutoDriver::run(byte dir, float stepsPerSec) 57 | { 58 | SPIXfer(RUN | dir); 59 | unsigned long integerSpeed = spdCalc(stepsPerSec); 60 | if (integerSpeed > 0xFFFFF) integerSpeed = 0xFFFFF; 61 | 62 | // Now we need to push this value out to the dSPIN. The 32-bit value is 63 | // stored in memory in little-endian format, but the dSPIN expects a 64 | // big-endian output, so we need to reverse the byte-order of the 65 | // data as we're sending it out. Note that only 3 of the 4 bytes are 66 | // valid here. 67 | 68 | // We begin by pointing bytePointer at the first byte in integerSpeed. 69 | byte* bytePointer = (byte*)&integerSpeed; 70 | // Next, we'll iterate through a for loop, indexing across the bytes in 71 | // integerSpeed starting with byte 2 and ending with byte 0. 72 | for (int8_t i = 2; i >= 0; i--) 73 | { 74 | SPIXfer(bytePointer[i]); 75 | } 76 | } 77 | 78 | // STEP_CLOCK puts the device in external step clocking mode. When active, 79 | // pin 25, STCK, becomes the step clock for the device, and steps it in 80 | // the direction (set by the FWD and REV constants) imposed by the call 81 | // of this function. Motion commands (RUN, MOVE, etc) will cause the device 82 | // to exit step clocking mode. 83 | void AutoDriver::stepClock(byte dir) 84 | { 85 | SPIXfer(STEP_CLOCK | dir); 86 | } 87 | 88 | // MOVE will send the motor numStep full steps in the 89 | // direction imposed by dir (FWD or REV constants may be used). The motor 90 | // will accelerate according the acceleration and deceleration curves, and 91 | // will run at MAX_SPEED. Stepping mode will adhere to FS_SPD value, as well. 92 | void AutoDriver::move(byte dir, unsigned long numSteps) 93 | { 94 | SPIXfer(MOVE | dir); 95 | if (numSteps > 0x3FFFFF) numSteps = 0x3FFFFF; 96 | // See run() for an explanation of what's going on here. 97 | byte* bytePointer = (byte*)&numSteps; 98 | for (int8_t i = 2; i >= 0; i--) 99 | { 100 | SPIXfer(bytePointer[i]); 101 | } 102 | } 103 | 104 | // GOTO operates much like MOVE, except it produces absolute motion instead 105 | // of relative motion. The motor will be moved to the indicated position 106 | // in the shortest possible fashion. 107 | void AutoDriver::goTo(long pos) 108 | { 109 | SPIXfer(GOTO); 110 | if (pos > 0x3FFFFF) pos = 0x3FFFFF; 111 | // See run() for an explanation of what's going on here. 112 | byte* bytePointer = (byte*)&pos; 113 | for (int8_t i = 2; i >= 0; i--) 114 | { 115 | SPIXfer(bytePointer[i]); 116 | } 117 | } 118 | 119 | // Same as GOTO, but with user constrained rotational direction. 120 | void AutoDriver::goToDir(byte dir, long pos) 121 | { 122 | SPIXfer(GOTO_DIR | dir); 123 | if (pos > 0x3FFFFF) pos = 0x3FFFFF; 124 | // See run() for an explanation of what's going on here. 125 | byte* bytePointer = (byte*)&pos; 126 | for (int8_t i = 2; i >= 0; i--) 127 | { 128 | SPIXfer(bytePointer[i]); 129 | } 130 | } 131 | 132 | // GoUntil will set the motor running with direction dir (REV or 133 | // FWD) until a falling edge is detected on the SW pin. Depending 134 | // on bit SW_MODE in CONFIG, either a hard stop or a soft stop is 135 | // performed at the falling edge, and depending on the value of 136 | // act (either RESET or COPY) the value in the ABS_POS register is 137 | // either RESET to 0 or COPY-ed into the MARK register. 138 | void AutoDriver::goUntil(byte action, byte dir, float stepsPerSec) 139 | { 140 | SPIXfer(GO_UNTIL | action | dir); 141 | unsigned long integerSpeed = spdCalc(stepsPerSec); 142 | if (integerSpeed > 0x3FFFFF) integerSpeed = 0x3FFFFF; 143 | // See run() for an explanation of what's going on here. 144 | byte* bytePointer = (byte*)&integerSpeed; 145 | for (int8_t i = 2; i >= 0; i--) 146 | { 147 | SPIXfer(bytePointer[i]); 148 | } 149 | } 150 | 151 | // Similar in nature to GoUntil, ReleaseSW produces motion at the 152 | // higher of two speeds: the value in MIN_SPEED or 5 steps/s. 153 | // The motor continues to run at this speed until a rising edge 154 | // is detected on the switch input, then a hard stop is performed 155 | // and the ABS_POS register is either COPY-ed into MARK or RESET to 156 | // 0, depending on whether RESET or COPY was passed to the function 157 | // for act. 158 | void AutoDriver::releaseSw(byte action, byte dir) 159 | { 160 | SPIXfer(RELEASE_SW | action | dir); 161 | } 162 | 163 | // GoHome is equivalent to GoTo(0), but requires less time to send. 164 | // Note that no direction is provided; motion occurs through shortest 165 | // path. If a direction is required, use GoTo_DIR(). 166 | void AutoDriver::goHome() 167 | { 168 | SPIXfer(GO_HOME); 169 | } 170 | 171 | // GoMark is equivalent to GoTo(MARK), but requires less time to send. 172 | // Note that no direction is provided; motion occurs through shortest 173 | // path. If a direction is required, use GoTo_DIR(). 174 | void AutoDriver::goMark() 175 | { 176 | SPIXfer(GO_MARK); 177 | } 178 | 179 | // setMark() and setHome() allow the user to define new MARK or 180 | // ABS_POS values. 181 | void AutoDriver::setMark(long newMark) 182 | { 183 | setParam(MARK, newMark); 184 | } 185 | 186 | void AutoDriver::setPos(long newPos) 187 | { 188 | setParam(ABS_POS, newPos); 189 | } 190 | 191 | // Sets the ABS_POS register to 0, effectively declaring the current 192 | // position to be "HOME". 193 | void AutoDriver::resetPos() 194 | { 195 | SPIXfer(RESET_POS); 196 | } 197 | 198 | // Reset device to power up conditions. Equivalent to toggling the STBY 199 | // pin or cycling power. 200 | void AutoDriver::resetDev() 201 | { 202 | SPIXfer(RESET_DEVICE); 203 | } 204 | 205 | // Bring the motor to a halt using the deceleration curve. 206 | void AutoDriver::softStop() 207 | { 208 | SPIXfer(SOFT_STOP); 209 | } 210 | 211 | // Stop the motor with infinite deceleration. 212 | void AutoDriver::hardStop() 213 | { 214 | SPIXfer(HARD_STOP); 215 | } 216 | 217 | // Decelerate the motor and put the bridges in Hi-Z state. 218 | void AutoDriver::softHiZ() 219 | { 220 | SPIXfer(SOFT_HIZ); 221 | } 222 | 223 | // Put the bridges in Hi-Z state immediately with no deceleration. 224 | void AutoDriver::hardHiZ() 225 | { 226 | SPIXfer(HARD_HIZ); 227 | } 228 | 229 | // Fetch and return the 16-bit value in the STATUS register. Resets 230 | // any warning flags and exits any error states. Using GetParam() 231 | // to read STATUS does not clear these values. 232 | int AutoDriver::getStatus() 233 | { 234 | int temp = 0; 235 | byte* bytePointer = (byte*)&temp; 236 | SPIXfer(GET_STATUS); 237 | bytePointer[1] = SPIXfer(0); 238 | bytePointer[0] = SPIXfer(0); 239 | return temp; 240 | } 241 | -------------------------------------------------------------------------------- /src/SparkFunAutoDriverConfig.cpp: -------------------------------------------------------------------------------- 1 | #include "SparkFunAutoDriver.h" 2 | 3 | // Setup the SYNC/BUSY pin to be either SYNC or BUSY, and to a desired 4 | // ticks per step level. 5 | void AutoDriver::configSyncPin(byte pinFunc, byte syncSteps) 6 | { 7 | // Only some of the bits in this register are of interest to us; we need to 8 | // clear those bits. It happens that they are the upper four. 9 | byte syncPinConfig = (byte)getParam(STEP_MODE); 10 | syncPinConfig &= 0x0F; 11 | 12 | // Now, let's OR in the arguments. We're going to mask the incoming 13 | // data to avoid touching any bits that aren't appropriate. See datasheet 14 | // for more info about which bits we're touching. 15 | syncPinConfig |= ((pinFunc & 0x80) | (syncSteps & 0x70)); 16 | 17 | // Now we should be able to send that byte right back to the dSPIN- it 18 | // won't corrupt the other bits, and the changes are made. 19 | setParam(STEP_MODE, (unsigned long)syncPinConfig); 20 | } 21 | 22 | // The dSPIN chip supports microstepping for a smoother ride. This function 23 | // provides an easy front end for changing the microstepping mode. 24 | void AutoDriver::configStepMode(byte stepMode) 25 | { 26 | 27 | // Only some of these bits are useful (the lower three). We'll extract the 28 | // current contents, clear those three bits, then set them accordingly. 29 | byte stepModeConfig = (byte)getParam(STEP_MODE); 30 | stepModeConfig &= 0xF8; 31 | 32 | // Now we can OR in the new bit settings. Mask the argument so we don't 33 | // accidentally the other bits, if the user sends us a non-legit value. 34 | stepModeConfig |= (stepMode&0x07); 35 | 36 | // Now push the change to the chip. 37 | setParam(STEP_MODE, (unsigned long)stepModeConfig); 38 | } 39 | 40 | byte AutoDriver::getStepMode() { 41 | return (byte)(getParam(STEP_MODE) & 0x07); 42 | } 43 | 44 | // This is the maximum speed the dSPIN will attempt to produce. 45 | void AutoDriver::setMaxSpeed(float stepsPerSecond) 46 | { 47 | // We need to convert the floating point stepsPerSecond into a value that 48 | // the dSPIN can understand. Fortunately, we have a function to do that. 49 | unsigned long integerSpeed = maxSpdCalc(stepsPerSecond); 50 | 51 | // Now, we can set that paramter. 52 | setParam(MAX_SPEED, integerSpeed); 53 | } 54 | 55 | 56 | float AutoDriver::getMaxSpeed() 57 | { 58 | return maxSpdParse(getParam(MAX_SPEED)); 59 | } 60 | 61 | // Set the minimum speed allowable in the system. This is the speed a motion 62 | // starts with; it will then ramp up to the designated speed or the max 63 | // speed, using the acceleration profile. 64 | void AutoDriver::setMinSpeed(float stepsPerSecond) 65 | { 66 | // We need to convert the floating point stepsPerSecond into a value that 67 | // the dSPIN can understand. Fortunately, we have a function to do that. 68 | unsigned long integerSpeed = minSpdCalc(stepsPerSecond); 69 | 70 | // MIN_SPEED also contains the LSPD_OPT flag, so we need to protect that. 71 | unsigned long temp = getParam(MIN_SPEED) & 0x00001000; 72 | 73 | // Now, we can set that paramter. 74 | setParam(MIN_SPEED, integerSpeed | temp); 75 | } 76 | 77 | float AutoDriver::getMinSpeed() 78 | { 79 | return minSpdParse(getParam(MIN_SPEED)); 80 | } 81 | 82 | // Above this threshold, the dSPIN will cease microstepping and go to full-step 83 | // mode. 84 | void AutoDriver::setFullSpeed(float stepsPerSecond) 85 | { 86 | unsigned long integerSpeed = FSCalc(stepsPerSecond); 87 | setParam(FS_SPD, integerSpeed); 88 | } 89 | 90 | float AutoDriver::getFullSpeed() 91 | { 92 | return FSParse(getParam(FS_SPD)); 93 | } 94 | 95 | // Set the acceleration rate, in steps per second per second. This value is 96 | // converted to a dSPIN friendly value. Any value larger than 29802 will 97 | // disable acceleration, putting the chip in "infinite" acceleration mode. 98 | void AutoDriver::setAcc(float stepsPerSecondPerSecond) 99 | { 100 | unsigned long integerAcc = accCalc(stepsPerSecondPerSecond); 101 | setParam(ACC, integerAcc); 102 | } 103 | 104 | float AutoDriver::getAcc() 105 | { 106 | return accParse(getParam(ACC)); 107 | } 108 | 109 | // Same rules as setAcc(). 110 | void AutoDriver::setDec(float stepsPerSecondPerSecond) 111 | { 112 | unsigned long integerDec = decCalc(stepsPerSecondPerSecond); 113 | setParam(DECEL, integerDec); 114 | } 115 | 116 | float AutoDriver::getDec() 117 | { 118 | return accParse(getParam(DECEL)); 119 | } 120 | 121 | void AutoDriver::setOCThreshold(byte threshold) 122 | { 123 | setParam(OCD_TH, 0x0F & threshold); 124 | } 125 | 126 | byte AutoDriver::getOCThreshold() 127 | { 128 | return (byte) (getParam(OCD_TH) & 0xF); 129 | } 130 | 131 | // The next few functions are all breakouts for individual options within the 132 | // single register CONFIG. We'll read CONFIG, blank some bits, then OR in the 133 | // new value. 134 | 135 | // This is a multiplier/divider setup for the PWM frequency when microstepping. 136 | // Divisors of 1-7 are available; multipliers of .625-2 are available. See 137 | // datasheet for more details; it's not clear what the frequency being 138 | // multiplied/divided here is, but it is clearly *not* the actual clock freq. 139 | void AutoDriver::setPWMFreq(int divisor, int multiplier) 140 | { 141 | unsigned long configVal = getParam(CONFIG); 142 | 143 | // The divisor is set by config 15:13, so mask 0xE000 to clear them. 144 | configVal &= ~(0xE000); 145 | // The multiplier is set by config 12:10; mask is 0x1C00 146 | configVal &= ~(0x1C00); 147 | // Now we can OR in the masked-out versions of the values passed in. 148 | configVal |= ((0xE000&divisor)|(0x1C00&multiplier)); 149 | setParam(CONFIG, configVal); 150 | } 151 | 152 | int AutoDriver::getPWMFreqDivisor() 153 | { 154 | return (int) (getParam(CONFIG) & 0xE000); 155 | } 156 | 157 | int AutoDriver::getPWMFreqMultiplier() 158 | { 159 | return (int) (getParam(CONFIG) & 0x1C00); 160 | } 161 | 162 | // Slew rate of the output in V/us. Can be 180, 290, or 530. 163 | void AutoDriver::setSlewRate(int slewRate) 164 | { 165 | unsigned long configVal = getParam(CONFIG); 166 | 167 | // These bits live in CONFIG 9:8, so the mask is 0x0300. 168 | configVal &= ~(0x0300); 169 | //Now, OR in the masked incoming value. 170 | configVal |= (0x0300&slewRate); 171 | setParam(CONFIG, configVal); 172 | } 173 | 174 | int AutoDriver::getSlewRate() 175 | { 176 | return (int) (getParam(CONFIG) & 0x0300); 177 | } 178 | 179 | // Single bit- do we shutdown the drivers on overcurrent or not? 180 | void AutoDriver::setOCShutdown(int OCShutdown) 181 | { 182 | unsigned long configVal = getParam(CONFIG); 183 | // This bit is CONFIG 7, mask is 0x0080 184 | configVal &= ~(0x0080); 185 | //Now, OR in the masked incoming value. 186 | configVal |= (0x0080&OCShutdown); 187 | setParam(CONFIG, configVal); 188 | } 189 | 190 | int AutoDriver::getOCShutdown() 191 | { 192 | return (int) (getParam(CONFIG) & 0x0080); 193 | } 194 | 195 | // Enable motor voltage compensation? Not at all straightforward- check out 196 | // p34 of the datasheet. 197 | void AutoDriver::setVoltageComp(int vsCompMode) 198 | { 199 | unsigned long configVal = getParam(CONFIG); 200 | // This bit is CONFIG 5, mask is 0x0020 201 | configVal &= ~(0x0020); 202 | //Now, OR in the masked incoming value. 203 | configVal |= (0x0020&vsCompMode); 204 | setParam(CONFIG, configVal); 205 | } 206 | 207 | int AutoDriver::getVoltageComp() 208 | { 209 | return (int) (getParam(CONFIG) & 0x0020); 210 | } 211 | 212 | // The switch input can either hard-stop the driver _or_ activate an interrupt. 213 | // This bit allows you to select what it does. 214 | void AutoDriver::setSwitchMode(int switchMode) 215 | { 216 | unsigned long configVal = getParam(CONFIG); 217 | // This bit is CONFIG 4, mask is 0x0010 218 | configVal &= ~(0x0010); 219 | //Now, OR in the masked incoming value. 220 | configVal |= (0x0010 & switchMode); 221 | setParam(CONFIG, configVal); 222 | } 223 | 224 | int AutoDriver::getSwitchMode() 225 | { 226 | return (int) (getParam(CONFIG) & 0x0010); 227 | } 228 | 229 | // There are a number of clock options for this chip- it can be configured to 230 | // accept a clock, drive a crystal or resonator, and pass or not pass the 231 | // clock signal downstream. Theoretically, you can use pretty much any 232 | // frequency you want to drive it; practically, this library assumes it's 233 | // being driven at 16MHz. Also, the device will use these bits to set the 234 | // math used to figure out steps per second and stuff like that. 235 | void AutoDriver::setOscMode(int oscillatorMode) 236 | { 237 | unsigned long configVal = getParam(CONFIG); 238 | // These bits are CONFIG 3:0, mask is 0x000F 239 | configVal &= ~(0x000F); 240 | //Now, OR in the masked incoming value. 241 | configVal |= (0x000F&oscillatorMode); 242 | setParam(CONFIG, configVal); 243 | } 244 | 245 | int AutoDriver::getOscMode() 246 | { 247 | return (int) (getParam(CONFIG) & 0x000F); 248 | } 249 | 250 | // The KVAL registers are...weird. I don't entirely understand how they differ 251 | // from the microstepping, but if you have trouble getting the motor to run, 252 | // tweaking KVAL has proven effective in the past. There's a separate register 253 | // for each case: running, static, accelerating, and decelerating. 254 | 255 | void AutoDriver::setAccKVAL(byte kvalInput) 256 | { 257 | setParam(KVAL_ACC, kvalInput); 258 | } 259 | 260 | byte AutoDriver::getAccKVAL() 261 | { 262 | return (byte) getParam(KVAL_ACC); 263 | } 264 | 265 | void AutoDriver::setDecKVAL(byte kvalInput) 266 | { 267 | setParam(KVAL_DEC, kvalInput); 268 | } 269 | 270 | byte AutoDriver::getDecKVAL() 271 | { 272 | return (byte) getParam(KVAL_DEC); 273 | } 274 | 275 | void AutoDriver::setRunKVAL(byte kvalInput) 276 | { 277 | setParam(KVAL_RUN, kvalInput); 278 | } 279 | 280 | byte AutoDriver::getRunKVAL() 281 | { 282 | return (byte) getParam(KVAL_RUN); 283 | } 284 | 285 | void AutoDriver::setHoldKVAL(byte kvalInput) 286 | { 287 | setParam(KVAL_HOLD, kvalInput); 288 | } 289 | 290 | byte AutoDriver::getHoldKVAL() 291 | { 292 | return (byte) getParam(KVAL_HOLD); 293 | } 294 | 295 | // Enable or disable the low-speed optimization option. With LSPD_OPT enabled, 296 | // motion starts from 0 instead of MIN_SPEED and low-speed optimization keeps 297 | // the driving sine wave prettier than normal until MIN_SPEED is reached. 298 | void AutoDriver::setLoSpdOpt(boolean enable) 299 | { 300 | unsigned long temp = getParam(MIN_SPEED); 301 | if (enable) temp |= 0x00001000; // Set the LSPD_OPT bit 302 | else temp &= 0xffffefff; // Clear the LSPD_OPT bit 303 | setParam(MIN_SPEED, temp); 304 | } 305 | 306 | boolean AutoDriver::getLoSpdOpt() 307 | { 308 | return (boolean) ((getParam(MIN_SPEED) & 0x00001000) != 0); 309 | } 310 | 311 | -------------------------------------------------------------------------------- /src/SparkFunAutoDriverSupport.cpp: -------------------------------------------------------------------------------- 1 | #include "SparkFunAutoDriver.h" 2 | #include 3 | 4 | // AutoDriverSupport.cpp - Contains utility functions for converting real-world 5 | // units (eg, steps/s) to values usable by the dsPIN controller. These are all 6 | // private members of class AutoDriver. 7 | 8 | // The value in the ACC register is [(steps/s/s)*(tick^2)]/(2^-40) where tick is 9 | // 250ns (datasheet value)- 0x08A on boot. 10 | // Multiply desired steps/s/s by .137438 to get an appropriate value for this register. 11 | // This is a 12-bit value, so we need to make sure the value is at or below 0xFFF. 12 | unsigned long AutoDriver::accCalc(float stepsPerSecPerSec) 13 | { 14 | float temp = stepsPerSecPerSec * 0.137438; 15 | if( (unsigned long) long(temp) > 0x00000FFF) return 0x00000FFF; 16 | else return (unsigned long) long(temp); 17 | } 18 | 19 | 20 | float AutoDriver::accParse(unsigned long stepsPerSecPerSec) 21 | { 22 | return (float) (stepsPerSecPerSec & 0x00000FFF) / 0.137438; 23 | } 24 | 25 | // The calculation for DEC is the same as for ACC. Value is 0x08A on boot. 26 | // This is a 12-bit value, so we need to make sure the value is at or below 0xFFF. 27 | unsigned long AutoDriver::decCalc(float stepsPerSecPerSec) 28 | { 29 | float temp = stepsPerSecPerSec * 0.137438; 30 | if( (unsigned long) long(temp) > 0x00000FFF) return 0x00000FFF; 31 | else return (unsigned long) long(temp); 32 | } 33 | 34 | float AutoDriver::decParse(unsigned long stepsPerSecPerSec) 35 | { 36 | return (float) (stepsPerSecPerSec & 0x00000FFF) / 0.137438; 37 | } 38 | 39 | // The value in the MAX_SPD register is [(steps/s)*(tick)]/(2^-18) where tick is 40 | // 250ns (datasheet value)- 0x041 on boot. 41 | // Multiply desired steps/s by .065536 to get an appropriate value for this register 42 | // This is a 10-bit value, so we need to make sure it remains at or below 0x3FF 43 | unsigned long AutoDriver::maxSpdCalc(float stepsPerSec) 44 | { 45 | unsigned long temp = ceil(stepsPerSec * .065536); 46 | if( temp > 0x000003FF) return 0x000003FF; 47 | else return temp; 48 | } 49 | 50 | 51 | float AutoDriver::maxSpdParse(unsigned long stepsPerSec) 52 | { 53 | return (float) (stepsPerSec & 0x000003FF) / 0.065536; 54 | } 55 | 56 | // The value in the MIN_SPD register is [(steps/s)*(tick)]/(2^-24) where tick is 57 | // 250ns (datasheet value)- 0x000 on boot. 58 | // Multiply desired steps/s by 4.1943 to get an appropriate value for this register 59 | // This is a 12-bit value, so we need to make sure the value is at or below 0xFFF. 60 | unsigned long AutoDriver::minSpdCalc(float stepsPerSec) 61 | { 62 | float temp = stepsPerSec / 0.238; 63 | if( (unsigned long) long(temp) > 0x00000FFF) return 0x00000FFF; 64 | else return (unsigned long) long(temp); 65 | } 66 | 67 | float AutoDriver::minSpdParse(unsigned long stepsPerSec) 68 | { 69 | return (float) ((stepsPerSec & 0x00000FFF) * 0.238); 70 | } 71 | 72 | // The value in the FS_SPD register is ([(steps/s)*(tick)]/(2^-18))-0.5 where tick is 73 | // 250ns (datasheet value)- 0x027 on boot. 74 | // Multiply desired steps/s by .065536 and subtract .5 to get an appropriate value for this register 75 | // This is a 10-bit value, so we need to make sure the value is at or below 0x3FF. 76 | unsigned long AutoDriver::FSCalc(float stepsPerSec) 77 | { 78 | float temp = (stepsPerSec * .065536)-.5; 79 | if( (unsigned long) long(temp) > 0x000003FF) return 0x000003FF; 80 | else return (unsigned long) long(temp); 81 | } 82 | 83 | float AutoDriver::FSParse(unsigned long stepsPerSec) 84 | { 85 | return (((float) (stepsPerSec & 0x000003FF)) + 0.5) / 0.065536; 86 | } 87 | 88 | // The value in the INT_SPD register is [(steps/s)*(tick)]/(2^-24) where tick is 89 | // 250ns (datasheet value)- 0x408 on boot. 90 | // Multiply desired steps/s by 4.1943 to get an appropriate value for this register 91 | // This is a 14-bit value, so we need to make sure the value is at or below 0x3FFF. 92 | unsigned long AutoDriver::intSpdCalc(float stepsPerSec) 93 | { 94 | float temp = stepsPerSec * 4.1943; 95 | if( (unsigned long) long(temp) > 0x00003FFF) return 0x00003FFF; 96 | else return (unsigned long) long(temp); 97 | } 98 | 99 | float AutoDriver::intSpdParse(unsigned long stepsPerSec) 100 | { 101 | return (float) (stepsPerSec & 0x00003FFF) / 4.1943; 102 | } 103 | 104 | // When issuing RUN command, the 20-bit speed is [(steps/s)*(tick)]/(2^-28) where tick is 105 | // 250ns (datasheet value). 106 | // Multiply desired steps/s by 67.106 to get an appropriate value for this register 107 | // This is a 20-bit value, so we need to make sure the value is at or below 0xFFFFF. 108 | unsigned long AutoDriver::spdCalc(float stepsPerSec) 109 | { 110 | unsigned long temp = stepsPerSec * 67.106; 111 | if( temp > 0x000FFFFF) return 0x000FFFFF; 112 | else return temp; 113 | } 114 | 115 | float AutoDriver::spdParse(unsigned long stepsPerSec) 116 | { 117 | return (float) (stepsPerSec & 0x000FFFFF) / 67.106; 118 | } 119 | 120 | // Much of the functionality between "get parameter" and "set parameter" is 121 | // very similar, so we deal with that by putting all of it in one function 122 | // here to save memory space and simplify the program. 123 | long AutoDriver::paramHandler(byte param, unsigned long value) 124 | { 125 | long retVal = 0; // This is a temp for the value to return. 126 | 127 | // This switch structure handles the appropriate action for each register. 128 | // This is necessary since not all registers are of the same length, either 129 | // bit-wise or byte-wise, so we want to make sure we mask out any spurious 130 | // bits and do the right number of transfers. That is handled by the xferParam() 131 | // function, in most cases, but for 1-byte or smaller transfers, we call 132 | // SPIXfer() directly. 133 | switch (param) 134 | { 135 | // ABS_POS is the current absolute offset from home. It is a 22 bit number expressed 136 | // in two's complement. At power up, this value is 0. It cannot be written when 137 | // the motor is running, but at any other time, it can be updated to change the 138 | // interpreted position of the motor. 139 | case ABS_POS: 140 | retVal = xferParam(value, 22); 141 | break; 142 | // EL_POS is the current electrical position in the step generation cycle. It can 143 | // be set when the motor is not in motion. Value is 0 on power up. 144 | case EL_POS: 145 | retVal = xferParam(value, 9); 146 | break; 147 | // MARK is a second position other than 0 that the motor can be told to go to. As 148 | // with ABS_POS, it is 22-bit two's complement. Value is 0 on power up. 149 | case MARK: 150 | retVal = xferParam(value, 22); 151 | break; 152 | // SPEED contains information about the current speed. It is read-only. It does 153 | // NOT provide direction information. 154 | case SPEED: 155 | retVal = xferParam(0, 20); 156 | break; 157 | // ACC and DEC set the acceleration and deceleration rates. Set ACC to 0xFFF 158 | // to get infinite acceleration/decelaeration- there is no way to get infinite 159 | // deceleration w/o infinite acceleration (except the HARD STOP command). 160 | // Cannot be written while motor is running. Both default to 0x08A on power up. 161 | // AccCalc() and DecCalc() functions exist to convert steps/s/s values into 162 | // 12-bit values for these two registers. 163 | case ACC: 164 | retVal = xferParam(value, 12); 165 | break; 166 | case DECEL: 167 | retVal = xferParam(value, 12); 168 | break; 169 | // MAX_SPEED is just what it says- any command which attempts to set the speed 170 | // of the motor above this value will simply cause the motor to turn at this 171 | // speed. Value is 0x041 on power up. 172 | // MaxSpdCalc() function exists to convert steps/s value into a 10-bit value 173 | // for this register. 174 | case MAX_SPEED: 175 | retVal = xferParam(value, 10); 176 | break; 177 | // MIN_SPEED controls two things- the activation of the low-speed optimization 178 | // feature and the lowest speed the motor will be allowed to operate at. LSPD_OPT 179 | // is the 13th bit, and when it is set, the minimum allowed speed is automatically 180 | // set to zero. This value is 0 on startup. 181 | // MinSpdCalc() function exists to convert steps/s value into a 12-bit value for this 182 | // register. SetLSPDOpt() function exists to enable/disable the optimization feature. 183 | case MIN_SPEED: 184 | retVal = xferParam(value, 13); 185 | break; 186 | // FS_SPD register contains a threshold value above which microstepping is disabled 187 | // and the dSPIN operates in full-step mode. Defaults to 0x027 on power up. 188 | // FSCalc() function exists to convert steps/s value into 10-bit integer for this 189 | // register. 190 | case FS_SPD: 191 | retVal = xferParam(value, 10); 192 | break; 193 | // KVAL is the maximum voltage of the PWM outputs. These 8-bit values are ratiometric 194 | // representations: 255 for full output voltage, 128 for half, etc. Default is 0x29. 195 | // The implications of different KVAL settings is too complex to dig into here, but 196 | // it will usually work to max the value for RUN, ACC, and DEC. Maxing the value for 197 | // HOLD may result in excessive power dissipation when the motor is not running. 198 | case KVAL_HOLD: 199 | retVal = xferParam(value, 8); 200 | break; 201 | case KVAL_RUN: 202 | retVal = xferParam(value, 8); 203 | break; 204 | case KVAL_ACC: 205 | retVal = xferParam(value, 8); 206 | break; 207 | case KVAL_DEC: 208 | retVal = xferParam(value, 8); 209 | break; 210 | // INT_SPD, ST_SLP, FN_SLP_ACC and FN_SLP_DEC are all related to the back EMF 211 | // compensation functionality. Please see the datasheet for details of this 212 | // function- it is too complex to discuss here. Default values seem to work 213 | // well enough. 214 | case INT_SPD: 215 | retVal = xferParam(value, 14); 216 | break; 217 | case ST_SLP: 218 | retVal = xferParam(value, 8); 219 | break; 220 | case FN_SLP_ACC: 221 | retVal = xferParam(value, 8); 222 | break; 223 | case FN_SLP_DEC: 224 | retVal = xferParam(value, 8); 225 | break; 226 | // K_THERM is motor winding thermal drift compensation. Please see the datasheet 227 | // for full details on operation- the default value should be okay for most users. 228 | case K_THERM: 229 | value &= 0x0F; 230 | retVal = xferParam(value, 8); 231 | break; 232 | // ADC_OUT is a read-only register containing the result of the ADC measurements. 233 | // This is less useful than it sounds; see the datasheet for more information. 234 | case ADC_OUT: 235 | retVal = xferParam(value, 8); 236 | break; 237 | // Set the overcurrent threshold. Ranges from 375mA to 6A in steps of 375mA. 238 | // A set of defined constants is provided for the user's convenience. Default 239 | // value is 3.375A- 0x08. This is a 4-bit value. 240 | case OCD_TH: 241 | value &= 0x0F; 242 | retVal = xferParam(value, 8); 243 | break; 244 | // Stall current threshold. Defaults to 0x40, or 2.03A. Value is from 31.25mA to 245 | // 4A in 31.25mA steps. This is a 7-bit value. 246 | case STALL_TH: 247 | value &= 0x7F; 248 | retVal = xferParam(value, 8); 249 | break; 250 | // STEP_MODE controls the microstepping settings, as well as the generation of an 251 | // output signal from the dSPIN. Bits 2:0 control the number of microsteps per 252 | // step the part will generate. Bit 7 controls whether the BUSY/SYNC pin outputs 253 | // a BUSY signal or a step synchronization signal. Bits 6:4 control the frequency 254 | // of the output signal relative to the full-step frequency; see datasheet for 255 | // that relationship as it is too complex to reproduce here. 256 | // Most likely, only the microsteps per step value will be needed; there is a set 257 | // of constants provided for ease of use of these values. 258 | case STEP_MODE: 259 | retVal = xferParam(value, 8); 260 | break; 261 | // ALARM_EN controls which alarms will cause the FLAG pin to fall. A set of constants 262 | // is provided to make this easy to interpret. By default, ALL alarms will trigger the 263 | // FLAG pin. 264 | case ALARM_EN: 265 | retVal = xferParam(value, 8); 266 | break; 267 | // CONFIG contains some assorted configuration bits and fields. A fairly comprehensive 268 | // set of reasonably self-explanatory constants is provided, but users should refer 269 | // to the datasheet before modifying the contents of this register to be certain they 270 | // understand the implications of their modifications. Value on boot is 0x2E88; this 271 | // can be a useful way to verify proper start up and operation of the dSPIN chip. 272 | case CONFIG: 273 | retVal = xferParam(value, 16); 274 | break; 275 | // STATUS contains read-only information about the current condition of the chip. A 276 | // comprehensive set of constants for masking and testing this register is provided, but 277 | // users should refer to the datasheet to ensure that they fully understand each one of 278 | // the bits in the register. 279 | case STATUS: // STATUS is a read-only register 280 | retVal = xferParam(0, 16);; 281 | break; 282 | default: 283 | SPIXfer((byte)value); 284 | break; 285 | } 286 | return retVal; 287 | } 288 | 289 | // Generalization of the subsections of the register read/write functionality. 290 | // We want the end user to just write the value without worrying about length, 291 | // so we pass a bit length parameter from the calling function. 292 | long AutoDriver::xferParam(unsigned long value, byte bitLen) 293 | { 294 | byte byteLen = bitLen/8; // How many BYTES do we have? 295 | if (bitLen%8 > 0) byteLen++; // Make sure not to lose any partial byte values. 296 | 297 | byte temp; 298 | 299 | unsigned long retVal = 0; 300 | 301 | for (int i = 0; i < byteLen; i++) 302 | { 303 | retVal = retVal << 8; 304 | temp = SPIXfer((byte)(value>>((byteLen-i-1)*8))); 305 | retVal |= temp; 306 | } 307 | 308 | unsigned long mask = 0xffffffff >> (32-bitLen); 309 | return retVal & mask; 310 | } 311 | 312 | byte AutoDriver::SPIXfer(byte data) 313 | { 314 | byte dataPacket[_numBoards]; 315 | int i; 316 | for (i=0; i < _numBoards; i++) 317 | { 318 | dataPacket[i] = 0; 319 | } 320 | dataPacket[_position] = data; 321 | digitalWrite(_CSPin, LOW); 322 | _SPI->beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE3)); 323 | _SPI->transfer(dataPacket, _numBoards); 324 | _SPI->endTransaction(); 325 | digitalWrite(_CSPin, HIGH); 326 | return dataPacket[_position]; 327 | } 328 | 329 | -------------------------------------------------------------------------------- /src/SparkFundSPINConstants.h: -------------------------------------------------------------------------------- 1 | #ifndef _dspin_constants_h_ 2 | #define _dspin_constants_h_ 3 | 4 | // Constant definitions provided by ST 5 | 6 | // constant definitions for overcurrent thresholds. Write these values to 7 | // register OCD_TH to set the level at which an overcurrent even occurs. 8 | #define OCD_TH_375mA 0x00 9 | #define OCD_TH_750mA 0x01 10 | #define OCD_TH_1125mA 0x02 11 | #define OCD_TH_1500mA 0x03 12 | #define OCD_TH_1875mA 0x04 13 | #define OCD_TH_2250mA 0x05 14 | #define OCD_TH_2625mA 0x06 15 | #define OCD_TH_3000mA 0x07 16 | #define OCD_TH_3375mA 0x08 17 | #define OCD_TH_3750mA 0x09 18 | #define OCD_TH_4125mA 0x0A 19 | #define OCD_TH_4500mA 0x0B 20 | #define OCD_TH_4875mA 0x0C 21 | #define OCD_TH_5250mA 0x0D 22 | #define OCD_TH_5625mA 0x0E 23 | #define OCD_TH_6000mA 0x0F 24 | 25 | // STEP_MODE option values. 26 | // First comes the "microsteps per step" options... 27 | #define STEP_MODE_STEP_SEL 0x07 // Mask for these bits only. 28 | #define STEP_SEL_1 0x00 29 | #define STEP_SEL_1_2 0x01 30 | #define STEP_SEL_1_4 0x02 31 | #define STEP_SEL_1_8 0x03 32 | #define STEP_SEL_1_16 0x04 33 | #define STEP_SEL_1_32 0x05 34 | #define STEP_SEL_1_64 0x06 35 | #define STEP_SEL_1_128 0x07 36 | 37 | // ...next, define the SYNC_EN bit. When set, the BUSYN pin will instead 38 | // output a clock related to the full-step frequency as defined by the 39 | // SYNC_SEL bits below. 40 | #define STEP_MODE_SYNC_EN 0x80 // Mask for this bit 41 | #define SYNC_EN 0x80 42 | 43 | // ...last, define the SYNC_SEL modes. The clock output is defined by 44 | // the full-step frequency and the value in these bits- see the datasheet 45 | // for a matrix describing that relationship (page 46). 46 | #define STEP_MODE_SYNC_SEL 0x70 47 | #define SYNC_SEL_1_2 0x00 48 | #define SYNC_SEL_1 0x10 49 | #define SYNC_SEL_2 0x20 50 | #define SYNC_SEL_4 0x30 51 | #define SYNC_SEL_8 0x40 52 | #define SYNC_SEL_16 0x50 53 | #define SYNC_SEL_32 0x60 54 | #define SYNC_SEL_64 0x70 55 | 56 | // Bit names for the ALARM_EN register. 57 | // Each of these bits defines one potential alarm condition. 58 | // When one of these conditions occurs and the respective bit in ALARM_EN is set, 59 | // the FLAG pin will go low. The register must be queried to determine which event 60 | // caused the alarm. 61 | #define ALARM_EN_OVERCURRENT 0x01 62 | #define ALARM_EN_THERMAL_SHUTDOWN 0x02 63 | #define ALARM_EN_THERMAL_WARNING 0x04 64 | #define ALARM_EN_UNDER_VOLTAGE 0x08 65 | #define ALARM_EN_STALL_DET_A 0x10 66 | #define ALARM_EN_STALL_DET_B 0x20 67 | #define ALARM_EN_SW_TURN_ON 0x40 68 | #define ALARM_EN_WRONG_NPERF_CMD 0x80 69 | 70 | // CONFIG register renames. 71 | 72 | // Oscillator options. 73 | // The dSPIN needs to know what the clock frequency is because it uses that for some 74 | // calculations during operation. 75 | #define CONFIG_OSC_SEL 0x000F // Mask for this bit field. 76 | #define CONFIG_INT_16MHZ 0x0000 // Internal 16MHz, no output 77 | #define CONFIG_INT_16MHZ_OSCOUT_2MHZ 0x0008 // Default; internal 16MHz, 2MHz output 78 | #define CONFIG_INT_16MHZ_OSCOUT_4MHZ 0x0009 // Internal 16MHz, 4MHz output 79 | #define CONFIG_INT_16MHZ_OSCOUT_8MHZ 0x000A // Internal 16MHz, 8MHz output 80 | #define CONFIG_INT_16MHZ_OSCOUT_16MHZ 0x000B // Internal 16MHz, 16MHz output 81 | #define CONFIG_EXT_8MHZ_XTAL_DRIVE 0x0004 // External 8MHz crystal 82 | #define CONFIG_EXT_16MHZ_XTAL_DRIVE 0x0005 // External 16MHz crystal 83 | #define CONFIG_EXT_24MHZ_XTAL_DRIVE 0x0006 // External 24MHz crystal 84 | #define CONFIG_EXT_32MHZ_XTAL_DRIVE 0x0007 // External 32MHz crystal 85 | #define CONFIG_EXT_8MHZ_OSCOUT_INVERT 0x000C // External 8MHz crystal, output inverted 86 | #define CONFIG_EXT_16MHZ_OSCOUT_INVERT 0x000D // External 16MHz crystal, output inverted 87 | #define CONFIG_EXT_24MHZ_OSCOUT_INVERT 0x000E // External 24MHz crystal, output inverted 88 | #define CONFIG_EXT_32MHZ_OSCOUT_INVERT 0x000F // External 32MHz crystal, output inverted 89 | 90 | // Configure the functionality of the external switch input 91 | #define CONFIG_SW_MODE 0x0010 // Mask for this bit. 92 | #define CONFIG_SW_HARD_STOP 0x0000 // Default; hard stop motor on switch. 93 | #define CONFIG_SW_USER 0x0010 // Tie to the GoUntil and ReleaseSW 94 | // commands to provide jog function. 95 | // See page 25 of datasheet. 96 | 97 | // Configure the motor voltage compensation mode (see page 34 of datasheet) 98 | #define CONFIG_EN_VSCOMP 0x0020 // Mask for this bit. 99 | #define CONFIG_VS_COMP_DISABLE 0x0000 // Disable motor voltage compensation. 100 | #define CONFIG_VS_COMP_ENABLE 0x0020 // Enable motor voltage compensation. 101 | 102 | // Configure overcurrent detection event handling 103 | #define CONFIG_OC_SD 0x0080 // Mask for this bit. 104 | #define CONFIG_OC_SD_DISABLE 0x0000 // Bridges do NOT shutdown on OC detect 105 | #define CONFIG_OC_SD_ENABLE 0x0080 // Bridges shutdown on OC detect 106 | 107 | // Configure the slew rate of the power bridge output 108 | #define CONFIG_POW_SR 0x0300 // Mask for this bit field. 109 | #define CONFIG_SR_180V_us 0x0000 // 180V/us 110 | #define CONFIG_SR_290V_us 0x0200 // 290V/us 111 | #define CONFIG_SR_530V_us 0x0300 // 530V/us 112 | 113 | // Integer divisors for PWM sinewave generation 114 | // See page 32 of the datasheet for more information on this. 115 | #define CONFIG_F_PWM_DEC 0x1C00 // mask for this bit field 116 | #define CONFIG_PWM_MUL_0_625 (0x00)<<10 117 | #define CONFIG_PWM_MUL_0_75 (0x01)<<10 118 | #define CONFIG_PWM_MUL_0_875 (0x02)<<10 119 | #define CONFIG_PWM_MUL_1 (0x03)<<10 120 | #define CONFIG_PWM_MUL_1_25 (0x04)<<10 121 | #define CONFIG_PWM_MUL_1_5 (0x05)<<10 122 | #define CONFIG_PWM_MUL_1_75 (0x06)<<10 123 | #define CONFIG_PWM_MUL_2 (0x07)<<10 124 | 125 | // Multiplier for the PWM sinewave frequency 126 | #define CONFIG_F_PWM_INT 0xE000 // mask for this bit field. 127 | #define CONFIG_PWM_DIV_1 (0x00)<<13 128 | #define CONFIG_PWM_DIV_2 (0x01)<<13 129 | #define CONFIG_PWM_DIV_3 (0x02)<<13 130 | #define CONFIG_PWM_DIV_4 (0x03)<<13 131 | #define CONFIG_PWM_DIV_5 (0x04)<<13 132 | #define CONFIG_PWM_DIV_6 (0x05)<<13 133 | #define CONFIG_PWM_DIV_7 (0x06)<<13 134 | 135 | // Status register bit renames- read-only bits conferring information about the 136 | // device to the user. 137 | #define STATUS_HIZ 0x0001 // high when bridges are in HiZ mode 138 | #define STATUS_BUSY 0x0002 // mirrors BUSY pin 139 | #define STATUS_SW_F 0x0004 // low when switch open, high when closed 140 | #define STATUS_SW_EVN 0x0008 // active high, set on switch falling edge, 141 | // cleared by reading STATUS 142 | #define STATUS_DIR 0x0010 // Indicates current motor direction. 143 | // High is FWD, Low is REV. 144 | #define STATUS_NOTPERF_CMD 0x0080 // Last command not performed. 145 | #define STATUS_WRONG_CMD 0x0100 // Last command not valid. 146 | #define STATUS_UVLO 0x0200 // Undervoltage lockout is active 147 | #define STATUS_TH_WRN 0x0400 // Thermal warning 148 | #define STATUS_TH_SD 0x0800 // Thermal shutdown 149 | #define STATUS_OCD 0x1000 // Overcurrent detected 150 | #define STATUS_STEP_LOSS_A 0x2000 // Stall detected on A bridge 151 | #define STATUS_STEP_LOSS_B 0x4000 // Stall detected on B bridge 152 | #define STATUS_SCK_MOD 0x8000 // Step clock mode is active 153 | 154 | // Status register motor status field 155 | #define STATUS_MOT_STATUS 0x0060 // field mask 156 | #define STATUS_MOT_STATUS_STOPPED (0x0000)<<13 // Motor stopped 157 | #define STATUS_MOT_STATUS_ACCELERATION (0x0001)<<13 // Motor accelerating 158 | #define STATUS_MOT_STATUS_DECELERATION (0x0002)<<13 // Motor decelerating 159 | #define STATUS_MOT_STATUS_CONST_SPD (0x0003)<<13 // Motor at constant speed 160 | 161 | // Register address redefines. 162 | // See the Param_Handler() function for more info about these. 163 | #define ABS_POS 0x01 164 | #define EL_POS 0x02 165 | #define MARK 0x03 166 | #define SPEED 0x04 167 | #define ACC 0x05 168 | #define DECEL 0x06 169 | #define MAX_SPEED 0x07 170 | #define MIN_SPEED 0x08 171 | #define FS_SPD 0x15 172 | #define KVAL_HOLD 0x09 173 | #define KVAL_RUN 0x0A 174 | #define KVAL_ACC 0x0B 175 | #define KVAL_DEC 0x0C 176 | #define INT_SPD 0x0D 177 | #define ST_SLP 0x0E 178 | #define FN_SLP_ACC 0x0F 179 | #define FN_SLP_DEC 0x10 180 | #define K_THERM 0x11 181 | #define ADC_OUT 0x12 182 | #define OCD_TH 0x13 183 | #define STALL_TH 0x14 184 | #define STEP_MODE 0x16 185 | #define ALARM_EN 0x17 186 | #define CONFIG 0x18 187 | #define STATUS 0x19 188 | 189 | //dSPIN commands 190 | #define NOP 0x00 191 | #define SET_PARAM 0x00 192 | #define GET_PARAM 0x20 193 | #define RUN 0x50 194 | #define STEP_CLOCK 0x58 195 | #define MOVE 0x40 196 | #define GOTO 0x60 197 | #define GOTO_DIR 0x68 198 | #define GO_UNTIL 0x82 199 | #define RELEASE_SW 0x92 200 | #define GO_HOME 0x70 201 | #define GO_MARK 0x78 202 | #define RESET_POS 0xD8 203 | #define RESET_DEVICE 0xC0 204 | #define SOFT_STOP 0xB0 205 | #define HARD_STOP 0xB8 206 | #define SOFT_HIZ 0xA0 207 | #define HARD_HIZ 0xA8 208 | #define GET_STATUS 0xD0 209 | 210 | #endif 211 | 212 | --------------------------------------------------------------------------------