Browse Source

Implement MIXING_EXTRUDER and SWITCHING_EXTRUDER

Scott Lahteine 8 years ago
parent
commit
05da02f0a2

+ 55
- 25
Marlin/Marlin.h View File

167
   #define disable_z() NOOP
167
   #define disable_z() NOOP
168
 #endif
168
 #endif
169
 
169
 
170
-#if HAS_E0_ENABLE
171
-  #define  enable_e0() E0_ENABLE_WRITE( E_ENABLE_ON)
172
-  #define disable_e0() E0_ENABLE_WRITE(!E_ENABLE_ON)
173
-#else
174
-  #define  enable_e0() NOOP
175
-  #define disable_e0() NOOP
176
-#endif
177
-
178
-#if (EXTRUDERS > 1) && HAS_E1_ENABLE
179
-  #define  enable_e1() E1_ENABLE_WRITE( E_ENABLE_ON)
180
-  #define disable_e1() E1_ENABLE_WRITE(!E_ENABLE_ON)
181
-#else
170
+#if ENABLED(MIXING_EXTRUDER)
171
+
172
+  /**
173
+   * Mixing steppers synchronize their enable (and direction) together
174
+   */
175
+  #if MIXING_STEPPERS > 3
176
+    #define  enable_e0() { E0_ENABLE_WRITE( E_ENABLE_ON); E1_ENABLE_WRITE( E_ENABLE_ON); E2_ENABLE_WRITE( E_ENABLE_ON); E3_ENABLE_WRITE( E_ENABLE_ON); }
177
+    #define disable_e0() { E0_ENABLE_WRITE(!E_ENABLE_ON); E1_ENABLE_WRITE(!E_ENABLE_ON); E2_ENABLE_WRITE(!E_ENABLE_ON); E3_ENABLE_WRITE(!E_ENABLE_ON); }
178
+  #elif MIXING_STEPPERS > 2
179
+    #define  enable_e0() { E0_ENABLE_WRITE( E_ENABLE_ON); E1_ENABLE_WRITE( E_ENABLE_ON); E2_ENABLE_WRITE( E_ENABLE_ON); }
180
+    #define disable_e0() { E0_ENABLE_WRITE(!E_ENABLE_ON); E1_ENABLE_WRITE(!E_ENABLE_ON); E2_ENABLE_WRITE(!E_ENABLE_ON); }
181
+  #else
182
+    #define  enable_e0() { E0_ENABLE_WRITE( E_ENABLE_ON); E1_ENABLE_WRITE( E_ENABLE_ON); }
183
+    #define disable_e0() { E0_ENABLE_WRITE(!E_ENABLE_ON); E1_ENABLE_WRITE(!E_ENABLE_ON); }
184
+  #endif
182
   #define  enable_e1() NOOP
185
   #define  enable_e1() NOOP
183
   #define disable_e1() NOOP
186
   #define disable_e1() NOOP
184
-#endif
185
-
186
-#if (EXTRUDERS > 2) && HAS_E2_ENABLE
187
-  #define  enable_e2() E2_ENABLE_WRITE( E_ENABLE_ON)
188
-  #define disable_e2() E2_ENABLE_WRITE(!E_ENABLE_ON)
189
-#else
190
   #define  enable_e2() NOOP
187
   #define  enable_e2() NOOP
191
   #define disable_e2() NOOP
188
   #define disable_e2() NOOP
192
-#endif
193
-
194
-#if (EXTRUDERS > 3) && HAS_E3_ENABLE
195
-  #define  enable_e3() E3_ENABLE_WRITE( E_ENABLE_ON)
196
-  #define disable_e3() E3_ENABLE_WRITE(!E_ENABLE_ON)
197
-#else
198
   #define  enable_e3() NOOP
189
   #define  enable_e3() NOOP
199
   #define disable_e3() NOOP
190
   #define disable_e3() NOOP
200
-#endif
191
+
192
+#else // !MIXING_EXTRUDER
193
+
194
+  #if HAS_E0_ENABLE
195
+    #define  enable_e0() E0_ENABLE_WRITE( E_ENABLE_ON)
196
+    #define disable_e0() E0_ENABLE_WRITE(!E_ENABLE_ON)
197
+  #else
198
+    #define  enable_e0() NOOP
199
+    #define disable_e0() NOOP
200
+  #endif
201
+
202
+  #if E_STEPPERS > 1 && HAS_E1_ENABLE
203
+    #define  enable_e1() E1_ENABLE_WRITE( E_ENABLE_ON)
204
+    #define disable_e1() E1_ENABLE_WRITE(!E_ENABLE_ON)
205
+  #else
206
+    #define  enable_e1() NOOP
207
+    #define disable_e1() NOOP
208
+  #endif
209
+
210
+  #if E_STEPPERS > 2 && HAS_E2_ENABLE
211
+    #define  enable_e2() E2_ENABLE_WRITE( E_ENABLE_ON)
212
+    #define disable_e2() E2_ENABLE_WRITE(!E_ENABLE_ON)
213
+  #else
214
+    #define  enable_e2() NOOP
215
+    #define disable_e2() NOOP
216
+  #endif
217
+
218
+  #if E_STEPPERS > 3 && HAS_E3_ENABLE
219
+    #define  enable_e3() E3_ENABLE_WRITE( E_ENABLE_ON)
220
+    #define disable_e3() E3_ENABLE_WRITE(!E_ENABLE_ON)
221
+  #else
222
+    #define  enable_e3() NOOP
223
+    #define disable_e3() NOOP
224
+  #endif
225
+
226
+#endif // !MIXING_EXTRUDER
201
 
227
 
202
 /**
228
 /**
203
  * The axis order in all axis related arrays is X, Y, Z, E
229
  * The axis order in all axis related arrays is X, Y, Z, E
376
   void print_heaterstates();
402
   void print_heaterstates();
377
 #endif
403
 #endif
378
 
404
 
405
+#if ENABLED(MIXING_EXTRUDER)
406
+  extern float mixing_factor[MIXING_STEPPERS];
407
+#endif
408
+
379
 void calculate_volumetric_multipliers();
409
 void calculate_volumetric_multipliers();
380
 
410
 
381
 // Buzzer
411
 // Buzzer

+ 444
- 247
Marlin/Marlin_main.cpp View File

183
  * M145 - Set the heatup state H<hotend> B<bed> F<fan speed> for S<material> (0=PLA, 1=ABS)
183
  * M145 - Set the heatup state H<hotend> B<bed> F<fan speed> for S<material> (0=PLA, 1=ABS)
184
  * M149 - Set temperature units
184
  * M149 - Set temperature units
185
  * M150 - Set BlinkM Color Output R: Red<0-255> U(!): Green<0-255> B: Blue<0-255> over i2c, G for green does not work.
185
  * M150 - Set BlinkM Color Output R: Red<0-255> U(!): Green<0-255> B: Blue<0-255> over i2c, G for green does not work.
186
+ * M163 - Set a single proportion for a mixing extruder. Requires MIXING_EXTRUDER.
187
+ * M164 - Save the mix as a virtual extruder. Requires MIXING_EXTRUDER and MIXING_VIRTUAL_TOOLS.
188
+ * M165 - Set the proportions for a mixing extruder. Use parameters ABCDHI to set the mixing factors. Requires MIXING_EXTRUDER.
186
  * M190 - Sxxx Wait for bed current temp to reach target temp. Waits only when heating
189
  * M190 - Sxxx Wait for bed current temp to reach target temp. Waits only when heating
187
  *        Rxxx Wait for bed current temp to reach target temp. Waits when heating and cooling
190
  *        Rxxx Wait for bed current temp to reach target temp. Waits when heating and cooling
188
  * M200 - Set filament diameter, D<diameter>, setting E axis units to cubic. (Use S0 to revert to linear units.)
191
  * M200 - Set filament diameter, D<diameter>, setting E axis units to cubic. (Use S0 to revert to linear units.)
397
 
400
 
398
 // Extruder offsets
401
 // Extruder offsets
399
 #if HOTENDS > 1
402
 #if HOTENDS > 1
400
-  #ifndef HOTEND_OFFSET_X
401
-    #define HOTEND_OFFSET_X { 0 } // X offsets for each extruder
402
-  #endif
403
-  #ifndef HOTEND_OFFSET_Y
404
-    #define HOTEND_OFFSET_Y { 0 } // Y offsets for each extruder
405
-  #endif
406
   float hotend_offset[][HOTENDS] = {
403
   float hotend_offset[][HOTENDS] = {
407
     HOTEND_OFFSET_X,
404
     HOTEND_OFFSET_X,
408
     HOTEND_OFFSET_Y
405
     HOTEND_OFFSET_Y
409
-    #if ENABLED(DUAL_X_CARRIAGE)
410
-      , { 0 } // Z offsets for each extruder
406
+    #ifdef HOTEND_OFFSET_Z
407
+      , HOTEND_OFFSET_Z
411
     #endif
408
     #endif
412
   };
409
   };
413
 #endif
410
 #endif
507
   FilamentChangeMenuResponse filament_change_menu_response;
504
   FilamentChangeMenuResponse filament_change_menu_response;
508
 #endif
505
 #endif
509
 
506
 
507
+#if ENABLED(MIXING_EXTRUDER)
508
+  float mixing_factor[MIXING_STEPPERS];
509
+  #if MIXING_VIRTUAL_TOOLS > 1
510
+    float mixing_virtual_tool_mix[MIXING_VIRTUAL_TOOLS][MIXING_STEPPERS];
511
+  #endif
512
+#endif
513
+
510
 static bool send_ok[BUFSIZE];
514
 static bool send_ok[BUFSIZE];
511
 
515
 
512
 #if HAS_SERVOS
516
 #if HAS_SERVOS
952
       lcd_init();
956
       lcd_init();
953
     #endif
957
     #endif
954
   #endif
958
   #endif
959
+
960
+  #if ENABLED(MIXING_EXTRUDER) && MIXING_VIRTUAL_TOOLS > 1
961
+    // Initialize mixing to 100% color 1
962
+    for (uint8_t i = 0; i < MIXING_STEPPERS; i++)
963
+      mixing_factor[i] = (i == 0) ? 1 : 0;
964
+    for (uint8_t t = 0; t < MIXING_VIRTUAL_TOOLS; t++)
965
+      for (uint8_t i = 0; i < MIXING_STEPPERS; i++)
966
+        mixing_virtual_tool_mix[t][i] = mixing_factor[i];
967
+  #endif
955
 }
968
 }
956
 
969
 
957
 /**
970
 /**
2544
 
2557
 
2545
 #endif // FWRETRACT
2558
 #endif // FWRETRACT
2546
 
2559
 
2560
+#if ENABLED(MIXING_EXTRUDER)
2561
+
2562
+  void normalize_mix() {
2563
+    float mix_total = 0.0;
2564
+    for (int i = 0; i < MIXING_STEPPERS; i++) {
2565
+      float v = mixing_factor[i];
2566
+      if (v < 0) v = mixing_factor[i] = 0;
2567
+      mix_total += v;
2568
+    }
2569
+    // Scale all values if they don't add up to ~1.0
2570
+    if (mix_total < 0.9999 || mix_total > 1.0001) {
2571
+      SERIAL_PROTOCOLLNPGM("Warning: Mix factors must add up to 1.0. Scaling.");
2572
+      float mix_scale = 1.0 / mix_total;
2573
+      for (int i = 0; i < MIXING_STEPPERS; i++)
2574
+        mixing_factor[i] *= mix_scale;
2575
+    }
2576
+  }
2577
+
2578
+  #if ENABLED(DIRECT_MIXING_IN_G1)
2579
+    // Get mixing parameters from the GCode
2580
+    // Factors that are left out are set to 0
2581
+    // The total "must" be 1.0 (but it will be normalized)
2582
+    void gcode_get_mix() {
2583
+      const char* mixing_codes = "ABCDHI";
2584
+      for (int i = 0; i < MIXING_STEPPERS; i++)
2585
+        mixing_factor[i] = code_seen(mixing_codes[i]) ? code_value_float() : 0;
2586
+
2587
+      normalize_mix();
2588
+    }
2589
+  #endif
2590
+
2591
+#endif
2592
+
2547
 /**
2593
 /**
2548
  * ***************************************************************************
2594
  * ***************************************************************************
2549
  * ***************************** G-CODE HANDLING *****************************
2595
  * ***************************** G-CODE HANDLING *****************************
2572
     if(!DEBUGGING(DRYRUN))
2618
     if(!DEBUGGING(DRYRUN))
2573
       print_job_timer.incFilamentUsed(destination[E_AXIS] - current_position[E_AXIS]);
2619
       print_job_timer.incFilamentUsed(destination[E_AXIS] - current_position[E_AXIS]);
2574
   #endif
2620
   #endif
2621
+
2622
+  // Get ABCDHI mixing factors
2623
+  #if ENABLED(MIXING_EXTRUDER) && ENABLED(DIRECT_MIXING_IN_G1)
2624
+    gcode_get_mix();
2625
+  #endif
2575
 }
2626
 }
2576
 
2627
 
2577
 void unknown_command_error() {
2628
 void unknown_command_error() {
4733
 
4784
 
4734
     KEEPALIVE_STATE(NOT_BUSY);
4785
     KEEPALIVE_STATE(NOT_BUSY);
4735
 
4786
 
4787
+    target_extruder = active_extruder; // for print_heaterstates
4788
+
4736
     do {
4789
     do {
4737
       // Target temperature might be changed during the loop
4790
       // Target temperature might be changed during the loop
4738
       if (theTarget != thermalManager.degTargetBed()) {
4791
       if (theTarget != thermalManager.degTargetBed()) {
5258
     if (volumetric_enabled) {
5311
     if (volumetric_enabled) {
5259
       filament_size[target_extruder] = code_value_linear_units();
5312
       filament_size[target_extruder] = code_value_linear_units();
5260
       // make sure all extruders have some sane value for the filament size
5313
       // make sure all extruders have some sane value for the filament size
5261
-      for (int i = 0; i < EXTRUDERS; i++)
5314
+      for (int i = 0; i < COUNT(filament_size); i++)
5262
         if (! filament_size[i]) filament_size[i] = DEFAULT_NOMINAL_FILAMENT_DIA;
5315
         if (! filament_size[i]) filament_size[i] = DEFAULT_NOMINAL_FILAMENT_DIA;
5263
     }
5316
     }
5264
   }
5317
   }
5496
    *   T<tool>
5549
    *   T<tool>
5497
    *   X<xoffset>
5550
    *   X<xoffset>
5498
    *   Y<yoffset>
5551
    *   Y<yoffset>
5499
-   *   Z<zoffset> - Available with DUAL_X_CARRIAGE
5552
+   *   Z<zoffset> - Available with DUAL_X_CARRIAGE and SWITCHING_EXTRUDER
5500
    */
