diff --git a/.gitignore b/.gitignore index 0a12acfd7c..a24cf93707 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ applet/ *~ *.orig *.rej +*.bak diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 58e8b2e6f3..3cbe131c95 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -155,8 +155,8 @@ // Configuration for second X-carriage // Note: the first x-carriage is defined as the x-carriage which homes to the minimum endstop; // the second x-carriage always homes to the maximum endstop. -#define X2_MIN_POS 88 // set minimum to ensure second x-carriage doesn't hit the parked first X-carriage -#define X2_MAX_POS 350.45 // set maximum to the distance between toolheads when both heads are homed +#define X2_MIN_POS 80 // set minimum to ensure second x-carriage doesn't hit the parked first X-carriage +#define X2_MAX_POS 353 // set maximum to the distance between toolheads when both heads are homed #define X2_HOME_DIR 1 // the second X-carriage always homes to the maximum endstop position #define X2_HOME_POS X2_MAX_POS // default home position is the maximum carriage position // However: In this mode the EXTRUDER_OFFSET_X value for the second extruder provides a software @@ -169,7 +169,29 @@ #define X2_STEP_PIN 25 #define X2_DIR_PIN 23 -#endif // DUAL_X_CARRIAGE +// There are a few selectable movement modes for dual x-carriages using M605 S +// Mode 0: Full control. The slicer has full control over both x-carriages and can achieve optimal travel results +// as long as it supports dual x-carriages. (M605 S0) +// Mode 1: Auto-park mode. The firmware will automatically park and unpark the x-carriages on tool changes so +// that additional slicer support is not required. (M605 S1) +// Mode 2: Duplication mode. The firmware will transparently make the second x-carriage and extruder copy all +// actions of the first x-carriage. This allows the printer to print 2 arbitrary items at +// once. (2nd extruder x offset and temp offset are set using: M605 S2 [Xnnn] [Rmmm]) + +// This is the default power-up mode which can be later using M605. +#define DEFAULT_DUAL_X_CARRIAGE_MODE 0 + +// As the x-carriages are independent we can now account for any relative Z offset +#define EXTRUDER1_Z_OFFSET 0.0 // z offset relative to extruder 0 + +// Default settings in "Auto-park Mode" +#define TOOLCHANGE_PARK_ZLIFT 0.2 // the distance to raise Z axis when parking an extruder +#define TOOLCHANGE_UNPARK_ZLIFT 1 // the distance to raise Z axis when unparking an extruder + +// Default x offset in duplication mode (typically set to half print bed width) +#define DEFAULT_DUPLICATION_X_OFFSET 100 + +#endif //DUAL_X_CARRIAGE //homing hits the endstop, then retracts by this distance, before it tries to slowly bump again: #define X_HOME_RETRACT_MM 5 diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index e15ffdf4e0..4609ce818e 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -139,6 +139,7 @@ // M503 - print the current settings (from memory not from eeprom) // M540 - Use S[0|1] to enable or disable the stop SD card print on endstop hit (requires ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED) // M600 - Pause for filament change X[pos] Y[pos] Z[relative lift] E[initial retract] L[later retract distance for removal] +// M605 - Set dual x-carriage movement mode: S [ X R ] // M907 - Set digital trimpot motor current using axis codes. // M908 - Control digital trimpot directly. // M350 - Set microstepping mode. @@ -168,9 +169,15 @@ float current_position[NUM_AXIS] = { 0.0, 0.0, 0.0, 0.0 }; float add_homeing[3]={0,0,0}; float min_pos[3] = { X_MIN_POS, Y_MIN_POS, Z_MIN_POS }; float max_pos[3] = { X_MAX_POS, Y_MAX_POS, Z_MAX_POS }; -// Extruder offset, only in XY plane + +// Extruder offset #if EXTRUDERS > 1 -float extruder_offset[2][EXTRUDERS] = { +#ifndef DUAL_X_CARRIAGE + #define NUM_EXTRUDER_OFFSETS 2 // only in XY plane +#else + #define NUM_EXTRUDER_OFFSETS 3 // supports offsets in XYZ plane +#endif +float extruder_offset[NUM_EXTRUDER_OFFSETS][EXTRUDERS] = { #if defined(EXTRUDER_OFFSET_X) && defined(EXTRUDER_OFFSET_Y) EXTRUDER_OFFSET_X, EXTRUDER_OFFSET_Y #endif @@ -691,8 +698,13 @@ XYZ_CONSTS_FROM_CONFIG(signed char, home_dir, HOME_DIR); #endif #if X_HOME_DIR != -1 || X2_HOME_DIR != 1 #error "Please use canonical x-carriage assignment" // the x-carriages are defined by their homing directions - #endif + #endif +#define DXC_FULL_CONTROL_MODE 0 +#define DXC_AUTO_PARK_MODE 1 +#define DXC_DUPLICATION_MODE 2 +static int dual_x_carriage_mode = DEFAULT_DUAL_X_CARRIAGE_MODE; + static float x_home_pos(int extruder) { if (extruder == 0) return base_home_pos(X_AXIS) + add_homeing[X_AXIS]; @@ -708,16 +720,31 @@ static int x_home_dir(int extruder) { return (extruder == 0) ? X_HOME_DIR : X2_HOME_DIR; } -static float inactive_x_carriage_pos = X2_MAX_POS; -#endif +static float inactive_extruder_x_pos = X2_MAX_POS; // used in mode 0 & 1 +static bool active_extruder_parked = false; // used in mode 1 & 2 +static float raised_parked_position[NUM_AXIS]; // used in mode 1 +static unsigned long delayed_move_time = 0; // used in mode 1 +static float duplicate_extruder_x_offset = DEFAULT_DUPLICATION_X_OFFSET; // used in mode 2 +static float duplicate_extruder_temp_offset = 0; // used in mode 2 +bool extruder_duplication_enabled = false; // used in mode 2 +#endif //DUAL_X_CARRIAGE static void axis_is_at_home(int axis) { #ifdef DUAL_X_CARRIAGE - if (axis == X_AXIS && active_extruder != 0) { - current_position[X_AXIS] = x_home_pos(active_extruder); - min_pos[X_AXIS] = X2_MIN_POS; - max_pos[X_AXIS] = max(extruder_offset[X_AXIS][1], X2_MAX_POS); - return; + if (axis == X_AXIS) { + if (active_extruder != 0) { + current_position[X_AXIS] = x_home_pos(active_extruder); + min_pos[X_AXIS] = X2_MIN_POS; + max_pos[X_AXIS] = max(extruder_offset[X_AXIS][1], X2_MAX_POS); + return; + } + else if (dual_x_carriage_mode == DXC_DUPLICATION_MODE && active_extruder == 0) { + current_position[X_AXIS] = base_home_pos(X_AXIS) + add_homeing[X_AXIS]; + min_pos[X_AXIS] = base_min_pos(X_AXIS) + add_homeing[X_AXIS]; + max_pos[X_AXIS] = min(base_max_pos(X_AXIS) + add_homeing[X_AXIS], + max(extruder_offset[X_AXIS][1], X2_MAX_POS) - duplicate_extruder_x_offset); + return; + } } #endif current_position[axis] = base_home_pos(axis) + add_homeing[axis]; @@ -869,7 +896,7 @@ void process_commands() for(int8_t i=0; i < NUM_AXIS; i++) { destination[i] = current_position[i]; } - feedrate = 0.0; + feedrate = 0.0; #ifdef DELTA // A delta can only safely home all axis at the same time @@ -920,6 +947,7 @@ void process_commands() int x_axis_home_dir = home_dir(X_AXIS); #else int x_axis_home_dir = x_home_dir(active_extruder); + extruder_duplication_enabled = false; #endif plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); @@ -950,12 +978,19 @@ void process_commands() { #ifdef DUAL_X_CARRIAGE int tmp_extruder = active_extruder; + extruder_duplication_enabled = false; active_extruder = !active_extruder; HOMEAXIS(X); - inactive_x_carriage_pos = current_position[X_AXIS]; + inactive_extruder_x_pos = current_position[X_AXIS]; active_extruder = tmp_extruder; - #endif HOMEAXIS(X); + // reset state used by the different modes + memcpy(raised_parked_position, current_position, sizeof(raised_parked_position)); + delayed_move_time = 0; + active_extruder_parked = true; + #else + HOMEAXIS(X); + #endif } if((home_all_axis) || (code_seen(axis_codes[Y_AXIS]))) { @@ -1199,6 +1234,10 @@ void process_commands() break; } if (code_seen('S')) setTargetHotend(code_value(), tmp_extruder); +#ifdef DUAL_X_CARRIAGE + if (dual_x_carriage_mode == DXC_DUPLICATION_MODE && tmp_extruder == 0) + setTargetHotend1(code_value() == 0.0 ? 0.0 : code_value() + duplicate_extruder_temp_offset); +#endif setWatch(); break; case 140: // M140 set bed temp @@ -1252,9 +1291,17 @@ void process_commands() #endif if (code_seen('S')) { setTargetHotend(code_value(), tmp_extruder); +#ifdef DUAL_X_CARRIAGE + if (dual_x_carriage_mode == DXC_DUPLICATION_MODE && tmp_extruder == 0) + setTargetHotend1(code_value() == 0.0 ? 0.0 : code_value() + duplicate_extruder_temp_offset); +#endif CooldownNoWait = true; } else if (code_seen('R')) { setTargetHotend(code_value(), tmp_extruder); +#ifdef DUAL_X_CARRIAGE + if (dual_x_carriage_mode == DXC_DUPLICATION_MODE && tmp_extruder == 0) + setTargetHotend1(code_value() == 0.0 ? 0.0 : code_value() + duplicate_extruder_temp_offset); +#endif CooldownNoWait = false; } #ifdef AUTOTEMP @@ -1671,6 +1718,12 @@ void process_commands() { extruder_offset[Y_AXIS][tmp_extruder] = code_value(); } + #ifdef DUAL_X_CARRIAGE + if(code_seen('Z')) + { + extruder_offset[Z_AXIS][tmp_extruder] = code_value(); + } + #endif SERIAL_ECHO_START; SERIAL_ECHOPGM(MSG_HOTEND_OFFSET); for(tmp_extruder = 0; tmp_extruder < EXTRUDERS; tmp_extruder++) @@ -1679,6 +1732,10 @@ void process_commands() SERIAL_ECHO(extruder_offset[X_AXIS][tmp_extruder]); SERIAL_ECHO(","); SERIAL_ECHO(extruder_offset[Y_AXIS][tmp_extruder]); + #ifdef DUAL_X_CARRIAGE + SERIAL_ECHO(","); + SERIAL_ECHO(extruder_offset[Z_AXIS][tmp_extruder]); + #endif } SERIAL_ECHOLN(""); }break; @@ -2013,6 +2070,53 @@ void process_commands() } break; #endif //FILAMENTCHANGEENABLE + #ifdef DUAL_X_CARRIAGE + case 605: // Set dual x-carriage movement mode: + // M605 S0: Full control mode. The slicer has full control over x-carriage movement + // M605 S1: Auto-park mode. The inactive head will auto park/unpark without slicer involvement + // M605 S2 [Xnnn] [Rmmm]: Duplication mode. The second extruder will duplicate the first with nnn + // millimeters x-offset and an optional differential hotend temperature of + // mmm degrees. E.g., with "M605 S2 X100 R2" the second extruder will duplicate + // the first with a spacing of 100mm in the x direction and 2 degrees hotter. + // + // Note: the X axis should be homed after changing dual x-carriage mode. + { + st_synchronize(); + + if (code_seen('S')) + dual_x_carriage_mode = code_value(); + + if (dual_x_carriage_mode == DXC_DUPLICATION_MODE) + { + if (code_seen('X')) + duplicate_extruder_x_offset = max(code_value(),X2_MIN_POS - x_home_pos(0)); + + if (code_seen('R')) + duplicate_extruder_temp_offset = code_value(); + + SERIAL_ECHO_START; + SERIAL_ECHOPGM(MSG_HOTEND_OFFSET); + SERIAL_ECHO(" "); + SERIAL_ECHO(extruder_offset[X_AXIS][0]); + SERIAL_ECHO(","); + SERIAL_ECHO(extruder_offset[Y_AXIS][0]); + SERIAL_ECHO(" "); + SERIAL_ECHO(duplicate_extruder_x_offset); + SERIAL_ECHO(","); + SERIAL_ECHOLN(extruder_offset[Y_AXIS][1]); + } + else if (dual_x_carriage_mode != DXC_FULL_CONTROL_MODE && dual_x_carriage_mode != DXC_AUTO_PARK_MODE) + { + dual_x_carriage_mode = DEFAULT_DUAL_X_CARRIAGE_MODE; + } + + active_extruder_parked = false; + extruder_duplication_enabled = false; + delayed_move_time = 0; + } + break; + #endif //DUAL_X_CARRIAGE + case 907: // M907 Set digital trimpot motor current using axis codes. { #if defined(DIGIPOTSS_PIN) && DIGIPOTSS_PIN > -1 @@ -2092,19 +2196,56 @@ void process_commands() // Save current position to return to after applying extruder offset memcpy(destination, current_position, sizeof(destination)); #ifdef DUAL_X_CARRIAGE - // only apply Y extruder offset in dual x carriage mode (x offset is already used in determining home pos) + if (dual_x_carriage_mode == DXC_AUTO_PARK_MODE && Stopped == false && + (delayed_move_time != 0 || current_position[X_AXIS] != x_home_pos(active_extruder))) + { + // Park old head: 1) raise 2) move to park position 3) lower + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS] + TOOLCHANGE_PARK_ZLIFT, + current_position[E_AXIS], max_feedrate[Z_AXIS], active_extruder); + plan_buffer_line(x_home_pos(active_extruder), current_position[Y_AXIS], current_position[Z_AXIS] + TOOLCHANGE_PARK_ZLIFT, + current_position[E_AXIS], max_feedrate[X_AXIS], active_extruder); + plan_buffer_line(x_home_pos(active_extruder), current_position[Y_AXIS], current_position[Z_AXIS], + current_position[E_AXIS], max_feedrate[Z_AXIS], active_extruder); + st_synchronize(); + } + + // apply Y & Z extruder offset (x offset is already used in determining home pos) current_position[Y_AXIS] = current_position[Y_AXIS] - extruder_offset[Y_AXIS][active_extruder] + extruder_offset[Y_AXIS][tmp_extruder]; - - float tmp_x_pos = current_position[X_AXIS]; - - // Set the new active extruder and position + current_position[Z_AXIS] = current_position[Z_AXIS] - + extruder_offset[Z_AXIS][active_extruder] + + extruder_offset[Z_AXIS][tmp_extruder]; + active_extruder = tmp_extruder; - axis_is_at_home(X_AXIS); //this function updates X min/max values. - current_position[X_AXIS] = inactive_x_carriage_pos; - inactive_x_carriage_pos = tmp_x_pos; - #else + + // This function resets the max/min values - the current position may be overwritten below. + axis_is_at_home(X_AXIS); + + 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 == 0 || 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; + } + #else // Offset extruder (only by XY) int i; for(i = 0; i < 2; i++) { @@ -2309,6 +2450,48 @@ void prepare_move() active_extruder); } #else + +#ifdef DUAL_X_CARRIAGE + if (active_extruder_parked) + { + if (dual_x_carriage_mode == DXC_DUPLICATION_MODE && active_extruder == 0) + { + // move duplicate extruder into correct duplication position. + plan_set_position(inactive_extruder_x_pos, current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + plan_buffer_line(current_position[X_AXIS] + duplicate_extruder_x_offset, current_position[Y_AXIS], current_position[Z_AXIS], + current_position[E_AXIS], max_feedrate[X_AXIS], 1); + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + st_synchronize(); + extruder_duplication_enabled = true; + active_extruder_parked = false; + } + else if (dual_x_carriage_mode == DXC_AUTO_PARK_MODE) // handle unparking of head + { + if (current_position[E_AXIS] == destination[E_AXIS]) + { + // this is a travel move - skit it but keep track of current position (so that it can later + // be used as start of first non-travel move) + if (delayed_move_time != 0xFFFFFFFFUL) + { + memcpy(current_position, destination, sizeof(current_position)); + if (destination[Z_AXIS] > raised_parked_position[Z_AXIS]) + raised_parked_position[Z_AXIS] = destination[Z_AXIS]; + delayed_move_time = millis(); + return; + } + } + delayed_move_time = 0; + // unpark extruder: 1) raise, 2) move into starting XY position, 3) lower + plan_buffer_line(raised_parked_position[X_AXIS], raised_parked_position[Y_AXIS], raised_parked_position[Z_AXIS], current_position[E_AXIS], max_feedrate[Z_AXIS], active_extruder); + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], raised_parked_position[Z_AXIS], + current_position[E_AXIS], min(max_feedrate[X_AXIS],max_feedrate[Y_AXIS]), active_extruder); + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], + current_position[E_AXIS], max_feedrate[Z_AXIS], active_extruder); + active_extruder_parked = false; + } + } +#endif //DUAL_X_CARRIAGE + // Do not use feedmultiply for E or Z only moves if( (current_position[X_AXIS] == destination [X_AXIS]) && (current_position[Y_AXIS] == destination [Y_AXIS])) { plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder); @@ -2316,7 +2499,7 @@ void prepare_move() else { plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate*feedmultiply/60/100.0, active_extruder); } -#endif +#endif //else DELTA for(int8_t i=0; i < NUM_AXIS; i++) { current_position[i] = destination[i]; } @@ -2428,6 +2611,16 @@ void manage_inactivity() WRITE(E0_ENABLE_PIN,oldstatus); } #endif + #if defined(DUAL_X_CARRIAGE) + // handle delayed move timeout + if (delayed_move_time != 0 && (millis() - delayed_move_time) > 1000 && Stopped == false) + { + // travel moves have been received so enact them + delayed_move_time = 0xFFFFFFFFUL; // force moves to be done + memcpy(destination,current_position,sizeof(destination)); + prepare_move(); + } + #endif check_axes_activity(); } diff --git a/Marlin/stepper.cpp b/Marlin/stepper.cpp index 0ba1001395..7d738ac5e9 100644 --- a/Marlin/stepper.cpp +++ b/Marlin/stepper.cpp @@ -349,20 +349,36 @@ ISR(TIMER1_COMPA_vect) // Set the direction bits (X_AXIS=A_AXIS and Y_AXIS=B_AXIS for COREXY) if((out_bits & (1<active_extruder != 0) + WRITE(X2_DIR_PIN, INVERT_X_DIR); + else + WRITE(X_DIR_PIN, INVERT_X_DIR); + } + #else WRITE(X_DIR_PIN, INVERT_X_DIR); + #endif count_direction[X_AXIS]=-1; } else{ #ifdef DUAL_X_CARRIAGE - if (active_extruder != 0) - WRITE(X2_DIR_PIN,!INVERT_X_DIR); - else - #endif + if (extruder_duplication_enabled){ + WRITE(X_DIR_PIN, !INVERT_X_DIR); + WRITE(X2_DIR_PIN, !INVERT_X_DIR); + } + else{ + if (current_block->active_extruder != 0) + WRITE(X2_DIR_PIN, !INVERT_X_DIR); + else + WRITE(X_DIR_PIN, !INVERT_X_DIR); + } + #else WRITE(X_DIR_PIN, !INVERT_X_DIR); + #endif count_direction[X_AXIS]=1; } if((out_bits & (1<active_extruder == 0 && X_HOME_DIR == -1) + || (current_block->active_extruder != 0 && X2_HOME_DIR == -1)) + #endif { #if defined(X_MIN_PIN) && X_MIN_PIN > -1 bool x_min_endstop=(READ(X_MIN_PIN) != X_MIN_ENDSTOP_INVERTING); @@ -404,8 +421,9 @@ ISR(TIMER1_COMPA_vect) { #ifdef DUAL_X_CARRIAGE // with 2 x-carriages, endstops are only checked in the homing direction for the active extruder - if ((active_extruder == 0 && X_HOME_DIR == 1) || (active_extruder != 0 && X2_HOME_DIR == 1)) - #endif + if ((current_block->active_extruder == 0 && X_HOME_DIR == 1) + || (current_block->active_extruder != 0 && X2_HOME_DIR == 1)) + #endif { #if defined(X_MAX_PIN) && X_MAX_PIN > -1 bool x_max_endstop=(READ(X_MAX_PIN) != X_MAX_ENDSTOP_INVERTING); @@ -455,8 +473,8 @@ ISR(TIMER1_COMPA_vect) if ((out_bits & (1<steps_x; if (counter_x > 0) { - #ifdef DUAL_X_CARRIAGE - if (active_extruder != 0) - WRITE(X2_STEP_PIN,!INVERT_X_STEP_PIN); - else - #endif + #ifdef DUAL_X_CARRIAGE + if (extruder_duplication_enabled){ WRITE(X_STEP_PIN, !INVERT_X_STEP_PIN); + WRITE(X2_STEP_PIN, !INVERT_X_STEP_PIN); + } + else { + if (current_block->active_extruder != 0) + WRITE(X2_STEP_PIN, !INVERT_X_STEP_PIN); + else + WRITE(X_STEP_PIN, !INVERT_X_STEP_PIN); + } + #else + WRITE(X_STEP_PIN, !INVERT_X_STEP_PIN); + #endif counter_x -= current_block->step_event_count; - count_position[X_AXIS]+=count_direction[X_AXIS]; - #ifdef DUAL_X_CARRIAGE - if (active_extruder != 0) - WRITE(X2_STEP_PIN,INVERT_X_STEP_PIN); - else - #endif + count_position[X_AXIS]+=count_direction[X_AXIS]; + #ifdef DUAL_X_CARRIAGE + if (extruder_duplication_enabled){ WRITE(X_STEP_PIN, INVERT_X_STEP_PIN); + WRITE(X2_STEP_PIN, INVERT_X_STEP_PIN); + } + else { + if (current_block->active_extruder != 0) + WRITE(X2_STEP_PIN, INVERT_X_STEP_PIN); + else + WRITE(X_STEP_PIN, INVERT_X_STEP_PIN); + } + #else + WRITE(X_STEP_PIN, INVERT_X_STEP_PIN); + #endif } counter_y += current_block->steps_y; @@ -556,16 +590,16 @@ ISR(TIMER1_COMPA_vect) counter_z += current_block->steps_z; if (counter_z > 0) { WRITE(Z_STEP_PIN, !INVERT_Z_STEP_PIN); - - #ifdef Z_DUAL_STEPPER_DRIVERS + + #ifdef Z_DUAL_STEPPER_DRIVERS WRITE(Z2_STEP_PIN, !INVERT_Z_STEP_PIN); #endif counter_z -= current_block->step_event_count; count_position[Z_AXIS]+=count_direction[Z_AXIS]; WRITE(Z_STEP_PIN, INVERT_Z_STEP_PIN); - - #ifdef Z_DUAL_STEPPER_DRIVERS + + #ifdef Z_DUAL_STEPPER_DRIVERS WRITE(Z2_STEP_PIN, INVERT_Z_STEP_PIN); #endif } diff --git a/Marlin/stepper.h b/Marlin/stepper.h index 6e60a332e7..ac9dd8af59 100644 --- a/Marlin/stepper.h +++ b/Marlin/stepper.h @@ -28,9 +28,16 @@ #define NORM_E_DIR() { if(current_block->active_extruder == 2) { WRITE(E2_DIR_PIN, !INVERT_E2_DIR); } else { if(current_block->active_extruder == 1) { WRITE(E1_DIR_PIN, !INVERT_E1_DIR); } else { WRITE(E0_DIR_PIN, !INVERT_E0_DIR); }}} #define REV_E_DIR() { if(current_block->active_extruder == 2) { WRITE(E2_DIR_PIN, INVERT_E2_DIR); } else { if(current_block->active_extruder == 1) { WRITE(E1_DIR_PIN, INVERT_E1_DIR); } else { WRITE(E0_DIR_PIN, INVERT_E0_DIR); }}} #elif EXTRUDERS > 1 - #define WRITE_E_STEP(v) { if(current_block->active_extruder == 1) { WRITE(E1_STEP_PIN, v); } else { WRITE(E0_STEP_PIN, v); }} - #define NORM_E_DIR() { if(current_block->active_extruder == 1) { WRITE(E1_DIR_PIN, !INVERT_E1_DIR); } else { WRITE(E0_DIR_PIN, !INVERT_E0_DIR); }} - #define REV_E_DIR() { if(current_block->active_extruder == 1) { WRITE(E1_DIR_PIN, INVERT_E1_DIR); } else { WRITE(E0_DIR_PIN, INVERT_E0_DIR); }} + #ifndef DUAL_X_CARRIAGE + #define WRITE_E_STEP(v) { if(current_block->active_extruder == 1) { WRITE(E1_STEP_PIN, v); } else { WRITE(E0_STEP_PIN, v); }} + #define NORM_E_DIR() { if(current_block->active_extruder == 1) { WRITE(E1_DIR_PIN, !INVERT_E1_DIR); } else { WRITE(E0_DIR_PIN, !INVERT_E0_DIR); }} + #define REV_E_DIR() { if(current_block->active_extruder == 1) { WRITE(E1_DIR_PIN, INVERT_E1_DIR); } else { WRITE(E0_DIR_PIN, INVERT_E0_DIR); }} + #else + extern bool extruder_duplication_enabled; + #define WRITE_E_STEP(v) { if(extruder_duplication_enabled) { WRITE(E0_STEP_PIN, v); WRITE(E1_STEP_PIN, v); } else if(current_block->active_extruder == 1) { WRITE(E1_STEP_PIN, v); } else { WRITE(E0_STEP_PIN, v); }} + #define NORM_E_DIR() { if(extruder_duplication_enabled) { WRITE(E0_DIR_PIN, !INVERT_E0_DIR); WRITE(E1_DIR_PIN, !INVERT_E1_DIR); } else if(current_block->active_extruder == 1) { WRITE(E1_DIR_PIN, !INVERT_E1_DIR); } else { WRITE(E0_DIR_PIN, !INVERT_E0_DIR); }} + #define REV_E_DIR() { if(extruder_duplication_enabled) { WRITE(E0_DIR_PIN, INVERT_E0_DIR); WRITE(E1_DIR_PIN, INVERT_E1_DIR); } else if(current_block->active_extruder == 1) { WRITE(E1_DIR_PIN, INVERT_E1_DIR); } else { WRITE(E0_DIR_PIN, INVERT_E0_DIR); }} + #endif #else #define WRITE_E_STEP(v) WRITE(E0_STEP_PIN, v) #define NORM_E_DIR() WRITE(E0_DIR_PIN, !INVERT_E0_DIR)