From 65c19f82b9827604d1286823a655d9ecf106b6b3 Mon Sep 17 00:00:00 2001 From: Mihai <299015+mh-dm@users.noreply.github.com> Date: Thu, 6 Jun 2024 05:26:09 +0300 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=A7=20Minimum=20Stepper=20Pulse=20in?= =?UTF-8?q?=20Nanoseconds=20(#27113)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/Configuration_adv.h | 27 +++-- Marlin/src/HAL/TEENSY40_41/timers.h | 9 +- Marlin/src/core/macros.h | 3 - Marlin/src/inc/Changes.h | 2 + Marlin/src/inc/Conditionals_adv.h | 20 ++-- Marlin/src/module/stepper.cpp | 43 ++++--- Marlin/src/module/stepper.h | 4 +- Marlin/src/module/stepper/cycles.h | 179 +++++++++------------------- 8 files changed, 113 insertions(+), 174 deletions(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 283bbe39d3..794a59ac13 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -2556,27 +2556,28 @@ //#define MINIMUM_STEPPER_PRE_DIR_DELAY 650 /** - * Minimum stepper driver pulse width (in µs) - * 0 : Smallest possible width the MCU can produce, compatible with TMC2xxx drivers - * 0 : Minimum 500ns for LV8729, adjusted in stepper.h - * 1 : Minimum for A4988 and A5984 stepper drivers - * 2 : Minimum for DRV8825 stepper drivers - * 3 : Minimum for TB6600 stepper drivers - * 30 : Minimum for TB6560 stepper drivers + * Minimum stepper driver pulse width (in ns) + * If undefined, these defaults (from Conditionals_adv.h) apply: + * 100 : Minimum for TMC2xxx stepper drivers + * 500 : Minimum for LV8729 + * 1000 : Minimum for A4988 and A5984 stepper drivers + * 2000 : Minimum for DRV8825 stepper drivers + * 3000 : Minimum for TB6600 stepper drivers + * 30000 : Minimum for TB6560 stepper drivers * * Override the default value based on the driver type set in Configuration.h. */ -//#define MINIMUM_STEPPER_PULSE 2 +//#define MINIMUM_STEPPER_PULSE_NS 2000 /** * Maximum stepping rate (in Hz) the stepper driver allows - * If undefined, defaults to 1MHz / (2 * MINIMUM_STEPPER_PULSE) + * If undefined, these defaults (from Conditionals_adv.h) apply: * 5000000 : Maximum for TMC2xxx stepper drivers * 1000000 : Maximum for LV8729 stepper driver - * 500000 : Maximum for A4988 stepper driver - * 250000 : Maximum for DRV8825 stepper driver - * 150000 : Maximum for TB6600 stepper driver - * 15000 : Maximum for TB6560 stepper driver + * 500000 : Maximum for A4988 stepper driver + * 250000 : Maximum for DRV8825 stepper driver + * 150000 : Maximum for TB6600 stepper driver + * 15000 : Maximum for TB6560 stepper driver * * Override the default value based on the driver type set in Configuration.h. */ diff --git a/Marlin/src/HAL/TEENSY40_41/timers.h b/Marlin/src/HAL/TEENSY40_41/timers.h index 3c7cda0b4e..fc160ab8b8 100644 --- a/Marlin/src/HAL/TEENSY40_41/timers.h +++ b/Marlin/src/HAL/TEENSY40_41/timers.h @@ -36,13 +36,13 @@ typedef uint32_t hal_timer_t; #define HAL_TIMER_TYPE_MAX 0xFFFFFFFE -#define GPT_TIMER_RATE F_BUS_ACTUAL // 150MHz +#define GPT_TIMER_RATE (F_CPU / 4) // 150MHz (Can't use F_BUS_ACTUAL because it's extern volatile) #define GPT1_TIMER_PRESCALE 2 #define GPT2_TIMER_PRESCALE 10 -#define GPT1_TIMER_RATE (GPT_TIMER_RATE / GPT1_TIMER_PRESCALE) // 75MHz -#define GPT2_TIMER_RATE (GPT_TIMER_RATE / GPT2_TIMER_PRESCALE) // 15MHz +#define GPT1_TIMER_RATE (GPT_TIMER_RATE / GPT1_TIMER_PRESCALE) // 150MHz / 2 = 75MHz +#define GPT2_TIMER_RATE (GPT_TIMER_RATE / GPT2_TIMER_PRESCALE) // 150MHz / 10 = 15MHz #ifndef MF_TIMER_STEP #define MF_TIMER_STEP 0 // Timer Index for Stepper @@ -57,7 +57,8 @@ typedef uint32_t hal_timer_t; #define TEMP_TIMER_RATE 1000000 #define TEMP_TIMER_FREQUENCY 1000 -#define STEPPER_TIMER_RATE GPT1_TIMER_RATE +#define HAL_TIMER_RATE GPT1_TIMER_RATE +#define STEPPER_TIMER_RATE HAL_TIMER_RATE #define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000) #define STEPPER_TIMER_PRESCALE ((GPT_TIMER_RATE / 1000000) / STEPPER_TIMER_TICKS_PER_US) diff --git a/Marlin/src/core/macros.h b/Marlin/src/core/macros.h index 5d2f4f0de1..56250fb149 100644 --- a/Marlin/src/core/macros.h +++ b/Marlin/src/core/macros.h @@ -55,9 +55,6 @@ #define CYCLES_PER_MICROSECOND (F_CPU / 1000000UL) // 16 or 20 on AVR #endif -// Nanoseconds per cycle -#define NANOSECONDS_PER_CYCLE (1000000000.0 / F_CPU) - // Macros to make a string from a macro #define STRINGIFY_(M) #M #define STRINGIFY(M) STRINGIFY_(M) diff --git a/Marlin/src/inc/Changes.h b/Marlin/src/inc/Changes.h index 1019638931..a4a5b24c22 100644 --- a/Marlin/src/inc/Changes.h +++ b/Marlin/src/inc/Changes.h @@ -641,6 +641,8 @@ #error "PROBE_PT_[123]_[XY] is now defined using PROBE_PT_[123] with an array { x, y }." #elif defined(SQUARE_WAVE_STEPPING) #error "SQUARE_WAVE_STEPPING is now EDGE_STEPPING." +#elif defined(MINIMUM_STEPPER_PULSE) + #error "MINIMUM_STEPPER_PULSE (in µs) is now MINIMUM_STEPPER_PULSE_NS. Multiply old MINIMUM_STEPPER_PULSE x 1000!" #elif defined(FAN_PIN) #error "FAN_PIN is now FAN0_PIN." #elif defined(X_MIN_ENDSTOP_INVERTING) || defined(Y_MIN_ENDSTOP_INVERTING) || defined(Z_MIN_ENDSTOP_INVERTING) \ diff --git a/Marlin/src/inc/Conditionals_adv.h b/Marlin/src/inc/Conditionals_adv.h index 8e5814f5f2..ef0b18e4b7 100644 --- a/Marlin/src/inc/Conditionals_adv.h +++ b/Marlin/src/inc/Conditionals_adv.h @@ -1198,21 +1198,21 @@ #define MINIMUM_STEPPER_PRE_DIR_DELAY MINIMUM_STEPPER_POST_DIR_DELAY #endif -#ifndef MINIMUM_STEPPER_PULSE +#ifndef MINIMUM_STEPPER_PULSE_NS #if HAS_DRIVER(TB6560) - #define MINIMUM_STEPPER_PULSE 30 + #define MINIMUM_STEPPER_PULSE_NS 30000 #elif HAS_DRIVER(TB6600) - #define MINIMUM_STEPPER_PULSE 3 + #define MINIMUM_STEPPER_PULSE_NS 3000 #elif HAS_DRIVER(DRV8825) - #define MINIMUM_STEPPER_PULSE 2 + #define MINIMUM_STEPPER_PULSE_NS 2000 #elif HAS_DRIVER(A4988) || HAS_DRIVER(A5984) - #define MINIMUM_STEPPER_PULSE 1 - #elif HAS_TRINAMIC_CONFIG || HAS_TRINAMIC_STANDALONE - #define MINIMUM_STEPPER_PULSE 0 + #define MINIMUM_STEPPER_PULSE_NS 1000 #elif HAS_DRIVER(LV8729) - #define MINIMUM_STEPPER_PULSE 0 + #define MINIMUM_STEPPER_PULSE_NS 500 + #elif HAS_TRINAMIC_CONFIG || HAS_TRINAMIC_STANDALONE + #define MINIMUM_STEPPER_PULSE_NS 100 #else - #define MINIMUM_STEPPER_PULSE 2 + // Expecting MAXIMUM_STEPPER_RATE to be defined #endif #endif @@ -1230,7 +1230,7 @@ #elif HAS_TRINAMIC_CONFIG || HAS_TRINAMIC_STANDALONE #define MAXIMUM_STEPPER_RATE 5000000 #else - #define MAXIMUM_STEPPER_RATE 250000 + // Expecting MINIMUM_STEPPER_PULSE_NS to be defined #endif #endif diff --git a/Marlin/src/module/stepper.cpp b/Marlin/src/module/stepper.cpp index 083d2019dc..ba4030f0d6 100644 --- a/Marlin/src/module/stepper.cpp +++ b/Marlin/src/module/stepper.cpp @@ -519,16 +519,15 @@ xyze_int8_t Stepper::count_direction{0}; #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)) -#define NS_PER_PULSE_TIMER_TICK (1000000000UL / (STEPPER_TIMER_RATE)) +constexpr uint32_t cycles_to_ns(const uint32_t CYC) { return 1000UL * (CYC) / ((F_CPU) / 1000000); } +constexpr uint32_t ns_per_pulse_timer_tick = 1000000000UL / (STEPPER_TIMER_RATE); // Round up when converting from ns to timer ticks -#define NS_TO_PULSE_TIMER_TICKS(NS) (((NS) + (NS_PER_PULSE_TIMER_TICK) / 2) / (NS_PER_PULSE_TIMER_TICK)) +constexpr hal_timer_t ns_to_pulse_timer_ticks(const uint32_t ns) { return (ns + ns_per_pulse_timer_tick / 2) / ns_per_pulse_timer_tick; } -#define TIMER_SETUP_NS (CYCLES_TO_NS(TIMER_READ_ADD_AND_STORE_CYCLES)) - -#define PULSE_HIGH_TICK_COUNT hal_timer_t(NS_TO_PULSE_TIMER_TICKS(_MIN_PULSE_HIGH_NS - _MIN(_MIN_PULSE_HIGH_NS, TIMER_SETUP_NS))) -#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))) +constexpr uint32_t timer_setup_ns = cycles_to_ns(timer_read_add_and_store_cycles); +constexpr hal_timer_t PULSE_HIGH_TICK_COUNT = ns_to_pulse_timer_ticks(_min_pulse_high_ns - _MIN(_min_pulse_high_ns, timer_setup_ns)); +constexpr hal_timer_t PULSE_LOW_TICK_COUNT = 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() (start_pulse_count = HAL_timer_get_count(MF_TIMER_PULSE)) @@ -1720,7 +1719,7 @@ void Stepper::isr() { #endif } -#if MINIMUM_STEPPER_PULSE || MAXIMUM_STEPPER_RATE +#if MINIMUM_STEPPER_PULSE_NS || MAXIMUM_STEPPER_RATE #define ISR_PULSE_CONTROL 1 #endif #if ISR_PULSE_CONTROL && DISABLED(I2S_STEPPER_STREAM) @@ -2080,7 +2079,7 @@ void Stepper::pulse_phase_isr() { TERN_(I2S_STEPPER_STREAM, i2s_push_sample()); - // TODO: need to deal with MINIMUM_STEPPER_PULSE over i2s + // TODO: need to deal with MINIMUM_STEPPER_PULSE_NS over i2s #if ISR_MULTI_STEPS START_TIMED_PULSE(); AWAIT_HIGH_PULSE(); @@ -2256,25 +2255,25 @@ 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 ) - , (((F_CPU) / ISR_EXECUTION_CYCLES(1)) >> 1) + max_step_isr_frequency_sh(0) + , max_step_isr_frequency_sh(1) #if MULTISTEPPING_LIMIT >= 4 - , (((F_CPU) / ISR_EXECUTION_CYCLES(2)) >> 2) + , max_step_isr_frequency_sh(2) #endif #if MULTISTEPPING_LIMIT >= 8 - , (((F_CPU) / ISR_EXECUTION_CYCLES(3)) >> 3) + , max_step_isr_frequency_sh(3) #endif #if MULTISTEPPING_LIMIT >= 16 - , (((F_CPU) / ISR_EXECUTION_CYCLES(4)) >> 4) + , max_step_isr_frequency_sh(4) #endif #if MULTISTEPPING_LIMIT >= 32 - , (((F_CPU) / ISR_EXECUTION_CYCLES(5)) >> 5) + , max_step_isr_frequency_sh(5) #endif #if MULTISTEPPING_LIMIT >= 64 - , (((F_CPU) / ISR_EXECUTION_CYCLES(6)) >> 6) + , max_step_isr_frequency_sh(6) #endif #if MULTISTEPPING_LIMIT >= 128 - , (((F_CPU) / ISR_EXECUTION_CYCLES(7)) >> 7) + , max_step_isr_frequency_sh(7) #endif }; @@ -2702,9 +2701,9 @@ hal_timer_t Stepper::block_phase_isr() { // Decide if axis smoothing is possible if (stepper.adaptive_step_smoothing_enabled) { 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... + 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 + if (max_rate < min_step_isr_frequency) // Don't exceed the estimated ISR limit ++oversampling_factor; // Increase the oversampling (used for left-shift) } } @@ -3737,8 +3736,8 @@ void Stepper::report_positions() { #define _READ_DIR(AXIS) AXIS ##_DIR_READ() #define _APPLY_DIR(AXIS, FWD) AXIS ##_APPLY_DIR(FWD, true) - #if MINIMUM_STEPPER_PULSE - #define STEP_PULSE_CYCLES ((MINIMUM_STEPPER_PULSE) * CYCLES_PER_MICROSECOND) + #if MINIMUM_STEPPER_PULSE_NS + #define STEP_PULSE_CYCLES ((MINIMUM_STEPPER_PULSE_NS) * CYCLES_PER_MICROSECOND / 1000) #else #define STEP_PULSE_CYCLES 0 #endif @@ -3761,7 +3760,7 @@ void Stepper::report_positions() { #else #define _SAVE_START() NOOP #if EXTRA_CYCLES_BABYSTEP > 0 - #define _PULSE_WAIT() DELAY_NS(EXTRA_CYCLES_BABYSTEP * NANOSECONDS_PER_CYCLE) + #define _PULSE_WAIT() DELAY_CYCLES(EXTRA_CYCLES_BABYSTEP) #elif ENABLED(DELTA) #define _PULSE_WAIT() DELAY_US(2); #elif STEP_PULSE_CYCLES > 0 diff --git a/Marlin/src/module/stepper.h b/Marlin/src/module/stepper.h index 8cf6d39dea..3586c23e70 100644 --- a/Marlin/src/module/stepper.h +++ b/Marlin/src/module/stepper.h @@ -146,12 +146,12 @@ constexpr ena_mask_t enable_overlap[] = { TERN0(INPUT_SHAPING_Y, _ISDMF[Y_AXIS] * _ISDASU[Y_AXIS]) + TERN0(INPUT_SHAPING_Z, _ISDMF[Z_AXIS] * _ISDASU[Z_AXIS]); #if defined(__AVR__) || !defined(ADAPTIVE_STEP_SMOOTHING) - // MIN_STEP_ISR_FREQUENCY is known at compile time on AVRs and any reduction in SRAM is welcome + // min_step_isr_frequency is known at compile time on AVRs and any reduction in SRAM is welcome template constexpr float max_isr_rate() { return _MAX(_ISDMF[ISALIM(INDEX - 1, _ISDMF)] * _ISDASU[ISALIM(INDEX - 1, _ISDASU)], max_isr_rate()); } template<> constexpr float max_isr_rate<0>() { - return TERN0(ADAPTIVE_STEP_SMOOTHING, MIN_STEP_ISR_FREQUENCY); + return TERN0(ADAPTIVE_STEP_SMOOTHING, min_step_isr_frequency); } constexpr float max_step_rate = _MIN(max_isr_rate(), max_shaped_rate); #else diff --git a/Marlin/src/module/stepper/cycles.h b/Marlin/src/module/stepper/cycles.h index 0089124eed..b01d199cd8 100644 --- a/Marlin/src/module/stepper/cycles.h +++ b/Marlin/src/module/stepper/cycles.h @@ -40,184 +40,123 @@ * take longer, pulses will be longer. For example the SKR Pro * (stm32f407zgt6) requires ~60 cyles. */ - #define TIMER_READ_ADD_AND_STORE_CYCLES 34UL + constexpr uint32_t timer_read_add_and_store_cycles = 34UL; // The base ISR - #define ISR_BASE_CYCLES 770UL + constexpr uint32_t isr_base_cycles = 770UL; // Linear advance base time is 64 cycles - #if ENABLED(LIN_ADVANCE) - #define ISR_LA_BASE_CYCLES 64UL - #else - #define ISR_LA_BASE_CYCLES 0UL - #endif + constexpr uint32_t isr_la_base_cycles = TERN0(LIN_ADVANCE, 64UL); // S curve interpolation adds 40 cycles - #if ENABLED(S_CURVE_ACCELERATION) - #ifdef STM32G0B1xx - #define ISR_S_CURVE_CYCLES 500UL - #else - #define ISR_S_CURVE_CYCLES 40UL - #endif - #else - #define ISR_S_CURVE_CYCLES 0UL - #endif + constexpr uint32_t isr_s_curve_cycles = TERN0(S_CURVE_ACCELERATION, TERN(STM32G0B1xx, 500UL, 40UL)); // Input shaping base time - #if HAS_ZV_SHAPING - #define ISR_SHAPING_BASE_CYCLES 180UL - #else - #define ISR_SHAPING_BASE_CYCLES 0UL - #endif + constexpr uint32_t isr_shaping_base_cycles = TERN0(HAS_ZV_SHAPING, 180UL); // Stepper Loop base cycles - #define ISR_LOOP_BASE_CYCLES 4UL + constexpr uint32_t isr_loop_base_cycles = 4UL; // And each stepper (start + stop pulse) takes in worst case - #define ISR_STEPPER_CYCLES 100UL + constexpr uint32_t isr_stepper_cycles = 100UL; #else // Cycles to perform actions in START_TIMED_PULSE - #define TIMER_READ_ADD_AND_STORE_CYCLES 13UL + constexpr uint32_t timer_read_add_and_store_cycles = 13UL; // The base ISR - #define ISR_BASE_CYCLES 882UL + constexpr uint32_t isr_base_cycles = 882UL; // Linear advance base time is 32 cycles - #if ENABLED(LIN_ADVANCE) - #define ISR_LA_BASE_CYCLES 30UL - #else - #define ISR_LA_BASE_CYCLES 0UL - #endif + constexpr uint32_t isr_la_base_cycles = TERN0(LIN_ADVANCE, 30UL); // S curve interpolation adds 160 cycles - #if ENABLED(S_CURVE_ACCELERATION) - #define ISR_S_CURVE_CYCLES 160UL - #else - #define ISR_S_CURVE_CYCLES 0UL - #endif + constexpr uint32_t isr_s_curve_cycles = TERN0(S_CURVE_ACCELERATION, 160UL); // Input shaping base time - #if HAS_ZV_SHAPING - #define ISR_SHAPING_BASE_CYCLES 290UL - #else - #define ISR_SHAPING_BASE_CYCLES 0UL - #endif + constexpr uint32_t isr_shaping_base_cycles = TERN0(HAS_ZV_SHAPING, 290UL); // Stepper Loop base cycles - #define ISR_LOOP_BASE_CYCLES 32UL + constexpr uint32_t isr_loop_base_cycles = 32UL; // And each stepper (start + stop pulse) takes in worst case - #define ISR_STEPPER_CYCLES 60UL + constexpr uint32_t isr_stepper_cycles = 60UL; #endif // If linear advance is disabled, the loop also handles them -#if DISABLED(LIN_ADVANCE) && ENABLED(MIXING_EXTRUDER) - #define ISR_MIXING_STEPPER_CYCLES ((MIXING_STEPPERS) * (ISR_STEPPER_CYCLES)) -#else - #define ISR_MIXING_STEPPER_CYCLES 0UL -#endif +constexpr uint32_t isr_mixing_stepper_cycles = (0UL + #if DISABLED(LIN_ADVANCE) && ENABLED(MIXING_EXTRUDER) + + (MIXING_STEPPERS) * isr_stepper_cycles + #endif +); -// Add time for each stepper -#if HAS_X_STEP - #define ISR_X_STEPPER_CYCLES ISR_STEPPER_CYCLES -#endif -#if HAS_Y_STEP - #define ISR_Y_STEPPER_CYCLES ISR_STEPPER_CYCLES -#endif -#if HAS_Z_STEP - #define ISR_Z_STEPPER_CYCLES ISR_STEPPER_CYCLES -#endif -#if HAS_I_STEP - #define ISR_I_STEPPER_CYCLES ISR_STEPPER_CYCLES -#endif -#if HAS_J_STEP - #define ISR_J_STEPPER_CYCLES ISR_STEPPER_CYCLES -#endif -#if HAS_K_STEP - #define ISR_K_STEPPER_CYCLES ISR_STEPPER_CYCLES -#endif -#if HAS_U_STEP - #define ISR_U_STEPPER_CYCLES ISR_STEPPER_CYCLES -#endif -#if HAS_V_STEP - #define ISR_V_STEPPER_CYCLES ISR_STEPPER_CYCLES -#endif -#if HAS_W_STEP - #define ISR_W_STEPPER_CYCLES ISR_STEPPER_CYCLES -#endif -#if HAS_EXTRUDERS - #define ISR_E_STEPPER_CYCLES ISR_STEPPER_CYCLES // E is always interpolated, even for mixing extruders -#endif - -// And the total minimum loop time, not including the base -#define _PLUS_AXIS_CYCLES(A) + (ISR_##A##_STEPPER_CYCLES) -#define MIN_ISR_LOOP_CYCLES (ISR_MIXING_STEPPER_CYCLES LOGICAL_AXIS_MAP(_PLUS_AXIS_CYCLES)) - -// Calculate the minimum MPU cycles needed per pulse to enforce, limited to the max stepper rate -#define _MIN_STEPPER_PULSE_CYCLES(N) _MAX(uint32_t((F_CPU) / (MAXIMUM_STEPPER_RATE)), ((F_CPU) / 500000UL) * (N)) -#if MINIMUM_STEPPER_PULSE - #define MIN_STEPPER_PULSE_CYCLES _MIN_STEPPER_PULSE_CYCLES(uint32_t(MINIMUM_STEPPER_PULSE)) -#elif HAS_DRIVER(LV8729) - #define MIN_STEPPER_PULSE_CYCLES uint32_t((((F_CPU) - 1) / 2000000) + 1) // 0.5µs, aka 500ns -#else - #define MIN_STEPPER_PULSE_CYCLES _MIN_STEPPER_PULSE_CYCLES(1UL) -#endif +// And the total minimum loop time, for all steppers, not including the base +constexpr uint32_t min_isr_loop_cycles = isr_mixing_stepper_cycles + LOGICAL_AXES * isr_stepper_cycles; // Calculate the minimum pulse times (high and low) -#if MINIMUM_STEPPER_PULSE && MAXIMUM_STEPPER_RATE - constexpr uint32_t _MIN_STEP_PERIOD_NS = 1000000000UL / MAXIMUM_STEPPER_RATE; - constexpr uint32_t _MIN_PULSE_HIGH_NS = 1000UL * MINIMUM_STEPPER_PULSE; - constexpr uint32_t _MIN_PULSE_LOW_NS = _MAX((_MIN_STEP_PERIOD_NS - _MIN(_MIN_STEP_PERIOD_NS, _MIN_PULSE_HIGH_NS)), _MIN_PULSE_HIGH_NS); -#elif MINIMUM_STEPPER_PULSE - // Assume 50% duty cycle - constexpr uint32_t _MIN_PULSE_HIGH_NS = 1000UL * MINIMUM_STEPPER_PULSE; - constexpr uint32_t _MIN_PULSE_LOW_NS = _MIN_PULSE_HIGH_NS; -#elif MAXIMUM_STEPPER_RATE - // Assume 50% duty cycle - constexpr uint32_t _MIN_PULSE_HIGH_NS = 500000000UL / MAXIMUM_STEPPER_RATE; - constexpr uint32_t _MIN_PULSE_LOW_NS = _MIN_PULSE_HIGH_NS; +#if defined(MINIMUM_STEPPER_PULSE_NS) && defined(MAXIMUM_STEPPER_RATE) + constexpr uint32_t _min_step_period_ns = 1000000000UL / (MAXIMUM_STEPPER_RATE), + _min_pulse_high_ns = MINIMUM_STEPPER_PULSE_NS, + _min_pulse_low_ns = _MAX(_min_step_period_ns - _MIN(_min_step_period_ns, _min_pulse_high_ns), _min_pulse_high_ns); +#elif defined(MINIMUM_STEPPER_PULSE_NS) + // Assume equal high and low pulse durations + constexpr uint32_t _min_pulse_high_ns = MINIMUM_STEPPER_PULSE_NS, + _min_pulse_low_ns = _min_pulse_high_ns; +#elif defined(MAXIMUM_STEPPER_RATE) + // Assume equal high and low pulse durations + constexpr uint32_t _min_pulse_high_ns = 500000000UL / MAXIMUM_STEPPER_RATE, + _min_pulse_low_ns = _min_pulse_high_ns; #else - #error "Expected at least one of MINIMUM_STEPPER_PULSE or MAXIMUM_STEPPER_RATE to be defined" + #error "At least one of MINIMUM_STEPPER_PULSE_NS or MAXIMUM_STEPPER_RATE must be defined" #endif +// Calculate the minimum MPU cycles needed per pulse to enforce +constexpr uint32_t min_stepper_pulse_cycles = _min_pulse_high_ns * CYCLES_PER_MICROSECOND / 1000; + // 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)) +constexpr uint32_t isr_loop_cycles(const int R) { return ((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_ZV_SHAPING, (ISR_LOOP_BASE_CYCLES + TERN0(INPUT_SHAPING_X, ISR_X_STEPPER_CYCLES) + TERN0(INPUT_SHAPING_Y, ISR_Y_STEPPER_CYCLES) + TERN0(INPUT_SHAPING_Z, ISR_Z_STEPPER_CYCLES)) << R)) +constexpr uint32_t isr_shaping_loop_cycles(const int R) { + return ( + #if HAS_ZV_SHAPING + isr_loop_base_cycles + + isr_stepper_cycles * COUNT_ENABLED(INPUT_SHAPING_X, INPUT_SHAPING_Y, INPUT_SHAPING_Z) + #else + 0 + #endif + ) << R; +} // If linear advance is enabled, then it is handled separately #if ENABLED(LIN_ADVANCE) // Estimate the minimum LA loop time - #if ENABLED(MIXING_EXTRUDER) // ToDo: ??? + constexpr uint32_t min_isr_la_loop_cycles = (isr_stepper_cycles + // ToDo: ??? // HELP ME: What is what? // Directions are set up for MIXING_STEPPERS - like before. // Finding the right stepper may last up to MIXING_STEPPERS loops in get_next_stepper(). // These loops are a bit faster than advancing a bresenham counter. // Always only one E stepper is stepped. - #define MIN_ISR_LA_LOOP_CYCLES ((MIXING_STEPPERS) * (ISR_STEPPER_CYCLES)) - #else - #define MIN_ISR_LA_LOOP_CYCLES ISR_STEPPER_CYCLES - #endif + * TERN1(MIXING_EXTRUDER, (MIXING_STEPPERS)) + ); - // And the real loop time - #define ISR_LA_LOOP_CYCLES _MAX(MIN_STEPPER_PULSE_CYCLES, MIN_ISR_LA_LOOP_CYCLES) - -#else - #define ISR_LA_LOOP_CYCLES 0UL #endif +// The real LA loop time will be the larger minimum (pulse or loop) +constexpr uint32_t isr_la_loop_cycles = TERN0(LIN_ADVANCE, _MAX(min_stepper_pulse_cycles, min_isr_la_loop_cycles)); + // 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) +constexpr uint32_t isr_execution_cycles(const int R) { return (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 1x stepping (in Hz) -#define MAX_STEP_ISR_FREQUENCY_1X ((F_CPU) / ISR_EXECUTION_CYCLES(0)) +constexpr uint32_t max_step_isr_frequency_1x = (F_CPU) / isr_execution_cycles(0); +constexpr uint32_t max_step_isr_frequency_sh(const int S) { return ((F_CPU) / isr_execution_cycles(S)) >> S; } // 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. -#define MIN_STEP_ISR_FREQUENCY (MAX_STEP_ISR_FREQUENCY_1X >> 1) +constexpr uint32_t min_step_isr_frequency = max_step_isr_frequency_1x >> 1;