From 12fdde24d89643969554222b0d94cf190cf1fe85 Mon Sep 17 00:00:00 2001 From: David Buezas Date: Tue, 13 May 2025 23:14:04 +0200 Subject: [PATCH] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20Optimize=20Smooth=20Linear?= =?UTF-8?q?=20Advance=20(via=20fixed-point)=20(#27818)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/Configuration_adv.h | 6 +- Marlin/src/gcode/feature/advance/M900.cpp | 46 ++++--- Marlin/src/inc/SanityCheck.h | 2 +- Marlin/src/lcd/e3v2/jyersui/dwin.cpp | 25 ++-- Marlin/src/lcd/e3v2/proui/dwin.cpp | 7 +- Marlin/src/lcd/extui/ui_api.cpp | 4 +- Marlin/src/lcd/menu/menu_advanced.cpp | 28 +++-- Marlin/src/lcd/menu/menu_tune.cpp | 9 +- Marlin/src/lcd/sovol_rts/sovol_rts.cpp | 6 +- Marlin/src/lcd/tft/touch.cpp | 76 ++++++------ Marlin/src/module/planner.cpp | 13 +- Marlin/src/module/planner.h | 31 ++++- Marlin/src/module/settings.cpp | 44 ++++--- Marlin/src/module/stepper.cpp | 141 ++++++++++++---------- Marlin/src/module/stepper.h | 26 ++-- Marlin/src/module/tool_change.cpp | 2 +- 16 files changed, 265 insertions(+), 201 deletions(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index f31a284d81..762ae2aa81 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -2366,11 +2366,11 @@ * Higher k and higher XY acceleration may require larger ADVANCE_TAU to avoid skipping steps. */ #if ENABLED(DISTINCT_E_FACTORS) - #define ADVANCE_TAU { 0.01 } // (s) Smoothing time to reduce extruder acceleration, per extruder + #define ADVANCE_TAU { 0.02 } // (s) Smoothing time to reduce extruder acceleration, per extruder #else - #define ADVANCE_TAU 0.01 // (s) Smoothing time to reduce extruder acceleration + #define ADVANCE_TAU 0.02 // (s) Smoothing time to reduce extruder acceleration #endif - #define SMOOTH_LIN_ADV_HZ 5000 // (Hz) How often to update extruder speed + #define SMOOTH_LIN_ADV_HZ 1000 // (Hz) How often to update extruder speed #define INPUT_SHAPING_E_SYNC // Synchronize the extruder-shaped XY axes (to increase precision) #endif #endif diff --git a/Marlin/src/gcode/feature/advance/M900.cpp b/Marlin/src/gcode/feature/advance/M900.cpp index dc59b5bc90..7b92cad9d2 100644 --- a/Marlin/src/gcode/feature/advance/M900.cpp +++ b/Marlin/src/gcode/feature/advance/M900.cpp @@ -29,7 +29,7 @@ #include "../../../module/stepper.h" #if ENABLED(ADVANCE_K_EXTRA) - float other_extruder_advance_K[DISTINCT_E]; + float other_extruder_advance_K[EXTRUDERS]; uint8_t lin_adv_slot = 0; #endif @@ -62,17 +62,17 @@ void GcodeSuite::M900() { } #endif - float &kref = planner.extruder_advance_K[E_INDEX_N(tool_index)], newK = kref; - const float oldK = newK; + const float oldK = planner.get_advance_k(tool_index); + float newK = oldK; #if ENABLED(SMOOTH_LIN_ADVANCE) - const float oldU = stepper.get_advance_tau(E_INDEX_N(tool_index)); + const float oldU = stepper.get_advance_tau(tool_index); float newU = oldU; #endif #if ENABLED(ADVANCE_K_EXTRA) - float &lref = other_extruder_advance_K[E_INDEX_N(tool_index)]; + float &lref = other_extruder_advance_K[tool_index]; const bool old_slot = TEST(lin_adv_slot, tool_index), // Each tool uses 1 bit to store its current slot (0 or 1) new_slot = parser.boolval('S', old_slot); // The new slot (0 or 1) to set for the tool (default = no change) @@ -125,9 +125,9 @@ void GcodeSuite::M900() { if (newK != oldK || TERN0(SMOOTH_LIN_ADVANCE, newU != oldU)) { planner.synchronize(); - if (newK != oldK) kref = newK; + if (newK != oldK) planner.set_advance_k(newK, tool_index); #if ENABLED(SMOOTH_LIN_ADVANCE) - if (newU != oldU) stepper.set_advance_tau(newU); + if (newU != oldU) stepper.set_advance_tau(newU, tool_index); #endif } @@ -136,11 +136,11 @@ void GcodeSuite::M900() { #if ENABLED(ADVANCE_K_EXTRA) #if DISABLED(DISTINCT_E_FACTORS) - SERIAL_ECHOLNPGM("Advance S", new_slot, " K", kref, "(S", !new_slot, " K", lref, ")"); + SERIAL_ECHOLNPGM("Advance S", new_slot, " K", newK, "(S", !new_slot, " K", lref, ")"); #else EXTRUDER_LOOP() { const bool slot = TEST(lin_adv_slot, e); - SERIAL_ECHOLNPGM("Advance T", e, " S", slot, " K", planner.extruder_advance_K[e], + SERIAL_ECHOLNPGM("Advance T", e, " S", slot, " K", planner.get_advance_k(e), "(S", !slot, " K", other_extruder_advance_K[e], ")"); } #endif @@ -149,14 +149,14 @@ void GcodeSuite::M900() { SERIAL_ECHO_START(); #if DISABLED(DISTINCT_E_FACTORS) - SERIAL_ECHOPGM("Advance K=", planner.extruder_advance_K[0]); + SERIAL_ECHOPGM("Advance K=", planner.get_advance_k()); #if ENABLED(SMOOTH_LIN_ADVANCE) SERIAL_ECHOPGM(" TAU=", stepper.get_advance_tau()); #endif SERIAL_EOL(); #else SERIAL_ECHOPGM("Advance K"); - EXTRUDER_LOOP() SERIAL_ECHO(C(' '), C('0' + e), C(':'), planner.extruder_advance_K[e]); + EXTRUDER_LOOP() SERIAL_ECHO(C(' '), C('0' + e), C(':'), planner.get_advance_k(e)); SERIAL_EOL(); #if ENABLED(SMOOTH_LIN_ADVANCE) SERIAL_ECHOPGM("Advance TAU"); @@ -174,23 +174,21 @@ void GcodeSuite::M900_report(const bool forReplay/*=true*/) { TERN_(MARLIN_SMALL_BUILD, return); report_heading(forReplay, F(STR_LINEAR_ADVANCE)); - #if DISABLED(DISTINCT_E_FACTORS) + DISTINCT_E_LOOP() { report_echo_start(forReplay); - SERIAL_ECHOPGM(" M900 K", planner.extruder_advance_K[0]); + SERIAL_ECHOPGM( + #if ENABLED(DISTINCT_E_FACTORS) + " M900 T", e, " K" + #else + " M900 K" + #endif + ); + SERIAL_ECHO(planner.get_advance_k(e)); #if ENABLED(SMOOTH_LIN_ADVANCE) - SERIAL_ECHOPGM(" M900 U", stepper.get_advance_tau()); + SERIAL_ECHOPGM(" U", stepper.get_advance_tau(e)); #endif SERIAL_EOL(); - #else - EXTRUDER_LOOP() { - report_echo_start(forReplay); - SERIAL_ECHOPGM(" M900 T", e, " K", planner.extruder_advance_K[e]); - #if ENABLED(SMOOTH_LIN_ADVANCE) - SERIAL_ECHOPGM(" U", stepper.get_advance_tau(e)); - #endif - SERIAL_EOL(); - } - #endif + } } #endif // LIN_ADVANCE diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index ff75824673..97cc2ed198 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -3725,7 +3725,7 @@ static_assert(NUM_SERVOS <= NUM_SERVO_PLUGS, "NUM_SERVOS (or some servo index) i * Check per-axis initializers for errors */ -#define __PLUS_TEST(I,A) && (sanity_arr_##A[_MIN(I,signed(COUNT(sanity_arr_##A)-1))] > 0) +#define __PLUS_TEST(I,A) && (sanity_arr_##A[ALIM(I,sanity_arr_##A)] > 0) #define _PLUS_TEST(A) (1 REPEAT2(14,__PLUS_TEST,A)) #if HAS_MULTI_EXTRUDER #define _EXTRA_NOTE " (Did you forget to enable DISTINCT_E_FACTORS?)" diff --git a/Marlin/src/lcd/e3v2/jyersui/dwin.cpp b/Marlin/src/lcd/e3v2/jyersui/dwin.cpp index aa087cefc4..f2c54da745 100644 --- a/Marlin/src/lcd/e3v2/jyersui/dwin.cpp +++ b/Marlin/src/lcd/e3v2/jyersui/dwin.cpp @@ -2398,10 +2398,13 @@ void JyersDWIN::menuItemHandler(const uint8_t menu, const uint8_t item, bool dra case MOTION_LA: if (draw) { drawMenuItem(row, ICON_MaxAccelerated, GET_TEXT_F(MSG_ADVANCE_K)); - drawFloat(planner.extruder_advance_K[0], row, false, 100); + drawFloat(planner.get_advance_k(), row, false, 100); } - else - modifyValue(planner.extruder_advance_K[0], 0, 10, 100); + else { + static float k = planner.get_advance_k(); + modifyValue(k, 0, 10, 100, []{ planner.set_advance_k(k); }); + } + break; #endif } @@ -2914,10 +2917,12 @@ void JyersDWIN::menuItemHandler(const uint8_t menu, const uint8_t item, bool dra case ADVANCED_LA: if (draw) { drawMenuItem(row, ICON_MaxAccelerated, GET_TEXT_F(MSG_ADVANCE_K)); - drawFloat(planner.extruder_advance_K[0], row, false, 100); + drawFloat(planner.get_advance_k(), row, false, 100); + } + else { + static float k = planner.get_advance_k(); + modifyValue(k, 0, 10, 100, []{ planner.set_advance_k(k); }); } - else - modifyValue(planner.extruder_advance_K[0], 0, 10, 100); break; #endif @@ -3925,10 +3930,12 @@ void JyersDWIN::menuItemHandler(const uint8_t menu, const uint8_t item, bool dra case TUNE_LA: if (draw) { drawMenuItem(row, ICON_MaxAccelerated, GET_TEXT_F(MSG_ADVANCE_K)); - drawFloat(planner.extruder_advance_K[0], row, false, 100); + drawFloat(planner.get_advance_k(), row, false, 100); + } + else { + static float k = planner.get_advance_k(); + modifyValue(k, 0, 10, 100, []{ planner.set_advance_k(k); }); } - else - modifyValue(planner.extruder_advance_K[0], 0, 10, 100); break; #endif diff --git a/Marlin/src/lcd/e3v2/proui/dwin.cpp b/Marlin/src/lcd/e3v2/proui/dwin.cpp index c3a69c1c66..7574439051 100644 --- a/Marlin/src/lcd/e3v2/proui/dwin.cpp +++ b/Marlin/src/lcd/e3v2/proui/dwin.cpp @@ -2686,7 +2686,8 @@ void applyMaxAccel() { planner.set_max_acceleration(hmiValue.axis, menuData.valu #endif #if ENABLED(LIN_ADVANCE) - void setLA_K() { setPFloatOnClick(0, 10, 3); } + void applyLA_K() { planner.set_advance_k(menuData.value / MINUNITMULT); } + void setLA_K() { setPFloatOnClick(0, 10, 3, applyLA_K); } #endif #if HAS_X_AXIS @@ -3545,7 +3546,7 @@ void drawTuneMenu() { EDIT_ITEM(ICON_JDmm, MSG_JUNCTION_DEVIATION, onDrawPFloat3Menu, setJDmm, &planner.junction_deviation_mm); #endif #if ENABLED(PROUI_ITEM_ADVK) - EDIT_ITEM(ICON_MaxAccelerated, MSG_ADVANCE_K, onDrawPFloat3Menu, setLA_K, &planner.extruder_advance_K[0]); + EDIT_ITEM(ICON_MaxAccelerated, MSG_ADVANCE_K, onDrawPFloat3Menu, setLA_K, &planner.get_advance_k()); #endif #if HAS_LOCKSCREEN MENU_ITEM(ICON_Lock, MSG_LOCKSCREEN, onDrawMenuItem, dwinLockScreen); @@ -3683,7 +3684,7 @@ void drawMotionMenu() { MENU_ITEM(ICON_Homing, MSG_HOMING_FEEDRATE, onDrawSubMenu, drawHomingFRMenu); #endif #if ENABLED(LIN_ADVANCE) - EDIT_ITEM(ICON_MaxAccelerated, MSG_ADVANCE_K, onDrawPFloat3Menu, setLA_K, &planner.extruder_advance_K[0]); + EDIT_ITEM(ICON_MaxAccelerated, MSG_ADVANCE_K, onDrawPFloat3Menu, setLA_K, &planner.get_advance_k()); #endif #if ENABLED(SHAPING_MENU) MENU_ITEM(ICON_InputShaping, MSG_INPUT_SHAPING, onDrawSubMenu, drawInputShaping_menu); diff --git a/Marlin/src/lcd/extui/ui_api.cpp b/Marlin/src/lcd/extui/ui_api.cpp index b3f4c39c24..5380b05596 100644 --- a/Marlin/src/lcd/extui/ui_api.cpp +++ b/Marlin/src/lcd/extui/ui_api.cpp @@ -643,12 +643,12 @@ namespace ExtUI { #if ENABLED(LIN_ADVANCE) float getLinearAdvance_mm_mm_s(const extruder_t extruder) { - return (extruder < EXTRUDERS) ? planner.extruder_advance_K[E_INDEX_N(extruder - E0)] : 0; + return (extruder < EXTRUDERS) ? planner.get_advance_k(E_INDEX_N(extruder - E0)) : 0; } void setLinearAdvance_mm_mm_s(const_float_t value, const extruder_t extruder) { if (extruder < EXTRUDERS) - planner.extruder_advance_K[E_INDEX_N(extruder - E0)] = constrain(value, 0, 10); + planner.set_advance_k(constrain(value, 0, 10), E_INDEX_N(extruder - E0)); } #endif diff --git a/Marlin/src/lcd/menu/menu_advanced.cpp b/Marlin/src/lcd/menu/menu_advanced.cpp index 92f2f51536..b15a21fc7b 100644 --- a/Marlin/src/lcd/menu/menu_advanced.cpp +++ b/Marlin/src/lcd/menu/menu_advanced.cpp @@ -117,10 +117,13 @@ void menu_backlash(); #if ENABLED(LIN_ADVANCE) #if DISABLED(DISTINCT_E_FACTORS) - EDIT_ITEM(float42_52, MSG_ADVANCE_K, &planner.extruder_advance_K[0], 0, 10); + editable.decimal = planner.get_advance_k(); + EDIT_ITEM(float42_52, MSG_ADVANCE_K, &editable.decimal, 0.0f, 10.0f, []{ planner.set_advance_k(editable.decimal); }); #else - EXTRUDER_LOOP() - EDIT_ITEM_N(float42_52, e, MSG_ADVANCE_K_E, &planner.extruder_advance_K[e], 0, 10); + EXTRUDER_LOOP() { + editable.decimal = planner.get_advance_k(e); + EDIT_ITEM_N(float42_52, e, MSG_ADVANCE_K_E, &editable.decimal, 0.0f, 10.0f, []{ planner.set_advance_k(editable.decimal, MenuItemBase::itemIndex); }); + } #endif #if ENABLED(SMOOTH_LIN_ADVANCE) #if DISABLED(DISTINCT_E_FACTORS) @@ -745,15 +748,19 @@ void menu_advanced_settings() { #endif #if HAS_ADV_FILAMENT_MENU - SUBMENU(MSG_FILAMENT, menu_advanced_filament); - #endif - #if ENABLED(LIN_ADVANCE) && DISABLED(HAS_ADV_FILAMENT_MENU) + SUBMENU(MSG_FILAMENT, menu_advanced_filament); + + #elif ENABLED(LIN_ADVANCE) + #if DISABLED(DISTINCT_E_FACTORS) - EDIT_ITEM(float42_52, MSG_ADVANCE_K, &planner.extruder_advance_K[0], 0, 10); + editable.decimal = planner.get_advance_k(); + EDIT_ITEM(float42_52, MSG_ADVANCE_K, &editable.decimal, 0.0f, 10.0f, []{ planner.set_advance_k(editable.decimal); }); #else - EXTRUDER_LOOP() - EDIT_ITEM_N(float42_52, e, MSG_ADVANCE_K_E, &planner.extruder_advance_K[e], 0, 10); + EXTRUDER_LOOP() { + editable.decimal = planner.get_advance_k(e); + EDIT_ITEM_N(float42_52, e, MSG_ADVANCE_K_E, &editable.decimal, 0.0f, 10.0f, []{ planner.set_advance_k(editable.decimal, MenuItemBase::itemIndex); }); + } #endif #if ENABLED(SMOOTH_LIN_ADVANCE) #if DISABLED(DISTINCT_E_FACTORS) @@ -766,7 +773,8 @@ void menu_advanced_settings() { } #endif #endif - #endif + + #endif // LIN_ADVANCE && !HAS_ADV_FILAMENT_MENU // M540 S - Abort on endstop hit when SD printing #if ENABLED(SD_ABORT_ON_ENDSTOP_HIT) diff --git a/Marlin/src/lcd/menu/menu_tune.cpp b/Marlin/src/lcd/menu/menu_tune.cpp index d5cb805244..7f4696a3f1 100644 --- a/Marlin/src/lcd/menu/menu_tune.cpp +++ b/Marlin/src/lcd/menu/menu_tune.cpp @@ -216,10 +216,13 @@ void menu_tune() { // #if ENABLED(LIN_ADVANCE) && DISABLED(SLIM_LCD_MENUS) #if DISABLED(DISTINCT_E_FACTORS) - EDIT_ITEM(float42_52, MSG_ADVANCE_K, &planner.extruder_advance_K[0], 0, 10); + editable.decimal = planner.get_advance_k(); + EDIT_ITEM(float42_52, MSG_ADVANCE_K, &editable.decimal, 0.0f, 10.0f, []{ planner.set_advance_k(editable.decimal); }); #else - EXTRUDER_LOOP() - EDIT_ITEM_N(float42_52, e, MSG_ADVANCE_K_E, &planner.extruder_advance_K[e], 0, 10); + EXTRUDER_LOOP() { + editable.decimal = planner.get_advance_k(e); + EDIT_ITEM_N(float42_52, e, MSG_ADVANCE_K_E, &editable.decimal, 0.0f, 10.0f, []{ planner.set_advance_k(editable.decimal, MenuItemBase::itemIndex); }); + } #endif #if ENABLED(SMOOTH_LIN_ADVANCE) #if DISABLED(DISTINCT_E_FACTORS) diff --git a/Marlin/src/lcd/sovol_rts/sovol_rts.cpp b/Marlin/src/lcd/sovol_rts/sovol_rts.cpp index bea95be96a..3c09838684 100644 --- a/Marlin/src/lcd/sovol_rts/sovol_rts.cpp +++ b/Marlin/src/lcd/sovol_rts/sovol_rts.cpp @@ -894,7 +894,7 @@ void RTS::handleData() { break; case 4: // Go to Advanced Settings - TERN_(LIN_ADVANCE, sendData(planner.extruder_advance_K[0] * 100, Advance_K_VP)); + TERN_(LIN_ADVANCE, sendData(planner.get_advance_k() * 100, Advance_K_VP)); gotoPage(ID_AdvWarn_L, ID_AdvWarn_D); break; @@ -1292,7 +1292,7 @@ void RTS::handleData() { #if ENABLED(LIN_ADVANCE) case 7: // Confirm - sendData(planner.extruder_advance_K[0] * 100, Advance_K_VP); + sendData(planner.get_advance_k() * 100, Advance_K_VP); gotoPage(ID_Advanced_L, ID_Advanced_D); break; #endif @@ -1350,7 +1350,7 @@ void RTS::handleData() { #endif case A_Retract: planner.settings.retract_acceleration = recdat.data[0]; break; #if ENABLED(LIN_ADVANCE) - case Advance_K: planner.extruder_advance_K[0] = float(recdat.data[0]) / 100.0f; break; + case Advance_K: planner.set_advance_k(float(recdat.data[0]) / 100.0f); break; #endif #endif case Accel: planner.settings.acceleration = recdat.data[0]; break; diff --git a/Marlin/src/lcd/tft/touch.cpp b/Marlin/src/lcd/tft/touch.cpp index bb226e50c6..fbba927a86 100644 --- a/Marlin/src/lcd/tft/touch.cpp +++ b/Marlin/src/lcd/tft/touch.cpp @@ -181,44 +181,51 @@ void Touch::touch(touch_control_t *control) { case SLIDER: hold(control); ui.encoderPosition = (x - control->x) * control->data / control->width; break; case INCREASE: hold(control, repeat_delay - 5); TERN(AUTO_BED_LEVELING_UBL, ui.external_control ? bedlevel.encoder_diff++ : ui.encoderPosition++, ui.encoderPosition++); break; case DECREASE: hold(control, repeat_delay - 5); TERN(AUTO_BED_LEVELING_UBL, ui.external_control ? bedlevel.encoder_diff-- : ui.encoderPosition--, ui.encoderPosition--); break; - case HEATER: - int8_t heater; - heater = control->data; + case HEATER: { ui.clear_for_drawing(); - #if HAS_HOTEND - if (heater >= 0) { // HotEnd - #if HOTENDS == 1 - MenuItem_int3::action(GET_TEXT_F(MSG_NOZZLE), &thermalManager.temp_hotend[0].target, 0, thermalManager.hotend_max_target(0), []{ thermalManager.start_watching_hotend(0); }); - #else - MenuItemBase::itemIndex = heater; - MenuItem_int3::action(GET_TEXT_F(MSG_NOZZLE_N), &thermalManager.temp_hotend[heater].target, 0, thermalManager.hotend_max_target(heater), []{ thermalManager.start_watching_hotend(MenuItemBase::itemIndex); }); + const int8_t heater = control->data; + switch (heater) { + default: // Hotend + #if HAS_HOTEND + #define HOTEND_HEATER(N) TERN0(HAS_MULTI_HOTEND, N) + TERN_(HAS_MULTI_HOTEND, MenuItemBase::itemIndex = heater); + MenuItem_int3::action(GET_TEXT_F(TERN(HAS_MULTI_HOTEND, MSG_NOZZLE_N, MSG_NOZZLE)), + &thermalManager.temp_hotend[HOTEND_HEATER(heater)].target, 0, thermalManager.hotend_max_target(HOTEND_HEATER(heater)), + []{ thermalManager.start_watching_hotend(HOTEND_HEATER(MenuItemBase::itemIndex)); } + ); #endif - } - #endif - #if HAS_HEATED_BED - else if (heater == H_BED) { - MenuItem_int3::action(GET_TEXT_F(MSG_BED), &thermalManager.temp_bed.target, 0, BED_MAX_TARGET, thermalManager.start_watching_bed); - } - #endif - #if HAS_HEATED_CHAMBER - else if (heater == H_CHAMBER) { - MenuItem_int3::action(GET_TEXT_F(MSG_CHAMBER), &thermalManager.temp_chamber.target, 0, CHAMBER_MAX_TARGET, thermalManager.start_watching_chamber); - } - #endif - #if HAS_COOLER - else if (heater == H_COOLER) { - MenuItem_int3::action(GET_TEXT_F(MSG_COOLER), &thermalManager.temp_cooler.target, 0, COOLER_MAX_TARGET, thermalManager.start_watching_cooler); - } - #endif + break; - break; - case FAN: + #if HAS_HEATED_BED + case H_BED: + MenuItem_int3::action(GET_TEXT_F(MSG_BED), &thermalManager.temp_bed.target, 0, BED_MAX_TARGET, thermalManager.start_watching_bed); + break; + #endif + + #if HAS_HEATED_CHAMBER + case H_CHAMBER: + MenuItem_int3::action(GET_TEXT_F(MSG_CHAMBER), &thermalManager.temp_chamber.target, 0, CHAMBER_MAX_TARGET, thermalManager.start_watching_chamber); + break; + #endif + + #if HAS_COOLER + case H_COOLER: + MenuItem_int3::action(GET_TEXT_F(MSG_COOLER), &thermalManager.temp_cooler.target, 0, COOLER_MAX_TARGET, thermalManager.start_watching_cooler); + break; + #endif + + } // switch + + } break; + + case FAN: { ui.clear_for_drawing(); static uint8_t fan, fan_speed; fan = 0; fan_speed = thermalManager.fan_speed[fan]; MenuItem_percent::action(GET_TEXT_F(MSG_FIRST_FAN_SPEED), &fan_speed, 0, 255, []{ thermalManager.set_fan_speed(fan, fan_speed); TERN_(LASER_SYNCHRONOUS_M106_M107, planner.buffer_sync_block(BLOCK_BIT_SYNC_FANS));}); - break; + } break; + case FEEDRATE: ui.clear_for_drawing(); MenuItem_int3::action(GET_TEXT_F(MSG_SPEED), &feedrate_percentage, SPEED_EDIT_MIN, SPEED_EDIT_MAX); @@ -228,11 +235,10 @@ void Touch::touch(touch_control_t *control) { case FLOWRATE: ui.clear_for_drawing(); MenuItemBase::itemIndex = control->data; - #if EXTRUDERS == 1 - MenuItem_int3::action(GET_TEXT_F(MSG_FLOW), &planner.flow_percentage[MenuItemBase::itemIndex], FLOW_EDIT_MIN, FLOW_EDIT_MAX, []{ planner.refresh_e_factor(MenuItemBase::itemIndex); }); - #else - MenuItem_int3::action(GET_TEXT_F(MSG_FLOW_N), &planner.flow_percentage[MenuItemBase::itemIndex], FLOW_EDIT_MIN, FLOW_EDIT_MAX, []{ planner.refresh_e_factor(MenuItemBase::itemIndex); }); - #endif + MenuItem_int3::action(GET_TEXT_F(TERN(HAS_MULTI_EXTRUDER, MSG_FLOW_N, MSG_FLOW)), + &planner.flow_percentage[MenuItemBase::itemIndex], FLOW_EDIT_MIN, FLOW_EDIT_MAX, + []{ planner.refresh_e_factor(MenuItemBase::itemIndex); } + ); break; #endif diff --git a/Marlin/src/module/planner.cpp b/Marlin/src/module/planner.cpp index 87cb4cd21b..fe497058d9 100644 --- a/Marlin/src/module/planner.cpp +++ b/Marlin/src/module/planner.cpp @@ -236,6 +236,9 @@ float Planner::previous_nominal_speed; #if ENABLED(LIN_ADVANCE) float Planner::extruder_advance_K[DISTINCT_E]; // Initialized by settings.load + #if ENABLED(SMOOTH_LIN_ADVANCE) + uint32_t Planner::extruder_advance_K_q27[DISTINCT_E]; + #endif #endif #if HAS_POSITION_FLOAT @@ -2457,7 +2460,7 @@ bool Planner::_populate_block( block->acceleration_steps_per_s2 = accel; block->acceleration = accel / steps_per_mm; #if DISABLED(S_CURVE_ACCELERATION) - block->acceleration_rate = uint32_t(accel * (float(1UL << 24) / (STEPPER_TIMER_RATE))); + block->acceleration_rate = uint32_t(accel * (float(_BV32(24)) / (STEPPER_TIMER_RATE))); #endif #if HAS_ROUGH_LIN_ADVANCE @@ -2478,7 +2481,13 @@ bool Planner::_populate_block( } #elif ENABLED(SMOOTH_LIN_ADVANCE) block->use_advance_lead = use_advance_lead; - block->e_step_ratio = (block->direction_bits.e ? 1 : -1) * float(block->steps.e) / block->step_event_count; + const uint32_t ratio = (uint64_t(block->steps.e) * _BV32(30)) / block->step_event_count; + block->e_step_ratio_q30 = block->direction_bits.e ? ratio : -ratio; + + #if ENABLED(INPUT_SHAPING_E_SYNC) + const uint32_t xy_steps = TERN0(INPUT_SHAPING_X, block->steps.x) + TERN0(INPUT_SHAPING_Y, block->steps.y); + block->xy_length_inv_q30 = xy_steps ? (_BV32(30) / xy_steps) : 0; + #endif #endif // Formula for the average speed over a 1 step worth of distance if starting from zero and diff --git a/Marlin/src/module/planner.h b/Marlin/src/module/planner.h index 1c23f95cb1..ead39a8bd4 100644 --- a/Marlin/src/module/planner.h +++ b/Marlin/src/module/planner.h @@ -247,7 +247,10 @@ typedef struct PlannerBlock { #if ENABLED(SMOOTH_LIN_ADVANCE) uint32_t cruise_time; // Cruise time in STEP timer counts - float e_step_ratio; + int32_t e_step_ratio_q30; // Ratio of e steps to block steps. + #if ENABLED(INPUT_SHAPING_E_SYNC) + uint32_t xy_length_inv_q30; // inverse of block->steps.x + block.steps.y + #endif #endif #if ANY(S_CURVE_ACCELERATION, SMOOTH_LIN_ADVANCE) uint32_t cruise_rate, // The actual cruise rate to use, between end of the acceleration phase and start of deceleration phase @@ -359,9 +362,8 @@ typedef struct PlannerSettings { #if ENABLED(EDITABLE_STEPS_PER_UNIT) float axis_steps_per_mm[DISTINCT_AXES]; #else - #define _DLIM(I) ALIM(I, _dasu) - #define _DASU(N) _dasu[_DLIM(N)], - #define _EASU(N) _dasu[_DLIM(E_AXIS + N)], + #define _DASU(N) _dasu[ALIM(N, _dasu)], + #define _EASU(N) _dasu[ALIM(E_AXIS + N, _dasu)], static constexpr float axis_steps_per_mm[DISTINCT_AXES] = { REPEAT(NUM_AXES, _DASU) TERN_(HAS_EXTRUDERS, REPEAT(DISTINCT_E, _EASU)) @@ -526,6 +528,23 @@ class Planner { #if ENABLED(LIN_ADVANCE) static float extruder_advance_K[DISTINCT_E]; + static void set_advance_k(const_float_t k, const uint8_t e=active_extruder) { + UNUSED(e); + extruder_advance_K[E_INDEX_N(e)] = k; + #if ENABLED(SMOOTH_LIN_ADVANCE) + extruder_advance_K_q27[E_INDEX_N(e)] = k * (1UL << 27); + #endif + } + static float get_advance_k(const uint8_t e=active_extruder) { + UNUSED(e); + return extruder_advance_K[E_INDEX_N(e)]; + } + #if ENABLED(SMOOTH_LIN_ADVANCE) + static uint32_t get_advance_k_q27(const uint8_t e=active_extruder) { + UNUSED(e); + return extruder_advance_K_q27[E_INDEX_N(e)]; + } + #endif #endif /** @@ -602,6 +621,10 @@ class Planner { volatile static uint32_t block_buffer_runtime_us; // Theoretical block buffer runtime in µs #endif + #if ENABLED(SMOOTH_LIN_ADVANCE) + static uint32_t extruder_advance_K_q27[DISTINCT_E]; + #endif + public: /** diff --git a/Marlin/src/module/settings.cpp b/Marlin/src/module/settings.cpp index 1a46c6cc2a..59cb7244e9 100644 --- a/Marlin/src/module/settings.cpp +++ b/Marlin/src/module/settings.cpp @@ -126,7 +126,7 @@ #endif #if ENABLED(ADVANCE_K_EXTRA) - extern float other_extruder_advance_K[DISTINCT_E]; + extern float other_extruder_advance_K[EXTRUDERS]; #endif #if HAS_MULTI_EXTRUDER @@ -2641,18 +2641,14 @@ void MarlinSettings::postprocess() { _FIELD_TEST(planner_extruder_advance_K); EEPROM_READ(extruder_advance_K); if (!validating) - COPY(planner.extruder_advance_K, extruder_advance_K); + DISTINCT_E_LOOP() planner.set_advance_k(extruder_advance_K[e], e); + #if ENABLED(SMOOTH_LIN_ADVANCE) _FIELD_TEST(stepper_extruder_advance_tau); float tau[DISTINCT_E]; EEPROM_READ(tau); - if (!validating) { - #if ENABLED(DISTINCT_E_FACTORS) - EXTRUDER_LOOP() stepper.set_advance_tau(tau[e], e); - #else - stepper.set_advance_tau(tau[0]); - #endif - } + if (!validating) + DISTINCT_E_LOOP() stepper.set_advance_tau(tau[e], e); #endif } #endif @@ -3615,21 +3611,23 @@ void MarlinSettings::reset() { #if ENABLED(DISTINCT_E_FACTORS) constexpr float linAdvanceK[] = ADVANCE_K; - EXTRUDER_LOOP() { - const float a = linAdvanceK[ALIM(e, linAdvanceK)]; - planner.extruder_advance_K[e] = a; - TERN_(ADVANCE_K_EXTRA, other_extruder_advance_K[e] = a); - } - #else - planner.extruder_advance_K[0] = ADVANCE_K; - #endif - #if ENABLED(SMOOTH_LIN_ADVANCE) - #if ENABLED(DISTINCT_E_FACTORS) + #if ENABLED(SMOOTH_LIN_ADVANCE) constexpr float linAdvanceTau[] = ADVANCE_TAU; - EXTRUDER_LOOP() - stepper.set_advance_tau(linAdvanceTau[ALIM(e, linAdvanceTau)], e); - #else - stepper.set_advance_tau(ADVANCE_TAU); + #endif + + EXTRUDER_LOOP() { + const float k = linAdvanceK[ALIM(e, linAdvanceK)]; + planner.set_advance_k(k, e); + TERN_(SMOOTH_LIN_ADVANCE, stepper.set_advance_tau(linAdvanceTau[ALIM(e, linAdvanceTau)], e)); + TERN_(ADVANCE_K_EXTRA, other_extruder_advance_K[e] = k); + } + + #else // !DISTINCT_E_FACTORS + + planner.set_advance_k(ADVANCE_K); + TERN_(SMOOTH_LIN_ADVANCE, stepper.set_advance_tau(ADVANCE_TAU)); + #if ENABLED(ADVANCE_K_EXTRA) + EXTRUDER_LOOP() other_extruder_advance_K[e] = ADVANCE_K; #endif #endif diff --git a/Marlin/src/module/stepper.cpp b/Marlin/src/module/stepper.cpp index e9f83aa532..04c796acb3 100644 --- a/Marlin/src/module/stepper.cpp +++ b/Marlin/src/module/stepper.cpp @@ -1510,6 +1510,10 @@ HAL_STEP_TIMER_ISR() { #define STEP_MULTIPLY(A,B) MultiU24X32toH16(A, B) #endif +#if ENABLED(SMOOTH_LIN_ADVANCE) + FORCE_INLINE static constexpr int32_t MULT_Q(uint8_t q, int32_t x, int32_t y) { return (int64_t(x) * y) >> q; } +#endif + void Stepper::isr() { static hal_timer_t nextMainISR = 0; // Interval until the next main Stepper Pulse phase (0 = Now) @@ -2877,9 +2881,9 @@ hal_timer_t Stepper::block_phase_isr() { #if ENABLED(SMOOTH_LIN_ADVANCE) - float Stepper::extruder_advance_tau[DISTINCT_E], - Stepper::extruder_advance_tau_ticks[DISTINCT_E], - Stepper::extruder_advance_alpha[DISTINCT_E]; + float Stepper::extruder_advance_tau[DISTINCT_E]; + uint32_t Stepper::extruder_advance_tau_ticks[DISTINCT_E], + Stepper::extruder_advance_alpha_q30[DISTINCT_E]; void Stepper::set_la_interval(const int32_t rate) { if (rate == 0) { @@ -2904,117 +2908,119 @@ hal_timer_t Stepper::block_phase_isr() { constexpr uint16_t IS_COMPENSATION_BUFFER_SIZE = uint16_t(float(SMOOTH_LIN_ADV_HZ) / float(SHAPING_MIN_FREQ) / 2.0f + 0.5f); typedef struct { - xy_float_t buffer[IS_COMPENSATION_BUFFER_SIZE]; + xy_long_t buffer[IS_COMPENSATION_BUFFER_SIZE]; uint16_t index; + FORCE_INLINE void add(const xy_long_t &input) { + buffer[index] = input; + if (++index == IS_COMPENSATION_BUFFER_SIZE) index = 0; + } + FORCE_INLINE xy_long_t past_item(const uint16_t n) { + const int16_t i = int16_t(index) - n; + return buffer[i >= 0 ? i : i + IS_COMPENSATION_BUFFER_SIZE]; + } } DelayBuffer; DelayBuffer delayBuffer; - void add_to_buffer(xy_float_t input) { - delayBuffer.buffer[delayBuffer.index++] = input; - if (delayBuffer.index == IS_COMPENSATION_BUFFER_SIZE) - delayBuffer.index = 0; - } - - xy_float_t lookback(shaping_time_t t /* in stepper timer ticks */) { - constexpr float ADV_TICKS_PER_STEPPER_TICKS = float(SMOOTH_LIN_ADV_HZ) / (STEPPER_TIMER_RATE); - uint32_t delay_steps = t * ADV_TICKS_PER_STEPPER_TICKS + 0.5f; // Convert time to steps - uint16_t past_i; - if (delay_steps>= IS_COMPENSATION_BUFFER_SIZE) { - // this means the buffer is too small. TODO: how to inform user? - past_i = delayBuffer.index; - } - else { - past_i = (delayBuffer.index + IS_COMPENSATION_BUFFER_SIZE - delay_steps) % IS_COMPENSATION_BUFFER_SIZE; - } - return delayBuffer.buffer[past_i]; + xy_long_t smooth_lin_adv_lookback(const shaping_time_t stepper_ticks) { + constexpr uint32_t ADV_TICKS_PER_STEPPER_TICKS_Q30 = (uint64_t(SMOOTH_LIN_ADV_HZ) * _BV32(30)) / STEPPER_TIMER_RATE; + const uint16_t delay_steps = MULT_Q(30, stepper_ticks, ADV_TICKS_PER_STEPPER_TICKS_Q30); + return delayBuffer.past_item(delay_steps); } #endif // INPUT_SHAPING_E_SYNC - float lookahead(uint32_t t) { + int32_t smooth_lin_adv_lookahead(uint32_t stepper_ticks) { for (uint8_t i = 0; block_t *block = planner.get_future_block(i); i++) { if (block->is_sync()) continue; - if (t <= block->acceleration_time) { - if (!block->use_advance_lead) return 0.0f; - uint32_t rate = STEP_MULTIPLY(t, block->acceleration_rate) + block->initial_rate; + if (stepper_ticks <= block->acceleration_time) { + if (!block->use_advance_lead) return 0; + uint32_t rate = STEP_MULTIPLY(stepper_ticks, block->acceleration_rate) + block->initial_rate; NOMORE(rate, block->nominal_rate); - return rate * block->e_step_ratio; + return MULT_Q(30, rate, block->e_step_ratio_q30); } - t -= block->acceleration_time; + stepper_ticks -= block->acceleration_time; - if (t <= block->cruise_time) { - if (!block->use_advance_lead) return 0.0f; - return block->cruise_rate * block->e_step_ratio; + if (stepper_ticks <= block->cruise_time) { + if (!block->use_advance_lead) return 0; + return MULT_Q(30, block->cruise_rate, block->e_step_ratio_q30); } - t -= block->cruise_time; + stepper_ticks -= block->cruise_time; - if (t <= block->deceleration_time) { - if (!block->use_advance_lead) return 0.0f; - uint32_t rate = STEP_MULTIPLY(t, block->acceleration_rate); + if (stepper_ticks <= block->deceleration_time) { + if (!block->use_advance_lead) return 0; + uint32_t rate = STEP_MULTIPLY(stepper_ticks, block->acceleration_rate); if (rate < block->cruise_rate) { rate = block->cruise_rate - rate; NOLESS(rate, block->final_rate); } else rate = block->final_rate; - return rate * block->e_step_ratio; + return MULT_Q(30, rate, block->e_step_ratio_q30); } - t -= block->deceleration_time; + stepper_ticks -= block->deceleration_time; } - return 0.0f; + return 0; } hal_timer_t Stepper::smooth_lin_adv_isr() { - float target_adv_steps = 0; + int32_t target_adv_steps = 0; if (current_block) { - const uint32_t t = extruder_advance_tau_ticks[0] + curr_timer_tick; - target_adv_steps = lookahead(t) * planner.extruder_advance_K[0]; + const uint32_t stepper_ticks = extruder_advance_tau_ticks[E_INDEX_N(active_extruder)] + curr_timer_tick; + target_adv_steps = MULT_Q(27, smooth_lin_adv_lookahead(stepper_ticks), planner.get_advance_k_q27()); } else { curr_step_rate = 0; } - static float last_target_adv_steps = 0; - constexpr float dt_inv = SMOOTH_LIN_ADV_HZ; - float la_step_rate = (target_adv_steps - last_target_adv_steps) * dt_inv; + static int32_t last_target_adv_steps = 0; + constexpr uint16_t dt_inv = SMOOTH_LIN_ADV_HZ; + int32_t la_step_rate = (target_adv_steps - last_target_adv_steps) * dt_inv; last_target_adv_steps = target_adv_steps; - static float smoothed_vals[SMOOTH_LIN_ADV_EXP_ORDER] = {0}; + static int32_t smoothed_vals[SMOOTH_LIN_ADV_EXP_ORDER] = {0}; + for (uint8_t i = 0; i < SMOOTH_LIN_ADV_EXP_ORDER; i++) { // Approximate gaussian smoothing via higher order exponential smoothing - la_step_rate = extruder_advance_alpha[0] * la_step_rate + (1 - extruder_advance_alpha[0]) * smoothed_vals[i]; - smoothed_vals[i] = la_step_rate; + smoothed_vals[i] += MULT_Q(30, la_step_rate - smoothed_vals[i], extruder_advance_alpha_q30[E_INDEX_N(active_extruder)]); + la_step_rate = smoothed_vals[i]; } - const float planned_step_rate = current_block ? curr_step_rate * current_block->e_step_ratio : 0; - float total_step_rate = la_step_rate + planned_step_rate; + + const int32_t planned_step_rate = current_block + ? MULT_Q(30, curr_step_rate, current_block->e_step_ratio_q30) + : 0; + + int32_t total_step_rate = la_step_rate + planned_step_rate; #if ENABLED(INPUT_SHAPING_E_SYNC) - xy_float_t pre_shaping_rate = xy_float_t({0, 0}), - first_pulse_rate = xy_float_t({0, 0}); - float unshaped_rate_e = total_step_rate; + xy_long_t pre_shaping_rate = xy_long_t({0, 0}), + first_pulse_rate = xy_long_t({0, 0}); + int32_t unshaped_rate_e = total_step_rate; if (current_block) { - const float xy_length = TERN0(INPUT_SHAPING_X, current_block->steps.x) + TERN0(INPUT_SHAPING_Y, current_block->steps.y); - if (xy_length > 0) { + if (current_block->xy_length_inv_q30 > 0) { unshaped_rate_e = 0; - pre_shaping_rate = xy_float_t({ - TERN0(INPUT_SHAPING_X, total_step_rate * current_block->steps.x / xy_length), - TERN0(INPUT_SHAPING_Y, total_step_rate * current_block->steps.y / xy_length) + + pre_shaping_rate = xy_long_t({ + TERN0(INPUT_SHAPING_X, MULT_Q(30, total_step_rate * current_block->steps.x, current_block->xy_length_inv_q30)), + TERN0(INPUT_SHAPING_Y, MULT_Q(30, total_step_rate * current_block->steps.y, current_block->xy_length_inv_q30)) }); - first_pulse_rate = xy_float_t({ - TERN0(INPUT_SHAPING_X, pre_shaping_rate.x * Stepper::shaping_x.factor1 / 128.0f), - TERN0(INPUT_SHAPING_Y, pre_shaping_rate.y * Stepper::shaping_y.factor1 / 128.0f) + + first_pulse_rate = xy_long_t({ + TERN0(INPUT_SHAPING_X, (pre_shaping_rate.x * Stepper::shaping_x.factor1) >> 7), + TERN0(INPUT_SHAPING_Y, (pre_shaping_rate.y * Stepper::shaping_y.factor1) >> 7) }); } } - const xy_float_t second_pulse_rate = { - TERN0(INPUT_SHAPING_X, lookback(ShapingQueue::get_delay_x()).x * Stepper::shaping_x.factor2 / 128.0f), - TERN0(INPUT_SHAPING_Y, lookback(ShapingQueue::get_delay_y()).y * Stepper::shaping_y.factor2 / 128.0f) - }; - add_to_buffer(pre_shaping_rate); - const float x = TERN0(INPUT_SHAPING_X, first_pulse_rate.x + second_pulse_rate.x), - y = TERN0(INPUT_SHAPING_Y, first_pulse_rate.y + second_pulse_rate.y); + const xy_long_t second_pulse_rate = { + TERN0(INPUT_SHAPING_X, (smooth_lin_adv_lookback(ShapingQueue::get_delay_x()).x * Stepper::shaping_x.factor2)) >> 7, + TERN0(INPUT_SHAPING_Y, (smooth_lin_adv_lookback(ShapingQueue::get_delay_y()).y * Stepper::shaping_y.factor2)) >> 7 + }; + + delayBuffer.add(pre_shaping_rate); + + const int32_t x = TERN0(INPUT_SHAPING_X, first_pulse_rate.x + second_pulse_rate.x), + y = TERN0(INPUT_SHAPING_Y, first_pulse_rate.y + second_pulse_rate.y); total_step_rate = unshaped_rate_e + x + y; @@ -3025,6 +3031,7 @@ hal_timer_t Stepper::block_phase_isr() { curr_timer_tick += SMOOTH_LIN_ADV_INTERVAL; return SMOOTH_LIN_ADV_INTERVAL; } + #endif // SMOOTH_LIN_ADVANCE // Timer interrupt for E. LA_steps is set in the main routine diff --git a/Marlin/src/module/stepper.h b/Marlin/src/module/stepper.h index 1c06d83351..3fb0b44884 100644 --- a/Marlin/src/module/stepper.h +++ b/Marlin/src/module/stepper.h @@ -352,13 +352,18 @@ class Stepper { #endif #if ENABLED(SMOOTH_LIN_ADVANCE) - static void set_advance_tau(const_float_t tau, const uint8_t e=E_INDEX_N(active_extruder)) { - extruder_advance_tau[e] = tau; - extruder_advance_tau_ticks[e] = tau * (STEPPER_TIMER_RATE); // i.e., <= STEPPER_TIMER_RATE / 2 + static float extruder_advance_tau[DISTINCT_E]; // Smoothing time; also the lookahead time of the smoother + static void set_advance_tau(const_float_t tau, const uint8_t e=active_extruder) { + const uint8_t i = E_INDEX_N(e); + extruder_advance_tau[i] = tau; + extruder_advance_tau_ticks[i] = tau * STEPPER_TIMER_RATE; // α=1−exp(−dt/τ) - extruder_advance_alpha[e] = 1.0f - expf(-(SMOOTH_LIN_ADV_INTERVAL) * (SMOOTH_LIN_ADV_EXP_ORDER) / extruder_advance_tau_ticks[e]); + const float alpha_float = 1.0f - expf(-float(SMOOTH_LIN_ADV_INTERVAL) * (SMOOTH_LIN_ADV_EXP_ORDER) / extruder_advance_tau_ticks[i]); + extruder_advance_alpha_q30[i] = int32_t(alpha_float * _BV32(30)); + } + static float get_advance_tau(const uint8_t e=active_extruder) { + return extruder_advance_tau[E_INDEX_N(e)]; } - static float get_advance_tau(const uint8_t e=E_INDEX_N(active_extruder)) { return extruder_advance_tau[e]; } #endif private: @@ -449,12 +454,11 @@ class Stepper { static hal_timer_t nextAdvanceISR, la_interval; // Interval between ISR calls for LA #if ENABLED(SMOOTH_LIN_ADVANCE) - static uint32_t curr_timer_tick, // Current tick relative to block start - curr_step_rate; // Current motion step rate - static float extruder_advance_tau[DISTINCT_E], // Smoothing time; also the lookahead time of the smoother - extruder_advance_tau_ticks[DISTINCT_E], // Same as extruder_advance_tau but in in stepper timer ticks - extruder_advance_alpha[DISTINCT_E]; // The smoothing factor of each stage of the high-order exponential - // smoothing filter (calculated from tau) + static uint32_t curr_timer_tick, // Current tick relative to block start + curr_step_rate; // Current motion step rate + static uint32_t extruder_advance_tau_ticks[DISTINCT_E], // Same as extruder_advance_tau but in in stepper timer ticks + extruder_advance_alpha_q30[DISTINCT_E]; // The smoothing factor of each stage of the high-order exponential + // smoothing filter (calculated from tau) #else static int32_t la_delta_error, // Analogue of delta_error.e for E steps in LA ISR la_dividend, // Analogue of advance_dividend.e for E steps in LA ISR diff --git a/Marlin/src/module/tool_change.cpp b/Marlin/src/module/tool_change.cpp index fcaa64cefe..980f9327b5 100644 --- a/Marlin/src/module/tool_change.cpp +++ b/Marlin/src/module/tool_change.cpp @@ -1587,7 +1587,7 @@ void tool_change(const uint8_t new_tool, bool no_move/*=false*/) { #endif // Migrate Linear Advance K factor to the new extruder - TERN_(LIN_ADVANCE, planner.extruder_advance_K[active_extruder] = planner.extruder_advance_K[migration_extruder]); + TERN_(LIN_ADVANCE, planner.set_advance_k(planner.get_advance_k(migration_extruder), active_extruder)); // Temporary migration toolchange_settings restored on exit. i.e., before next tool_change(). #if defined(MIGRATION_FS_EXTRA_PRIME) \