├── .gitattributes ├── .gitignore ├── Hardware ├── L6470 AutoDriver.brd └── L6470 AutoDriver.sch ├── LICENSE.md ├── Libraries ├── Arduino │ ├── .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 └── README.md ├── Production └── L6470AutoDriver-Panel_v13.brd └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ################# 2 | ## SparkFun Useful stuff 3 | ################# 4 | 5 | ## AVR Development 6 | *.eep 7 | *.elf 8 | *.lst 9 | *.lss 10 | *.sym 11 | *.d 12 | *.o 13 | *.srec 14 | *.map 15 | 16 | ## Notepad++ backup files 17 | *.bak 18 | 19 | ## BOM files 20 | *bom* 21 | 22 | ################# 23 | ## Eclipse 24 | ################# 25 | 26 | *.pydevproject 27 | .project 28 | .metadata 29 | bin/ 30 | tmp/ 31 | *.tmp 32 | *.bak 33 | *.swp 34 | *~.nib 35 | local.properties 36 | .classpath 37 | .settings/ 38 | .loadpath 39 | 40 | # External tool builders 41 | .externalToolBuilders/ 42 | 43 | # Locally stored "Eclipse launch configurations" 44 | *.launch 45 | 46 | # CDT-specific 47 | .cproject 48 | 49 | # PDT-specific 50 | .buildpath 51 | 52 | 53 | ############# 54 | ## Eagle 55 | ############# 56 | 57 | # Ignore the board and schematic backup files and lock files 58 | *.b#? 59 | *.s#? 60 | *.l#? 61 | *.lck 62 | 63 | 64 | ################# 65 | ## Visual Studio 66 | ################# 67 | 68 | ## Ignore Visual Studio temporary files, build results, and 69 | ## files generated by popular Visual Studio add-ons. 70 | 71 | # User-specific files 72 | *.suo 73 | *.user 74 | *.sln.docstates 75 | 76 | # Build results 77 | [Dd]ebug/ 78 | [Rr]elease/ 79 | *_i.c 80 | *_p.c 81 | *.ilk 82 | *.meta 83 | *.obj 84 | *.pch 85 | *.pdb 86 | *.pgc 87 | *.pgd 88 | *.rsp 89 | *.sbr 90 | *.tlb 91 | *.tli 92 | *.tlh 93 | *.tmp 94 | *.vspscc 95 | .builds 96 | *.dotCover 97 | 98 | ## TODO: If you have NuGet Package Restore enabled, uncomment this 99 | #packages/ 100 | 101 | # Visual C++ cache files 102 | ipch/ 103 | *.aps 104 | *.ncb 105 | *.opensdf 106 | *.sdf 107 | 108 | # Visual Studio profiler 109 | *.psess 110 | *.vsp 111 | 112 | # ReSharper is a .NET coding add-in 113 | _ReSharper* 114 | 115 | # Installshield output folder 116 | [Ee]xpress 117 | 118 | # DocProject is a documentation generator add-in 119 | DocProject/buildhelp/ 120 | DocProject/Help/*.HxT 121 | DocProject/Help/*.HxC 122 | DocProject/Help/*.hhc 123 | DocProject/Help/*.hhk 124 | DocProject/Help/*.hhp 125 | DocProject/Help/Html2 126 | DocProject/Help/html 127 | 128 | # Click-Once directory 129 | publish 130 | 131 | # Others 132 | [Bb]in 133 | [Oo]bj 134 | sql 135 | TestResults 136 | *.Cache 137 | ClientBin 138 | stylecop.* 139 | ~$* 140 | *.dbmdl 141 | Generated_Code #added for RIA/Silverlight projects 142 | 143 | # Backup & report files from converting an old project file to a newer 144 | # Visual Studio version. Backup files are not needed, because we have git ;-) 145 | _UpgradeReport_Files/ 146 | Backup*/ 147 | UpgradeLog*.XML 148 | 149 | 150 | ############ 151 | ## Windows 152 | ############ 153 | 154 | # Windows image file caches 155 | Thumbs.db 156 | 157 | # Folder config file 158 | Desktop.ini 159 | 160 | 161 | ############# 162 | ## Mac OS 163 | ############# 164 | 165 | .DS_Store 166 | 167 | 168 | ############# 169 | ## Linux 170 | ############# 171 | 172 | # backup files (*.bak on Win) 173 | *~ 174 | 175 | 176 | ############# 177 | ## Python 178 | ############# 179 | 180 | *.py[co] 181 | 182 | # Packages 183 | *.egg 184 | *.egg-info 185 | dist 186 | build 187 | eggs 188 | parts 189 | bin 190 | var 191 | sdist 192 | develop-eggs 193 | .installed.cfg 194 | 195 | # Installer logs 196 | pip-log.txt 197 | 198 | # Unit test / coverage reports 199 | .coverage 200 | .tox 201 | 202 | #Translations 203 | *.mo 204 | 205 | #Mr Developer 206 | .mr.developer.cfg 207 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | SparkFun License Information 2 | ============================ 3 | 4 | SparkFun uses two different licenses for our files — one for hardware and one for code. 5 | 6 | Hardware 7 | --------- 8 | 9 | **SparkFun hardware is released under [Creative Commons Share-alike 4.0 International](http://creativecommons.org/licenses/by-sa/4.0/).** 10 | 11 | Note: This is a human-readable summary of (and not a substitute for) the [license](http://creativecommons.org/licenses/by-sa/4.0/legalcode). 12 | 13 | You are free to: 14 | 15 | Share — copy and redistribute the material in any medium or format 16 | Adapt — remix, transform, and build upon the material 17 | for any purpose, even commercially. 18 | The licensor cannot revoke these freedoms as long as you follow the license terms. 19 | Under the following terms: 20 | 21 | Attribution — You must give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use. 22 | ShareAlike — If you remix, transform, or build upon the material, you must distribute your contributions under the same license as the original. 23 | No additional restrictions — You may not apply legal terms or technological measures that legally restrict others from doing anything the license permits. 24 | Notices: 25 | 26 | You do not have to comply with the license for elements of the material in the public domain or where your use is permitted by an applicable exception or limitation. 27 | No warranties are given. The license may not give you all of the permissions necessary for your intended use. For example, other rights such as publicity, privacy, or moral rights may limit how you use the material. 28 | 29 | 30 | Code 31 | -------- 32 | 33 | **SparkFun code, firmware, and software is released under the MIT License(http://opensource.org/licenses/MIT).** 34 | 35 | The MIT License (MIT) 36 | 37 | Copyright (c) 2016 SparkFun Electronics 38 | 39 | Permission is hereby granted, free of charge, to any person obtaining a copy 40 | of this software and associated documentation files (the "Software"), to deal 41 | in the Software without restriction, including without limitation the rights 42 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 43 | copies of the Software, and to permit persons to whom the Software is 44 | furnished to do so, subject to the following conditions: 45 | 46 | The above copyright notice and this permission notice shall be included in all 47 | copies or substantial portions of the Software. 48 | 49 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 50 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 51 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 52 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 53 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 54 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 55 | SOFTWARE. 56 | -------------------------------------------------------------------------------- /Libraries/Arduino/.gitignore: -------------------------------------------------------------------------------- 1 | # EAGLE created backup files # 2 | *.s#? 3 | *.b#? 4 | *.ods 5 | *.csv 6 | *.epf -------------------------------------------------------------------------------- /Libraries/Arduino/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 | -------------------------------------------------------------------------------- /Libraries/Arduino/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 | -------------------------------------------------------------------------------- /Libraries/Arduino/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 | -------------------------------------------------------------------------------- /Libraries/Arduino/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 | -------------------------------------------------------------------------------- /Libraries/Arduino/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 | -------------------------------------------------------------------------------- /Libraries/Arduino/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 | -------------------------------------------------------------------------------- /Libraries/Arduino/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 | -------------------------------------------------------------------------------- /Libraries/Arduino/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 | -------------------------------------------------------------------------------- /Libraries/Arduino/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 | -------------------------------------------------------------------------------- /Libraries/Arduino/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 | -------------------------------------------------------------------------------- /Libraries/Arduino/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 | -------------------------------------------------------------------------------- /Libraries/Arduino/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 | -------------------------------------------------------------------------------- /Libraries/Arduino/library.properties: -------------------------------------------------------------------------------- 1 | name=SparkFun L6470 AutoDriver 2 | version=1.3.0 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 | -------------------------------------------------------------------------------- /Libraries/Arduino/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 | -------------------------------------------------------------------------------- /Libraries/Arduino/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 | -------------------------------------------------------------------------------- /Libraries/Arduino/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 | -------------------------------------------------------------------------------- /Libraries/Arduino/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 | -------------------------------------------------------------------------------- /Libraries/Arduino/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 | -------------------------------------------------------------------------------- /Libraries/Arduino/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 | -------------------------------------------------------------------------------- /Libraries/Arduino/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)<<5 // Motor stopped 157 | #define STATUS_MOT_STATUS_ACCELERATION (0x0001)<<5 // Motor accelerating 158 | #define STATUS_MOT_STATUS_DECELERATION (0x0002)<<5 // Motor decelerating 159 | #define STATUS_MOT_STATUS_CONST_SPD (0x0003)<<5 // 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 | -------------------------------------------------------------------------------- /Libraries/README.md: -------------------------------------------------------------------------------- 1 | SparkFun AutoDriver Libraries 2 | ========== 3 | 4 | Libraries for using the AutoDriver in various environments 5 | 6 | Directory Contents 7 | ------------------- 8 | * **/Arduino** - [Arduino IDE](http://www.arduino.cc/en/Main/Software) library and example files 9 | 10 | License Information 11 | ------------------- 12 | This product is open source! 13 | 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! 14 | 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. 15 | 16 | Distributed as-is; no warranty is given. 17 | 18 | - Your friends at SparkFun. 19 | 20 | BUILD INSTRUCTIONS: 21 | --------------------- 22 | While we make every effort to keep our library repositories up-to-date with the product repositories, it may be a good idea to update the libraries to the latest version. 23 | 24 | To get the most up-to-date version of the library, you must use the following git subtree commands. 25 | 26 | git subtree add -P Libraries/Arduino --squash https://github.com/sparkfun/SparkFun_AutoDriver_Arduino_Library master 27 | 28 | git subtree pull -P Libraries/Arduino --squash https://github.com/sparkfun/SparkFun_AutoDriver_Arduino_Library master 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | SparkFun AutoDriver - Stepper Motor Driver 2 | ========================================== 3 | 4 | ![AutoDriver](https://cdn.sparkfun.com//assets/parts/1/1/2/8/8/13752-01a.jpg) 5 | 6 | [*AutoDriver (BOB-13752)*](https://www.sparkfun.com/products/13752) 7 | 8 | The AutoDriver is a bipolar stepper driver based on the ST Micro L6470 chip. It allows a processor to control a single 3A bipolar stepper motor across an 8-45V supply range. 9 | 10 | Repository Contents 11 | ------------------- 12 | * **/Hardware** - All Eagle design files (.brd, .sch) 13 | * **/Libraries** - All Arduino libraries and board examples 14 | * **/Production** - Test bed files and production panel files 15 | 16 | 17 | Documentation 18 | -------------- 19 | * **[Library](https://github.com/sparkfun/SparkFun_AutoDriver_Arduino_Library)** - Arduino library for the AutoDriver. 20 | * **[Hookup Guide](https://learn.sparkfun.com/tutorials/getting-started-with-the-autodriver---v13)** - Basic hookup guide for the Auto Driver. 21 | * **[SparkFun Fritzing repo](https://github.com/sparkfun/Fritzing_Parts)** - Fritzing diagrams for SparkFun products. 22 | * **[SparkFun 3D Model repo](https://github.com/sparkfun/3D_Models)** - 3D models of SparkFun products. 23 | * **[SparkFun Graphical Datasheets](https://github.com/sparkfun/Graphical_Datasheets)** -Graphical Datasheets for various SparkFun products. 24 | 25 | License Information 26 | ------------------- 27 | 28 | This product is _**open source**_! 29 | 30 | Please review the LICENSE.md file for license information. 31 | 32 | If you have any questions or concerns on licensing, please contact techsupport@sparkfun.com. 33 | 34 | Distributed as-is; no warranty is given. 35 | 36 | - Your friends at SparkFun. 37 | --------------------------------------------------------------------------------