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
|
||||
#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)
|
||||
bool Stepper::frozen; // = false
|
||||
#endif
|
||||
@ -614,27 +618,26 @@ void Stepper::set_directions() {
|
||||
TERN_(HAS_V_DIR, SET_STEP_DIR(V));
|
||||
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
|
||||
// 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);
|
||||
count_direction.e = -1;
|
||||
}
|
||||
else {
|
||||
MIXER_STEPPER_LOOP(j) NORM_E_DIR(j);
|
||||
count_direction.e = 1;
|
||||
}
|
||||
#elif HAS_EXTRUDERS
|
||||
if (motor_direction(E_AXIS)) {
|
||||
#else
|
||||
REV_E_DIR(stepper_extruder);
|
||||
#endif
|
||||
count_direction.e = -1;
|
||||
}
|
||||
else {
|
||||
#if ENABLED(MIXING_EXTRUDER)
|
||||
MIXER_STEPPER_LOOP(j) NORM_E_DIR(j);
|
||||
#else
|
||||
NORM_E_DIR(stepper_extruder);
|
||||
#endif
|
||||
count_direction.e = 1;
|
||||
}
|
||||
#endif
|
||||
#endif // HAS_EXTRUDERS
|
||||
|
||||
DIR_WAIT_AFTER();
|
||||
}
|
||||
@ -1587,6 +1590,7 @@ void Stepper::isr() {
|
||||
*/
|
||||
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
|
||||
@ -1594,9 +1598,36 @@ void Stepper::isr() {
|
||||
* timing, since the MCU isn't fast enough.
|
||||
*/
|
||||
if (!--max_loops) next_isr_ticks = min_ticks;
|
||||
#endif
|
||||
|
||||
// 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
|
||||
// sure that the time has not arrived yet - Warrantied by the scheduler
|
||||
@ -2091,6 +2122,9 @@ hal_timer_t Stepper::calc_timer_interval(uint32_t step_rate) {
|
||||
|
||||
// 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) {
|
||||
|
||||
#if ENABLED(OLD_ADAPTIVE_MULTISTEPPING)
|
||||
|
||||
#if MULTISTEPPING_LIMIT == 1
|
||||
|
||||
// Just make sure the step rate is doable
|
||||
@ -2101,24 +2135,24 @@ hal_timer_t Stepper::calc_multistep_timer_interval(uint32_t step_rate) {
|
||||
// The stepping frequency limits for each multistepping rate
|
||||
static const uint32_t limit[] PROGMEM = {
|
||||
( MAX_STEP_ISR_FREQUENCY_1X )
|
||||
, ( MAX_STEP_ISR_FREQUENCY_2X >> 1)
|
||||
, (((F_CPU) / ISR_EXECUTION_CYCLES(1)) >> 1)
|
||||
#if MULTISTEPPING_LIMIT >= 4
|
||||
, ( MAX_STEP_ISR_FREQUENCY_4X >> 2)
|
||||
, (((F_CPU) / ISR_EXECUTION_CYCLES(2)) >> 2)
|
||||
#endif
|
||||
#if MULTISTEPPING_LIMIT >= 8
|
||||
, ( MAX_STEP_ISR_FREQUENCY_8X >> 3)
|
||||
, (((F_CPU) / ISR_EXECUTION_CYCLES(3)) >> 3)
|
||||
#endif
|
||||
#if MULTISTEPPING_LIMIT >= 16
|
||||
, ( MAX_STEP_ISR_FREQUENCY_16X >> 4)
|
||||
, (((F_CPU) / ISR_EXECUTION_CYCLES(4)) >> 4)
|
||||
#endif
|
||||
#if MULTISTEPPING_LIMIT >= 32
|
||||
, ( MAX_STEP_ISR_FREQUENCY_32X >> 5)
|
||||
, (((F_CPU) / ISR_EXECUTION_CYCLES(5)) >> 5)
|
||||
#endif
|
||||
#if MULTISTEPPING_LIMIT >= 64
|
||||
, ( MAX_STEP_ISR_FREQUENCY_64X >> 6)
|
||||
, (((F_CPU) / ISR_EXECUTION_CYCLES(6)) >> 6)
|
||||
#endif
|
||||
#if MULTISTEPPING_LIMIT >= 128
|
||||
, (MAX_STEP_ISR_FREQUENCY_128X >> 7)
|
||||
, (((F_CPU) / ISR_EXECUTION_CYCLES(7)) >> 7)
|
||||
#endif
|
||||
};
|
||||
|
||||
@ -2132,6 +2166,15 @@ hal_timer_t Stepper::calc_multistep_timer_interval(uint32_t step_rate) {
|
||||
|
||||
#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
|
||||
|
||||
return calc_timer_interval(step_rate);
|
||||
}
|
||||
|
||||
@ -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.
|
||||
*/
|
||||
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
|
||||
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"
|
||||
#endif
|
||||
|
||||
// The loop takes the base time plus the time for all the bresenham logic for 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:
|
||||
// The loop takes the base time plus the time for all the bresenham logic for 1 << R pulses plus the time
|
||||
// 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))
|
||||
|
||||
// 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 ENABLED(LIN_ADVANCE)
|
||||
@ -241,24 +241,17 @@
|
||||
#define ISR_LA_LOOP_CYCLES 0UL
|
||||
#endif
|
||||
|
||||
// Now estimate the total ISR execution time in cycles given a step per ISR 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)
|
||||
// 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)
|
||||
|
||||
// The maximum allowable stepping frequency when doing x128-x1 stepping (in Hz)
|
||||
#define MAX_STEP_ISR_FREQUENCY_128X ((F_CPU) / ISR_EXECUTION_CYCLES(7))
|
||||
#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))
|
||||
// The maximum allowable stepping frequency when doing 1x stepping (in Hz)
|
||||
#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
|
||||
// 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 / 2)
|
||||
#define MIN_STEP_ISR_FREQUENCY (MAX_STEP_ISR_FREQUENCY_1X >> 1)
|
||||
|
||||
// Number of axes that could be enabled/disabled. Dual/multiple steppers are combined.
|
||||
#define ENABLE_COUNT (NUM_AXES + E_STEPPERS)
|
||||
typedef bits_t(ENABLE_COUNT) ena_mask_t;
|
||||
|
||||
@ -547,6 +540,10 @@ class Stepper {
|
||||
static uint8_t steps_per_isr;
|
||||
#endif
|
||||
|
||||
#if DISABLED(OLD_ADAPTIVE_MULTISTEPPING)
|
||||
static hal_timer_t time_spent_in_isr, time_spent_out_isr;
|
||||
#endif
|
||||
|
||||
#if ENABLED(ADAPTIVE_STEP_SMOOTHING)
|
||||
static uint8_t oversampling_factor; // Oversampling factor (log2(multiplier)) to increase temporal resolution of axis
|
||||
#else
|
||||
|
Loading…
Reference in New Issue
Block a user