Browse Source

Added Y_DUAL_STEPPER_DRIVERS

Enables two stepper drivers to be used for the Y axis (useful for
Shapeoko style machines)
Each Y driver can be stepped either the same way or in opposite
directions, accounting for different hardware setups (leadscrew vs. belt
driven)
Richard Miles 10 years ago
parent
commit
7ee275b620
3 changed files with 325 additions and 144 deletions
  1. 67
    6
      Marlin/Configuration_adv.h
  2. 20
    10
      Marlin/Marlin.h
  3. 238
    128
      Marlin/stepper.cpp

+ 67
- 6
Marlin/Configuration_adv.h View File

@@ -18,12 +18,6 @@
18 18
 //#define WATCH_TEMP_PERIOD 40000 //40 seconds
19 19
 //#define WATCH_TEMP_INCREASE 10  //Heat up at least 10 degree in 20 seconds
20 20
 
21
-// Wait for Cooldown
22
-// This defines if the M109 call should not block if it is cooling down.
23
-// example: From a current temp of 220, you set M109 S200. 
24
-// if CooldownNoWait is defined M109 will not wait for the cooldown to finish
25
-#define CooldownNoWait true
26
-
27 21
 #ifdef PIDTEMP
28 22
   // this adds an experimental additional term to the heatingpower, proportional to the extrusion speed.
29 23
   // if Kc is choosen well, the additional required power due to increased melting should be compensated.
@@ -152,6 +146,68 @@
152 146
   #define EXTRUDERS 1
153 147
 #endif
154 148
 
149
+// Same again but for Y Axis.
150
+#define Y_DUAL_STEPPER_DRIVERS
151
+
152
+// Define if the two Y drives need to rotate in opposite directions
153
+#define INVERT_Y2_VS_Y_DIR true
154
+
155
+#ifdef Y_DUAL_STEPPER_DRIVERS
156
+  #undef EXTRUDERS
157
+  #define EXTRUDERS 1
158
+#endif
159
+
160
+#ifdef Z_DUAL_STEPPER_DRIVERS && Y_DUAL_STEPPER_DRIVERS
161
+  #error "You cannot have dual drivers for both Y and Z"
162
+#endif 
163
+
164
+// Enable this for dual x-carriage printers. 
165
+// A dual x-carriage design has the advantage that the inactive extruder can be parked which
166
+// prevents hot-end ooze contaminating the print. It also reduces the weight of each x-carriage
167
+// allowing faster printing speeds.
168
+//#define DUAL_X_CARRIAGE
169
+#ifdef DUAL_X_CARRIAGE
170
+// Configuration for second X-carriage
171
+// Note: the first x-carriage is defined as the x-carriage which homes to the minimum endstop;
172
+// the second x-carriage always homes to the maximum endstop.
173
+#define X2_MIN_POS 80     // set minimum to ensure second x-carriage doesn't hit the parked first X-carriage
174
+#define X2_MAX_POS 353    // set maximum to the distance between toolheads when both heads are homed 
175
+#define X2_HOME_DIR 1     // the second X-carriage always homes to the maximum endstop position
176
+#define X2_HOME_POS X2_MAX_POS // default home position is the maximum carriage position 
177
+    // However: In this mode the EXTRUDER_OFFSET_X value for the second extruder provides a software 
178
+    // override for X2_HOME_POS. This also allow recalibration of the distance between the two endstops
179
+    // without modifying the firmware (through the "M218 T1 X???" command).
180
+    // Remember: you should set the second extruder x-offset to 0 in your slicer.
181
+
182
+// Pins for second x-carriage stepper driver (defined here to avoid further complicating pins.h)
183
+#define X2_ENABLE_PIN 29
184
+#define X2_STEP_PIN 25
185
+#define X2_DIR_PIN 23
186
+
187
+// There are a few selectable movement modes for dual x-carriages using M605 S<mode>
188
+//    Mode 0: Full control. The slicer has full control over both x-carriages and can achieve optimal travel results
189
+//                           as long as it supports dual x-carriages. (M605 S0)
190
+//    Mode 1: Auto-park mode. The firmware will automatically park and unpark the x-carriages on tool changes so
191
+//                           that additional slicer support is not required. (M605 S1)
192
+//    Mode 2: Duplication mode. The firmware will transparently make the second x-carriage and extruder copy all  
193
+//                           actions of the first x-carriage. This allows the printer to print 2 arbitrary items at
194
+//                           once. (2nd extruder x offset and temp offset are set using: M605 S2 [Xnnn] [Rmmm])
195
+
196
+// This is the default power-up mode which can be later using M605. 
197
+#define DEFAULT_DUAL_X_CARRIAGE_MODE 0 
198
+
199
+// As the x-carriages are independent we can now account for any relative Z offset
200
+#define EXTRUDER1_Z_OFFSET 0.0           // z offset relative to extruder 0
201
+
202
+// Default settings in "Auto-park Mode" 
203
+#define TOOLCHANGE_PARK_ZLIFT   0.2      // the distance to raise Z axis when parking an extruder
204
+#define TOOLCHANGE_UNPARK_ZLIFT 1        // the distance to raise Z axis when unparking an extruder
205
+
206
+// Default x offset in duplication mode (typically set to half print bed width)
207
+#define DEFAULT_DUPLICATION_X_OFFSET 100
208
+
209
+#endif //DUAL_X_CARRIAGE
210
+    
155 211
 //homing hits the endstop, then retracts by this distance, before it tries to slowly bump again:
156 212
 #define X_HOME_RETRACT_MM 5 
157 213
 #define Y_HOME_RETRACT_MM 5 
@@ -174,6 +230,11 @@
174 230
 #define DEFAULT_MINIMUMFEEDRATE       0.0     // minimum feedrate
175 231
 #define DEFAULT_MINTRAVELFEEDRATE     0.0
176 232
 
233
+// Feedrates for manual moves along X, Y, Z, E from panel
234
+#ifdef ULTIPANEL
235
+#define MANUAL_FEEDRATE {50*60, 50*60, 4*60, 60}  // set the speeds for manual moves (mm/min)
236
+#endif
237
+
177 238
 // minimum time in microseconds that a movement needs to take if the buffer is emptied.
178 239
 #define DEFAULT_MINSEGMENTTIME        20000
179 240
 

+ 20
- 10
Marlin/Marlin.h View File

@@ -51,22 +51,22 @@
51 51
   #define MYSERIAL MSerial