5553
    */
5501
   inline void gcode_M218() {
5554
   inline void gcode_M218() {
5502
     if (get_target_extruder_from_command(218)) return;
5555
     if (get_target_extruder_from_command(218)) return;
5504
     if (code_seen('X')) hotend_offset[X_AXIS][target_extruder] = code_value_axis_units(X_AXIS);
5557
     if (code_seen('X')) hotend_offset[X_AXIS][target_extruder] = code_value_axis_units(X_AXIS);
5505
     if (code_seen('Y')) hotend_offset[Y_AXIS][target_extruder] = code_value_axis_units(Y_AXIS);
5558
     if (code_seen('Y')) hotend_offset[Y_AXIS][target_extruder] = code_value_axis_units(Y_AXIS);
5506
 
5559
 
5507
-    #if ENABLED(DUAL_X_CARRIAGE)
5560
+    #if ENABLED(DUAL_X_CARRIAGE) || ENABLED(SWITCHING_EXTRUDER)
5508
       if (code_seen('Z')) hotend_offset[Z_AXIS][target_extruder] = code_value_axis_units(Z_AXIS);
5561
       if (code_seen('Z')) hotend_offset[Z_AXIS][target_extruder] = code_value_axis_units(Z_AXIS);
5509
     #endif
5562
     #endif
5510
 
5563
 
5515
       SERIAL_ECHO(hotend_offset[X_AXIS][e]);
5568
       SERIAL_ECHO(hotend_offset[X_AXIS][e]);
5516
       SERIAL_CHAR(',');
5569
       SERIAL_CHAR(',');
5517
       SERIAL_ECHO(hotend_offset[Y_AXIS][e]);
5570
       SERIAL_ECHO(hotend_offset[Y_AXIS][e]);
5518
-      #if ENABLED(DUAL_X_CARRIAGE)
5571
+      #if ENABLED(DUAL_X_CARRIAGE) || ENABLED(SWITCHING_EXTRUDER)
5519
         SERIAL_CHAR(',');
5572
         SERIAL_CHAR(',');
5520
         SERIAL_ECHO(hotend_offset[Z_AXIS][e]);
5573
         SERIAL_ECHO(hotend_offset[Z_AXIS][e]);
5521
       #endif
5574
       #endif
6528
 
6581
 
6529
 #endif // HAS_MICROSTEPS
6582
 #endif // HAS_MICROSTEPS
6530
 
6583
 
6584
+#if ENABLED(MIXING_EXTRUDER)
6585
+
6586
+  /**
6587
+   * M163: Set a single mix factor for a mixing extruder
6588
+   *       This is called "weight" by some systems.
6589
+   *
6590
+   *   S[index]   The channel index to set
6591
+   *   P[float]   The mix value
6592
+   *
6593
+   */
6594
+  inline void gcode_M163() {
6595
+    int mix_index = code_seen('S') ? code_value_int() : 0;
6596
+    float mix_value = code_seen('P') ? code_value_float() : 0.0;
6597
+    if (mix_index < MIXING_STEPPERS) mixing_factor[mix_index] = mix_value;
6598
+  }
6599
+
6600
+  #if MIXING_VIRTUAL_TOOLS > 1
6601
+
6602
+    /**
6603
+     * M164: Store the current mix factors as a virtual tool.
6604
+     *
6605
+     *   S[index]   The virtual tool to store
6606
+     *
6607
+     */
6608
+    inline void gcode_M164() {
6609
+      int tool_index = code_seen('S') ? code_value_int() : 0;
6610
+      if (tool_index < MIXING_VIRTUAL_TOOLS) {
6611
+        normalize_mix();
6612
+        for (uint8_t i = 0; i < MIXING_STEPPERS; i++)
6613
+          mixing_virtual_tool_mix[tool_index][i] = mixing_factor[i];
6614
+      }
6615
+    }
6616
+
6617
+  #endif
6618
+
6619
+  #if ENABLED(DIRECT_MIXING_IN_G1)
6620
+    /**
6621
+     * M165: Set multiple mix factors for a mixing extruder.
6622
+     *       Factors that are left out will be set to 0.
6623
+     *       All factors together must add up to 1.0.
6624
+     *
6625
+     *   A[factor] Mix factor for extruder stepper 1
6626
+     *   B[factor] Mix factor for extruder stepper 2
6627
+     *   C[factor] Mix factor for extruder stepper 3
6628
+     *   D[factor] Mix factor for extruder stepper 4
6629
+     *   H[factor] Mix factor for extruder stepper 5
6630
+     *   I[factor] Mix factor for extruder stepper 6
6631
+     *
6632
+     */
6633
+    inline void gcode_M165() { gcode_get_mix(); }
6634
+  #endif
6635
+
6636
+#endif // MIXING_EXTRUDER
6637
+
6531
 /**
6638
 /**
6532
  * M999: Restart after being stopped
6639
  * M999: Restart after being stopped
6533
  *
6640
  *
6548
   FlushSerialRequestResend();
6655
   FlushSerialRequestResend();
6549
 }
6656
 }
6550
 
6657
 
6658
+#if ENABLED(SWITCHING_EXTRUDER)
6659
+  inline void move_extruder_servo(uint8_t e) {
6660
+    const int angles[2] = SWITCHING_EXTRUDER_SERVO_ANGLES;
6661
+    MOVE_SERVO(SWITCHING_EXTRUDER_SERVO_NR, angles[e]);
6662
+  }
6663
+#endif
6664
+
6665
+inline void invalid_extruder_error(const uint8_t &e) {
6666
+  SERIAL_ECHO_START;
6667
+  SERIAL_CHAR('T');
6668
+  SERIAL_PROTOCOL_F(e, DEC);
6669
+  SERIAL_ECHOLN(MSG_INVALID_EXTRUDER);
6670
+}
6671
+
6551
 /**
6672
 /**
6552
  * T0-T3: Switch tool, usually switching extruders
6673
  * T0-T3: Switch tool, usually switching extruders
6553
  *
6674
  *
6555
  *   S1           Don't move the tool in XY after change
6676
  *   S1           Don't move the tool in XY after change
6556
  */
6677
  */
6557
 inline void gcode_T(uint8_t tmp_extruder) {
6678
 inline void gcode_T(uint8_t tmp_extruder) {
6558
-  if (tmp_extruder >= EXTRUDERS) {
6559
-    SERIAL_ECHO_START;
6560
-    SERIAL_CHAR('T');
6561
-    SERIAL_PROTOCOL_F(tmp_extruder, DEC);
6562
-    SERIAL_ECHOLN(MSG_INVALID_EXTRUDER);
6563
-    return;
6564
-  }
6565
 
6679
 
6566
-  #if ENABLED(DEBUG_LEVELING_FEATURE)
6567
-    if (DEBUGGING(LEVELING)) {
6568
-      SERIAL_ECHOLNPGM(">>> gcode_T");
6569
-      DEBUG_POS("BEFORE", current_position);
6680
+  #if ENABLED(MIXING_EXTRUDER) && MIXING_VIRTUAL_TOOLS > 1
6681
+
6682
+    if (tmp_extruder >= MIXING_VIRTUAL_TOOLS) {
6683
+      invalid_extruder_error(tmp_extruder);
6684
+      return;
6570
     }
6685
     }
6571
-  #endif
6572
 
6686
 
6573
-  #if HOTENDS > 1
6687
+    // T0-Tnnn: Switch virtual tool by changing the mix
6688
+    for (uint8_t j = 0; j < MIXING_STEPPERS; j++)
6689
+      mixing_factor[j] = mixing_virtual_tool_mix[tmp_extruder][j];
6574
 
6690
 
6575
-    float old_feedrate = feedrate;
6691
+  #else //!MIXING_EXTRUDER || MIXING_VIRTUAL_TOOLS <= 1
6576
 
6692
 
6577
-    if (code_seen('F')) {
6578
-      float next_feedrate = code_value_axis_units(X_AXIS);
6579
-      if (next_feedrate > 0.0) old_feedrate = feedrate = next_feedrate;
6580
-    }
6581
-    else
6582
-      feedrate = XY_PROBE_FEEDRATE;
6693
+    #if ENABLED(DEBUG_LEVELING_FEATURE)
6694
+      if (DEBUGGING(LEVELING)) {
6695
+        SERIAL_ECHOLNPGM(">>> gcode_T");
6696
+        DEBUG_POS("BEFORE", current_position);
6697
+      }
6698
+    #endif
6583
 
6699
 
6584
-    if (tmp_extruder != active_extruder) {
6585
-      bool no_move = code_seen('S') && code_value_bool();
6586
-      if (!no_move && axis_unhomed_error(true, true, true)) {
6587
-        SERIAL_ECHOLNPGM("No move on toolchange");
6588
-        no_move = true;
6700
+    #if HOTENDS > 1
6701
+
6702
+      if (tmp_extruder >= EXTRUDERS) {
6703
+        invalid_extruder_error(tmp_extruder);
6704
+        return;
6589
       }
6705
       }
6590
 
6706
 
6591
-      // Save current position to destination, for use later
6592
-      set_destination_to_current();
6707
+      float old_feedrate = feedrate;
6593
 
6708
 
6594
-      #if ENABLED(DUAL_X_CARRIAGE)
6709
+      if (code_seen('F')) {
6710
+        float next_feedrate = code_value_axis_units(X_AXIS);
6711
+        if (next_feedrate > 0.0) old_feedrate = feedrate = next_feedrate;
6712
+      }
6713
+      else
6714
+        feedrate = XY_PROBE_FEEDRATE;
6595
 
6715
 
6596
-        #if ENABLED(DEBUG_LEVELING_FEATURE)
6597
-          if (DEBUGGING(LEVELING)) {
6598
-            SERIAL_ECHOPGM("Dual X Carriage Mode ");
6599
-            switch (dual_x_carriage_mode) {
6600
-              case DXC_DUPLICATION_MODE: SERIAL_ECHOLNPGM("DXC_DUPLICATION_MODE"); break;
6601
-              case DXC_AUTO_PARK_MODE: SERIAL_ECHOLNPGM("DXC_AUTO_PARK_MODE"); break;
6602
-              case DXC_FULL_CONTROL_MODE: SERIAL_ECHOLNPGM("DXC_FULL_CONTROL_MODE"); break;
6603
-            }
6604
-          }
6605
-        #endif
6716
+      if (tmp_extruder != active_extruder) {
6717
+        bool no_move = code_seen('S') && code_value_bool();
6718
+
6719
+        if (!no_move && axis_unhomed_error(true, true, true)) {
6720
+          SERIAL_ECHOLNPGM("No move on toolchange");
6721
+          no_move = true;
6722
+        }
6723
+
6724
+        // Save current position to destination, for use later
6725
+        set_destination_to_current();
6726
+
6727
+        #if ENABLED(DUAL_X_CARRIAGE)
6606
 
6728
 
6607
-        if (dual_x_carriage_mode == DXC_AUTO_PARK_MODE && IsRunning()
6608
-             && (delayed_move_time || current_position[X_AXIS] != x_home_pos(active_extruder))
6609
-           ) {
6610
           #if ENABLED(DEBUG_LEVELING_FEATURE)
6729
           #if ENABLED(DEBUG_LEVELING_FEATURE)
6611
             if (DEBUGGING(LEVELING)) {
6730
             if (DEBUGGING(LEVELING)) {
6612
-              SERIAL_ECHOPAIR("Raise to ", current_position[Z_AXIS] + TOOLCHANGE_PARK_ZLIFT); SERIAL_EOL;
6613
-              SERIAL_ECHOPAIR("MoveX to ", x_home_pos(active_extruder)); SERIAL_EOL;
6614
-              SERIAL_ECHOPAIR("Lower to ", current_position[Z_AXIS]); SERIAL_EOL;
6731
+              SERIAL_ECHOPGM("Dual X Carriage Mode ");
6732
+              switch (dual_x_carriage_mode) {
6733
+                case DXC_DUPLICATION_MODE: SERIAL_ECHOLNPGM("DXC_DUPLICATION_MODE"); break;
6734
+                case DXC_AUTO_PARK_MODE: SERIAL_ECHOLNPGM("DXC_AUTO_PARK_MODE"); break;
6735
+                case DXC_FULL_CONTROL_MODE: SERIAL_ECHOLNPGM("DXC_FULL_CONTROL_MODE"); break;
6736
+              }
6615
             }
6737
             }
6616
           #endif
6738
           #endif
6617
-          // Park old head: 1) raise 2) move to park position 3) lower
6618
-          planner.buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS] + TOOLCHANGE_PARK_ZLIFT,
6619
-                           current_position[E_AXIS], planner.max_feedrate[Z_AXIS], active_extruder);
6620
-          planner.buffer_line(x_home_pos(active_extruder), current_position[Y_AXIS], current_position[Z_AXIS] + TOOLCHANGE_PARK_ZLIFT,
6621
-                           current_position[E_AXIS], planner.max_feedrate[X_AXIS], active_extruder);
6622
-          planner.buffer_line(x_home_pos(active_extruder), current_position[Y_AXIS], current_position[Z_AXIS],
6623
-                           current_position[E_AXIS], planner.max_feedrate[Z_AXIS], active_extruder);
6624
-          stepper.synchronize();
6625
-        }
6626
 
6739
 
6627
-        // apply Y & Z extruder offset (x offset is already used in determining home pos)
6628
-        current_position[Y_AXIS] -= hotend_offset[Y_AXIS][active_extruder] - hotend_offset[Y_AXIS][tmp_extruder];
6629
-        current_position[Z_AXIS] -= hotend_offset[Z_AXIS][active_extruder] - hotend_offset[Z_AXIS][tmp_extruder];
6630
-        active_extruder = tmp_extruder;
6740
+          if (dual_x_carriage_mode == DXC_AUTO_PARK_MODE && IsRunning() &&
6741
+              (delayed_move_time || current_position[X_AXIS] != x_home_pos(active_extruder))
6742
+          ) {
6743
+            #if ENABLED(DEBUG_LEVELING_FEATURE)
6744
+              if (DEBUGGING(LEVELING)) {
6745
+                SERIAL_ECHOPAIR("Raise to ", current_position[Z_AXIS] + TOOLCHANGE_PARK_ZLIFT); SERIAL_EOL;
6746
+                SERIAL_ECHOPAIR("MoveX to ", x_home_pos(active_extruder)); SERIAL_EOL;
6747
+                SERIAL_ECHOPAIR("Lower to ", current_position[Z_AXIS]); SERIAL_EOL;
6748
+              }
6749
+            #endif
6750
+            // Park old head: 1) raise 2) move to park position 3) lower
6751
+            for (uint8_t i = 0; i < 3; i++)
6752
+              planner.buffer_line(
6753
+                i == 0 ? current_position[X_AXIS] : x_home_pos(active_extruder),
6754
+                current_position[Y_AXIS],
6755
+                current_position[Z_AXIS] + (i == 2 ? 0 : TOOLCHANGE_PARK_ZLIFT),
6756
+                current_position[E_AXIS],
6757
+                planner.max_feedrate[i == 1 ? X_AXIS : Z_AXIS],
6758
+                active_extruder
6759
+              );
6760
+            stepper.synchronize();
6761
+          }
6631
 
6762
 
6632
-        // This function resets the max/min values - the current position may be overwritten below.
6633
-        set_axis_is_at_home(X_AXIS);
6763
+          // apply Y & Z extruder offset (x offset is already used in determining home pos)
6764
+          current_position[Y_AXIS] -= hotend_offset[Y_AXIS][active_extruder] - hotend_offset[Y_AXIS][tmp_extruder];
6765
+          current_position[Z_AXIS] -= hotend_offset[Z_AXIS][active_extruder] - hotend_offset[Z_AXIS][tmp_extruder];
6766
+          active_extruder = tmp_extruder;
6634
 
6767
 
6635
-        #if ENABLED(DEBUG_LEVELING_FEATURE)
6636
-          if (DEBUGGING(LEVELING)) DEBUG_POS("New Extruder", current_position);
6637
-        #endif
6768
+          // This function resets the max/min values - the current position may be overwritten below.
6769
+          set_axis_is_at_home(X_AXIS);
6638
 
6770
 
6639
-        switch (dual_x_carriage_mode) {
6640
-          case DXC_FULL_CONTROL_MODE:
6641
-            current_position[X_AXIS] = inactive_extruder_x_pos;
6642
-            inactive_extruder_x_pos = destination[X_AXIS];
6643
-            break;
6644
-          case DXC_DUPLICATION_MODE:
6645
-            active_extruder_parked = (active_extruder == 0); // this triggers the second extruder to move into the duplication position
6646
-            if (active_extruder_parked)
6647
-              current_position[X_AXIS] = inactive_extruder_x_pos;
6648
-            else
6649
-              current_position[X_AXIS] = destination[X_AXIS] + duplicate_extruder_x_offset;
6650
-            inactive_extruder_x_pos = destination[X_AXIS];
6651
-            extruder_duplication_enabled = false;
6652
-            break;
6653
-          default:
6654
-            // record raised toolhead position for use by unpark
6655
-            memcpy(raised_parked_position, current_position, sizeof(raised_parked_position));
6656
-            raised_parked_position[Z_AXIS] += TOOLCHANGE_UNPARK_ZLIFT;
6657
-            active_extruder_parked = true;
6658
-            delayed_move_time = 0;
6659
-            break;
6660
-        }
6771
+          #if ENABLED(DEBUG_LEVELING_FEATURE)
6772
+            if (DEBUGGING(LEVELING)) DEBUG_POS("New Extruder", current_position);
6773
+          #endif
6661
 
6774
 
6662
-        #if ENABLED(DEBUG_LEVELING_FEATURE)
6663
-          if (DEBUGGING(LEVELING)) {
6664
-            SERIAL_ECHOPAIR("Active extruder parked: ", active_extruder_parked ? "yes" : "no");
6665
-            SERIAL_EOL;
6666
-            DEBUG_POS("New extruder (parked)", current_position);
6775
+          switch (dual_x_carriage_mode) {
6776
+            case DXC_FULL_CONTROL_MODE:
6777
+              current_position[X_AXIS] = inactive_extruder_x_pos;
6778
+              inactive_extruder_x_pos = destination[X_AXIS];
6779
+              break;
6780
+            case DXC_DUPLICATION_MODE:
6781
+              active_extruder_parked = (active_extruder == 0); // this triggers the second extruder to move into the duplication position
6782
+              if (active_extruder_parked)
6783
+                current_position[X_AXIS] = inactive_extruder_x_pos;
6784
+              else
6785
+                current_position[X_AXIS] = destination[X_AXIS] + duplicate_extruder_x_offset;
6786
+              inactive_extruder_x_pos = destination[X_AXIS];
6787
+              extruder_duplication_enabled = false;
6788
+              break;
6789
+            default:
6790
+              // record raised toolhead position for use by unpark
6791
+              memcpy(raised_parked_position, current_position, sizeof(raised_parked_position));
6792
+              raised_parked_position[Z_AXIS] += TOOLCHANGE_UNPARK_ZLIFT;
6793
+              active_extruder_parked = true;
6794
+              delayed_move_time = 0;
6795
+              break;
6667
           }
6796
           }
6668
-        #endif
6669
-
6670
-       // No extra case for AUTO_BED_LEVELING_FEATURE in DUAL_X_CARRIAGE. Does that mean they don't work together?
6671
-      #else // !DUAL_X_CARRIAGE
6672
-
6673
-        /**
6674
-         * Set current_position to the position of the new nozzle.
6675
-         * Offsets are based on linear distance, so we need to get
6676
-         * the resulting position in coordinate space.
6677
-         *
6678
-         * - With grid or 3-point leveling, offset XYZ by a tilted vector
6679
-         * - With mesh leveling, update Z for the new position
6680
-         * - Otherwise, just use the raw linear distance
6681
-         *
6682
-         * Software endstops are altered here too. Consider a case where:
6683
-         *   E0 at X=0 ... E1 at X=10
6684
-         * When we switch to E1 now X=10, but E1 can't move left.
6685
-         * To express this we apply the change in XY to the software endstops.
6686
-         * E1 can move farther right than E0, so the right limit is extended.
6687
-         *
6688
-         * Note that we don't adjust the Z software endstops. Why not?
6689
-         * Consider a case where Z=0 (here) and switching to E1 makes Z=1
6690
-         * because the bed is 1mm lower at the new position. As long as
6691
-         * the first nozzle is out of the way, the carriage should be
6692
-         * allowed to move 1mm lower. This technically "breaks" the
6693
-         * Z software endstop. But this is technically correct (and
6694
-         * there is no viable alternative).
6695
-         */
6696
-        #if ENABLED(AUTO_BED_LEVELING_FEATURE)
6697
-          // Offset extruder, make sure to apply the bed level rotation matrix
6698
-          vector_3 tmp_offset_vec = vector_3(hotend_offset[X_AXIS][tmp_extruder],
6699
-                                             hotend_offset[Y_AXIS][tmp_extruder],
6700
-                                             0),
6701
-                   act_offset_vec = vector_3(hotend_offset[X_AXIS][active_extruder],
6702
-                                             hotend_offset[Y_AXIS][active_extruder],
6703
-                                             0),
6704
-                   offset_vec = tmp_offset_vec - act_offset_vec;
6705
 
6797
 
6706
           #if ENABLED(DEBUG_LEVELING_FEATURE)
6798
           #if ENABLED(DEBUG_LEVELING_FEATURE)
6707
             if (DEBUGGING(LEVELING)) {
6799
             if (DEBUGGING(LEVELING)) {
6708
-              tmp_offset_vec.debug("tmp_offset_vec");
6709
-              act_offset_vec.debug("act_offset_vec");
6710
-              offset_vec.debug("offset_vec (BEFORE)");
6800
+              SERIAL_ECHOPAIR("Active extruder parked: ", active_extruder_parked ? "yes" : "no");
6801
+              SERIAL_EOL;
6802
+              DEBUG_POS("New extruder (parked)", current_position);
6711
             }
6803
             }
6712
           #endif
6804
           #endif
6713
 
6805
 
6714
-          offset_vec.apply_rotation(planner.bed_level_matrix.transpose(planner.bed_level_matrix));
6715
-
6716
-          #if ENABLED(DEBUG_LEVELING_FEATURE)
6717
-            if (DEBUGGING(LEVELING)) offset_vec.debug("offset_vec (AFTER)");
6806
+          // No extra case for AUTO_BED_LEVELING_FEATURE in DUAL_X_CARRIAGE. Does that mean they don't work together?
6807
+        #else // !DUAL_X_CARRIAGE
6808
+
6809
+          #if ENABLED(SWITCHING_EXTRUDER)
6810
+            // <0 if the new nozzle is higher, >0 if lower. A bigger raise when lower.
6811
+            float z_diff = hotend_offset[Z_AXIS][active_extruder] - hotend_offset[Z_AXIS][tmp_extruder],
6812
+                  z_raise = 0.3 + (z_diff > 0.0 ? z_diff : 0.0);
6813
+          
6814
+            // Always raise by some amount
6815
+            planner.buffer_line(
6816
+              current_position[X_AXIS],
6817
+              current_position[Y_AXIS],
6818
+              current_position[Z_AXIS] + z_raise,
6819
+              current_position[E_AXIS],
6820
+              planner.max_feedrate[Z_AXIS],
6821
+              active_extruder
6822
+            );
6823
+            stepper.synchronize();
6824
+          
6825
+            move_extruder_servo(active_extruder);
6826
+            delay(500);
6827
+          
6828
+            // Move back down, if needed
6829
+            if (z_raise != z_diff) {
6830
+              planner.buffer_line(
6831
+                current_position[X_AXIS],
6832
+                current_position[Y_AXIS],
6833
+                current_position[Z_AXIS] + z_diff,
6834
+                current_position[E_AXIS],
6835
+                planner.max_feedrate[Z_AXIS],
6836
+                active_extruder
6837
+              );
6838
+              stepper.synchronize();
6839
+            }
6718
           #endif
6840
           #endif
6841
+          
6842
+          /**
6843
+           * Set current_position to the position of the new nozzle.
6844
+           * Offsets are based on linear distance, so we need to get
6845
+           * the resulting position in coordinate space.
6846
+           *
6847
+           * - With grid or 3-point leveling, offset XYZ by a tilted vector
6848
+           * - With mesh leveling, update Z for the new position
6849
+           * - Otherwise, just use the raw linear distance
6850
+           *
6851
+           * Software endstops are altered here too. Consider a case where:
6852
+           *   E0 at X=0 ... E1 at X=10
6853
+           * When we switch to E1 now X=10, but E1 can't move left.
6854
+           * To express this we apply the change in XY to the software endstops.
6855
+           * E1 can move farther right than E0, so the right limit is extended.
6856
+           *
6857
+           * Note that we don't adjust the Z software endstops. Why not?
6858
+           * Consider a case where Z=0 (here) and switching to E1 makes Z=1
6859
+           * because the bed is 1mm lower at the new position. As long as
6860
+           * the first nozzle is out of the way, the carriage should be
6861
+           * allowed to move 1mm lower. This technically "breaks" the
6862
+           * Z software endstop. But this is technically correct (and
6863
+           * there is no viable alternative).
6864
+           */
6865
+          #if ENABLED(AUTO_BED_LEVELING_FEATURE)
6866
+            // Offset extruder, make sure to apply the bed level rotation matrix
6867
+            vector_3 tmp_offset_vec = vector_3(hotend_offset[X_AXIS][tmp_extruder],
6868
+                                               hotend_offset[Y_AXIS][tmp_extruder],
6869
+                                               0),
6870
+                     act_offset_vec = vector_3(hotend_offset[X_AXIS][active_extruder],
6871
+                                               hotend_offset[Y_AXIS][active_extruder],
6872
+                                               0),
6873
+                     offset_vec = tmp_offset_vec - act_offset_vec;
6719
 
6874
 
6720
-          // Adjustments to the current position
6721
-          float xydiff[2] = { offset_vec.x, offset_vec.y };
6722
-          current_position[Z_AXIS] += offset_vec.z;
6875
+            #if ENABLED(DEBUG_LEVELING_FEATURE)
6876
+              if (DEBUGGING(LEVELING)) {
6877
+                tmp_offset_vec.debug("tmp_offset_vec");
6878
+                act_offset_vec.debug("act_offset_vec");
6879
+                offset_vec.debug("offset_vec (BEFORE)");
6880
+              }
6881
+            #endif
6723
 
6882
 
6724
-        #else // !AUTO_BED_LEVELING_FEATURE
6883
+            offset_vec.apply_rotation(planner.bed_level_matrix.transpose(planner.bed_level_matrix));
6725
 
6884
 
6726
-          float xydiff[2] = {
6727
-            hotend_offset[X_AXIS][tmp_extruder] - hotend_offset[X_AXIS][active_extruder],
6728
-            hotend_offset[Y_AXIS][tmp_extruder] - hotend_offset[Y_AXIS][active_extruder]
6729
-          };
6885
+            #if ENABLED(DEBUG_LEVELING_FEATURE)
6886
+              if (DEBUGGING(LEVELING)) offset_vec.debug("offset_vec (AFTER)");
6887
+            #endif
6730
 
6888
 
6731
-          #if ENABLED(MESH_BED_LEVELING)
6889
+            // Adjustments to the current position
6890
+            float xydiff[2] = { offset_vec.x, offset_vec.y };
6891
+            current_position[Z_AXIS] += offset_vec.z;
6732
 
6892
 
6733
-            if (mbl.active()) {
6734
-              #if ENABLED(DEBUG_LEVELING_FEATURE)
6735
-                if (DEBUGGING(LEVELING)) SERIAL_ECHOPAIR("Z before MBL: ", current_position[Z_AXIS]);
6736
-              #endif
6737
-              float xpos = RAW_CURRENT_POSITION(X_AXIS),
6738
-                    ypos = RAW_CURRENT_POSITION(Y_AXIS);
6739
-              current_position[Z_AXIS] += mbl.get_z(xpos + xydiff[X_AXIS], ypos + xydiff[Y_AXIS]) - mbl.get_z(xpos, ypos);
6740
-              #if ENABLED(DEBUG_LEVELING_FEATURE)
6741
-                if (DEBUGGING(LEVELING)) {
6742
-                  SERIAL_ECHOPAIR(" after: ", current_position[Z_AXIS]);
6743
-                  SERIAL_EOL;
6744
-                }
6745
-              #endif
6746
-            }
6893
+          #else // !AUTO_BED_LEVELING_FEATURE
6894
+  
6895
+            float xydiff[2] = {
6896
+              hotend_offset[X_AXIS][tmp_extruder] - hotend_offset[X_AXIS][active_extruder],
6897
+              hotend_offset[Y_AXIS][tmp_extruder] - hotend_offset[Y_AXIS][active_extruder]
6898
+            };
6747
 
6899
 
6748
-          #endif // MESH_BED_LEVELING
6900
+            #if ENABLED(MESH_BED_LEVELING)
6749
 
6901
 
6750
-        #endif // !AUTO_BED_LEVELING_FEATURE
6902
+              if (mbl.active()) {
6903
+                #if ENABLED(DEBUG_LEVELING_FEATURE)
6904
+                  if (DEBUGGING(LEVELING)) SERIAL_ECHOPAIR("Z before MBL: ", current_position[Z_AXIS]);
6905
+                #endif
6906
+                float xpos = RAW_CURRENT_POSITION(X_AXIS),
6907
+                      ypos = RAW_CURRENT_POSITION(Y_AXIS);
6908
+                current_position[Z_AXIS] += mbl.get_z(xpos + xydiff[X_AXIS], ypos + xydiff[Y_AXIS]) - mbl.get_z(xpos, ypos);
6909
+                #if ENABLED(DEBUG_LEVELING_FEATURE)
6910
+                  if (DEBUGGING(LEVELING)) {
6911
+                    SERIAL_ECHOPAIR(" after: ", current_position[Z_AXIS]);
6912
+                    SERIAL_EOL;
6913
+                  }
6914
+                #endif
6915
+              }
6751
 
6916
 
6752
-        #if ENABLED(DEBUG_LEVELING_FEATURE)
6753
-          if (DEBUGGING(LEVELING)) {
6754
-            SERIAL_ECHOPAIR("Offset Tool XY by { ", xydiff[X_AXIS]);
6755
-            SERIAL_ECHOPAIR(", ", xydiff[X_AXIS]);
6756
-            SERIAL_ECHOLNPGM(" }");
6757
-          }
6758
-        #endif
6917
+            #endif // MESH_BED_LEVELING
6918
+  
6919
+          #endif // !AUTO_BED_LEVELING_FEATURE
6759
 
6920
 
6760
-        // The newly-selected extruder XY is actually at...
6761
-        current_position[X_AXIS] += xydiff[X_AXIS];
6762
-        current_position[Y_AXIS] += xydiff[Y_AXIS];
6763
-        for (uint8_t i = X_AXIS; i <= Y_AXIS; i++) {
6764
-          position_shift[i] += xydiff[i];
6765
-          update_software_endstops((AxisEnum)i);
6766
-        }
6921
+          #if ENABLED(DEBUG_LEVELING_FEATURE)
6922
+            if (DEBUGGING(LEVELING)) {
6923
+              SERIAL_ECHOPAIR("Offset Tool XY by { ", xydiff[X_AXIS]);
6924
+              SERIAL_ECHOPAIR(", ", xydiff[X_AXIS]);
6925
+              SERIAL_ECHOLNPGM(" }");
6926
+            }
6927
+          #endif
6767
 
6928
 
6768
-        // Set the new active extruder
6769
-        active_extruder = tmp_extruder;
6929
+          // The newly-selected extruder XY is actually at...
6930
+          current_position[X_AXIS] += xydiff[X_AXIS];
6931
+          current_position[Y_AXIS] += xydiff[Y_AXIS];
6932
+          for (uint8_t i = X_AXIS; i <= Y_AXIS; i++) {
6933
+            position_shift[i] += xydiff[i];
6934
+            update_software_endstops((AxisEnum)i);
6935
+          }
6770
 
6936
 
6771
-      #endif // !DUAL_X_CARRIAGE
6937
+          // Set the new active extruder
6938
+          active_extruder = tmp_extruder;
6772
 
6939
 
6773
-      #if ENABLED(DEBUG_LEVELING_FEATURE)
6774
-        if (DEBUGGING(LEVELING)) DEBUG_POS("Sync After Toolchange", current_position);
6775
-      #endif
6776
-
6777
-      // Tell the planner the new "current position"
6778
-      SYNC_PLAN_POSITION_KINEMATIC();
6940
+        #endif // !DUAL_X_CARRIAGE
6779
 
6941
 
6780
-      // Move to the "old position" (move the extruder into place)
6781
-      if (!no_move && IsRunning()) {
6782
         #if ENABLED(DEBUG_LEVELING_FEATURE)
6942
         #if ENABLED(DEBUG_LEVELING_FEATURE)
6783
-          if (DEBUGGING(LEVELING)) DEBUG_POS("Move back", destination);
6943
+          if (DEBUGGING(LEVELING)) DEBUG_POS("Sync After Toolchange", current_position);
6784
         #endif
6944
         #endif
6785
-        prepare_move_to_destination();
6786
-      }
6787
 
6945
 
6788
-    } // (tmp_extruder != active_extruder)
6946
+        // Tell the planner the new "current position"
6947
+        SYNC_PLAN_POSITION_KINEMATIC();
6789
 
6948
 
6790
-    stepper.synchronize();
6949
+        // Move to the "old position" (move the extruder into place)
6950
+        if (!no_move && IsRunning()) {
6951
+          #if ENABLED(DEBUG_LEVELING_FEATURE)
6952
+            if (DEBUGGING(LEVELING)) DEBUG_POS("Move back", destination);
6953
+          #endif
6954
+          prepare_move_to_destination();
6955
+        }
6791
 
6956
 
6792
-    #if ENABLED(EXT_SOLENOID)
6793
-      disable_all_solenoids();
6794
-      enable_solenoid_on_active_extruder();
6795
-    #endif // EXT_SOLENOID
6957
+      } // (tmp_extruder != active_extruder)
6796
 
6958
 
6797
-    feedrate = old_feedrate;
6959
+      stepper.synchronize();
6798
 
6960
 
6799
-  #else // !HOTENDS > 1
6961
+      #if ENABLED(EXT_SOLENOID)
6962
+        disable_all_solenoids();
6963
+        enable_solenoid_on_active_extruder();
6964
+      #endif // EXT_SOLENOID
6800
 
6965
 
6801
-    // Set the new active extruder
6802
-    active_extruder = tmp_extruder;
6966
+      feedrate = old_feedrate;
6803
 
6967
 
6804
-  #endif
6968
+    #else // HOTENDS <= 1
6805
 
6969
 
6806
-  #if ENABLED(DEBUG_LEVELING_FEATURE)
6807
-    if (DEBUGGING(LEVELING)) {
6808
-      DEBUG_POS("AFTER", current_position);
6809
-      SERIAL_ECHOLNPGM("<<< gcode_T");
6810
-    }
6811
-  #endif
6970
+      // Set the new active extruder
6971
+      active_extruder = tmp_extruder;
6812
 
6972
 
6813
-  SERIAL_ECHO_START;
6814
-  SERIAL_ECHOPGM(MSG_ACTIVE_EXTRUDER);
6815
-  SERIAL_PROTOCOLLN((int)active_extruder);
6973
+    #endif // HOTENDS <= 1
6974
+
6975
+    #if ENABLED(DEBUG_LEVELING_FEATURE)
6976
+      if (DEBUGGING(LEVELING)) {
6977
+        DEBUG_POS("AFTER", current_position);
6978
+        SERIAL_ECHOLNPGM("<<< gcode_T");
6979
+      }
6980
+    #endif
6981
+  
6982
+    SERIAL_ECHO_START;
6983
+    SERIAL_ECHOPGM(MSG_ACTIVE_EXTRUDER);
6984
+    SERIAL_PROTOCOLLN((int)active_extruder);
6985
+
6986
+  #endif //!MIXING_EXTRUDER || MIXING_VIRTUAL_TOOLS <= 1
6816
 }
6987
 }
