diff --git a/.travis.yml b/.travis.yml index 30210b42ffbf..026cb6029fcc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -136,6 +136,13 @@ script: - opt_enable EEPROM_SETTINGS EEPROM_CHITCHAT M100_FREE_MEMORY_WATCHER INCH_MODE_SUPPORT TEMPERATURE_UNITS_SUPPORT - build_marlin # + # Mixing Extruder + # + - restore_configs + - opt_enable MIXING_EXTRUDER + - opt_set MIXING_STEPPERS 2 + - build_marlin + # # Test DUAL_X_CARRIAGE # - restore_configs diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 01c10530a73d..d2dfe125824a 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -133,20 +133,34 @@ // :[1,2,3,4] #define EXTRUDERS 1 -// For Cyclops or any "multi-extruder" that shares a single nozzle. -//#define SINGLENOZZLE - // Offset of the extruders (uncomment if using more than one and relying on firmware to position when changing). // The offset has to be X=0, Y=0 for the extruder 0 hotend (default extruder). // For the other hotends it is their distance from the extruder 0 hotend. //#define HOTEND_OFFSET_X {0.0, 20.00} // (in mm) for each extruder, offset of the hotend on the X axis //#define HOTEND_OFFSET_Y {0.0, 5.00} // (in mm) for each extruder, offset of the hotend on the Y axis +// For Cyclops or any "multi-extruder" that shares a single nozzle. +//#define SINGLENOZZLE + +/** + * "Mixing Extruder" + * - Adds a new code, M165, to set the current mix factors. + * - Extends the stepping routines to move multiple steppers in proportion to the mix. + * - Optional support for Repetier Host M163, M164, and virtual extruder. + * - This implementation supports only a single extruder. + * - Enable DIRECT_MIXING_IN_G1 for Pia Taubert's reference implementation + */ +//#define MIXING_EXTRUDER +#ifdef MIXING_EXTRUDER + #define MIXING_STEPPERS 2 // Number of steppers in your mixing extruder + #define MIXING_VIRTUAL_TOOLS 16 // Use the Virtual Tool method with M163 and M164 + //#define DIRECT_MIXING_IN_G1 // Allow ABCDHI mix factors in G1 movement commands +#endif + //// The following define selects which power supply you have. Please choose the one that matches your setup // 1 = ATX // 2 = X-Box 360 203Watts (the blue wire connected to PS_ON and the red wire to VCC) // :{1:'ATX',2:'X-Box 360'} - #define POWER_SUPPLY 1 // Define this to have the electronics keep the power supply off on startup. If you don't know what this is leave it. diff --git a/Marlin/Marlin.h b/Marlin/Marlin.h index c4298aaac7d8..0dd960c76b82 100644 --- a/Marlin/Marlin.h +++ b/Marlin/Marlin.h @@ -171,37 +171,64 @@ void manage_inactivity(bool ignore_stepper_queue = false); #define disable_z() ; #endif -#if HAS_E0_ENABLE - #define enable_e0() E0_ENABLE_WRITE( E_ENABLE_ON) - #define disable_e0() E0_ENABLE_WRITE(!E_ENABLE_ON) -#else - #define enable_e0() /* nothing */ - #define disable_e0() /* nothing */ -#endif -#if (EXTRUDERS > 1) && HAS_E1_ENABLE - #define enable_e1() E1_ENABLE_WRITE( E_ENABLE_ON) - #define disable_e1() E1_ENABLE_WRITE(!E_ENABLE_ON) -#else - #define enable_e1() /* nothing */ - #define disable_e1() /* nothing */ -#endif +#if ENABLED(MIXING_EXTRUDER) + + /** + * Mixing steppers synchronize their enable (and direction) together + */ + #if MIXING_STEPPERS > 3 + #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); } + #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); } + #elif MIXING_STEPPERS > 2 + #define enable_e0() { E0_ENABLE_WRITE( E_ENABLE_ON); E1_ENABLE_WRITE( E_ENABLE_ON); E2_ENABLE_WRITE( E_ENABLE_ON); } + #define disable_e0() { E0_ENABLE_WRITE(!E_ENABLE_ON); E1_ENABLE_WRITE(!E_ENABLE_ON); E2_ENABLE_WRITE(!E_ENABLE_ON); } + #else + #define enable_e0() { E0_ENABLE_WRITE( E_ENABLE_ON); E1_ENABLE_WRITE( E_ENABLE_ON); } + #define disable_e0() { E0_ENABLE_WRITE(!E_ENABLE_ON); E1_ENABLE_WRITE(!E_ENABLE_ON); } + #endif + #define enable_e1() NOOP + #define disable_e1() NOOP + #define enable_e2() NOOP + #define disable_e2() NOOP + #define enable_e3() NOOP + #define disable_e3() NOOP + +#else // !MIXING_EXTRUDER + + #if HAS_E0_ENABLE + #define enable_e0() E0_ENABLE_WRITE( E_ENABLE_ON) + #define disable_e0() E0_ENABLE_WRITE(!E_ENABLE_ON) + #else + #define enable_e0() NOOP + #define disable_e0() NOOP + #endif -#if (EXTRUDERS > 2) && HAS_E2_ENABLE - #define enable_e2() E2_ENABLE_WRITE( E_ENABLE_ON) - #define disable_e2() E2_ENABLE_WRITE(!E_ENABLE_ON) -#else - #define enable_e2() /* nothing */ - #define disable_e2() /* nothing */ -#endif + #if (EXTRUDERS > 1) && HAS_E1_ENABLE + #define enable_e1() E1_ENABLE_WRITE( E_ENABLE_ON) + #define disable_e1() E1_ENABLE_WRITE(!E_ENABLE_ON) + #else + #define enable_e1() NOOP + #define disable_e1() NOOP + #endif -#if (EXTRUDERS > 3) && HAS_E3_ENABLE - #define enable_e3() E3_ENABLE_WRITE( E_ENABLE_ON) - #define disable_e3() E3_ENABLE_WRITE(!E_ENABLE_ON) -#else - #define enable_e3() /* nothing */ - #define disable_e3() /* nothing */ -#endif + #if (EXTRUDERS > 2) && HAS_E2_ENABLE + #define enable_e2() E2_ENABLE_WRITE( E_ENABLE_ON) + #define disable_e2() E2_ENABLE_WRITE(!E_ENABLE_ON) + #else + #define enable_e2() NOOP + #define disable_e2() NOOP + #endif + + #if (EXTRUDERS > 3) && HAS_E3_ENABLE + #define enable_e3() E3_ENABLE_WRITE( E_ENABLE_ON) + #define disable_e3() E3_ENABLE_WRITE(!E_ENABLE_ON) + #else + #define enable_e3() NOOP + #define disable_e3() NOOP + #endif + +#endif // !MIXING_EXTRUDER /** * The axis order in all axis related arrays is X, Y, Z, E @@ -371,6 +398,10 @@ extern uint8_t active_extruder; void print_heaterstates(); #endif +#if ENABLED(MIXING_EXTRUDER) + extern float mixing_factor[MIXING_STEPPERS]; +#endif + void calculate_volumetric_multipliers(); // Buzzer diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 293d16522013..8c34f0fb814f 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -181,6 +181,9 @@ * M145 - Set the heatup state H B F for S (0=PLA, 1=ABS) * M149 - Set temperature units * 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. + * M163 - Set a single proportion for a mixing extruder. Requires MIXING_EXTRUDER. + * M164 - Save the mix as a virtual extruder. Requires MIXING_EXTRUDER and MIXING_VIRTUAL_TOOLS. + * M165 - Set the proportions for a mixing extruder. Use parameters ABCDHI to set the mixing factors. Requires MIXING_EXTRUDER. * M190 - Sxxx Wait for bed current temp to reach target temp. Waits only when heating * Rxxx Wait for bed current temp to reach target temp. Waits when heating and cooling * M200 - set filament diameter and set E axis units to cubic millimeters (use S0 to set back to millimeters).:D- @@ -490,6 +493,13 @@ static uint8_t target_extruder; static bool filament_ran_out = false; #endif +#if ENABLED(MIXING_EXTRUDER) + float mixing_factor[MIXING_STEPPERS]; + #if MIXING_VIRTUAL_TOOLS > 1 + float mixing_virtual_tool_mix[MIXING_VIRTUAL_TOOLS][MIXING_STEPPERS]; + #endif +#endif + static bool send_ok[BUFSIZE]; #if HAS_SERVOS @@ -928,6 +938,15 @@ void setup() { lcd_init(); #endif #endif + + #if ENABLED(MIXING_EXTRUDER) && MIXING_VIRTUAL_TOOLS > 1 + // Initialize mixing to 100% color 1 + for (uint8_t i = 0; i < MIXING_STEPPERS; i++) + mixing_factor[i] = (i == 0) ? 1 : 0; + for (uint8_t t = 0; t < MIXING_VIRTUAL_TOOLS; t++) + for (uint8_t i = 0; i < MIXING_STEPPERS; i++) + mixing_virtual_tool_mix[t][i] = mixing_factor[i]; + #endif } /** @@ -2512,6 +2531,37 @@ static void homeaxis(AxisEnum axis) { #endif // FWRETRACT +#if ENABLED(MIXING_EXTRUDER) + + void normalize_mix() { + float mix_total = 0.0; + for (int i = 0; i < MIXING_STEPPERS; i++) { + float v = mixing_factor[i]; + if (v < 0) v = mixing_factor[i] = 0; + mix_total += v; + } + // Scale all values if they don't add up to ~1.0 + if (mix_total < 0.9999 || mix_total > 1.0001) { + SERIAL_PROTOCOLLNPGM("Warning: Mix factors must add up to 1.0. Scaling."); + float mix_scale = 1.0 / mix_total; + for (int i = 0; i < MIXING_STEPPERS; i++) + mixing_factor[i] *= mix_scale; + } + } + + // Get mixing parameters from the GCode + // Factors that are left out are set to 0 + // The total "must" be 1.0 (but it will be normalized) + void gcode_get_mix() { + const char* mixing_codes = "ABCDHI"; + for (int i = 0; i < MIXING_STEPPERS; i++) + mixing_factor[i] = code_seen(mixing_codes[i]) ? code_value_float() : 0; + + normalize_mix(); + } + +#endif + /** * *************************************************************************** * ***************************** G-CODE HANDLING ***************************** @@ -2536,6 +2586,10 @@ void gcode_get_destination() { float next_feedrate = code_value_linear_units(); if (next_feedrate > 0.0) feedrate = next_feedrate; } + // Get ABCDHI mixing factors + #if ENABLED(MIXING_EXTRUDER) && ENABLED(DIRECT_MIXING_IN_G1) + gcode_get_mix(); + #endif } void unknown_command_error() { @@ -4658,6 +4712,8 @@ inline void gcode_M109() { KEEPALIVE_STATE(NOT_BUSY); + target_extruder = active_extruder; // for print_heaterstates + do { // Target temperature might be changed during the loop if (theTarget != thermalManager.degTargetBed()) { @@ -6410,6 +6466,58 @@ inline void gcode_M907() { #endif // HAS_MICROSTEPS +#if ENABLED(MIXING_EXTRUDER) + + /** + * M163: Set a single mix factor for a mixing extruder + * This is called "weight" by some systems. + * + * S[index] The channel index to set + * P[float] The mix value + * + */ + inline void gcode_M163() { + int mix_index = code_seen('S') ? code_value_int() : 0; + float mix_value = code_seen('P') ? code_value_float() : 0.0; + if (mix_index < MIXING_STEPPERS) mixing_factor[mix_index] = mix_value; + } + + #if MIXING_VIRTUAL_TOOLS > 1 + + /** + * M164: Store the current mix factors as a virtual tool. + * + * S[index] The virtual tool to store + * + */ + inline void gcode_M164() { + int tool_index = code_seen('S') ? code_value_int() : 0; + if (tool_index < MIXING_VIRTUAL_TOOLS) { + normalize_mix(); + for (uint8_t i = 0; i < MIXING_STEPPERS; i++) + mixing_virtual_tool_mix[tool_index][i] = mixing_factor[i]; + } + } + + #endif + + /** + * M165: Set multiple mix factors for a mixing extruder. + * Factors that are left out will be set to 0. + * All factors together must add up to 1.0. + * + * A[factor] Mix factor for extruder stepper 1 + * B[factor] Mix factor for extruder stepper 2 + * C[factor] Mix factor for extruder stepper 3 + * D[factor] Mix factor for extruder stepper 4 + * H[factor] Mix factor for extruder stepper 5 + * I[factor] Mix factor for extruder stepper 6 + * + */ + inline void gcode_M165() { gcode_get_mix(); } + +#endif // MIXING_EXTRUDER + /** * M999: Restart after being stopped * @@ -6430,6 +6538,13 @@ inline void gcode_M999() { FlushSerialRequestResend(); } +inline void invalid_extruder_error(const uint8_t &e) { + SERIAL_ECHO_START; + SERIAL_CHAR('T'); + SERIAL_PROTOCOL_F(e, DEC); + SERIAL_ECHOLN(MSG_INVALID_EXTRUDER); +} + /** * T0-T3: Switch tool, usually switching extruders * @@ -6437,188 +6552,201 @@ inline void gcode_M999() { * S1 Don't move the tool in XY after change */ inline void gcode_T(uint8_t tmp_extruder) { - if (tmp_extruder >= EXTRUDERS) { - SERIAL_ECHO_START; - SERIAL_CHAR('T'); - SERIAL_PROTOCOL_F(tmp_extruder, DEC); - SERIAL_ECHOLN(MSG_INVALID_EXTRUDER); - return; - } - - #if HOTENDS > 1 - float stored_feedrate = feedrate; + #if ENABLED(MIXING_EXTRUDER) && MIXING_VIRTUAL_TOOLS > 1 - if (code_seen('F')) { - float next_feedrate = code_value_axis_units(X_AXIS); - if (next_feedrate > 0.0) stored_feedrate = feedrate = next_feedrate; + if (tmp_extruder >= MIXING_VIRTUAL_TOOLS) { + invalid_extruder_error(tmp_extruder); + return; } - else - feedrate = XY_PROBE_FEEDRATE; - if (tmp_extruder != active_extruder) { - bool no_move = code_seen('S') && code_value_bool(); - // Save current position to return to after applying extruder offset - if (!no_move) set_destination_to_current(); - #if ENABLED(DUAL_X_CARRIAGE) - if (dual_x_carriage_mode == DXC_AUTO_PARK_MODE && IsRunning() && - (delayed_move_time || current_position[X_AXIS] != x_home_pos(active_extruder))) { - // Park old head: 1) raise 2) move to park position 3) lower - planner.buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS] + TOOLCHANGE_PARK_ZLIFT, - current_position[E_AXIS], planner.max_feedrate[Z_AXIS], active_extruder); - planner.buffer_line(x_home_pos(active_extruder), current_position[Y_AXIS], current_position[Z_AXIS] + TOOLCHANGE_PARK_ZLIFT, - current_position[E_AXIS], planner.max_feedrate[X_AXIS], active_extruder); - planner.buffer_line(x_home_pos(active_extruder), current_position[Y_AXIS], current_position[Z_AXIS], - current_position[E_AXIS], planner.max_feedrate[Z_AXIS], active_extruder); - stepper.synchronize(); - } + // T0-Tnnn: Switch virtual tool by changing the mix + for (uint8_t j = 0; j < MIXING_STEPPERS; j++) + mixing_factor[j] = mixing_virtual_tool_mix[tmp_extruder][j]; - // apply Y & Z extruder offset (x offset is already used in determining home pos) - current_position[Y_AXIS] -= hotend_offset[Y_AXIS][active_extruder] - hotend_offset[Y_AXIS][tmp_extruder]; - current_position[Z_AXIS] -= hotend_offset[Z_AXIS][active_extruder] - hotend_offset[Z_AXIS][tmp_extruder]; - active_extruder = tmp_extruder; + #else //!MIXING_EXTRUDER || MIXING_VIRTUAL_TOOLS <= 1 - // This function resets the max/min values - the current position may be overwritten below. - set_axis_is_at_home(X_AXIS); + #if HOTENDS > 1 - if (dual_x_carriage_mode == DXC_FULL_CONTROL_MODE) { - current_position[X_AXIS] = inactive_extruder_x_pos; - inactive_extruder_x_pos = destination[X_AXIS]; - } - else if (dual_x_carriage_mode == DXC_DUPLICATION_MODE) { - active_extruder_parked = (active_extruder == 0); // this triggers the second extruder to move into the duplication position - if (active_extruder_parked) + if (tmp_extruder >= EXTRUDERS) { + invalid_extruder_error(tmp_extruder); + return; + } + + float stored_feedrate = feedrate; + + if (code_seen('F')) { + float next_feedrate = code_value_axis_units(X_AXIS); + if (next_feedrate > 0.0) stored_feedrate = feedrate = next_feedrate; + } + else + feedrate = XY_PROBE_FEEDRATE; + + if (tmp_extruder != active_extruder) { + bool no_move = code_seen('S') && code_value_bool(); + // Save current position to return to after applying extruder offset + if (!no_move) set_destination_to_current(); + #if ENABLED(DUAL_X_CARRIAGE) + if (dual_x_carriage_mode == DXC_AUTO_PARK_MODE && IsRunning() && + (delayed_move_time || current_position[X_AXIS] != x_home_pos(active_extruder))) { + // Park old head: 1) raise 2) move to park position 3) lower + planner.buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS] + TOOLCHANGE_PARK_ZLIFT, + current_position[E_AXIS], planner.max_feedrate[Z_AXIS], active_extruder); + planner.buffer_line(x_home_pos(active_extruder), current_position[Y_AXIS], current_position[Z_AXIS] + TOOLCHANGE_PARK_ZLIFT, + current_position[E_AXIS], planner.max_feedrate[X_AXIS], active_extruder); + planner.buffer_line(x_home_pos(active_extruder), current_position[Y_AXIS], current_position[Z_AXIS], + current_position[E_AXIS], planner.max_feedrate[Z_AXIS], active_extruder); + stepper.synchronize(); + } + + // apply Y & Z extruder offset (x offset is already used in determining home pos) + current_position[Y_AXIS] -= hotend_offset[Y_AXIS][active_extruder] - hotend_offset[Y_AXIS][tmp_extruder]; + current_position[Z_AXIS] -= hotend_offset[Z_AXIS][active_extruder] - hotend_offset[Z_AXIS][tmp_extruder]; + active_extruder = tmp_extruder; + + // This function resets the max/min values - the current position may be overwritten below. + set_axis_is_at_home(X_AXIS); + + if (dual_x_carriage_mode == DXC_FULL_CONTROL_MODE) { current_position[X_AXIS] = inactive_extruder_x_pos; - else - current_position[X_AXIS] = destination[X_AXIS] + duplicate_extruder_x_offset; - inactive_extruder_x_pos = destination[X_AXIS]; - extruder_duplication_enabled = false; - } - else { - // record raised toolhead position for use by unpark - memcpy(raised_parked_position, current_position, sizeof(raised_parked_position)); - raised_parked_position[Z_AXIS] += TOOLCHANGE_UNPARK_ZLIFT; - active_extruder_parked = true; - delayed_move_time = 0; - } - // No extra case for AUTO_BED_LEVELING_FEATURE in DUAL_X_CARRIAGE. Does that mean they don't work together? - #else // !DUAL_X_CARRIAGE - - // - // Set current_position to the position of the new nozzle. - // Offsets are based on linear distance, so we need to get - // the resulting position in coordinate space. - // - // - With grid or 3-point leveling, offset XYZ by a tilted vector - // - With mesh leveling, update Z for the new position - // - Otherwise, just use the raw linear distance - // - // Software endstops are altered here too. Consider a case where: - // E0 at X=0 ... E1 at X=10 - // When we switch to E1 now X=10, but E1 can't move left. - // To express this we apply the change in XY to the software endstops. - // E1 can move farther right than E0, so the right limit is extended. - // - // Note that we don't adjust the Z software endstops. Why not? - // Consider a case where Z=0 (here) and switching to E1 makes Z=1 - // because the bed is 1mm lower at the new position. As long as - // the first nozzle is out of the way, the carriage should be - // allowed to move 1mm lower. This technically "breaks" the - // Z software endstop. But this is technically correct (and - // there is no viable alternative). - // - float xydiff[2] = { - hotend_offset[X_AXIS][tmp_extruder] - hotend_offset[X_AXIS][active_extruder], - hotend_offset[Y_AXIS][tmp_extruder] - hotend_offset[Y_AXIS][active_extruder] - }; + inactive_extruder_x_pos = destination[X_AXIS]; + } + else if (dual_x_carriage_mode == DXC_DUPLICATION_MODE) { + active_extruder_parked = (active_extruder == 0); // this triggers the second extruder to move into the duplication position + if (active_extruder_parked) + current_position[X_AXIS] = inactive_extruder_x_pos; + else + current_position[X_AXIS] = destination[X_AXIS] + duplicate_extruder_x_offset; + inactive_extruder_x_pos = destination[X_AXIS]; + extruder_duplication_enabled = false; + } + else { + // record raised toolhead position for use by unpark + memcpy(raised_parked_position, current_position, sizeof(raised_parked_position)); + raised_parked_position[Z_AXIS] += TOOLCHANGE_UNPARK_ZLIFT; + active_extruder_parked = true; + delayed_move_time = 0; + } + // No extra case for AUTO_BED_LEVELING_FEATURE in DUAL_X_CARRIAGE. Does that mean they don't work together? + #else // !DUAL_X_CARRIAGE + + // + // Set current_position to the position of the new nozzle. + // Offsets are based on linear distance, so we need to get + // the resulting position in coordinate space. + // + // - With grid or 3-point leveling, offset XYZ by a tilted vector + // - With mesh leveling, update Z for the new position + // - Otherwise, just use the raw linear distance + // + // Software endstops are altered here too. Consider a case where: + // E0 at X=0 ... E1 at X=10 + // When we switch to E1 now X=10, but E1 can't move left. + // To express this we apply the change in XY to the software endstops. + // E1 can move farther right than E0, so the right limit is extended. + // + // Note that we don't adjust the Z software endstops. Why not? + // Consider a case where Z=0 (here) and switching to E1 makes Z=1 + // because the bed is 1mm lower at the new position. As long as + // the first nozzle is out of the way, the carriage should be + // allowed to move 1mm lower. This technically "breaks" the + // Z software endstop. But this is technically correct (and + // there is no viable alternative). + // + float xydiff[2] = { + hotend_offset[X_AXIS][tmp_extruder] - hotend_offset[X_AXIS][active_extruder], + hotend_offset[Y_AXIS][tmp_extruder] - hotend_offset[Y_AXIS][active_extruder] + }; + + #if ENABLED(AUTO_BED_LEVELING_FEATURE) + // Offset extruder, make sure to apply the bed level rotation matrix + vector_3 tmp_offset_vec = vector_3(hotend_offset[X_AXIS][tmp_extruder], + hotend_offset[Y_AXIS][tmp_extruder], + 0), + act_offset_vec = vector_3(hotend_offset[X_AXIS][active_extruder], + hotend_offset[Y_AXIS][active_extruder], + 0), + offset_vec = tmp_offset_vec - act_offset_vec; - #if ENABLED(AUTO_BED_LEVELING_FEATURE) - // Offset extruder, make sure to apply the bed level rotation matrix - vector_3 tmp_offset_vec = vector_3(hotend_offset[X_AXIS][tmp_extruder], - hotend_offset[Y_AXIS][tmp_extruder], - 0), - act_offset_vec = vector_3(hotend_offset[X_AXIS][active_extruder], - hotend_offset[Y_AXIS][active_extruder], - 0), - offset_vec = tmp_offset_vec - act_offset_vec; + #if ENABLED(DEBUG_LEVELING_FEATURE) + if (DEBUGGING(LEVELING)) { + SERIAL_ECHOLNPGM(">>> gcode_T"); + tmp_offset_vec.debug("tmp_offset_vec"); + act_offset_vec.debug("act_offset_vec"); + offset_vec.debug("offset_vec (BEFORE)"); + DEBUG_POS("BEFORE rotation", current_position); + } + #endif - #if ENABLED(DEBUG_LEVELING_FEATURE) - if (DEBUGGING(LEVELING)) { - SERIAL_ECHOLNPGM(">>> gcode_T"); - tmp_offset_vec.debug("tmp_offset_vec"); - act_offset_vec.debug("act_offset_vec"); - offset_vec.debug("offset_vec (BEFORE)"); - DEBUG_POS("BEFORE rotation", current_position); - } - #endif + offset_vec.apply_rotation(planner.bed_level_matrix.transpose(planner.bed_level_matrix)); - offset_vec.apply_rotation(planner.bed_level_matrix.transpose(planner.bed_level_matrix)); + // Adjust the current position + current_position[X_AXIS] += offset_vec.x; + current_position[Y_AXIS] += offset_vec.y; + current_position[Z_AXIS] += offset_vec.z; - // Adjust the current position - current_position[X_AXIS] += offset_vec.x; - current_position[Y_AXIS] += offset_vec.y; - current_position[Z_AXIS] += offset_vec.z; + #if ENABLED(DEBUG_LEVELING_FEATURE) + if (DEBUGGING(LEVELING)) { + offset_vec.debug("offset_vec (AFTER)"); + DEBUG_POS("AFTER rotation", current_position); + SERIAL_ECHOLNPGM("<<< gcode_T"); + } + #endif - #if ENABLED(DEBUG_LEVELING_FEATURE) - if (DEBUGGING(LEVELING)) { - offset_vec.debug("offset_vec (AFTER)"); - DEBUG_POS("AFTER rotation", current_position); - SERIAL_ECHOLNPGM("<<< gcode_T"); + #elif ENABLED(MESH_BED_LEVELING) + + if (mbl.active()) { + float xpos = current_position[X_AXIS] - home_offset[X_AXIS], + ypos = current_position[Y_AXIS] - home_offset[Y_AXIS]; + current_position[Z_AXIS] += mbl.get_z(xpos + xydiff[X_AXIS], ypos + xydiff[Y_AXIS]) - mbl.get_z(xpos, ypos); } - #endif - #elif ENABLED(MESH_BED_LEVELING) + #else // no bed leveling - if (mbl.active()) { - float xpos = current_position[X_AXIS] - home_offset[X_AXIS], - ypos = current_position[Y_AXIS] - home_offset[Y_AXIS]; - current_position[Z_AXIS] += mbl.get_z(xpos + xydiff[X_AXIS], ypos + xydiff[Y_AXIS]) - mbl.get_z(xpos, ypos); - } + // The newly-selected extruder XY is actually at... + current_position[X_AXIS] += xydiff[X_AXIS]; + current_position[Y_AXIS] += xydiff[Y_AXIS]; - #else // no bed leveling + #endif // no bed leveling - // The newly-selected extruder XY is actually at... - current_position[X_AXIS] += xydiff[X_AXIS]; - current_position[Y_AXIS] += xydiff[Y_AXIS]; - - #endif // no bed leveling + for (uint8_t i = X_AXIS; i <= Y_AXIS; i++) { + position_shift[i] += xydiff[i]; + update_software_endstops((AxisEnum)i); + } - for (uint8_t i = X_AXIS; i <= Y_AXIS; i++) { - position_shift[i] += xydiff[i]; - update_software_endstops((AxisEnum)i); - } + // Set the new active extruder + active_extruder = tmp_extruder; - // Set the new active extruder - active_extruder = tmp_extruder; + #endif // !DUAL_X_CARRIAGE - #endif // !DUAL_X_CARRIAGE + // Tell the planner the new "current position" + SYNC_PLAN_POSITION_KINEMATIC(); - // Tell the planner the new "current position" - SYNC_PLAN_POSITION_KINEMATIC(); + // Move to the "old position" (move the extruder into place) + if (!no_move && IsRunning()) prepare_move_to_destination(); - // Move to the "old position" (move the extruder into place) - if (!no_move && IsRunning()) prepare_move_to_destination(); + } // (tmp_extruder != active_extruder) - } // (tmp_extruder != active_extruder) + #if ENABLED(EXT_SOLENOID) + stepper.synchronize(); + disable_all_solenoids(); + enable_solenoid_on_active_extruder(); + #endif // EXT_SOLENOID - #if ENABLED(EXT_SOLENOID) - stepper.synchronize(); - disable_all_solenoids(); - enable_solenoid_on_active_extruder(); - #endif // EXT_SOLENOID + feedrate = stored_feedrate; - feedrate = stored_feedrate; + #else // HOTENDS <= 1 - #else // !HOTENDS > 1 + // Set the new active extruder + active_extruder = tmp_extruder; - // Set the new active extruder - active_extruder = tmp_extruder; + #endif // HOTENDS <= 1 - #endif + SERIAL_ECHO_START; + SERIAL_ECHOPGM(MSG_ACTIVE_EXTRUDER); + SERIAL_PROTOCOLLN((int)active_extruder); - SERIAL_ECHO_START; - SERIAL_ECHOPGM(MSG_ACTIVE_EXTRUDER); - SERIAL_PROTOCOLLN((int)active_extruder); + #endif //!MIXING_EXTRUDER || MIXING_VIRTUAL_TOOLS <= 1 } /** @@ -7012,6 +7140,20 @@ void process_next_command() { #endif //EXPERIMENTAL_I2CBUS + #if ENABLED(MIXING_EXTRUDER) + case 163: // M163 S P set weight for a mixing extruder + gcode_M163(); + break; + #if MIXING_VIRTUAL_TOOLS > 1 + case 164: // M164 S save current mix as a virtual extruder + gcode_M164(); + break; + #endif + case 165: // M165 [ABCDHI] set multiple mix weights + gcode_M165(); + break; + #endif + case 200: // M200 D set filament diameter and set E axis units to cubic millimeters (use S0 to set back to millimeters). gcode_M200(); break; diff --git a/Marlin/SanityCheck.h b/Marlin/SanityCheck.h index 81e2db8bd052..917ced9c0599 100644 --- a/Marlin/SanityCheck.h +++ b/Marlin/SanityCheck.h @@ -468,6 +468,21 @@ #endif #endif // DUAL_X_CARRIAGE +/** + * Mixing Extruder requirements + */ +#if ENABLED(MIXING_EXTRUDER) + #if EXTRUDERS > 1 + #error "MIXING_EXTRUDER currently only supports one extruder." + #endif + #if MIXING_STEPPERS < 2 + #error "You must set MIXING_STEPPERS >= 2 for a mixing extruder." + #endif + #if ENABLED(FILAMENT_SENSOR) + #error "MIXING_EXTRUDER is incompatible with FILAMENT_SENSOR. Comment out this line to use it anyway." + #endif +#endif + /** * Make sure auto fan pins don't conflict with the fan pin */ diff --git a/Marlin/example_configurations/Cartesio/Configuration.h b/Marlin/example_configurations/Cartesio/Configuration.h index 915be5b55a20..73713db866a5 100644 --- a/Marlin/example_configurations/Cartesio/Configuration.h +++ b/Marlin/example_configurations/Cartesio/Configuration.h @@ -133,20 +133,34 @@ // :[1,2,3,4] #define EXTRUDERS 3 -// For Cyclops or any "multi-extruder" that shares a single nozzle. -//#define SINGLENOZZLE - // Offset of the extruders (uncomment if using more than one and relying on firmware to position when changing). // The offset has to be X=0, Y=0 for the extruder 0 hotend (default extruder). // For the other hotends it is their distance from the extruder 0 hotend. //#define HOTEND_OFFSET_X {0.0, 20.00} // (in mm) for each extruder, offset of the hotend on the X axis //#define HOTEND_OFFSET_Y {0.0, 5.00} // (in mm) for each extruder, offset of the hotend on the Y axis +// For Cyclops or any "multi-extruder" that shares a single nozzle. +//#define SINGLENOZZLE + +/** + * "Mixing Extruder" + * - Adds a new code, M165, to set the current mix factors. + * - Extends the stepping routines to move multiple steppers in proportion to the mix. + * - Optional support for Repetier Host M163, M164, and virtual extruder. + * - This implementation supports only a single extruder. + * - Enable DIRECT_MIXING_IN_G1 for Pia Taubert's reference implementation + */ +//#define MIXING_EXTRUDER +#ifdef MIXING_EXTRUDER + #define MIXING_STEPPERS 2 // Number of steppers in your mixing extruder + #define MIXING_VIRTUAL_TOOLS 16 // Use the Virtual Tool method with M163 and M164 + //#define DIRECT_MIXING_IN_G1 // Allow ABCDHI mix factors in G1 movement commands +#endif + //// The following define selects which power supply you have. Please choose the one that matches your setup // 1 = ATX // 2 = X-Box 360 203Watts (the blue wire connected to PS_ON and the red wire to VCC) // :{1:'ATX',2:'X-Box 360'} - #define POWER_SUPPLY 1 // Define this to have the electronics keep the power supply off on startup. If you don't know what this is leave it. diff --git a/Marlin/example_configurations/Felix/Configuration.h b/Marlin/example_configurations/Felix/Configuration.h index 62aa357f8cbd..08f5b04e511f 100644 --- a/Marlin/example_configurations/Felix/Configuration.h +++ b/Marlin/example_configurations/Felix/Configuration.h @@ -133,20 +133,34 @@ // :[1,2,3,4] #define EXTRUDERS 1 -// For Cyclops or any "multi-extruder" that shares a single nozzle. -//#define SINGLENOZZLE - // Offset of the extruders (uncomment if using more than one and relying on firmware to position when changing). // The offset has to be X=0, Y=0 for the extruder 0 hotend (default extruder). // For the other hotends it is their distance from the extruder 0 hotend. //#define HOTEND_OFFSET_X {0.0, 20.00} // (in mm) for each extruder, offset of the hotend on the X axis //#define HOTEND_OFFSET_Y {0.0, 5.00} // (in mm) for each extruder, offset of the hotend on the Y axis +// For Cyclops or any "multi-extruder" that shares a single nozzle. +//#define SINGLENOZZLE + +/** + * "Mixing Extruder" + * - Adds a new code, M165, to set the current mix factors. + * - Extends the stepping routines to move multiple steppers in proportion to the mix. + * - Optional support for Repetier Host M163, M164, and virtual extruder. + * - This implementation supports only a single extruder. + * - Enable DIRECT_MIXING_IN_G1 for Pia Taubert's reference implementation + */ +//#define MIXING_EXTRUDER +#ifdef MIXING_EXTRUDER + #define MIXING_STEPPERS 2 // Number of steppers in your mixing extruder + #define MIXING_VIRTUAL_TOOLS 16 // Use the Virtual Tool method with M163 and M164 + //#define DIRECT_MIXING_IN_G1 // Allow ABCDHI mix factors in G1 movement commands +#endif + //// The following define selects which power supply you have. Please choose the one that matches your setup // 1 = ATX // 2 = X-Box 360 203Watts (the blue wire connected to PS_ON and the red wire to VCC) // :{1:'ATX',2:'X-Box 360'} - #define POWER_SUPPLY 1 // Define this to have the electronics keep the power supply off on startup. If you don't know what this is leave it. diff --git a/Marlin/example_configurations/Felix/DUAL/Configuration.h b/Marlin/example_configurations/Felix/DUAL/Configuration.h index e20fa1211836..f6f7c02ba918 100644 --- a/Marlin/example_configurations/Felix/DUAL/Configuration.h +++ b/Marlin/example_configurations/Felix/DUAL/Configuration.h @@ -133,20 +133,34 @@ // :[1,2,3,4] #define EXTRUDERS 2 -// For Cyclops or any "multi-extruder" that shares a single nozzle. -//#define SINGLENOZZLE - // Offset of the extruders (uncomment if using more than one and relying on firmware to position when changing). // The offset has to be X=0, Y=0 for the extruder 0 hotend (default extruder). // For the other hotends it is their distance from the extruder 0 hotend. //#define HOTEND_OFFSET_X {0.0, 20.00} // (in mm) for each extruder, offset of the hotend on the X axis //#define HOTEND_OFFSET_Y {0.0, 5.00} // (in mm) for each extruder, offset of the hotend on the Y axis +// For Cyclops or any "multi-extruder" that shares a single nozzle. +//#define SINGLENOZZLE + +/** + * "Mixing Extruder" + * - Adds a new code, M165, to set the current mix factors. + * - Extends the stepping routines to move multiple steppers in proportion to the mix. + * - Optional support for Repetier Host M163, M164, and virtual extruder. + * - This implementation supports only a single extruder. + * - Enable DIRECT_MIXING_IN_G1 for Pia Taubert's reference implementation + */ +//#define MIXING_EXTRUDER +#ifdef MIXING_EXTRUDER + #define MIXING_STEPPERS 2 // Number of steppers in your mixing extruder + #define MIXING_VIRTUAL_TOOLS 16 // Use the Virtual Tool method with M163 and M164 + //#define DIRECT_MIXING_IN_G1 // Allow ABCDHI mix factors in G1 movement commands +#endif + //// The following define selects which power supply you have. Please choose the one that matches your setup // 1 = ATX // 2 = X-Box 360 203Watts (the blue wire connected to PS_ON and the red wire to VCC) // :{1:'ATX',2:'X-Box 360'} - #define POWER_SUPPLY 1 // Define this to have the electronics keep the power supply off on startup. If you don't know what this is leave it. diff --git a/Marlin/example_configurations/Hephestos/Configuration.h b/Marlin/example_configurations/Hephestos/Configuration.h index a1995b3b3585..0c0e158f7a3f 100644 --- a/Marlin/example_configurations/Hephestos/Configuration.h +++ b/Marlin/example_configurations/Hephestos/Configuration.h @@ -136,20 +136,34 @@ // :[1,2,3,4] #define EXTRUDERS 1 -// For Cyclops or any "multi-extruder" that shares a single nozzle. -//#define SINGLENOZZLE - // Offset of the extruders (uncomment if using more than one and relying on firmware to position when changing). // The offset has to be X=0, Y=0 for the extruder 0 hotend (default extruder). // For the other hotends it is their distance from the extruder 0 hotend. //#define HOTEND_OFFSET_X {0.0, 20.00} // (in mm) for each extruder, offset of the hotend on the X axis //#define HOTEND_OFFSET_Y {0.0, 5.00} // (in mm) for each extruder, offset of the hotend on the Y axis +// For Cyclops or any "multi-extruder" that shares a single nozzle. +//#define SINGLENOZZLE + +/** + * "Mixing Extruder" + * - Adds a new code, M165, to set the current mix factors. + * - Extends the stepping routines to move multiple steppers in proportion to the mix. + * - Optional support for Repetier Host M163, M164, and virtual extruder. + * - This implementation supports only a single extruder. + * - Enable DIRECT_MIXING_IN_G1 for Pia Taubert's reference implementation + */ +//#define MIXING_EXTRUDER +#ifdef MIXING_EXTRUDER + #define MIXING_STEPPERS 2 // Number of steppers in your mixing extruder + #define MIXING_VIRTUAL_TOOLS 16 // Use the Virtual Tool method with M163 and M164 + //#define DIRECT_MIXING_IN_G1 // Allow ABCDHI mix factors in G1 movement commands +#endif + //// The following define selects which power supply you have. Please choose the one that matches your setup // 1 = ATX // 2 = X-Box 360 203Watts (the blue wire connected to PS_ON and the red wire to VCC) // :{1:'ATX',2:'X-Box 360'} - #define POWER_SUPPLY 1 // Define this to have the electronics keep the power supply off on startup. If you don't know what this is leave it. diff --git a/Marlin/example_configurations/Hephestos_2/Configuration.h b/Marlin/example_configurations/Hephestos_2/Configuration.h index f15ad7a4892e..358f2fdf1cec 100644 --- a/Marlin/example_configurations/Hephestos_2/Configuration.h +++ b/Marlin/example_configurations/Hephestos_2/Configuration.h @@ -133,20 +133,34 @@ // :[1,2,3,4] #define EXTRUDERS 1 -// For Cyclops or any "multi-extruder" that shares a single nozzle. -//#define SINGLENOZZLE - // Offset of the extruders (uncomment if using more than one and relying on firmware to position when changing). // The offset has to be X=0, Y=0 for the extruder 0 hotend (default extruder). // For the other hotends it is their distance from the extruder 0 hotend. //#define HOTEND_OFFSET_X {0.0, 20.00} // (in mm) for each extruder, offset of the hotend on the X axis //#define HOTEND_OFFSET_Y {0.0, 5.00} // (in mm) for each extruder, offset of the hotend on the Y axis +// For Cyclops or any "multi-extruder" that shares a single nozzle. +//#define SINGLENOZZLE + +/** + * "Mixing Extruder" + * - Adds a new code, M165, to set the current mix factors. + * - Extends the stepping routines to move multiple steppers in proportion to the mix. + * - Optional support for Repetier Host M163, M164, and virtual extruder. + * - This implementation supports only a single extruder. + * - Enable DIRECT_MIXING_IN_G1 for Pia Taubert's reference implementation + */ +//#define MIXING_EXTRUDER +#ifdef MIXING_EXTRUDER + #define MIXING_STEPPERS 2 // Number of steppers in your mixing extruder + #define MIXING_VIRTUAL_TOOLS 16 // Use the Virtual Tool method with M163 and M164 + //#define DIRECT_MIXING_IN_G1 // Allow ABCDHI mix factors in G1 movement commands +#endif + //// The following define selects which power supply you have. Please choose the one that matches your setup // 1 = ATX // 2 = X-Box 360 203Watts (the blue wire connected to PS_ON and the red wire to VCC) // :{1:'ATX',2:'X-Box 360'} - #define POWER_SUPPLY 1 // Define this to have the electronics keep the power supply off on startup. If you don't know what this is leave it. diff --git a/Marlin/example_configurations/K8200/Configuration.h b/Marlin/example_configurations/K8200/Configuration.h index 54362c250627..d1b334c8fde7 100644 --- a/Marlin/example_configurations/K8200/Configuration.h +++ b/Marlin/example_configurations/K8200/Configuration.h @@ -140,20 +140,34 @@ // :[1,2,3,4] #define EXTRUDERS 1 -// For Cyclops or any "multi-extruder" that shares a single nozzle. -//#define SINGLENOZZLE - // Offset of the extruders (uncomment if using more than one and relying on firmware to position when changing). // The offset has to be X=0, Y=0 for the extruder 0 hotend (default extruder). // For the other hotends it is their distance from the extruder 0 hotend. //#define HOTEND_OFFSET_X {0.0, 20.00} // (in mm) for each extruder, offset of the hotend on the X axis //#define HOTEND_OFFSET_Y {0.0, 5.00} // (in mm) for each extruder, offset of the hotend on the Y axis +// For Cyclops or any "multi-extruder" that shares a single nozzle. +//#define SINGLENOZZLE + +/** + * "Mixing Extruder" + * - Adds a new code, M165, to set the current mix factors. + * - Extends the stepping routines to move multiple steppers in proportion to the mix. + * - Optional support for Repetier Host M163, M164, and virtual extruder. + * - This implementation supports only a single extruder. + * - Enable DIRECT_MIXING_IN_G1 for Pia Taubert's reference implementation + */ +//#define MIXING_EXTRUDER +#ifdef MIXING_EXTRUDER + #define MIXING_STEPPERS 2 // Number of steppers in your mixing extruder + #define MIXING_VIRTUAL_TOOLS 16 // Use the Virtual Tool method with M163 and M164 + //#define DIRECT_MIXING_IN_G1 // Allow ABCDHI mix factors in G1 movement commands +#endif + //// The following define selects which power supply you have. Please choose the one that matches your setup // 1 = ATX // 2 = X-Box 360 203Watts (the blue wire connected to PS_ON and the red wire to VCC) // :{1:'ATX',2:'X-Box 360'} - #define POWER_SUPPLY 1 // Define this to have the electronics keep the power supply off on startup. If you don't know what this is leave it. diff --git a/Marlin/example_configurations/RepRapWorld/Megatronics/Configuration.h b/Marlin/example_configurations/RepRapWorld/Megatronics/Configuration.h index 356c706c896f..0daafd0877c3 100644 --- a/Marlin/example_configurations/RepRapWorld/Megatronics/Configuration.h +++ b/Marlin/example_configurations/RepRapWorld/Megatronics/Configuration.h @@ -133,20 +133,34 @@ // :[1,2,3,4] #define EXTRUDERS 1 -// For Cyclops or any "multi-extruder" that shares a single nozzle. -//#define SINGLENOZZLE - // Offset of the extruders (uncomment if using more than one and relying on firmware to position when changing). // The offset has to be X=0, Y=0 for the extruder 0 hotend (default extruder). // For the other hotends it is their distance from the extruder 0 hotend. //#define HOTEND_OFFSET_X {0.0, 20.00} // (in mm) for each extruder, offset of the hotend on the X axis //#define HOTEND_OFFSET_Y {0.0, 5.00} // (in mm) for each extruder, offset of the hotend on the Y axis +// For Cyclops or any "multi-extruder" that shares a single nozzle. +//#define SINGLENOZZLE + +/** + * "Mixing Extruder" + * - Adds a new code, M165, to set the current mix factors. + * - Extends the stepping routines to move multiple steppers in proportion to the mix. + * - Optional support for Repetier Host M163, M164, and virtual extruder. + * - This implementation supports only a single extruder. + * - Enable DIRECT_MIXING_IN_G1 for Pia Taubert's reference implementation + */ +//#define MIXING_EXTRUDER +#ifdef MIXING_EXTRUDER + #define MIXING_STEPPERS 2 // Number of steppers in your mixing extruder + #define MIXING_VIRTUAL_TOOLS 16 // Use the Virtual Tool method with M163 and M164 + //#define DIRECT_MIXING_IN_G1 // Allow ABCDHI mix factors in G1 movement commands +#endif + //// The following define selects which power supply you have. Please choose the one that matches your setup // 1 = ATX // 2 = X-Box 360 203Watts (the blue wire connected to PS_ON and the red wire to VCC) // :{1:'ATX',2:'X-Box 360'} - #define POWER_SUPPLY 1 // Define this to have the electronics keep the power supply off on startup. If you don't know what this is leave it. diff --git a/Marlin/example_configurations/RigidBot/Configuration.h b/Marlin/example_configurations/RigidBot/Configuration.h index a0abbeda8845..1c58af052bb5 100644 --- a/Marlin/example_configurations/RigidBot/Configuration.h +++ b/Marlin/example_configurations/RigidBot/Configuration.h @@ -136,20 +136,34 @@ // :[1,2,3,4] #define EXTRUDERS 1 // Single extruder. Set to 2 for dual extruders -// For Cyclops or any "multi-extruder" that shares a single nozzle. -//#define SINGLENOZZLE - // Offset of the extruders (uncomment if using more than one and relying on firmware to position when changing). // The offset has to be X=0, Y=0 for the extruder 0 hotend (default extruder). // For the other hotends it is their distance from the extruder 0 hotend. #define HOTEND_OFFSET_X {0.0, 36.00} // (in mm) for each extruder, offset of the hotend on the X axis #define HOTEND_OFFSET_Y {0.0, 0.00} // (in mm) for each extruder, offset of the hotend on the Y axis +// For Cyclops or any "multi-extruder" that shares a single nozzle. +//#define SINGLENOZZLE + +/** + * "Mixing Extruder" + * - Adds a new code, M165, to set the current mix factors. + * - Extends the stepping routines to move multiple steppers in proportion to the mix. + * - Optional support for Repetier Host M163, M164, and virtual extruder. + * - This implementation supports only a single extruder. + * - Enable DIRECT_MIXING_IN_G1 for Pia Taubert's reference implementation + */ +//#define MIXING_EXTRUDER +#ifdef MIXING_EXTRUDER + #define MIXING_STEPPERS 2 // Number of steppers in your mixing extruder + #define MIXING_VIRTUAL_TOOLS 16 // Use the Virtual Tool method with M163 and M164 + //#define DIRECT_MIXING_IN_G1 // Allow ABCDHI mix factors in G1 movement commands +#endif + //// The following define selects which power supply you have. Please choose the one that matches your setup // 1 = ATX // 2 = X-Box 360 203Watts (the blue wire connected to PS_ON and the red wire to VCC) // :{1:'ATX',2:'X-Box 360'} - #define POWER_SUPPLY 1 // Define this to have the electronics keep the power supply off on startup. If you don't know what this is leave it. diff --git a/Marlin/example_configurations/SCARA/Configuration.h b/Marlin/example_configurations/SCARA/Configuration.h index cc10ca773fcd..048d0e92ddd0 100644 --- a/Marlin/example_configurations/SCARA/Configuration.h +++ b/Marlin/example_configurations/SCARA/Configuration.h @@ -158,20 +158,34 @@ // :[1,2,3,4] #define EXTRUDERS 1 -// For Cyclops or any "multi-extruder" that shares a single nozzle. -//#define SINGLENOZZLE - // Offset of the extruders (uncomment if using more than one and relying on firmware to position when changing). // The offset has to be X=0, Y=0 for the extruder 0 hotend (default extruder). // For the other hotends it is their distance from the extruder 0 hotend. //#define HOTEND_OFFSET_X {0.0, 20.00} // (in mm) for each extruder, offset of the hotend on the X axis //#define HOTEND_OFFSET_Y {0.0, 5.00} // (in mm) for each extruder, offset of the hotend on the Y axis +// For Cyclops or any "multi-extruder" that shares a single nozzle. +//#define SINGLENOZZLE + +/** + * "Mixing Extruder" + * - Adds a new code, M165, to set the current mix factors. + * - Extends the stepping routines to move multiple steppers in proportion to the mix. + * - Optional support for Repetier Host M163, M164, and virtual extruder. + * - This implementation supports only a single extruder. + * - Enable DIRECT_MIXING_IN_G1 for Pia Taubert's reference implementation + */ +//#define MIXING_EXTRUDER +#ifdef MIXING_EXTRUDER + #define MIXING_STEPPERS 2 // Number of steppers in your mixing extruder + #define MIXING_VIRTUAL_TOOLS 16 // Use the Virtual Tool method with M163 and M164 + //#define DIRECT_MIXING_IN_G1 // Allow ABCDHI mix factors in G1 movement commands +#endif + //// The following define selects which power supply you have. Please choose the one that matches your setup // 1 = ATX // 2 = X-Box 360 203Watts (the blue wire connected to PS_ON and the red wire to VCC) // :{1:'ATX',2:'X-Box 360'} - #define POWER_SUPPLY 1 // Define this to have the electronics keep the power supply off on startup. If you don't know what this is leave it. diff --git a/Marlin/example_configurations/TAZ4/Configuration.h b/Marlin/example_configurations/TAZ4/Configuration.h index 77a5b1d96ce6..f24f0fb5e226 100644 --- a/Marlin/example_configurations/TAZ4/Configuration.h +++ b/Marlin/example_configurations/TAZ4/Configuration.h @@ -133,20 +133,34 @@ // :[1,2,3,4] #define EXTRUDERS 1 -// For Cyclops or any "multi-extruder" that shares a single nozzle. -//#define SINGLENOZZLE - // Offset of the extruders (uncomment if using more than one and relying on firmware to position when changing). // The offset has to be X=0, Y=0 for the extruder 0 hotend (default extruder). // For the other hotends it is their distance from the extruder 0 hotend. //#define HOTEND_OFFSET_X {0.0, 20.00} // (in mm) for each extruder, offset of the hotend on the X axis //#define HOTEND_OFFSET_Y {0.0, 5.00} // (in mm) for each extruder, offset of the hotend on the Y axis +// For Cyclops or any "multi-extruder" that shares a single nozzle. +//#define SINGLENOZZLE + +/** + * "Mixing Extruder" + * - Adds a new code, M165, to set the current mix factors. + * - Extends the stepping routines to move multiple steppers in proportion to the mix. + * - Optional support for Repetier Host M163, M164, and virtual extruder. + * - This implementation supports only a single extruder. + * - Enable DIRECT_MIXING_IN_G1 for Pia Taubert's reference implementation + */ +//#define MIXING_EXTRUDER +#ifdef MIXING_EXTRUDER + #define MIXING_STEPPERS 2 // Number of steppers in your mixing extruder + #define MIXING_VIRTUAL_TOOLS 16 // Use the Virtual Tool method with M163 and M164 + //#define DIRECT_MIXING_IN_G1 // Allow ABCDHI mix factors in G1 movement commands +#endif + //// The following define selects which power supply you have. Please choose the one that matches your setup // 1 = ATX // 2 = X-Box 360 203Watts (the blue wire connected to PS_ON and the red wire to VCC) // :{1:'ATX',2:'X-Box 360'} - #define POWER_SUPPLY 1 // Define this to have the electronics keep the power supply off on startup. If you don't know what this is leave it. diff --git a/Marlin/example_configurations/WITBOX/Configuration.h b/Marlin/example_configurations/WITBOX/Configuration.h index b560808722fe..55099e0b2f83 100644 --- a/Marlin/example_configurations/WITBOX/Configuration.h +++ b/Marlin/example_configurations/WITBOX/Configuration.h @@ -136,20 +136,34 @@ // :[1,2,3,4] #define EXTRUDERS 1 -// For Cyclops or any "multi-extruder" that shares a single nozzle. -//#define SINGLENOZZLE - // Offset of the extruders (uncomment if using more than one and relying on firmware to position when changing). // The offset has to be X=0, Y=0 for the extruder 0 hotend (default extruder). // For the other hotends it is their distance from the extruder 0 hotend. //#define HOTEND_OFFSET_X {0.0, 20.00} // (in mm) for each extruder, offset of the hotend on the X axis //#define HOTEND_OFFSET_Y {0.0, 5.00} // (in mm) for each extruder, offset of the hotend on the Y axis +// For Cyclops or any "multi-extruder" that shares a single nozzle. +//#define SINGLENOZZLE + +/** + * "Mixing Extruder" + * - Adds a new code, M165, to set the current mix factors. + * - Extends the stepping routines to move multiple steppers in proportion to the mix. + * - Optional support for Repetier Host M163, M164, and virtual extruder. + * - This implementation supports only a single extruder. + * - Enable DIRECT_MIXING_IN_G1 for Pia Taubert's reference implementation + */ +//#define MIXING_EXTRUDER +#ifdef MIXING_EXTRUDER + #define MIXING_STEPPERS 2 // Number of steppers in your mixing extruder + #define MIXING_VIRTUAL_TOOLS 16 // Use the Virtual Tool method with M163 and M164 + //#define DIRECT_MIXING_IN_G1 // Allow ABCDHI mix factors in G1 movement commands +#endif + //// The following define selects which power supply you have. Please choose the one that matches your setup // 1 = ATX // 2 = X-Box 360 203Watts (the blue wire connected to PS_ON and the red wire to VCC) // :{1:'ATX',2:'X-Box 360'} - #define POWER_SUPPLY 1 // Define this to have the electronics keep the power supply off on startup. If you don't know what this is leave it. diff --git a/Marlin/example_configurations/adafruit/ST7565/Configuration.h b/Marlin/example_configurations/adafruit/ST7565/Configuration.h index 5039f64e93db..65915c7e8e88 100644 --- a/Marlin/example_configurations/adafruit/ST7565/Configuration.h +++ b/Marlin/example_configurations/adafruit/ST7565/Configuration.h @@ -133,20 +133,34 @@ // :[1,2,3,4] #define EXTRUDERS 1 -// For Cyclops or any "multi-extruder" that shares a single nozzle. -//#define SINGLENOZZLE - // Offset of the extruders (uncomment if using more than one and relying on firmware to position when changing). // The offset has to be X=0, Y=0 for the extruder 0 hotend (default extruder). // For the other hotends it is their distance from the extruder 0 hotend. //#define HOTEND_OFFSET_X {0.0, 20.00} // (in mm) for each extruder, offset of the hotend on the X axis //#define HOTEND_OFFSET_Y {0.0, 5.00} // (in mm) for each extruder, offset of the hotend on the Y axis +// For Cyclops or any "multi-extruder" that shares a single nozzle. +//#define SINGLENOZZLE + +/** + * "Mixing Extruder" + * - Adds a new code, M165, to set the current mix factors. + * - Extends the stepping routines to move multiple steppers in proportion to the mix. + * - Optional support for Repetier Host M163, M164, and virtual extruder. + * - This implementation supports only a single extruder. + * - Enable DIRECT_MIXING_IN_G1 for Pia Taubert's reference implementation + */ +//#define MIXING_EXTRUDER +#ifdef MIXING_EXTRUDER + #define MIXING_STEPPERS 2 // Number of steppers in your mixing extruder + #define MIXING_VIRTUAL_TOOLS 16 // Use the Virtual Tool method with M163 and M164 + //#define DIRECT_MIXING_IN_G1 // Allow ABCDHI mix factors in G1 movement commands +#endif + //// The following define selects which power supply you have. Please choose the one that matches your setup // 1 = ATX // 2 = X-Box 360 203Watts (the blue wire connected to PS_ON and the red wire to VCC) // :{1:'ATX',2:'X-Box 360'} - #define POWER_SUPPLY 1 // Define this to have the electronics keep the power supply off on startup. If you don't know what this is leave it. diff --git a/Marlin/example_configurations/delta/biv2.5/Configuration.h b/Marlin/example_configurations/delta/biv2.5/Configuration.h index aca16d02d6f9..6ad686723887 100644 --- a/Marlin/example_configurations/delta/biv2.5/Configuration.h +++ b/Marlin/example_configurations/delta/biv2.5/Configuration.h @@ -133,20 +133,34 @@ // :[1,2,3,4] #define EXTRUDERS 2 -// For Cyclops or any "multi-extruder" that shares a single nozzle. -//#define SINGLENOZZLE - // Offset of the extruders (uncomment if using more than one and relying on firmware to position when changing). // The offset has to be X=0, Y=0 for the extruder 0 hotend (default extruder). // For the other hotends it is their distance from the extruder 0 hotend. //#define HOTEND_OFFSET_X {0.0, 20.00} // (in mm) for each extruder, offset of the hotend on the X axis //#define HOTEND_OFFSET_Y {0.0, 5.00} // (in mm) for each extruder, offset of the hotend on the Y axis +// For Cyclops or any "multi-extruder" that shares a single nozzle. +//#define SINGLENOZZLE + +/** + * "Mixing Extruder" + * - Adds a new code, M165, to set the current mix factors. + * - Extends the stepping routines to move multiple steppers in proportion to the mix. + * - Optional support for Repetier Host M163, M164, and virtual extruder. + * - This implementation supports only a single extruder. + * - Enable DIRECT_MIXING_IN_G1 for Pia Taubert's reference implementation + */ +//#define MIXING_EXTRUDER +#ifdef MIXING_EXTRUDER + #define MIXING_STEPPERS 2 // Number of steppers in your mixing extruder + #define MIXING_VIRTUAL_TOOLS 16 // Use the Virtual Tool method with M163 and M164 + //#define DIRECT_MIXING_IN_G1 // Allow ABCDHI mix factors in G1 movement commands +#endif + //// The following define selects which power supply you have. Please choose the one that matches your setup // 1 = ATX // 2 = X-Box 360 203Watts (the blue wire connected to PS_ON and the red wire to VCC) // :{1:'ATX',2:'X-Box 360'} - #define POWER_SUPPLY 1 // Define this to have the electronics keep the power supply off on startup. If you don't know what this is leave it. diff --git a/Marlin/example_configurations/delta/generic/Configuration.h b/Marlin/example_configurations/delta/generic/Configuration.h index 5e2afed02713..2c7a251fe67e 100644 --- a/Marlin/example_configurations/delta/generic/Configuration.h +++ b/Marlin/example_configurations/delta/generic/Configuration.h @@ -133,20 +133,34 @@ // :[1,2,3,4] #define EXTRUDERS 1 -// For Cyclops or any "multi-extruder" that shares a single nozzle. -//#define SINGLENOZZLE - // Offset of the extruders (uncomment if using more than one and relying on firmware to position when changing). // The offset has to be X=0, Y=0 for the extruder 0 hotend (default extruder). // For the other hotends it is their distance from the extruder 0 hotend. //#define HOTEND_OFFSET_X {0.0, 20.00} // (in mm) for each extruder, offset of the hotend on the X axis //#define HOTEND_OFFSET_Y {0.0, 5.00} // (in mm) for each extruder, offset of the hotend on the Y axis +// For Cyclops or any "multi-extruder" that shares a single nozzle. +//#define SINGLENOZZLE + +/** + * "Mixing Extruder" + * - Adds a new code, M165, to set the current mix factors. + * - Extends the stepping routines to move multiple steppers in proportion to the mix. + * - Optional support for Repetier Host M163, M164, and virtual extruder. + * - This implementation supports only a single extruder. + * - Enable DIRECT_MIXING_IN_G1 for Pia Taubert's reference implementation + */ +//#define MIXING_EXTRUDER +#ifdef MIXING_EXTRUDER + #define MIXING_STEPPERS 2 // Number of steppers in your mixing extruder + #define MIXING_VIRTUAL_TOOLS 16 // Use the Virtual Tool method with M163 and M164 + //#define DIRECT_MIXING_IN_G1 // Allow ABCDHI mix factors in G1 movement commands +#endif + //// The following define selects which power supply you have. Please choose the one that matches your setup // 1 = ATX // 2 = X-Box 360 203Watts (the blue wire connected to PS_ON and the red wire to VCC) // :{1:'ATX',2:'X-Box 360'} - #define POWER_SUPPLY 1 // Define this to have the electronics keep the power supply off on startup. If you don't know what this is leave it. diff --git a/Marlin/example_configurations/delta/kossel_mini/Configuration.h b/Marlin/example_configurations/delta/kossel_mini/Configuration.h index f27d37710969..06fe4c4155af 100644 --- a/Marlin/example_configurations/delta/kossel_mini/Configuration.h +++ b/Marlin/example_configurations/delta/kossel_mini/Configuration.h @@ -133,20 +133,34 @@ // :[1,2,3,4] #define EXTRUDERS 1 -// For Cyclops or any "multi-extruder" that shares a single nozzle. -//#define SINGLENOZZLE - // Offset of the extruders (uncomment if using more than one and relying on firmware to position when changing). // The offset has to be X=0, Y=0 for the extruder 0 hotend (default extruder). // For the other hotends it is their distance from the extruder 0 hotend. //#define HOTEND_OFFSET_X {0.0, 20.00} // (in mm) for each extruder, offset of the hotend on the X axis //#define HOTEND_OFFSET_Y {0.0, 5.00} // (in mm) for each extruder, offset of the hotend on the Y axis +// For Cyclops or any "multi-extruder" that shares a single nozzle. +//#define SINGLENOZZLE + +/** + * "Mixing Extruder" + * - Adds a new code, M165, to set the current mix factors. + * - Extends the stepping routines to move multiple steppers in proportion to the mix. + * - Optional support for Repetier Host M163, M164, and virtual extruder. + * - This implementation supports only a single extruder. + * - Enable DIRECT_MIXING_IN_G1 for Pia Taubert's reference implementation + */ +//#define MIXING_EXTRUDER +#ifdef MIXING_EXTRUDER + #define MIXING_STEPPERS 2 // Number of steppers in your mixing extruder + #define MIXING_VIRTUAL_TOOLS 16 // Use the Virtual Tool method with M163 and M164 + //#define DIRECT_MIXING_IN_G1 // Allow ABCDHI mix factors in G1 movement commands +#endif + //// The following define selects which power supply you have. Please choose the one that matches your setup // 1 = ATX // 2 = X-Box 360 203Watts (the blue wire connected to PS_ON and the red wire to VCC) // :{1:'ATX',2:'X-Box 360'} - #define POWER_SUPPLY 1 // Define this to have the electronics keep the power supply off on startup. If you don't know what this is leave it. diff --git a/Marlin/example_configurations/delta/kossel_pro/Configuration.h b/Marlin/example_configurations/delta/kossel_pro/Configuration.h index 36fbd8e1a18c..adf3cfb7331a 100644 --- a/Marlin/example_configurations/delta/kossel_pro/Configuration.h +++ b/Marlin/example_configurations/delta/kossel_pro/Configuration.h @@ -139,20 +139,34 @@ // :[1,2,3,4] #define EXTRUDERS 1 -// For Cyclops or any "multi-extruder" that shares a single nozzle. -//#define SINGLENOZZLE - // Offset of the extruders (uncomment if using more than one and relying on firmware to position when changing). // The offset has to be X=0, Y=0 for the extruder 0 hotend (default extruder). // For the other hotends it is their distance from the extruder 0 hotend. //#define HOTEND_OFFSET_X {0.0, 20.00} // (in mm) for each extruder, offset of the hotend on the X axis //#define HOTEND_OFFSET_Y {0.0, 5.00} // (in mm) for each extruder, offset of the hotend on the Y axis +// For Cyclops or any "multi-extruder" that shares a single nozzle. +//#define SINGLENOZZLE + +/** + * "Mixing Extruder" + * - Adds a new code, M165, to set the current mix factors. + * - Extends the stepping routines to move multiple steppers in proportion to the mix. + * - Optional support for Repetier Host M163, M164, and virtual extruder. + * - This implementation supports only a single extruder. + * - Enable DIRECT_MIXING_IN_G1 for Pia Taubert's reference implementation + */ +//#define MIXING_EXTRUDER +#ifdef MIXING_EXTRUDER + #define MIXING_STEPPERS 2 // Number of steppers in your mixing extruder + #define MIXING_VIRTUAL_TOOLS 16 // Use the Virtual Tool method with M163 and M164 + //#define DIRECT_MIXING_IN_G1 // Allow ABCDHI mix factors in G1 movement commands +#endif + //// The following define selects which power supply you have. Please choose the one that matches your setup // 1 = ATX // 2 = X-Box 360 203Watts (the blue wire connected to PS_ON and the red wire to VCC) // :{1:'ATX',2:'X-Box 360'} - #define POWER_SUPPLY 1 // Define this to have the electronics keep the power supply off on startup. If you don't know what this is leave it. diff --git a/Marlin/example_configurations/delta/kossel_xl/Configuration.h b/Marlin/example_configurations/delta/kossel_xl/Configuration.h index 48cc54ffffdb..31adca893ce3 100644 --- a/Marlin/example_configurations/delta/kossel_xl/Configuration.h +++ b/Marlin/example_configurations/delta/kossel_xl/Configuration.h @@ -126,20 +126,34 @@ // :[1,2,3,4] #define EXTRUDERS 1 -// For Cyclops or any "multi-extruder" that shares a single nozzle. -//#define SINGLENOZZLE - // Offset of the extruders (uncomment if using more than one and relying on firmware to position when changing). // The offset has to be X=0, Y=0 for the extruder 0 hotend (default extruder). // For the other hotends it is their distance from the extruder 0 hotend. //#define HOTEND_OFFSET_X {0.0, 20.00} // (in mm) for each extruder, offset of the hotend on the X axis //#define HOTEND_OFFSET_Y {0.0, 5.00} // (in mm) for each extruder, offset of the hotend on the Y axis +// For Cyclops or any "multi-extruder" that shares a single nozzle. +//#define SINGLENOZZLE + +/** + * "Mixing Extruder" + * - Adds a new code, M165, to set the current mix factors. + * - Extends the stepping routines to move multiple steppers in proportion to the mix. + * - Optional support for Repetier Host M163, M164, and virtual extruder. + * - This implementation supports only a single extruder. + * - Enable DIRECT_MIXING_IN_G1 for Pia Taubert's reference implementation + */ +//#define MIXING_EXTRUDER +#ifdef MIXING_EXTRUDER + #define MIXING_STEPPERS 2 // Number of steppers in your mixing extruder + #define MIXING_VIRTUAL_TOOLS 16 // Use the Virtual Tool method with M163 and M164 + //#define DIRECT_MIXING_IN_G1 // Allow ABCDHI mix factors in G1 movement commands +#endif + //// The following define selects which power supply you have. Please choose the one that matches your setup // 1 = ATX // 2 = X-Box 360 203Watts (the blue wire connected to PS_ON and the red wire to VCC) // :{1:'ATX',2:'X-Box 360'} - #define POWER_SUPPLY 2 // Define this to have the electronics keep the power supply off on startup. If you don't know what this is leave it. diff --git a/Marlin/example_configurations/makibox/Configuration.h b/Marlin/example_configurations/makibox/Configuration.h index f1b0c813d24d..64b22d460cbc 100644 --- a/Marlin/example_configurations/makibox/Configuration.h +++ b/Marlin/example_configurations/makibox/Configuration.h @@ -133,20 +133,34 @@ // :[1,2,3,4] #define EXTRUDERS 1 -// For Cyclops or any "multi-extruder" that shares a single nozzle. -//#define SINGLENOZZLE - // Offset of the extruders (uncomment if using more than one and relying on firmware to position when changing). // The offset has to be X=0, Y=0 for the extruder 0 hotend (default extruder). // For the other hotends it is their distance from the extruder 0 hotend. //#define HOTEND_OFFSET_X {0.0, 20.00} // (in mm) for each extruder, offset of the hotend on the X axis //#define HOTEND_OFFSET_Y {0.0, 5.00} // (in mm) for each extruder, offset of the hotend on the Y axis +// For Cyclops or any "multi-extruder" that shares a single nozzle. +//#define SINGLENOZZLE + +/** + * "Mixing Extruder" + * - Adds a new code, M165, to set the current mix factors. + * - Extends the stepping routines to move multiple steppers in proportion to the mix. + * - Optional support for Repetier Host M163, M164, and virtual extruder. + * - This implementation supports only a single extruder. + * - Enable DIRECT_MIXING_IN_G1 for Pia Taubert's reference implementation + */ +//#define MIXING_EXTRUDER +#ifdef MIXING_EXTRUDER + #define MIXING_STEPPERS 2 // Number of steppers in your mixing extruder + #define MIXING_VIRTUAL_TOOLS 16 // Use the Virtual Tool method with M163 and M164 + //#define DIRECT_MIXING_IN_G1 // Allow ABCDHI mix factors in G1 movement commands +#endif + //// The following define selects which power supply you have. Please choose the one that matches your setup // 1 = ATX // 2 = X-Box 360 203Watts (the blue wire connected to PS_ON and the red wire to VCC) // :{1:'ATX',2:'X-Box 360'} - #define POWER_SUPPLY 1 // Define this to have the electronics keep the power supply off on startup. If you don't know what this is leave it. diff --git a/Marlin/example_configurations/tvrrug/Round2/Configuration.h b/Marlin/example_configurations/tvrrug/Round2/Configuration.h index b693cb22bcff..12fcec5bdff2 100644 --- a/Marlin/example_configurations/tvrrug/Round2/Configuration.h +++ b/Marlin/example_configurations/tvrrug/Round2/Configuration.h @@ -133,20 +133,34 @@ // :[1,2,3,4] #define EXTRUDERS 1 -// For Cyclops or any "multi-extruder" that shares a single nozzle. -//#define SINGLENOZZLE - // Offset of the extruders (uncomment if using more than one and relying on firmware to position when changing). // The offset has to be X=0, Y=0 for the extruder 0 hotend (default extruder). // For the other hotends it is their distance from the extruder 0 hotend. //#define HOTEND_OFFSET_X {0.0, 20.00} // (in mm) for each extruder, offset of the hotend on the X axis //#define HOTEND_OFFSET_Y {0.0, 5.00} // (in mm) for each extruder, offset of the hotend on the Y axis +// For Cyclops or any "multi-extruder" that shares a single nozzle. +//#define SINGLENOZZLE + +/** + * "Mixing Extruder" + * - Adds a new code, M165, to set the current mix factors. + * - Extends the stepping routines to move multiple steppers in proportion to the mix. + * - Optional support for Repetier Host M163, M164, and virtual extruder. + * - This implementation supports only a single extruder. + * - Enable DIRECT_MIXING_IN_G1 for Pia Taubert's reference implementation + */ +//#define MIXING_EXTRUDER +#ifdef MIXING_EXTRUDER + #define MIXING_STEPPERS 2 // Number of steppers in your mixing extruder + #define MIXING_VIRTUAL_TOOLS 16 // Use the Virtual Tool method with M163 and M164 + //#define DIRECT_MIXING_IN_G1 // Allow ABCDHI mix factors in G1 movement commands +#endif + //// The following define selects which power supply you have. Please choose the one that matches your setup // 1 = ATX // 2 = X-Box 360 203Watts (the blue wire connected to PS_ON and the red wire to VCC) // :{1:'ATX',2:'X-Box 360'} - #define POWER_SUPPLY 1 // Define this to have the electronics keep the power supply off on startup. If you don't know what this is leave it. diff --git a/Marlin/pins.h b/Marlin/pins.h index bbabe53be17c..b5ebd6db8042 100644 --- a/Marlin/pins.h +++ b/Marlin/pins.h @@ -281,6 +281,17 @@ #define _H3_PINS HEATER_3_PIN, EXTRUDER_3_AUTO_FAN_PIN, marlinAnalogInputToDigitalPin(TEMP_3_PIN), #endif #endif +#elif ENABLED(MIXING_EXTRUDER) + #undef _E1_PINS + #define _E1_PINS E1_STEP_PIN, E1_DIR_PIN, E1_ENABLE_PIN, + #if MIXING_STEPPERS > 2 + #undef _E2_PINS + #define _E2_PINS E2_STEP_PIN, E2_DIR_PIN, E2_ENABLE_PIN, + #if MIXING_STEPPERS > 3 + #undef _E3_PINS + #define _E3_PINS E3_STEP_PIN, E3_DIR_PIN, E3_ENABLE_PIN, + #endif + #endif #endif #define BED_PINS HEATER_BED_PIN, marlinAnalogInputToDigitalPin(TEMP_BED_PIN), diff --git a/Marlin/pins_MEGACONTROLLER.h b/Marlin/pins_MEGACONTROLLER.h index 8e423a3bcb42..070c41d296a2 100644 --- a/Marlin/pins_MEGACONTROLLER.h +++ b/Marlin/pins_MEGACONTROLLER.h @@ -28,8 +28,8 @@ #error "Oops! Make sure you have 'Arduino Mega' selected from the 'Tools -> Boards' menu." #endif -#if EXTRUDERS > 2 || HOTENDS > 2 - #error "Mega Controller supports up to 2 extruders. Comment this line to keep going." +#if EXTRUDERS > 2 || MIXING_STEPPERS > 2 + #error "Mega Controller supports up to 2 extruders / E-steppers. Comment this line to keep going." #endif #define SERVO0_PIN 30 diff --git a/Marlin/pins_RUMBA.h b/Marlin/pins_RUMBA.h index e086ec446c90..a25a377e3b1f 100644 --- a/Marlin/pins_RUMBA.h +++ b/Marlin/pins_RUMBA.h @@ -28,8 +28,8 @@ #error "Oops! Make sure you have 'Arduino Mega' selected from the 'Tools -> Boards' menu." #endif -#if EXTRUDERS > 3 || HOTENDS > 3 - #error "RUMBA supports up to 3 extruders. Comment this line to keep going." +#if EXTRUDERS > 3 || MIXING_STEPPERS > 3 + #error "RUMBA supports up to 3 extruders / E-steppers. Comment this line to keep going." #endif #define DEFAULT_MACHINE_NAME "Rumba" diff --git a/Marlin/planner.cpp b/Marlin/planner.cpp index b742dfe6ea56..2ec9d77d34cf 100644 --- a/Marlin/planner.cpp +++ b/Marlin/planner.cpp @@ -623,6 +623,12 @@ void Planner::check_axes_activity() { // Bail if this is a zero-length block if (block->step_event_count <= dropsegments) return; + // For a mixing extruder, get a magnified step_event_count for each + #if ENABLED(MIXING_EXTRUDER) + for (uint8_t i = 0; i < MIXING_STEPPERS; i++) + block->mix_event_count[i] = (mixing_factor[i] < 0.0001) ? 0 : block->step_event_count / mixing_factor[i]; + #endif + #if FAN_COUNT > 0 for (uint8_t i = 0; i < FAN_COUNT; i++) block->fan_speed[i] = fanSpeeds[i]; #endif diff --git a/Marlin/planner.h b/Marlin/planner.h index 71e6b81196b9..d963fba4c43a 100644 --- a/Marlin/planner.h +++ b/Marlin/planner.h @@ -58,6 +58,10 @@ typedef struct { long steps[NUM_AXIS]; // Step count along each axis unsigned long step_event_count; // The number of step events required to complete this block + #if ENABLED(MIXING_EXTRUDER) + unsigned long mix_event_count[MIXING_STEPPERS]; // Scaled step_event_count for the mixing steppers + #endif + long accelerate_until, // The index of the step event on which to stop acceleration decelerate_after, // The index of the step event on which to start decelerating acceleration_rate; // The acceleration rate used for acceleration calculation diff --git a/Marlin/stepper.cpp b/Marlin/stepper.cpp index 300bd286f578..7683a58009d0 100644 --- a/Marlin/stepper.cpp +++ b/Marlin/stepper.cpp @@ -95,13 +95,13 @@ volatile unsigned long Stepper::step_events_completed = 0; // The number of step volatile unsigned char Stepper::eISR_Rate = 200; // Keep the ISR at a low rate until needed #if ENABLED(LIN_ADVANCE) - volatile int Stepper::e_steps[EXTRUDERS]; + volatile int Stepper::e_steps[ADVANCE_STEPPERS]; int Stepper::extruder_advance_k = LIN_ADVANCE_K, Stepper::final_estep_rate, - Stepper::current_estep_rate[EXTRUDERS], - Stepper::current_adv_steps[EXTRUDERS]; + Stepper::current_estep_rate[ADVANCE_STEPPERS], + Stepper::current_adv_steps[ADVANCE_STEPPERS]; #else - long Stepper::e_steps[EXTRUDERS], + long Stepper::e_steps[ADVANCE_STEPPERS], Stepper::final_advance = 0, Stepper::old_advance = 0, Stepper::advance_rate, @@ -114,6 +114,10 @@ long Stepper::acceleration_time, Stepper::deceleration_time; volatile long Stepper::count_position[NUM_AXIS] = { 0 }; volatile signed char Stepper::count_direction[NUM_AXIS] = { 1, 1, 1, 1 }; +#if ENABLED(MIXING_EXTRUDER) + long Stepper::counter_M[MIXING_STEPPERS]; +#endif + unsigned short Stepper::acc_step_rate; // needed for deceleration start point uint8_t Stepper::step_loops, Stepper::step_loops_nominal; unsigned short Stepper::OCR1A_nominal; @@ -176,7 +180,9 @@ volatile long Stepper::endstops_trigsteps[3]; #define Z_APPLY_STEP(v,Q) Z_STEP_WRITE(v) #endif -#define E_APPLY_STEP(v,Q) E_STEP_WRITE(v) +#if DISABLED(MIXING_EXTRUDER) + #define E_APPLY_STEP(v,Q) E_STEP_WRITE(v) +#endif // intRes = longIn1 * longIn2 >> 24 // uses: @@ -319,8 +325,15 @@ void Stepper::isr() { if (current_block) { current_block->busy = true; trapezoid_generator_reset(); - counter_X = -(current_block->step_event_count >> 1); - counter_Y = counter_Z = counter_E = counter_X; + + // Initialize Bresenham counters to 1/2 the ceiling + counter_X = counter_Y = counter_Z = counter_E = -(current_block->step_event_count >> 1); + + #if ENABLED(MIXING_EXTRUDER) + for (uint8_t i = 0; i < MIXING_STEPPERS; i++) + counter_M[i] = -(current_block->mix_event_count[i] >> 1); + #endif + step_events_completed = 0; #if ENABLED(Z_LATE_ENABLE) @@ -360,25 +373,72 @@ void Stepper::isr() { counter_E += current_block->steps[E_AXIS]; if (counter_E > 0) { counter_E -= current_block->step_event_count; - count_position[E_AXIS] += count_direction[E_AXIS]; - e_steps[current_block->active_extruder] += motor_direction(E_AXIS) ? -1 : 1; + #if DISABLED(MIXING_EXTRUDER) + // Don't step E here for mixing extruder + count_position[E_AXIS] += count_direction[E_AXIS]; + e_steps[current_block->active_extruder] += motor_direction(E_AXIS) ? -1 : 1; + #endif } - if (current_block->use_advance_lead) { - int delta_adv_steps; //Maybe a char would be enough? - delta_adv_steps = (((long)extruder_advance_k * current_estep_rate[current_block->active_extruder]) >> 9) - current_adv_steps[current_block->active_extruder]; - e_steps[current_block->active_extruder] += delta_adv_steps; - current_adv_steps[current_block->active_extruder] += delta_adv_steps; - } + #if DISABLED(MIXING_EXTRUDER) + + // Don't advance E here for mixing extruder + if (current_block->use_advance_lead) { + int delta_adv_steps = (((long)extruder_advance_k * current_estep_rate[current_block->active_extruder]) >> 9) - current_adv_steps[current_block->active_extruder]; + e_steps[current_block->active_extruder] += delta_adv_steps; + current_adv_steps[current_block->active_extruder] += delta_adv_steps; + } + + #else // MIXING_EXTRUDER + + // Step mixing steppers proportionally + long dir = motor_direction(E_AXIS) ? -1 : 1; + MIXING_STEPPERS_LOOP(j) { + counter_m[j] += current_block->steps[E_AXIS]; + if (counter_m[j] > 0) { + counter_m[j] -= current_block->mix_event_count[j]; + e_steps[j] += dir; + } + } + + // Apply advance lead proportionally (??) + if (current_block->use_advance_lead) { + int delta_adv_steps = (((long)extruder_advance_k * current_estep_rate[current_block->active_extruder]) >> 9) - current_adv_steps[current_block->active_extruder]; + MIXING_STEPPERS_LOOP(j) { + int steps = delta_adv_steps * current_block->step_event_count / current_block->mix_event_count[j]; + e_steps[j] += steps; + current_adv_steps[j] += steps; + } + } + + #endif // MIXING_EXTRUDER #elif ENABLED(ADVANCE) + // Always count the unified E axis counter_E += current_block->steps[E_AXIS]; if (counter_E > 0) { counter_E -= current_block->step_event_count; - e_steps[current_block->active_extruder] += motor_direction(E_AXIS) ? -1 : 1; + #if DISABLED(MIXING_EXTRUDER) + // Don't step E here for mixing extruder + e_steps[current_block->active_extruder] += motor_direction(E_AXIS) ? -1 : 1; + #endif } + #if ENABLED(MIXING_EXTRUDER) + + // Step mixing steppers proportionally + long dir = motor_direction(E_AXIS) ? -1 : 1; + MIXING_STEPPERS_LOOP(j) { + counter_m[j] += current_block->steps[E_AXIS]; + if (counter_m[j] > 0) { + counter_m[j] -= current_block->mix_event_count[j]; + e_steps[j] += dir; + } + } + + #endif // MIXING_EXTRUDER + #endif // ADVANCE or LIN_ADVANCE #define _COUNTER(AXIS) counter_## AXIS @@ -392,9 +452,22 @@ void Stepper::isr() { STEP_ADD(X); STEP_ADD(Y); STEP_ADD(Z); + #if DISABLED(ADVANCE) && DISABLED(LIN_ADVANCE) - STEP_ADD(E); - #endif + #if ENABLED(MIXING_EXTRUDER) + // Keep updating the single E axis + counter_E += current_block->steps[E_AXIS]; + // Tick the counters used for this mix + MIXING_STEPPERS_LOOP(j) { + // Step mixing steppers (proportionally) + counter_M[j] += current_block->steps[E_AXIS]; + // Step when the counter goes over zero + if (counter_M[j] > 0) En_STEP_WRITE(j, !INVERT_E_STEP_PIN); + } + #else // !MIXING_EXTRUDER + STEP_ADD(E); + #endif + #endif // !ADVANCE && !LIN_ADVANCE #define STEP_IF_COUNTER(AXIS) \ if (_COUNTER(AXIS) > 0) { \ @@ -406,15 +479,30 @@ void Stepper::isr() { STEP_IF_COUNTER(X); STEP_IF_COUNTER(Y); STEP_IF_COUNTER(Z); + #if DISABLED(ADVANCE) && DISABLED(LIN_ADVANCE) - STEP_IF_COUNTER(E); - #endif + #if ENABLED(MIXING_EXTRUDER) + // Always step the single E axis + if (counter_E > 0) { + counter_E -= current_block->step_event_count; + count_position[E_AXIS] += count_direction[E_AXIS]; + } + MIXING_STEPPERS_LOOP(j) { + if (counter_M[j] > 0) { + counter_M[j] -= current_block->mix_event_count[j]; + En_STEP_WRITE(j, INVERT_E_STEP_PIN); + } + } + #else // !MIXING_EXTRUDER + STEP_IF_COUNTER(E); + #endif + #endif // !ADVANCE && !LIN_ADVANCE step_events_completed++; if (step_events_completed >= current_block->step_event_count) break; } - #if ENABLED(LIN_ADVANCE) + #if ENABLED(ADVANCE) || ENABLED(LIN_ADVANCE) // If we have esteps to execute, fire the next ISR "now" if (e_steps[current_block->active_extruder]) OCR0A = TCNT0 + 2; #endif @@ -439,14 +527,34 @@ void Stepper::isr() { if (current_block->use_advance_lead) current_estep_rate[current_block->active_extruder] = ((unsigned long)acc_step_rate * current_block->e_speed_multiplier8) >> 8; + if (current_block->use_advance_lead) { + #if ENABLED(MIXING_EXTRUDER) + MIXING_STEPPERS_LOOP(j) + 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; + #else + current_estep_rate[current_block->active_extruder] = ((unsigned long)acc_step_rate * current_block->e_speed_multiplier8) >> 8; + #endif + } + #elif ENABLED(ADVANCE) advance += advance_rate * step_loops; //NOLESS(advance, current_block->advance); + long advance_whole = advance >> 8, + advance_factor = advance_whole - old_advance; + // Do E steps + advance steps - e_steps[current_block->active_extruder] += ((advance >> 8) - old_advance); - old_advance = advance >> 8; + #if ENABLED(MIXING_EXTRUDER) + // ...for mixing steppers proportionally + MIXING_STEPPERS_LOOP(j) + e_steps[j] += advance_factor * current_block->step_event_count / current_block->mix_event_count[j]; + #else + // ...for the active extruder + e_steps[current_block->active_extruder] += advance_factor; + #endif + + old_advance = advance_whole; #endif // ADVANCE or LIN_ADVANCE @@ -471,8 +579,14 @@ void Stepper::isr() { #if ENABLED(LIN_ADVANCE) - if (current_block->use_advance_lead) - current_estep_rate[current_block->active_extruder] = ((unsigned long)step_rate * current_block->e_speed_multiplier8) >> 8; + if (current_block->use_advance_lead) { + #if ENABLED(MIXING_EXTRUDER) + MIXING_STEPPERS_LOOP(j) + 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; + #else + current_estep_rate[current_block->active_extruder] = ((unsigned long)step_rate * current_block->e_speed_multiplier8) >> 8; + #endif + } #elif ENABLED(ADVANCE) @@ -480,8 +594,16 @@ void Stepper::isr() { NOLESS(advance, final_advance); // Do E steps + advance steps - uint32_t advance_whole = advance >> 8; - e_steps[current_block->active_extruder] += advance_whole - old_advance; + long advance_whole = advance >> 8, + advance_factor = advance_whole - old_advance; + + #if ENABLED(MIXING_EXTRUDER) + MIXING_STEPPERS_LOOP(j) + e_steps[j] += advance_factor * current_block->step_event_count / current_block->mix_event_count[j]; + #else + e_steps[current_block->active_extruder] += advance_factor; + #endif + old_advance = advance_whole; #endif // ADVANCE or LIN_ADVANCE @@ -728,14 +850,14 @@ void Stepper::init() { #if ENABLED(LIN_ADVANCE) - for (int i = 0; i < EXTRUDERS; i++) { + for (int i = 0; i < ADVANCE_STEPPERS; i++) { e_steps[i] = 0; current_adv_steps[i] = 0; } #elif ENABLED(ADVANCE) - for (uint8_t i = 0; i < EXTRUDERS; i++) e_steps[i] = 0; + for (uint8_t i = 0; i < ADVANCE_STEPPERS; i++) e_steps[i] = 0; #endif diff --git a/Marlin/stepper.h b/Marlin/stepper.h index 6ad55216d5cc..126525efcb09 100644 --- a/Marlin/stepper.h +++ b/Marlin/stepper.h @@ -90,6 +90,14 @@ class Stepper { static bool performing_homing; #endif + #if ENABLED(ADVANCE) || ENABLED(LIN_ADVANCE) + #if ENABLED(MIXING_EXTRUDER) + #define ADVANCE_STEPPERS MIXING_STEPPERS + #else + #define ADVANCE_STEPPERS EXTRUDERS + #endif + #endif + private: static unsigned char last_direction_bits; // The next stepping-bits to be output @@ -107,15 +115,15 @@ class Stepper { static unsigned char old_OCR0A; static volatile unsigned char eISR_Rate; #if ENABLED(LIN_ADVANCE) - static volatile int e_steps[EXTRUDERS]; + static volatile int e_steps[ADVANCE_STEPPERS]; static int extruder_advance_k; static int final_estep_rate; - static int current_estep_rate[EXTRUDERS]; // Actual extruder speed [steps/s] - static int current_adv_steps[EXTRUDERS]; // The amount of current added esteps due to advance. + static int current_estep_rate[ADVANCE_STEPPERS]; // Actual extruder speed [steps/s] + static int current_adv_steps[ADVANCE_STEPPERS]; // The amount of current added esteps due to advance. // i.e., the current amount of pressure applied // to the spring (=filament). #else - static long e_steps[EXTRUDERS]; + static long e_steps[ADVANCE_STEPPERS]; static long advance_rate, advance, final_advance; static long old_advance; #endif @@ -147,6 +155,16 @@ class Stepper { // static volatile signed char count_direction[NUM_AXIS]; + // + // Mixing extruder mix counters + // + #if ENABLED(MIXING_EXTRUDER) + static long counter_M[MIXING_STEPPERS]; + #define MIXING_STEPPERS_LOOP(VAR) \ + for (uint8_t VAR = 0; VAR < MIXING_STEPPERS; VAR++) \ + if (current_block->mix_event_count[VAR]) + #endif + public: // @@ -315,12 +333,25 @@ class Stepper { } #if ENABLED(ADVANCE) + advance = current_block->initial_advance; final_advance = current_block->final_advance; + // Do E steps + advance steps - e_steps[current_block->active_extruder] += ((advance >>8) - old_advance); - old_advance = advance >>8; + #if ENABLED(MIXING_EXTRUDER) + long advance_factor = (advance >> 8) - old_advance; + // ...for mixing steppers proportionally + MIXING_STEPPERS_LOOP(j) + e_steps[j] += advance_factor * current_block->step_event_count / current_block->mix_event_count[j]; + #else + // ...for the active extruder + e_steps[current_block->active_extruder] += ((advance >> 8) - old_advance); + #endif + + old_advance = advance >> 8; + #endif + deceleration_time = 0; // step_rate to timer interval OCR1A_nominal = calc_timer(current_block->nominal_rate); diff --git a/Marlin/stepper_indirection.h b/Marlin/stepper_indirection.h index 24e4c7c0ac04..bdd9a7c92550 100644 --- a/Marlin/stepper_indirection.h +++ b/Marlin/stepper_indirection.h @@ -183,25 +183,37 @@ #define E3_ENABLE_READ READ(E3_ENABLE_PIN) #if EXTRUDERS > 3 - #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);}} - #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);}} - #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);}} + #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); } } + #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); } } + #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); } } #elif EXTRUDERS > 2 - #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);}} - #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);}} - #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);}} + #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); } } + #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); } } + #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); } } #elif EXTRUDERS > 1 - #define _E_STEP_WRITE(v) {if(current_block->active_extruder==1){E1_STEP_WRITE(v);}else{E0_STEP_WRITE(v);}} - #define _NORM_E_DIR() {if(current_block->active_extruder==1){E1_DIR_WRITE(!INVERT_E1_DIR);}else{E0_DIR_WRITE(!INVERT_E0_DIR);}} - #define _REV_E_DIR() {if(current_block->active_extruder==1){E1_DIR_WRITE(INVERT_E1_DIR);}else{E0_DIR_WRITE(INVERT_E0_DIR);}} #if DISABLED(DUAL_X_CARRIAGE) - #define E_STEP_WRITE(v) _E_STEP_WRITE(v) - #define NORM_E_DIR() _NORM_E_DIR() - #define REV_E_DIR() _REV_E_DIR() + #define E_STEP_WRITE(v) { if (current_block->active_extruder == 0) { E0_STEP_WRITE(v); } else { E1_STEP_WRITE(v); } } + #define NORM_E_DIR() { if (current_block->active_extruder == 0) { E0_DIR_WRITE(!INVERT_E0_DIR); } else { E1_DIR_WRITE(!INVERT_E1_DIR); } } + #define REV_E_DIR() { if (current_block->active_extruder == 0) { E0_DIR_WRITE(INVERT_E0_DIR); } else { E1_DIR_WRITE(INVERT_E1_DIR); } } #else - #define E_STEP_WRITE(v) {if(extruder_duplication_enabled){E0_STEP_WRITE(v);E1_STEP_WRITE(v);}else _E_STEP_WRITE(v);} - #define NORM_E_DIR() {if(extruder_duplication_enabled){E0_DIR_WRITE(!INVERT_E0_DIR);E1_DIR_WRITE(!INVERT_E1_DIR);}else _NORM_E_DIR();} - #define REV_E_DIR() {if(extruder_duplication_enabled){E0_DIR_WRITE(INVERT_E0_DIR);E1_DIR_WRITE(INVERT_E1_DIR);}else _REV_E_DIR();} + #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); } } + #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); } } + #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); } } + #endif +#elif ENABLED(MIXING_EXTRUDER) + #define E_STEP_WRITE(v) NOOP /* not used for mixing extruders! */ + #if MIXING_STEPPERS > 3 + #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); } } + #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); } + #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); } + #elif MIXING_STEPPERS > 2 + #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); } } + #define NORM_E_DIR() { E0_DIR_WRITE(!INVERT_E0_DIR); E1_DIR_WRITE(!INVERT_E1_DIR); E2_DIR_WRITE(!INVERT_E2_DIR); } + #define REV_E_DIR() { E0_DIR_WRITE( INVERT_E0_DIR); E1_DIR_WRITE( INVERT_E1_DIR); E2_DIR_WRITE( INVERT_E2_DIR); } + #else + #define En_STEP_WRITE(n,v) { switch (n) { case 0: E0_STEP_WRITE(v); break; case 1: E1_STEP_WRITE(v); } } + #define NORM_E_DIR() { E0_DIR_WRITE(!INVERT_E0_DIR); E1_DIR_WRITE(!INVERT_E1_DIR); } + #define REV_E_DIR() { E0_DIR_WRITE( INVERT_E0_DIR); E1_DIR_WRITE( INVERT_E1_DIR); } #endif #else #define E_STEP_WRITE(v) E0_STEP_WRITE(v)