️ Handle shared enable pins (#22824)

x301
Scott Lahteine 3 years ago committed by Scott Lahteine
parent 25a131b942
commit 021ceeba0b

@ -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());

@ -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);

@ -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

@ -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;

@ -74,7 +74,7 @@ public:
#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();

@ -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);

@ -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

@ -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
}

@ -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

@ -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;

@ -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);

@ -29,29 +29,186 @@
#include "../../feature/bedlevel/bedlevel.h"
#endif
/**
* M17: Enable stepper motors
*/
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()
);
#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];
}
}
else {
LCD_MESSAGEPGM(MSG_NO_MOVE);
enable_all_steppers();
#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));
}
/**
* M18, M84: Disable 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()) {
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);
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 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();

@ -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

@ -879,7 +879,7 @@ private:
#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)

@ -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

@ -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;

@ -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("");

@ -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;
}

@ -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) {

@ -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"
));
}

@ -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;

@ -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();
}

@ -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

@ -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

@ -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();

@ -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();

Loading…
Cancel
Save