diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index c168240e243d..0069a6f77e12 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -1062,14 +1062,13 @@ * * Zero Vibration (ZV) Input Shaping for X and/or Y movements. * - * This option uses a lot of SRAM for the step buffer, which is related to the - * largest step rate possible for the shaped axes. If the build fails due to - * low SRAM the buffer size may be reduced by setting smaller values for - * DEFAULT_AXIS_STEPS_PER_UNIT and/or DEFAULT_MAX_FEEDRATE. Disabling - * ADAPTIVE_STEP_SMOOTHING and reducing the step rate for non-shaped axes may - * also reduce the buffer sizes. Runtime editing of max feedrate (M203) or - * resonant frequency (M593) may result in input shaping losing effectiveness - * during high speed movements to prevent buffer overruns. + * This option uses a lot of SRAM for the step buffer. The buffer size is + * calculated automatically from SHAPING_FREQ_[XY], DEFAULT_AXIS_STEPS_PER_UNIT, + * DEFAULT_MAX_FEEDRATE and ADAPTIVE_STEP_SMOOTHING. The default calculation can + * be overridden by setting SHAPING_MIN_FREQ and/or SHAPING_MAX_FEEDRATE. + * The higher the frequency and the lower the feedrate, the smaller the buffer. + * If the buffer is too small at runtime, input shaping will have reduced + * effectiveness during high speed movements. * * Tune with M593 D F: * @@ -1083,14 +1082,16 @@ //#define INPUT_SHAPING_Y #if EITHER(INPUT_SHAPING_X, INPUT_SHAPING_Y) #if ENABLED(INPUT_SHAPING_X) - #define SHAPING_FREQ_X 40 // (Hz) The default dominant resonant frequency on the X axis. - #define SHAPING_ZETA_X 0.15f // Damping ratio of the X axis (range: 0.0 = no damping to 1.0 = critical damping). + #define SHAPING_FREQ_X 40 // (Hz) The default dominant resonant frequency on the X axis. + #define SHAPING_ZETA_X 0.15f // Damping ratio of the X axis (range: 0.0 = no damping to 1.0 = critical damping). #endif #if ENABLED(INPUT_SHAPING_Y) - #define SHAPING_FREQ_Y 40 // (Hz) The default dominant resonant frequency on the Y axis. - #define SHAPING_ZETA_Y 0.15f // Damping ratio of the Y axis (range: 0.0 = no damping to 1.0 = critical damping). + #define SHAPING_FREQ_Y 40 // (Hz) The default dominant resonant frequency on the Y axis. + #define SHAPING_ZETA_Y 0.15f // Damping ratio of the Y axis (range: 0.0 = no damping to 1.0 = critical damping). #endif - //#define SHAPING_MENU // Add a menu to the LCD to set shaping parameters. + //#define SHAPING_MIN_FREQ 20 // By default the minimum of the shaping frequencies. Override to affect SRAM usage. + //#define SHAPING_MAX_STEPRATE 10000 // By default the maximum total step rate of the shaped axes. Override to affect SRAM usage. + //#define SHAPING_MENU // Add a menu to the LCD to set shaping parameters. #endif #define AXIS_RELATIVE_MODES { false, false, false, false } diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index 42f1409739ef..802506f1633a 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -4272,17 +4272,24 @@ static_assert(_PLUS_TEST(4), "HOMING_FEEDRATE_MM_M values must be positive."); // Check requirements for Input Shaping #if HAS_SHAPING && defined(__AVR__) + #ifdef SHAPING_MIN_FREQ + static_assert((SHAPING_MIN_FREQ) > 0, "SHAPING_MIN_FREQ must be > 0."); + #else + TERN_(INPUT_SHAPING_X, static_assert((SHAPING_FREQ_X) > 0, "SHAPING_FREQ_X must be > 0 or SHAPING_MIN_FREQ must be set.")); + TERN_(INPUT_SHAPING_Y, static_assert((SHAPING_FREQ_Y) > 0, "SHAPING_FREQ_Y must be > 0 or SHAPING_MIN_FREQ must be set.")); + #endif #if ENABLED(INPUT_SHAPING_X) #if F_CPU > 16000000 - static_assert((SHAPING_FREQ_X) * 2 * 0x10000 >= (STEPPER_TIMER_RATE), "SHAPING_FREQ_X is below the minimum (20) for AVR 20MHz."); + static_assert((SHAPING_FREQ_X) == 0 || (SHAPING_FREQ_X) * 2 * 0x10000 >= (STEPPER_TIMER_RATE), "SHAPING_FREQ_X is below the minimum (20) for AVR 20MHz."); #else - static_assert((SHAPING_FREQ_X) * 2 * 0x10000 >= (STEPPER_TIMER_RATE), "SHAPING_FREQ_X is below the minimum (16) for AVR 16MHz."); + static_assert((SHAPING_FREQ_X) == 0 || (SHAPING_FREQ_X) * 2 * 0x10000 >= (STEPPER_TIMER_RATE), "SHAPING_FREQ_X is below the minimum (16) for AVR 16MHz."); #endif - #elif ENABLED(INPUT_SHAPING_Y) + #endif + #if ENABLED(INPUT_SHAPING_Y) #if F_CPU > 16000000 - static_assert((SHAPING_FREQ_Y) * 2 * 0x10000 >= (STEPPER_TIMER_RATE), "SHAPING_FREQ_Y is below the minimum (20) for AVR 20MHz."); + static_assert((SHAPING_FREQ_Y) == 0 || (SHAPING_FREQ_Y) * 2 * 0x10000 >= (STEPPER_TIMER_RATE), "SHAPING_FREQ_Y is below the minimum (20) for AVR 20MHz."); #else - static_assert((SHAPING_FREQ_Y) * 2 * 0x10000 >= (STEPPER_TIMER_RATE), "SHAPING_FREQ_Y is below the minimum (16) for AVR 16MHz."); + static_assert((SHAPING_FREQ_Y) == 0 || (SHAPING_FREQ_Y) * 2 * 0x10000 >= (STEPPER_TIMER_RATE), "SHAPING_FREQ_Y is below the minimum (16) for AVR 16MHz."); #endif #endif #endif diff --git a/Marlin/src/module/settings.cpp b/Marlin/src/module/settings.cpp index 4ae4c19922d9..de38cf23770c 100644 --- a/Marlin/src/module/settings.cpp +++ b/Marlin/src/module/settings.cpp @@ -193,8 +193,6 @@ typedef struct { bool NUM_AXIS_LIST(X:1, Y:1, Z:1, I:1, J:1, K:1, U:1, V:1, // Defaults for reset / fill in on load static const uint32_t _DMA[] PROGMEM = DEFAULT_MAX_ACCELERATION; -static const float _DASU[] PROGMEM = DEFAULT_AXIS_STEPS_PER_UNIT; -static const feedRate_t _DMF[] PROGMEM = DEFAULT_MAX_FEEDRATE; /** * Current EEPROM Layout diff --git a/Marlin/src/module/stepper.h b/Marlin/src/module/stepper.h index 6d9814b4dfc3..e92d478dc6be 100644 --- a/Marlin/src/module/stepper.h +++ b/Marlin/src/module/stepper.h @@ -326,49 +326,43 @@ constexpr ena_mask_t enable_overlap[] = { #endif }; +constexpr float _DASU[] = DEFAULT_AXIS_STEPS_PER_UNIT; +constexpr feedRate_t _DMF[] = DEFAULT_MAX_FEEDRATE; + //static_assert(!any_enable_overlap(), "There is some overlap."); #if HAS_SHAPING - // These constexpr are used to calculate the shaping queue buffer sizes - constexpr xyze_float_t max_feedrate = DEFAULT_MAX_FEEDRATE; - constexpr xyze_float_t steps_per_unit = DEFAULT_AXIS_STEPS_PER_UNIT; - // MIN_STEP_ISR_FREQUENCY is known at compile time on AVRs and any reduction in SRAM is welcome - #ifdef __AVR__ - constexpr float max_isr_rate = _MAX( - LOGICAL_AXIS_LIST( - max_feedrate.e * steps_per_unit.e, - max_feedrate.x * steps_per_unit.x, - max_feedrate.y * steps_per_unit.y, - max_feedrate.z * steps_per_unit.z, - max_feedrate.i * steps_per_unit.i, - max_feedrate.j * steps_per_unit.j, - max_feedrate.k * steps_per_unit.k, - max_feedrate.u * steps_per_unit.u, - max_feedrate.v * steps_per_unit.v, - max_feedrate.w * steps_per_unit.w - ) - OPTARG(ADAPTIVE_STEP_SMOOTHING, MIN_STEP_ISR_FREQUENCY) - ); - constexpr float max_step_rate = _MIN(max_isr_rate, - TERN0(INPUT_SHAPING_X, max_feedrate.x * steps_per_unit.x) + - TERN0(INPUT_SHAPING_Y, max_feedrate.y * steps_per_unit.y) - ); + #ifdef SHAPING_MAX_STEPRATE + constexpr float max_step_rate = SHAPING_MAX_STEPRATE; #else - constexpr float max_step_rate = TERN0(INPUT_SHAPING_X, max_feedrate.x * steps_per_unit.x) + - TERN0(INPUT_SHAPING_Y, max_feedrate.y * steps_per_unit.y); + constexpr float max_shaped_rate = TERN0(INPUT_SHAPING_X, _DMF[X_AXIS] * _DASU[X_AXIS]) + + TERN0(INPUT_SHAPING_Y, _DMF[Y_AXIS] * _DASU[Y_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 + template constexpr float max_isr_rate() { + return _MAX(_DMF[INDEX - 1] * _DASU[INDEX - 1], max_isr_rate()); + } + template<> constexpr float max_isr_rate<0>() { + return TERN0(ADAPTIVE_STEP_SMOOTHING, MIN_STEP_ISR_FREQUENCY); + } + constexpr float max_step_rate = _MIN(max_isr_rate(), max_shaped_rate); + #else + constexpr float max_step_rate = max_shaped_rate; + #endif #endif - constexpr uint16_t shaping_echoes = max_step_rate / _MIN(0x7FFFFFFFL OPTARG(INPUT_SHAPING_X, SHAPING_FREQ_X) OPTARG(INPUT_SHAPING_Y, SHAPING_FREQ_Y)) / 2 + 3; + + #ifndef SHAPING_MIN_FREQ + #define SHAPING_MIN_FREQ _MIN(0x7FFFFFFFL OPTARG(INPUT_SHAPING_X, SHAPING_FREQ_X) OPTARG(INPUT_SHAPING_Y, SHAPING_FREQ_Y)) + #endif + constexpr uint16_t shaping_min_freq = SHAPING_MIN_FREQ, + shaping_echoes = max_step_rate / shaping_min_freq / 2 + 3; typedef IF::type shaping_time_t; enum shaping_echo_t { ECHO_NONE = 0, ECHO_FWD = 1, ECHO_BWD = 2 }; struct shaping_echo_axis_t { - #if ENABLED(INPUT_SHAPING_X) - shaping_echo_t x:2; - #endif - #if ENABLED(INPUT_SHAPING_Y) - shaping_echo_t y:2; - #endif + TERN_(INPUT_SHAPING_X, shaping_echo_t x:2); + TERN_(INPUT_SHAPING_Y, shaping_echo_t y:2); }; class ShapingQueue {