6817
 
6988
 
6818
 /**
6989
 /**
7219
 
7390
 
7220
       #endif //EXPERIMENTAL_I2CBUS
7391
       #endif //EXPERIMENTAL_I2CBUS
7221
 
7392
 
7393
+      #if ENABLED(MIXING_EXTRUDER)
7394
+        case 163: // M163 S<int> P<float> set weight for a mixing extruder
7395
+          gcode_M163();
7396
+          break;
7397
+        #if MIXING_VIRTUAL_TOOLS > 1
7398
+          case 164: // M164 S<int> save current mix as a virtual extruder
7399
+            gcode_M164();
7400
+            break;
7401
+        #endif
7402
+        #if ENABLED(DIRECT_MIXING_IN_G1)
7403
+          case 165: // M165 [ABCDHI]<float> set multiple mix weights
7404
+            gcode_M165();
7405
+            break;
7406
+        #endif
7407
+      #endif
7408
+
7222
       case 200: // M200 D<diameter> Set filament diameter and set E axis units to cubic. (Use S0 to revert to linear units.)
7409
       case 200: // M200 D<diameter> Set filament diameter and set E axis units to cubic. (Use S0 to revert to linear units.)
7223
         gcode_M200();
7410
         gcode_M200();
7224
         break;
7411
         break;
8033
       nextMotorCheck = ms + 2500UL; // Not a time critical function, so only check every 2.5s
8220
       nextMotorCheck = ms + 2500UL; // Not a time critical function, so only check every 2.5s
8034
       if (X_ENABLE_READ == X_ENABLE_ON || Y_ENABLE_READ == Y_ENABLE_ON || Z_ENABLE_READ == Z_ENABLE_ON || thermalManager.soft_pwm_bed > 0
8221
       if (X_ENABLE_READ == X_ENABLE_ON || Y_ENABLE_READ == Y_ENABLE_ON || Z_ENABLE_READ == Z_ENABLE_ON || thermalManager.soft_pwm_bed > 0
8035
           || E0_ENABLE_READ == E_ENABLE_ON // If any of the drivers are enabled...
8222
           || E0_ENABLE_READ == E_ENABLE_ON // If any of the drivers are enabled...
8036
-          #if EXTRUDERS > 1
8223
+          #if E_STEPPERS > 1
8037
             || E1_ENABLE_READ == E_ENABLE_ON
8224
             || E1_ENABLE_READ == E_ENABLE_ON
8038
             #if HAS_X2_ENABLE
8225
             #if HAS_X2_ENABLE
8039
               || X2_ENABLE_READ == X_ENABLE_ON
8226
               || X2_ENABLE_READ == X_ENABLE_ON
8040
             #endif
8227
             #endif
8041
-            #if EXTRUDERS > 2
8228
+            #if E_STEPPERS > 2
8042
               || E2_ENABLE_READ == E_ENABLE_ON
8229
               || E2_ENABLE_READ == E_ENABLE_ON
8043
-              #if EXTRUDERS > 3
8230
+              #if E_STEPPERS > 3
8044
                 || E3_ENABLE_READ == E_ENABLE_ON
8231
                 || E3_ENABLE_READ == E_ENABLE_ON
8045
               #endif
8232
               #endif
8046
             #endif
8233
             #endif
8303
   #endif
8490
   #endif
8304
 
8491
 
8305
   #if ENABLED(EXTRUDER_RUNOUT_PREVENT)
8492
   #if ENABLED(EXTRUDER_RUNOUT_PREVENT)
8306
-    if (ELAPSED(ms, previous_cmd_ms + (EXTRUDER_RUNOUT_SECONDS) * 1000UL))
8307
-      if (thermalManager.degHotend(active_extruder) > EXTRUDER_RUNOUT_MINTEMP) {
8493
+    if (ELAPSED(ms, previous_cmd_ms + (EXTRUDER_RUNOUT_SECONDS) * 1000UL)
8494
+      && thermalManager.degHotend(active_extruder) > EXTRUDER_RUNOUT_MINTEMP) {
8495
+      #if ENABLED(SWITCHING_EXTRUDER)
8496
+        bool oldstatus = E0_ENABLE_READ;
8497
+        enable_e0();
8498
+      #else // !SWITCHING_EXTRUDER
8308
         bool oldstatus;
8499
         bool oldstatus;
8309
         switch (active_extruder) {
8500
         switch (active_extruder) {
8310
           case 0:
8501
           case 0:
8311
             oldstatus = E0_ENABLE_READ;
8502
             oldstatus = E0_ENABLE_READ;
8312
             enable_e0();
8503
             enable_e0();
8313
             break;
8504
             break;
8314
-          #if EXTRUDERS > 1
8505
+          #if E_STEPPERS > 1
8315
             case 1:
8506
             case 1:
8316
               oldstatus = E1_ENABLE_READ;
8507
               oldstatus = E1_ENABLE_READ;
8317
               enable_e1();
8508
               enable_e1();
8318
               break;
8509
               break;
8319
-            #if EXTRUDERS > 2
8510
+            #if E_STEPPERS > 2
8320
               case 2:
8511
               case 2:
8321
                 oldstatus = E2_ENABLE_READ;
8512
                 oldstatus = E2_ENABLE_READ;
8322
                 enable_e2();
8513
                 enable_e2();
8323
                 break;
8514
                 break;
8324
-              #if EXTRUDERS > 3
8515
+              #if E_STEPPERS > 3
8325
                 case 3:
8516
                 case 3:
8326
                   oldstatus = E3_ENABLE_READ;
8517
                   oldstatus = E3_ENABLE_READ;
8327
                   enable_e3();
8518
                   enable_e3();
8330
             #endif
8521
             #endif
8331
           #endif
8522
           #endif
8332
         }
8523
         }
8333
-        float oldepos = current_position[E_AXIS], oldedes = destination[E_AXIS];
8334
-        planner.buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS],
8335
-                         destination[E_AXIS] + (EXTRUDER_RUNOUT_EXTRUDE) * (EXTRUDER_RUNOUT_ESTEPS) / planner.axis_steps_per_mm[E_AXIS],
8336
-                         (EXTRUDER_RUNOUT_SPEED) / 60. * (EXTRUDER_RUNOUT_ESTEPS) / planner.axis_steps_per_mm[E_AXIS], active_extruder);
8524
+      #endif // !SWITCHING_EXTRUDER
8525
+
8526
+      float oldepos = current_position[E_AXIS], oldedes = destination[E_AXIS];
8527
+      planner.buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS],
8528
+                       destination[E_AXIS] + (EXTRUDER_RUNOUT_EXTRUDE) * (EXTRUDER_RUNOUT_ESTEPS) / planner.axis_steps_per_mm[E_AXIS],
8529
+                       (EXTRUDER_RUNOUT_SPEED) / 60. * (EXTRUDER_RUNOUT_ESTEPS) / planner.axis_steps_per_mm[E_AXIS], active_extruder);
8337
       current_position[E_AXIS] = oldepos;
8530
       current_position[E_AXIS] = oldepos;
8338
       destination[E_AXIS] = oldedes;
8531
       destination[E_AXIS] = oldedes;
8339
       planner.set_e_position_mm(oldepos);
8532
       planner.set_e_position_mm(oldepos);
8340
       previous_cmd_ms = ms; // refresh_cmd_timeout()
8533
       previous_cmd_ms = ms; // refresh_cmd_timeout()
8341
       stepper.synchronize();
8534
       stepper.synchronize();
8342
-      switch (active_extruder) {
8343
-        case 0:
8344
-          E0_ENABLE_WRITE(oldstatus);
8345
-          break;
8346
-        #if EXTRUDERS > 1
8347
-          case 1:
8348
-            E1_ENABLE_WRITE(oldstatus);
8535
+      #if ENABLED(SWITCHING_EXTRUDER)
8536
+        E0_ENABLE_WRITE(oldstatus);
8537
+      #else
8538
+        switch (active_extruder) {
8539
+          case 0:
8540
+            E0_ENABLE_WRITE(oldstatus);
8349
             break;
8541
             break;
8350
-          #if EXTRUDERS > 2
8351
-            case 2:
8352
-              E2_ENABLE_WRITE(oldstatus);
8542
+          #if E_STEPPERS > 1
8543
+            case 1:
8544
+              E1_ENABLE_WRITE(oldstatus);
8353
               break;
8545
               break;
8354
-            #if EXTRUDERS > 3
8355
-              case 3:
8356
-                E3_ENABLE_WRITE(oldstatus);
8546
+            #if E_STEPPERS > 2
8547
+              case 2:
8548
+                E2_ENABLE_WRITE(oldstatus);
8357
                 break;
8549
                 break;
8550
+              #if E_STEPPERS > 3
8551
+                case 3:
8552
+                  E3_ENABLE_WRITE(oldstatus);
8553
+                  break;
8554
+              #endif
8358
             #endif
8555
             #endif
8359
           #endif
8556
           #endif
8360
-        #endif
8361
-      }
8557
+        }
8558
+      #endif // !SWITCHING_EXTRUDER
8362
     }
8559
     }
8363
-  #endif
8560
+  #endif // EXTRUDER_RUNOUT_PREVENT
8364
 
8561
 
8365
   #if ENABLED(DUAL_X_CARRIAGE)
8562
   #if ENABLED(DUAL_X_CARRIAGE)
8366
     // handle delayed move timeout
8563
     // handle delayed move timeout
8498
 }
8695
 }
8499
 
8696
 
8500
 void calculate_volumetric_multipliers() {
8697
 void calculate_volumetric_multipliers() {
8501
-  for (int i = 0; i < EXTRUDERS; i++)
8698
+  for (int i = 0; i < COUNT(filament_size); i++)
8502
     volumetric_multiplier[i] = calculate_volumetric_multiplier(filament_size[i]);
8699
     volumetric_multiplier[i] = calculate_volumetric_multiplier(filament_size[i]);
8503
 }
8700
 }

+ 2
- 2
Marlin/configuration_store.cpp View File

349
 
349
 
350
   // Save filament sizes
350
   // Save filament sizes
351
   for (uint8_t q = 0; q < MAX_EXTRUDERS; q++) {
351
   for (uint8_t q = 0; q < MAX_EXTRUDERS; q++) {
352
-    if (q < EXTRUDERS) dummy = filament_size[q];
352
+    if (q < COUNT(filament_size)) dummy = filament_size[q];
353
     EEPROM_WRITE_VAR(i, dummy);
353
     EEPROM_WRITE_VAR(i, dummy);
354
   }
354
   }
355
 
355
 
531
 
531
 
532
     for (uint8_t q = 0; q < MAX_EXTRUDERS; q++) {
532
     for (uint8_t q = 0; q < MAX_EXTRUDERS; q++) {
533
       EEPROM_READ_VAR(i, dummy);
533
       EEPROM_READ_VAR(i, dummy);
534
-      if (q < EXTRUDERS) filament_size[q] = dummy;
534
+      if (q < COUNT(filament_size)) filament_size[q] = dummy;
535
     }
535
     }
536
 
536
 
537
     if (eeprom_checksum == stored_checksum) {
537
     if (eeprom_checksum == stored_checksum) {

+ 3
- 0
Marlin/language_en.h View File

251
 #ifndef MSG_PID_C
251
 #ifndef MSG_PID_C
252
   #define MSG_PID_C                           "PID-C"
252
   #define MSG_PID_C                           "PID-C"
253
 #endif
253
 #endif
254
+#ifndef MSG_SELECT
255
+  #define MSG_SELECT                          "Select"
256
+#endif
254
 #ifndef MSG_E1
257
 #ifndef MSG_E1
255
   #define MSG_E1                              " E1"
258
   #define MSG_E1                              " E1"
256
 #endif
259
 #endif

+ 16
- 5
Marlin/pins.h View File

285
       #define _H3_PINS HEATER_3_PIN, EXTRUDER_3_AUTO_FAN_PIN, marlinAnalogInputToDigitalPin(TEMP_3_PIN),
285
       #define _H3_PINS HEATER_3_PIN, EXTRUDER_3_AUTO_FAN_PIN, marlinAnalogInputToDigitalPin(TEMP_3_PIN),
286
     #endif
286
     #endif
287
   #endif
287
   #endif
288
+#elif ENABLED(MIXING_EXTRUDER)
289
+  #undef _E1_PINS
290
+  #define _E1_PINS E1_STEP_PIN, E1_DIR_PIN, E1_ENABLE_PIN,
291
+  #if MIXING_STEPPERS > 2
292
+    #undef _E2_PINS
293
+    #define _E2_PINS E2_STEP_PIN, E2_DIR_PIN, E2_ENABLE_PIN,
294
+    #if MIXING_STEPPERS > 3
295
+      #undef _E3_PINS
296
+      #define _E3_PINS E3_STEP_PIN, E3_DIR_PIN, E3_ENABLE_PIN,
297
+    #endif
298
+  #endif
288
 #endif
299
 #endif
289
 
300
 
290
 #define BED_PINS HEATER_BED_PIN, marlinAnalogInputToDigitalPin(TEMP_BED_PIN),
301
 #define BED_PINS HEATER_BED_PIN, marlinAnalogInputToDigitalPin(TEMP_BED_PIN),
374
 // The X2 axis, if any, should be the next open extruder port
385
 // The X2 axis, if any, should be the next open extruder port
375
 #if ENABLED(DUAL_X_CARRIAGE) || ENABLED(X_DUAL_STEPPER_DRIVERS)
386
 #if ENABLED(DUAL_X_CARRIAGE) || ENABLED(X_DUAL_STEPPER_DRIVERS)
376
   #ifndef X2_STEP_PIN
387
   #ifndef X2_STEP_PIN
377
-    #define X2_STEP_PIN   _EPIN(EXTRUDERS, STEP)
378
-    #define X2_DIR_PIN    _EPIN(EXTRUDERS, DIR)
379
-    #define X2_ENABLE_PIN _EPIN(EXTRUDERS, ENABLE)
388
+    #define X2_STEP_PIN   _EPIN(E_STEPPERS, STEP)
389
+    #define X2_DIR_PIN    _EPIN(E_STEPPERS, DIR)
390
+    #define X2_ENABLE_PIN _EPIN(E_STEPPERS, ENABLE)
380
   #endif
391
   #endif
381
   #undef _X2_PINS
392
   #undef _X2_PINS
382
   #define _X2_PINS X2_STEP_PIN, X2_DIR_PIN, X2_ENABLE_PIN,
393
   #define _X2_PINS X2_STEP_PIN, X2_DIR_PIN, X2_ENABLE_PIN,
383
-  #define Y2_E_INDEX INCREMENT(EXTRUDERS)
394
+  #define Y2_E_INDEX INCREMENT(E_STEPPERS)
384
 #else
395
 #else
385
-  #define Y2_E_INDEX EXTRUDERS
396
+  #define Y2_E_INDEX E_STEPPERS
386
 #endif
397
 #endif
387
 
398
 
388
 // The Y2 axis, if any, should be the next open extruder port
399
 // The Y2 axis, if any, should be the next open extruder port

+ 2
- 2
Marlin/pins_MEGACONTROLLER.h View File

28
   #error "Oops!  Make sure you have 'Arduino Mega' selected from the 'Tools -> Boards' menu."
28
   #error "Oops!  Make sure you have 'Arduino Mega' selected from the 'Tools -> Boards' menu."
29
 #endif
29
 #endif
30
 
30
 
31
-#if EXTRUDERS > 2 || HOTENDS > 2
32
-  #error "Mega Controller supports up to 2 extruders. Comment this line to keep going."
31
+#if E_STEPPERS > 2 || HOTENDS > 2
32
+  #error "Mega Controller supports up to 2 hotends / E-steppers. Comment this line to keep going."
33
 #endif
33
 #endif
34
 
34
 
35
 #define BOARD_NAME "Mega Controller"
35
 #define BOARD_NAME "Mega Controller"

+ 2
- 2
Marlin/pins_RUMBA.h View File

28
   #error "Oops!  Make sure you have 'Arduino Mega' selected from the 'Tools -> Boards' menu."
28
   #error "Oops!  Make sure you have 'Arduino Mega' selected from the 'Tools -> Boards' menu."
29
 #endif
29
 #endif
30
 
30
 
31
-#if EXTRUDERS > 3 || HOTENDS > 3
32
-  #error "RUMBA supports up to 3 extruders. Comment this line to keep going."
31
+#if E_STEPPERS > 3 || HOTENDS > 3
32
+  #error "RUMBA supports up to 3 hotends / E-steppers. Comment this line to keep going."
33
 #endif
33
 #endif
34
 
34
 
35
 #define DEFAULT_MACHINE_NAME "Rumba"
35
 #define DEFAULT_MACHINE_NAME "Rumba"

+ 6
- 0
Marlin/planner.cpp View File

629
   // Bail if this is a zero-length block
629
   // Bail if this is a zero-length block
630
   if (block->step_event_count <= dropsegments) return;
630
   if (block->step_event_count <= dropsegments) return;
631
 
631
 
632
+  // For a mixing extruder, get a magnified step_event_count for each
633
+  #if ENABLED(MIXING_EXTRUDER)
634
+    for (uint8_t i = 0; i < MIXING_STEPPERS; i++)
635
+      block->mix_event_count[i] = (mixing_factor[i] < 0.0001) ? 0 : block->step_event_count / mixing_factor[i];
636
+  #endif
637
+
632
   #if FAN_COUNT > 0
638
   #if FAN_COUNT > 0
633
     for (uint8_t i = 0; i < FAN_COUNT; i++) block->fan_speed[i] = fanSpeeds[i];
639
     for (uint8_t i = 0; i < FAN_COUNT; i++) block->fan_speed[i] = fanSpeeds[i];
634
   #endif
640
   #endif

+ 4
- 0
Marlin/planner.h View File

58
   long steps[NUM_AXIS];                     // Step count along each axis
58
   long steps[NUM_AXIS];                     // Step count along each axis
59
   unsigned long step_event_count;           // The number of step events required to complete this block
59
   unsigned long step_event_count;           // The number of step events required to complete this block
60
 
60
 
61
+  #if ENABLED(MIXING_EXTRUDER)
62
+    unsigned long mix_event_count[MIXING_STEPPERS]; // Scaled step_event_count for the mixing steppers
63
+  #endif
64
+
61
   long accelerate_until,                    // The index of the step event on which to stop acceleration
65
   long accelerate_until,                    // The index of the step event on which to stop acceleration
62
        decelerate_after,                    // The index of the step event on which to start decelerating
66
        decelerate_after,                    // The index of the step event on which to start decelerating
63
        acceleration_rate;                   // The acceleration rate used for acceleration calculation
67
        acceleration_rate;                   // The acceleration rate used for acceleration calculation

+ 159
- 48
Marlin/stepper.cpp View File

95
   volatile unsigned char Stepper::eISR_Rate = 200; // Keep the ISR at a low rate until needed
95
   volatile unsigned char Stepper::eISR_Rate = 200; // Keep the ISR at a low rate until needed
96
 
96
 
97
   #if ENABLED(LIN_ADVANCE)
97
   #if ENABLED(LIN_ADVANCE)
98
-    volatile int Stepper::e_steps[EXTRUDERS];
98
+    volatile int Stepper::e_steps[E_STEPPERS];
99
     int Stepper::extruder_advance_k = LIN_ADVANCE_K,
99
     int Stepper::extruder_advance_k = LIN_ADVANCE_K,
100
         Stepper::final_estep_rate,
100
         Stepper::final_estep_rate,
101
-        Stepper::current_estep_rate[EXTRUDERS],
102
-        Stepper::current_adv_steps[EXTRUDERS];
101
+        Stepper::current_estep_rate[E_STEPPERS],
102
+        Stepper::current_adv_steps[E_STEPPERS];
103
   #else
103
   #else
104
-    long  Stepper::e_steps[EXTRUDERS],
104
+    long  Stepper::e_steps[E_STEPPERS],
105
           Stepper::final_advance = 0,
105
           Stepper::final_advance = 0,
106
           Stepper::old_advance = 0,
106
           Stepper::old_advance = 0,
107
           Stepper::advance_rate,
107
           Stepper::advance_rate,
114
 volatile long Stepper::count_position[NUM_AXIS] = { 0 };
114
 volatile long Stepper::count_position[NUM_AXIS] = { 0 };
115
 volatile signed char Stepper::count_direction[NUM_AXIS] = { 1, 1, 1, 1 };
115
 volatile signed char Stepper::count_direction[NUM_AXIS] = { 1, 1, 1, 1 };
116
 
116
 
117
+#if ENABLED(MIXING_EXTRUDER)
118
+  long Stepper::counter_M[MIXING_STEPPERS];
119
+#endif
120
+
117
 unsigned short Stepper::acc_step_rate; // needed for deceleration start point
121
 unsigned short Stepper::acc_step_rate; // needed for deceleration start point
118
 uint8_t Stepper::step_loops, Stepper::step_loops_nominal;
122
 uint8_t Stepper::step_loops, Stepper::step_loops_nominal;
119
 unsigned short Stepper::OCR1A_nominal;
123
 unsigned short Stepper::OCR1A_nominal;
179
   #define Z_APPLY_STEP(v,Q) Z_STEP_WRITE(v)
183
   #define Z_APPLY_STEP(v,Q) Z_STEP_WRITE(v)
180
 #endif
184
 #endif
181
 
185
 
182
-#define E_APPLY_STEP(v,Q) E_STEP_WRITE(v)
186
+#if DISABLED(MIXING_EXTRUDER)
187
+  #define E_APPLY_STEP(v,Q) E_STEP_WRITE(v)
188
+#endif
183
 
189
 
184
 // intRes = longIn1 * longIn2 >> 24
190
 // intRes = longIn1 * longIn2 >> 24
185
 // uses:
191
 // uses:
322
     if (current_block) {
328
     if (current_block) {
323
       current_block->busy = true;
329
       current_block->busy = true;
324
       trapezoid_generator_reset();
330
       trapezoid_generator_reset();
325
-      counter_X = -(current_block->step_event_count >> 1);
326
-      counter_Y = counter_Z = counter_E = counter_X;
331
+
332
+      // Initialize Bresenham counters to 1/2 the ceiling
333
+      counter_X = counter_Y = counter_Z = counter_E = -(current_block->step_event_count >> 1);
334
+
335
+      #if ENABLED(MIXING_EXTRUDER)
336
+        MIXING_STEPPERS_LOOP(i)
337
+          counter_M[i] = -(current_block->mix_event_count[i] >> 1);
338
+      #endif
339
+
327
       step_events_completed = 0;
340
       step_events_completed = 0;
328
 
341
 
329
       #if ENABLED(Z_LATE_ENABLE)
342
       #if ENABLED(Z_LATE_ENABLE)
335
       #endif
348
       #endif
336
 
349
 
337
       // #if ENABLED(ADVANCE)
350
       // #if ENABLED(ADVANCE)
338
-      //   e_steps[current_block->active_extruder] = 0;
351
+      //   e_steps[TOOL_E_INDEX] = 0;
339
       // #endif
352
       // #endif
340
     }
353
     }
341
     else {
354
     else {
343
     }
356
     }
344
   }
357
   }
345
 
358
 
346
-  if (current_block != NULL) {
359
+  if (current_block) {
347
 
360
 
348
     // Update endstops state, if enabled
361
     // Update endstops state, if enabled
349
     #if HAS_BED_PROBE
362
     #if HAS_BED_PROBE
363
         counter_E += current_block->steps[E_AXIS];
376
         counter_E += current_block->steps[E_AXIS];
364
         if (counter_E > 0) {
377
         if (counter_E > 0) {
365
           counter_E -= current_block->step_event_count;
378
           counter_E -= current_block->step_event_count;
366
-          count_position[E_AXIS] += count_direction[E_AXIS];
367
-          e_steps[current_block->active_extruder] += motor_direction(E_AXIS) ? -1 : 1;
379
+          #if DISABLED(MIXING_EXTRUDER)
380
+            // Don't step E here for mixing extruder
381
+            count_position[E_AXIS] += count_direction[E_AXIS];
382
+            e_steps[TOOL_E_INDEX] += motor_direction(E_AXIS) ? -1 : 1;
383
+          #endif
368
         }
384
         }
369
 
385
 
386
+        #if ENABLED(MIXING_EXTRUDER)
387
+          // Step mixing steppers proportionally
388
+          long dir = motor_direction(E_AXIS) ? -1 : 1;
389
+          MIXING_STEPPERS_LOOP(j) {
390
+            counter_m[j] += current_block->steps[E_AXIS];
391
+            if (counter_m[j] > 0) {
392
+              counter_m[j] -= current_block->mix_event_count[j];
393
+              e_steps[j] += dir;
394
+            }
395
+          }
396
+        #endif
397
+
370
         if (current_block->use_advance_lead) {
398
         if (current_block->use_advance_lead) {
371
-          int delta_adv_steps; //Maybe a char would be enough?
372
-          delta_adv_steps = (((long)extruder_advance_k * current_estep_rate[current_block->active_extruder]) >> 9) - current_adv_steps[current_block->active_extruder];
373
-          e_steps[current_block->active_extruder] += delta_adv_steps;
374
-          current_adv_steps[current_block->active_extruder] += delta_adv_steps;
399
+          int delta_adv_steps = (((long)extruder_advance_k * current_estep_rate[TOOL_E_INDEX]) >> 9) - current_adv_steps[TOOL_E_INDEX];
400
+          #if ENABLED(MIXING_EXTRUDER)
401
+            // Mixing extruders apply advance lead proportionally
402
+            MIXING_STEPPERS_LOOP(j) {
403
+              int steps = delta_adv_steps * current_block->step_event_count / current_block->mix_event_count[j];
404
+              e_steps[j] += steps;
405
+              current_adv_steps[j] += steps;
406
+            }
407
+          #else
408
+            // For most extruders, advance the single E stepper
409
+            e_steps[TOOL_E_INDEX] += delta_adv_steps;
410
+            current_adv_steps[TOOL_E_INDEX] += delta_adv_steps;
411
+          #endif
375
         }
412
         }
376
 
413
 
377
       #elif ENABLED(ADVANCE)
414
       #elif ENABLED(ADVANCE)
378
 
415
 
416
+        // Always count the unified E axis
379
         counter_E += current_block->steps[E_AXIS];
417
         counter_E += current_block->steps[E_AXIS];
380
         if (counter_E > 0) {
418
         if (counter_E > 0) {
381
           counter_E -= current_block->step_event_count;
419
           counter_E -= current_block->step_event_count;
382
-          e_steps[current_block->active_extruder] += motor_direction(E_AXIS) ? -1 : 1;
420
+          #if DISABLED(MIXING_EXTRUDER)
421
+            // Don't step E here for mixing extruder
422
+            e_steps[TOOL_E_INDEX] += motor_direction(E_AXIS) ? -1 : 1;
423
+          #endif
383
         }
424
         }
384
 
425
 
426
+        #if ENABLED(MIXING_EXTRUDER)
427
+
428
+          // Step mixing steppers proportionally
429
+          long dir = motor_direction(E_AXIS) ? -1 : 1;
430
+          MIXING_STEPPERS_LOOP(j) {
431
+            counter_m[j] += current_block->steps[E_AXIS];
432
+            if (counter_m[j] > 0) {
433
+              counter_m[j] -= current_block->mix_event_count[j];
434
+              e_steps[j] += dir;
435
+            }
436
+          }
437
+
438
+        #endif // MIXING_EXTRUDER
439
+
385
       #endif // ADVANCE or LIN_ADVANCE
440
       #endif // ADVANCE or LIN_ADVANCE
386
 
441
 
387
       #define _COUNTER(AXIS) counter_## AXIS
442
       #define _COUNTER(AXIS) counter_## AXIS
395
       STEP_ADD(X);
450
       STEP_ADD(X);
396
       STEP_ADD(Y);
451
       STEP_ADD(Y);
397
       STEP_ADD(Z);
452
       STEP_ADD(Z);
453
+
398
       #if DISABLED(ADVANCE) && DISABLED(LIN_ADVANCE)
454
       #if DISABLED(ADVANCE) && DISABLED(LIN_ADVANCE)
399
-        STEP_ADD(E);
400
-      #endif
455
+        #if ENABLED(MIXING_EXTRUDER)
456
+          // Keep updating the single E axis
457
+          counter_E += current_block->steps[E_AXIS];
458
+          // Tick the counters used for this mix
459
+          MIXING_STEPPERS_LOOP(j) {
460
+            // Step mixing steppers (proportionally)
461
+            counter_M[j] += current_block->steps[E_AXIS];
462
+            // Step when the counter goes over zero
463
+            if (counter_M[j] > 0) En_STEP_WRITE(j, !INVERT_E_STEP_PIN);
464
+          }
465
+        #else // !MIXING_EXTRUDER
466
+          STEP_ADD(E);
467
+        #endif
468
+      #endif // !ADVANCE && !LIN_ADVANCE
401
 
469
 
402
       #define STEP_IF_COUNTER(AXIS) \
470
       #define STEP_IF_COUNTER(AXIS) \
403
         if (_COUNTER(AXIS) > 0) { \
471
         if (_COUNTER(AXIS) > 0) { \
409
       STEP_IF_COUNTER(X);
477
       STEP_IF_COUNTER(X);
410
       STEP_IF_COUNTER(Y);
478
       STEP_IF_COUNTER(Y);
411
       STEP_IF_COUNTER(Z);
479
       STEP_IF_COUNTER(Z);
480
+
412
       #if DISABLED(ADVANCE) && DISABLED(LIN_ADVANCE)
481
       #if DISABLED(ADVANCE) && DISABLED(LIN_ADVANCE)
413
-        STEP_IF_COUNTER(E);
414
-      #endif
482
+        #if ENABLED(MIXING_EXTRUDER)
483
+          // Always step the single E axis
484
+          if (counter_E > 0) {
485
+            counter_E -= current_block->step_event_count;
486
+            count_position[E_AXIS] += count_direction[E_AXIS];
487
+          }
488
+          MIXING_STEPPERS_LOOP(j) {
489
+            if (counter_M[j] > 0) {
490
+              counter_M[j] -= current_block->mix_event_count[j];
491
+              En_STEP_WRITE(j, INVERT_E_STEP_PIN);
492
+            }
493
+          }
494
+        #else // !MIXING_EXTRUDER
495
+          STEP_IF_COUNTER(E);
496
+        #endif
497
+      #endif // !ADVANCE && !LIN_ADVANCE
415
 
498
 
416
       step_events_completed++;
499
       step_events_completed++;
417
       if (step_events_completed >= current_block->step_event_count) break;
500
       if (step_events_completed >= current_block->step_event_count) break;
418
     }
501
     }
419
 
502
 
420
-    #if ENABLED(LIN_ADVANCE)
503
+    #if ENABLED(ADVANCE) || ENABLED(LIN_ADVANCE)
421
       // If we have esteps to execute, fire the next ISR "now"
504
       // If we have esteps to execute, fire the next ISR "now"
422
-      if (e_steps[current_block->active_extruder]) OCR0A = TCNT0 + 2;
505
+      if (e_steps[TOOL_E_INDEX]) OCR0A = TCNT0 + 2;
423
     #endif
506
     #endif
424
 
507
 
425
     // Calculate new timer value
508
     // Calculate new timer value
440
       #if ENABLED(LIN_ADVANCE)
523
       #if ENABLED(LIN_ADVANCE)
441
 
524
 
442
         if (current_block->use_advance_lead)
525
         if (current_block->use_advance_lead)
443
-          current_estep_rate[current_block->active_extruder] = ((unsigned long)acc_step_rate * current_block->e_speed_multiplier8) >> 8;
526
+          current_estep_rate[TOOL_E_INDEX] = ((unsigned long)acc_step_rate * current_block->e_speed_multiplier8) >> 8;
527
+
528
+        if (current_block->use_advance_lead) {
529
+          #if ENABLED(MIXING_EXTRUDER)
530
+            MIXING_STEPPERS_LOOP(j)
531
+              current_estep_rate[j] = ((unsigned long)acc_step_rate * current_block->e_speed_multiplier8 * current_block->step_event_count / current_block->mix_event_count[j]) >> 8;
532
+          #else
533
+            current_estep_rate[TOOL_E_INDEX] = ((unsigned long)acc_step_rate * current_block->e_speed_multiplier8) >> 8;
534
+          #endif
535
+        }
444
 
536
 
445
       #elif ENABLED(ADVANCE)
537
       #elif ENABLED(ADVANCE)
446
 
538
 
447
         advance += advance_rate * step_loops;
539
         advance += advance_rate * step_loops;
448
         //NOLESS(advance, current_block->advance);
540
         //NOLESS(advance, current_block->advance);
449
 
541
 
542
+        long advance_whole = advance >> 8,
543
+             advance_factor = advance_whole - old_advance;
544
+
450
         // Do E steps + advance steps
545
         // Do E steps + advance steps
451
-        e_steps[current_block->active_extruder] += ((advance >> 8) - old_advance);
452
-        old_advance = advance >> 8;
546
+        #if ENABLED(MIXING_EXTRUDER)
547
+          // ...for mixing steppers proportionally
548
+          MIXING_STEPPERS_LOOP(j)
549
+            e_steps[j] += advance_factor * current_block->step_event_count / current_block->mix_event_count[j];
550
+        #else
551
+          // ...for the active extruder
552
+          e_steps[TOOL_E_INDEX] += advance_factor;
553
+        #endif
554
+
555
+        old_advance = advance_whole;
453
 
556
 
454
       #endif // ADVANCE or LIN_ADVANCE
557
       #endif // ADVANCE or LIN_ADVANCE
455
 
558
 
456
       #if ENABLED(ADVANCE) || ENABLED(LIN_ADVANCE)
559
       #if ENABLED(ADVANCE) || ENABLED(LIN_ADVANCE)
457
-        eISR_Rate = (timer >> 2) * step_loops / abs(e_steps[current_block->active_extruder]);
560
+        eISR_Rate = (timer >> 2) * step_loops / abs(e_steps[TOOL_E_INDEX]);
458
       #endif
561
       #endif
459
     }
562
     }
460
     else if (step_events_completed > (unsigned long)current_block->decelerate_after) {
563
     else if (step_events_completed > (unsigned long)current_block->decelerate_after) {
474
 
577
 
475
       #if ENABLED(LIN_ADVANCE)
578
       #if ENABLED(LIN_ADVANCE)
476
 
579
 
477
-        if (current_block->use_advance_lead)
478
-          current_estep_rate[current_block->active_extruder] = ((unsigned long)step_rate * current_block->e_speed_multiplier8) >> 8;
580
+        if (current_block->use_advance_lead) {
581
+          #if ENABLED(MIXING_EXTRUDER)
582
+            MIXING_STEPPERS_LOOP(j)
583
+              current_estep_rate[j] = ((unsigned long)step_rate * current_block->e_speed_multiplier8 * current_block->step_event_count / current_block->mix_event_count[j]) >> 8;
584
+          #else
585
+            current_estep_rate[TOOL_E_INDEX] = ((unsigned long)step_rate * current_block->e_speed_multiplier8) >> 8;
586
+          #endif
587
+        }
479
 
588
 
480
       #elif ENABLED(ADVANCE)
589
       #elif ENABLED(ADVANCE)
481
 
590
 
483
         NOLESS(advance, final_advance);
592
         NOLESS(advance, final_advance);
484
 
593
 
485
         // Do E steps + advance steps
594
         // Do E steps + advance steps
486
-        uint32_t advance_whole = advance >> 8;
487
-        e_steps[current_block->active_extruder] += advance_whole - old_advance;
595
+        long advance_whole = advance >> 8,
596
+             advance_factor = advance_whole - old_advance;
597
+
598
+        #if ENABLED(MIXING_EXTRUDER)
599
+          MIXING_STEPPERS_LOOP(j)
600
+            e_steps[j] += advance_factor * current_block->step_event_count / current_block->mix_event_count[j];
601
+        #else
602
+          e_steps[TOOL_E_INDEX] += advance_factor;
603
+        #endif
604
+
488
         old_advance = advance_whole;
605
         old_advance = advance_whole;
489
 
606
 
490
       #endif // ADVANCE or LIN_ADVANCE
607
       #endif // ADVANCE or LIN_ADVANCE
491
 
608
 
492
       #if ENABLED(ADVANCE) || ENABLED(LIN_ADVANCE)
609
       #if ENABLED(ADVANCE) || ENABLED(LIN_ADVANCE)
493
-        eISR_Rate = (timer >> 2) * step_loops / abs(e_steps[current_block->active_extruder]);
610
+        eISR_Rate = (timer >> 2) * step_loops / abs(e_steps[TOOL_E_INDEX]);
494
       #endif
611
       #endif
495
     }
612
     }
496
     else {
613
     else {
498
       #if ENABLED(LIN_ADVANCE)
615
       #if ENABLED(LIN_ADVANCE)
499
 
616
 
500
         if (current_block->use_advance_lead)
617
         if (current_block->use_advance_lead)
501
-          current_estep_rate[current_block->active_extruder] = final_estep_rate;
618
+          current_estep_rate[TOOL_E_INDEX] = final_estep_rate;
502
 
619
 
503
-        eISR_Rate = (OCR1A_nominal >> 2) * step_loops_nominal / abs(e_steps[current_block->active_extruder]);
620
+        eISR_Rate = (OCR1A_nominal >> 2) * step_loops_nominal / abs(e_steps[TOOL_E_INDEX]);
504
 
621
 
505
       #endif
622
       #endif
506
 
623
 
537
           E## INDEX ##_DIR_WRITE(INVERT_E## INDEX ##_DIR); \
654
           E## INDEX ##_DIR_WRITE(INVERT_E## INDEX ##_DIR); \
538
           e_steps[INDEX]++; \
655
           e_steps[INDEX]++; \
539
         } \
656
         } \
540
-        else if (e_steps[INDEX] > 0) { \
657
+        else { \
541
           E## INDEX ##_DIR_WRITE(!INVERT_E## INDEX ##_DIR); \
658
           E## INDEX ##_DIR_WRITE(!INVERT_E## INDEX ##_DIR); \
542
           e_steps[INDEX]--; \
659
           e_steps[INDEX]--; \
543
         } \
660
         } \
547
     // Step all E steppers that have steps
664
     // Step all E steppers that have steps
548
     for (uint8_t i = 0; i < step_loops; i++) {
665
     for (uint8_t i = 0; i < step_loops; i++) {
549
       STEP_E_ONCE(0);
666
       STEP_E_ONCE(0);
550
-      #if EXTRUDERS > 1
667
+      #if E_STEPPERS > 1
551
         STEP_E_ONCE(1);
668
         STEP_E_ONCE(1);
552
-        #if EXTRUDERS > 2
669
+        #if E_STEPPERS > 2
553
           STEP_E_ONCE(2);
670
           STEP_E_ONCE(2);
554
-          #if EXTRUDERS > 3
671
+          #if E_STEPPERS > 3
555
             STEP_E_ONCE(3);
672
             STEP_E_ONCE(3);
556
           #endif
673
           #endif
557
         #endif
674
         #endif
730
 
847
 
731
   #if ENABLED(ADVANCE) || ENABLED(LIN_ADVANCE)
848
   #if ENABLED(ADVANCE) || ENABLED(LIN_ADVANCE)
732
 
849
 
733
-    #if ENABLED(LIN_ADVANCE)
734
-
735
-      for (int i = 0; i < EXTRUDERS; i++) {
736
-        e_steps[i] = 0;
850
+    for (int i = 0; i < E_STEPPERS; i++) {
851
+      e_steps[i] = 0;
852
+      #if ENABLED(LIN_ADVANCE)
737
         current_adv_steps[i] = 0;
853
         current_adv_steps[i] = 0;
738
-      }
739
-
740
-    #elif ENABLED(ADVANCE)
741
-
742
-      for (uint8_t i = 0; i < EXTRUDERS; i++) e_steps[i] = 0;
743
-
744
-    #endif
854
+      #endif
855
+    }
745
 
856
 
746
     #if defined(TCCR0A) && defined(WGM01)
857
     #if defined(TCCR0A) && defined(WGM01)
747
       CBI(TCCR0A, WGM01);
858
       CBI(TCCR0A, WGM01);

+ 29
- 6
Marlin/stepper.h View File

107
       static unsigned char old_OCR0A;
107
       static unsigned char old_OCR0A;
108
       static volatile unsigned char eISR_Rate;
108
       static volatile unsigned char eISR_Rate;
109
       #if ENABLED(LIN_ADVANCE)
109
       #if ENABLED(LIN_ADVANCE)
110
-        static volatile int e_steps[EXTRUDERS];
110
+        static volatile int e_steps[E_STEPPERS];
111
         static int extruder_advance_k;
111
         static int extruder_advance_k;
112
         static int final_estep_rate;
112
         static int final_estep_rate;
113
-        static int current_estep_rate[EXTRUDERS]; // Actual extruder speed [steps/s]
114
-        static int current_adv_steps[EXTRUDERS];  // The amount of current added esteps due to advance.
113
+        static int current_estep_rate[E_STEPPERS]; // Actual extruder speed [steps/s]
114
+        static int current_adv_steps[E_STEPPERS];  // The amount of current added esteps due to advance.
115
                                                   // i.e., the current amount of pressure applied
115
                                                   // i.e., the current amount of pressure applied
116
                                                   // to the spring (=filament).
116
                                                   // to the spring (=filament).
117
       #else
117
       #else
118
-        static long e_steps[EXTRUDERS];
118
+        static long e_steps[E_STEPPERS];
119
         static long advance_rate, advance, final_advance;
119
         static long advance_rate, advance, final_advance;
120
         static long old_advance;
120
         static long old_advance;
121
       #endif
121
       #endif
147
     //
147
     //
148
     static volatile signed char count_direction[NUM_AXIS];
148
     static volatile signed char count_direction[NUM_AXIS];
149
 
149
 
150
+    //
151
+    // Mixing extruder mix counters
152
+    //
153
+    #if ENABLED(MIXING_EXTRUDER)
154
+      static long counter_M[MIXING_STEPPERS];
155
+      #define MIXING_STEPPERS_LOOP(VAR) \
156
+        for (uint8_t VAR = 0; VAR < MIXING_STEPPERS; VAR++) \
157
+          if (current_block->mix_event_count[VAR])
158
+    #endif
159
+
150
   public:
160
   public:
151
 
161
 
152
     //
162
     //
315
       }
325
       }
316
 
326
 
317
       #if ENABLED(ADVANCE)
327
       #if ENABLED(ADVANCE)
328
+
318
         advance = current_block->initial_advance;
329
         advance = current_block->initial_advance;
319
         final_advance = current_block->final_advance;
330
         final_advance = current_block->final_advance;
331
+
320
         // Do E steps + advance steps
332
         // Do E steps + advance steps
321
-        e_steps[current_block->active_extruder] += ((advance >>8) - old_advance);
322
-        old_advance = advance >>8;
333
+        #if ENABLED(MIXING_EXTRUDER)
334
+          long advance_factor = (advance >> 8) - old_advance;
335
+          // ...for mixing steppers proportionally
336
+          MIXING_STEPPERS_LOOP(j)
337
+            e_steps[j] += advance_factor * current_block->step_event_count / current_block->mix_event_count[j];
338
+        #else
339
+          // ...for the active extruder
340
+          e_steps[TOOL_E_INDEX] += ((advance >> 8) - old_advance);
341
+        #endif
342
+
343
+        old_advance = advance >> 8;
344
+
323
       #endif
345
       #endif
346
+
324
       deceleration_time = 0;
347
       deceleration_time = 0;
325
       // step_rate to timer interval
348
       // step_rate to timer interval
326
       OCR1A_nominal = calc_timer(current_block->nominal_rate);
349
       OCR1A_nominal = calc_timer(current_block->nominal_rate);

+ 32
- 16
Marlin/stepper_indirection.h View File

182
 #define E3_ENABLE_WRITE(STATE) WRITE(E3_ENABLE_PIN,STATE)
182
 #define E3_ENABLE_WRITE(STATE) WRITE(E3_ENABLE_PIN,STATE)
183
 #define E3_ENABLE_READ READ(E3_ENABLE_PIN)
183
 #define E3_ENABLE_READ READ(E3_ENABLE_PIN)
184
 
184
 
185
-#if EXTRUDERS > 3
186
-  #define E_STEP_WRITE(v) {switch(current_block->active_extruder){case 3:E3_STEP_WRITE(v);break;case 2:E2_STEP_WRITE(v);break;case 1:E1_STEP_WRITE(v);break;default:E0_STEP_WRITE(v);}}
187
-  #define NORM_E_DIR() {switch(current_block->active_extruder){case 3:E3_DIR_WRITE(!INVERT_E3_DIR);break;case 2:E2_DIR_WRITE(!INVERT_E2_DIR);break;case 1:E1_DIR_WRITE(!INVERT_E1_DIR);break;default:E0_DIR_WRITE(!INVERT_E0_DIR);}}
188
-  #define REV_E_DIR() {switch(current_block->active_extruder){case 3:E3_DIR_WRITE(INVERT_E3_DIR);break;case 2:E2_DIR_WRITE(INVERT_E2_DIR);break;case 1:E1_DIR_WRITE(INVERT_E1_DIR);break;default:E0_DIR_WRITE(INVERT_E0_DIR);}}
185
+#if ENABLED(SWITCHING_EXTRUDER)
186
+  #define E_STEP_WRITE(v) E0_STEP_WRITE(v)
187
+  #define NORM_E_DIR() E0_DIR_WRITE(current_block->active_extruder ?  INVERT_E0_DIR : !INVERT_E0_DIR)
188
+  #define  REV_E_DIR() E0_DIR_WRITE(current_block->active_extruder ? !INVERT_E0_DIR :  INVERT_E0_DIR)
189
+#elif EXTRUDERS > 3
190
+  #define E_STEP_WRITE(v) { switch (current_block->active_extruder) { case 0: E0_STEP_WRITE(v); break; case 1: E1_STEP_WRITE(v); break; case 2: E2_STEP_WRITE(v); break; case 3: E3_STEP_WRITE(v); } }
191
+  #define NORM_E_DIR() { switch (current_block->active_extruder) { case 0: E0_DIR_WRITE(!INVERT_E0_DIR); break; case 1: E1_DIR_WRITE(!INVERT_E1_DIR); break; case 2: E2_DIR_WRITE(!INVERT_E2_DIR); break; case 3: E3_DIR_WRITE(!INVERT_E3_DIR); } }
192
+  #define REV_E_DIR() { switch (current_block->active_extruder) { case 0: E0_DIR_WRITE(INVERT_E0_DIR); break; case 1: E1_DIR_WRITE(INVERT_E1_DIR); break; case 2: E2_DIR_WRITE(INVERT_E2_DIR); break; case 3: E3_DIR_WRITE(INVERT_E3_DIR); } }
189
 #elif EXTRUDERS > 2
193
 #elif EXTRUDERS > 2
190
-  #define E_STEP_WRITE(v) {switch(current_block->active_extruder){case 2:E2_STEP_WRITE(v);break;case 1:E1_STEP_WRITE(v);break;default:E0_STEP_WRITE(v);}}
191
-  #define NORM_E_DIR() {switch(current_block->active_extruder){case 2:E2_DIR_WRITE(!INVERT_E2_DIR);break;case 1:E1_DIR_WRITE(!INVERT_E1_DIR);break;default:E0_DIR_WRITE(!INVERT_E0_DIR);}}
192
-  #define REV_E_DIR() {switch(current_block->active_extruder){case 2:E2_DIR_WRITE(INVERT_E2_DIR);break;case 1:E1_DIR_WRITE(INVERT_E1_DIR);break;default:E0_DIR_WRITE(INVERT_E0_DIR);}}
194
+  #define E_STEP_WRITE(v) { switch (current_block->active_extruder) { case 0: E0_STEP_WRITE(v); break; case 1: E1_STEP_WRITE(v); break; case 2: E2_STEP_WRITE(v); } }
195
+  #define NORM_E_DIR() { switch (current_block->active_extruder) { case 0: E0_DIR_WRITE(!INVERT_E0_DIR); break; case 1: E1_DIR_WRITE(!INVERT_E1_DIR); break; case 2: E2_DIR_WRITE(!INVERT_E2_DIR); } }
196
+  #define REV_E_DIR() { switch (current_block->active_extruder) { case 0: E0_DIR_WRITE(INVERT_E0_DIR); break; case 1: E1_DIR_WRITE(INVERT_E1_DIR); break; case 2: E2_DIR_WRITE(INVERT_E2_DIR); } }
193
 #elif EXTRUDERS > 1
197
 #elif EXTRUDERS > 1
194
-  #define _E_STEP_WRITE(v) {if(current_block->active_extruder==1){E1_STEP_WRITE(v);}else{E0_STEP_WRITE(v);}}
195
-  #define _NORM_E_DIR() {if(current_block->active_extruder==1){E1_DIR_WRITE(!INVERT_E1_DIR);}else{E0_DIR_WRITE(!INVERT_E0_DIR);}}
196
-  #define _REV_E_DIR() {if(current_block->active_extruder==1){E1_DIR_WRITE(INVERT_E1_DIR);}else{E0_DIR_WRITE(INVERT_E0_DIR);}}
197
   #if DISABLED(DUAL_X_CARRIAGE)
198
   #if DISABLED(DUAL_X_CARRIAGE)
198
-    #define E_STEP_WRITE(v) _E_STEP_WRITE(v)
199
-    #define NORM_E_DIR() _NORM_E_DIR()
200
-    #define REV_E_DIR() _REV_E_DIR()
199
+    #define E_STEP_WRITE(v) { if (current_block->active_extruder == 0) { E0_STEP_WRITE(v); } else { E1_STEP_WRITE(v); } }
200
+    #define NORM_E_DIR() { if (current_block->active_extruder == 0) { E0_DIR_WRITE(!INVERT_E0_DIR); } else { E1_DIR_WRITE(!INVERT_E1_DIR); } }
201
+    #define REV_E_DIR() { if (current_block->active_extruder == 0) { E0_DIR_WRITE(INVERT_E0_DIR); } else { E1_DIR_WRITE(INVERT_E1_DIR); } }
202
+  #else
203
+    #define E_STEP_WRITE(v) { if (extruder_duplication_enabled) { E0_STEP_WRITE(v); E1_STEP_WRITE(v); } else if (current_block->active_extruder == 0) { E0_STEP_WRITE(v); } else { E1_STEP_WRITE(v); } }
204
+    #define NORM_E_DIR() { if (extruder_duplication_enabled) { E0_DIR_WRITE(!INVERT_E0_DIR); E1_DIR_WRITE(!INVERT_E1_DIR); } else if (current_block->active_extruder == 0) { E0_DIR_WRITE(!INVERT_E0_DIR); } else { E1_DIR_WRITE(!INVERT_E1_DIR); } }
205
+    #define REV_E_DIR() { if (extruder_duplication_enabled) { E0_DIR_WRITE(INVERT_E0_DIR); E1_DIR_WRITE(INVERT_E1_DIR); } else if (current_block->active_extruder == 0) { E0_DIR_WRITE(INVERT_E0_DIR); } else { E1_DIR_WRITE(INVERT_E1_DIR); } }
206
+  #endif
207
+#elif ENABLED(MIXING_EXTRUDER)
208
+  #define E_STEP_WRITE(v) NOOP /* not used for mixing extruders! */
209
+  #if MIXING_STEPPERS > 3
210
+    #define En_STEP_WRITE(n,v) { switch (n) { case 0: E0_STEP_WRITE(v); break; case 1: E1_STEP_WRITE(v); break; case 2: E2_STEP_WRITE(v); break; case 3: E3_STEP_WRITE(v); } }
211
+    #define NORM_E_DIR() { E0_DIR_WRITE(!INVERT_E0_DIR); E1_DIR_WRITE(!INVERT_E1_DIR); E2_DIR_WRITE(!INVERT_E2_DIR); E3_DIR_WRITE(!INVERT_E3_DIR); }
212
+    #define REV_E_DIR()  { E0_DIR_WRITE( INVERT_E0_DIR); E1_DIR_WRITE( INVERT_E1_DIR); E2_DIR_WRITE( INVERT_E2_DIR); E3_DIR_WRITE( INVERT_E3_DIR); }
213
+  #elif MIXING_STEPPERS > 2
214
+    #define En_STEP_WRITE(n,v) { switch (n) { case 0: E0_STEP_WRITE(v); break; case 1: E1_STEP_WRITE(v); break; case 2: E2_STEP_WRITE(v); } }
215
+    #define NORM_E_DIR() { E0_DIR_WRITE(!INVERT_E0_DIR); E1_DIR_WRITE(!INVERT_E1_DIR); E2_DIR_WRITE(!INVERT_E2_DIR); }
216
+    #define REV_E_DIR()  { E0_DIR_WRITE( INVERT_E0_DIR); E1_DIR_WRITE( INVERT_E1_DIR); E2_DIR_WRITE( INVERT_E2_DIR); }
201
   #else
