mirror of
https://github.com/MarlinFirmware/Marlin.git
synced 2024-11-28 06:21:31 +00:00
⚡️ Smart Adaptive Multi-Stepping (#25474)
This commit is contained in:
parent
6f2d8a3872
commit
3c88270361
@ -194,6 +194,10 @@ uint32_t Stepper::acceleration_time, Stepper::deceleration_time;
|
|||||||
uint8_t Stepper::steps_per_isr = 1; // Count of steps to perform per Stepper ISR call
|
uint8_t Stepper::steps_per_isr = 1; // Count of steps to perform per Stepper ISR call
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if DISABLED(OLD_ADAPTIVE_MULTISTEPPING)
|
||||||
|
hal_timer_t Stepper::time_spent_in_isr = 0, Stepper::time_spent_out_isr = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if ENABLED(FREEZE_FEATURE)
|
#if ENABLED(FREEZE_FEATURE)
|
||||||
bool Stepper::frozen; // = false
|
bool Stepper::frozen; // = false
|
||||||
#endif
|
#endif
|
||||||
@ -614,27 +618,26 @@ void Stepper::set_directions() {
|
|||||||
TERN_(HAS_V_DIR, SET_STEP_DIR(V));
|
TERN_(HAS_V_DIR, SET_STEP_DIR(V));
|
||||||
TERN_(HAS_W_DIR, SET_STEP_DIR(W));
|
TERN_(HAS_W_DIR, SET_STEP_DIR(W));
|
||||||
|
|
||||||
#if ENABLED(MIXING_EXTRUDER)
|
#if HAS_EXTRUDERS
|
||||||
// Because this is valid for the whole block we don't know
|
// Because this is valid for the whole block we don't know
|
||||||
// what E steppers will step. Likely all. Set all.
|
// what E steppers will step. Likely all. Set all.
|
||||||
if (motor_direction(E_AXIS)) {
|
if (motor_direction(E_AXIS)) {
|
||||||
MIXER_STEPPER_LOOP(j) REV_E_DIR(j);
|
#if ENABLED(MIXING_EXTRUDER)
|
||||||
|
MIXER_STEPPER_LOOP(j) REV_E_DIR(j);
|
||||||
|
#else
|
||||||
|
REV_E_DIR(stepper_extruder);
|
||||||
|
#endif
|
||||||
count_direction.e = -1;
|
count_direction.e = -1;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
MIXER_STEPPER_LOOP(j) NORM_E_DIR(j);
|
#if ENABLED(MIXING_EXTRUDER)
|
||||||
|
MIXER_STEPPER_LOOP(j) NORM_E_DIR(j);
|
||||||
|
#else
|
||||||
|
NORM_E_DIR(stepper_extruder);
|
||||||
|
#endif
|
||||||
count_direction.e = 1;
|
count_direction.e = 1;
|
||||||
}
|
}
|
||||||
#elif HAS_EXTRUDERS
|
#endif // HAS_EXTRUDERS
|
||||||
if (motor_direction(E_AXIS)) {
|
|
||||||
REV_E_DIR(stepper_extruder);
|
|
||||||
count_direction.e = -1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
NORM_E_DIR(stepper_extruder);
|
|
||||||
count_direction.e = 1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
DIR_WAIT_AFTER();
|
DIR_WAIT_AFTER();
|
||||||
}
|
}
|
||||||
@ -1587,16 +1590,44 @@ void Stepper::isr() {
|
|||||||
*/
|
*/
|
||||||
min_ticks = HAL_timer_get_count(MF_TIMER_STEP) + hal_timer_t(TERN(__AVR__, 8, 1) * (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));
|
||||||
|
|
||||||
/**
|
#if ENABLED(OLD_ADAPTIVE_MULTISTEPPING)
|
||||||
* NB: If for some reason the stepper monopolizes the MPU, eventually the
|
/**
|
||||||
* timer will wrap around (and so will 'next_isr_ticks'). So, limit the
|
* NB: If for some reason the stepper monopolizes the MPU, eventually the
|
||||||
* loop to 10 iterations. Beyond that, there's no way to ensure correct pulse
|
* timer will wrap around (and so will 'next_isr_ticks'). So, limit the
|
||||||
* timing, since the MCU isn't fast enough.
|
* loop to 10 iterations. Beyond that, there's no way to ensure correct pulse
|
||||||
*/
|
* timing, since the MCU isn't fast enough.
|
||||||
if (!--max_loops) next_isr_ticks = min_ticks;
|
*/
|
||||||
|
if (!--max_loops) next_isr_ticks = min_ticks;
|
||||||
|
#endif
|
||||||
|
|
||||||
// Advance pulses if not enough time to wait for the next ISR
|
// Advance pulses if not enough time to wait for the next ISR
|
||||||
} while (next_isr_ticks < min_ticks);
|
} while (TERN(OLD_ADAPTIVE_MULTISTEPPING, true, --max_loops) && next_isr_ticks < min_ticks);
|
||||||
|
|
||||||
|
#if DISABLED(OLD_ADAPTIVE_MULTISTEPPING)
|
||||||
|
|
||||||
|
// Track the time spent in the ISR
|
||||||
|
const hal_timer_t time_spent = HAL_timer_get_count(MF_TIMER_STEP);
|
||||||
|
time_spent_in_isr += time_spent;
|
||||||
|
|
||||||
|
if (next_isr_ticks < min_ticks) {
|
||||||
|
next_isr_ticks = min_ticks;
|
||||||
|
|
||||||
|
// When forced out of the ISR, increase multi-stepping
|
||||||
|
#if MULTISTEPPING_LIMIT > 1
|
||||||
|
if (steps_per_isr < MULTISTEPPING_LIMIT) {
|
||||||
|
steps_per_isr <<= 1;
|
||||||
|
// ticks_nominal will need to be recalculated if we are in cruise phase
|
||||||
|
ticks_nominal = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Track the time spent voluntarily outside the ISR
|
||||||
|
time_spent_out_isr += next_isr_ticks;
|
||||||
|
time_spent_out_isr -= time_spent;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // !OLD_ADAPTIVE_MULTISTEPPING
|
||||||
|
|
||||||
// Now 'next_isr_ticks' contains the period to the next Stepper ISR - And we are
|
// Now 'next_isr_ticks' contains the period to the next Stepper ISR - And we are
|
||||||
// sure that the time has not arrived yet - Warrantied by the scheduler
|
// sure that the time has not arrived yet - Warrantied by the scheduler
|
||||||
@ -2091,44 +2122,56 @@ hal_timer_t Stepper::calc_timer_interval(uint32_t step_rate) {
|
|||||||
|
|
||||||
// Get the timer interval and the number of loops to perform per tick
|
// Get the timer interval and the number of loops to perform per tick
|
||||||
hal_timer_t Stepper::calc_multistep_timer_interval(uint32_t step_rate) {
|
hal_timer_t Stepper::calc_multistep_timer_interval(uint32_t step_rate) {
|
||||||
#if MULTISTEPPING_LIMIT == 1
|
|
||||||
|
|
||||||
// Just make sure the step rate is doable
|
#if ENABLED(OLD_ADAPTIVE_MULTISTEPPING)
|
||||||
NOMORE(step_rate, uint32_t(MAX_STEP_ISR_FREQUENCY_1X));
|
|
||||||
|
|
||||||
#else
|
#if MULTISTEPPING_LIMIT == 1
|
||||||
|
|
||||||
// The stepping frequency limits for each multistepping rate
|
// Just make sure the step rate is doable
|
||||||
static const uint32_t limit[] PROGMEM = {
|
NOMORE(step_rate, uint32_t(MAX_STEP_ISR_FREQUENCY_1X));
|
||||||
( MAX_STEP_ISR_FREQUENCY_1X )
|
|
||||||
, ( MAX_STEP_ISR_FREQUENCY_2X >> 1)
|
|
||||||
#if MULTISTEPPING_LIMIT >= 4
|
|
||||||
, ( MAX_STEP_ISR_FREQUENCY_4X >> 2)
|
|
||||||
#endif
|
|
||||||
#if MULTISTEPPING_LIMIT >= 8
|
|
||||||
, ( MAX_STEP_ISR_FREQUENCY_8X >> 3)
|
|
||||||
#endif
|
|
||||||
#if MULTISTEPPING_LIMIT >= 16
|
|
||||||
, ( MAX_STEP_ISR_FREQUENCY_16X >> 4)
|
|
||||||
#endif
|
|
||||||
#if MULTISTEPPING_LIMIT >= 32
|
|
||||||
, ( MAX_STEP_ISR_FREQUENCY_32X >> 5)
|
|
||||||
#endif
|
|
||||||
#if MULTISTEPPING_LIMIT >= 64
|
|
||||||
, ( MAX_STEP_ISR_FREQUENCY_64X >> 6)
|
|
||||||
#endif
|
|
||||||
#if MULTISTEPPING_LIMIT >= 128
|
|
||||||
, (MAX_STEP_ISR_FREQUENCY_128X >> 7)
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
// Find a doable step rate using multistepping
|
#else
|
||||||
uint8_t multistep = 1;
|
|
||||||
for (uint8_t i = 0; i < COUNT(limit) && step_rate > uint32_t(pgm_read_dword(&limit[i])); ++i) {
|
// The stepping frequency limits for each multistepping rate
|
||||||
step_rate >>= 1;
|
static const uint32_t limit[] PROGMEM = {
|
||||||
multistep <<= 1;
|
( MAX_STEP_ISR_FREQUENCY_1X )
|
||||||
}
|
, (((F_CPU) / ISR_EXECUTION_CYCLES(1)) >> 1)
|
||||||
steps_per_isr = multistep;
|
#if MULTISTEPPING_LIMIT >= 4
|
||||||
|
, (((F_CPU) / ISR_EXECUTION_CYCLES(2)) >> 2)
|
||||||
|
#endif
|
||||||
|
#if MULTISTEPPING_LIMIT >= 8
|
||||||
|
, (((F_CPU) / ISR_EXECUTION_CYCLES(3)) >> 3)
|
||||||
|
#endif
|
||||||
|
#if MULTISTEPPING_LIMIT >= 16
|
||||||
|
, (((F_CPU) / ISR_EXECUTION_CYCLES(4)) >> 4)
|
||||||
|
#endif
|
||||||
|
#if MULTISTEPPING_LIMIT >= 32
|
||||||
|
, (((F_CPU) / ISR_EXECUTION_CYCLES(5)) >> 5)
|
||||||
|
#endif
|
||||||
|
#if MULTISTEPPING_LIMIT >= 64
|
||||||
|
, (((F_CPU) / ISR_EXECUTION_CYCLES(6)) >> 6)
|
||||||
|
#endif
|
||||||
|
#if MULTISTEPPING_LIMIT >= 128
|
||||||
|
, (((F_CPU) / ISR_EXECUTION_CYCLES(7)) >> 7)
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
// Find a doable step rate using multistepping
|
||||||
|
uint8_t multistep = 1;
|
||||||
|
for (uint8_t i = 0; i < COUNT(limit) && step_rate > uint32_t(pgm_read_dword(&limit[i])); ++i) {
|
||||||
|
step_rate >>= 1;
|
||||||
|
multistep <<= 1;
|
||||||
|
}
|
||||||
|
steps_per_isr = multistep;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#elif MULTISTEPPING_LIMIT > 1
|
||||||
|
|
||||||
|
uint8_t loops = steps_per_isr;
|
||||||
|
if (MULTISTEPPING_LIMIT >= 16 && loops >= 16) { step_rate >>= 4; loops >>= 4; }
|
||||||
|
if (MULTISTEPPING_LIMIT >= 4 && loops >= 4) { step_rate >>= 2; loops >>= 2; }
|
||||||
|
if (MULTISTEPPING_LIMIT >= 2 && loops >= 2) { step_rate >>= 1; }
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -2141,6 +2184,19 @@ hal_timer_t Stepper::calc_multistep_timer_interval(uint32_t step_rate) {
|
|||||||
* have been done, so it is less time critical.
|
* have been done, so it is less time critical.
|
||||||
*/
|
*/
|
||||||
hal_timer_t Stepper::block_phase_isr() {
|
hal_timer_t Stepper::block_phase_isr() {
|
||||||
|
#if DISABLED(OLD_ADAPTIVE_MULTISTEPPING)
|
||||||
|
// If the ISR uses < 50% of MPU time, halve multi-stepping
|
||||||
|
const hal_timer_t time_spent = HAL_timer_get_count(MF_TIMER_STEP);
|
||||||
|
#if MULTISTEPPING_LIMIT > 1
|
||||||
|
if (steps_per_isr > 1 && time_spent_out_isr >= time_spent_in_isr + time_spent) {
|
||||||
|
steps_per_isr >>= 1;
|
||||||
|
// ticks_nominal will need to be recalculated if we are in cruise phase
|
||||||
|
ticks_nominal = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
time_spent_in_isr = -time_spent; // unsigned but guaranteed to be +ve when needed
|
||||||
|
time_spent_out_isr = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
// If no queued movements, just wait 1ms for the next block
|
// If no queued movements, just wait 1ms for the next block
|
||||||
hal_timer_t interval = (STEPPER_TIMER_RATE) / 1000UL;
|
hal_timer_t interval = (STEPPER_TIMER_RATE) / 1000UL;
|
||||||
|
@ -212,12 +212,12 @@
|
|||||||
#error "Expected at least one of MINIMUM_STEPPER_PULSE or MAXIMUM_STEPPER_RATE to be defined"
|
#error "Expected at least one of MINIMUM_STEPPER_PULSE or MAXIMUM_STEPPER_RATE to be defined"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// The loop takes the base time plus the time for all the bresenham logic for R pulses plus the time
|
// The loop takes the base time plus the time for all the bresenham logic for 1 << R pulses plus the time
|
||||||
// between pulses for (R-1) pulses. But the user could be enforcing a minimum time so the loop time is:
|
// between pulses for ((1 << R) - 1) pulses. But the user could be enforcing a minimum time so the loop time is:
|
||||||
#define ISR_LOOP_CYCLES(R) ((ISR_LOOP_BASE_CYCLES + MIN_ISR_LOOP_CYCLES + MIN_STEPPER_PULSE_CYCLES) * ((1UL << R) - 1) + _MAX(MIN_ISR_LOOP_CYCLES, MIN_STEPPER_PULSE_CYCLES))
|
#define ISR_LOOP_CYCLES(R) ((ISR_LOOP_BASE_CYCLES + MIN_ISR_LOOP_CYCLES + MIN_STEPPER_PULSE_CYCLES) * ((1UL << R) - 1) + _MAX(MIN_ISR_LOOP_CYCLES, MIN_STEPPER_PULSE_CYCLES))
|
||||||
|
|
||||||
// Model input shaping as an extra loop call
|
// Model input shaping as an extra loop call
|
||||||
#define ISR_SHAPING_LOOP_CYCLES(R) (TERN0(HAS_SHAPING, ((ISR_LOOP_BASE_CYCLES) + TERN0(INPUT_SHAPING_X, ISR_X_STEPPER_CYCLES) + TERN0(INPUT_SHAPING_Y, ISR_Y_STEPPER_CYCLES)) << R))
|
#define ISR_SHAPING_LOOP_CYCLES(R) (TERN0(HAS_SHAPING, (ISR_LOOP_BASE_CYCLES + TERN0(INPUT_SHAPING_X, ISR_X_STEPPER_CYCLES) + TERN0(INPUT_SHAPING_Y, ISR_Y_STEPPER_CYCLES)) << R))
|
||||||
|
|
||||||
// If linear advance is enabled, then it is handled separately
|
// If linear advance is enabled, then it is handled separately
|
||||||
#if ENABLED(LIN_ADVANCE)
|
#if ENABLED(LIN_ADVANCE)
|
||||||
@ -241,24 +241,17 @@
|
|||||||
#define ISR_LA_LOOP_CYCLES 0UL
|
#define ISR_LA_LOOP_CYCLES 0UL
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Now estimate the total ISR execution time in cycles given a step per ISR multiplier
|
// Estimate the total ISR execution time in cycles given a step-per-ISR shift multiplier
|
||||||
#define ISR_EXECUTION_CYCLES(R) (((ISR_BASE_CYCLES + ISR_S_CURVE_CYCLES + ISR_SHAPING_BASE_CYCLES + ISR_LOOP_CYCLES(R) + ISR_SHAPING_LOOP_CYCLES(R) + ISR_LA_BASE_CYCLES + ISR_LA_LOOP_CYCLES)) >> R)
|
#define ISR_EXECUTION_CYCLES(R) ((ISR_BASE_CYCLES + ISR_S_CURVE_CYCLES + ISR_SHAPING_BASE_CYCLES + ISR_LOOP_CYCLES(R) + ISR_SHAPING_LOOP_CYCLES(R) + ISR_LA_BASE_CYCLES + ISR_LA_LOOP_CYCLES) >> R)
|
||||||
|
|
||||||
// The maximum allowable stepping frequency when doing x128-x1 stepping (in Hz)
|
// The maximum allowable stepping frequency when doing 1x stepping (in Hz)
|
||||||
#define MAX_STEP_ISR_FREQUENCY_128X ((F_CPU) / ISR_EXECUTION_CYCLES(7))
|
#define MAX_STEP_ISR_FREQUENCY_1X ((F_CPU) / ISR_EXECUTION_CYCLES(0))
|
||||||
#define MAX_STEP_ISR_FREQUENCY_64X ((F_CPU) / ISR_EXECUTION_CYCLES(6))
|
|
||||||
#define MAX_STEP_ISR_FREQUENCY_32X ((F_CPU) / ISR_EXECUTION_CYCLES(5))
|
|
||||||
#define MAX_STEP_ISR_FREQUENCY_16X ((F_CPU) / ISR_EXECUTION_CYCLES(4))
|
|
||||||
#define MAX_STEP_ISR_FREQUENCY_8X ((F_CPU) / ISR_EXECUTION_CYCLES(3))
|
|
||||||
#define MAX_STEP_ISR_FREQUENCY_4X ((F_CPU) / ISR_EXECUTION_CYCLES(2))
|
|
||||||
#define MAX_STEP_ISR_FREQUENCY_2X ((F_CPU) / ISR_EXECUTION_CYCLES(1))
|
|
||||||
#define MAX_STEP_ISR_FREQUENCY_1X ((F_CPU) / ISR_EXECUTION_CYCLES(0))
|
|
||||||
|
|
||||||
// The minimum step ISR rate used by ADAPTIVE_STEP_SMOOTHING to target 50% CPU usage
|
// The minimum step ISR rate used by ADAPTIVE_STEP_SMOOTHING to target 50% CPU usage
|
||||||
// This does not account for the possibility of multi-stepping.
|
// This does not account for the possibility of multi-stepping.
|
||||||
// Should a MULTISTEPPING_LIMIT of 1 should be required with ADAPTIVE_STEP_SMOOTHING?
|
#define MIN_STEP_ISR_FREQUENCY (MAX_STEP_ISR_FREQUENCY_1X >> 1)
|
||||||
#define MIN_STEP_ISR_FREQUENCY (MAX_STEP_ISR_FREQUENCY_1X / 2)
|
|
||||||
|
|
||||||
|
// Number of axes that could be enabled/disabled. Dual/multiple steppers are combined.
|
||||||
#define ENABLE_COUNT (NUM_AXES + E_STEPPERS)
|
#define ENABLE_COUNT (NUM_AXES + E_STEPPERS)
|
||||||
typedef bits_t(ENABLE_COUNT) ena_mask_t;
|
typedef bits_t(ENABLE_COUNT) ena_mask_t;
|
||||||
|
|
||||||
@ -547,6 +540,10 @@ class Stepper {
|
|||||||
static uint8_t steps_per_isr;
|
static uint8_t steps_per_isr;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if DISABLED(OLD_ADAPTIVE_MULTISTEPPING)
|
||||||
|
static hal_timer_t time_spent_in_isr, time_spent_out_isr;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if ENABLED(ADAPTIVE_STEP_SMOOTHING)
|
#if ENABLED(ADAPTIVE_STEP_SMOOTHING)
|
||||||
static uint8_t oversampling_factor; // Oversampling factor (log2(multiplier)) to increase temporal resolution of axis
|
static uint8_t oversampling_factor; // Oversampling factor (log2(multiplier)) to increase temporal resolution of axis
|
||||||
#else
|
#else
|
||||||
|
Loading…
Reference in New Issue
Block a user