Merge upstream changes from Marlin 2.1.2
This commit is contained in:
@@ -137,6 +137,10 @@ Stepper stepper; // Singleton
|
||||
#include "../lcd/extui/ui_api.h"
|
||||
#endif
|
||||
|
||||
#if ENABLED(I2S_STEPPER_STREAM)
|
||||
#include "../HAL/ESP32/i2s.h"
|
||||
#endif
|
||||
|
||||
// public:
|
||||
|
||||
#if EITHER(HAS_EXTRA_ENDSTOPS, Z_STEPPER_AUTO_ALIGN)
|
||||
@@ -195,7 +199,7 @@ IF_DISABLED(ADAPTIVE_STEP_SMOOTHING, constexpr) uint8_t Stepper::oversampling_fa
|
||||
|
||||
xyze_long_t Stepper::delta_error{0};
|
||||
|
||||
xyze_ulong_t Stepper::advance_dividend{0};
|
||||
xyze_long_t Stepper::advance_dividend{0};
|
||||
uint32_t Stepper::advance_divisor = 0,
|
||||
Stepper::step_events_completed = 0, // The number of step events executed in the current block
|
||||
Stepper::accelerate_until, // The count at which to stop accelerating
|
||||
@@ -228,6 +232,28 @@ uint32_t Stepper::advance_divisor = 0,
|
||||
Stepper::la_advance_steps = 0;
|
||||
#endif
|
||||
|
||||
#if HAS_SHAPING
|
||||
shaping_time_t ShapingQueue::now = 0;
|
||||
shaping_time_t ShapingQueue::times[shaping_echoes];
|
||||
shaping_echo_axis_t ShapingQueue::echo_axes[shaping_echoes];
|
||||
uint16_t ShapingQueue::tail = 0;
|
||||
|
||||
#if ENABLED(INPUT_SHAPING_X)
|
||||
shaping_time_t ShapingQueue::delay_x;
|
||||
shaping_time_t ShapingQueue::peek_x_val = shaping_time_t(-1);
|
||||
uint16_t ShapingQueue::head_x = 0;
|
||||
uint16_t ShapingQueue::_free_count_x = shaping_echoes - 1;
|
||||
ShapeParams Stepper::shaping_x;
|
||||
#endif
|
||||
#if ENABLED(INPUT_SHAPING_Y)
|
||||
shaping_time_t ShapingQueue::delay_y;
|
||||
shaping_time_t ShapingQueue::peek_y_val = shaping_time_t(-1);
|
||||
uint16_t ShapingQueue::head_y = 0;
|
||||
uint16_t ShapingQueue::_free_count_y = shaping_echoes - 1;
|
||||
ShapeParams Stepper::shaping_y;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if ENABLED(INTEGRATED_BABYSTEPPING)
|
||||
uint32_t Stepper::nextBabystepISR = BABYSTEP_NEVER;
|
||||
#endif
|
||||
@@ -454,12 +480,10 @@ xyze_int8_t Stepper::count_direction{0};
|
||||
#define PULSE_LOW_TICK_COUNT hal_timer_t(NS_TO_PULSE_TIMER_TICKS(_MIN_PULSE_LOW_NS - _MIN(_MIN_PULSE_LOW_NS, TIMER_SETUP_NS)))
|
||||
|
||||
#define USING_TIMED_PULSE() hal_timer_t start_pulse_count = 0
|
||||
#define START_TIMED_PULSE(DIR) (start_pulse_count = HAL_timer_get_count(MF_TIMER_PULSE))
|
||||
#define AWAIT_TIMED_PULSE(DIR) while (PULSE_##DIR##_TICK_COUNT > HAL_timer_get_count(MF_TIMER_PULSE) - start_pulse_count) { }
|
||||
#define START_HIGH_PULSE() START_TIMED_PULSE(HIGH)
|
||||
#define AWAIT_HIGH_PULSE() AWAIT_TIMED_PULSE(HIGH)
|
||||
#define START_LOW_PULSE() START_TIMED_PULSE(LOW)
|
||||
#define AWAIT_LOW_PULSE() AWAIT_TIMED_PULSE(LOW)
|
||||
#define START_TIMED_PULSE() (start_pulse_count = HAL_timer_get_count(MF_TIMER_PULSE))
|
||||
#define AWAIT_TIMED_PULSE(DIR) while (PULSE_##DIR##_TICK_COUNT > HAL_timer_get_count(MF_TIMER_PULSE) - start_pulse_count) { /* nada */ }
|
||||
#define AWAIT_HIGH_PULSE() AWAIT_TIMED_PULSE(HIGH)
|
||||
#define AWAIT_LOW_PULSE() AWAIT_TIMED_PULSE(LOW)
|
||||
|
||||
#if MINIMUM_STEPPER_PRE_DIR_DELAY > 0
|
||||
#define DIR_WAIT_BEFORE() DELAY_NS(MINIMUM_STEPPER_PRE_DIR_DELAY)
|
||||
@@ -555,6 +579,16 @@ void Stepper::disable_all_steppers() {
|
||||
TERN_(EXTENSIBLE_UI, ExtUI::onSteppersDisabled());
|
||||
}
|
||||
|
||||
#define SET_STEP_DIR(A) \
|
||||
if (motor_direction(_AXIS(A))) { \
|
||||
A##_APPLY_DIR(INVERT_##A##_DIR, false); \
|
||||
count_direction[_AXIS(A)] = -1; \
|
||||
} \
|
||||
else { \
|
||||
A##_APPLY_DIR(!INVERT_##A##_DIR, false); \
|
||||
count_direction[_AXIS(A)] = 1; \
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the stepper direction of each axis
|
||||
*
|
||||
@@ -566,16 +600,6 @@ void Stepper::set_directions() {
|
||||
|
||||
DIR_WAIT_BEFORE();
|
||||
|
||||
#define SET_STEP_DIR(A) \
|
||||
if (motor_direction(_AXIS(A))) { \
|
||||
A##_APPLY_DIR(INVERT_##A##_DIR, false); \
|
||||
count_direction[_AXIS(A)] = -1; \
|
||||
} \
|
||||
else { \
|
||||
A##_APPLY_DIR(!INVERT_##A##_DIR, false); \
|
||||
count_direction[_AXIS(A)] = 1; \
|
||||
}
|
||||
|
||||
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
|
||||
@@ -1463,6 +1487,8 @@ void Stepper::isr() {
|
||||
// Enable ISRs to reduce USART processing latency
|
||||
hal.isr_on();
|
||||
|
||||
TERN_(HAS_SHAPING, shaping_isr()); // Do Shaper stepping, if needed
|
||||
|
||||
if (!nextMainISR) pulse_phase_isr(); // 0 = Do coordinated axes Stepper pulses
|
||||
|
||||
#if ENABLED(LIN_ADVANCE)
|
||||
@@ -1493,10 +1519,12 @@ void Stepper::isr() {
|
||||
|
||||
// Get the interval to the next ISR call
|
||||
const uint32_t interval = _MIN(
|
||||
uint32_t(HAL_TIMER_TYPE_MAX), // Come back in a very long time
|
||||
nextMainISR // Time until the next Pulse / Block phase
|
||||
OPTARG(LIN_ADVANCE, nextAdvanceISR) // Come back early for Linear Advance?
|
||||
OPTARG(INTEGRATED_BABYSTEPPING, nextBabystepISR) // Come back early for Babystepping?
|
||||
uint32_t(HAL_TIMER_TYPE_MAX), // Come back in a very long time
|
||||
nextMainISR // Time until the next Pulse / Block phase
|
||||
OPTARG(INPUT_SHAPING_X, ShapingQueue::peek_x()) // Time until next input shaping echo for X
|
||||
OPTARG(INPUT_SHAPING_Y, ShapingQueue::peek_y()) // Time until next input shaping echo for Y
|
||||
OPTARG(LIN_ADVANCE, nextAdvanceISR) // Come back early for Linear Advance?
|
||||
OPTARG(INTEGRATED_BABYSTEPPING, nextBabystepISR) // Come back early for Babystepping?
|
||||
);
|
||||
|
||||
//
|
||||
@@ -1507,14 +1535,9 @@ void Stepper::isr() {
|
||||
//
|
||||
|
||||
nextMainISR -= interval;
|
||||
|
||||
#if ENABLED(LIN_ADVANCE)
|
||||
if (nextAdvanceISR != LA_ADV_NEVER) nextAdvanceISR -= interval;
|
||||
#endif
|
||||
|
||||
#if ENABLED(INTEGRATED_BABYSTEPPING)
|
||||
if (nextBabystepISR != BABYSTEP_NEVER) nextBabystepISR -= interval;
|
||||
#endif
|
||||
TERN_(HAS_SHAPING, ShapingQueue::decrement_delays(interval));
|
||||
TERN_(LIN_ADVANCE, if (nextAdvanceISR != LA_ADV_NEVER) nextAdvanceISR -= interval);
|
||||
TERN_(INTEGRATED_BABYSTEPPING, if (nextBabystepISR != BABYSTEP_NEVER) nextBabystepISR -= interval);
|
||||
|
||||
/**
|
||||
* This needs to avoid a race-condition caused by interleaving
|
||||
@@ -1558,14 +1581,7 @@ void Stepper::isr() {
|
||||
* On AVR the ISR epilogue+prologue is estimated at 100 instructions - Give 8µs as margin
|
||||
* On ARM the ISR epilogue+prologue is estimated at 20 instructions - Give 1µs as margin
|
||||
*/
|
||||
min_ticks = HAL_timer_get_count(MF_TIMER_STEP) + hal_timer_t(
|
||||
#ifdef __AVR__
|
||||
8
|
||||
#else
|
||||
1
|
||||
#endif
|
||||
* (STEPPER_TIMER_TICKS_PER_US)
|
||||
);
|
||||
min_ticks = HAL_timer_get_count(MF_TIMER_STEP) + hal_timer_t(TERN(__AVR__, 8, 1) * (STEPPER_TIMER_TICKS_PER_US));
|
||||
|
||||
/**
|
||||
* NB: If for some reason the stepper monopolizes the MPU, eventually the
|
||||
@@ -1607,11 +1623,24 @@ void Stepper::pulse_phase_isr() {
|
||||
// If we must abort the current block, do so!
|
||||
if (abort_current_block) {
|
||||
abort_current_block = false;
|
||||
if (current_block) discard_current_block();
|
||||
if (current_block) {
|
||||
discard_current_block();
|
||||
#if HAS_SHAPING
|
||||
ShapingQueue::purge();
|
||||
#if ENABLED(INPUT_SHAPING_X)
|
||||
shaping_x.delta_error = 0;
|
||||
shaping_x.last_block_end_pos = count_position.x;
|
||||
#endif
|
||||
#if ENABLED(INPUT_SHAPING_Y)
|
||||
shaping_y.delta_error = 0;
|
||||
shaping_y.last_block_end_pos = count_position.y;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// If there is no current block, do nothing
|
||||
if (!current_block) return;
|
||||
if (!current_block || step_events_completed >= step_event_count) return;
|
||||
|
||||
// Skipping step processing causes motion to freeze
|
||||
if (TERN0(FREEZE_FEATURE, frozen)) return;
|
||||
@@ -1630,6 +1659,9 @@ void Stepper::pulse_phase_isr() {
|
||||
#endif
|
||||
xyze_bool_t step_needed{0};
|
||||
|
||||
// Direct Stepping page?
|
||||
const bool is_page = current_block->is_page();
|
||||
|
||||
do {
|
||||
#define _APPLY_STEP(AXIS, INV, ALWAYS) AXIS ##_APPLY_STEP(INV, ALWAYS)
|
||||
#define _INVERT_STEP_PIN(AXIS) INVERT_## AXIS ##_STEP_PIN
|
||||
@@ -1638,15 +1670,50 @@ void Stepper::pulse_phase_isr() {
|
||||
#define PULSE_PREP(AXIS) do{ \
|
||||
delta_error[_AXIS(AXIS)] += advance_dividend[_AXIS(AXIS)]; \
|
||||
step_needed[_AXIS(AXIS)] = (delta_error[_AXIS(AXIS)] >= 0); \
|
||||
if (step_needed[_AXIS(AXIS)]) { \
|
||||
count_position[_AXIS(AXIS)] += count_direction[_AXIS(AXIS)]; \
|
||||
if (step_needed[_AXIS(AXIS)]) \
|
||||
delta_error[_AXIS(AXIS)] -= advance_divisor; \
|
||||
}while(0)
|
||||
|
||||
// With input shaping, direction changes can happen with almost only
|
||||
// AWAIT_LOW_PULSE() and DIR_WAIT_BEFORE() between steps. To work around
|
||||
// the TMC2208 / TMC2225 shutdown bug (#16076), add a half step hysteresis
|
||||
// in each direction. This results in the position being off by half an
|
||||
// average half step during travel but correct at the end of each segment.
|
||||
#if AXIS_DRIVER_TYPE_X(TMC2208) || AXIS_DRIVER_TYPE_X(TMC2208_STANDALONE) || \
|
||||
AXIS_DRIVER_TYPE_X(TMC5160) || AXIS_DRIVER_TYPE_X(TMC5160_STANDALONE)
|
||||
#define HYSTERESIS_X 64
|
||||
#else
|
||||
#define HYSTERESIS_X 0
|
||||
#endif
|
||||
#if AXIS_DRIVER_TYPE_Y(TMC2208) || AXIS_DRIVER_TYPE_Y(TMC2208_STANDALONE) || \
|
||||
AXIS_DRIVER_TYPE_Y(TMC5160) || AXIS_DRIVER_TYPE_Y(TMC5160_STANDALONE)
|
||||
#define HYSTERESIS_Y 64
|
||||
#else
|
||||
#define HYSTERESIS_Y 0
|
||||
#endif
|
||||
#define _HYSTERESIS(AXIS) HYSTERESIS_##AXIS
|
||||
#define HYSTERESIS(AXIS) _HYSTERESIS(AXIS)
|
||||
|
||||
#define PULSE_PREP_SHAPING(AXIS, DELTA_ERROR, DIVIDEND) do{ \
|
||||
if (step_needed[_AXIS(AXIS)]) { \
|
||||
DELTA_ERROR += (DIVIDEND); \
|
||||
if ((MAXDIR(AXIS) && DELTA_ERROR <= -(64 + HYSTERESIS(AXIS))) || (MINDIR(AXIS) && DELTA_ERROR >= (64 + HYSTERESIS(AXIS)))) { \
|
||||
{ USING_TIMED_PULSE(); START_TIMED_PULSE(); AWAIT_LOW_PULSE(); } \
|
||||
TBI(last_direction_bits, _AXIS(AXIS)); \
|
||||
DIR_WAIT_BEFORE(); \
|
||||
SET_STEP_DIR(AXIS); \
|
||||
DIR_WAIT_AFTER(); \
|
||||
} \
|
||||
step_needed[_AXIS(AXIS)] = DELTA_ERROR <= -(64 + HYSTERESIS(AXIS)) || DELTA_ERROR >= (64 + HYSTERESIS(AXIS)); \
|
||||
if (step_needed[_AXIS(AXIS)]) \
|
||||
DELTA_ERROR += MAXDIR(AXIS) ? -128 : 128; \
|
||||
} \
|
||||
}while(0)
|
||||
|
||||
// Start an active pulse if needed
|
||||
#define PULSE_START(AXIS) do{ \
|
||||
if (step_needed[_AXIS(AXIS)]) { \
|
||||
count_position[_AXIS(AXIS)] += count_direction[_AXIS(AXIS)]; \
|
||||
_APPLY_STEP(AXIS, !_INVERT_STEP_PIN(AXIS), 0); \
|
||||
} \
|
||||
}while(0)
|
||||
@@ -1658,9 +1725,6 @@ void Stepper::pulse_phase_isr() {
|
||||
} \
|
||||
}while(0)
|
||||
|
||||
// Direct Stepping page?
|
||||
const bool is_page = current_block->is_page();
|
||||
|
||||
#if ENABLED(DIRECT_STEPPING)
|
||||
// Direct stepping is currently not ready for HAS_I_AXIS
|
||||
if (is_page) {
|
||||
@@ -1810,6 +1874,24 @@ void Stepper::pulse_phase_isr() {
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if HAS_SHAPING
|
||||
// record an echo if a step is needed in the primary bresenham
|
||||
const bool x_step = TERN0(INPUT_SHAPING_X, shaping_x.enabled && step_needed[X_AXIS]),
|
||||
y_step = TERN0(INPUT_SHAPING_Y, shaping_y.enabled && step_needed[Y_AXIS]);
|
||||
if (x_step || y_step)
|
||||
ShapingQueue::enqueue(x_step, TERN0(INPUT_SHAPING_X, shaping_x.forward), y_step, TERN0(INPUT_SHAPING_Y, shaping_y.forward));
|
||||
|
||||
// do the first part of the secondary bresenham
|
||||
#if ENABLED(INPUT_SHAPING_X)
|
||||
if (shaping_x.enabled)
|
||||
PULSE_PREP_SHAPING(X, shaping_x.delta_error, shaping_x.factor1 * (shaping_x.forward ? 1 : -1));
|
||||
#endif
|
||||
#if ENABLED(INPUT_SHAPING_Y)
|
||||
if (shaping_y.enabled)
|
||||
PULSE_PREP_SHAPING(Y, shaping_y.delta_error, shaping_y.factor1 * (shaping_y.forward ? 1 : -1));
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
#if ISR_MULTI_STEPS
|
||||
@@ -1849,7 +1931,10 @@ void Stepper::pulse_phase_isr() {
|
||||
#endif
|
||||
|
||||
#if ENABLED(MIXING_EXTRUDER)
|
||||
if (step_needed.e) E_STEP_WRITE(mixer.get_next_stepper(), !INVERT_E_STEP_PIN);
|
||||
if (step_needed.e) {
|
||||
count_position[E_AXIS] += count_direction[E_AXIS];
|
||||
E_STEP_WRITE(mixer.get_next_stepper(), !INVERT_E_STEP_PIN);
|
||||
}
|
||||
#elif HAS_E0_STEP
|
||||
PULSE_START(E);
|
||||
#endif
|
||||
@@ -1858,7 +1943,7 @@ void Stepper::pulse_phase_isr() {
|
||||
|
||||
// TODO: need to deal with MINIMUM_STEPPER_PULSE over i2s
|
||||
#if ISR_MULTI_STEPS
|
||||
START_HIGH_PULSE();
|
||||
START_TIMED_PULSE();
|
||||
AWAIT_HIGH_PULSE();
|
||||
#endif
|
||||
|
||||
@@ -1898,12 +1983,66 @@ void Stepper::pulse_phase_isr() {
|
||||
#endif
|
||||
|
||||
#if ISR_MULTI_STEPS
|
||||
if (events_to_do) START_LOW_PULSE();
|
||||
if (events_to_do) START_TIMED_PULSE();
|
||||
#endif
|
||||
|
||||
} while (--events_to_do);
|
||||
}
|
||||
|
||||
#if HAS_SHAPING
|
||||
|
||||
void Stepper::shaping_isr() {
|
||||
xy_bool_t step_needed{0};
|
||||
|
||||
// Clear the echoes that are ready to process. If the buffers are too full and risk overflo, also apply echoes early.
|
||||
TERN_(INPUT_SHAPING_X, step_needed[X_AXIS] = !ShapingQueue::peek_x() || ShapingQueue::free_count_x() < steps_per_isr);
|
||||
TERN_(INPUT_SHAPING_Y, step_needed[Y_AXIS] = !ShapingQueue::peek_y() || ShapingQueue::free_count_y() < steps_per_isr);
|
||||
|
||||
if (bool(step_needed)) while (true) {
|
||||
#if ENABLED(INPUT_SHAPING_X)
|
||||
if (step_needed[X_AXIS]) {
|
||||
const bool forward = ShapingQueue::dequeue_x();
|
||||
PULSE_PREP_SHAPING(X, shaping_x.delta_error, shaping_x.factor2 * (forward ? 1 : -1));
|
||||
PULSE_START(X);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ENABLED(INPUT_SHAPING_Y)
|
||||
if (step_needed[Y_AXIS]) {
|
||||
const bool forward = ShapingQueue::dequeue_y();
|
||||
PULSE_PREP_SHAPING(Y, shaping_y.delta_error, shaping_y.factor2 * (forward ? 1 : -1));
|
||||
PULSE_START(Y);
|
||||
}
|
||||
#endif
|
||||
|
||||
TERN_(I2S_STEPPER_STREAM, i2s_push_sample());
|
||||
|
||||
USING_TIMED_PULSE();
|
||||
if (bool(step_needed)) {
|
||||
#if ISR_MULTI_STEPS
|
||||
START_TIMED_PULSE();
|
||||
AWAIT_HIGH_PULSE();
|
||||
#endif
|
||||
#if ENABLED(INPUT_SHAPING_X)
|
||||
PULSE_STOP(X);
|
||||
#endif
|
||||
#if ENABLED(INPUT_SHAPING_Y)
|
||||
PULSE_STOP(Y);
|
||||
#endif
|
||||
}
|
||||
|
||||
TERN_(INPUT_SHAPING_X, step_needed[X_AXIS] = !ShapingQueue::peek_x() || ShapingQueue::free_count_x() < steps_per_isr);
|
||||
TERN_(INPUT_SHAPING_Y, step_needed[Y_AXIS] = !ShapingQueue::peek_y() || ShapingQueue::free_count_y() < steps_per_isr);
|
||||
|
||||
if (!bool(step_needed)) break;
|
||||
|
||||
START_TIMED_PULSE();
|
||||
AWAIT_LOW_PULSE();
|
||||
}
|
||||
}
|
||||
|
||||
#endif // HAS_SHAPING
|
||||
|
||||
// Calculate timer interval, with all limits applied.
|
||||
uint32_t Stepper::calc_timer_interval(uint32_t step_rate) {
|
||||
#ifdef CPU_32_BIT
|
||||
@@ -2351,35 +2490,55 @@ uint32_t Stepper::block_phase_isr() {
|
||||
acceleration_time = deceleration_time = 0;
|
||||
|
||||
#if ENABLED(ADAPTIVE_STEP_SMOOTHING)
|
||||
uint8_t oversampling = 0; // Assume no axis smoothing (via oversampling)
|
||||
oversampling_factor = 0; // Assume no axis smoothing (via oversampling)
|
||||
// Decide if axis smoothing is possible
|
||||
uint32_t max_rate = current_block->nominal_rate; // Get the step event rate
|
||||
while (max_rate < MIN_STEP_ISR_FREQUENCY) { // As long as more ISRs are possible...
|
||||
max_rate <<= 1; // Try to double the rate
|
||||
if (max_rate < MIN_STEP_ISR_FREQUENCY) // Don't exceed the estimated ISR limit
|
||||
++oversampling; // Increase the oversampling (used for left-shift)
|
||||
++oversampling_factor; // Increase the oversampling (used for left-shift)
|
||||
}
|
||||
oversampling_factor = oversampling; // For all timer interval calculations
|
||||
#else
|
||||
constexpr uint8_t oversampling = 0;
|
||||
#endif
|
||||
|
||||
// Based on the oversampling factor, do the calculations
|
||||
step_event_count = current_block->step_event_count << oversampling;
|
||||
step_event_count = current_block->step_event_count << oversampling_factor;
|
||||
|
||||
// Initialize Bresenham delta errors to 1/2
|
||||
delta_error = TERN_(LIN_ADVANCE, la_delta_error =) -int32_t(step_event_count);
|
||||
|
||||
// Calculate Bresenham dividends and divisors
|
||||
advance_dividend = current_block->steps << 1;
|
||||
advance_dividend = (current_block->steps << 1).asLong();
|
||||
advance_divisor = step_event_count << 1;
|
||||
|
||||
#if ENABLED(INPUT_SHAPING_X)
|
||||
if (shaping_x.enabled) {
|
||||
const int64_t steps = TEST(current_block->direction_bits, X_AXIS) ? -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 = !TEST(current_block->direction_bits, X_AXIS);
|
||||
if (!ShapingQueue::empty_x()) SET_BIT_TO(current_block->direction_bits, X_AXIS, TEST(last_direction_bits, X_AXIS));
|
||||
}
|
||||
#endif
|
||||
|
||||
// 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 = TEST(current_block->direction_bits, Y_AXIS) ? -int64_t(current_block->steps.y) : int64_t(current_block->steps.y);
|
||||
shaping_y.last_block_end_pos += steps;
|
||||
shaping_y.forward = !TEST(current_block->direction_bits, Y_AXIS);
|
||||
if (!ShapingQueue::empty_y()) SET_BIT_TO(current_block->direction_bits, Y_AXIS, TEST(last_direction_bits, Y_AXIS));
|
||||
}
|
||||
#endif
|
||||
|
||||
// No step events completed so far
|
||||
step_events_completed = 0;
|
||||
|
||||
// Compute the acceleration and deceleration points
|
||||
accelerate_until = current_block->accelerate_until << oversampling;
|
||||
decelerate_after = current_block->decelerate_after << oversampling;
|
||||
accelerate_until = current_block->accelerate_until << oversampling_factor;
|
||||
decelerate_after = current_block->decelerate_after << oversampling_factor;
|
||||
|
||||
TERN_(MIXING_EXTRUDER, mixer.stepper_setup(current_block->b_color));
|
||||
|
||||
@@ -2393,7 +2552,7 @@ uint32_t Stepper::block_phase_isr() {
|
||||
#endif
|
||||
if (current_block->la_advance_rate) {
|
||||
// apply LA scaling and discount the effect of frequency scaling
|
||||
la_dividend = (advance_dividend.e << current_block->la_scaling) << oversampling;
|
||||
la_dividend = (advance_dividend.e << current_block->la_scaling) << oversampling_factor;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -2472,31 +2631,28 @@ uint32_t Stepper::block_phase_isr() {
|
||||
// the acceleration and speed values calculated in block_phase_isr().
|
||||
// This helps keep LA in sync with, for example, S_CURVE_ACCELERATION.
|
||||
la_delta_error += la_dividend;
|
||||
if (la_delta_error >= 0) {
|
||||
const bool step_needed = la_delta_error >= 0;
|
||||
if (step_needed) {
|
||||
count_position.e += count_direction.e;
|
||||
la_advance_steps += count_direction.e;
|
||||
la_delta_error -= advance_divisor;
|
||||
|
||||
// Set the STEP pulse ON
|
||||
#if ENABLED(MIXING_EXTRUDER)
|
||||
E_STEP_WRITE(mixer.get_next_stepper(), !INVERT_E_STEP_PIN);
|
||||
#else
|
||||
E_STEP_WRITE(stepper_extruder, !INVERT_E_STEP_PIN);
|
||||
#endif
|
||||
E_STEP_WRITE(TERN(MIXING_EXTRUDER, mixer.get_next_stepper(), stepper_extruder), !INVERT_E_STEP_PIN);
|
||||
}
|
||||
|
||||
TERN_(I2S_STEPPER_STREAM, i2s_push_sample());
|
||||
|
||||
if (step_needed) {
|
||||
// Enforce a minimum duration for STEP pulse ON
|
||||
#if ISR_PULSE_CONTROL
|
||||
USING_TIMED_PULSE();
|
||||
START_HIGH_PULSE();
|
||||
START_TIMED_PULSE();
|
||||
AWAIT_HIGH_PULSE();
|
||||
#endif
|
||||
|
||||
// Set the STEP pulse OFF
|
||||
#if ENABLED(MIXING_EXTRUDER)
|
||||
E_STEP_WRITE(mixer.get_stepper(), INVERT_E_STEP_PIN);
|
||||
#else
|
||||
E_STEP_WRITE(stepper_extruder, INVERT_E_STEP_PIN);
|
||||
#endif
|
||||
E_STEP_WRITE(TERN(MIXING_EXTRUDER, mixer.get_stepper(), stepper_extruder), INVERT_E_STEP_PIN);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2822,6 +2978,79 @@ void Stepper::init() {
|
||||
#endif
|
||||
}
|
||||
|
||||
#if HAS_SHAPING
|
||||
|
||||
/**
|
||||
* Calculate a fixed point factor to apply to the signal and its echo
|
||||
* when shaping an axis.
|
||||
*/
|
||||
void Stepper::set_shaping_damping_ratio(const AxisEnum axis, const float zeta) {
|
||||
// from the damping ratio, get a factor that can be applied to advance_dividend for fixed point maths
|
||||
// for ZV, we use amplitudes 1/(1+K) and K/(1+K) where K = exp(-zeta * M_PI / sqrt(1.0f - zeta * zeta))
|
||||
// which can be converted to 1:7 fixed point with an excellent fit with a 3rd order polynomial
|
||||
float factor2;
|
||||
if (zeta <= 0.0f) factor2 = 64.0f;
|
||||
else if (zeta >= 1.0f) factor2 = 0.0f;
|
||||
else {
|
||||
factor2 = 64.44056192 + -99.02008832 * zeta;
|
||||
const float zeta2 = zeta * zeta;
|
||||
factor2 += -7.58095488 * zeta2;
|
||||
const float zeta3 = zeta2 * zeta;
|
||||
factor2 += 43.073216 * zeta3;
|
||||
factor2 = floor(factor2);
|
||||
}
|
||||
|
||||
const bool was_on = hal.isr_state();
|
||||
hal.isr_off();
|
||||
TERN_(INPUT_SHAPING_X, if (axis == X_AXIS) { shaping_x.factor2 = factor2; shaping_x.factor1 = 128 - factor2; shaping_x.zeta = zeta; })
|
||||
TERN_(INPUT_SHAPING_Y, if (axis == Y_AXIS) { shaping_y.factor2 = factor2; shaping_y.factor1 = 128 - factor2; shaping_y.zeta = zeta; })
|
||||
if (was_on) hal.isr_on();
|
||||
}
|
||||
|
||||
float Stepper::get_shaping_damping_ratio(const AxisEnum axis) {
|
||||
TERN_(INPUT_SHAPING_X, if (axis == X_AXIS) return shaping_x.zeta);
|
||||
TERN_(INPUT_SHAPING_Y, if (axis == Y_AXIS) return shaping_y.zeta);
|
||||
return -1;
|
||||
}
|
||||
|
||||
void Stepper::set_shaping_frequency(const AxisEnum axis, const float freq) {
|
||||
// enabling or disabling shaping whilst moving can result in lost steps
|
||||
Planner::synchronize();
|
||||
|
||||
const bool was_on = hal.isr_state();
|
||||
hal.isr_off();
|
||||
|
||||
const shaping_time_t delay = freq ? float(uint32_t(STEPPER_TIMER_RATE) / 2) / freq : shaping_time_t(-1);
|
||||
#if ENABLED(INPUT_SHAPING_X)
|
||||
if (axis == X_AXIS) {
|
||||
ShapingQueue::set_delay(X_AXIS, delay);
|
||||
shaping_x.frequency = freq;
|
||||
shaping_x.enabled = !!freq;
|
||||
shaping_x.delta_error = 0;
|
||||
shaping_x.last_block_end_pos = count_position.x;
|
||||
}
|
||||
#endif
|
||||
#if ENABLED(INPUT_SHAPING_Y)
|
||||
if (axis == Y_AXIS) {
|
||||
ShapingQueue::set_delay(Y_AXIS, delay);
|
||||
shaping_y.frequency = freq;
|
||||
shaping_y.enabled = !!freq;
|
||||
shaping_y.delta_error = 0;
|
||||
shaping_y.last_block_end_pos = count_position.y;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (was_on) hal.isr_on();
|
||||
}
|
||||
|
||||
float Stepper::get_shaping_frequency(const AxisEnum axis) {
|
||||
TERN_(INPUT_SHAPING_X, if (axis == X_AXIS) return shaping_x.frequency);
|
||||
TERN_(INPUT_SHAPING_Y, if (axis == Y_AXIS) return shaping_y.frequency);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif // HAS_SHAPING
|
||||
|
||||
/**
|
||||
* Set the stepper positions directly in steps
|
||||
*
|
||||
@@ -2832,6 +3061,13 @@ void Stepper::init() {
|
||||
* derive the current XYZE position later on.
|
||||
*/
|
||||
void Stepper::_set_position(const abce_long_t &spos) {
|
||||
#if ENABLED(INPUT_SHAPING_X)
|
||||
const int32_t x_shaping_delta = count_position.x - shaping_x.last_block_end_pos;
|
||||
#endif
|
||||
#if ENABLED(INPUT_SHAPING_Y)
|
||||
const int32_t y_shaping_delta = count_position.y - shaping_y.last_block_end_pos;
|
||||
#endif
|
||||
|
||||
#if ANY(IS_CORE, MARKFORGED_XY, MARKFORGED_YX)
|
||||
#if CORE_IS_XY
|
||||
// corexy positioning
|
||||
@@ -2861,6 +3097,19 @@ void Stepper::_set_position(const abce_long_t &spos) {
|
||||
// default non-h-bot planning
|
||||
count_position = spos;
|
||||
#endif
|
||||
|
||||
#if ENABLED(INPUT_SHAPING_X)
|
||||
if (shaping_x.enabled) {
|
||||
count_position.x += x_shaping_delta;
|
||||
shaping_x.last_block_end_pos = spos.x;
|
||||
}
|
||||
#endif
|
||||
#if ENABLED(INPUT_SHAPING_Y)
|
||||
if (shaping_y.enabled) {
|
||||
count_position.y += y_shaping_delta;
|
||||
shaping_y.last_block_end_pos = spos.y;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2900,6 +3149,8 @@ void Stepper::set_axis_position(const AxisEnum a, const int32_t &v) {
|
||||
#endif
|
||||
|
||||
count_position[a] = v;
|
||||
TERN_(INPUT_SHAPING_X, if (a == X_AXIS) shaping_x.last_block_end_pos = v);
|
||||
TERN_(INPUT_SHAPING_Y, if (a == Y_AXIS) shaping_y.last_block_end_pos = v);
|
||||
|
||||
#ifdef __AVR__
|
||||
// Reenable Stepper ISR
|
||||
@@ -3027,7 +3278,7 @@ void Stepper::report_positions() {
|
||||
|
||||
#if EXTRA_CYCLES_BABYSTEP > 20
|
||||
#define _SAVE_START() const hal_timer_t pulse_start = HAL_timer_get_count(MF_TIMER_PULSE)
|
||||
#define _PULSE_WAIT() while (EXTRA_CYCLES_BABYSTEP > (uint32_t)(HAL_timer_get_count(MF_TIMER_PULSE) - pulse_start) * (PULSE_TIMER_PRESCALE)) { /* nada */ }
|
||||
#define _PULSE_WAIT() while (EXTRA_CYCLES_BABYSTEP > uint32_t(HAL_timer_get_count(MF_TIMER_PULSE) - pulse_start) * (PULSE_TIMER_PRESCALE)) { /* nada */ }
|
||||
#else
|
||||
#define _SAVE_START() NOOP
|
||||
#if EXTRA_CYCLES_BABYSTEP > 0
|
||||
@@ -3865,30 +4116,53 @@ void Stepper::report_positions() {
|
||||
}
|
||||
}
|
||||
|
||||
// MS1 MS2 MS3 Stepper Driver Microstepping mode table
|
||||
#ifndef MICROSTEP1
|
||||
#define MICROSTEP1 LOW,LOW,LOW
|
||||
#endif
|
||||
#if ENABLED(HEROIC_STEPPER_DRIVERS)
|
||||
#ifndef MICROSTEP128
|
||||
#define MICROSTEP128 LOW,HIGH,LOW
|
||||
#endif
|
||||
#else
|
||||
#ifndef MICROSTEP2
|
||||
#define MICROSTEP2 HIGH,LOW,LOW
|
||||
#endif
|
||||
#ifndef MICROSTEP4
|
||||
#define MICROSTEP4 LOW,HIGH,LOW
|
||||
#endif
|
||||
#endif
|
||||
#ifndef MICROSTEP8
|
||||
#define MICROSTEP8 HIGH,HIGH,LOW
|
||||
#endif
|
||||
#ifndef MICROSTEP16
|
||||
#define MICROSTEP16 HIGH,HIGH,LOW
|
||||
#endif
|
||||
|
||||
void Stepper::microstep_mode(const uint8_t driver, const uint8_t stepping_mode) {
|
||||
switch (stepping_mode) {
|
||||
#if HAS_MICROSTEP1
|
||||
#ifdef MICROSTEP1
|
||||
case 1: microstep_ms(driver, MICROSTEP1); break;
|
||||
#endif
|
||||
#if HAS_MICROSTEP2
|
||||
#ifdef MICROSTEP2
|
||||
case 2: microstep_ms(driver, MICROSTEP2); break;
|
||||
#endif
|
||||
#if HAS_MICROSTEP4
|
||||
#ifdef MICROSTEP4
|
||||
case 4: microstep_ms(driver, MICROSTEP4); break;
|
||||
#endif
|
||||
#if HAS_MICROSTEP8
|
||||
#ifdef MICROSTEP8
|
||||
case 8: microstep_ms(driver, MICROSTEP8); break;
|
||||
#endif
|
||||
#if HAS_MICROSTEP16
|
||||
#ifdef MICROSTEP16
|
||||
case 16: microstep_ms(driver, MICROSTEP16); break;
|
||||
#endif
|
||||
#if HAS_MICROSTEP32
|
||||
#ifdef MICROSTEP32
|
||||
case 32: microstep_ms(driver, MICROSTEP32); break;
|
||||
#endif
|
||||
#if HAS_MICROSTEP64
|
||||
#ifdef MICROSTEP64
|
||||
case 64: microstep_ms(driver, MICROSTEP64); break;
|
||||
#endif
|
||||
#if HAS_MICROSTEP128
|
||||
#ifdef MICROSTEP128
|
||||
case 128: microstep_ms(driver, MICROSTEP128); break;
|
||||
#endif
|
||||
|
||||
|
Reference in New Issue
Block a user