217
   #else
202
-    #define E_STEP_WRITE(v) {if(extruder_duplication_enabled){E0_STEP_WRITE(v);E1_STEP_WRITE(v);}else _E_STEP_WRITE(v);}
203
-    #define NORM_E_DIR() {if(extruder_duplication_enabled){E0_DIR_WRITE(!INVERT_E0_DIR);E1_DIR_WRITE(!INVERT_E1_DIR);}else _NORM_E_DIR();}
204
-    #define REV_E_DIR() {if(extruder_duplication_enabled){E0_DIR_WRITE(INVERT_E0_DIR);E1_DIR_WRITE(INVERT_E1_DIR);}else _REV_E_DIR();}
218
+    #define En_STEP_WRITE(n,v) { switch (n) { case 0: E0_STEP_WRITE(v); break; case 1: E1_STEP_WRITE(v); } }
219
+    #define NORM_E_DIR() { E0_DIR_WRITE(!INVERT_E0_DIR); E1_DIR_WRITE(!INVERT_E1_DIR); }
220
+    #define REV_E_DIR()  { E0_DIR_WRITE( INVERT_E0_DIR); E1_DIR_WRITE( INVERT_E1_DIR); }
205
   #endif
221
   #endif
206
 #else
222
 #else
207
   #define E_STEP_WRITE(v) E0_STEP_WRITE(v)
