🧑‍💻 Change Marlin DIR bits: 1=Forward, 0=Reverse (#25791)

This commit is contained in:
Scott Lahteine
2023-05-15 22:00:15 -05:00
committed by GitHub
parent 48496dfec1
commit 25ddde0394
11 changed files with 265 additions and 329 deletions

View File

@@ -383,111 +383,114 @@ xyze_int8_t Stepper::count_direction{0};
}
#if HAS_SYNCED_X_STEPPERS
#define X_APPLY_DIR(v,Q) do{ X_DIR_WRITE(v); X2_DIR_WRITE(INVERT_DIR(X2_VS_X, v)); }while(0)
#define X_APPLY_DIR(FWD,Q) do{ X_DIR_WRITE(FWD); X2_DIR_WRITE(INVERT_DIR(X2_VS_X, FWD)); }while(0)
#if ENABLED(X_DUAL_ENDSTOPS)
#define X_APPLY_STEP(v,Q) DUAL_ENDSTOP_APPLY_STEP(X,v)
#define X_APPLY_STEP(FWD,Q) DUAL_ENDSTOP_APPLY_STEP(X,FWD)
#else
#define X_APPLY_STEP(v,Q) do{ X_STEP_WRITE(v); X2_STEP_WRITE(v); }while(0)
#define X_APPLY_STEP(FWD,Q) do{ X_STEP_WRITE(FWD); X2_STEP_WRITE(FWD); }while(0)
#endif
#elif ENABLED(DUAL_X_CARRIAGE)
#define X_APPLY_DIR(v,ALWAYS) do{ \
if (extruder_duplication_enabled || ALWAYS) { X_DIR_WRITE(v); X2_DIR_WRITE((v) ^ idex_mirrored_mode); } \
else if (last_moved_extruder) X2_DIR_WRITE(v); else X_DIR_WRITE(v); \
#define X_APPLY_DIR(FWD,ALWAYS) do{ \
if (extruder_duplication_enabled || ALWAYS) { X_DIR_WRITE(FWD); X2_DIR_WRITE((FWD) ^ idex_mirrored_mode); } \
else if (last_moved_extruder) X2_DIR_WRITE(FWD); else X_DIR_WRITE(FWD); \
}while(0)
#define X_APPLY_STEP(v,ALWAYS) do{ \
if (extruder_duplication_enabled || ALWAYS) { X_STEP_WRITE(v); X2_STEP_WRITE(v); } \
else if (last_moved_extruder) X2_STEP_WRITE(v); else X_STEP_WRITE(v); \
#define X_APPLY_STEP(FWD,ALWAYS) do{ \
if (extruder_duplication_enabled || ALWAYS) { X_STEP_WRITE(FWD); X2_STEP_WRITE(FWD); } \
else if (last_moved_extruder) X2_STEP_WRITE(FWD); else X_STEP_WRITE(FWD); \
}while(0)
#elif HAS_X_AXIS
#define X_APPLY_DIR(v,Q) X_DIR_WRITE(v)
#define X_APPLY_STEP(v,Q) X_STEP_WRITE(v)
#define X_APPLY_DIR(FWD,Q) X_DIR_WRITE(FWD)
#define X_APPLY_STEP(FWD,Q) X_STEP_WRITE(FWD)
#endif
#if HAS_SYNCED_Y_STEPPERS
#define Y_APPLY_DIR(v,Q) do{ Y_DIR_WRITE(v); Y2_DIR_WRITE(INVERT_DIR(Y2_VS_Y, v)); }while(0)
#define Y_APPLY_DIR(FWD,Q) do{ Y_DIR_WRITE(FWD); Y2_DIR_WRITE(INVERT_DIR(Y2_VS_Y, FWD)); }while(0)
#if ENABLED(Y_DUAL_ENDSTOPS)
#define Y_APPLY_STEP(v,Q) DUAL_ENDSTOP_APPLY_STEP(Y,v)
#define Y_APPLY_STEP(FWD,Q) DUAL_ENDSTOP_APPLY_STEP(Y,FWD)
#else
#define Y_APPLY_STEP(v,Q) do{ Y_STEP_WRITE(v); Y2_STEP_WRITE(v); }while(0)
#define Y_APPLY_STEP(FWD,Q) do{ Y_STEP_WRITE(FWD); Y2_STEP_WRITE(FWD); }while(0)
#endif
#elif HAS_Y_AXIS
#define Y_APPLY_DIR(v,Q) Y_DIR_WRITE(v)
#define Y_APPLY_STEP(v,Q) Y_STEP_WRITE(v)
#define Y_APPLY_DIR(FWD,Q) Y_DIR_WRITE(FWD)
#define Y_APPLY_STEP(FWD,Q) Y_STEP_WRITE(FWD)
#endif
#if NUM_Z_STEPPERS == 4
#define Z_APPLY_DIR(v,Q) do{ \
Z_DIR_WRITE(v); Z2_DIR_WRITE(INVERT_DIR(Z2_VS_Z, v)); \
Z3_DIR_WRITE(INVERT_DIR(Z3_VS_Z, v)); Z4_DIR_WRITE(INVERT_DIR(Z4_VS_Z, v)); \
#define Z_APPLY_DIR(FWD,Q) do{ \
Z_DIR_WRITE(FWD); Z2_DIR_WRITE(INVERT_DIR(Z2_VS_Z, FWD)); \
Z3_DIR_WRITE(INVERT_DIR(Z3_VS_Z, FWD)); Z4_DIR_WRITE(INVERT_DIR(Z4_VS_Z, FWD)); \
}while(0)
#if ENABLED(Z_MULTI_ENDSTOPS)
#define Z_APPLY_STEP(v,Q) QUAD_ENDSTOP_APPLY_STEP(Z,v)
#define Z_APPLY_STEP(FWD,Q) QUAD_ENDSTOP_APPLY_STEP(Z,FWD)
#elif ENABLED(Z_STEPPER_AUTO_ALIGN)
#define Z_APPLY_STEP(v,Q) QUAD_SEPARATE_APPLY_STEP(Z,v)
#define Z_APPLY_STEP(FWD,Q) QUAD_SEPARATE_APPLY_STEP(Z,FWD)
#else
#define Z_APPLY_STEP(v,Q) do{ Z_STEP_WRITE(v); Z2_STEP_WRITE(v); Z3_STEP_WRITE(v); Z4_STEP_WRITE(v); }while(0)
#define Z_APPLY_STEP(FWD,Q) do{ Z_STEP_WRITE(FWD); Z2_STEP_WRITE(FWD); Z3_STEP_WRITE(FWD); Z4_STEP_WRITE(FWD); }while(0)
#endif
#elif NUM_Z_STEPPERS == 3
#define Z_APPLY_DIR(v,Q) do{ \
Z_DIR_WRITE(v); Z2_DIR_WRITE(INVERT_DIR(Z2_VS_Z, v)); Z3_DIR_WRITE(INVERT_DIR(Z3_VS_Z, v)); \
#define Z_APPLY_DIR(FWD,Q) do{ \
Z_DIR_WRITE(FWD); Z2_DIR_WRITE(INVERT_DIR(Z2_VS_Z, FWD)); Z3_DIR_WRITE(INVERT_DIR(Z3_VS_Z, FWD)); \
}while(0)
#if ENABLED(Z_MULTI_ENDSTOPS)
#define Z_APPLY_STEP(v,Q) TRIPLE_ENDSTOP_APPLY_STEP(Z,v)
#define Z_APPLY_STEP(FWD,Q) TRIPLE_ENDSTOP_APPLY_STEP(Z,FWD)
#elif ENABLED(Z_STEPPER_AUTO_ALIGN)
#define Z_APPLY_STEP(v,Q) TRIPLE_SEPARATE_APPLY_STEP(Z,v)
#define Z_APPLY_STEP(FWD,Q) TRIPLE_SEPARATE_APPLY_STEP(Z,FWD)
#else
#define Z_APPLY_STEP(v,Q) do{ Z_STEP_WRITE(v); Z2_STEP_WRITE(v); Z3_STEP_WRITE(v); }while(0)
#define Z_APPLY_STEP(FWD,Q) do{ Z_STEP_WRITE(FWD); Z2_STEP_WRITE(FWD); Z3_STEP_WRITE(FWD); }while(0)
#endif
#elif NUM_Z_STEPPERS == 2
#define Z_APPLY_DIR(v,Q) do{ Z_DIR_WRITE(v); Z2_DIR_WRITE(INVERT_DIR(Z2_VS_Z, v)); }while(0)
#define Z_APPLY_DIR(FWD,Q) do{ Z_DIR_WRITE(FWD); Z2_DIR_WRITE(INVERT_DIR(Z2_VS_Z, FWD)); }while(0)
#if ENABLED(Z_MULTI_ENDSTOPS)
#define Z_APPLY_STEP(v,Q) DUAL_ENDSTOP_APPLY_STEP(Z,v)
#define Z_APPLY_STEP(FWD,Q) DUAL_ENDSTOP_APPLY_STEP(Z,FWD)
#elif ENABLED(Z_STEPPER_AUTO_ALIGN)
#define Z_APPLY_STEP(v,Q) DUAL_SEPARATE_APPLY_STEP(Z,v)
#define Z_APPLY_STEP(FWD,Q) DUAL_SEPARATE_APPLY_STEP(Z,FWD)
#else
#define Z_APPLY_STEP(v,Q) do{ Z_STEP_WRITE(v); Z2_STEP_WRITE(v); }while(0)
#define Z_APPLY_STEP(FWD,Q) do{ Z_STEP_WRITE(FWD); Z2_STEP_WRITE(FWD); }while(0)
#endif
#elif HAS_Z_AXIS
#define Z_APPLY_DIR(v,Q) Z_DIR_WRITE(v)
#define Z_APPLY_STEP(v,Q) Z_STEP_WRITE(v)
#define Z_APPLY_DIR(FWD,Q) Z_DIR_WRITE(FWD)
#define Z_APPLY_STEP(FWD,Q) Z_STEP_WRITE(FWD)
#endif
#if HAS_I_AXIS
#define I_APPLY_DIR(v,Q) I_DIR_WRITE(v)
#define I_APPLY_STEP(v,Q) I_STEP_WRITE(v)
#define I_APPLY_DIR(FWD,Q) I_DIR_WRITE(FWD)
#define I_APPLY_STEP(FWD,Q) I_STEP_WRITE(FWD)
#endif
#if HAS_J_AXIS
#define J_APPLY_DIR(v,Q) J_DIR_WRITE(v)
#define J_APPLY_STEP(v,Q) J_STEP_WRITE(v)
#define J_APPLY_DIR(FWD,Q) J_DIR_WRITE(FWD)
#define J_APPLY_STEP(FWD,Q) J_STEP_WRITE(FWD)
#endif
#if HAS_K_AXIS
#define K_APPLY_DIR(v,Q) K_DIR_WRITE(v)
#define K_APPLY_STEP(v,Q) K_STEP_WRITE(v)
#define K_APPLY_DIR(FWD,Q) K_DIR_WRITE(FWD)
#define K_APPLY_STEP(FWD,Q) K_STEP_WRITE(FWD)
#endif
#if HAS_U_AXIS
#define U_APPLY_DIR(v,Q) U_DIR_WRITE(v)
#define U_APPLY_STEP(v,Q) U_STEP_WRITE(v)
#define U_APPLY_DIR(FWD,Q) U_DIR_WRITE(FWD)
#define U_APPLY_STEP(FWD,Q) U_STEP_WRITE(FWD)
#endif
#if HAS_V_AXIS
#define V_APPLY_DIR(v,Q) V_DIR_WRITE(v)
#define V_APPLY_STEP(v,Q) V_STEP_WRITE(v)
#define V_APPLY_DIR(FWD,Q) V_DIR_WRITE(FWD)
#define V_APPLY_STEP(FWD,Q) V_STEP_WRITE(FWD)
#endif
#if HAS_W_AXIS
#define W_APPLY_DIR(v,Q) W_DIR_WRITE(v)
#define W_APPLY_STEP(v,Q) W_STEP_WRITE(v)
#define W_APPLY_DIR(FWD,Q) W_DIR_WRITE(FWD)
#define W_APPLY_STEP(FWD,Q) W_STEP_WRITE(FWD)
#endif
#define E0_APPLY_DIR(REV) do{ (REV) ? FWD_E_DIR(0) : REV_E_DIR(0); }while(0)
#define E1_APPLY_DIR(REV) do{ (REV) ? FWD_E_DIR(1) : REV_E_DIR(1); }while(0)
#define E2_APPLY_DIR(REV) do{ (REV) ? FWD_E_DIR(2) : REV_E_DIR(2); }while(0)
#define E3_APPLY_DIR(REV) do{ (REV) ? FWD_E_DIR(3) : REV_E_DIR(3); }while(0)
#define E4_APPLY_DIR(REV) do{ (REV) ? FWD_E_DIR(4) : REV_E_DIR(4); }while(0)
#define E5_APPLY_DIR(REV) do{ (REV) ? FWD_E_DIR(5) : REV_E_DIR(5); }while(0)
#define E6_APPLY_DIR(REV) do{ (REV) ? FWD_E_DIR(6) : REV_E_DIR(6); }while(0)
#define E7_APPLY_DIR(REV) do{ (REV) ? FWD_E_DIR(7) : REV_E_DIR(7); }while(0)
//#define E0_APPLY_DIR(FWD) do{ (FWD) ? FWD_E_DIR(0) : REV_E_DIR(0); }while(0)
//#define E1_APPLY_DIR(FWD) do{ (FWD) ? FWD_E_DIR(1) : REV_E_DIR(1); }while(0)
//#define E2_APPLY_DIR(FWD) do{ (FWD) ? FWD_E_DIR(2) : REV_E_DIR(2); }while(0)
//#define E3_APPLY_DIR(FWD) do{ (FWD) ? FWD_E_DIR(3) : REV_E_DIR(3); }while(0)
//#define E4_APPLY_DIR(FWD) do{ (FWD) ? FWD_E_DIR(4) : REV_E_DIR(4); }while(0)
//#define E5_APPLY_DIR(FWD) do{ (FWD) ? FWD_E_DIR(5) : REV_E_DIR(5); }while(0)
//#define E6_APPLY_DIR(FWD) do{ (FWD) ? FWD_E_DIR(6) : REV_E_DIR(6); }while(0)
//#define E7_APPLY_DIR(FWD) do{ (FWD) ? FWD_E_DIR(7) : REV_E_DIR(7); }while(0)
#if DISABLED(MIXING_EXTRUDER)
#define E_APPLY_STEP(v,Q) E_STEP_WRITE(stepper_extruder, v)
#if ENABLED(MIXING_EXTRUDER)
#define E_APPLY_DIR(FWD,Q) do{ if (FWD) { MIXER_STEPPER_LOOP(j) FWD_E_DIR(j); } else { MIXER_STEPPER_LOOP(j) REV_E_DIR(j); } }while(0)
#else
#define E_APPLY_STEP(FWD,Q) E_STEP_WRITE(stepper_extruder, FWD)
#define E_APPLY_DIR(FWD,Q) do{ if (FWD) { FWD_E_DIR(stepper_extruder); } else { REV_E_DIR(stepper_extruder); } }while(0)
#endif
#define CYCLES_TO_NS(CYC) (1000UL * (CYC) / ((F_CPU) / 1000000))
@@ -602,16 +605,12 @@ void Stepper::disable_all_steppers() {
}
// Set a single axis direction based on the last set flags.
// A direction bit of "1" indicates reverse or negative motion.
#define SET_STEP_DIR(A) \
if (motor_direction(_AXIS(A))) { \
A##_APPLY_DIR(LOW, false); \
count_direction[_AXIS(A)] = -1; \
} \
else { \
A##_APPLY_DIR(HIGH, false); \
count_direction[_AXIS(A)] = 1; \
}
// A direction bit of "1" indicates forward or positive motion.
#define SET_STEP_DIR(A) do{ \
const bool fwd = motor_direction(_AXIS(A)); \
A##_APPLY_DIR(fwd, false); \
count_direction[_AXIS(A)] = fwd ? 1 : -1; \
}while(0)
/**
* Set the stepper direction of each axis
@@ -621,36 +620,15 @@ void Stepper::disable_all_steppers() {
* COREYZ: Y_AXIS=B_AXIS and Z_AXIS=C_AXIS
*/
void Stepper::apply_directions() {
DIR_WAIT_BEFORE();
NUM_AXIS_CODE(
LOGICAL_AXIS_CODE(
SET_STEP_DIR(E),
SET_STEP_DIR(X), SET_STEP_DIR(Y), SET_STEP_DIR(Z), // ABC
SET_STEP_DIR(I), SET_STEP_DIR(J), SET_STEP_DIR(K),
SET_STEP_DIR(U), SET_STEP_DIR(V), SET_STEP_DIR(W)
);
#if HAS_EXTRUDERS
// Because this is valid for the whole block we don't know
// what E steppers will step. Likely all. Set all.
if (motor_direction(E_AXIS)) {
#if ENABLED(MIXING_EXTRUDER)
MIXER_STEPPER_LOOP(j) REV_E_DIR(j);
#else
REV_E_DIR(stepper_extruder);
#endif
count_direction.e = -1;
}
else {
#if ENABLED(MIXING_EXTRUDER)
MIXER_STEPPER_LOOP(j) FWD_E_DIR(j);
#else
FWD_E_DIR(stepper_extruder);
#endif
count_direction.e = 1;
}
#endif // HAS_EXTRUDERS
DIR_WAIT_AFTER();
}
@@ -1858,8 +1836,8 @@ void Stepper::pulse_phase_isr() {
#if STEPPER_PAGE_FORMAT == SP_4x4D_128
#define PAGE_SEGMENT_UPDATE(AXIS, VALUE) do{ \
if ((VALUE) < 7) dm[_AXIS(AXIS)] = true; \
else if ((VALUE) > 7) dm[_AXIS(AXIS)] = false; \
if ((VALUE) < 7) dm[_AXIS(AXIS)] = false; \
else if ((VALUE) > 7) dm[_AXIS(AXIS)] = true; \
page_step_state.sd[_AXIS(AXIS)] = VALUE; \
page_step_state.bd[_AXIS(AXIS)] += VALUE; \
}while(0)
@@ -1884,8 +1862,7 @@ void Stepper::pulse_phase_isr() {
PAGE_SEGMENT_UPDATE(Z, high >> 4);
PAGE_SEGMENT_UPDATE(E, high & 0xF);
if (dm != last_direction_bits)
set_directions(dm);
if (dm != last_direction_bits) set_directions(dm);
} break;
@@ -2409,29 +2386,16 @@ hal_timer_t Stepper::block_phase_isr() {
if (la_active) {
const uint32_t la_step_rate = la_advance_steps > current_block->final_adv_steps ? current_block->la_advance_rate : 0;
if (la_step_rate != step_rate) {
const bool reverse_e = la_step_rate > step_rate;
la_interval = calc_timer_interval((reverse_e ? la_step_rate - step_rate : step_rate - la_step_rate) >> current_block->la_scaling);
const bool forward_e = la_step_rate < step_rate;
la_interval = calc_timer_interval((forward_e ? step_rate - la_step_rate : la_step_rate - step_rate) >> current_block->la_scaling);
if (reverse_e != motor_direction(E_AXIS)) {
if (forward_e != motor_direction(E_AXIS)) {
last_direction_bits.toggle(E_AXIS);
count_direction.e = -count_direction.e;
DIR_WAIT_BEFORE();
if (reverse_e) {
#if ENABLED(MIXING_EXTRUDER)
MIXER_STEPPER_LOOP(j) REV_E_DIR(j);
#else
REV_E_DIR(stepper_extruder);
#endif
}
else {
#if ENABLED(MIXING_EXTRUDER)
MIXER_STEPPER_LOOP(j) FWD_E_DIR(j);
#else
FWD_E_DIR(stepper_extruder);
#endif
}
E_APPLY_DIR(forward_e, false);
DIR_WAIT_AFTER();
}
@@ -2688,13 +2652,13 @@ hal_timer_t Stepper::block_phase_isr() {
#if ENABLED(INPUT_SHAPING_X)
if (shaping_x.enabled) {
const int64_t steps = current_block->direction_bits.x ? -int64_t(current_block->steps.x) : int64_t(current_block->steps.x);
const int64_t steps = current_block->direction_bits.x ? int64_t(current_block->steps.x) : -int64_t(current_block->steps.x);
shaping_x.last_block_end_pos += steps;
// If there are any remaining echos unprocessed, then direction change must
// be delayed and processed in PULSE_PREP_SHAPING. This will cause half a step
// to be missed, which will need recovering and this can be done through shaping_x.remainder.
shaping_x.forward = !current_block->direction_bits.x;
shaping_x.forward = current_block->direction_bits.x;
if (!ShapingQueue::empty_x()) current_block->direction_bits.x = last_direction_bits.x;
}
#endif
@@ -2702,9 +2666,9 @@ hal_timer_t Stepper::block_phase_isr() {
// Y follows the same logic as X (but the comments aren't repeated)
#if ENABLED(INPUT_SHAPING_Y)
if (shaping_y.enabled) {
const int64_t steps = current_block->direction_bits.y ? -int64_t(current_block->steps.y) : int64_t(current_block->steps.y);
const int64_t steps = current_block->direction_bits.y ? int64_t(current_block->steps.y) : -int64_t(current_block->steps.y);
shaping_y.last_block_end_pos += steps;
shaping_y.forward = !current_block->direction_bits.y;
shaping_y.forward = current_block->direction_bits.y;
if (!ShapingQueue::empty_y()) current_block->direction_bits.y = last_direction_bits.y;
}
#endif
@@ -3450,36 +3414,36 @@ void Stepper::report_positions() {
#if HAS_Z_AXIS
// Z is handled differently to update the stepper
// counts (needed by Marlin for bed level probing).
const bool z_dir = TEST(command, FT_BIT_DIR_Z),
const bool z_fwd = TEST(command, FT_BIT_DIR_Z),
z_step = TEST(command, FT_BIT_STEP_Z);
#endif
if (applyDir) {
TERN_(HAS_X_AXIS, X_DIR_WRITE(TEST(command, FT_BIT_DIR_X)));
TERN_(HAS_Y_AXIS, Y_DIR_WRITE(TEST(command, FT_BIT_DIR_Y)));
TERN_(HAS_Z_AXIS, Z_DIR_WRITE(z_dir));
TERN_(HAS_EXTRUDERS, E0_DIR_WRITE(TEST(command, FT_BIT_DIR_E)));
TERN_(HAS_X_AXIS, X_APPLY_DIR(TEST(command, FT_BIT_DIR_X), false));
TERN_(HAS_Y_AXIS, Y_APPLY_DIR(TEST(command, FT_BIT_DIR_Y), false));
TERN_(HAS_Z_AXIS, Z_APPLY_DIR(z_fwd, false));
TERN_(HAS_EXTRUDERS, E_APPLY_DIR(TEST(command, FT_BIT_DIR_E), false));
DIR_WAIT_AFTER();
}
TERN_(HAS_X_AXIS, X_STEP_WRITE(TEST(command, FT_BIT_STEP_X)));
TERN_(HAS_Y_AXIS, Y_STEP_WRITE(TEST(command, FT_BIT_STEP_Y)));
TERN_(HAS_Z_AXIS, Z_STEP_WRITE(z_step));
TERN_(HAS_EXTRUDERS, E0_STEP_WRITE(TEST(command, FT_BIT_STEP_E)));
TERN_(HAS_X_AXIS, X_APPLY_STEP(TEST(command, FT_BIT_STEP_X), false));
TERN_(HAS_Y_AXIS, Y_APPLY_STEP(TEST(command, FT_BIT_STEP_Y), false));
TERN_(HAS_Z_AXIS, Z_APPLY_STEP(z_step, false));
TERN_(HAS_EXTRUDERS, E_APPLY_STEP(TEST(command, FT_BIT_STEP_E), false));
START_TIMED_PULSE();
#if HAS_Z_AXIS
// Update step counts
if (z_step) count_position.z += z_dir ? 1 : -1;
if (z_step) count_position.z += z_fwd ? 1 : -1;
#endif
AWAIT_HIGH_PULSE();
X_STEP_WRITE(0);
TERN_(HAS_Y_AXIS, Y_STEP_WRITE(0));
TERN_(HAS_Z_AXIS, Z_STEP_WRITE(0));
TERN_(HAS_EXTRUDERS, E0_STEP_WRITE(0));
TERN_(HAS_X_AXIS, X_APPLY_STEP(0, false));
TERN_(HAS_Y_AXIS, Y_APPLY_STEP(0, false));
TERN_(HAS_Z_AXIS, Z_APPLY_STEP(0, false));
TERN_(HAS_EXTRUDERS, E_APPLY_STEP(0, false));
} // Stepper::fxdTiCtrl_stepper
@@ -3565,7 +3529,7 @@ void Stepper::report_positions() {
#define _ENABLE_AXIS(A) enable_axis(_AXIS(A))
#define _READ_DIR(AXIS) AXIS ##_DIR_READ()
#define _APPLY_DIR(AXIS, INVERT) AXIS ##_APPLY_DIR(INVERT, true)
#define _APPLY_DIR(AXIS, FWD) AXIS ##_APPLY_DIR(FWD, true)
#if MINIMUM_STEPPER_PULSE
#define STEP_PULSE_CYCLES ((MINIMUM_STEPPER_PULSE) * CYCLES_PER_MICROSECOND)