diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 726058ebbc..7b642cc355 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -532,6 +532,11 @@ //#define USE_OCR2A_AS_TOP #endif +/** + * Use one of the PWM fans as a redundant part-cooling fan + */ +//#define REDUNDANT_PART_COOLING_FAN 2 // Index of the fan to sync with FAN 0. + // @section extruder /** @@ -677,6 +682,12 @@ #endif #endif +// Drive the E axis with two synchronized steppers +//#define E_DUAL_STEPPER_DRIVERS +#if ENABLED(E_DUAL_STEPPER_DRIVERS) + //#define INVERT_E1_VS_E0_DIR // Enable if the E motors need opposite DIR states +#endif + /** * Dual X Carriage * diff --git a/Marlin/src/MarlinCore.cpp b/Marlin/src/MarlinCore.cpp index 78c97cf3a3..404f36c79f 100644 --- a/Marlin/src/MarlinCore.cpp +++ b/Marlin/src/MarlinCore.cpp @@ -421,19 +421,18 @@ void startOrResumeJob() { * - Check if an idle but hot extruder needs filament extruded (EXTRUDER_RUNOUT_PREVENT) * - Pulse FET_SAFETY_PIN if it exists */ -inline void manage_inactivity(const bool ignore_stepper_queue=false) { +inline void manage_inactivity(const bool no_stepper_sleep=false) { queue.get_available_commands(); const millis_t ms = millis(); - // Prevent steppers timing-out in the middle of M600 - // unless PAUSE_PARK_NO_STEPPER_TIMEOUT is disabled - const bool parked_or_ignoring = ignore_stepper_queue + // Prevent steppers timing-out + const bool do_reset_timeout = no_stepper_sleep || TERN0(PAUSE_PARK_NO_STEPPER_TIMEOUT, did_pause_print); // Reset both the M18/M84 activity timeout and the M85 max 'kill' timeout - if (parked_or_ignoring) gcode.reset_stepper_timeout(ms); + if (do_reset_timeout) gcode.reset_stepper_timeout(ms); if (gcode.stepper_max_timed_out(ms)) { SERIAL_ERROR_MSG(STR_KILL_INACTIVE_TIME, parser.command_ptr); @@ -449,7 +448,7 @@ inline void manage_inactivity(const bool ignore_stepper_queue=false) { // activity timeout and the M85 max 'kill' timeout if (planner.has_blocks_queued()) gcode.reset_stepper_timeout(ms); - else if (!parked_or_ignoring && gcode.stepper_inactive_timeout()) { + else if (!do_reset_timeout && gcode.stepper_inactive_timeout()) { if (!already_shutdown_steppers) { already_shutdown_steppers = true; // L6470 SPI will consume 99% of free time without this @@ -732,14 +731,14 @@ inline void manage_inactivity(const bool ignore_stepper_queue=false) { * - Update the Průša MMU2 * - Handle Joystick jogging */ -void idle(TERN_(ADVANCED_PAUSE_FEATURE, bool no_stepper_sleep/*=false*/)) { +void idle(bool no_stepper_sleep/*=false*/) { #if ENABLED(MARLIN_DEV_MODE) static uint16_t idle_depth = 0; if (++idle_depth > 5) SERIAL_ECHOLNPAIR("idle() call depth: ", idle_depth); #endif // Core Marlin activities - manage_inactivity(TERN_(ADVANCED_PAUSE_FEATURE, no_stepper_sleep)); + manage_inactivity(no_stepper_sleep); // Manage Heaters (and Watchdog) thermalManager.manage_heater(); diff --git a/Marlin/src/MarlinCore.h b/Marlin/src/MarlinCore.h index ce1b106bfa..01a1be4d59 100644 --- a/Marlin/src/MarlinCore.h +++ b/Marlin/src/MarlinCore.h @@ -34,8 +34,8 @@ void stop(); // Pass true to keep steppers from timing out -void idle(TERN_(ADVANCED_PAUSE_FEATURE, bool no_stepper_sleep=false)); -inline void idle_no_sleep() { idle(TERN_(ADVANCED_PAUSE_FEATURE, true)); } +void idle(bool no_stepper_sleep=false); +inline void idle_no_sleep() { idle(true); } #if ENABLED(G38_PROBE_TARGET) extern uint8_t G38_move; // Flag to tell the ISR that G38 is in progress, and the type diff --git a/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp b/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp index 11c05f6054..e144390c8d 100644 --- a/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp +++ b/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp @@ -1025,7 +1025,7 @@ void set_message_with_feedback(PGM_P const msg_P) { SET_SOFT_ENDSTOP_LOOSE(true); do { - idle(); + idle_no_sleep(); new_z = ui.ubl_mesh_value(); TERN_(UBL_MESH_EDIT_MOVES_Z, do_blocking_move_to_z(h_offset + new_z)); // Move the nozzle as the point is edited SERIAL_FLUSH(); // Prevent host M105 buffer overrun. diff --git a/Marlin/src/feature/binary_stream.h b/Marlin/src/feature/binary_stream.h index 9eb151b27f..2ad7f236a1 100644 --- a/Marlin/src/feature/binary_stream.h +++ b/Marlin/src/feature/binary_stream.h @@ -24,9 +24,11 @@ #include "../inc/MarlinConfig.h" #define BINARY_STREAM_COMPRESSION - #if ENABLED(BINARY_STREAM_COMPRESSION) #include "../libs/heatshrink/heatshrink_decoder.h" + // STM32 (and others?) require a word-aligned buffer for SD card transfers via DMA + static __attribute__((aligned(sizeof(size_t)))) uint8_t decode_buffer[512] = {}; + static heatshrink_decoder hsd; #endif inline bool bs_serial_data_available(const serial_index_t index) { @@ -37,16 +39,6 @@ inline int bs_read_serial(const serial_index_t index) { return SERIAL_IMPL.read(index); } -#if ENABLED(BINARY_STREAM_COMPRESSION) - static heatshrink_decoder hsd; - #if BOTH(ARDUINO_ARCH_STM32F1, SDIO_SUPPORT) - // STM32 requires a word-aligned buffer for SD card transfers via DMA - static __attribute__((aligned(sizeof(size_t)))) uint8_t decode_buffer[512] = {}; - #else - static uint8_t decode_buffer[512] = {}; - #endif -#endif - class SDFileTransferProtocol { private: struct Packet { diff --git a/Marlin/src/gcode/bedlevel/G35.cpp b/Marlin/src/gcode/bedlevel/G35.cpp index ad2cc67db0..44df6d9273 100644 --- a/Marlin/src/gcode/bedlevel/G35.cpp +++ b/Marlin/src/gcode/bedlevel/G35.cpp @@ -91,8 +91,8 @@ void GcodeSuite::G35() { // Disable duplication mode on homing TERN_(HAS_DUPLICATION_MODE, set_duplication_enabled(false)); - // Home all before this procedure - home_all_axes(); + // Home only Z axis when X and Y is trusted, otherwise all axes, if needed before this procedure + if (!all_axes_trusted()) process_subcommands_now_P(PSTR("G28Z")); bool err_break = false; diff --git a/Marlin/src/gcode/calibrate/G34.cpp b/Marlin/src/gcode/calibrate/G34.cpp index bcca00dd42..956960866d 100644 --- a/Marlin/src/gcode/calibrate/G34.cpp +++ b/Marlin/src/gcode/calibrate/G34.cpp @@ -39,7 +39,7 @@ void GcodeSuite::G34() { // Home before the alignment procedure - if (!all_axes_trusted()) home_all_axes(); + home_if_needed(); TERN_(HAS_LEVELING, TEMPORARY_BED_LEVELING_STATE(false)); diff --git a/Marlin/src/gcode/calibrate/G34_M422.cpp b/Marlin/src/gcode/calibrate/G34_M422.cpp index 1803933d16..6869962028 100644 --- a/Marlin/src/gcode/calibrate/G34_M422.cpp +++ b/Marlin/src/gcode/calibrate/G34_M422.cpp @@ -167,7 +167,7 @@ void GcodeSuite::G34() { )); // Home before the alignment procedure - if (!all_axes_trusted()) home_all_axes(); + home_if_needed(); // Move the Z coordinate realm towards the positive - dirty trick current_position.z += z_probe * 0.5f; diff --git a/Marlin/src/gcode/feature/pause/M600.cpp b/Marlin/src/gcode/feature/pause/M600.cpp index 2daa7d999a..541fa08350 100644 --- a/Marlin/src/gcode/feature/pause/M600.cpp +++ b/Marlin/src/gcode/feature/pause/M600.cpp @@ -99,7 +99,7 @@ void GcodeSuite::M600() { #if ENABLED(HOME_BEFORE_FILAMENT_CHANGE) // If needed, home before parking for filament change - if (!all_axes_trusted()) home_all_axes(true); + home_if_needed(true); #endif #if HAS_MULTI_EXTRUDER diff --git a/Marlin/src/gcode/temp/M106_M107.cpp b/Marlin/src/gcode/temp/M106_M107.cpp index dcb0d34ffe..3f85c53d78 100644 --- a/Marlin/src/gcode/temp/M106_M107.cpp +++ b/Marlin/src/gcode/temp/M106_M107.cpp @@ -60,39 +60,40 @@ */ void GcodeSuite::M106() { const uint8_t pfan = parser.byteval('P', _ALT_P); + if (pfan >= _CNT_P) return; + #if REDUNDANT_PART_COOLING_FAN + if (pfan == REDUNDANT_PART_COOLING_FAN) return; + #endif - if (pfan < _CNT_P) { + #if ENABLED(EXTRA_FAN_SPEED) + const uint16_t t = parser.intval('T'); + if (t > 0) return thermalManager.set_temp_fan_speed(pfan, t); + #endif - #if ENABLED(EXTRA_FAN_SPEED) - const uint16_t t = parser.intval('T'); - if (t > 0) return thermalManager.set_temp_fan_speed(pfan, t); - #endif + const uint16_t dspeed = parser.seen_test('A') ? thermalManager.fan_speed[active_extruder] : 255; - const uint16_t dspeed = parser.seen_test('A') ? thermalManager.fan_speed[active_extruder] : 255; + uint16_t speed = dspeed; - uint16_t speed = dspeed; + // Accept 'I' if temperature presets are defined + #if PREHEAT_COUNT + const bool got_preset = parser.seenval('I'); + if (got_preset) speed = ui.material_preset[_MIN(parser.value_byte(), PREHEAT_COUNT - 1)].fan_speed; + #else + constexpr bool got_preset = false; + #endif - // Accept 'I' if temperature presets are defined - #if PREHEAT_COUNT - const bool got_preset = parser.seenval('I'); - if (got_preset) speed = ui.material_preset[_MIN(parser.value_byte(), PREHEAT_COUNT - 1)].fan_speed; - #else - constexpr bool got_preset = false; - #endif + if (!got_preset && parser.seenval('S')) + speed = parser.value_ushort(); - if (!got_preset && parser.seenval('S')) - speed = parser.value_ushort(); + TERN_(FOAMCUTTER_XYUV, speed *= 2.55); // Get command in % of max heat - TERN_(FOAMCUTTER_XYUV, speed *= 2.55); // Get command in % of max heat + // Set speed, with constraint + thermalManager.set_fan_speed(pfan, speed); - // Set speed, with constraint - thermalManager.set_fan_speed(pfan, speed); + TERN_(LASER_SYNCHRONOUS_M106_M107, planner.buffer_sync_block(BLOCK_FLAG_SYNC_FANS)); - TERN_(LASER_SYNCHRONOUS_M106_M107, planner.buffer_sync_block(BLOCK_FLAG_SYNC_FANS)); - - if (TERN0(DUAL_X_CARRIAGE, idex_is_duplicating())) // pfan == 0 when duplicating - thermalManager.set_fan_speed(1 - pfan, speed); - } + if (TERN0(DUAL_X_CARRIAGE, idex_is_duplicating())) // pfan == 0 when duplicating + thermalManager.set_fan_speed(1 - pfan, speed); } /** @@ -101,6 +102,9 @@ void GcodeSuite::M106() { void GcodeSuite::M107() { const uint8_t pfan = parser.byteval('P', _ALT_P); if (pfan >= _CNT_P) return; + #if REDUNDANT_PART_COOLING_FAN + if (pfan == REDUNDANT_PART_COOLING_FAN) return; + #endif thermalManager.set_fan_speed(pfan, 0); diff --git a/Marlin/src/inc/Conditionals_LCD.h b/Marlin/src/inc/Conditionals_LCD.h index ea83b5abbc..833fe0d227 100644 --- a/Marlin/src/inc/Conditionals_LCD.h +++ b/Marlin/src/inc/Conditionals_LCD.h @@ -558,7 +558,12 @@ #undef DISABLE_E #endif -#if ENABLED(SWITCHING_EXTRUDER) // One stepper for every two EXTRUDERS +#if ENABLED(E_DUAL_STEPPER_DRIVERS) // E0/E1 steppers act in tandem as E0 + + #define E_STEPPERS 2 + +#elif ENABLED(SWITCHING_EXTRUDER) // One stepper for every two EXTRUDERS + #if EXTRUDERS > 4 #define E_STEPPERS 3 #elif EXTRUDERS > 2 @@ -569,17 +574,24 @@ #if DISABLED(SWITCHING_NOZZLE) #define HOTENDS E_STEPPERS #endif -#elif ENABLED(MIXING_EXTRUDER) + +#elif ENABLED(MIXING_EXTRUDER) // Multiple feeds are mixed proportionally + #define E_STEPPERS MIXING_STEPPERS #define E_MANUAL 1 #if MIXING_STEPPERS == 2 #define HAS_DUAL_MIXING 1 #endif -#elif ENABLED(SWITCHING_TOOLHEAD) + +#elif ENABLED(SWITCHING_TOOLHEAD) // Toolchanger + #define E_STEPPERS EXTRUDERS #define E_MANUAL EXTRUDERS -#elif HAS_PRUSA_MMU2 + +#elif HAS_PRUSA_MMU2 // Průša Multi-Material Unit v2 + #define E_STEPPERS 1 + #endif // No inactive extruders with SWITCHING_NOZZLE or Průša MMU1 diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index ffb79a6baa..7a178db3aa 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -1161,6 +1161,19 @@ static_assert(Y_MAX_LENGTH >= Y_BED_SIZE, "Movement bounds (Y_MIN_POS, Y_MAX_POS #endif #endif +/** + * Dual E Steppers requirements + */ +#if ENABLED(E_DUAL_STEPPER_DRIVERS) + #if EXTRUDERS > 1 + #error "E_DUAL_STEPPER_DRIVERS can only be used with EXTRUDERS set to 1." + #elif ENABLED(MIXING_EXTRUDER) + #error "E_DUAL_STEPPER_DRIVERS is incompatible with MIXING_EXTRUDER." + #elif ENABLED(SWITCHING_EXTRUDER) + #error "E_DUAL_STEPPER_DRIVERS is incompatible with SWITCHING_EXTRUDER." + #endif +#endif + /** * Linear Advance 1.5 - Check K value range */ @@ -1877,6 +1890,14 @@ static_assert(Y_MAX_LENGTH >= Y_BED_SIZE, "Movement bounds (Y_MIN_POS, Y_MAX_POS #endif #endif +#ifdef REDUNDANT_PART_COOLING_FAN + #if FAN_COUNT < 2 + #error "REDUNDANT_PART_COOLING_FAN requires a board with at least two PWM fans." + #else + static_assert(WITHIN(REDUNDANT_PART_COOLING_FAN, 1, FAN_COUNT - 1), "REDUNDANT_PART_COOLING_FAN must be between 1 and " STRINGIFY(DECREMENT(FAN_COUNT)) "."); + #endif +#endif + /** * Case Light requirements */ diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index cf6586f3f0..597ec2d553 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2021-06-14" + #define STRING_DISTRIBUTION_DATE "2021-06-15" #endif /** diff --git a/Marlin/src/lcd/menu/menu_temperature.cpp b/Marlin/src/lcd/menu/menu_temperature.cpp index 33a3d2f445..96e6ee5f8e 100644 --- a/Marlin/src/lcd/menu/menu_temperature.cpp +++ b/Marlin/src/lcd/menu/menu_temperature.cpp @@ -57,8 +57,14 @@ void Temperature::lcd_preheat(const uint8_t e, const int8_t indh, const int8_t i if (indb >= 0 && ui.material_preset[indb].bed_temp > 0) setTargetBed(ui.material_preset[indb].bed_temp); #endif #if HAS_FAN - if (indh >= 0) - set_fan_speed(active_extruder < (FAN_COUNT) ? active_extruder : 0, ui.material_preset[indh].fan_speed); + if (indh >= 0) { + const uint8_t fan_index = active_extruder < (FAN_COUNT) ? active_extruder : 0; + if (true + #if REDUNDANT_PART_COOLING_FAN + && fan_index != REDUNDANT_PART_COOLING_FAN + #endif + ) set_fan_speed(fan_index, ui.material_preset[indh].fan_speed); + } #endif ui.return_to_status(); } @@ -215,37 +221,37 @@ void menu_temperature() { #if HAS_FAN0 _FAN_EDIT_ITEMS(0,FIRST_FAN_SPEED); #endif - #if HAS_FAN1 + #if HAS_FAN1 && REDUNDANT_PART_COOLING_FAN != 1 FAN_EDIT_ITEMS(1); #elif SNFAN(1) singlenozzle_item(1); #endif - #if HAS_FAN2 + #if HAS_FAN2 && REDUNDANT_PART_COOLING_FAN != 2 FAN_EDIT_ITEMS(2); #elif SNFAN(2) singlenozzle_item(2); #endif - #if HAS_FAN3 + #if HAS_FAN3 && REDUNDANT_PART_COOLING_FAN != 3 FAN_EDIT_ITEMS(3); #elif SNFAN(3) singlenozzle_item(3); #endif - #if HAS_FAN4 + #if HAS_FAN4 && REDUNDANT_PART_COOLING_FAN != 4 FAN_EDIT_ITEMS(4); #elif SNFAN(4) singlenozzle_item(4); #endif - #if HAS_FAN5 + #if HAS_FAN5 && REDUNDANT_PART_COOLING_FAN != 5 FAN_EDIT_ITEMS(5); #elif SNFAN(5) singlenozzle_item(5); #endif - #if HAS_FAN6 + #if HAS_FAN6 && REDUNDANT_PART_COOLING_FAN != 6 FAN_EDIT_ITEMS(6); #elif SNFAN(6) singlenozzle_item(6); #endif - #if HAS_FAN7 + #if HAS_FAN7 && REDUNDANT_PART_COOLING_FAN != 7 FAN_EDIT_ITEMS(7); #elif SNFAN(7) singlenozzle_item(7); diff --git a/Marlin/src/module/motion.cpp b/Marlin/src/module/motion.cpp index d465a00356..b540c9a938 100644 --- a/Marlin/src/module/motion.cpp +++ b/Marlin/src/module/motion.cpp @@ -294,6 +294,10 @@ void report_current_position_projected() { #endif +void home_if_needed(const bool keeplev/*=false*/) { + if (!all_axes_trusted()) gcode.home_all_axes(keeplev); +} + /** * Run out the planner buffer and re-sync the current * position from the last-updated stepper positions. diff --git a/Marlin/src/module/motion.h b/Marlin/src/module/motion.h index d099246f17..c41738a5ab 100644 --- a/Marlin/src/module/motion.h +++ b/Marlin/src/module/motion.h @@ -392,33 +392,35 @@ void set_axis_is_at_home(const AxisEnum axis); void set_axis_never_homed(const AxisEnum axis); linear_axis_bits_t axes_should_home(linear_axis_bits_t axis_bits=linear_bits); bool homing_needed_error(linear_axis_bits_t axis_bits=linear_bits); - FORCE_INLINE void set_axis_unhomed(const AxisEnum axis) { CBI(axis_homed, axis); } - FORCE_INLINE void set_axis_untrusted(const AxisEnum axis) { CBI(axis_trusted, axis); } - FORCE_INLINE void set_all_unhomed() { axis_homed = axis_trusted = 0; } - FORCE_INLINE void set_axis_homed(const AxisEnum axis) { SBI(axis_homed, axis); } - FORCE_INLINE void set_axis_trusted(const AxisEnum axis) { SBI(axis_trusted, axis); } - FORCE_INLINE void set_all_homed() { axis_homed = axis_trusted = linear_bits; } + inline void set_axis_unhomed(const AxisEnum axis) { CBI(axis_homed, axis); } + inline void set_axis_untrusted(const AxisEnum axis) { CBI(axis_trusted, axis); } + inline void set_all_unhomed() { axis_homed = axis_trusted = 0; } + inline void set_axis_homed(const AxisEnum axis) { SBI(axis_homed, axis); } + inline void set_axis_trusted(const AxisEnum axis) { SBI(axis_trusted, axis); } + inline void set_all_homed() { axis_homed = axis_trusted = linear_bits; } #else constexpr linear_axis_bits_t axis_homed = linear_bits, axis_trusted = linear_bits; // Zero-endstop machines are always homed and trusted - FORCE_INLINE void homeaxis(const AxisEnum axis) {} - FORCE_INLINE void set_axis_never_homed(const AxisEnum) {} - FORCE_INLINE linear_axis_bits_t axes_should_home(linear_axis_bits_t=linear_bits) { return false; } - FORCE_INLINE bool homing_needed_error(linear_axis_bits_t=linear_bits) { return false; } - FORCE_INLINE void set_axis_unhomed(const AxisEnum axis) {} - FORCE_INLINE void set_axis_untrusted(const AxisEnum axis) {} - FORCE_INLINE void set_all_unhomed() {} - FORCE_INLINE void set_axis_homed(const AxisEnum axis) {} - FORCE_INLINE void set_axis_trusted(const AxisEnum axis) {} - FORCE_INLINE void set_all_homed() {} + inline void homeaxis(const AxisEnum axis) {} + inline void set_axis_never_homed(const AxisEnum) {} + inline linear_axis_bits_t axes_should_home(linear_axis_bits_t=linear_bits) { return false; } + inline bool homing_needed_error(linear_axis_bits_t=linear_bits) { return false; } + inline void set_axis_unhomed(const AxisEnum axis) {} + inline void set_axis_untrusted(const AxisEnum axis) {} + inline void set_all_unhomed() {} + inline void set_axis_homed(const AxisEnum axis) {} + inline void set_axis_trusted(const AxisEnum axis) {} + inline void set_all_homed() {} #endif -FORCE_INLINE bool axis_was_homed(const AxisEnum axis) { return TEST(axis_homed, axis); } -FORCE_INLINE bool axis_is_trusted(const AxisEnum axis) { return TEST(axis_trusted, axis); } -FORCE_INLINE bool axis_should_home(const AxisEnum axis) { return (axes_should_home() & _BV(axis)) != 0; } -FORCE_INLINE bool no_axes_homed() { return !axis_homed; } -FORCE_INLINE bool all_axes_homed() { return linear_bits == (axis_homed & linear_bits); } -FORCE_INLINE bool homing_needed() { return !all_axes_homed(); } -FORCE_INLINE bool all_axes_trusted() { return linear_bits == (axis_trusted & linear_bits); } +inline bool axis_was_homed(const AxisEnum axis) { return TEST(axis_homed, axis); } +inline bool axis_is_trusted(const AxisEnum axis) { return TEST(axis_trusted, axis); } +inline bool axis_should_home(const AxisEnum axis) { return (axes_should_home() & _BV(axis)) != 0; } +inline bool no_axes_homed() { return !axis_homed; } +inline bool all_axes_homed() { return linear_bits == (axis_homed & linear_bits); } +inline bool homing_needed() { return !all_axes_homed(); } +inline bool all_axes_trusted() { return linear_bits == (axis_trusted & linear_bits); } + +void home_if_needed(const bool keeplev=false); #if ENABLED(NO_MOTION_BEFORE_HOMING) #define MOTION_CONDITIONS (IsRunning() && !homing_needed_error()) diff --git a/Marlin/src/module/stepper/indirection.h b/Marlin/src/module/stepper/indirection.h index 4770fd4dc1..08d0be0b31 100644 --- a/Marlin/src/module/stepper/indirection.h +++ b/Marlin/src/module/stepper/indirection.h @@ -645,6 +645,11 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset #endif +#elif ENABLED(E_DUAL_STEPPER_DRIVERS) + #define E_STEP_WRITE(E,V) do{ E0_STEP_WRITE(V); E1_STEP_WRITE(V); }while(0) + #define NORM_E_DIR(E) do{ E0_DIR_WRITE(!INVERT_E0_DIR); E1_DIR_WRITE(!INVERT_E0_DIR ^ ENABLED(INVERT_E1_VS_E0_DIR)); }while(0) + #define REV_E_DIR(E) do{ E0_DIR_WRITE( INVERT_E0_DIR); E1_DIR_WRITE( INVERT_E0_DIR ^ ENABLED(INVERT_E1_VS_E0_DIR)); }while(0) + #elif E_STEPPERS #define E_STEP_WRITE(E,V) E0_STEP_WRITE(V) #define NORM_E_DIR(E) E0_DIR_WRITE(!INVERT_E0_DIR) @@ -1013,6 +1018,7 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset // #if ENABLED(MIXING_EXTRUDER) + /** * Mixing steppers keep all their enable (and direction) states synchronized */ @@ -1020,6 +1026,12 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset #define _CALL_DIS_E(N) DISABLE_STEPPER_E##N () ; #define ENABLE_AXIS_E0() { RREPEAT(MIXING_STEPPERS, _CALL_ENA_E) } #define DISABLE_AXIS_E0() { RREPEAT(MIXING_STEPPERS, _CALL_DIS_E) } + +#elif ENABLED(E_DUAL_STEPPER_DRIVERS) + + #define ENABLE_AXIS_E0() do{ ENABLE_STEPPER_E0(); ENABLE_STEPPER_E1(); }while(0) + #define DISABLE_AXIS_E0() do{ DISABLE_STEPPER_E0(); DISABLE_STEPPER_E1(); }while(0) + #endif #ifndef ENABLE_AXIS_E0 diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp index e7d4ece721..9274d0631e 100644 --- a/Marlin/src/module/temperature.cpp +++ b/Marlin/src/module/temperature.cpp @@ -333,6 +333,9 @@ const char str_t_thermal_runaway[] PROGMEM = STR_T_THERMAL_RUNAWAY, if (fan >= FAN_COUNT) return; fan_speed[fan] = speed; + #if REDUNDANT_PART_COOLING_FAN + if (fan == 0) fan_speed[REDUNDANT_PART_COOLING_FAN] = speed; + #endif TERN_(REPORT_FAN_CHANGE, report_fan_speed(fan)); } diff --git a/Marlin/src/pins/pins_postprocess.h b/Marlin/src/pins/pins_postprocess.h index bd52e30454..ac4459bd02 100644 --- a/Marlin/src/pins/pins_postprocess.h +++ b/Marlin/src/pins/pins_postprocess.h @@ -543,9 +543,17 @@ #define _EPIN(p,q) __EPIN(p,q) #define DIAG_REMAPPED(p,q) (PIN_EXISTS(q) && _EPIN(p##_E_INDEX, DIAG) == q##_PIN) -// The X2 axis, if any, should be the next open extruder port -#define X2_E_INDEX E_STEPPERS +// The E0/E1 steppers are always used for Dual E +#if ENABLED(E_DUAL_STEPPER_DRIVERS) + #ifndef E1_STEP_PIN + #error "No E1 stepper available for E_DUAL_STEPPER_DRIVERS!" + #endif + #define X2_E_INDEX INCREMENT(E_STEPPERS) +#else + #define X2_E_INDEX E_STEPPERS +#endif +// The X2 axis, if any, should be the next open extruder port #if EITHER(DUAL_X_CARRIAGE, X_DUAL_STEPPER_DRIVERS) #ifndef X2_STEP_PIN #define X2_STEP_PIN _EPIN(X2_E_INDEX, STEP) diff --git a/buildroot/tests/DUE b/buildroot/tests/DUE index 9931776e00..9eb2157428 100755 --- a/buildroot/tests/DUE +++ b/buildroot/tests/DUE @@ -24,7 +24,7 @@ opt_enable S_CURVE_ACCELERATION EEPROM_SETTINGS GCODE_MACROS \ SKEW_CORRECTION SKEW_CORRECTION_FOR_Z SKEW_CORRECTION_GCODE CALIBRATION_GCODE \ BACKLASH_COMPENSATION BACKLASH_GCODE BAUD_RATE_GCODE BEZIER_CURVE_SUPPORT \ FWRETRACT ARC_SUPPORT ARC_P_CIRCLES CNC_WORKSPACE_PLANES CNC_COORDINATE_SYSTEMS \ - PSU_CONTROL AUTO_POWER_CONTROL \ + PSU_CONTROL AUTO_POWER_CONTROL E_DUAL_STEPPER_DRIVERS \ PIDTEMPBED SLOW_PWM_HEATERS THERMAL_PROTECTION_CHAMBER \ PINS_DEBUGGING MAX7219_DEBUG M114_DETAIL \ EXTENSIBLE_UI @@ -38,10 +38,9 @@ restore_configs opt_set MOTHERBOARD BOARD_RADDS NUM_Z_STEPPER_DRIVERS 3 opt_enable USE_XMAX_PLUG USE_YMAX_PLUG ENDSTOPPULLUPS BLTOUCH AUTO_BED_LEVELING_BILINEAR \ Z_STEPPER_AUTO_ALIGN Z_STEPPER_ALIGN_KNOWN_STEPPER_POSITIONS Z_SAFE_HOMING - #TOUCH_UI_FTDI_EVE LCD_ALEPHOBJECTS_CLCD_UI OTHER_PIN_LAYOUT pins_set ramps/RAMPS X_MAX_PIN -1 pins_set ramps/RAMPS Y_MAX_PIN -1 -exec_test $1 $2 "RADDS with ABL (Bilinear), Triple Z Axis, Z_STEPPER_AUTO_ALIGN" "$3" +exec_test $1 $2 "RADDS with ABL (Bilinear), Triple Z Axis, Z_STEPPER_AUTO_ALIGN, E_DUAL_STEPPER_DRIVERS" "$3" # # Test SWITCHING_EXTRUDER diff --git a/buildroot/tests/LPC1768 b/buildroot/tests/LPC1768 index 95a055d695..b4e489d310 100755 --- a/buildroot/tests/LPC1768 +++ b/buildroot/tests/LPC1768 @@ -16,7 +16,7 @@ set -e restore_configs opt_set MOTHERBOARD BOARD_RAMPS_14_RE_ARM_EFB SERIAL_PORT_3 3 \ NEOPIXEL_TYPE NEO_GRB RGB_LED_R_PIN P2_12 RGB_LED_G_PIN P1_23 RGB_LED_B_PIN P1_22 RGB_LED_W_PIN P1_24 -opt_enable FYSETC_MINI_12864_2_1 SDSUPPORT SDCARD_READONLY SERIAL_PORT_2 RGBW_LED \ +opt_enable FYSETC_MINI_12864_2_1 SDSUPPORT SDCARD_READONLY SERIAL_PORT_2 RGBW_LED E_DUAL_STEPPER_DRIVERS \ NEOPIXEL_LED NEOPIXEL_IS_SEQUENTIAL NEOPIXEL_STARTUP_TEST NEOPIXEL_BKGD_INDEX_FIRST NEOPIXEL_BKGD_INDEX_LAST NEOPIXEL_BKGD_COLOR NEOPIXEL_BKGD_ALWAYS_ON exec_test $1 $2 "ReARM EFB VIKI2, SDSUPPORT, 2 Serial ports (USB CDC + UART0), NeoPixel" "$3" diff --git a/buildroot/tests/mega2560 b/buildroot/tests/mega2560 index 3ddb68fe88..0932388969 100755 --- a/buildroot/tests/mega2560 +++ b/buildroot/tests/mega2560 @@ -68,7 +68,8 @@ exec_test $1 $2 "Multiple runout sensors (x5) | Distinct runout states" "$3" # restore_configs opt_set MOTHERBOARD BOARD_AZTEEG_X3_PRO MIXING_STEPPERS 5 LCD_LANGUAGE ru \ - NUM_RUNOUT_SENSORS E_STEPPERS FIL_RUNOUT2_PIN 16 FIL_RUNOUT3_PIN 17 FIL_RUNOUT4_PIN 4 FIL_RUNOUT5_PIN 5 + NUM_RUNOUT_SENSORS E_STEPPERS REDUNDANT_PART_COOLING_FAN 1 \ + FIL_RUNOUT2_PIN 16 FIL_RUNOUT3_PIN 17 FIL_RUNOUT4_PIN 4 FIL_RUNOUT5_PIN 5 opt_enable MIXING_EXTRUDER GRADIENT_MIX GRADIENT_VTOOL CR10_STOCKDISPLAY \ USE_CONTROLLER_FAN CONTROLLER_FAN_EDITABLE CONTROLLER_FAN_IGNORE_Z \ FILAMENT_RUNOUT_SENSOR ADVANCED_PAUSE_FEATURE NOZZLE_PARK_FEATURE