223
   #define E_STEP_WRITE(v) E0_STEP_WRITE(v)

+ 25
- 16
Marlin/ultralcd.cpp View File

1365
   #endif
1365
   #endif
1366
   static void lcd_move_z() { _lcd_move_xyz(PSTR(MSG_MOVE_Z), Z_AXIS, sw_endstop_min[Z_AXIS], sw_endstop_max[Z_AXIS]); }
1366
   static void lcd_move_z() { _lcd_move_xyz(PSTR(MSG_MOVE_Z), Z_AXIS, sw_endstop_min[Z_AXIS], sw_endstop_max[Z_AXIS]); }
1367
   static void lcd_move_e(
1367
   static void lcd_move_e(
1368
-    #if EXTRUDERS > 1
1368
+    #if E_STEPPERS > 1
1369
       int8_t eindex = -1
1369
       int8_t eindex = -1
1370
     #endif
1370
     #endif
1371
   ) {
1371
   ) {
1375
       current_position[E_AXIS] += float((int32_t)encoderPosition) * move_menu_scale;
1375
       current_position[E_AXIS] += float((int32_t)encoderPosition) * move_menu_scale;
1376
       encoderPosition = 0;
1376
       encoderPosition = 0;
1377
       manual_move_to_current(E_AXIS
1377
       manual_move_to_current(E_AXIS
1378
-        #if EXTRUDERS > 1
1378
+        #if E_STEPPERS > 1
1379
           , eindex
1379
           , eindex
1380
         #endif
1380
         #endif
1381
       );
1381
       );
1383
     }
1383
     }