52 52
 #endif
53 53
 
54
-#define SERIAL_PROTOCOL(x) MYSERIAL.print(x);
55
-#define SERIAL_PROTOCOL_F(x,y) MYSERIAL.print(x,y);
56
-#define SERIAL_PROTOCOLPGM(x) serialprintPGM(PSTR(x));
57
-#define SERIAL_PROTOCOLLN(x) {MYSERIAL.print(x);MYSERIAL.write('\n');}
58
-#define SERIAL_PROTOCOLLNPGM(x) {serialprintPGM(PSTR(x));MYSERIAL.write('\n');}
54
+#define SERIAL_PROTOCOL(x) (MYSERIAL.print(x))
55
+#define SERIAL_PROTOCOL_F(x,y) (MYSERIAL.print(x,y))
56
+#define SERIAL_PROTOCOLPGM(x) (serialprintPGM(PSTR(x)))
57
+#define SERIAL_PROTOCOLLN(x) (MYSERIAL.print(x),MYSERIAL.write('\n'))
58
+#define SERIAL_PROTOCOLLNPGM(x) (serialprintPGM(PSTR(x)),MYSERIAL.write('\n'))
59 59
 
60 60
 
61 61
 const char errormagic[] PROGMEM ="Error:";
62 62
 const char echomagic[] PROGMEM ="echo:";
63
-#define SERIAL_ERROR_START serialprintPGM(errormagic);
63
+#define SERIAL_ERROR_START (serialprintPGM(errormagic))
64 64
 #define SERIAL_ERROR(x) SERIAL_PROTOCOL(x)
65 65
 #define SERIAL_ERRORPGM(x) SERIAL_PROTOCOLPGM(x)
66 66
 #define SERIAL_ERRORLN(x) SERIAL_PROTOCOLLN(x)
67 67
 #define SERIAL_ERRORLNPGM(x) SERIAL_PROTOCOLLNPGM(x)
68 68
 
69
-#define SERIAL_ECHO_START serialprintPGM(echomagic);
69
+#define SERIAL_ECHO_START (serialprintPGM(echomagic))
70 70
 #define SERIAL_ECHO(x) SERIAL_PROTOCOL(x)
71 71
 #define SERIAL_ECHOPGM(x) SERIAL_PROTOCOLPGM(x)
72 72
 #define SERIAL_ECHOLN(x) SERIAL_PROTOCOLLN(x)
@@ -96,7 +96,11 @@ void process_commands();
96 96
 
97 97
 void manage_inactivity();
98 98
 
99
-#if defined(X_ENABLE_PIN) && X_ENABLE_PIN > -1
99
+#if defined(DUAL_X_CARRIAGE) && defined(X_ENABLE_PIN) && X_ENABLE_PIN > -1 \
100
+    && defined(X2_ENABLE_PIN) && X2_ENABLE_PIN > -1
101
+  #define  enable_x() do { WRITE(X_ENABLE_PIN, X_ENABLE_ON); WRITE(X2_ENABLE_PIN, X_ENABLE_ON); } while (0)
102
+  #define disable_x() do { WRITE(X_ENABLE_PIN,!X_ENABLE_ON); WRITE(X2_ENABLE_PIN,!X_ENABLE_ON); } while (0)
103
+#elif defined(X_ENABLE_PIN) && X_ENABLE_PIN > -1
100 104
   #define  enable_x() WRITE(X_ENABLE_PIN, X_ENABLE_ON)
101 105
   #define disable_x() WRITE(X_ENABLE_PIN,!X_ENABLE_ON)
102 106
 #else
@@ -105,8 +109,13 @@ void manage_inactivity();
105 109
 #endif
106 110
 
107 111
 #if defined(Y_ENABLE_PIN) && Y_ENABLE_PIN > -1
108
-  #define  enable_y() WRITE(Y_ENABLE_PIN, Y_ENABLE_ON)
109
-  #define disable_y() WRITE(Y_ENABLE_PIN,!Y_ENABLE_ON)
112
+  #ifdef Y_DUAL_STEPPER_DRIVERS
113
+    #define  enable_y() { WRITE(Y_ENABLE_PIN, Y_ENABLE_ON); WRITE(Y2_ENABLE_PIN,  Y_ENABLE_ON); }
114
+    #define disable_y() { WRITE(Y_ENABLE_PIN,!Y_ENABLE_ON); WRITE(Y2_ENABLE_PIN, !Y_ENABLE_ON); }
115
+  #else
116
+    #define  enable_y() WRITE(Y_ENABLE_PIN, Y_ENABLE_ON)
117
+    #define disable_y() WRITE(Y_ENABLE_PIN,!Y_ENABLE_ON)
118
+  #endif
110 119
 #else
111 120
   #define enable_y() ;
112 121
   #define disable_y() ;
@@ -159,6 +168,7 @@ void ClearToSend();
159 168
 void get_coordinates();
160 169
 #ifdef DELTA
161 170
 void calculate_delta(float cartesian[3]);
171
+extern float delta[3];
162 172
 #endif
163 173
 void prepare_move();
164 174
 void kill();

+ 238
- 128
Marlin/stepper.cpp View File

@@ -48,8 +48,8 @@ block_t *current_block;  // A pointer to the block currently being traced
48 48
 // Variables used by The Stepper Driver Interrupt
49 49
 static unsigned char out_bits;        // The next stepping-bits to be output
50 50
 static long counter_x,       // Counter variables for the bresenham line tracer
51
-            counter_y, 
52
-            counter_z,       
51
+            counter_y,
52
+            counter_z,
53 53
             counter_e;
54 54
 volatile static unsigned long step_events_completed; // The number of step events executed in the current block
55 55
 #ifdef ADVANCE
@@ -224,27 +224,27 @@ void enable_endstops(bool check)
224 224
 //   |               BLOCK 1            |      BLOCK 2          |    d
225 225
 //
226 226
 //                           time ----->
227
-// 
228
-//  The trapezoid is the shape the speed curve over time. It starts at block->initial_rate, accelerates 
229
-//  first block->accelerate_until step_events_completed, then keeps going at constant speed until 
227
+//
228
+//  The trapezoid is the shape the speed curve over time. It starts at block->initial_rate, accelerates
229
+//  first block->accelerate_until step_events_completed, then keeps going at constant speed until
230 230
 //  step_events_completed reaches block->decelerate_after after which it decelerates until the trapezoid generator is reset.
