From 07939a64f3cded5639c3ffe57538bbf66bfebdf9 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Tue, 28 Sep 2021 01:07:51 -0500 Subject: [PATCH] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20Handle=20shared=20enable?= =?UTF-8?q?=20pins=20(#22824)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/MarlinCore.cpp | 80 ++----- Marlin/src/MarlinCore.h | 9 - Marlin/src/feature/controllerfan.cpp | 27 +-- Marlin/src/feature/fwretract.cpp | 4 +- Marlin/src/feature/fwretract.h | 2 +- Marlin/src/feature/mmu/mmu.cpp | 3 +- Marlin/src/feature/mmu/mmu2.cpp | 36 +-- Marlin/src/feature/pause.cpp | 4 +- Marlin/src/feature/power.cpp | 22 +- Marlin/src/feature/powerloss.cpp | 2 +- Marlin/src/gcode/config/M301.cpp | 7 +- Marlin/src/gcode/control/M17_M18_M84.cpp | 210 ++++++++++++++++-- .../src/gcode/feature/fwretract/G10_G11.cpp | 2 +- Marlin/src/gcode/gcode.h | 2 +- Marlin/src/inc/Conditionals_LCD.h | 10 +- .../lcd/extui/anycubic_chiron/chiron_tft.cpp | 3 +- .../anycubic_i3mega/anycubic_i3mega_lcd.cpp | 3 +- .../lcd/extui/dgus_reloaded/DGUSRxHandler.cpp | 7 +- .../lcd/extui/dgus_reloaded/DGUSTxHandler.cpp | 10 +- .../generic/stress_test_screen.cpp | 2 +- Marlin/src/lcd/extui/nextion/nextion_tft.cpp | 3 +- Marlin/src/module/planner.cpp | 70 +++--- Marlin/src/module/probe.cpp | 10 +- Marlin/src/module/settings.cpp | 2 +- Marlin/src/module/stepper.cpp | 131 +++++++++-- Marlin/src/module/stepper.h | 102 +++++++++ 26 files changed, 517 insertions(+), 246 deletions(-) diff --git a/Marlin/src/MarlinCore.cpp b/Marlin/src/MarlinCore.cpp index 280c619ad203d..1b9c8885b1fb0 100644 --- a/Marlin/src/MarlinCore.cpp +++ b/Marlin/src/MarlinCore.cpp @@ -81,10 +81,6 @@ #endif #endif -#if ENABLED(EXTENSIBLE_UI) - #include "lcd/extui/ui_api.h" -#endif - #if HAS_ETHERNET #include "feature/ethernet.h" #endif @@ -312,48 +308,6 @@ bool pin_is_protected(const pin_t pin) { #pragma GCC diagnostic pop -void enable_e_steppers() { - #define _ENA_E(N) ENABLE_AXIS_E##N(); - REPEAT(E_STEPPERS, _ENA_E) -} - -void enable_all_steppers() { - TERN_(AUTO_POWER_CONTROL, powerManager.power_on()); - ENABLE_AXIS_X(); - ENABLE_AXIS_Y(); - ENABLE_AXIS_Z(); - ENABLE_AXIS_I(); // Marlin 6-axis support by DerAndere (https://github.com/DerAndere1/Marlin/wiki) - ENABLE_AXIS_J(); - ENABLE_AXIS_K(); - enable_e_steppers(); - - TERN_(EXTENSIBLE_UI, ExtUI::onSteppersEnabled()); -} - -void disable_e_steppers() { - #define _DIS_E(N) DISABLE_AXIS_E##N(); - REPEAT(E_STEPPERS, _DIS_E) -} - -void disable_e_stepper(const uint8_t e) { - #define _CASE_DIS_E(N) case N: DISABLE_AXIS_E##N(); break; - switch (e) { - REPEAT(E_STEPPERS, _CASE_DIS_E) - } -} - -void disable_all_steppers() { - DISABLE_AXIS_X(); - DISABLE_AXIS_Y(); - DISABLE_AXIS_Z(); - DISABLE_AXIS_I(); - DISABLE_AXIS_J(); - DISABLE_AXIS_K(); - disable_e_steppers(); - - TERN_(EXTENSIBLE_UI, ExtUI::onSteppersDisabled()); -} - /** * A Print Job exists when the timer is running or SD is printing */ @@ -464,13 +418,13 @@ inline void manage_inactivity(const bool no_stepper_sleep=false) { already_shutdown_steppers = true; // L6470 SPI will consume 99% of free time without this // Individual axes will be disabled if configured - if (ENABLED(DISABLE_INACTIVE_X)) DISABLE_AXIS_X(); - if (ENABLED(DISABLE_INACTIVE_Y)) DISABLE_AXIS_Y(); - if (ENABLED(DISABLE_INACTIVE_Z)) DISABLE_AXIS_Z(); - if (ENABLED(DISABLE_INACTIVE_I)) DISABLE_AXIS_I(); - if (ENABLED(DISABLE_INACTIVE_J)) DISABLE_AXIS_J(); - if (ENABLED(DISABLE_INACTIVE_K)) DISABLE_AXIS_K(); - if (ENABLED(DISABLE_INACTIVE_E)) disable_e_steppers(); + TERN_(DISABLE_INACTIVE_X, stepper.disable_axis(X_AXIS)); + TERN_(DISABLE_INACTIVE_Y, stepper.disable_axis(Y_AXIS)); + TERN_(DISABLE_INACTIVE_Z, stepper.disable_axis(Z_AXIS)); + TERN_(DISABLE_INACTIVE_I, stepper.disable_axis(I_AXIS)); + TERN_(DISABLE_INACTIVE_J, stepper.disable_axis(J_AXIS)); + TERN_(DISABLE_INACTIVE_K, stepper.disable_axis(K_AXIS)); + TERN_(DISABLE_INACTIVE_E, stepper.disable_e_steppers()); TERN_(AUTO_BED_LEVELING_UBL, ubl.steppers_were_disabled()); } @@ -689,13 +643,13 @@ inline void manage_inactivity(const bool no_stepper_sleep=false) { #if ENABLED(SWITCHING_EXTRUDER) bool oldstatus; switch (active_extruder) { - default: oldstatus = E0_ENABLE_READ(); ENABLE_AXIS_E0(); break; + default: oldstatus = stepper.AXIS_IS_ENABLED(E_AXIS, 0); stepper.ENABLE_EXTRUDER(0); break; #if E_STEPPERS > 1 - case 2: case 3: oldstatus = E1_ENABLE_READ(); ENABLE_AXIS_E1(); break; + case 2: case 3: oldstatus = stepper.AXIS_IS_ENABLED(E_AXIS, 1); stepper.ENABLE_EXTRUDER(1); break; #if E_STEPPERS > 2 - case 4: case 5: oldstatus = E2_ENABLE_READ(); ENABLE_AXIS_E2(); break; + case 4: case 5: oldstatus = stepper.AXIS_IS_ENABLED(E_AXIS, 2); stepper.ENABLE_EXTRUDER(2); break; #if E_STEPPERS > 3 - case 6: case 7: oldstatus = E3_ENABLE_READ(); ENABLE_AXIS_E3(); break; + case 6: case 7: oldstatus = stepper.AXIS_IS_ENABLED(E_AXIS, 3); stepper.ENABLE_EXTRUDER(3); break; #endif // E_STEPPERS > 3 #endif // E_STEPPERS > 2 #endif // E_STEPPERS > 1 @@ -704,7 +658,7 @@ inline void manage_inactivity(const bool no_stepper_sleep=false) { bool oldstatus; switch (active_extruder) { default: - #define _CASE_EN(N) case N: oldstatus = E##N##_ENABLE_READ(); ENABLE_AXIS_E##N(); break; + #define _CASE_EN(N) case N: oldstatus = stepper.AXIS_IS_ENABLED(E_AXIS, N); stepper.ENABLE_EXTRUDER(N); break; REPEAT(E_STEPPERS, _CASE_EN); } #endif @@ -718,17 +672,17 @@ inline void manage_inactivity(const bool no_stepper_sleep=false) { #if ENABLED(SWITCHING_EXTRUDER) switch (active_extruder) { - default: oldstatus = E0_ENABLE_WRITE(oldstatus); break; + default: if (oldstatus) stepper.ENABLE_EXTRUDER(0); else stepper.DISABLE_EXTRUDER(0); break; #if E_STEPPERS > 1 - case 2: case 3: oldstatus = E1_ENABLE_WRITE(oldstatus); break; + case 2: case 3: if (oldstatus) stepper.ENABLE_EXTRUDER(1); else stepper.DISABLE_EXTRUDER(1); break; #if E_STEPPERS > 2 - case 4: case 5: oldstatus = E2_ENABLE_WRITE(oldstatus); break; + case 4: case 5: if (oldstatus) stepper.ENABLE_EXTRUDER(2); else stepper.DISABLE_EXTRUDER(2); break; #endif // E_STEPPERS > 2 #endif // E_STEPPERS > 1 } #else // !SWITCHING_EXTRUDER switch (active_extruder) { - #define _CASE_RESTORE(N) case N: E##N##_ENABLE_WRITE(oldstatus); break; + #define _CASE_RESTORE(N) case N: if (oldstatus) stepper.ENABLE_EXTRUDER(N); else stepper.DISABLE_EXTRUDER(N); break; REPEAT(E_STEPPERS, _CASE_RESTORE); } #endif // !SWITCHING_EXTRUDER @@ -940,7 +894,7 @@ void minkill(const bool steppers_off/*=false*/) { TERN_(HAS_CUTTER, cutter.kill()); // Reiterate cutter shutdown // Power off all steppers (for M112) or just the E steppers - steppers_off ? disable_all_steppers() : disable_e_steppers(); + steppers_off ? stepper.disable_all_steppers() : stepper.disable_e_steppers(); TERN_(PSU_CONTROL, powerManager.power_off()); diff --git a/Marlin/src/MarlinCore.h b/Marlin/src/MarlinCore.h index 6428b77398335..c3698d616da0b 100644 --- a/Marlin/src/MarlinCore.h +++ b/Marlin/src/MarlinCore.h @@ -38,15 +38,6 @@ inline void idle_no_sleep() { idle(true); } extern bool G38_did_trigger; // Flag from the ISR to indicate the endstop changed #endif -/** - * The axis order in all axis related arrays is X, Y, Z, E - */ -void enable_e_steppers(); -void enable_all_steppers(); -void disable_e_stepper(const uint8_t e); -void disable_e_steppers(); -void disable_all_steppers(); - void kill(PGM_P const lcd_error=nullptr, PGM_P const lcd_component=nullptr, const bool steppers_off=false); void minkill(const bool steppers_off=false); diff --git a/Marlin/src/feature/controllerfan.cpp b/Marlin/src/feature/controllerfan.cpp index 35f567fa8fee8..5efddbb11169d 100644 --- a/Marlin/src/feature/controllerfan.cpp +++ b/Marlin/src/feature/controllerfan.cpp @@ -25,7 +25,7 @@ #if ENABLED(USE_CONTROLLER_FAN) #include "controllerfan.h" -#include "../module/stepper/indirection.h" +#include "../module/stepper.h" #include "../module/temperature.h" ControllerFan controllerFan; @@ -54,33 +54,12 @@ void ControllerFan::update() { if (ELAPSED(ms, nextMotorCheck)) { nextMotorCheck = ms + 2500UL; // Not a time critical function, so only check every 2.5s - #define MOTOR_IS_ON(A,B) (A##_ENABLE_READ() == bool(B##_ENABLE_ON)) - #define _OR_ENABLED_E(N) || MOTOR_IS_ON(E##N,E) - - const bool motor_on = ( - ( DISABLED(CONTROLLER_FAN_IGNORE_Z) && - ( MOTOR_IS_ON(Z,Z) - || TERN0(HAS_Z2_ENABLE, MOTOR_IS_ON(Z2,Z)) - || TERN0(HAS_Z3_ENABLE, MOTOR_IS_ON(Z3,Z)) - || TERN0(HAS_Z4_ENABLE, MOTOR_IS_ON(Z4,Z)) - ) - ) || ( - DISABLED(CONTROLLER_FAN_USE_Z_ONLY) && - ( MOTOR_IS_ON(X,X) || MOTOR_IS_ON(Y,Y) - || TERN0(HAS_X2_ENABLE, MOTOR_IS_ON(X2,X)) - || TERN0(HAS_Y2_ENABLE, MOTOR_IS_ON(Y2,Y)) - #if E_STEPPERS - REPEAT(E_STEPPERS, _OR_ENABLED_E) - #endif - ) - ) - ); - // If any triggers for the controller fan are true... // - At least one stepper driver is enabled // - The heated bed is enabled // - TEMP_SENSOR_BOARD is reporting >= CONTROLLER_FAN_MIN_BOARD_TEMP - if ( motor_on + const ena_mask_t axis_mask = TERN(CONTROLLER_FAN_USE_Z_ONLY, _BV(Z_AXIS), ~TERN0(CONTROLLER_FAN_IGNORE_Z, _BV(Z_AXIS))); + if ( (stepper.axis_enabled.bits & axis_mask) || TERN0(HAS_HEATED_BED, thermalManager.temp_bed.soft_pwm_amount > 0) || TERN0(HAS_CONTROLLER_FAN_MIN_BOARD_TEMP, thermalManager.wholeDegBoard() >= CONTROLLER_FAN_MIN_BOARD_TEMP) ) lastMotorOn = ms; //... set time to NOW so the fan will turn on diff --git a/Marlin/src/feature/fwretract.cpp b/Marlin/src/feature/fwretract.cpp index 26817b9ed23b1..4077d8d1c2098 100644 --- a/Marlin/src/feature/fwretract.cpp +++ b/Marlin/src/feature/fwretract.cpp @@ -75,7 +75,7 @@ void FWRetract::reset() { LOOP_L_N(i, EXTRUDERS) { retracted[i] = false; - TERN_(HAS_MULTI_EXTRUDER, retracted_swap[i] = false); + E_TERN_(retracted_swap[i] = false); current_retract[i] = 0.0; } } @@ -91,7 +91,7 @@ void FWRetract::reset() { * Note: Auto-retract will apply the set Z hop in addition to any Z hop * included in the G-code. Use M207 Z0 to to prevent double hop. */ -void FWRetract::retract(const bool retracting OPTARG(HAS_MULTI_EXTRUDER, bool swapping/*=false*/)) { +void FWRetract::retract(const bool retracting E_OPTARG(bool swapping/*=false*/)) { // Prevent two retracts or recovers in a row if (retracted[active_extruder] == retracting) return; diff --git a/Marlin/src/feature/fwretract.h b/Marlin/src/feature/fwretract.h index 9b0ff19c8bb63..d6d0432e3aa70 100644 --- a/Marlin/src/feature/fwretract.h +++ b/Marlin/src/feature/fwretract.h @@ -74,7 +74,7 @@ class FWRetract { #endif } - static void retract(const bool retracting OPTARG(HAS_MULTI_EXTRUDER, bool swapping = false)); + static void retract(const bool retracting E_OPTARG(bool swapping=false)); static void M207_report(); static void M207(); diff --git a/Marlin/src/feature/mmu/mmu.cpp b/Marlin/src/feature/mmu/mmu.cpp index 718972313844e..6340f3c3017bd 100644 --- a/Marlin/src/feature/mmu/mmu.cpp +++ b/Marlin/src/feature/mmu/mmu.cpp @@ -26,6 +26,7 @@ #include "../MarlinCore.h" #include "../module/planner.h" +#include "../module/stepper.h" void mmu_init() { SET_OUTPUT(E_MUX0_PIN); @@ -35,7 +36,7 @@ void mmu_init() { void select_multiplexed_stepper(const uint8_t e) { planner.synchronize(); - disable_e_steppers(); + stepper.disable_e_steppers(); WRITE(E_MUX0_PIN, TEST(e, 0) ? HIGH : LOW); WRITE(E_MUX1_PIN, TEST(e, 1) ? HIGH : LOW); WRITE(E_MUX2_PIN, TEST(e, 2) ? HIGH : LOW); diff --git a/Marlin/src/feature/mmu/mmu2.cpp b/Marlin/src/feature/mmu/mmu2.cpp index cf03eaf7f6578..3727c8c86dde4 100644 --- a/Marlin/src/feature/mmu/mmu2.cpp +++ b/Marlin/src/feature/mmu/mmu2.cpp @@ -35,7 +35,7 @@ MMU2 mmu2; #include "../../libs/nozzle.h" #include "../../module/temperature.h" #include "../../module/planner.h" -#include "../../module/stepper/indirection.h" +#include "../../module/stepper.h" #include "../../MarlinCore.h" #if ENABLED(HOST_PROMPT_SUPPORT) @@ -486,7 +486,7 @@ static void mmu2_not_responding() { if (index != extruder) { - DISABLE_AXIS_E0(); + stepper.disable_extruder(); ui.status_printf_P(0, GET_TEXT(MSG_MMU2_LOADING_FILAMENT), int(index + 1)); command(MMU_CMD_T0 + index); @@ -495,7 +495,7 @@ static void mmu2_not_responding() { if (load_to_gears()) { extruder = index; // filament change is finished active_extruder = 0; - ENABLE_AXIS_E0(); + stepper.enable_extruder(); SERIAL_ECHO_MSG(STR_ACTIVE_EXTRUDER, extruder); } ui.reset_status(); @@ -531,13 +531,13 @@ static void mmu2_not_responding() { #if ENABLED(MMU2_MENUS) planner.synchronize(); const uint8_t index = mmu2_choose_filament(); - DISABLE_AXIS_E0(); + stepper.disable_extruder(); command(MMU_CMD_T0 + index); manage_response(true, true); if (load_to_gears()) { mmu_loop(); - ENABLE_AXIS_E0(); + stepper.enable_extruder(); extruder = index; active_extruder = 0; } @@ -566,7 +566,7 @@ static void mmu2_not_responding() { set_runout_valid(false); if (index != extruder) { - DISABLE_AXIS_E0(); + stepper.disable_extruder(); if (FILAMENT_PRESENT()) { DEBUG_ECHOLNPGM("Unloading\n"); mmu_loading_flag = false; @@ -582,7 +582,7 @@ static void mmu2_not_responding() { extruder = index; active_extruder = 0; - ENABLE_AXIS_E0(); + stepper.enable_extruder(); SERIAL_ECHO_MSG(STR_ACTIVE_EXTRUDER, extruder); ui.reset_status(); @@ -620,14 +620,14 @@ static void mmu2_not_responding() { #if ENABLED(MMU2_MENUS) planner.synchronize(); uint8_t index = mmu2_choose_filament(); - DISABLE_AXIS_E0(); + stepper.disable_extruder(); command(MMU_CMD_T0 + index); manage_response(true, true); mmu_continue_loading(); command(MMU_CMD_C0); mmu_loop(); - ENABLE_AXIS_E0(); + stepper.enable_extruder(); extruder = index; active_extruder = 0; #else @@ -670,14 +670,14 @@ static void mmu2_not_responding() { set_runout_valid(false); if (index != extruder) { - DISABLE_AXIS_E0(); + stepper.disable_extruder(); ui.status_printf_P(0, GET_TEXT(MSG_MMU2_LOADING_FILAMENT), int(index + 1)); command(MMU_CMD_T0 + index); manage_response(true, true); command(MMU_CMD_C0); extruder = index; //filament change is finished active_extruder = 0; - ENABLE_AXIS_E0(); + stepper.enable_extruder(); SERIAL_ECHO_MSG(STR_ACTIVE_EXTRUDER, extruder); ui.reset_status(); } @@ -714,13 +714,13 @@ static void mmu2_not_responding() { #if ENABLED(MMU2_MENUS) planner.synchronize(); uint8_t index = mmu2_choose_filament(); - DISABLE_AXIS_E0(); + stepper.disable_extruder(); command(MMU_CMD_T0 + index); manage_response(true, true); command(MMU_CMD_C0); mmu_loop(); - ENABLE_AXIS_E0(); + stepper.enable_extruder(); extruder = index; active_extruder = 0; #else @@ -912,7 +912,7 @@ bool MMU2::load_filament_to_nozzle(const uint8_t index) { return false; } - DISABLE_AXIS_E0(); + stepper.disable_extruder(); command(MMU_CMD_T0 + index); manage_response(true, true); @@ -950,7 +950,7 @@ bool MMU2::eject_filament(const uint8_t index, const bool recover) { LCD_MESSAGEPGM(MSG_MMU2_EJECTING_FILAMENT); - ENABLE_AXIS_E0(); + stepper.enable_extruder(); current_position.e -= MMU2_FILAMENTCHANGE_EJECT_FEED; line_to_current_position(MMM_TO_MMS(2500)); planner.synchronize(); @@ -979,7 +979,7 @@ bool MMU2::eject_filament(const uint8_t index, const bool recover) { BUZZ(200, 404); - DISABLE_AXIS_E0(); + stepper.disable_extruder(); return true; } @@ -1016,7 +1016,7 @@ bool MMU2::unload() { void MMU2::execute_extruder_sequence(const E_Step * sequence, int steps) { planner.synchronize(); - ENABLE_AXIS_E0(); + stepper.enable_extruder(); const E_Step* step = sequence; @@ -1034,7 +1034,7 @@ void MMU2::execute_extruder_sequence(const E_Step * sequence, int steps) { step++; } - DISABLE_AXIS_E0(); + stepper.disable_extruder(); } #endif // HAS_PRUSA_MMU2 diff --git a/Marlin/src/feature/pause.cpp b/Marlin/src/feature/pause.cpp index 24cd52e548dc8..d54326116ef8b 100644 --- a/Marlin/src/feature/pause.cpp +++ b/Marlin/src/feature/pause.cpp @@ -302,8 +302,8 @@ bool load_filament(const_float_t slow_load_length/*=0*/, const_float_t fast_load * send current back to their board, potentially frying it. */ inline void disable_active_extruder() { - #if HAS_E_STEPPER_ENABLE - disable_e_stepper(active_extruder); + #if HAS_EXTRUDERS + stepper.DISABLE_EXTRUDER(active_extruder); safe_delay(100); #endif } diff --git a/Marlin/src/feature/power.cpp b/Marlin/src/feature/power.cpp index b86249fbc0527..8116bd2e446d6 100644 --- a/Marlin/src/feature/power.cpp +++ b/Marlin/src/feature/power.cpp @@ -27,7 +27,7 @@ #include "../inc/MarlinConfig.h" #include "power.h" -#include "../module/stepper/indirection.h" +#include "../module/stepper.h" #include "../MarlinCore.h" #if ENABLED(PS_OFF_SOUND) @@ -120,6 +120,9 @@ void Power::power_off() { */ bool Power::is_power_needed() { + // If any of the stepper drivers are enabled... + if (stepper.axis_enabled.bits) return true; + if (printJobOngoing() || printingIsPaused()) return true; #if ENABLED(AUTO_POWER_FANS) @@ -140,23 +143,6 @@ void Power::power_off() { if (TERN0(AUTO_POWER_COOLER_FAN, thermalManager.coolerfan_speed)) return true; - // If any of the drivers or the bed are enabled... - if (X_ENABLE_READ() == X_ENABLE_ON || Y_ENABLE_READ() == Y_ENABLE_ON || Z_ENABLE_READ() == Z_ENABLE_ON - #if HAS_X2_ENABLE - || X2_ENABLE_READ() == X_ENABLE_ON - #endif - #if HAS_Y2_ENABLE - || Y2_ENABLE_READ() == Y_ENABLE_ON - #endif - #if HAS_Z2_ENABLE - || Z2_ENABLE_READ() == Z_ENABLE_ON - #endif - #if E_STEPPERS - #define _OR_ENABLED_E(N) || E##N##_ENABLE_READ() == E_ENABLE_ON - REPEAT(E_STEPPERS, _OR_ENABLED_E) - #endif - ) return true; - #if HAS_HOTEND HOTEND_LOOP() if (thermalManager.degTargetHotend(e) > 0 || thermalManager.temp_hotend[e].soft_pwm_amount > 0) return true; #endif diff --git a/Marlin/src/feature/powerloss.cpp b/Marlin/src/feature/powerloss.cpp index 159121ba45926..8db31daa40332 100644 --- a/Marlin/src/feature/powerloss.cpp +++ b/Marlin/src/feature/powerloss.cpp @@ -186,7 +186,7 @@ void PrintJobRecovery::save(const bool force/*=false*/, const float zraise/*=POW TERN_(GCODE_REPEAT_MARKERS, info.stored_repeat = repeat); TERN_(HAS_HOME_OFFSET, info.home_offset = home_offset); TERN_(HAS_POSITION_SHIFT, info.position_shift = position_shift); - TERN_(HAS_MULTI_EXTRUDER, info.active_extruder = active_extruder); + E_TERN_(info.active_extruder = active_extruder); #if DISABLED(NO_VOLUMETRICS) info.flag.volumetric_enabled = parser.volumetric_enabled; diff --git a/Marlin/src/gcode/config/M301.cpp b/Marlin/src/gcode/config/M301.cpp index 19b438309ce3d..db882b3b6505a 100644 --- a/Marlin/src/gcode/config/M301.cpp +++ b/Marlin/src/gcode/config/M301.cpp @@ -48,10 +48,10 @@ void GcodeSuite::M301() { // multi-extruder PID patch: M301 updates or prints a single extruder's PID values // default behavior (omitting E parameter) is to update for extruder 0 only - int8_t e = parser.byteval('E', -1); // extruder being updated + int8_t e = E_TERN0(parser.byteval('E', -1)); // extruder being updated if (!parser.seen("PID" TERN_(PID_EXTRUSION_SCALING, "CL") TERN_(PID_FAN_SCALING, "F"))) - return M301_report(true, e); + return M301_report(true E_OPTARG(e)); if (e == -1) e = 0; @@ -78,8 +78,9 @@ void GcodeSuite::M301() { SERIAL_ERROR_MSG(STR_INVALID_EXTRUDER); } -void GcodeSuite::M301_report(const bool forReplay/*=true*/, const int8_t eindex/*=-1*/) { +void GcodeSuite::M301_report(const bool forReplay/*=true*/ E_OPTARG(const int8_t eindex/*=-1*/)) { report_heading(forReplay, PSTR(STR_HOTEND_PID)); + IF_DISABLED(HAS_MULTI_EXTRUDER, constexpr int8_t eindex = -1); HOTEND_LOOP() { if (e == eindex || eindex == -1) { report_echo_start(forReplay); diff --git a/Marlin/src/gcode/control/M17_M18_M84.cpp b/Marlin/src/gcode/control/M17_M18_M84.cpp index e6e0f033ecac2..82df20ac45f19 100644 --- a/Marlin/src/gcode/control/M17_M18_M84.cpp +++ b/Marlin/src/gcode/control/M17_M18_M84.cpp @@ -29,29 +29,186 @@ #include "../../feature/bedlevel/bedlevel.h" #endif +#define DEBUG_OUT ENABLED(MARLIN_DEV_MODE) +#include "../../core/debug_out.h" +#include "../../libs/hex_print.h" + +inline axis_flags_t selected_axis_bits() { + axis_flags_t selected{0}; + #if HAS_EXTRUDERS + if (parser.seen('E')) { + if (E_TERN0(parser.has_value())) { + const uint8_t e = parser.value_int(); + if (e < EXTRUDERS) + selected.bits = _BV(INDEX_OF_AXIS(E_AXIS, e)); + } + else + selected.bits = selected.e_bits(); + } + #endif + selected.bits |= LINEAR_AXIS_GANG( + (parser.seen_test('X') << X_AXIS), + | (parser.seen_test('Y') << Y_AXIS), + | (parser.seen_test('Z') << Z_AXIS), + | (parser.seen_test(AXIS4_NAME) << I_AXIS), + | (parser.seen_test(AXIS5_NAME) << J_AXIS), + | (parser.seen_test(AXIS6_NAME) << K_AXIS) + ); + return selected; +} + +// Enable specified axes and warn about other affected axes +void do_enable(const axis_flags_t to_enable) { + const ena_mask_t was_enabled = stepper.axis_enabled.bits, + shall_enable = to_enable.bits & ~was_enabled; + + DEBUG_ECHOLNPGM("Now Enabled: ", hex_word(stepper.axis_enabled.bits), " Enabling: ", hex_word(to_enable.bits), " | ", shall_enable); + + if (!shall_enable) return; // All specified axes already enabled? + + ena_mask_t also_enabled = 0; // Track steppers enabled due to overlap + + // Enable all flagged axes + LOOP_LINEAR_AXES(a) { + if (TEST(shall_enable, a)) { + stepper.enable_axis(AxisEnum(a)); // Mark and enable the requested axis + DEBUG_ECHOLNPGM("Enabled ", axis_codes[a], " (", a, ") with overlap ", hex_word(enable_overlap[a]), " ... Enabled: ", hex_word(stepper.axis_enabled.bits)); + also_enabled |= enable_overlap[a]; + } + } + #if HAS_EXTRUDERS + LOOP_L_N(e, EXTRUDERS) { + const uint8_t a = INDEX_OF_AXIS(E_AXIS, e); + if (TEST(shall_enable, a)) { + stepper.ENABLE_EXTRUDER(e); + DEBUG_ECHOLNPGM("Enabled E", AS_DIGIT(e), " (", a, ") with overlap ", hex_word(enable_overlap[a]), " ... ", hex_word(stepper.axis_enabled.bits)); + also_enabled |= enable_overlap[a]; + } + } + #endif + + if ((also_enabled &= ~(shall_enable | was_enabled))) { + SERIAL_CHAR('('); + LOOP_LINEAR_AXES(a) if (TEST(also_enabled, a)) SERIAL_CHAR(axis_codes[a], ' '); + #if HAS_EXTRUDERS + #define _EN_ALSO(N) if (TEST(also_enabled, INDEX_OF_AXIS(E_AXIS, N))) SERIAL_CHAR('E', '0' + N, ' '); + REPEAT(EXTRUDERS, _EN_ALSO) + #endif + SERIAL_ECHOLNPGM("also enabled)"); + } + + DEBUG_ECHOLNPGM("Enabled Now: ", hex_word(stepper.axis_enabled.bits)); +} + /** - * M17: Enable stepper motors + * M17: Enable stepper motor power for one or more axes. + * Print warnings for axes that share an ENABLE_PIN. + * + * Examples: + * + * M17 XZ ; Enable X and Z axes + * M17 E ; Enable all E steppers + * M17 E1 ; Enable just the E1 stepper */ void GcodeSuite::M17() { if (parser.seen_axis()) { - LOGICAL_AXIS_CODE( - if (TERN0(HAS_E_STEPPER_ENABLE, parser.seen_test('E'))) enable_e_steppers(), - if (parser.seen_test('X')) ENABLE_AXIS_X(), - if (parser.seen_test('Y')) ENABLE_AXIS_Y(), - if (parser.seen_test('Z')) ENABLE_AXIS_Z(), - if (parser.seen_test(AXIS4_NAME)) ENABLE_AXIS_I(), - if (parser.seen_test(AXIS5_NAME)) ENABLE_AXIS_J(), - if (parser.seen_test(AXIS6_NAME)) ENABLE_AXIS_K() - ); + if (any_enable_overlap()) + do_enable(selected_axis_bits()); + else { + #if HAS_EXTRUDERS + if (parser.seen('E')) { + if (parser.has_value()) { + const uint8_t e = parser.value_int(); + if (e < EXTRUDERS) stepper.ENABLE_EXTRUDER(e); + } + else + stepper.enable_e_steppers(); + } + #endif + LINEAR_AXIS_CODE( + if (parser.seen_test('X')) stepper.enable_axis(X_AXIS), + if (parser.seen_test('Y')) stepper.enable_axis(Y_AXIS), + if (parser.seen_test('Z')) stepper.enable_axis(Z_AXIS), + if (parser.seen_test(AXIS4_NAME)) stepper.enable_axis(I_AXIS), + if (parser.seen_test(AXIS5_NAME)) stepper.enable_axis(J_AXIS), + if (parser.seen_test(AXIS6_NAME)) stepper.enable_axis(K_AXIS) + ); + } } else { LCD_MESSAGEPGM(MSG_NO_MOVE); - enable_all_steppers(); + stepper.enable_all_steppers(); } } +void try_to_disable(const axis_flags_t to_disable) { + ena_mask_t still_enabled = to_disable.bits & stepper.axis_enabled.bits; + + DEBUG_ECHOLNPGM("Enabled: ", hex_word(stepper.axis_enabled.bits), " To Disable: ", hex_word(to_disable.bits), " | ", hex_word(still_enabled)); + + if (!still_enabled) return; + + // Attempt to disable all flagged axes + LOOP_LINEAR_AXES(a) + if (TEST(to_disable.bits, a)) { + DEBUG_ECHOPGM("Try to disable ", axis_codes[a], " (", a, ") with overlap ", hex_word(enable_overlap[a]), " ... "); + if (stepper.disable_axis(AxisEnum(a))) { // Mark the requested axis and request to disable + DEBUG_ECHOPGM("OK"); + still_enabled &= ~(_BV(a) | enable_overlap[a]); // If actually disabled, clear one or more tracked bits + } + else + DEBUG_ECHOPGM("OVERLAP"); + DEBUG_ECHOLNPGM(" ... still_enabled=", hex_word(still_enabled)); + } + #if HAS_EXTRUDERS + LOOP_L_N(e, EXTRUDERS) { + const uint8_t a = INDEX_OF_AXIS(E_AXIS, e); + if (TEST(to_disable.bits, a)) { + DEBUG_ECHOPGM("Try to disable E", AS_DIGIT(e), " (", a, ") with overlap ", hex_word(enable_overlap[a]), " ... "); + if (stepper.DISABLE_EXTRUDER(e)) { + DEBUG_ECHOPGM("OK"); + still_enabled &= ~(_BV(a) | enable_overlap[a]); + } + else + DEBUG_ECHOPGM("OVERLAP"); + DEBUG_ECHOLNPGM(" ... still_enabled=", hex_word(still_enabled)); + } + } + #endif + + auto overlap_warning = [](const ena_mask_t axis_bits) { + SERIAL_ECHOPGM(" not disabled. Shared with"); + LOOP_LINEAR_AXES(a) if (TEST(axis_bits, a)) SERIAL_CHAR(' ', axis_codes[a]); + #if HAS_EXTRUDERS + #define _EN_STILLON(N) if (TEST(axis_bits, INDEX_OF_AXIS(E_AXIS, N))) SERIAL_CHAR(' ', 'E', '0' + N); + REPEAT(EXTRUDERS, _EN_STILLON) + #endif + SERIAL_ECHOLNPGM("."); + }; + + // If any of the requested axes are still enabled, give a warning + LOOP_LINEAR_AXES(a) { + if (TEST(still_enabled, a)) { + SERIAL_CHAR(axis_codes[a]); + overlap_warning(stepper.axis_enabled.bits & enable_overlap[a]); + } + } + #if HAS_EXTRUDERS + LOOP_L_N(e, EXTRUDERS) { + const uint8_t a = INDEX_OF_AXIS(E_AXIS, e); + if (TEST(still_enabled, a)) { + SERIAL_CHAR('E', '0' + e); + overlap_warning(stepper.axis_enabled.bits & enable_overlap[a]); + } + } + #endif + + DEBUG_ECHOLNPGM("Enabled Now: ", hex_word(stepper.axis_enabled.bits)); +} + /** - * M18, M84: Disable stepper motors + * M18, M84: Disable stepper motor power for one or more axes. + * Print warnings for axes that share an ENABLE_PIN. */ void GcodeSuite::M18_M84() { if (parser.seenval('S')) { @@ -61,15 +218,26 @@ void GcodeSuite::M18_M84() { else { if (parser.seen_axis()) { planner.synchronize(); - LOGICAL_AXIS_CODE( - if (TERN0(HAS_E_STEPPER_ENABLE, parser.seen_test('E'))) disable_e_steppers(), - if (parser.seen_test('X')) DISABLE_AXIS_X(), - if (parser.seen_test('Y')) DISABLE_AXIS_Y(), - if (parser.seen_test('Z')) DISABLE_AXIS_Z(), - if (parser.seen_test(AXIS4_NAME)) DISABLE_AXIS_I(), - if (parser.seen_test(AXIS5_NAME)) DISABLE_AXIS_J(), - if (parser.seen_test(AXIS6_NAME)) DISABLE_AXIS_K() - ); + if (any_enable_overlap()) + try_to_disable(selected_axis_bits()); + else { + #if HAS_EXTRUDERS + if (parser.seen('E')) { + if (E_TERN0(parser.has_value())) + stepper.DISABLE_EXTRUDER(parser.value_int()); + else + stepper.disable_e_steppers(); + } + #endif + LINEAR_AXIS_CODE( + if (parser.seen_test('X')) stepper.disable_axis(X_AXIS), + if (parser.seen_test('Y')) stepper.disable_axis(Y_AXIS), + if (parser.seen_test('Z')) stepper.disable_axis(Z_AXIS), + if (parser.seen_test(AXIS4_NAME)) stepper.disable_axis(I_AXIS), + if (parser.seen_test(AXIS5_NAME)) stepper.disable_axis(J_AXIS), + if (parser.seen_test(AXIS6_NAME)) stepper.disable_axis(K_AXIS) + ); + } } else planner.finish_and_disable(); diff --git a/Marlin/src/gcode/feature/fwretract/G10_G11.cpp b/Marlin/src/gcode/feature/fwretract/G10_G11.cpp index 35330fe0ac129..1889f83d62118 100644 --- a/Marlin/src/gcode/feature/fwretract/G10_G11.cpp +++ b/Marlin/src/gcode/feature/fwretract/G10_G11.cpp @@ -32,7 +32,7 @@ * G10 - Retract filament according to settings of M207 * TODO: Handle 'G10 P' for tool settings and 'G10 L' for workspace settings */ -void GcodeSuite::G10() { fwretract.retract(true OPTARG(HAS_MULTI_EXTRUDER, parser.boolval('S'))); } +void GcodeSuite::G10() { fwretract.retract(true E_OPTARG(parser.boolval('S'))); } /** * G11 - Recover filament according to settings of M208 diff --git a/Marlin/src/gcode/gcode.h b/Marlin/src/gcode/gcode.h index a7fc7ff9902c1..4a3c865a4fd88 100644 --- a/Marlin/src/gcode/gcode.h +++ b/Marlin/src/gcode/gcode.h @@ -879,7 +879,7 @@ class GcodeSuite { #if ENABLED(PIDTEMP) static void M301(); - static void M301_report(const bool forReplay=true, const int8_t eindex=-1); + static void M301_report(const bool forReplay=true E_OPTARG(const int8_t eindex=-1)); #endif #if ENABLED(PREVENT_COLD_EXTRUSION) diff --git a/Marlin/src/inc/Conditionals_LCD.h b/Marlin/src/inc/Conditionals_LCD.h index 381a0827e1243..99b360f9f0d9b 100644 --- a/Marlin/src/inc/Conditionals_LCD.h +++ b/Marlin/src/inc/Conditionals_LCD.h @@ -587,6 +587,8 @@ * HOTENDS - Number of hotends, whether connected or separate * E_STEPPERS - Number of actual E stepper motors * E_MANUAL - Number of E steppers for LCD move options + * + * These defines must be simple constants for use in REPEAT, etc. */ #if EXTRUDERS #define HAS_EXTRUDERS 1 @@ -605,9 +607,14 @@ #undef DISABLE_E #endif +#define E_OPTARG(N) OPTARG(HAS_MULTI_EXTRUDER, N) +#define E_TERN_(N) TERN_(HAS_MULTI_EXTRUDER, N) +#define E_TERN0(N) TERN0(HAS_MULTI_EXTRUDER, N) + #if ENABLED(E_DUAL_STEPPER_DRIVERS) // E0/E1 steppers act in tandem as E0 #define E_STEPPERS 2 + #define E_MANUAL 1 #elif ENABLED(SWITCHING_EXTRUDER) // One stepper for every two EXTRUDERS @@ -637,7 +644,8 @@ #elif HAS_PRUSA_MMU2 // Průša Multi-Material Unit v2 - #define E_STEPPERS 1 + #define E_STEPPERS 1 + #define E_MANUAL 1 #endif diff --git a/Marlin/src/lcd/extui/anycubic_chiron/chiron_tft.cpp b/Marlin/src/lcd/extui/anycubic_chiron/chiron_tft.cpp index 42364f28908f0..1b572367f2b62 100644 --- a/Marlin/src/lcd/extui/anycubic_chiron/chiron_tft.cpp +++ b/Marlin/src/lcd/extui/anycubic_chiron/chiron_tft.cpp @@ -37,6 +37,7 @@ #include "FileNavigator.h" #include "../../../gcode/queue.h" +#include "../../../module/stepper.h" #include "../../../sd/cardreader.h" #include "../../../libs/numtostr.h" #include "../../../MarlinCore.h" @@ -665,7 +666,7 @@ void ChironTFT::PanelAction(uint8_t req) { case 19: // A19 Motors off if (!isPrinting()) { - disable_all_steppers(); // from marlincore.h + stepper.disable_all_steppers(); SendtoTFTLN(AC_msg_ready); } break; diff --git a/Marlin/src/lcd/extui/anycubic_i3mega/anycubic_i3mega_lcd.cpp b/Marlin/src/lcd/extui/anycubic_i3mega/anycubic_i3mega_lcd.cpp index 4f51e04c2161b..e07e377dfc404 100644 --- a/Marlin/src/lcd/extui/anycubic_i3mega/anycubic_i3mega_lcd.cpp +++ b/Marlin/src/lcd/extui/anycubic_i3mega/anycubic_i3mega_lcd.cpp @@ -27,6 +27,7 @@ #include "../ui_api.h" #include "../../../libs/numtostr.h" +#include "../../../module/stepper.h" // for disable_all_steppers #include "../../../module/motion.h" // for quickstop_stepper, A20 read printing speed, feedrate_percentage #include "../../../MarlinCore.h" // for disable_steppers #include "../../../inc/MarlinConfig.h" @@ -738,7 +739,7 @@ void AnycubicTFTClass::GetCommandFromTFT() { case 19: // A19 stop stepper drivers - sent on stop extrude command and on turn motors off command if (!isPrinting()) { quickstop_stepper(); - disable_all_steppers(); + stepper.disable_all_steppers(); } SENDLINE_PGM(""); diff --git a/Marlin/src/lcd/extui/dgus_reloaded/DGUSRxHandler.cpp b/Marlin/src/lcd/extui/dgus_reloaded/DGUSRxHandler.cpp index 42731cd866674..8567e5c0e784f 100644 --- a/Marlin/src/lcd/extui/dgus_reloaded/DGUSRxHandler.cpp +++ b/Marlin/src/lcd/extui/dgus_reloaded/DGUSRxHandler.cpp @@ -33,6 +33,7 @@ #include "../../../core/language.h" #include "../../../module/temperature.h" #include "../../../module/printcounter.h" +#include "../../../module/stepper.h" #include "../../../gcode/queue.h" #if ENABLED(ADVANCED_PAUSE_FEATURE) #include "../../../feature/pause.h" @@ -375,10 +376,10 @@ void DGUSRxHandler::Steppers(DGUS_VP &vp, void *data_ptr) { switch (control) { case DGUS_Data::Control::ENABLE: - enable_all_steppers(); + stepper.enable_all_steppers(); break; case DGUS_Data::Control::DISABLE: - disable_all_steppers(); + stepper.disable_all_steppers(); break; } @@ -553,7 +554,7 @@ void DGUSRxHandler::FilamentSelect(DGUS_VP &vp, void *data_ptr) { default: return; case DGUS_Data::Extruder::CURRENT: case DGUS_Data::Extruder::E0: - TERN_(HAS_MULTI_EXTRUDER, case DGUS_Data::Extruder::E1:) + E_TERN_(case DGUS_Data::Extruder::E1:) dgus_screen_handler.filament_extruder = extruder; break; } diff --git a/Marlin/src/lcd/extui/dgus_reloaded/DGUSTxHandler.cpp b/Marlin/src/lcd/extui/dgus_reloaded/DGUSTxHandler.cpp index b419428fbc4f7..6c14745904e84 100644 --- a/Marlin/src/lcd/extui/dgus_reloaded/DGUSTxHandler.cpp +++ b/Marlin/src/lcd/extui/dgus_reloaded/DGUSTxHandler.cpp @@ -286,14 +286,8 @@ void DGUSTxHandler::TempMax(DGUS_VP &vp) { } void DGUSTxHandler::StepperStatus(DGUS_VP &vp) { - if (X_ENABLE_READ() == X_ENABLE_ON - && Y_ENABLE_READ() == Y_ENABLE_ON - && Z_ENABLE_READ() == Z_ENABLE_ON) { - dgus_display.Write((uint16_t)vp.addr, Swap16((uint16_t)DGUS_Data::Status::ENABLED)); - } - else { - dgus_display.Write((uint16_t)vp.addr, Swap16((uint16_t)DGUS_Data::Status::DISABLED)); - } + const bool motor_on = stepper.axis_enabled.bits & (_BV(LINEAR_AXES) - 1); + dgus_display.Write((uint16_t)vp.addr, Swap16(uint16_t(motor_on ? DGUS_Data::Status::ENABLED : DGUS_Data::Status::DISABLED))); } void DGUSTxHandler::StepIcons(DGUS_VP &vp) { diff --git a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/stress_test_screen.cpp b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/stress_test_screen.cpp index 6f32bf06d7a53..ab1f96a399c6e 100644 --- a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/stress_test_screen.cpp +++ b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/stress_test_screen.cpp @@ -125,7 +125,7 @@ void StressTestScreen::onIdle() { injectCommands_P(PSTR( "G0 X100 Y100 Z100 F6000\n" "T0\nG4 S1" - TERN_(HAS_MULTI_EXTRUDER, "\nT1\nG4 S1") + E_TERN_("\nT1\nG4 S1") "\nG0 X150 Y150 Z150" )); } diff --git a/Marlin/src/lcd/extui/nextion/nextion_tft.cpp b/Marlin/src/lcd/extui/nextion/nextion_tft.cpp index 50423db4fd11c..c4e0e66a39bc4 100644 --- a/Marlin/src/lcd/extui/nextion/nextion_tft.cpp +++ b/Marlin/src/lcd/extui/nextion/nextion_tft.cpp @@ -33,6 +33,7 @@ #include "../../../MarlinCore.h" #include "../../../feature/pause.h" +#include "../../../module/stepper.h" #include "../../../gcode/queue.h" #include "../../../libs/numtostr.h" #include "../../../sd/cardreader.h" @@ -536,7 +537,7 @@ void NextionTFT::PanelAction(uint8_t req) { case 57: // Disable Motors if (!isPrinting()) { - disable_all_steppers(); // from marlincore.h + stepper.disable_all_steppers(); SEND_TXT("tmppage.M117", "Motors disabled"); } break; diff --git a/Marlin/src/module/planner.cpp b/Marlin/src/module/planner.cpp index f22a99316ffac..c6edfb835e4be 100644 --- a/Marlin/src/module/planner.cpp +++ b/Marlin/src/module/planner.cpp @@ -1375,13 +1375,13 @@ void Planner::check_axes_activity() { // Disable inactive axes // LOGICAL_AXIS_CODE( - if (TERN0(DISABLE_E, !axis_active.e)) disable_e_steppers(), - if (TERN0(DISABLE_X, !axis_active.x)) DISABLE_AXIS_X(), - if (TERN0(DISABLE_Y, !axis_active.y)) DISABLE_AXIS_Y(), - if (TERN0(DISABLE_Z, !axis_active.z)) DISABLE_AXIS_Z(), - if (TERN0(DISABLE_I, !axis_active.i)) DISABLE_AXIS_I(), - if (TERN0(DISABLE_J, !axis_active.j)) DISABLE_AXIS_J(), - if (TERN0(DISABLE_K, !axis_active.k)) DISABLE_AXIS_K() + if (TERN0(DISABLE_E, !axis_active.e)) stepper.disable_e_steppers(), + if (TERN0(DISABLE_X, !axis_active.x)) stepper.disable_axis(X_AXIS), + if (TERN0(DISABLE_Y, !axis_active.y)) stepper.disable_axis(Y_AXIS), + if (TERN0(DISABLE_Z, !axis_active.z)) stepper.disable_axis(Z_AXIS), + if (TERN0(DISABLE_I, !axis_active.i)) stepper.disable_axis(I_AXIS), + if (TERN0(DISABLE_J, !axis_active.j)) stepper.disable_axis(J_AXIS), + if (TERN0(DISABLE_K, !axis_active.k)) stepper.disable_axis(K_AXIS) ); // @@ -1707,7 +1707,7 @@ float Planner::triggered_position_mm(const AxisEnum axis) { void Planner::finish_and_disable() { while (has_blocks_queued() || cleaning_buffer_counter) idle(); - disable_all_steppers(); + stepper.disable_all_steppers(); } /** @@ -2144,7 +2144,7 @@ bool Planner::_populate_block(block_t * const block, bool split_move, block->e_to_p_pressure = baricuda_e_to_p_pressure; #endif - TERN_(HAS_MULTI_EXTRUDER, block->extruder = extruder); + E_TERN_(block->extruder = extruder); #if ENABLED(AUTO_POWER_CONTROL) if (LINEAR_AXIS_GANG( @@ -2160,43 +2160,43 @@ bool Planner::_populate_block(block_t * const block, bool split_move, // Enable active axes #if EITHER(CORE_IS_XY, MARKFORGED_XY) if (block->steps.a || block->steps.b) { - ENABLE_AXIS_X(); - ENABLE_AXIS_Y(); + stepper.enable_axis(X_AXIS); + stepper.enable_axis(Y_AXIS); } #if DISABLED(Z_LATE_ENABLE) - if (block->steps.z) ENABLE_AXIS_Z(); + if (block->steps.z) stepper.enable_axis(Z_AXIS); #endif #elif CORE_IS_XZ if (block->steps.a || block->steps.c) { - ENABLE_AXIS_X(); - ENABLE_AXIS_Z(); + stepper.enable_axis(X_AXIS); + stepper.enable_axis(Z_AXIS); } - if (block->steps.y) ENABLE_AXIS_Y(); + if (block->steps.y) stepper.enable_axis(Y_AXIS); #elif CORE_IS_YZ if (block->steps.b || block->steps.c) { - ENABLE_AXIS_Y(); - ENABLE_AXIS_Z(); + stepper.enable_axis(Y_AXIS); + stepper.enable_axis(Z_AXIS); } - if (block->steps.x) ENABLE_AXIS_X(); + if (block->steps.x) stepper.enable_axis(X_AXIS); #else LINEAR_AXIS_CODE( - if (block->steps.x) ENABLE_AXIS_X(), - if (block->steps.y) ENABLE_AXIS_Y(), - if (TERN(Z_LATE_ENABLE, 0, block->steps.z)) ENABLE_AXIS_Z(), - if (block->steps.i) ENABLE_AXIS_I(), - if (block->steps.j) ENABLE_AXIS_J(), - if (block->steps.k) ENABLE_AXIS_K() + if (block->steps.x) stepper.enable_axis(X_AXIS), + if (block->steps.y) stepper.enable_axis(Y_AXIS), + if (TERN(Z_LATE_ENABLE, 0, block->steps.z)) stepper.enable_axis(Z_AXIS), + if (block->steps.i) stepper.enable_axis(I_AXIS), + if (block->steps.j) stepper.enable_axis(J_AXIS), + if (block->steps.k) stepper.enable_axis(K_AXIS) ); #endif #if EITHER(IS_CORE, MARKFORGED_XY) #if LINEAR_AXES >= 4 - if (block->steps.i) ENABLE_AXIS_I(); + if (block->steps.i) stepper.enable_axis(I_AXIS); #endif #if LINEAR_AXES >= 5 - if (block->steps.j) ENABLE_AXIS_J(); + if (block->steps.j) stepper.enable_axis(J_AXIS); #endif #if LINEAR_AXES >= 6 - if (block->steps.k) ENABLE_AXIS_K(); + if (block->steps.k) stepper.enable_axis(K_AXIS); #endif #endif @@ -2214,27 +2214,27 @@ bool Planner::_populate_block(block_t * const block, bool split_move, #define ENABLE_ONE_E(N) do{ \ if (E_STEPPER_INDEX(extruder) == N) { \ - ENABLE_AXIS_E##N(); \ + stepper.ENABLE_EXTRUDER(N); \ g_uc_extruder_last_move[N] = (BLOCK_BUFFER_SIZE) * 2; \ if ((N) == 0 && TERN0(HAS_DUPLICATION_MODE, extruder_duplication_enabled)) \ - ENABLE_AXIS_E1(); \ + stepper.ENABLE_EXTRUDER(1); \ } \ else if (!g_uc_extruder_last_move[N]) { \ - DISABLE_AXIS_E##N(); \ + stepper.DISABLE_EXTRUDER(N); \ if ((N) == 0 && TERN0(HAS_DUPLICATION_MODE, extruder_duplication_enabled)) \ - DISABLE_AXIS_E1(); \ + stepper.DISABLE_EXTRUDER(1); \ } \ }while(0); #else - #define ENABLE_ONE_E(N) ENABLE_AXIS_E##N(); + #define ENABLE_ONE_E(N) stepper.ENABLE_EXTRUDER(N); #endif REPEAT(E_STEPPERS, ENABLE_ONE_E); // (ENABLE_ONE_E must end with semicolon) } - #endif // EXTRUDERS + #endif // HAS_EXTRUDERS if (esteps) NOLESS(fr_mm_s, settings.min_feedrate_mm_s); @@ -3049,7 +3049,7 @@ bool Planner::buffer_line(const xyze_pos_t &cart, const_feedRate_t fr_mm_s, cons FANS_LOOP(i) block->fan_speed[i] = thermalManager.fan_speed[i]; #endif - TERN_(HAS_MULTI_EXTRUDER, block->extruder = extruder); + E_TERN_(block->extruder = extruder); block->page_idx = page_idx; @@ -3085,7 +3085,7 @@ bool Planner::buffer_line(const xyze_pos_t &cart, const_feedRate_t fr_mm_s, cons // Move buffer head block_buffer_head = next_buffer_head; - enable_all_steppers(); + stepper.enable_all_steppers(); stepper.wake_up(); } diff --git a/Marlin/src/module/probe.cpp b/Marlin/src/module/probe.cpp index 3aca68845d8f9..638bb6be817a9 100644 --- a/Marlin/src/module/probe.cpp +++ b/Marlin/src/module/probe.cpp @@ -251,17 +251,17 @@ xyz_pos_t Probe::offset; // Initialized by settings.load() void Probe::set_probing_paused(const bool dopause) { TERN_(PROBING_HEATERS_OFF, thermalManager.pause_heaters(dopause)); TERN_(PROBING_FANS_OFF, thermalManager.set_fans_paused(dopause)); - TERN_(PROBING_ESTEPPERS_OFF, if (dopause) disable_e_steppers()); + TERN_(PROBING_ESTEPPERS_OFF, if (dopause) stepper.disable_e_steppers()); #if ENABLED(PROBING_STEPPERS_OFF) && DISABLED(DELTA) static uint8_t old_trusted; if (dopause) { old_trusted = axis_trusted; - DISABLE_AXIS_X(); - DISABLE_AXIS_Y(); + stepper.disable_axis(X_AXIS); + stepper.disable_axis(Y_AXIS); } else { - if (TEST(old_trusted, X_AXIS)) ENABLE_AXIS_X(); - if (TEST(old_trusted, Y_AXIS)) ENABLE_AXIS_Y(); + if (TEST(old_trusted, X_AXIS)) stepper.enable_axis(X_AXIS); + if (TEST(old_trusted, Y_AXIS)) stepper.enable_axis(Y_AXIS); axis_trusted = old_trusted; } #endif diff --git a/Marlin/src/module/settings.cpp b/Marlin/src/module/settings.cpp index 921b25dad702a..a4b8bb19e63aa 100644 --- a/Marlin/src/module/settings.cpp +++ b/Marlin/src/module/settings.cpp @@ -3278,7 +3278,7 @@ void MarlinSettings::reset() { // // Tool-changing Parameters // - TERN_(HAS_MULTI_EXTRUDER, gcode.M217_report(forReplay)); + E_TERN_(gcode.M217_report(forReplay)); // // Backlash Compensation diff --git a/Marlin/src/module/stepper.cpp b/Marlin/src/module/stepper.cpp index aa68ccd4ecff9..3a1ee39c529a8 100644 --- a/Marlin/src/module/stepper.cpp +++ b/Marlin/src/module/stepper.cpp @@ -123,6 +123,10 @@ Stepper stepper; // Singleton bool L64XX_OK_to_power_up = false; // flag to keep L64xx steppers powered down after a reset or power up #endif +#if ENABLED(AUTO_POWER_CONTROL) + #include "../feature/power.h" +#endif + #if ENABLED(POWER_LOSS_RECOVERY) #include "../feature/powerloss.h" #endif @@ -131,6 +135,10 @@ Stepper stepper; // Singleton #include "../feature/spindle_laser.h" #endif +#if ENABLED(EXTENSIBLE_UI) + #include "../lcd/extui/ui_api.h" +#endif + // public: #if EITHER(HAS_EXTRA_ENDSTOPS, Z_STEPPER_AUTO_ALIGN) @@ -145,6 +153,8 @@ Stepper stepper; // Singleton #endif #endif +axis_flags_t Stepper::axis_enabled; // {0} + // private: block_t* Stepper::current_block; // (= nullptr) A pointer to the block currently being traced @@ -473,6 +483,89 @@ xyze_int8_t Stepper::count_direction{0}; #define DIR_WAIT_AFTER() #endif +void Stepper::enable_axis(const AxisEnum axis) { + #define _CASE_ENABLE(N) case N##_AXIS: ENABLE_AXIS_##N(); break; + switch (axis) { + LINEAR_AXIS_CODE( + _CASE_ENABLE(X), _CASE_ENABLE(Y), _CASE_ENABLE(Z), + _CASE_ENABLE(I), _CASE_ENABLE(J), _CASE_ENABLE(K) + ); + default: break; + } + mark_axis_enabled(axis); +} + +bool Stepper::disable_axis(const AxisEnum axis) { + mark_axis_disabled(axis); + // If all the axes that share the enabled bit are disabled + const bool can_disable = can_axis_disable(axis); + if (can_disable) { + #define _CASE_DISABLE(N) case N##_AXIS: DISABLE_AXIS_##N(); break; + switch (axis) { + LINEAR_AXIS_CODE( + _CASE_DISABLE(X), _CASE_DISABLE(Y), _CASE_DISABLE(Z), + _CASE_DISABLE(I), _CASE_DISABLE(J), _CASE_DISABLE(K) + ); + default: break; + } + } + return can_disable; +} + +#if HAS_EXTRUDERS + + void Stepper::enable_extruder(E_TERN_(const uint8_t eindex)) { + IF_DISABLED(HAS_MULTI_EXTRUDER, constexpr uint8_t eindex = 0); + #define _CASE_ENA_E(N) case N: ENABLE_AXIS_E##N(); mark_axis_enabled(E_AXIS E_OPTARG(eindex)); break; + switch (eindex) { + REPEAT(E_STEPPERS, _CASE_ENA_E) + } + } + + bool Stepper::disable_extruder(E_TERN_(const uint8_t eindex)) { + IF_DISABLED(HAS_MULTI_EXTRUDER, constexpr uint8_t eindex = 0); + mark_axis_disabled(E_AXIS E_OPTARG(eindex)); + const bool can_disable = can_axis_disable(E_AXIS E_OPTARG(eindex)); + if (can_disable) { + #define _CASE_DIS_E(N) case N: DISABLE_AXIS_E##N(); break; + switch (eindex) { REPEAT(E_STEPPERS, _CASE_DIS_E) } + } + return can_disable; + } + + void Stepper::enable_e_steppers() { + #define _ENA_E(N) ENABLE_EXTRUDER(N); + REPEAT(EXTRUDERS, _ENA_E) + } + + void Stepper::disable_e_steppers() { + #define _DIS_E(N) DISABLE_EXTRUDER(N); + REPEAT(EXTRUDERS, _DIS_E) + } + +#endif + +void Stepper::enable_all_steppers() { + TERN_(AUTO_POWER_CONTROL, powerManager.power_on()); + LINEAR_AXIS_CODE( + enable_axis(X_AXIS), enable_axis(Y_AXIS), enable_axis(Z_AXIS), + enable_axis(I_AXIS), enable_axis(J_AXIS), enable_axis(K_AXIS) + ); + enable_e_steppers(); + + TERN_(EXTENSIBLE_UI, ExtUI::onSteppersEnabled()); +} + +void Stepper::disable_all_steppers() { + LINEAR_AXIS_CODE( + disable_axis(X_AXIS), disable_axis(Y_AXIS), disable_axis(Z_AXIS), + disable_axis(I_AXIS), disable_axis(J_AXIS), disable_axis(K_AXIS) + ); + disable_e_steppers(); + + TERN_(EXTENSIBLE_UI, ExtUI::onSteppersDisabled()); +} + /** * Set the stepper direction of each axis * @@ -494,24 +587,12 @@ void Stepper::set_directions() { count_direction[_AXIS(A)] = 1; \ } - #if HAS_X_DIR - SET_STEP_DIR(X); // A - #endif - #if HAS_Y_DIR - SET_STEP_DIR(Y); // B - #endif - #if HAS_Z_DIR - SET_STEP_DIR(Z); // C - #endif - #if HAS_I_DIR - SET_STEP_DIR(I); - #endif - #if HAS_J_DIR - SET_STEP_DIR(J); - #endif - #if HAS_K_DIR - SET_STEP_DIR(K); - #endif + TERN_(HAS_X_DIR, SET_STEP_DIR(X)); // A + TERN_(HAS_Y_DIR, SET_STEP_DIR(Y)); // B + TERN_(HAS_Z_DIR, SET_STEP_DIR(Z)); // C + TERN_(HAS_I_DIR, SET_STEP_DIR(I)); + TERN_(HAS_J_DIR, SET_STEP_DIR(J)); + TERN_(HAS_K_DIR, SET_STEP_DIR(K)); #if DISABLED(LIN_ADVANCE) #if ENABLED(MIXING_EXTRUDER) @@ -2204,7 +2285,7 @@ uint32_t Stepper::block_phase_isr() { TERN_(MIXING_EXTRUDER, mixer.stepper_setup(current_block->b_color)); - TERN_(HAS_MULTI_EXTRUDER, stepper_extruder = current_block->extruder); + E_TERN_(stepper_extruder = current_block->extruder); // Initialize the trapezoid generator from the current block. #if ENABLED(LIN_ADVANCE) @@ -2227,7 +2308,7 @@ uint32_t Stepper::block_phase_isr() { || current_block->direction_bits != last_direction_bits || TERN(MIXING_EXTRUDER, false, stepper_extruder != last_moved_extruder) ) { - TERN_(HAS_MULTI_EXTRUDER, last_moved_extruder = stepper_extruder); + E_TERN_(last_moved_extruder = stepper_extruder); TERN_(HAS_L64XX, L64XX_OK_to_power_up = true); set_directions(current_block->direction_bits); } @@ -2276,7 +2357,7 @@ uint32_t Stepper::block_phase_isr() { // If delayed Z enable, enable it now. This option will severely interfere with // timing between pulses when chaining motion between blocks, and it could lead // to lost steps in both X and Y axis, so avoid using it unless strictly necessary!! - if (current_block->steps.z) ENABLE_AXIS_Z(); + if (current_block->steps.z) enable_axis(Z_AXIS); #endif // Mark the time_nominal as not calculated yet @@ -2872,7 +2953,7 @@ void Stepper::report_positions() { #if ENABLED(BABYSTEPPING) - #define _ENABLE_AXIS(AXIS) ENABLE_AXIS_## AXIS() + #define _ENABLE_AXIS(A) enable_axis(_AXIS(A)) #define _READ_DIR(AXIS) AXIS ##_DIR_READ() #define _INVERT_DIR(AXIS) INVERT_## AXIS ##_DIR #define _APPLY_DIR(AXIS, INVERT) AXIS ##_APPLY_DIR(INVERT, true) @@ -3000,8 +3081,10 @@ void Stepper::report_positions() { const bool z_direction = direction ^ BABYSTEP_INVERT_Z; - ENABLE_AXIS_X(); ENABLE_AXIS_Y(); ENABLE_AXIS_Z(); - ENABLE_AXIS_I(); ENABLE_AXIS_J(); ENABLE_AXIS_K(); + LINEAR_AXIS_CODE( + enable_axis(X_AXIS), enable_axis(Y_AXIS), enable_axis(Z_AXIS), + enable_axis(I_AXIS), enable_axis(J_AXIS), enable_axis(K_AXIS) + ); DIR_WAIT_BEFORE(); diff --git a/Marlin/src/module/stepper.h b/Marlin/src/module/stepper.h index ca88d6b6b1ada..0bfb418d40dc3 100644 --- a/Marlin/src/module/stepper.h +++ b/Marlin/src/module/stepper.h @@ -236,6 +236,71 @@ // Perhaps DISABLE_MULTI_STEPPING should be required with ADAPTIVE_STEP_SMOOTHING. #define MIN_STEP_ISR_FREQUENCY (MAX_STEP_ISR_FREQUENCY_1X / 2) +#define ENABLE_COUNT (LINEAR_AXES + E_STEPPERS) +typedef IF<(ENABLE_COUNT > 8), uint16_t, uint8_t>::type ena_mask_t; + +// Axis flags type, for enabled state or other simple state +typedef struct { + union { + ena_mask_t bits; + struct { + bool LINEAR_AXIS_LIST(X:1, Y:1, Z:1, I:1, J:1, K:1); + #if HAS_EXTRUDERS + bool LIST_N(EXTRUDERS, E0:1, E1:1, E2:1, E3:1, E4:1, E5:1, E6:1, E7:1); + #endif + }; + }; + constexpr ena_mask_t linear_bits() { return _BV(LINEAR_AXES) - 1; } + constexpr ena_mask_t e_bits() { return (_BV(EXTRUDERS) - 1) << LINEAR_AXES; } +} axis_flags_t; + +// All the stepper enable pins +constexpr pin_t ena_pins[] = { + LINEAR_AXIS_LIST(X_ENABLE_PIN, Y_ENABLE_PIN, Z_ENABLE_PIN, I_ENABLE_PIN, J_ENABLE_PIN, K_ENABLE_PIN), + LIST_N(E_STEPPERS, E0_ENABLE_PIN, E1_ENABLE_PIN, E2_ENABLE_PIN, E3_ENABLE_PIN, E4_ENABLE_PIN, E5_ENABLE_PIN, E6_ENABLE_PIN, E7_ENABLE_PIN) +}; + +// Index of the axis or extruder element in a combined array +constexpr uint8_t index_of_axis(const AxisEnum axis E_OPTARG(const uint8_t eindex=0)) { + return uint8_t(axis) + (E_TERN0(axis < LINEAR_AXES ? 0 : eindex)); +} +//#define __IAX_N(N,V...) _IAX_##N(V) +//#define _IAX_N(N,V...) __IAX_N(N,V) +//#define _IAX_1(A) index_of_axis(A) +//#define _IAX_2(A,B) index_of_axis(A E_OPTARG(B)) +//#define INDEX_OF_AXIS(V...) _IAX_N(TWO_ARGS(V),V) + +#define INDEX_OF_AXIS(A,V...) index_of_axis(A E_OPTARG(V+0)) + +// Bit mask for a matching enable pin, or 0 +constexpr ena_mask_t ena_same(const uint8_t a, const uint8_t b) { + return ena_pins[a] == ena_pins[b] ? _BV(b) : 0; +} + +// Recursively get the enable overlaps mask for a given linear axis or extruder +constexpr ena_mask_t ena_overlap(const uint8_t a=0, const uint8_t b=0) { + return b >= ENABLE_COUNT ? 0 : (a == b ? 0 : ena_same(a, b)) | ena_overlap(a, b + 1); +} + +// Recursively get whether there's any overlap at all +constexpr bool any_enable_overlap(const uint8_t a=0) { + return a >= ENABLE_COUNT ? false : ena_overlap(a) || any_enable_overlap(a + 1); +} + +// Array of axes that overlap with each +// TODO: Consider cases where >=2 steppers are used by a linear axis or extruder +// (e.g., CoreXY, Dual XYZ, or E with multiple steppers, etc.). +constexpr ena_mask_t enable_overlap[] = { + #define _OVERLAP(N) ena_overlap(INDEX_OF_AXIS(AxisEnum(N))), + REPEAT(LINEAR_AXES, _OVERLAP) + #if HAS_EXTRUDERS + #define _E_OVERLAP(N) ena_overlap(INDEX_OF_AXIS(E_AXIS, N)), + REPEAT(E_STEPPERS, _E_OVERLAP) + #endif +}; + +//static_assert(!any_enable_overlap(), "There is some overlap."); + // // Stepper class definition // @@ -519,6 +584,43 @@ class Stepper { static void refresh_motor_power(); #endif + static axis_flags_t axis_enabled; // Axis stepper(s) ENABLED states + + static inline bool axis_is_enabled(const AxisEnum axis E_OPTARG(const uint8_t eindex=0)) { + return TEST(axis_enabled.bits, INDEX_OF_AXIS(axis, eindex)); + } + static inline void mark_axis_enabled(const AxisEnum axis E_OPTARG(const uint8_t eindex=0)) { + SBI(axis_enabled.bits, INDEX_OF_AXIS(axis, eindex)); + } + static inline void mark_axis_disabled(const AxisEnum axis E_OPTARG(const uint8_t eindex=0)) { + CBI(axis_enabled.bits, INDEX_OF_AXIS(axis, eindex)); + } + static inline bool can_axis_disable(const AxisEnum axis E_OPTARG(const uint8_t eindex=0)) { + return !any_enable_overlap() || !(axis_enabled.bits & enable_overlap[INDEX_OF_AXIS(axis, eindex)]); + } + + static void enable_axis(const AxisEnum axis); + static bool disable_axis(const AxisEnum axis); + + #if HAS_EXTRUDERS + static void enable_extruder(E_TERN_(const uint8_t eindex=0)); + static bool disable_extruder(E_TERN_(const uint8_t eindex=0)); + static void enable_e_steppers(); + static void disable_e_steppers(); + #else + static inline void enable_extruder() {} + static inline bool disable_extruder() {} + static inline void enable_e_steppers() {} + static inline void disable_e_steppers() {} + #endif + + #define ENABLE_EXTRUDER(N) enable_extruder(E_TERN_(N)) + #define DISABLE_EXTRUDER(N) disable_extruder(E_TERN_(N)) + #define AXIS_IS_ENABLED(N,V...) axis_is_enabled(N E_OPTARG(#V)) + + static void enable_all_steppers(); + static void disable_all_steppers(); + // Update direction states for all steppers static void set_directions();