1384
     if (lcdDrawUpdate) {
1384
     if (lcdDrawUpdate) {
1385
       PGM_P pos_label;
1385
       PGM_P pos_label;
1386
-      #if EXTRUDERS == 1
1386
+      #if E_STEPPERS == 1
1387
         pos_label = PSTR(MSG_MOVE_E);
1387
         pos_label = PSTR(MSG_MOVE_E);
1388
       #else
1388
       #else
1389
         switch (eindex) {
1389
         switch (eindex) {
1390
           default: pos_label = PSTR(MSG_MOVE_E MSG_MOVE_E1); break;
1390
           default: pos_label = PSTR(MSG_MOVE_E MSG_MOVE_E1); break;
1391
           case 1: pos_label = PSTR(MSG_MOVE_E MSG_MOVE_E2); break;
1391
           case 1: pos_label = PSTR(MSG_MOVE_E MSG_MOVE_E2); break;
1392
-          #if EXTRUDERS > 2
1392
+          #if E_STEPPERS > 2
1393
             case 2: pos_label = PSTR(MSG_MOVE_E MSG_MOVE_E3); break;
1393
             case 2: pos_label = PSTR(MSG_MOVE_E MSG_MOVE_E3); break;
1394
-            #if EXTRUDERS > 3
1394
+            #if E_STEPPERS > 3
1395
               case 3: pos_label = PSTR(MSG_MOVE_E MSG_MOVE_E4); break;
1395
               case 3: pos_label = PSTR(MSG_MOVE_E MSG_MOVE_E4); break;
1396
-            #endif //EXTRUDERS > 3
1397
-          #endif //EXTRUDERS > 2
1396
+            #endif
1397
+          #endif
1398
         }
1398
         }
1399
-      #endif //EXTRUDERS > 1
1399
+      #endif
1400
       lcd_implementation_drawedit(pos_label, ftostr41sign(current_position[E_AXIS]));
1400
       lcd_implementation_drawedit(pos_label, ftostr41sign(current_position[E_AXIS]));
1401
     }
1401
     }
