diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index c7da9fd45908a..330b1dc89e897 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -1057,12 +1057,12 @@ // Do not use with lasers! // Do not use with direct stepping! // -#define INPUT_SHAPING +//#define INPUT_SHAPING #if ENABLED(INPUT_SHAPING) - #define ISHAPING_FREQ_X 40 // (Hz) Resonant frequency. - #define ISHAPING_FREQ_Y 40 // (Hz) Resonant frequency. - #define ISHAPING_QUEUE_LENGTH_X 301 // Must be > steps/mm * maximum speed / IS_FREQ_X / 2. - #define ISHAPING_QUEUE_LENGTH_Y 301 // Must be > steps/mm * maximum speed / IS_FREQ_Y / 2. + #define SHAPING_FREQ_X 40 // (Hz) The dominant resonant frequency of the X axis. + #define SHAPING_FREQ_Y 40 // (Hz) The dominant resonant frequency of the Y axis. + #define SHAPING_BUFFER_X 301 // Must be > (steps/mm * maximum speed) / (SHAPING_FREQ_X * 2). + #define SHAPING_BUFFER_Y 301 // Must be > (steps/mm * maximum speed) / (SHAPING_FREQ_Y * 2). #endif #define AXIS_RELATIVE_MODES { false, false, false, false } diff --git a/Marlin/src/inc/Conditionals_adv.h b/Marlin/src/inc/Conditionals_adv.h index 7d3306ffb8923..1f2111833ab7e 100644 --- a/Marlin/src/inc/Conditionals_adv.h +++ b/Marlin/src/inc/Conditionals_adv.h @@ -1067,3 +1067,17 @@ #if ANY(DISABLE_INACTIVE_X, DISABLE_INACTIVE_Y, DISABLE_INACTIVE_Z, DISABLE_INACTIVE_I, DISABLE_INACTIVE_J, DISABLE_INACTIVE_K, DISABLE_INACTIVE_U, DISABLE_INACTIVE_V, DISABLE_INACTIVE_W, DISABLE_INACTIVE_E) #define HAS_DISABLE_INACTIVE_AXIS 1 #endif + +// Input shaping +#if ENABLED(INPUT_SHAPING) + #if !HAS_Y_AXIS + #undef SHAPING_FREQ_Y + #undef SHAPING_BUFFER_Y + #endif + #if SHAPING_FREQ_X && SHAPING_BUFFER_X + #define INPUT_SHAPING_X 1 + #endif + #if SHAPING_FREQ_Y && SHAPING_BUFFER_Y + #define INPUT_SHAPING_Y 1 + #endif +#endif diff --git a/Marlin/src/inc/Conditionals_post.h b/Marlin/src/inc/Conditionals_post.h index aa081a6b81286..c208466dd01fe 100644 --- a/Marlin/src/inc/Conditionals_post.h +++ b/Marlin/src/inc/Conditionals_post.h @@ -3716,13 +3716,3 @@ FIL_RUNOUT5_PULLDOWN, FIL_RUNOUT6_PULLDOWN, FIL_RUNOUT7_PULLDOWN, FIL_RUNOUT8_PULLDOWN) #define USING_PULLDOWNS 1 #endif - -// Input shaping -#if ENABLED(INPUT_SHAPING) - #if IS_FREQ_X && IS_QUEUE_LENGTH_X - #define INPUT_SHAPING_X - #endif - #if IS_FREQ_Y && IS_QUEUE_LENGTH_Y - #define INPUT_SHAPING_Y - #endif -#endif diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index a652c39d95b2f..5453f78e4c331 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -4191,11 +4191,6 @@ static_assert(_PLUS_TEST(4), "HOMING_FEEDRATE_MM_M values must be positive."); #endif #endif -// Misc. Cleanup -#undef _TEST_PWM -#undef _NUM_AXES_STR -#undef _LOGICAL_AXES_STR - // JTAG support in the HAL #if ENABLED(DISABLE_DEBUG) && !defined(JTAGSWD_DISABLE) #error "DISABLE_DEBUG is not supported for the selected MCU/Board." @@ -4208,9 +4203,24 @@ static_assert(_PLUS_TEST(4), "HOMING_FEEDRATE_MM_M values must be positive."); #error "BINARY_FILE_TRANSFER and CUSTOM_FIRMWARE_UPLOAD are required for custom upload." #endif -#if ENABLED(INPUT_SHAPING) - #if __AVR__ && (ENABLED(INPUT_SHAPING_X) && ((STEPPER_TIMER_RATE) > (IS_FREQ_X) * 2 * 65536) || \ - ENABLED(INPUT_SHAPING_Y) && ((STEPPER_TIMER_RATE) > (IS_FREQ_Y) * 2 * 65536)) - #error "Resonant frequency is below the minimum for AVR" +// Check requirements for Input Shaping +#if ENABLED(INPUT_SHAPING) && defined(__AVR__) + #if INPUT_SHAPING_X && (SHAPING_FREQ_X) * 2 * 0x10000 < (STEPPER_TIMER_RATE) + #if F_CPU > 16000000 + #error "SHAPING_FREQ_X is below the minimum (20) for AVR 20MHz." + #else + #error "SHAPING_FREQ_X is below the minimum (16) for AVR 16MHz." + #endif + #elif INPUT_SHAPING_Y && (SHAPING_FREQ_Y) * 2 * 0x10000 < (STEPPER_TIMER_RATE) + #if F_CPU > 16000000 + #error "SHAPING_FREQ_Y is below the minimum (20) for AVR 20MHz." + #else + #error "SHAPING_FREQ_Y is below the minimum (16) for AVR 16MHz." + #endif #endif #endif + +// Misc. Cleanup +#undef _TEST_PWM +#undef _NUM_AXES_STR +#undef _LOGICAL_AXES_STR diff --git a/Marlin/src/module/stepper.cpp b/Marlin/src/module/stepper.cpp index 30b4621009e1f..880f2ee02ef37 100644 --- a/Marlin/src/module/stepper.cpp +++ b/Marlin/src/module/stepper.cpp @@ -232,11 +232,11 @@ uint32_t Stepper::advance_divisor = 0, Stepper::la_advance_steps = 0; #endif -#if ENABLED(INPUT_SHAPING_X) - DelayQueue Stepper::ishaping_queue_x; +#if INPUT_SHAPING_X + DelayQueue Stepper::shaping_queue_x; #endif -#if ENABLED(INPUT_SHAPING_Y) - DelayQueue Stepper::ishaping_queue_y; +#if INPUT_SHAPING_Y + DelayQueue Stepper::shaping_queue_y; #endif #if ENABLED(INTEGRATED_BABYSTEPPING) @@ -1476,8 +1476,8 @@ void Stepper::isr() { if (!nextMainISR) pulse_phase_isr(); // 0 = Do coordinated axes Stepper pulses - TERN_(INPUT_SHAPING_X, if (!ishaping_queue_x.peek()) ishaping_isr_x()); - TERN_(INPUT_SHAPING_Y, if (!ishaping_queue_y.peek()) ishaping_isr_y()); + TERN_(INPUT_SHAPING_X, if (!shaping_queue_x.peek()) shaping_isr_x()); + TERN_(INPUT_SHAPING_Y, if (!shaping_queue_y.peek()) shaping_isr_y()); #if ENABLED(LIN_ADVANCE) if (!nextAdvanceISR) { // 0 = Do Linear Advance E Stepper pulses @@ -1509,8 +1509,8 @@ void Stepper::isr() { 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(INPUT_SHAPING_X, ishaping_queue_x.peek()) // Time until next input shaping echo for X - OPTARG(INPUT_SHAPING_Y, ishaping_queue_y.peek()) // Time until next input shaping echo for Y + OPTARG(INPUT_SHAPING_X, shaping_queue_x.peek()) // Time until next input shaping echo for X + OPTARG(INPUT_SHAPING_Y, shaping_queue_y.peek()) // 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? ); @@ -1523,8 +1523,8 @@ void Stepper::isr() { // nextMainISR -= interval; - TERN_(INPUT_SHAPING_X, ishaping_queue_x.decrement_delays(interval)); - TERN_(INPUT_SHAPING_Y, ishaping_queue_y.decrement_delays(interval)); + TERN_(INPUT_SHAPING_X, shaping_queue_x.decrement_delays(interval)); + TERN_(INPUT_SHAPING_Y, shaping_queue_y.decrement_delays(interval)); #if ENABLED(LIN_ADVANCE) if (nextAdvanceISR != LA_ADV_NEVER) nextAdvanceISR -= interval; @@ -1788,8 +1788,8 @@ void Stepper::pulse_phase_isr() { #endif // DIRECT_STEPPING if (!is_page) { - TERN_(INPUT_SHAPING_X, ishaping_queue_x.enqueue(ishaping_delay_x)); - TERN_(INPUT_SHAPING_Y, ishaping_queue_y.enqueue(ishaping_delay_y)); + TERN_(INPUT_SHAPING_X, shaping_queue_x.enqueue(shaping_delay_x)); + TERN_(INPUT_SHAPING_Y, shaping_queue_y.enqueue(shaping_delay_y)); // Determine if pulses are needed #if HAS_X_STEP @@ -1927,9 +1927,9 @@ void Stepper::pulse_phase_isr() { } while (--events_to_do); } -#if ENABLED(INPUT_SHAPING_X) - void Stepper::ishaping_isr_x() { - ishaping_queue_x.dequeue(); +#if INPUT_SHAPING_X + void Stepper::shaping_isr_x() { + shaping_queue_x.dequeue(); // echo step behaviour xyze_bool_t step_needed{0}; @@ -1948,9 +1948,9 @@ void Stepper::pulse_phase_isr() { } #endif -#if ENABLED(INPUT_SHAPING_Y) - void Stepper::ishaping_isr_y() { - ishaping_queue_y.dequeue(); +#if INPUT_SHAPING_Y + void Stepper::shaping_isr_y() { + shaping_queue_y.dequeue(); // echo step behaviour xyze_bool_t step_needed{0}; @@ -2046,10 +2046,10 @@ uint32_t Stepper::block_phase_isr() { // If current block is finished, reset pointer and finalize state if (step_events_completed >= step_event_count) { // Only end block when input shaping echoes are complete and idle in the meantime - if (TERN0(INPUT_SHAPING_X, !ishaping_queue_x.empty()) || TERN0(INPUT_SHAPING_Y, !ishaping_queue_y.empty())) { + if (TERN0(INPUT_SHAPING_X, !shaping_queue_x.empty()) || TERN0(INPUT_SHAPING_Y, !shaping_queue_y.empty())) { interval = 0; - TERN_(INPUT_SHAPING_X, NOLESS(interval, ishaping_queue_x.peek_tail() + 1)); - TERN_(INPUT_SHAPING_Y, NOLESS(interval, ishaping_queue_y.peek_tail() + 1)); + TERN_(INPUT_SHAPING_X, NOLESS(interval, shaping_queue_x.peek_tail() + 1)); + TERN_(INPUT_SHAPING_Y, NOLESS(interval, shaping_queue_y.peek_tail() + 1)); } else { #if ENABLED(DIRECT_STEPPING) @@ -2451,11 +2451,11 @@ uint32_t Stepper::block_phase_isr() { // and steps are repeated twice so dividends have to be scaled and halved TERN_(INPUT_SHAPING_X, delta_error.x = 0); TERN_(INPUT_SHAPING_Y, delta_error.y = 0); - TERN_(INPUT_SHAPING_X, advance_dividend.x = ((uint64_t)(current_block->steps.x) << 29) / step_event_count); - TERN_(INPUT_SHAPING_Y, advance_dividend.y = ((uint64_t)(current_block->steps.y) << 29) / step_event_count); + TERN_(INPUT_SHAPING_X, advance_dividend.x = (uint64_t(current_block->steps.x) << 29) / step_event_count); + TERN_(INPUT_SHAPING_Y, advance_dividend.y = (uint64_t(current_block->steps.y) << 29) / step_event_count); // finally, the scaling operation above introduces rounding errors which must now be removed - TERN_(INPUT_SHAPING_X, delta_error.x += (0x40000000l - advance_dividend.x * step_event_count) & 0x3ffffffful); - TERN_(INPUT_SHAPING_Y, delta_error.y += (0x40000000l - advance_dividend.y * step_event_count) & 0x3ffffffful); + TERN_(INPUT_SHAPING_X, delta_error.x += (0x40000000L - advance_dividend.x * step_event_count) & 0x3FFFFFFFUL); + TERN_(INPUT_SHAPING_Y, delta_error.y += (0x40000000L - advance_dividend.y * step_event_count) & 0x3FFFFFFFUL); // No step events completed so far step_events_completed = 0; diff --git a/Marlin/src/module/stepper.h b/Marlin/src/module/stepper.h index f9368f0088cad..fc6dbca79dca1 100644 --- a/Marlin/src/module/stepper.h +++ b/Marlin/src/module/stepper.h @@ -314,30 +314,26 @@ constexpr ena_mask_t enable_overlap[] = { #if ENABLED(INPUT_SHAPING) - #ifdef __AVR__ - typedef uint16_t ishaping_time_t; - #else - typedef uint32_t ishaping_time_t; - #endif + typedef IF::type shaping_time_t; template class DelayQueue { private: - ishaping_time_t now = 0, times[queue_length]; - uint16_t head = 0, tail = 0; + shaping_time_t now = 0, times[queue_length]; + uint16_t head = 0, tail = 0; public: - void decrement_delays(const ishaping_time_t interval) { now += interval; } - void enqueue(const ishaping_time_t delay) { + void decrement_delays(const shaping_time_t interval) { now += interval; } + void enqueue(const shaping_time_t delay) { times[tail] = now + delay; if (++tail == queue_length) tail = 0; } - ishaping_time_t peek() { + shaping_time_t peek() { if (head != tail) return times[head] - now; - else return ishaping_time_t(-1); + else return shaping_time_t(-1); } - ishaping_time_t peek_tail() { + shaping_time_t peek_tail() { if (head != tail) return times[(tail + queue_length - 1) % queue_length] - now; - else return ishaping_time_t(-1); + else return shaping_time_t(-1); } void dequeue() { if (++head == queue_length) head = 0; } void purge() { tail = head; } @@ -450,13 +446,15 @@ class Stepper { static bool bezier_2nd_half; // If Bézier curve has been initialized or not #endif - #if ENABLED(INPUT_SHAPING_X) - static DelayQueue ishaping_queue_x; - static constexpr ishaping_time_t ishaping_delay_x = uint32_t(STEPPER_TIMER_RATE) / (ISHAPING_FREQ_X) / 2; - #endif - #if ENABLED(INPUT_SHAPING_Y) - static DelayQueue ishaping_queue_y; - static constexpr ishaping_time_t ishaping_delay_y = uint32_t(STEPPER_TIMER_RATE) / (ISHAPING_FREQ_Y) / 2; + #if ENABLED(INPUT_SHAPING) + #if INPUT_SHAPING_X + static DelayQueue shaping_queue_x; + static constexpr shaping_time_t shaping_delay_x = uint32_t(STEPPER_TIMER_RATE) / (SHAPING_FREQ_X) / 2; + #endif + #if INPUT_SHAPING_Y + static DelayQueue shaping_queue_y; + static constexpr shaping_time_t shaping_delay_y = uint32_t(STEPPER_TIMER_RATE) / (SHAPING_FREQ_Y) / 2; + #endif #endif #if ENABLED(LIN_ADVANCE) @@ -518,11 +516,11 @@ class Stepper { // The stepper block processing ISR phase static uint32_t block_phase_isr(); - #if ENABLED(INPUT_SHAPING_X) - static void ishaping_isr_x(); + #if INPUT_SHAPING_X + static void shaping_isr_x(); #endif - #if ENABLED(INPUT_SHAPING_Y) - static void ishaping_isr_y(); + #if INPUT_SHAPING_Y + static void shaping_isr_y(); #endif #if ENABLED(LIN_ADVANCE) @@ -564,8 +562,8 @@ class Stepper { axis_did_move = 0; planner.release_current_block(); TERN_(LIN_ADVANCE, la_interval = nextAdvanceISR = LA_ADV_NEVER); - TERN_(INPUT_SHAPING_X, ishaping_queue_x.purge()); - TERN_(INPUT_SHAPING_Y, ishaping_queue_y.purge()); + TERN_(INPUT_SHAPING_X, shaping_queue_x.purge()); + TERN_(INPUT_SHAPING_Y, shaping_queue_y.purge()); } // Quickly stop all steppers diff --git a/buildroot/tests/mega2560 b/buildroot/tests/mega2560 index 9cb50688cdead..8ac8961dbbbe3 100755 --- a/buildroot/tests/mega2560 +++ b/buildroot/tests/mega2560 @@ -66,7 +66,7 @@ opt_enable VIKI2 BOOT_MARLIN_LOGO_ANIMATED SDSUPPORT AUTO_REPORT_SD_STATUS \ Z_PROBE_SERVO_NR Z_SERVO_ANGLES DEACTIVATE_SERVOS_AFTER_MOVE AUTO_BED_LEVELING_3POINT DEBUG_LEVELING_FEATURE \ EEPROM_SETTINGS EEPROM_CHITCHAT M114_DETAIL AUTO_REPORT_POSITION \ NO_VOLUMETRICS EXTENDED_CAPABILITIES_REPORT AUTO_REPORT_TEMPERATURES AUTOTEMP G38_PROBE_TARGET JOYSTICK \ - DIRECT_STEPPING DETECT_BROKEN_ENDSTOP \ + INPUT_SHAPING DIRECT_STEPPING DETECT_BROKEN_ENDSTOP \ FILAMENT_RUNOUT_SENSOR NOZZLE_PARK_FEATURE ADVANCED_PAUSE_FEATURE Z_SAFE_HOMING FIL_RUNOUT3_PULLUP exec_test $1 $2 "Multiple runout sensors (x5) | Distinct runout states" "$3"