From 87679279a85227be3123a7dc72223f2110ca1306 Mon Sep 17 00:00:00 2001 From: Andrew Bortz Date: Wed, 26 Jul 2023 13:59:29 -0700 Subject: [PATCH 1/7] Initial working implementation of nonlinear extrusion --- Marlin/Configuration_adv.h | 9 ++++ Marlin/src/gcode/feature/nonlinear/M592.cpp | 54 +++++++++++++++++++++ Marlin/src/gcode/gcode.cpp | 4 ++ Marlin/src/gcode/gcode.h | 5 ++ Marlin/src/inc/SanityCheck.h | 13 +++++ Marlin/src/module/planner.cpp | 2 +- Marlin/src/module/settings.cpp | 27 ++++++++++- Marlin/src/module/stepper.cpp | 48 +++++++++++++++--- Marlin/src/module/stepper.h | 14 ++++++ ini/features.ini | 1 + 10 files changed, 167 insertions(+), 10 deletions(-) create mode 100644 Marlin/src/gcode/feature/nonlinear/M592.cpp diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 6c29900cdf47..b10d9a33bd6f 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -2264,6 +2264,15 @@ //#define EXPERIMENTAL_I2S_LA // Allow I2S_STEPPER_STREAM to be used with LA. Performance degrades as the LA step rate reaches ~20kHz. #endif +/** + * Nonlinear Extrusion Control + * + * Enables control over extrusion rate based on instantaneous extruder velocity. This can be used + * to correct for underextrusion at high extruder speeds that are otherwise well-behaved (e.g. + * not yet skipping). +*/ +//#define NONLINEAR_EXTRUSION + // @section leveling /** diff --git a/Marlin/src/gcode/feature/nonlinear/M592.cpp b/Marlin/src/gcode/feature/nonlinear/M592.cpp new file mode 100644 index 000000000000..9f356d64aeee --- /dev/null +++ b/Marlin/src/gcode/feature/nonlinear/M592.cpp @@ -0,0 +1,54 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include "../../../inc/MarlinConfig.h" + +#if ENABLED(NONLINEAR_EXTRUSION) + +#include "../../gcode.h" +#include "../../../module/stepper.h" + +/** + * M592: Get or set nonlinear extrusion parameters + * A Linear coefficient (default 0.0) + * B Quadratic coefficient (default 0.0) + * C Constant coefficient (default 1.0) + * + * Adjusts the amount of extrusion based on the instantaneous velocity of extrusion, as a multiplier. + * The amount of extrusion is multiplied by (C + A*v + B*v^2) where v is extruder velocity in mm/s. + * Only adjusts forward extrusions, since those are the ones affected by backpressure. + */ +void GcodeSuite::M592() { + if (parser.seenval('A')) { + stepper.ne_A = parser.value_float(); + } + + if (parser.seenval('B')) { + stepper.ne_B = parser.value_float(); + } + + if (parser.seenval('C')) { + stepper.ne_C = parser.value_float(); + } +} + +#endif // NONLINEAR_EXTRUSION diff --git a/Marlin/src/gcode/gcode.cpp b/Marlin/src/gcode/gcode.cpp index fd2a78d1fd26..4902cebde2eb 100644 --- a/Marlin/src/gcode/gcode.cpp +++ b/Marlin/src/gcode/gcode.cpp @@ -935,6 +935,10 @@ void GcodeSuite::process_parsed_command(const bool no_ok/*=false*/) { case 575: M575(); break; // M575: Set serial baudrate #endif + #if ENABLED(NONLINEAR_EXTRUSION) + case 592: M592(); break; // M592: Nonlinear Extrusion control + #endif + #if HAS_ZV_SHAPING case 593: M593(); break; // M593: Input Shaping control #endif diff --git a/Marlin/src/gcode/gcode.h b/Marlin/src/gcode/gcode.h index f9ee81f2eb0c..ff24a106c387 100644 --- a/Marlin/src/gcode/gcode.h +++ b/Marlin/src/gcode/gcode.h @@ -259,6 +259,7 @@ * M554 - Get or set IP gateway. (Requires enabled Ethernet port) * M569 - Enable stealthChop on an axis. (Requires at least one _DRIVER_TYPE to be TMC2130/2160/2208/2209/5130/5160) * M575 - Change the serial baud rate. (Requires BAUD_RATE_GCODE) + * M592 - Get or set nonlinear extrusion parameters. (Requires NONLINEAR_EXTRUSION) * M593 - Get or set input shaping parameters. (Requires INPUT_SHAPING_[XY]) * M600 - Pause for filament change: "M600 X Y Z E L". (Requires ADVANCED_PAUSE_FEATURE) * M603 - Configure filament change: "M603 T U L". (Requires ADVANCED_PAUSE_FEATURE) @@ -1106,6 +1107,10 @@ class GcodeSuite { static void M575(); #endif + #if ENABLED(NONLINEAR_EXTRUSION) + static void M592(); + #endif + #if HAS_ZV_SHAPING static void M593(); static void M593_report(const bool forReplay=true); diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index 8eb8662c32e3..62cd3d4ffa06 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -852,6 +852,19 @@ static_assert(COUNT(arm) == LOGICAL_AXES, "AXIS_RELATIVE_MODES must contain " _L #endif #endif +/** + * Nonlinear Extrusion requirements + */ +#if ENABLED(NONLINEAR_EXTRUSION) + #if DISABLED(ADAPTIVE_STEP_SMOOTHING) + #error "ADAPTIVE_STEP_SMOOTHING is required for NONLINEAR_EXTRUSION" + #endif + + #if EXTRUDERS > 1 + #error "NONLINEAR_EXTRUSION doesn't currently support multi-extruder setups" + #endif +#endif + /** * Special tool-changing options */ diff --git a/Marlin/src/module/planner.cpp b/Marlin/src/module/planner.cpp index 6b645fa1337e..9b8b26892704 100644 --- a/Marlin/src/module/planner.cpp +++ b/Marlin/src/module/planner.cpp @@ -2005,7 +2005,7 @@ bool Planner::_populate_block( #if HAS_EXTRUDERS dm.e = (dist.e > 0); const float esteps_float = dist.e * e_factor[extruder]; - const uint32_t esteps = ABS(esteps_float) + 0.5f; + const uint32_t esteps = ABS(esteps_float); #else constexpr uint32_t esteps = 0; #endif diff --git a/Marlin/src/module/settings.cpp b/Marlin/src/module/settings.cpp index c125577f5ce9..c9ce69215684 100644 --- a/Marlin/src/module/settings.cpp +++ b/Marlin/src/module/settings.cpp @@ -36,7 +36,7 @@ */ // Change EEPROM version if the structure changes -#define EEPROM_VERSION "V88" +#define EEPROM_VERSION "V89" #define EEPROM_OFFSET 100 // Check the integrity of data offsets. @@ -634,6 +634,13 @@ typedef struct SettingsDataStruct { hotend_idle_settings_t hotend_idle_config; // M86 S T E B #endif + // + // NONLINEAR_EXTRUSION + // + #if ENABLED(NONLINEAR_EXTRUSION) + float ne_A, ne_B, ne_C; // M592 A B C + #endif + } SettingsData; //static_assert(sizeof(SettingsData) <= MARLIN_EEPROM_SIZE, "EEPROM too small to contain SettingsData!"); @@ -1729,6 +1736,15 @@ void MarlinSettings::postprocess() { EEPROM_WRITE(hotend_idle.cfg); #endif + // + // NONLINEAR_EXTRUSION + // + #if ENABLED(NONLINEAR_EXTRUSION) + EEPROM_WRITE(stepper.ne_A); + EEPROM_WRITE(stepper.ne_B); + EEPROM_WRITE(stepper.ne_C); + #endif + // // Report final CRC and Data Size // @@ -2803,6 +2819,15 @@ void MarlinSettings::postprocess() { EEPROM_READ(hotend_idle.cfg); #endif + // + // NONLINEAR_EXTRUSION + // + #if ENABLED(NONLINEAR_EXTRUSION) + EEPROM_READ(stepper.ne_A); + EEPROM_READ(stepper.ne_B); + EEPROM_READ(stepper.ne_C); + #endif + // // Validate Final Size and CRC // diff --git a/Marlin/src/module/stepper.cpp b/Marlin/src/module/stepper.cpp index 9bafe7443db1..8c813f165402 100644 --- a/Marlin/src/module/stepper.cpp +++ b/Marlin/src/module/stepper.cpp @@ -245,6 +245,17 @@ uint32_t Stepper::advance_divisor = 0, bool Stepper::la_active = false; #endif +#if ENABLED(NONLINEAR_EXTRUSION) + int32_t Stepper::ne_edividend; + float Stepper::ne_A = 0; + float Stepper::ne_B = 0; + float Stepper::ne_C = 1; + uint32_t Stepper::ne_Afix; + uint32_t Stepper::ne_Bfix; + uint32_t Stepper::ne_Cfix; + uint32_t Stepper::ne_scale; +#endif + #if HAS_ZV_SHAPING shaping_time_t ShapingQueue::now = 0; #if ANY(MCU_LPC1768, MCU_LPC1769) && DISABLED(NO_LPC_ETHERNET_BUFFER) @@ -2194,6 +2205,11 @@ 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(NONLINEAR_EXTRUSION) + uint32_t velocity = ne_scale * step_rate; // scale step_rate first so all intermediate values stay in range of 8.24 fixed point math + advance_dividend.e = STEP_MULTIPLY(ne_Cfix + STEP_MULTIPLY(velocity, ne_Afix) + STEP_MULTIPLY(velocity, STEP_MULTIPLY(velocity, ne_Bfix)), ne_edividend); + #endif + #if ENABLED(OLD_ADAPTIVE_MULTISTEPPING) #if MULTISTEPPING_LIMIT == 1 @@ -2636,15 +2652,16 @@ hal_timer_t Stepper::block_phase_isr() { acceleration_time = deceleration_time = 0; #if ENABLED(ADAPTIVE_STEP_SMOOTHING) - oversampling_factor = 0; // Assume no axis smoothing (via oversampling) + oversampling_factor = 0; // Assume no axis smoothing (via oversampling) + #if ENABLED(NONLINEAR_EXTRUSION) + oversampling_factor = 1; // We need at least 2x oversampling to ensure we can increase extruder step rate + #endif // Decide if axis smoothing is possible - uint32_t max_rate = current_block->nominal_rate; // Get the step event rate - if (TERN1(DWIN_LCD_PROUI, hmiData.adaptiveStepSmoothing)) { - 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 - ++oversampling_factor; // Increase the oversampling (used for left-shift) - } + 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... + max_rate <<= 1; // Try to double the rate + if (max_rate < MIN_STEP_ISR_FREQUENCY) // Don't exceed the estimated ISR limit + ++oversampling_factor; // Increase the oversampling (used for left-shift) } #endif @@ -2755,6 +2772,21 @@ hal_timer_t Stepper::block_phase_isr() { acc_step_rate = current_block->initial_rate; #endif + #if ENABLED(NONLINEAR_EXTRUSION) + ne_edividend = advance_dividend.e; + float scale = (float(ne_edividend) / advance_divisor) * planner.mm_per_step[E_AXIS_N(current_block->extruder)]; + ne_scale = (1L << 24) * scale; + if (current_block->direction_bits.e) { + ne_Afix = (1L << 24) * ne_A; + ne_Bfix = (1L << 24) * ne_B; + ne_Cfix = (1L << 24) * ne_C; + } else { + ne_Afix = 0; + ne_Bfix = 0; + ne_Cfix = (1L << 24); + } + #endif + // Calculate the initial timer interval interval = calc_multistep_timer_interval(current_block->initial_rate << oversampling_factor); acceleration_time += interval; diff --git a/Marlin/src/module/stepper.h b/Marlin/src/module/stepper.h index 7dbb6b8b5a1d..af1d98bc118e 100644 --- a/Marlin/src/module/stepper.h +++ b/Marlin/src/module/stepper.h @@ -326,6 +326,12 @@ class Stepper { static bool frozen; // Set this flag to instantly freeze motion #endif + #if ENABLED(NONLINEAR_EXTRUSION) + static float ne_A; + static float ne_B; + static float ne_C; + #endif + private: static block_t* current_block; // A pointer to the block currently being traced @@ -416,6 +422,14 @@ class Stepper { static bool la_active; // Whether linear advance is used on the present segment. #endif + #if ENABLED(NONLINEAR_EXTRUSION) + static int32_t ne_edividend; + static uint32_t ne_Afix; + static uint32_t ne_Bfix; + static uint32_t ne_Cfix; + static uint32_t ne_scale; + #endif + #if ENABLED(BABYSTEPPING) static constexpr hal_timer_t BABYSTEP_NEVER = HAL_TIMER_TYPE_MAX; static hal_timer_t nextBabystepISR; diff --git a/ini/features.ini b/ini/features.ini index 1a3546e575fd..c89f2fea417f 100644 --- a/ini/features.ini +++ b/ini/features.ini @@ -312,6 +312,7 @@ CONTROLLER_FAN_EDITABLE = build_src_filter=+ GCODE_MACROS = build_src_filter=+ GRADIENT_MIX = build_src_filter=+ +NONLINEAR_EXTRUSION = build_src_filter=+ OTA_FIRMWARE_UPDATE = build_src_filter=+ HAS_SAVED_POSITIONS = build_src_filter=+ + PARK_HEAD_ON_PAUSE = build_src_filter=+ From 1fa21f5c5a1d690e60ca7a5f1706d3992655a060 Mon Sep 17 00:00:00 2001 From: Andrew Bortz Date: Thu, 3 Aug 2023 12:46:12 -0700 Subject: [PATCH 2/7] Support negative params for nonlinear extrusion --- Marlin/src/gcode/feature/nonlinear/M592.cpp | 2 +- Marlin/src/inc/SanityCheck.h | 4 ++++ Marlin/src/module/stepper.cpp | 11 +++++++---- Marlin/src/module/stepper.h | 6 +++--- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/Marlin/src/gcode/feature/nonlinear/M592.cpp b/Marlin/src/gcode/feature/nonlinear/M592.cpp index 9f356d64aeee..6eabb48088ea 100644 --- a/Marlin/src/gcode/feature/nonlinear/M592.cpp +++ b/Marlin/src/gcode/feature/nonlinear/M592.cpp @@ -34,7 +34,7 @@ * C Constant coefficient (default 1.0) * * Adjusts the amount of extrusion based on the instantaneous velocity of extrusion, as a multiplier. - * The amount of extrusion is multiplied by (C + A*v + B*v^2) where v is extruder velocity in mm/s. + * The amount of extrusion is multiplied by max(C, C + A*v + B*v^2) where v is extruder velocity in mm/s. * Only adjusts forward extrusions, since those are the ones affected by backpressure. */ void GcodeSuite::M592() { diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index 62cd3d4ffa06..0f4db61eb11e 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -863,6 +863,10 @@ static_assert(COUNT(arm) == LOGICAL_AXES, "AXIS_RELATIVE_MODES must contain " _L #if EXTRUDERS > 1 #error "NONLINEAR_EXTRUSION doesn't currently support multi-extruder setups" #endif + + #if DISABLED(CPU_32_BIT) + #error "NONLINEAR_EXTRUSION requires 32-bit CPU" + #endif #endif /** diff --git a/Marlin/src/module/stepper.cpp b/Marlin/src/module/stepper.cpp index 8c813f165402..28878ac72609 100644 --- a/Marlin/src/module/stepper.cpp +++ b/Marlin/src/module/stepper.cpp @@ -250,9 +250,9 @@ uint32_t Stepper::advance_divisor = 0, float Stepper::ne_A = 0; float Stepper::ne_B = 0; float Stepper::ne_C = 1; - uint32_t Stepper::ne_Afix; - uint32_t Stepper::ne_Bfix; - uint32_t Stepper::ne_Cfix; + int32_t Stepper::ne_Afix; + int32_t Stepper::ne_Bfix; + int32_t Stepper::ne_Cfix; uint32_t Stepper::ne_scale; #endif @@ -2207,7 +2207,10 @@ hal_timer_t Stepper::calc_multistep_timer_interval(uint32_t step_rate) { #if ENABLED(NONLINEAR_EXTRUSION) uint32_t velocity = ne_scale * step_rate; // scale step_rate first so all intermediate values stay in range of 8.24 fixed point math - advance_dividend.e = STEP_MULTIPLY(ne_Cfix + STEP_MULTIPLY(velocity, ne_Afix) + STEP_MULTIPLY(velocity, STEP_MULTIPLY(velocity, ne_Bfix)), ne_edividend); + int32_t vd = (((int64_t)ne_Afix * velocity) >> 24) + (((((int64_t)ne_Bfix * velocity) >> 24) * velocity) >> 24); + if (vd < 0) vd = 0; + + advance_dividend.e = ((uint64_t)(ne_Cfix + vd) * ne_edividend) >> 24; #endif #if ENABLED(OLD_ADAPTIVE_MULTISTEPPING) diff --git a/Marlin/src/module/stepper.h b/Marlin/src/module/stepper.h index af1d98bc118e..e3ac6d8d7a7d 100644 --- a/Marlin/src/module/stepper.h +++ b/Marlin/src/module/stepper.h @@ -424,9 +424,9 @@ class Stepper { #if ENABLED(NONLINEAR_EXTRUSION) static int32_t ne_edividend; - static uint32_t ne_Afix; - static uint32_t ne_Bfix; - static uint32_t ne_Cfix; + static int32_t ne_Afix; + static int32_t ne_Bfix; + static int32_t ne_Cfix; static uint32_t ne_scale; #endif From acc8e446a03e7774e2be2e6b4d59d44dbd1f643b Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Mon, 7 Aug 2023 05:22:47 -0500 Subject: [PATCH 3/7] apply review changes --- Marlin/Configuration_adv.h | 7 ++-- Marlin/src/core/language.h | 1 + Marlin/src/gcode/feature/nonlinear/M592.cpp | 25 ++++++-------- Marlin/src/gcode/gcode.h | 1 + Marlin/src/inc/SanityCheck.h | 16 ++++----- Marlin/src/module/settings.cpp | 29 ++++++++-------- Marlin/src/module/stepper.cpp | 37 ++++++++++----------- Marlin/src/module/stepper.h | 17 +++++----- buildroot/tests/STM32F103RC_btt | 2 +- 9 files changed, 65 insertions(+), 70 deletions(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index b10d9a33bd6f..58712031d87e 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -2267,10 +2267,9 @@ /** * Nonlinear Extrusion Control * - * Enables control over extrusion rate based on instantaneous extruder velocity. This can be used - * to correct for underextrusion at high extruder speeds that are otherwise well-behaved (e.g. - * not yet skipping). -*/ + * Control extrusion rate based on instantaneous extruder velocity. Can be used to correct for + * underextrusion at high extruder speeds that are otherwise well-behaved (i.e., not skipping). + */ //#define NONLINEAR_EXTRUSION // @section leveling diff --git a/Marlin/src/core/language.h b/Marlin/src/core/language.h index b76a3d301cc5..73ae4b647852 100644 --- a/Marlin/src/core/language.h +++ b/Marlin/src/core/language.h @@ -299,6 +299,7 @@ #define STR_CHAMBER_PID "Chamber PID" #define STR_STEPS_PER_UNIT "Steps per unit" #define STR_LINEAR_ADVANCE "Linear Advance" +#define STR_NONLINEAR_EXTRUSION "Nonlinear Extrusion" #define STR_CONTROLLER_FAN "Controller Fan" #define STR_STEPPER_MOTOR_CURRENTS "Stepper motor currents" #define STR_RETRACT_S_F_Z "Retract (S F Z)" diff --git a/Marlin/src/gcode/feature/nonlinear/M592.cpp b/Marlin/src/gcode/feature/nonlinear/M592.cpp index 6eabb48088ea..dc8c1e1e588e 100644 --- a/Marlin/src/gcode/feature/nonlinear/M592.cpp +++ b/Marlin/src/gcode/feature/nonlinear/M592.cpp @@ -27,28 +27,25 @@ #include "../../gcode.h" #include "../../../module/stepper.h" +void GcodeSuite::M592_report(const bool forReplay/*=true*/) { + report_heading(forReplay, F(STR_NONLINEAR_EXTRUSION)); + SERIAL_ECHOLNPGM(" M593 A", stepper.ne.A, " B", stepper.ne.B, " C", stepper.ne.C); +} + /** * M592: Get or set nonlinear extrusion parameters * A Linear coefficient (default 0.0) * B Quadratic coefficient (default 0.0) * C Constant coefficient (default 1.0) * - * Adjusts the amount of extrusion based on the instantaneous velocity of extrusion, as a multiplier. - * The amount of extrusion is multiplied by max(C, C + A*v + B*v^2) where v is extruder velocity in mm/s. - * Only adjusts forward extrusions, since those are the ones affected by backpressure. + * Adjusts the amount of extrusion based on the instantaneous velocity of extrusion, as a multiplier. + * The amount of extrusion is multiplied by max(C, C + A*v + B*v^2) where v is extruder velocity in mm/s. + * Only adjusts forward extrusions, since those are the ones affected by backpressure. */ void GcodeSuite::M592() { - if (parser.seenval('A')) { - stepper.ne_A = parser.value_float(); - } - - if (parser.seenval('B')) { - stepper.ne_B = parser.value_float(); - } - - if (parser.seenval('C')) { - stepper.ne_C = parser.value_float(); - } + if (parser.seenval('A')) stepper.ne.A = parser.value_float(); + if (parser.seenval('B')) stepper.ne.B = parser.value_float(); + if (parser.seenval('C')) stepper.ne.C = parser.value_float(); } #endif // NONLINEAR_EXTRUSION diff --git a/Marlin/src/gcode/gcode.h b/Marlin/src/gcode/gcode.h index ff24a106c387..5e6e400cf1d4 100644 --- a/Marlin/src/gcode/gcode.h +++ b/Marlin/src/gcode/gcode.h @@ -1109,6 +1109,7 @@ class GcodeSuite { #if ENABLED(NONLINEAR_EXTRUSION) static void M592(); + static void M592_report(const bool forReplay=true); #endif #if HAS_ZV_SHAPING diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index 0f4db61eb11e..36c172e3a50f 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -853,19 +853,15 @@ static_assert(COUNT(arm) == LOGICAL_AXES, "AXIS_RELATIVE_MODES must contain " _L #endif /** - * Nonlinear Extrusion requirements + * Nonlinear Extrusion requirements */ #if ENABLED(NONLINEAR_EXTRUSION) #if DISABLED(ADAPTIVE_STEP_SMOOTHING) - #error "ADAPTIVE_STEP_SMOOTHING is required for NONLINEAR_EXTRUSION" - #endif - - #if EXTRUDERS > 1 - #error "NONLINEAR_EXTRUSION doesn't currently support multi-extruder setups" - #endif - - #if DISABLED(CPU_32_BIT) - #error "NONLINEAR_EXTRUSION requires 32-bit CPU" + #error "ADAPTIVE_STEP_SMOOTHING is required for NONLINEAR_EXTRUSION." + #elif HAS_MULTI_EXTRUDER + #error "NONLINEAR_EXTRUSION doesn't currently support multi-extruder setups." + #elif DISABLED(CPU_32_BIT) + #error "NONLINEAR_EXTRUSION requires a 32-bit CPU." #endif #endif diff --git a/Marlin/src/module/settings.cpp b/Marlin/src/module/settings.cpp index c9ce69215684..2194f3283a62 100644 --- a/Marlin/src/module/settings.cpp +++ b/Marlin/src/module/settings.cpp @@ -635,10 +635,10 @@ typedef struct SettingsDataStruct { #endif // - // NONLINEAR_EXTRUSION + // Nonlinear Extrusion // #if ENABLED(NONLINEAR_EXTRUSION) - float ne_A, ne_B, ne_C; // M592 A B C + ne_coeff_t stepper_ne; // M592 A B C #endif } SettingsData; @@ -1737,12 +1737,10 @@ void MarlinSettings::postprocess() { #endif // - // NONLINEAR_EXTRUSION + // Nonlinear Extrusion // #if ENABLED(NONLINEAR_EXTRUSION) - EEPROM_WRITE(stepper.ne_A); - EEPROM_WRITE(stepper.ne_B); - EEPROM_WRITE(stepper.ne_C); + EEPROM_WRITE(stepper.ne); #endif // @@ -2820,12 +2818,10 @@ void MarlinSettings::postprocess() { #endif // - // NONLINEAR_EXTRUSION + // Nonlinear Extrusion // #if ENABLED(NONLINEAR_EXTRUSION) - EEPROM_READ(stepper.ne_A); - EEPROM_READ(stepper.ne_B); - EEPROM_READ(stepper.ne_C); + EEPROM_READ(stepper.ne); #endif // @@ -3421,7 +3417,6 @@ void MarlinSettings::reset() { // // Heated Bed PID // - #if ENABLED(PIDTEMPBED) thermalManager.temp_bed.pid.set(DEFAULT_bedKp, DEFAULT_bedKi, DEFAULT_bedKd); #endif @@ -3429,7 +3424,6 @@ void MarlinSettings::reset() { // // Heated Chamber PID // - #if ENABLED(PIDTEMPCHAMBER) thermalManager.temp_chamber.pid.set(DEFAULT_chamberKp, DEFAULT_chamberKi, DEFAULT_chamberKd); #endif @@ -3481,7 +3475,6 @@ void MarlinSettings::reset() { // // Volumetric & Filament Size // - #if DISABLED(NO_VOLUMETRICS) parser.volumetric_enabled = ENABLED(VOLUMETRIC_DEFAULT_ON); for (uint8_t q = 0; q < COUNT(planner.filament_size); ++q) @@ -3623,6 +3616,11 @@ void MarlinSettings::reset() { // TERN_(FT_MOTION, fxdTiCtrl.set_defaults()); + // + // Nonlinear Extrusion + // + TERN_(NONLINEAR_EXTRUSION, stepper.ne.reset()); + // // Input Shaping // @@ -3892,6 +3890,11 @@ void MarlinSettings::reset() { // TERN_(FT_MOTION, gcode.M493_report(forReplay)); + // + // Nonlinear Extrusion + // + TERN_(NONLINEAR_EXTRUSION, gcode.M592_report(forReplay)); + // // Input Shaping // diff --git a/Marlin/src/module/stepper.cpp b/Marlin/src/module/stepper.cpp index 28878ac72609..fb00ccc4132a 100644 --- a/Marlin/src/module/stepper.cpp +++ b/Marlin/src/module/stepper.cpp @@ -246,13 +246,9 @@ uint32_t Stepper::advance_divisor = 0, #endif #if ENABLED(NONLINEAR_EXTRUSION) + ne_coeff_t Stepper::ne; + ne_fix_t Stepper::ne_fix; int32_t Stepper::ne_edividend; - float Stepper::ne_A = 0; - float Stepper::ne_B = 0; - float Stepper::ne_C = 1; - int32_t Stepper::ne_Afix; - int32_t Stepper::ne_Bfix; - int32_t Stepper::ne_Cfix; uint32_t Stepper::ne_scale; #endif @@ -2206,11 +2202,11 @@ hal_timer_t Stepper::calc_timer_interval(uint32_t step_rate) { hal_timer_t Stepper::calc_multistep_timer_interval(uint32_t step_rate) { #if ENABLED(NONLINEAR_EXTRUSION) - uint32_t velocity = ne_scale * step_rate; // scale step_rate first so all intermediate values stay in range of 8.24 fixed point math - int32_t vd = (((int64_t)ne_Afix * velocity) >> 24) + (((((int64_t)ne_Bfix * velocity) >> 24) * velocity) >> 24); - if (vd < 0) vd = 0; + const uint32_t velocity = ne_scale * step_rate; // Scale step_rate first so all intermediate values stay in range of 8.24 fixed point math + int32_t vd = (((int64_t)nefix.A * velocity) >> 24) + (((((int64_t)nefix.B * velocity) >> 24) * velocity) >> 24); + NOLESS(vd, 0); - advance_dividend.e = ((uint64_t)(ne_Cfix + vd) * ne_edividend) >> 24; + advance_dividend.e = (uint64_t(nefix.C + vd) * ne_edividend) >> 24; #endif #if ENABLED(OLD_ADAPTIVE_MULTISTEPPING) @@ -2655,9 +2651,10 @@ hal_timer_t Stepper::block_phase_isr() { acceleration_time = deceleration_time = 0; #if ENABLED(ADAPTIVE_STEP_SMOOTHING) - oversampling_factor = 0; // Assume no axis smoothing (via oversampling) #if ENABLED(NONLINEAR_EXTRUSION) - oversampling_factor = 1; // We need at least 2x oversampling to ensure we can increase extruder step rate + oversampling_factor = 1; // Need at least 2x oversampling to permit increase of E step rate + #else + oversampling_factor = 0; // Assume no axis smoothing (via oversampling) #endif // Decide if axis smoothing is possible uint32_t max_rate = current_block->nominal_rate; // Get the step event rate @@ -2777,16 +2774,16 @@ hal_timer_t Stepper::block_phase_isr() { #if ENABLED(NONLINEAR_EXTRUSION) ne_edividend = advance_dividend.e; - float scale = (float(ne_edividend) / advance_divisor) * planner.mm_per_step[E_AXIS_N(current_block->extruder)]; + const float scale = (float(ne_edividend) / advance_divisor) * planner.mm_per_step[E_AXIS_N(current_block->extruder)]; ne_scale = (1L << 24) * scale; if (current_block->direction_bits.e) { - ne_Afix = (1L << 24) * ne_A; - ne_Bfix = (1L << 24) * ne_B; - ne_Cfix = (1L << 24) * ne_C; - } else { - ne_Afix = 0; - ne_Bfix = 0; - ne_Cfix = (1L << 24); + ne_fix.A = (1L << 24) * ne.A; + ne_fix.B = (1L << 24) * ne.B; + ne_fix.C = (1L << 24) * ne.C; + } + else { + ne_fix.A = ne_fix.B = 0; + ne_fix.C = (1L << 24); } #endif diff --git a/Marlin/src/module/stepper.h b/Marlin/src/module/stepper.h index e3ac6d8d7a7d..89f1ecc9a213 100644 --- a/Marlin/src/module/stepper.h +++ b/Marlin/src/module/stepper.h @@ -284,6 +284,11 @@ constexpr ena_mask_t enable_overlap[] = { #endif // HAS_ZV_SHAPING +#if ENABLED(NONLINEAR_EXTRUSION) + typedef struct { float A, B, C; void reset() { A = B = 0.0f; C = 1.0f; } } ne_coeff_t; + typedef struct { int32_t A, B, C; } ne_fix_t; +#endif + // // Stepper class definition // @@ -327,9 +332,7 @@ class Stepper { #endif #if ENABLED(NONLINEAR_EXTRUSION) - static float ne_A; - static float ne_B; - static float ne_C; + static ne_coeff_t nla; #endif private: @@ -423,11 +426,9 @@ class Stepper { #endif #if ENABLED(NONLINEAR_EXTRUSION) - static int32_t ne_edividend; - static int32_t ne_Afix; - static int32_t ne_Bfix; - static int32_t ne_Cfix; - static uint32_t ne_scale; + static int32_t ne_edividend; + static uint32_t ne_scale; + static ne_fix_t ne_fix; #endif #if ENABLED(BABYSTEPPING) diff --git a/buildroot/tests/STM32F103RC_btt b/buildroot/tests/STM32F103RC_btt index 8df20740c49c..6e20b9e46918 100755 --- a/buildroot/tests/STM32F103RC_btt +++ b/buildroot/tests/STM32F103RC_btt @@ -12,7 +12,7 @@ set -e restore_configs opt_set MOTHERBOARD BOARD_BTT_SKR_MINI_E3_V1_0 SERIAL_PORT 1 SERIAL_PORT_2 -1 \ X_DRIVER_TYPE TMC2209 Y_DRIVER_TYPE TMC2209 Z_DRIVER_TYPE TMC2209 E0_DRIVER_TYPE TMC2209 -opt_enable CR10_STOCKDISPLAY PINS_DEBUGGING Z_IDLE_HEIGHT FT_MOTION FT_MOTION_MENU +opt_enable CR10_STOCKDISPLAY PINS_DEBUGGING Z_IDLE_HEIGHT FT_MOTION FT_MOTION_MENU NONLINEAR_EXTRUSION exec_test $1 $2 "BigTreeTech SKR Mini E3 1.0 - TMC2209 HW Serial, FT_MOTION" "$3" # clean up From 82b5101fa5ab74f03b71bc5f386e852d694a5f94 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Mon, 7 Aug 2023 15:55:52 -0500 Subject: [PATCH 4/7] fix test --- buildroot/tests/STM32F103RC_btt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildroot/tests/STM32F103RC_btt b/buildroot/tests/STM32F103RC_btt index 6e20b9e46918..b9fff2b6c533 100755 --- a/buildroot/tests/STM32F103RC_btt +++ b/buildroot/tests/STM32F103RC_btt @@ -12,7 +12,7 @@ set -e restore_configs opt_set MOTHERBOARD BOARD_BTT_SKR_MINI_E3_V1_0 SERIAL_PORT 1 SERIAL_PORT_2 -1 \ X_DRIVER_TYPE TMC2209 Y_DRIVER_TYPE TMC2209 Z_DRIVER_TYPE TMC2209 E0_DRIVER_TYPE TMC2209 -opt_enable CR10_STOCKDISPLAY PINS_DEBUGGING Z_IDLE_HEIGHT FT_MOTION FT_MOTION_MENU NONLINEAR_EXTRUSION +opt_enable CR10_STOCKDISPLAY PINS_DEBUGGING Z_IDLE_HEIGHT FT_MOTION FT_MOTION_MENU ADAPTIVE_STEP_SMOOTHING NONLINEAR_EXTRUSION exec_test $1 $2 "BigTreeTech SKR Mini E3 1.0 - TMC2209 HW Serial, FT_MOTION" "$3" # clean up From c8a516b2c3efe089175ea929eac377b7bc7879ea Mon Sep 17 00:00:00 2001 From: Andrew Bortz Date: Fri, 11 Aug 2023 17:28:29 -0700 Subject: [PATCH 5/7] Fix naming --- Marlin/src/module/stepper.cpp | 4 ++-- Marlin/src/module/stepper.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Marlin/src/module/stepper.cpp b/Marlin/src/module/stepper.cpp index fb00ccc4132a..6bbef87b3b6c 100644 --- a/Marlin/src/module/stepper.cpp +++ b/Marlin/src/module/stepper.cpp @@ -2203,10 +2203,10 @@ hal_timer_t Stepper::calc_multistep_timer_interval(uint32_t step_rate) { #if ENABLED(NONLINEAR_EXTRUSION) const uint32_t velocity = ne_scale * step_rate; // Scale step_rate first so all intermediate values stay in range of 8.24 fixed point math - int32_t vd = (((int64_t)nefix.A * velocity) >> 24) + (((((int64_t)nefix.B * velocity) >> 24) * velocity) >> 24); + int32_t vd = (((int64_t)ne_fix.A * velocity) >> 24) + (((((int64_t)ne_fix.B * velocity) >> 24) * velocity) >> 24); NOLESS(vd, 0); - advance_dividend.e = (uint64_t(nefix.C + vd) * ne_edividend) >> 24; + advance_dividend.e = (uint64_t(ne_fix.C + vd) * ne_edividend) >> 24; #endif #if ENABLED(OLD_ADAPTIVE_MULTISTEPPING) diff --git a/Marlin/src/module/stepper.h b/Marlin/src/module/stepper.h index 89f1ecc9a213..f25f7ecc2472 100644 --- a/Marlin/src/module/stepper.h +++ b/Marlin/src/module/stepper.h @@ -332,7 +332,7 @@ class Stepper { #endif #if ENABLED(NONLINEAR_EXTRUSION) - static ne_coeff_t nla; + static ne_coeff_t ne; #endif private: From dafe6af733c70fe7fb74f2a21cb3ee38b0a772d9 Mon Sep 17 00:00:00 2001 From: Andrew Bortz Date: Sat, 12 Aug 2023 18:33:20 +0000 Subject: [PATCH 6/7] Move nonlinear calc out of calc_multistep() --- Marlin/src/module/stepper.cpp | 28 +++++++++++++++++++++++----- Marlin/src/module/stepper.h | 4 ++++ 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/Marlin/src/module/stepper.cpp b/Marlin/src/module/stepper.cpp index 6bbef87b3b6c..1a878f86f7ee 100644 --- a/Marlin/src/module/stepper.cpp +++ b/Marlin/src/module/stepper.cpp @@ -2198,16 +2198,18 @@ hal_timer_t Stepper::calc_timer_interval(uint32_t step_rate) { #endif // !CPU_32_BIT } -// 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(NONLINEAR_EXTRUSION) +#if ENABLED(NONLINEAR_EXTRUSION) + void Stepper::calc_nonlinear_e(uint32_t step_rate) { const uint32_t velocity = ne_scale * step_rate; // Scale step_rate first so all intermediate values stay in range of 8.24 fixed point math int32_t vd = (((int64_t)ne_fix.A * velocity) >> 24) + (((((int64_t)ne_fix.B * velocity) >> 24) * velocity) >> 24); NOLESS(vd, 0); advance_dividend.e = (uint64_t(ne_fix.C + vd) * ne_edividend) >> 24; - #endif + } +#endif + +// 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) @@ -2333,6 +2335,10 @@ hal_timer_t Stepper::block_phase_isr() { interval = calc_multistep_timer_interval(acc_step_rate << oversampling_factor); acceleration_time += interval; + #if ENABLED(NONLINEAR_EXTRUSION) + calc_nonlinear_e(acc_step_rate << oversampling_factor); + #endif + #if ENABLED(LIN_ADVANCE) if (la_active) { const uint32_t la_step_rate = la_advance_steps < current_block->max_adv_steps ? current_block->la_advance_rate : 0; @@ -2403,6 +2409,10 @@ hal_timer_t Stepper::block_phase_isr() { interval = calc_multistep_timer_interval(step_rate << oversampling_factor); deceleration_time += interval; + #if ENABLED(NONLINEAR_EXTRUSION) + calc_nonlinear_e(step_rate << oversampling_factor); + #endif + #if ENABLED(LIN_ADVANCE) if (la_active) { const uint32_t la_step_rate = la_advance_steps > current_block->final_adv_steps ? current_block->la_advance_rate : 0; @@ -2451,6 +2461,10 @@ hal_timer_t Stepper::block_phase_isr() { // step_rate to timer interval and loops for the nominal speed ticks_nominal = calc_multistep_timer_interval(current_block->nominal_rate << oversampling_factor); + #if ENABLED(NONLINEAR_EXTRUSION) + calc_nonlinear_e(current_block->nominal_rate << oversampling_factor); + #endif + #if ENABLED(LIN_ADVANCE) if (la_active) la_interval = calc_timer_interval(current_block->nominal_rate >> current_block->la_scaling); @@ -2791,6 +2805,10 @@ hal_timer_t Stepper::block_phase_isr() { interval = calc_multistep_timer_interval(current_block->initial_rate << oversampling_factor); acceleration_time += interval; + #if ENABLED(NONLINEAR_EXTRUSION) + calc_nonlinear_e(current_block->initial_rate << oversampling_factor); + #endif + #if ENABLED(LIN_ADVANCE) if (la_active) { const uint32_t la_step_rate = la_advance_steps < current_block->max_adv_steps ? current_block->la_advance_rate : 0; diff --git a/Marlin/src/module/stepper.h b/Marlin/src/module/stepper.h index f25f7ecc2472..4312cfaa8b00 100644 --- a/Marlin/src/module/stepper.h +++ b/Marlin/src/module/stepper.h @@ -675,6 +675,10 @@ class Stepper { // Calculate timing interval and steps-per-ISR for the given step rate static hal_timer_t calc_multistep_timer_interval(uint32_t step_rate); + #if ENABLED(NONLINEAR_EXTRUSION) + static void calc_nonlinear_e(uint32_t step_rate); + #endif + #if ENABLED(S_CURVE_ACCELERATION) static void _calc_bezier_curve_coeffs(const int32_t v0, const int32_t v1, const uint32_t av); static int32_t _eval_bezier_curve(const uint32_t curr_step); From f051244fe71b50162e5aa933b9adce3b189d1f16 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Tue, 10 Oct 2023 21:39:25 -0500 Subject: [PATCH 7/7] small tweaks. restore DWIN_LCD_PROUI stuff --- Marlin/src/module/stepper.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/Marlin/src/module/stepper.cpp b/Marlin/src/module/stepper.cpp index 1a878f86f7ee..6077154cd266 100644 --- a/Marlin/src/module/stepper.cpp +++ b/Marlin/src/module/stepper.cpp @@ -2665,17 +2665,18 @@ hal_timer_t Stepper::block_phase_isr() { acceleration_time = deceleration_time = 0; #if ENABLED(ADAPTIVE_STEP_SMOOTHING) - #if ENABLED(NONLINEAR_EXTRUSION) - oversampling_factor = 1; // Need at least 2x oversampling to permit increase of E step rate - #else - oversampling_factor = 0; // Assume no axis smoothing (via oversampling) - #endif + // Nonlinear Extrusion needs at least 2x oversampling to permit increase of E step rate + // Otherwise assume no axis smoothing (via oversampling) + oversampling_factor = TERN(NONLINEAR_EXTRUSION, 1, 0); + // Decide if axis smoothing is possible - 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... - max_rate <<= 1; // Try to double the rate - if (max_rate < MIN_STEP_ISR_FREQUENCY) // Don't exceed the estimated ISR limit - ++oversampling_factor; // Increase the oversampling (used for left-shift) + if (TERN1(DWIN_LCD_PROUI, hmiData.adaptiveStepSmoothing)) { + 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... + max_rate <<= 1; // Try to double the rate + if (max_rate < MIN_STEP_ISR_FREQUENCY) // Don't exceed the estimated ISR limit + ++oversampling_factor; // Increase the oversampling (used for left-shift) + } } #endif