1402
   }
1402
   }
1403
 
1403
 
1404
-  #if EXTRUDERS > 1
1404
+  #if E_STEPPERS > 1
1405
     static void lcd_move_e0() { lcd_move_e(0); }
1405
     static void lcd_move_e0() { lcd_move_e(0); }
1406
     static void lcd_move_e1() { lcd_move_e(1); }
1406
     static void lcd_move_e1() { lcd_move_e(1); }
1407
-    #if EXTRUDERS > 2
1407
+    #if E_STEPPERS > 2
1408
       static void lcd_move_e2() { lcd_move_e(2); }
1408
       static void lcd_move_e2() { lcd_move_e(2); }
1409
-      #if EXTRUDERS > 3
1409
+      #if E_STEPPERS > 3
1410
         static void lcd_move_e3() { lcd_move_e(3); }
1410
         static void lcd_move_e3() { lcd_move_e(3); }
1411
       #endif
1411
       #endif
1412
     #endif
1412
     #endif
1413
-  #endif // EXTRUDERS > 1
1413
+  #endif
1414
 
1414
 
1415
   /**
1415
   /**
1416
    *
1416
    *
1432
       MENU_ITEM(submenu, MSG_MOVE_X, lcd_move_x);
1432
       MENU_ITEM(submenu, MSG_MOVE_X, lcd_move_x);
1433
       MENU_ITEM(submenu, MSG_MOVE_Y, lcd_move_y);
1433
       MENU_ITEM(submenu, MSG_MOVE_Y, lcd_move_y);
1434
     }
1434
     }
1435
+
1435
     if (move_menu_scale < 10.0) {
1436
     if (move_menu_scale < 10.0) {
1436
       if (_MOVE_XYZ_ALLOWED) MENU_ITEM(submenu, MSG_MOVE_Z, lcd_move_z);
1437
       if (_MOVE_XYZ_ALLOWED) MENU_ITEM(submenu, MSG_MOVE_Z, lcd_move_z);
1437
-      #if EXTRUDERS == 1
1438
+
1439
+      #if ENABLED(SWITCHING_EXTRUDER)
1440
+        if (active_extruder)
1441
+          MENU_ITEM(gcode, MSG_SELECT MSG_E1, PSTR("T0"));
1442
+        else
1443
+          MENU_ITEM(gcode, MSG_SELECT MSG_E2, PSTR("T1"));
1444
+      #endif
1445
+
1446
+      #if E_STEPPERS == 1
1438
         MENU_ITEM(submenu, MSG_MOVE_E, lcd_move_e);
1447
         MENU_ITEM(submenu, MSG_MOVE_E, lcd_move_e);
1439
       #else
1448
       #else
1440
         MENU_ITEM(submenu, MSG_MOVE_E MSG_MOVE_E1, lcd_move_e0);
1449
         MENU_ITEM(submenu, MSG_MOVE_E MSG_MOVE_E1, lcd_move_e0);
1441
         MENU_ITEM(submenu, MSG_MOVE_E MSG_MOVE_E2, lcd_move_e1);
1450
         MENU_ITEM(submenu, MSG_MOVE_E MSG_MOVE_E2, lcd_move_e1);
1442
-        #if EXTRUDERS > 2
1451
+        #if E_STEPPERS > 2
1443
           MENU_ITEM(submenu, MSG_MOVE_E MSG_MOVE_E3, lcd_move_e2);
1452
           MENU_ITEM(submenu, MSG_MOVE_E MSG_MOVE_E3, lcd_move_e2);
1444
-          #if EXTRUDERS > 3
1453
+          #if E_STEPPERS > 3
1445
             MENU_ITEM(submenu, MSG_MOVE_E MSG_MOVE_E4, lcd_move_e3);
1454
             MENU_ITEM(submenu, MSG_MOVE_E MSG_MOVE_E4, lcd_move_e3);
1446
           #endif
1455
           #endif
1447
         #endif
1456
         #endif
1448
-      #endif // EXTRUDERS > 1
1457
+      #endif
1449
     }
1458
     }
1450
     END_MENU();
1459
     END_MENU();
1451
   }
1460
   }

Loading…
Cancel
Save