231 231
 //  The slope of acceleration is calculated with the leib ramp alghorithm.
232 232
 
233 233
 void st_wake_up() {
234 234
   //  TCNT1 = 0;
235
-  ENABLE_STEPPER_DRIVER_INTERRUPT();  
235
+  ENABLE_STEPPER_DRIVER_INTERRUPT();
236 236
 }
237 237
 
238 238
 void step_wait(){
239 239
     for(int8_t i=0; i < 6; i++){
240 240
     }
241 241
 }
242
-  
242
+
243 243
 
244 244
 FORCE_INLINE unsigned short calc_timer(unsigned short step_rate) {
245 245
   unsigned short timer;
246 246
   if(step_rate > MAX_STEP_FREQUENCY) step_rate = MAX_STEP_FREQUENCY;
247
-  
247
+
248 248
   if(step_rate > 20000) { // If steprate > 20kHz >> step 4 times
249 249
     step_rate = (step_rate >> 2)&0x3fff;
250 250
     step_loops = 4;
@@ -255,11 +255,11 @@ FORCE_INLINE unsigned short calc_timer(unsigned short step_rate) {
255 255
   }
256 256
   else {
257 257
     step_loops = 1;
258
-  } 
259
-  
258
+  }
259
+
260 260
   if(step_rate < (F_CPU/500000)) step_rate = (F_CPU/500000);
261 261
   step_rate -= (F_CPU/500000); // Correct for minimal speed
262
-  if(step_rate >= (8*256)){ // higher step rate 
262
+  if(step_rate >= (8*256)){ // higher step rate
263 263
     unsigned short table_address = (unsigned short)&speed_lookuptable_fast[(unsigned char)(step_rate>>8)][0];
264 264
     unsigned char tmp_step_rate = (step_rate & 0x00ff);
265 265
     unsigned short gain = (unsigned short)pgm_read_word_near(table_address+2);
@@ -276,7 +276,7 @@ FORCE_INLINE unsigned short calc_timer(unsigned short step_rate) {
276 276
   return timer;
277 277
 }
278 278
 
279
-// Initializes the trapezoid generator from the current block. Called whenever a new 
279
+// Initializes the trapezoid generator from the current block. Called whenever a new
280 280
 // block begins.
281 281
 FORCE_INLINE void trapezoid_generator_reset() {
282 282
   #ifdef ADVANCE
@@ -284,7 +284,7 @@ FORCE_INLINE void trapezoid_generator_reset() {
284 284
     final_advance = current_block->final_advance;
285 285
     // Do E steps + advance steps
286 286
     e_steps[current_block->active_extruder] += ((advance >>8) - old_advance);
287
-    old_advance = advance >>8;  
287
+    old_advance = advance >>8;
288 288
   #endif
289 289
   deceleration_time = 0;
290 290
   // step_rate to timer interval
@@ -294,7 +294,7 @@ FORCE_INLINE void trapezoid_generator_reset() {
294 294
   acc_step_rate = current_block->initial_rate;
295 295
   acceleration_time = calc_timer(acc_step_rate);
296 296
   OCR1A = acceleration_time;
297
-  
297
+
298 298
 //    SERIAL_ECHO_START;
299 299
 //    SERIAL_ECHOPGM("advance :");
300 300
 //    SERIAL_ECHO(current_block->advance/256.0);
@@ -304,13 +304,13 @@ FORCE_INLINE void trapezoid_generator_reset() {
304 304
 //  SERIAL_ECHO(current_block->initial_advance/256.0);
305 305
 //    SERIAL_ECHOPGM("final advance :");
306 306
 //    SERIAL_ECHOLN(current_block->final_advance/256.0);
307
-    
307
+
308 308
 }
309 309
 
310
-// "The Stepper Driver Interrupt" - This timer interrupt is the workhorse.  
311
-// It pops blocks from the block_buffer and executes them by pulsing the stepper pins appropriately. 
310
+// "The Stepper Driver Interrupt" - This timer interrupt is the workhorse.
311
+// It pops blocks from the block_buffer and executes them by pulsing the stepper pins appropriately.
312 312
 ISR(TIMER1_COMPA_vect)
313
-{    
313
+{
314 314
   // If there is no current block, attempt to pop one from the buffer
315 315
   if (current_block == NULL) {
316 316
     // Anything in the buffer?
@@ -322,24 +322,24 @@ ISR(TIMER1_COMPA_vect)
322 322
       counter_y = counter_x;
323 323
       counter_z = counter_x;
324 324
       counter_e = counter_x;
325
-      step_events_completed = 0; 
326
-      
327
-      #ifdef Z_LATE_ENABLE 
325
+      step_events_completed = 0;
326
+
327
+      #ifdef Z_LATE_ENABLE
328 328
         if(current_block->steps_z > 0) {
329 329
           enable_z();
330 330
           OCR1A = 2000; //1ms wait
331 331
           return;
332 332
         }
333 333
       #endif
334
-      
334
+
335 335
 //      #ifdef ADVANCE
336 336
 //      e_steps[current_block->active_extruder] = 0;
337 337
 //      #endif
338
-    } 
338
+    }
339 339
     else {
340 340
         OCR1A=2000; // 1kHz.
341
-    }    
342
-  } 
341
+    }
342
+  }
343 343
 
344 344
   if (current_block != NULL) {
345 345
     // Set directions TO DO This should be done once during init of trapezoid. Endstops -> interrupt
@@ -348,22 +348,58 @@ ISR(TIMER1_COMPA_vect)
348 348
 
349 349
     // Set the direction bits (X_AXIS=A_AXIS and Y_AXIS=B_AXIS for COREXY)
350 350
     if((out_bits & (1<<X_AXIS))!=0){
351
-      WRITE(X_DIR_PIN, INVERT_X_DIR);
351
+      #ifdef DUAL_X_CARRIAGE
352
+        if (extruder_duplication_enabled){
353
+          WRITE(X_DIR_PIN, INVERT_X_DIR);
354
+          WRITE(X2_DIR_PIN, INVERT_X_DIR);
355
+        }
356
+        else{
357
+          if (current_block->active_extruder != 0)
358
+            WRITE(X2_DIR_PIN, INVERT_X_DIR);
359
+          else
360
+            WRITE(X_DIR_PIN, INVERT_X_DIR);
361
+        }
362
+      #else
363
+        WRITE(X_DIR_PIN, INVERT_X_DIR);
364
+      #endif        
352 365
       count_direction[X_AXIS]=-1;
353 366
     }
354 367
     else{
355
-      WRITE(X_DIR_PIN, !INVERT_X_DIR);
368
+      #ifdef DUAL_X_CARRIAGE
369
+        if (extruder_duplication_enabled){
370
+          WRITE(X_DIR_PIN, !INVERT_X_DIR);
371
+          WRITE(X2_DIR_PIN, !INVERT_X_DIR);
372
+        }
373
+        else{
374
+          if (current_block->active_extruder != 0)
375
+            WRITE(X2_DIR_PIN, !INVERT_X_DIR);
376
+          else
377
+            WRITE(X_DIR_PIN, !INVERT_X_DIR);
378
+        }
379
+      #else
380
+        WRITE(X_DIR_PIN, !INVERT_X_DIR);
381
+      #endif        
356 382
       count_direction[X_AXIS]=1;
357 383
     }
358 384
     if((out_bits & (1<<Y_AXIS))!=0){
359 385
       WRITE(Y_DIR_PIN, INVERT_Y_DIR);
386
+	  
387
+	  #ifdef Y_DUAL_STEPPER_DRIVERS
388
+	    WRITE(Y2_DIR_PIN, !(INVERT_Y_DIR == INVERT_Y2_VS_Y_DIR));
389
+	  #endif
390
+	  
360 391
       count_direction[Y_AXIS]=-1;
361 392
     }
362 393
     else{
363 394
       WRITE(Y_DIR_PIN, !INVERT_Y_DIR);
395
+	  
396
+	  #ifdef Y_DUAL_STEPPER_DRIVERS
397
+	    WRITE(Y2_DIR_PIN, (INVERT_Y_DIR == INVERT_Y2_VS_Y_DIR));
398
+	  #endif
399
+	  
364 400
       count_direction[Y_AXIS]=1;
365 401
     }
366
-    
402
+
367 403
     // Set direction en check limit switches
368 404
     #ifndef COREXY
369 405
     if ((out_bits & (1<<X_AXIS)) != 0) {   // stepping along -X axis
@@ -372,29 +408,43 @@ ISR(TIMER1_COMPA_vect)
372 408
     #endif
373 409
       CHECK_ENDSTOPS
374 410
       {
375
-        #if defined(X_MIN_PIN) && X_MIN_PIN > -1
376
-          bool x_min_endstop=(READ(X_MIN_PIN) != X_ENDSTOPS_INVERTING);
377
-          if(x_min_endstop && old_x_min_endstop && (current_block->steps_x > 0)) {
378
-            endstops_trigsteps[X_AXIS] = count_position[X_AXIS];
379
-            endstop_x_hit=true;
380
-            step_events_completed = current_block->step_event_count;
381
-          }
382
-          old_x_min_endstop = x_min_endstop;
383
-        #endif
411
+        #ifdef DUAL_X_CARRIAGE
412
+        // with 2 x-carriages, endstops are only checked in the homing direction for the active extruder
413
+        if ((current_block->active_extruder == 0 && X_HOME_DIR == -1) 
414
+            || (current_block->active_extruder != 0 && X2_HOME_DIR == -1))
415
+        #endif          
416
+        {
417
+          #if defined(X_MIN_PIN) && X_MIN_PIN > -1
418
+            bool x_min_endstop=(READ(X_MIN_PIN) != X_MIN_ENDSTOP_INVERTING);
419
+            if(x_min_endstop && old_x_min_endstop && (current_block->steps_x > 0)) {
420
+              endstops_trigsteps[X_AXIS] = count_position[X_AXIS];
421
+              endstop_x_hit=true;
422
+              step_events_completed = current_block->step_event_count;
423
+            }
424
+            old_x_min_endstop = x_min_endstop;
425
+          #endif
426
+        }
384 427
       }
385 428
     }
386 429
     else { // +direction
387
-      CHECK_ENDSTOPS 
430
+      CHECK_ENDSTOPS
388 431
       {
389
-        #if defined(X_MAX_PIN) && X_MAX_PIN > -1
390
-          bool x_max_endstop=(READ(X_MAX_PIN) != X_ENDSTOPS_INVERTING);
391
-          if(x_max_endstop && old_x_max_endstop && (current_block->steps_x > 0)){
392
-            endstops_trigsteps[X_AXIS] = count_position[X_AXIS];
393
-            endstop_x_hit=true;
394
-            step_events_completed = current_block->step_event_count;
395
-          }
396
-          old_x_max_endstop = x_max_endstop;
397
-        #endif
432
+        #ifdef DUAL_X_CARRIAGE
433
+        // with 2 x-carriages, endstops are only checked in the homing direction for the active extruder
434
+        if ((current_block->active_extruder == 0 && X_HOME_DIR == 1) 
435
+            || (current_block->active_extruder != 0 && X2_HOME_DIR == 1))
436
+        #endif          
437
+        {
438
+          #if defined(X_MAX_PIN) && X_MAX_PIN > -1
439
+            bool x_max_endstop=(READ(X_MAX_PIN) != X_MAX_ENDSTOP_INVERTING);
440
+            if(x_max_endstop && old_x_max_endstop && (current_block->steps_x > 0)){
441
+              endstops_trigsteps[X_AXIS] = count_position[X_AXIS];
442
+              endstop_x_hit=true;
443
+              step_events_completed = current_block->step_event_count;
444
+            }
445
+            old_x_max_endstop = x_max_endstop;
446
+          #endif
447
+        }
398 448
       }
399 449
     }
400 450
 
@@ -406,7 +456,7 @@ ISR(TIMER1_COMPA_vect)
406 456
       CHECK_ENDSTOPS
407 457
       {
408 458
         #if defined(Y_MIN_PIN) && Y_MIN_PIN > -1
409
-          bool y_min_endstop=(READ(Y_MIN_PIN) != Y_ENDSTOPS_INVERTING);
459
+          bool y_min_endstop=(READ(Y_MIN_PIN) != Y_MIN_ENDSTOP_INVERTING);
410 460
           if(y_min_endstop && old_y_min_endstop && (current_block->steps_y > 0)) {
411 461
             endstops_trigsteps[Y_AXIS] = count_position[Y_AXIS];
412 462
             endstop_y_hit=true;
@@ -420,7 +470,7 @@ ISR(TIMER1_COMPA_vect)
420 470
       CHECK_ENDSTOPS
421 471
       {
422 472
         #if defined(Y_MAX_PIN) && Y_MAX_PIN > -1
423
-          bool y_max_endstop=(READ(Y_MAX_PIN) != Y_ENDSTOPS_INVERTING);
473
+          bool y_max_endstop=(READ(Y_MAX_PIN) != Y_MAX_ENDSTOP_INVERTING);
424 474
           if(y_max_endstop && old_y_max_endstop && (current_block->steps_y > 0)){
425 475
             endstops_trigsteps[Y_AXIS] = count_position[Y_AXIS];
426 476
             endstop_y_hit=true;
@@ -434,15 +484,15 @@ ISR(TIMER1_COMPA_vect)
434 484
     if ((out_bits & (1<<Z_AXIS)) != 0) {   // -direction
435 485
       WRITE(Z_DIR_PIN,INVERT_Z_DIR);
436 486
       
437
-	  #ifdef Z_DUAL_STEPPER_DRIVERS
487
+      #ifdef Z_DUAL_STEPPER_DRIVERS
438 488
         WRITE(Z2_DIR_PIN,INVERT_Z_DIR);
439 489
       #endif
440
-      
490
+
441 491
       count_direction[Z_AXIS]=-1;
442 492
       CHECK_ENDSTOPS
443 493
       {
444 494
         #if defined(Z_MIN_PIN) && Z_MIN_PIN > -1
445
-          bool z_min_endstop=(READ(Z_MIN_PIN) != Z_ENDSTOPS_INVERTING);
495
+          bool z_min_endstop=(READ(Z_MIN_PIN) != Z_MIN_ENDSTOP_INVERTING);
446 496
           if(z_min_endstop && old_z_min_endstop && (current_block->steps_z > 0)) {
447 497
             endstops_trigsteps[Z_AXIS] = count_position[Z_AXIS];
448 498
             endstop_z_hit=true;
@@ -455,7 +505,7 @@ ISR(TIMER1_COMPA_vect)
455 505
     else { // +direction
456 506
       WRITE(Z_DIR_PIN,!INVERT_Z_DIR);
457 507
 
458
-	  #ifdef Z_DUAL_STEPPER_DRIVERS
508
+      #ifdef Z_DUAL_STEPPER_DRIVERS
459 509
         WRITE(Z2_DIR_PIN,!INVERT_Z_DIR);
460 510
       #endif
461 511
 
@@ -463,7 +513,7 @@ ISR(TIMER1_COMPA_vect)
463 513
       CHECK_ENDSTOPS
464 514
       {
465 515
         #if defined(Z_MAX_PIN) && Z_MAX_PIN > -1
466
-          bool z_max_endstop=(READ(Z_MAX_PIN) != Z_ENDSTOPS_INVERTING);
516
+          bool z_max_endstop=(READ(Z_MAX_PIN) != Z_MAX_ENDSTOP_INVERTING);
467 517
           if(z_max_endstop && old_z_max_endstop && (current_block->steps_z > 0)) {
468 518
             endstops_trigsteps[Z_AXIS] = count_position[Z_AXIS];
469 519
             endstop_z_hit=true;
@@ -484,10 +534,10 @@ ISR(TIMER1_COMPA_vect)
484 534
         count_direction[E_AXIS]=1;
485 535
       }
486 536
     #endif //!ADVANCE
487
-    
488 537
 
489
-    
490
-    for(int8_t i=0; i < step_loops; i++) { // Take multiple steps per interrupt (For high speed moves) 
538
+
539
+
540
+    for(int8_t i=0; i < step_loops; i++) { // Take multiple steps per interrupt (For high speed moves)
491 541
       #ifndef AT90USB
492 542
       MSerial.checkRx(); // Check for serial chars.
493 543
       #endif
@@ -502,38 +552,73 @@ ISR(TIMER1_COMPA_vect)
502 552
         else {
503 553
           e_steps[current_block->active_extruder]++;
504 554
         }
505
-      }    
555
+      }
506 556
       #endif //ADVANCE
507 557
 
508 558
         counter_x += current_block->steps_x;
509 559
         if (counter_x > 0) {
560
+        #ifdef DUAL_X_CARRIAGE
561
+          if (extruder_duplication_enabled){
562
+            WRITE(X_STEP_PIN, !INVERT_X_STEP_PIN);
563
+            WRITE(X2_STEP_PIN, !INVERT_X_STEP_PIN);
564
+          }
565
+          else {
566
+            if (current_block->active_extruder != 0)
567
+              WRITE(X2_STEP_PIN, !INVERT_X_STEP_PIN);
568
+            else
569
+              WRITE(X_STEP_PIN, !INVERT_X_STEP_PIN);
570
+          }
571
+        #else
510 572
           WRITE(X_STEP_PIN, !INVERT_X_STEP_PIN);
573
+        #endif        
511 574
           counter_x -= current_block->step_event_count;
512 575
           count_position[X_AXIS]+=count_direction[X_AXIS];   
576
+        #ifdef DUAL_X_CARRIAGE
577
+          if (extruder_duplication_enabled){
578
+            WRITE(X_STEP_PIN, INVERT_X_STEP_PIN);
579
+            WRITE(X2_STEP_PIN, INVERT_X_STEP_PIN);
580
+          }
581
+          else {
582
+            if (current_block->active_extruder != 0)
583
+              WRITE(X2_STEP_PIN, INVERT_X_STEP_PIN);
584
+            else
585
+              WRITE(X_STEP_PIN, INVERT_X_STEP_PIN);
586
+          }
587
+        #else
513 588
           WRITE(X_STEP_PIN, INVERT_X_STEP_PIN);
589
+        #endif
514 590
         }
515
-  
591
+
516 592
         counter_y += current_block->steps_y;
517 593
         if (counter_y > 0) {
518 594
           WRITE(Y_STEP_PIN, !INVERT_Y_STEP_PIN);
519
-          counter_y -= current_block->step_event_count; 
520
-          count_position[Y_AXIS]+=count_direction[Y_AXIS]; 
595
+		  
596
+		  #ifdef Y_DUAL_STEPPER_DRIVERS
597
+			WRITE(Y2_STEP_PIN, !INVERT_Y_STEP_PIN);
598
+		  #endif
599
+		  
600
+          counter_y -= current_block->step_event_count;
601
+          count_position[Y_AXIS]+=count_direction[Y_AXIS];
521 602
           WRITE(Y_STEP_PIN, INVERT_Y_STEP_PIN);
603
+		  
604
+		  #ifdef Y_DUAL_STEPPER_DRIVERS
605
+			WRITE(Y2_STEP_PIN, INVERT_Y_STEP_PIN);
606
+		  #endif
522 607
         }
523
-  
608
+
524 609
       counter_z += current_block->steps_z;
525 610
       if (counter_z > 0) {
526 611
         WRITE(Z_STEP_PIN, !INVERT_Z_STEP_PIN);
527 612
         
528
-		#ifdef Z_DUAL_STEPPER_DRIVERS
613
+        #ifdef Z_DUAL_STEPPER_DRIVERS
529 614
           WRITE(Z2_STEP_PIN, !INVERT_Z_STEP_PIN);
530 615
         #endif
531
-        
616
+
532 617
         counter_z -= current_block->step_event_count;
533 618
         count_position[Z_AXIS]+=count_direction[Z_AXIS];
534 619
         WRITE(Z_STEP_PIN, INVERT_Z_STEP_PIN);
535 620
         
536
-		#ifdef Z_DUAL_STEPPER_DRIVERS
621
+        #ifdef Z_DUAL_STEPPER_DRIVERS
537 622
           WRITE(Z2_STEP_PIN, INVERT_Z_STEP_PIN);
538 623
         #endif
539 624
       }
@@ -547,17 +632,17 @@ ISR(TIMER1_COMPA_vect)
547 632
           WRITE_E_STEP(INVERT_E_STEP_PIN);
548 633
         }
549 634
       #endif //!ADVANCE
550
-      step_events_completed += 1;  
635
+      step_events_completed += 1;
551 636
       if(step_events_completed >= current_block->step_event_count) break;
552 637
     }
553 638
     // Calculare new timer value
554 639
     unsigned short timer;
555 640
     unsigned short step_rate;
556 641
     if (step_events_completed <= (unsigned long int)current_block->accelerate_until) {
557
-      
642
+
558 643
       MultiU24X24toH16(acc_step_rate, acceleration_time, current_block->acceleration_rate);
559 644
       acc_step_rate += current_block->initial_rate;
560
-      
645
+
561 646
       // upper limit
562 647
       if(acc_step_rate > current_block->nominal_rate)
563 648
         acc_step_rate = current_block->nominal_rate;
@@ -573,13 +658,13 @@ ISR(TIMER1_COMPA_vect)
573 658
         //if(advance > current_block->advance) advance = current_block->advance;
574 659
         // Do E steps + advance steps
575 660
         e_steps[current_block->active_extruder] += ((advance >>8) - old_advance);
576
-        old_advance = advance >>8;  
577
-        
661
+        old_advance = advance >>8;
662
+
578 663
       #endif
579
-    } 
580
-    else if (step_events_completed > (unsigned long int)current_block->decelerate_after) {   
664
+    }
665
+    else if (step_events_completed > (unsigned long int)current_block->decelerate_after) {
581 666
       MultiU24X24toH16(step_rate, deceleration_time, current_block->acceleration_rate);
582
-      
667
+
583 668
       if(step_rate > acc_step_rate) { // Check step_rate stays positive
584 669
         step_rate = current_block->final_rate;
585 670
       }
@@ -602,7 +687,7 @@ ISR(TIMER1_COMPA_vect)
602 687
         if(advance < final_advance) advance = final_advance;
603 688
         // Do E steps + advance steps
604 689
         e_steps[current_block->active_extruder] += ((advance >>8) - old_advance);
605
-        old_advance = advance >>8;  
690
+        old_advance = advance >>8;
606 691
       #endif //ADVANCE
607 692
     }
608 693
     else {
@@ -611,12 +696,12 @@ ISR(TIMER1_COMPA_vect)
611 696
       step_loops = step_loops_nominal;
612 697
     }
613 698
 
614
-    // If current block is finished, reset pointer 
699
+    // If current block is finished, reset pointer
615 700
     if (step_events_completed >= current_block->step_event_count) {
616 701
       current_block = NULL;
617 702
       plan_discard_current_block();
618
-    }   
619
-  } 
703
+    }
704
+  }
620 705
 }
621 706
 
622 707
 #ifdef ADVANCE
@@ -635,7 +720,7 @@ ISR(TIMER1_COMPA_vect)
635 720
           WRITE(E0_DIR_PIN, INVERT_E0_DIR);
636 721
           e_steps[0]++;
637 722
           WRITE(E0_STEP_PIN, !INVERT_E_STEP_PIN);
638
-        } 
723
+        }
639 724
         else if (e_steps[0] > 0) {
640 725
           WRITE(E0_DIR_PIN, !INVERT_E0_DIR);
641 726
           e_steps[0]--;
@@ -649,7 +734,7 @@ ISR(TIMER1_COMPA_vect)
649 734
           WRITE(E1_DIR_PIN, INVERT_E1_DIR);
650 735
           e_steps[1]++;
651 736
           WRITE(E1_STEP_PIN, !INVERT_E_STEP_PIN);
652
-        } 
737
+        }
653 738
         else if (e_steps[1] > 0) {
654 739
           WRITE(E1_DIR_PIN, !INVERT_E1_DIR);
655 740
           e_steps[1]--;
@@ -664,7 +749,7 @@ ISR(TIMER1_COMPA_vect)
664 749
           WRITE(E2_DIR_PIN, INVERT_E2_DIR);
665 750
           e_steps[2]++;
666 751
           WRITE(E2_STEP_PIN, !INVERT_E_STEP_PIN);
667
-        } 
752
+        }
668 753
         else if (e_steps[2] > 0) {
669 754
           WRITE(E2_DIR_PIN, !INVERT_E2_DIR);
670 755
           e_steps[2]--;
@@ -680,22 +765,29 @@ void st_init()
680 765
 {
681 766
   digipot_init(); //Initialize Digipot Motor Current
682 767
   microstep_init(); //Initialize Microstepping Pins
683
-  
768
+
684 769
   //Initialize Dir Pins
685 770
   #if defined(X_DIR_PIN) && X_DIR_PIN > -1
686 771
     SET_OUTPUT(X_DIR_PIN);
687 772
   #endif
688
-  #if defined(Y_DIR_PIN) && Y_DIR_PIN > -1 
773
+  #if defined(X2_DIR_PIN) && X2_DIR_PIN > -1
774
+    SET_OUTPUT(X2_DIR_PIN);
775
+  #endif
776
+  #if defined(Y_DIR_PIN) && Y_DIR_PIN > -1
689 777
     SET_OUTPUT(Y_DIR_PIN);
778
+	
779
+	#if defined(Y_DUAL_STEPPER_DRIVERS) && defined(Y2_DIR_PIN) && (Y2_DIR_PIN > -1)
780
+	  SET_OUTPUT(Y2_DIR_PIN);
781
+	#endif
690 782
   #endif
691
-  #if defined(Z_DIR_PIN) && Z_DIR_PIN > -1 
783
+  #if defined(Z_DIR_PIN) && Z_DIR_PIN > -1
692 784
     SET_OUTPUT(Z_DIR_PIN);
693 785
 
694 786
     #if defined(Z_DUAL_STEPPER_DRIVERS) && defined(Z2_DIR_PIN) && (Z2_DIR_PIN > -1)
695 787
       SET_OUTPUT(Z2_DIR_PIN);
696 788
     #endif
697 789
   #endif
698
-  #if defined(E0_DIR_PIN) && E0_DIR_PIN > -1 
790
+  #if defined(E0_DIR_PIN) && E0_DIR_PIN > -1
699 791
     SET_OUTPUT(E0_DIR_PIN);
700 792
   #endif
701 793
   #if defined(E1_DIR_PIN) && (E1_DIR_PIN > -1)
@@ -711,14 +803,23 @@ void st_init()
711 803
     SET_OUTPUT(X_ENABLE_PIN);
712 804
     if(!X_ENABLE_ON) WRITE(X_ENABLE_PIN,HIGH);
713 805
   #endif
806
+  #if defined(X2_ENABLE_PIN) && X2_ENABLE_PIN > -1
807
+    SET_OUTPUT(X2_ENABLE_PIN);
808
+    if(!X_ENABLE_ON) WRITE(X2_ENABLE_PIN,HIGH);
809
+  #endif
714 810
   #if defined(Y_ENABLE_PIN) && Y_ENABLE_PIN > -1
715 811
     SET_OUTPUT(Y_ENABLE_PIN);
716 812
     if(!Y_ENABLE_ON) WRITE(Y_ENABLE_PIN,HIGH);
813
+	
814
+	#if defined(Y_DUAL_STEPPER_DRIVERS) && defined(Y2_ENABLE_PIN) && (Y2_ENABLE_PIN > -1)
815
+	  SET_OUTPUT(Y2_ENABLE_PIN);
816
+	  if(!Y_ENABLE_ON) WRITE(Y2_ENABLE_PIN,HIGH);
817
+	#endif
717 818
   #endif
718 819
   #if defined(Z_ENABLE_PIN) && Z_ENABLE_PIN > -1
719 820
     SET_OUTPUT(Z_ENABLE_PIN);
720 821
     if(!Z_ENABLE_ON) WRITE(Z_ENABLE_PIN,HIGH);
721
-    
822
+
722 823
     #if defined(Z_DUAL_STEPPER_DRIVERS) && defined(Z2_ENABLE_PIN) && (Z2_ENABLE_PIN > -1)
723 824
       SET_OUTPUT(Z2_ENABLE_PIN);
724 825
       if(!Z_ENABLE_ON) WRITE(Z2_ENABLE_PIN,HIGH);
@@ -738,62 +839,71 @@ void st_init()
738 839
   #endif
739 840
 
740 841
   //endstops and pullups
741
-  
842
+
742 843
   #if defined(X_MIN_PIN) && X_MIN_PIN > -1
743
-    SET_INPUT(X_MIN_PIN); 
844
+    SET_INPUT(X_MIN_PIN);
744 845
     #ifdef ENDSTOPPULLUP_XMIN
745 846
       WRITE(X_MIN_PIN,HIGH);
746 847
     #endif
747 848
   #endif
748
-      
849
+
749 850
   #if defined(Y_MIN_PIN) && Y_MIN_PIN > -1
750
-    SET_INPUT(Y_MIN_PIN); 
851
+    SET_INPUT(Y_MIN_PIN);
751 852
     #ifdef ENDSTOPPULLUP_YMIN
752 853
       WRITE(Y_MIN_PIN,HIGH);
753 854
     #endif
754 855
   #endif
755
-  
856
+
756 857
   #if defined(Z_MIN_PIN) && Z_MIN_PIN > -1
757
-    SET_INPUT(Z_MIN_PIN); 
858
+    SET_INPUT(Z_MIN_PIN);
758 859
     #ifdef ENDSTOPPULLUP_ZMIN
759 860
       WRITE(Z_MIN_PIN,HIGH);
760 861
     #endif
761 862
   #endif
762
-      
863
+
763 864
   #if defined(X_MAX_PIN) && X_MAX_PIN > -1
764
-    SET_INPUT(X_MAX_PIN); 
865
+    SET_INPUT(X_MAX_PIN);
765 866
     #ifdef ENDSTOPPULLUP_XMAX
766 867
       WRITE(X_MAX_PIN,HIGH);
767 868
     #endif
768 869
   #endif
769
-      
870
+
770 871
   #if defined(Y_MAX_PIN) && Y_MAX_PIN > -1
771
-    SET_INPUT(Y_MAX_PIN); 
872
+    SET_INPUT(Y_MAX_PIN);
772 873
     #ifdef ENDSTOPPULLUP_YMAX
773 874
       WRITE(Y_MAX_PIN,HIGH);
774 875
     #endif
775 876
   #endif
776
-  
877
+
777 878
   #if defined(Z_MAX_PIN) && Z_MAX_PIN > -1
778
-    SET_INPUT(Z_MAX_PIN); 
879
+    SET_INPUT(Z_MAX_PIN);
779 880
     #ifdef ENDSTOPPULLUP_ZMAX
780 881
       WRITE(Z_MAX_PIN,HIGH);
781 882
     #endif
782 883
   #endif
783
- 
884
+
784 885
 
785 886
   //Initialize Step Pins
786
-  #if defined(X_STEP_PIN) && (X_STEP_PIN > -1) 
887
+  #if defined(X_STEP_PIN) && (X_STEP_PIN > -1)
787 888
     SET_OUTPUT(X_STEP_PIN);
788 889
     WRITE(X_STEP_PIN,INVERT_X_STEP_PIN);
789 890
     disable_x();
790
-  #endif  
791
-  #if defined(Y_STEP_PIN) && (Y_STEP_PIN > -1) 
891
+  #endif
892
+  #if defined(X2_STEP_PIN) && (X2_STEP_PIN > -1)
893
+    SET_OUTPUT(X2_STEP_PIN);
894
+    WRITE(X2_STEP_PIN,INVERT_X_STEP_PIN);
895
+    disable_x();
896
+  #endif
897
+  #if defined(Y_STEP_PIN) && (Y_STEP_PIN > -1)
792 898
     SET_OUTPUT(Y_STEP_PIN);
793 899
     WRITE(Y_STEP_PIN,INVERT_Y_STEP_PIN);
900
+    #if defined(Y_DUAL_STEPPER_DRIVERS) && defined(Y2_STEP_PIN) && (Y2_STEP_PIN > -1)
901
+      SET_OUTPUT(Y2_STEP_PIN);
902
+      WRITE(Y2_STEP_PIN,INVERT_Y_STEP_PIN);
903
+    #endif
794 904
     disable_y();
795
-  #endif  
796
-  #if defined(Z_STEP_PIN) && (Z_STEP_PIN > -1) 
905
+  #endif
906
+  #if defined(Z_STEP_PIN) && (Z_STEP_PIN > -1)
797 907
     SET_OUTPUT(Z_STEP_PIN);
798 908
     WRITE(Z_STEP_PIN,INVERT_Z_STEP_PIN);
799 909
     #if defined(Z_DUAL_STEPPER_DRIVERS) && defined(Z2_STEP_PIN) && (Z2_STEP_PIN > -1)
@@ -801,33 +911,33 @@ void st_init()
801 911
       WRITE(Z2_STEP_PIN,INVERT_Z_STEP_PIN);
802 912
     #endif
803 913
     disable_z();
804
-  #endif  
805
-  #if defined(E0_STEP_PIN) && (E0_STEP_PIN > -1) 
914
+  #endif
915
+  #if defined(E0_STEP_PIN) && (E0_STEP_PIN > -1)
806 916
     SET_OUTPUT(E0_STEP_PIN);
807 917
     WRITE(E0_STEP_PIN,INVERT_E_STEP_PIN);
808 918
     disable_e0();
809
-  #endif  
810
-  #if defined(E1_STEP_PIN) && (E1_STEP_PIN > -1) 
919
+  #endif
920
+  #if defined(E1_STEP_PIN) && (E1_STEP_PIN > -1)
811 921
     SET_OUTPUT(E1_STEP_PIN);
812 922
     WRITE(E1_STEP_PIN,INVERT_E_STEP_PIN);
813 923
     disable_e1();
814
-  #endif  
815
-  #if defined(E2_STEP_PIN) && (E2_STEP_PIN > -1) 
924
+  #endif
925
+  #if defined(E2_STEP_PIN) && (E2_STEP_PIN > -1)
816 926
     SET_OUTPUT(E2_STEP_PIN);
817 927
     WRITE(E2_STEP_PIN,INVERT_E_STEP_PIN);
818 928
     disable_e2();
819
-  #endif  
929
+  #endif
820 930
 
821 931
   // waveform generation = 0100 = CTC
822 932
   TCCR1B &= ~(1<<WGM13);
823 933
   TCCR1B |=  (1<<WGM12);
824
-  TCCR1A &= ~(1<<WGM11); 
934
+  TCCR1A &= ~(1<<WGM11);
825 935
   TCCR1A &= ~(1<<WGM10);
826 936
 
827 937
   // output mode = 00 (disconnected)
828
-  TCCR1A &= ~(3<<COM1A0); 
829
-  TCCR1A &= ~(3<<COM1B0); 
830
-  
938
+  TCCR1A &= ~(3<<COM1A0);
939
+  TCCR1A &= ~(3<<COM1B0);
940
+
831 941
   // Set the timer pre-scaler
832 942
   // Generally we use a divider of 8, resulting in a 2MHz timer
833 943
   // frequency on a 16MHz MCU. If you are going to change this, be
@@ -837,19 +947,19 @@ void st_init()
837 947
 
838 948
   OCR1A = 0x4000;
839 949
   TCNT1 = 0;
840
-  ENABLE_STEPPER_DRIVER_INTERRUPT();  
950
+  ENABLE_STEPPER_DRIVER_INTERRUPT();
841 951
 
842 952
   #ifdef ADVANCE
843 953
   #if defined(TCCR0A) && defined(WGM01)
844 954
     TCCR0A &= ~(1<<WGM01);
845 955
     TCCR0A &= ~(1<<WGM00);
846
-  #endif  
956
+  #endif
847 957
     e_steps[0] = 0;
848 958
     e_steps[1] = 0;
849 959
     e_steps[2] = 0;
850 960
     TIMSK0 |= (1<<OCIE0A);
851 961
   #endif //ADVANCE
852
-  
962
+
853 963
   enable_endstops(true); // Start with endstops active. After homing they can be disabled
854 964
   sei();
855 965
 }
@@ -893,13 +1003,13 @@ long st_get_position(uint8_t axis)
893 1003
 
894 1004
 void finishAndDisableSteppers()
895 1005
 {
896
-  st_synchronize(); 
897
-  disable_x(); 
898
-  disable_y(); 
899
-  disable_z(); 
900
-  disable_e0(); 
901
-  disable_e1(); 
902
-  disable_e2(); 
1006
+  st_synchronize();
1007
+  disable_x();
1008
+  disable_y();
1009
+  disable_z();
1010
+  disable_e0();
1011
+  disable_e1();
1012
+  disable_e2();
903 1013
 }
904 1014
 
905 1015
 void quickStop()
@@ -926,10 +1036,10 @@ void digipot_init() //Initialize Digipot Motor Current
926 1036
 {
927 1037
   #if defined(DIGIPOTSS_PIN) && DIGIPOTSS_PIN > -1
928 1038
     const uint8_t digipot_motor_current[] = DIGIPOT_MOTOR_CURRENT;
929
-    
930
-    SPI.begin(); 
931
-    pinMode(DIGIPOTSS_PIN, OUTPUT);    
932
-    for(int i=0;i<=4;i++) 
1039
+
1040
+    SPI.begin();
1041
+    pinMode(DIGIPOTSS_PIN, OUTPUT);
1042
+    for(int i=0;i<=4;i++)
933 1043
       //digitalPotWrite(digipot_ch[i], digipot_motor_current[i]);
934 1044
       digipot_current(i,digipot_motor_current[i]);
935 1045
   #endif

Loading…
Cancel
Save