diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index a9d26ac920..215f1f8026 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -1150,16 +1150,18 @@ #if ENABLED(FT_MOTION) //#define FTM_IS_DEFAULT_MOTION // Use FT Motion as the factory default? #define FTM_DEFAULT_DYNFREQ_MODE dynFreqMode_DISABLED // Default mode of dynamic frequency calculation. (DISABLED, Z_BASED, MASS_BASED) - #define FTM_DEFAULT_SHAPER_X ftMotionShaper_NONE // Default shaper mode on X axis (NONE, ZV, ZVD, ZVDD, ZVDDD, EI, 2HEI, 3HEI, MZV) - #define FTM_DEFAULT_SHAPER_Y ftMotionShaper_NONE // Default shaper mode on Y axis - #define FTM_SHAPING_DEFAULT_FREQ_X 37.0f // (Hz) Default peak frequency used by input shapers - #define FTM_SHAPING_DEFAULT_FREQ_Y 37.0f // (Hz) Default peak frequency used by input shapers + #define FTM_LINEAR_ADV_DEFAULT_ENA false // Default linear advance enable (true) or disable (false) #define FTM_LINEAR_ADV_DEFAULT_K 0.0f // Default linear advance gain. (Acceleration-based scaling factor.) - #define FTM_SHAPING_ZETA_X 0.1f // Zeta used by input shapers for X axis - #define FTM_SHAPING_ZETA_Y 0.1f // Zeta used by input shapers for Y axis + #define FTM_DEFAULT_SHAPER_X ftMotionShaper_NONE // Default shaper mode on X axis (NONE, ZV, ZVD, ZVDD, ZVDDD, EI, 2HEI, 3HEI, MZV) + #define FTM_SHAPING_DEFAULT_FREQ_X 37.0f // (Hz) Default peak frequency used by input shapers + #define FTM_SHAPING_ZETA_X 0.1f // Zeta used by input shapers for X axis #define FTM_SHAPING_V_TOL_X 0.05f // Vibration tolerance used by EI input shapers for X axis + + #define FTM_DEFAULT_SHAPER_Y ftMotionShaper_NONE // Default shaper mode on Y axis + #define FTM_SHAPING_DEFAULT_FREQ_Y 37.0f // (Hz) Default peak frequency used by input shapers + #define FTM_SHAPING_ZETA_Y 0.1f // Zeta used by input shapers for Y axis #define FTM_SHAPING_V_TOL_Y 0.05f // Vibration tolerance used by EI input shapers for Y axis //#define FT_MOTION_MENU // Provide a MarlinUI menu to set M493 parameters @@ -1192,7 +1194,6 @@ #endif #define FTM_STEPS_PER_UNIT_TIME (FTM_STEPPER_FS / FTM_FS) // Interpolated stepper commands per unit time - #define FTM_CTS_COMPARE_VAL (FTM_STEPS_PER_UNIT_TIME / 2) // Comparison value used in interpolation algorithm #define FTM_MIN_TICKS ((STEPPER_TIMER_RATE) / (FTM_STEPPER_FS)) // Minimum stepper ticks between steps #define FTM_MIN_SHAPE_FREQ 10 // Minimum shaping frequency diff --git a/Marlin/Version.h b/Marlin/Version.h index 75a1397d0d..c6b0482653 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-09-09" +//#define STRING_DISTRIBUTION_DATE "2025-09-15" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/HAL/NATIVE_SIM/u8g/u8g_com_st7920_sw_spi.cpp b/Marlin/src/HAL/NATIVE_SIM/u8g/u8g_com_st7920_sw_spi.cpp index 46f2798afa..b07bc1644d 100644 --- a/Marlin/src/HAL/NATIVE_SIM/u8g/u8g_com_st7920_sw_spi.cpp +++ b/Marlin/src/HAL/NATIVE_SIM/u8g/u8g_com_st7920_sw_spi.cpp @@ -71,13 +71,13 @@ static uint8_t SPI_speed = 0; static uint8_t swSpiTransfer(uint8_t b, const uint8_t spi_speed, const pin_t sck_pin, const pin_t miso_pin, const pin_t mosi_pin) { for (uint8_t i = 0; i < 8; i++) { - WRITE_PIN(mosi_pin, !!(b & 0x80)); + WRITE_PIN(sck_pin, TERN(U8G_SPI_USE_MODE_3, LOW, HIGH)); DELAY_CYCLES(SPI_SPEED); - WRITE_PIN(sck_pin, HIGH); + WRITE_PIN(mosi_pin, !!(b & 0x80)); DELAY_CYCLES(SPI_SPEED); b <<= 1; if (miso_pin >= 0 && READ_PIN(miso_pin)) b |= 1; - WRITE_PIN(sck_pin, LOW); + WRITE_PIN(sck_pin, TERN(U8G_SPI_USE_MODE_3, HIGH, LOW)); DELAY_CYCLES(SPI_SPEED); } return b; @@ -85,7 +85,7 @@ static uint8_t swSpiTransfer(uint8_t b, const uint8_t spi_speed, const pin_t sck static uint8_t swSpiInit(const uint8_t spiRate, const pin_t sck_pin, const pin_t mosi_pin) { WRITE_PIN(mosi_pin, HIGH); - WRITE_PIN(sck_pin, LOW); + WRITE_PIN(sck_pin, TERN(U8G_SPI_USE_MODE_3, HIGH, LOW)); return spiRate; } @@ -93,11 +93,11 @@ static void u8g_com_st7920_write_byte_sw_spi(uint8_t rs, uint8_t val) { static uint8_t rs_last_state = 255; if (rs != rs_last_state) { // Transfer Data (FA) or Command (F8) - swSpiTransfer(rs ? 0x0FA : 0x0F8, SPI_speed, SCK_pin_ST7920_HAL, -1, MOSI_pin_ST7920_HAL_HAL); + swSpiTransfer(rs ? 0xFA : 0xF8, SPI_speed, SCK_pin_ST7920_HAL, -1, MOSI_pin_ST7920_HAL_HAL); rs_last_state = rs; DELAY_US(40); // Give the controller time to process the data: 20 is bad, 30 is OK, 40 is safe } - swSpiTransfer(val & 0x0F0, SPI_speed, SCK_pin_ST7920_HAL, -1, MOSI_pin_ST7920_HAL_HAL); + swSpiTransfer(val & 0xF0, SPI_speed, SCK_pin_ST7920_HAL, -1, MOSI_pin_ST7920_HAL_HAL); swSpiTransfer(val << 4, SPI_speed, SCK_pin_ST7920_HAL, -1, MOSI_pin_ST7920_HAL_HAL); } @@ -169,5 +169,32 @@ uint8_t u8g_com_ST7920_sw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void } #endif +#if ENABLED(LIGHTWEIGHT_UI) + + #define ST7920_CS() { WRITE(LCD_PINS_RS, HIGH); } + #define ST7920_NCS() { WRITE(LCD_PINS_RS, LOW); } + #define ST7920_SET_CMD() { ST7920_SWSPI_SND_8BIT(0xF8); } + #define ST7920_SET_DAT() { ST7920_SWSPI_SND_8BIT(0xFA); } + #define ST7920_WRITE_BYTE(a) { ST7920_SWSPI_SND_8BIT((uint8_t)((a)&0xF0u)); ST7920_SWSPI_SND_8BIT((uint8_t)((a)<<4U)); } + + #define ST7920_DAT(V) !!((V) & 0x80) + + #define ST7920_SND_BIT(...) do{ \ + WRITE(LCD_PINS_D4, LOW); \ + WRITE(LCD_PINS_EN, ST7920_DAT(val)); \ + WRITE(LCD_PINS_D4, HIGH); \ + val <<= 1; }while(0); + + void ST7920_SWSPI_SND_8BIT(uint8_t val) { + REPEAT(8, ST7920_SND_BIT); + } + + void ST7920_cs() { ST7920_CS(); } + void ST7920_ncs() { ST7920_NCS(); } + void ST7920_set_cmd() { ST7920_SET_CMD(); } + void ST7920_set_dat() { ST7920_SET_DAT(); } + void ST7920_write_byte(const uint8_t val) { ST7920_WRITE_BYTE(val); } +#endif // LIGHTWEIGHT_UI + #endif // IS_U8GLIB_ST7920 #endif // __PLAT_NATIVE_SIM__ diff --git a/Marlin/src/HAL/NATIVE_SIM/u8g/u8g_com_sw_spi.cpp b/Marlin/src/HAL/NATIVE_SIM/u8g/u8g_com_sw_spi.cpp index f984983b40..fd11e5d767 100644 --- a/Marlin/src/HAL/NATIVE_SIM/u8g/u8g_com_sw_spi.cpp +++ b/Marlin/src/HAL/NATIVE_SIM/u8g/u8g_com_sw_spi.cpp @@ -127,7 +127,7 @@ uint8_t swSpiTransfer_mode_3(uint8_t b, const uint8_t spi_speed, const pin_t sck static uint8_t SPI_speed = 0; static uint8_t swSpiInit(const uint8_t spi_speed, const uint8_t clk_pin, const uint8_t mosi_pin) { - return spi_speed; + return spi_speed; } static void u8g_sw_spi_shift_out(uint8_t dataPin, uint8_t clockPin, uint8_t val) { diff --git a/Marlin/src/feature/tmc_util.cpp b/Marlin/src/feature/tmc_util.cpp index 379ba8d0bf..06ee4c9e93 100644 --- a/Marlin/src/feature/tmc_util.cpp +++ b/Marlin/src/feature/tmc_util.cpp @@ -89,7 +89,9 @@ #if HAS_TMCX1X0 - static uint32_t get_pwm_scale(TMC2130Stepper &st) { return st.PWM_SCALE(); } + #if ENABLED(TMC_DEBUG) + static uint32_t get_pwm_scale(TMC2130Stepper &st) { return st.PWM_SCALE(); } + #endif static TMC_driver_data get_driver_data(TMC2130Stepper &st) { constexpr uint8_t OT_bp = 25, OTPW_bp = 26; @@ -148,7 +150,9 @@ #if HAS_DRIVER(TMC2240) - static uint32_t get_pwm_scale(TMC2240Stepper &st) { return st.PWM_SCALE(); } + #if ENABLED(TMC_DEBUG) + static uint32_t get_pwm_scale(TMC2240Stepper &st) { return st.PWM_SCALE(); } + #endif static TMC_driver_data get_driver_data(TMC2240Stepper &st) { constexpr uint8_t OT_bp = 25, OTPW_bp = 26; @@ -207,7 +211,9 @@ #if HAS_TMC220x - static uint32_t get_pwm_scale(TMC2208Stepper &st) { return st.pwm_scale_sum(); } + #if ENABLED(TMC_DEBUG) + static uint32_t get_pwm_scale(TMC2208Stepper &st) { return st.pwm_scale_sum(); } + #endif static TMC_driver_data get_driver_data(TMC2208Stepper &st) { constexpr uint8_t OTPW_bp = 0, OT_bp = 1; @@ -242,7 +248,9 @@ #if HAS_DRIVER(TMC2660) - static uint32_t get_pwm_scale(TMC2660Stepper) { return 0; } + #if ENABLED(TMC_DEBUG) + static uint32_t get_pwm_scale(TMC2660Stepper) { return 0; } + #endif static TMC_driver_data get_driver_data(TMC2660Stepper &st) { constexpr uint8_t OT_bp = 1, OTPW_bp = 2; diff --git a/Marlin/src/gcode/feature/ft_motion/M493.cpp b/Marlin/src/gcode/feature/ft_motion/M493.cpp index d5cfc82005..fe57de6ac8 100644 --- a/Marlin/src/gcode/feature/ft_motion/M493.cpp +++ b/Marlin/src/gcode/feature/ft_motion/M493.cpp @@ -61,13 +61,13 @@ void say_shaping() { // FT Shaping #if HAS_X_AXIS - if (AXIS_HAS_SHAPER(X)) { + if (AXIS_IS_SHAPING(X)) { SERIAL_ECHOPGM(" with " AXIS_0_NAME); say_shaper_type(X_AXIS); } #endif #if HAS_Y_AXIS - if (AXIS_HAS_SHAPER(Y)) { + if (AXIS_IS_SHAPING(Y)) { SERIAL_ECHOPGM(" and with " AXIS_1_NAME); say_shaper_type(Y_AXIS); } @@ -80,7 +80,7 @@ void say_shaping() { dynamic = z_based || g_based; // FT Dynamic Frequency Mode - if (AXIS_HAS_SHAPER(X) || AXIS_HAS_SHAPER(Y)) { + if (AXIS_IS_SHAPING(X) || AXIS_IS_SHAPING(Y)) { #if HAS_DYNAMIC_FREQ SERIAL_ECHOPGM("Dynamic Frequency Mode "); switch (ftMotion.cfg.dynFreqMode) { @@ -263,7 +263,7 @@ void GcodeSuite::M493() { // Dynamic frequency mode parameter. if (parser.seenval('D')) { - if (AXIS_HAS_SHAPER(X) || AXIS_HAS_SHAPER(Y)) { + if (AXIS_IS_SHAPING(X) || AXIS_IS_SHAPING(Y)) { const dynFreqMode_t val = dynFreqMode_t(parser.value_byte()); switch (val) { #if HAS_DYNAMIC_FREQ_MM @@ -297,7 +297,7 @@ void GcodeSuite::M493() { // Parse frequency parameter (X axis). if (parser.seenval('A')) { - if (AXIS_HAS_SHAPER(X)) { + if (AXIS_IS_SHAPING(X)) { const float val = parser.value_float(); // TODO: Frequency minimum is dependent on the shaper used; the above check isn't always correct. if (WITHIN(val, FTM_MIN_SHAPE_FREQ, (FTM_FS) / 2)) { @@ -326,7 +326,7 @@ void GcodeSuite::M493() { // Parse zeta parameter (X axis). if (parser.seenval('I')) { const float val = parser.value_float(); - if (AXIS_HAS_SHAPER(X)) { + if (AXIS_IS_SHAPING(X)) { if (WITHIN(val, 0.01f, 1.0f)) { ftMotion.cfg.zeta[0] = val; flag.update = true; @@ -341,7 +341,7 @@ void GcodeSuite::M493() { // Parse vtol parameter (X axis). if (parser.seenval('Q')) { const float val = parser.value_float(); - if (AXIS_HAS_EISHAPER(X)) { + if (AXIS_IS_EISHAPING(X)) { if (WITHIN(val, 0.00f, 1.0f)) { ftMotion.cfg.vtol[0] = val; flag.update = true; @@ -359,7 +359,7 @@ void GcodeSuite::M493() { // Parse frequency parameter (Y axis). if (parser.seenval('B')) { - if (AXIS_HAS_SHAPER(Y)) { + if (AXIS_IS_SHAPING(Y)) { const float val = parser.value_float(); if (WITHIN(val, FTM_MIN_SHAPE_FREQ, (FTM_FS) / 2)) { ftMotion.cfg.baseFreq.y = val; @@ -387,7 +387,7 @@ void GcodeSuite::M493() { // Parse zeta parameter (Y axis). if (parser.seenval('J')) { const float val = parser.value_float(); - if (AXIS_HAS_SHAPER(Y)) { + if (AXIS_IS_SHAPING(Y)) { if (WITHIN(val, 0.01f, 1.0f)) { ftMotion.cfg.zeta[1] = val; flag.update = true; @@ -402,7 +402,7 @@ void GcodeSuite::M493() { // Parse vtol parameter (Y axis). if (parser.seenval('R')) { const float val = parser.value_float(); - if (AXIS_HAS_EISHAPER(Y)) { + if (AXIS_IS_EISHAPING(Y)) { if (WITHIN(val, 0.00f, 1.0f)) { ftMotion.cfg.vtol[1] = val; flag.update = true; diff --git a/Marlin/src/gcode/feature/trinamic/M920.cpp b/Marlin/src/gcode/feature/trinamic/M920.cpp index f123c41622..4c777a83cc 100644 --- a/Marlin/src/gcode/feature/trinamic/M920.cpp +++ b/Marlin/src/gcode/feature/trinamic/M920.cpp @@ -95,15 +95,16 @@ void GcodeSuite::M920() { void GcodeSuite::M920_report(const bool forReplay/*=true*/) { TERN_(MARLIN_SMALL_BUILD, return); - report_heading(forReplay, F(STR_HOMING_CURRENT)); - - auto say_M920 = [](const bool forReplay, int8_t index=-1) { - report_echo_start(forReplay); - SERIAL_ECHOPGM(" M920"); - if (index >= 0) SERIAL_ECHOPGM(" " I_PARAM_STR, index); - }; - #if X_SENSORLESS || Y_SENSORLESS || Z_SENSORLESS + + report_heading(forReplay, F(STR_HOMING_CURRENT)); + + auto say_M920 = [](const bool forReplay, int8_t index=-1) { + report_echo_start(forReplay); + SERIAL_ECHOPGM(" M920"); + if (index >= 0) SERIAL_ECHOPGM(" " I_PARAM_STR, index); + }; + #if X2_SENSORLESS || Y2_SENSORLESS || Z2_SENSORLESS || Z3_SENSORLESS || Z4_SENSORLESS say_M920(forReplay, 0); #else @@ -123,23 +124,26 @@ void GcodeSuite::M920_report(const bool forReplay/*=true*/) { TERN_(V_SENSORLESS, SERIAL_ECHOPGM_P(SP_V_STR, homing_current_mA.V)); TERN_(W_SENSORLESS, SERIAL_ECHOPGM_P(SP_W_STR, homing_current_mA.W)); SERIAL_EOL(); - #endif - #if X2_SENSORLESS || Y2_SENSORLESS || Z2_SENSORLESS - say_M920(forReplay, 1); - TERN_(X2_SENSORLESS, SERIAL_ECHOPGM_P(SP_X_STR, homing_current_mA.X2)); - TERN_(Y2_SENSORLESS, SERIAL_ECHOPGM_P(SP_Y_STR, homing_current_mA.Y2)); - TERN_(Z2_SENSORLESS, SERIAL_ECHOPGM_P(SP_Z_STR, homing_current_mA.Z2)); - SERIAL_EOL(); - #endif - #if Z3_SENSORLESS - say_M920(forReplay, 2); - SERIAL_ECHOLNPGM(" Z", homing_current_mA.Z3); - #endif - #if Z4_SENSORLESS - say_M920(forReplay, 3); - SERIAL_ECHOLNPGM(" Z", homing_current_mA.Z4); - #endif + #if X2_SENSORLESS || Y2_SENSORLESS || Z2_SENSORLESS + say_M920(forReplay, 1); + TERN_(X2_SENSORLESS, SERIAL_ECHOPGM_P(SP_X_STR, homing_current_mA.X2)); + TERN_(Y2_SENSORLESS, SERIAL_ECHOPGM_P(SP_Y_STR, homing_current_mA.Y2)); + TERN_(Z2_SENSORLESS, SERIAL_ECHOPGM_P(SP_Z_STR, homing_current_mA.Z2)); + SERIAL_EOL(); + #endif + + #if Z3_SENSORLESS + say_M920(forReplay, 2); + SERIAL_ECHOLNPGM(" Z", homing_current_mA.Z3); + #endif + + #if Z4_SENSORLESS + say_M920(forReplay, 3); + SERIAL_ECHOLNPGM(" Z", homing_current_mA.Z4); + #endif + + #endif // X_SENSORLESS || Y_SENSORLESS || Z_SENSORLESS } #endif // EDITABLE_HOMING_CURRENT diff --git a/Marlin/src/inc/Conditionals-2-LCD.h b/Marlin/src/inc/Conditionals-2-LCD.h index 7d9f3c6250..0d8ca3510f 100644 --- a/Marlin/src/inc/Conditionals-2-LCD.h +++ b/Marlin/src/inc/Conditionals-2-LCD.h @@ -308,10 +308,6 @@ #endif -#if ANY(FYSETC_MINI_12864, MKS_MINI_12864) - #define U8G_SPI_USE_MODE_3 1 -#endif - // ST7920-based graphical displays #if ANY(IS_RRD_FG_SC, LCD_FOR_MELZI, SILVER_GATE_GLCD_CONTROLLER) #define DOGLCD @@ -319,6 +315,10 @@ #define IS_RRD_SC 1 #endif +#if ANY(FYSETC_MINI_12864, MKS_MINI_12864) || ALL(__PLAT_NATIVE_SIM__, IS_U8GLIB_ST7920) + #define U8G_SPI_USE_MODE_3 1 +#endif + // ST7565 / 64128N graphical displays #if ANY(MAKRPANEL, MINIPANEL) #define IS_ULTIPANEL 1 diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 116e85e811..aaa6432847 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-09-09" + #define STRING_DISTRIBUTION_DATE "2025-09-15" #endif /** diff --git a/Marlin/src/lcd/dogm/status_screen_lite_ST7920.cpp b/Marlin/src/lcd/dogm/status_screen_lite_ST7920.cpp index a9e8bb5646..703c18515a 100644 --- a/Marlin/src/lcd/dogm/status_screen_lite_ST7920.cpp +++ b/Marlin/src/lcd/dogm/status_screen_lite_ST7920.cpp @@ -478,13 +478,7 @@ void ST7920_Lite_Status_Screen::draw_fan_icon(const bool whichIcon) { } void ST7920_Lite_Status_Screen::draw_heat_icon(const bool whichIcon, const bool heating) { - set_ddram_address( - #if HOTENDS == 1 - DDRAM_LINE_2 - #else - DDRAM_LINE_3 - #endif - ); + set_ddram_address((HOTENDS < 2) ? DDRAM_LINE_2 : DDRAM_LINE_3); begin_data(); if (heating) write_word(whichIcon ? CGRAM_ICON_1_WORD : CGRAM_ICON_2_WORD); @@ -920,7 +914,7 @@ void ST7920_Lite_Status_Screen::update(const bool forceUpdate) { cs(); update_indicators(forceUpdate); update_status_or_position(forceUpdate); - update_progress(forceUpdate); + TERN_(HAS_PRINT_PROGRESS, update_progress(forceUpdate)); ncs(); } diff --git a/Marlin/src/lcd/dogm/status_screen_lite_ST7920.h b/Marlin/src/lcd/dogm/status_screen_lite_ST7920.h index e096825f8a..ac47da8ee8 100644 --- a/Marlin/src/lcd/dogm/status_screen_lite_ST7920.h +++ b/Marlin/src/lcd/dogm/status_screen_lite_ST7920.h @@ -31,7 +31,7 @@ class ST7920_Lite_Status_Screen { } current_bits; static void cs() { ST7920_cs(); current_bits.synced = false; } - static void ncs() { ST7920_cs(); current_bits.synced = false; } + static void ncs() { ST7920_ncs(); current_bits.synced = false; } static void sync_cmd() { ST7920_set_cmd(); } static void sync_dat() { ST7920_set_dat(); } static void write_byte(const uint8_t w) { ST7920_write_byte(w); } diff --git a/Marlin/src/lcd/dogm/u8g/ultralcd_st7920_u8glib_rrd_AVR.cpp b/Marlin/src/lcd/dogm/u8g/ultralcd_st7920_u8glib_rrd_AVR.cpp index f7b50741ac..32911b5bf1 100644 --- a/Marlin/src/lcd/dogm/u8g/ultralcd_st7920_u8glib_rrd_AVR.cpp +++ b/Marlin/src/lcd/dogm/u8g/ultralcd_st7920_u8glib_rrd_AVR.cpp @@ -91,24 +91,17 @@ #define ST7920_DAT(V) ((V) & 0x80) #endif -#define ST7920_SND_BIT do{ \ +#define ST7920_SND_BIT(...) do{ \ WRITE(ST7920_CLK_PIN, LOW); ST7920_DELAY_1; \ WRITE(ST7920_DAT_PIN, ST7920_DAT(val)); ST7920_DELAY_2; \ WRITE(ST7920_CLK_PIN, HIGH); ST7920_DELAY_3; \ - val <<= 1; }while(0) + val <<= 1; }while(0); // Optimize this code with -O3 #pragma GCC optimize (3) void ST7920_SWSPI_SND_8BIT(uint8_t val) { - ST7920_SND_BIT; // 1 - ST7920_SND_BIT; // 2 - ST7920_SND_BIT; // 3 - ST7920_SND_BIT; // 4 - ST7920_SND_BIT; // 5 - ST7920_SND_BIT; // 6 - ST7920_SND_BIT; // 7 - ST7920_SND_BIT; // 8 + REPEAT(8, ST7920_SND_BIT); } uint8_t u8g_dev_rrd_st7920_128x64_fn(u8g_t *u8g, u8g_dev_t *dev, uint8_t msg, void *arg) { diff --git a/Marlin/src/lcd/menu/menu_motion.cpp b/Marlin/src/lcd/menu/menu_motion.cpp index 956b58c633..3aded6ed72 100644 --- a/Marlin/src/lcd/menu/menu_motion.cpp +++ b/Marlin/src/lcd/menu/menu_motion.cpp @@ -312,7 +312,7 @@ void menu_move() { #include "../../module/ft_motion.h" - FSTR_P get_shaper_name(const AxisEnum axis=X_AXIS) { + FSTR_P get_shaper_name(const AxisEnum axis) { switch (ftMotion.cfg.shaper[axis]) { default: return nullptr; case ftMotionShaper_NONE: return GET_TEXT_F(MSG_LCD_OFF); @@ -457,20 +457,20 @@ void menu_move() { #if HAS_X_AXIS SUBMENU_N_S(X_AXIS, _shaper_name(X_AXIS), MSG_FTM_CMPN_MODE, menu_ftm_shaper_x); - if (AXIS_HAS_SHAPER(X)) { + if (AXIS_IS_SHAPING(X)) { EDIT_ITEM_FAST_N(float42_52, X_AXIS, MSG_FTM_BASE_FREQ_N, &c.baseFreq.x, FTM_MIN_SHAPE_FREQ, (FTM_FS) / 2, ftMotion.update_shaping_params); EDIT_ITEM_FAST_N(float42_52, X_AXIS, MSG_FTM_ZETA_N, &c.zeta.x, 0.0f, 1.0f, ftMotion.update_shaping_params); - if (AXIS_HAS_EISHAPER(X)) + if (AXIS_IS_EISHAPING(X)) EDIT_ITEM_FAST_N(float42_52, X_AXIS, MSG_FTM_VTOL_N, &c.vtol.x, 0.0f, 1.0f, ftMotion.update_shaping_params); } #endif #if HAS_Y_AXIS SUBMENU_N_S(Y_AXIS, _shaper_name(Y_AXIS), MSG_FTM_CMPN_MODE, menu_ftm_shaper_y); - if (AXIS_HAS_SHAPER(Y)) { + if (AXIS_IS_SHAPING(Y)) { EDIT_ITEM_FAST_N(float42_52, Y_AXIS, MSG_FTM_BASE_FREQ_N, &c.baseFreq.y, FTM_MIN_SHAPE_FREQ, (FTM_FS) / 2, ftMotion.update_shaping_params); EDIT_ITEM_FAST_N(float42_52, Y_AXIS, MSG_FTM_ZETA_N, &c.zeta.y, 0.0f, 1.0f, ftMotion.update_shaping_params); - if (AXIS_HAS_EISHAPER(Y)) + if (AXIS_IS_EISHAPING(Y)) EDIT_ITEM_FAST_N(float42_52, Y_AXIS, MSG_FTM_VTOL_N, &c.vtol.y, 0.0f, 1.0f, ftMotion.update_shaping_params); } #endif diff --git a/Marlin/src/module/ft_motion.cpp b/Marlin/src/module/ft_motion.cpp index d5865913ab..e819a0cdfc 100644 --- a/Marlin/src/module/ft_motion.cpp +++ b/Marlin/src/module/ft_motion.cpp @@ -53,15 +53,14 @@ AxisBits FTMotion::axis_move_dir; xyze_trajectory_t FTMotion::traj; // = {0.0f} Storage for fixed-time-based trajectory. xyze_trajectoryMod_t FTMotion::trajMod; // = {0.0f} Storage for fixed time trajectory window. -bool FTMotion::blockProcRdy = false; // Set when new block data is loaded from stepper module into FTM, ... - // ... and reset when block is completely converted to FTM trajectory. -bool FTMotion::batchRdy = false; // Indicates a batch of the fixed time trajectory... - // ... has been generated, is now available in the upper - - // batch of traj.x[], y, z ... e vectors, and is ready to be - // post processed, if applicable, then interpolated. Reset when the - // data has been shifted out. -bool FTMotion::batchRdyForInterp = false; // Indicates the batch is done being post processed... - // ... if applicable, and is ready to be converted to step commands. +bool FTMotion::blockProcRdy = false; // Set when new block data is loaded from stepper module into FTM, + // and reset when block is completely converted to FTM trajectory. +bool FTMotion::batchRdy = false; // Indicates a batch of the fixed time trajectory has been + // generated, is now available in the upper-batch of traj.A[], and + // is ready to be post-processed (if applicable) and interpolated. + // Reset once the data has been shifted out. +bool FTMotion::batchRdyForInterp = false; // Indicates the batch is done being post processed + // (if applicable) and is ready to be converted to step commands. // Trapezoid data variables. xyze_pos_t FTMotion::startPos, // (mm) Start position of block @@ -81,11 +80,12 @@ uint32_t FTMotion::N1, // Number of data points in the uint32_t FTMotion::max_intervals; // Total number of data points that will be generated from block. // Make vector variables. -uint32_t FTMotion::makeVector_idx = 0, // Index of fixed time trajectory generation of the overall block. - FTMotion::makeVector_batchIdx = 0; // Index of fixed time trajectory generation within the batch. +uint32_t FTMotion::traj_idx_get = 0, // Index of fixed time trajectory generation of the overall block. + FTMotion::traj_idx_set = 0; // Index of fixed time trajectory generation within the batch. // Interpolation variables. xyze_long_t FTMotion::steps = { 0 }; // Step count accumulator. +xyze_long_t FTMotion::step_error_q10 = { 0 }; // Fractional remainder in q10.21 format uint32_t FTMotion::interpIdx = 0; // Index of current data point being interpolated. @@ -170,14 +170,14 @@ void FTMotion::loop() { if (blockProcRdy) { - if (!batchRdy) makeVector(); // may clear blockProcRdy + if (!batchRdy) generateTrajectoryPointsFromBlock(); // may clear blockProcRdy // Check if the block has been completely converted: if (!blockProcRdy) { discard_planner_block_protected(); if (!batchRdy && !planner.has_blocks_queued()) { runoutBlock(); - makeVector(); // Additional call to guarantee batchRdy is set this loop. + generateTrajectoryPointsFromBlock(); // Additional call to guarantee batchRdy is set this loop. } } } @@ -202,13 +202,13 @@ void FTMotion::loop() { // ... data is ready in trajMod. batchRdyForInterp = true; - batchRdy = false; // Clear so makeVector() can resume generating points. + batchRdy = false; // Clear so generateTrajectoryPointsFromBlock() can resume generating points. } // Interpolation (generation of step commands from fixed time trajectory). while (batchRdyForInterp && (stepperCmdBuffItems() < (FTM_STEPPERCMD_BUFF_SIZE) - (FTM_STEPS_PER_UNIT_TIME))) { - convertToSteps(interpIdx); + generateStepsFromTrajectory(interpIdx); if (++interpIdx == FTM_BATCH_SIZE) { batchRdyForInterp = false; interpIdx = 0; @@ -269,11 +269,8 @@ void FTMotion::loop() { Ai[2] = Ai[0] * K2; const float adj = 1.0f / (Ai[0] + Ai[1] + Ai[2]); - for (uint32_t i = 0U; i < 3U; i++) { - Ai[i] *= adj; - } - } - break; + for (uint32_t i = 0; i < 3U; i++) Ai[i] *= adj; + } break; case ftMotionShaper_2HEI: { max_i = 3U; @@ -285,11 +282,8 @@ void FTMotion::loop() { Ai[3] = Ai[0] * K3; const float adj = 1.0f / (Ai[0] + Ai[1] + Ai[2] + Ai[3]); - for (uint32_t i = 0U; i < 4U; i++) { - Ai[i] *= adj; - } - } - break; + for (uint32_t i = 0; i < 4U; i++) Ai[i] *= adj; + } break; case ftMotionShaper_3HEI: { max_i = 4U; @@ -300,11 +294,8 @@ void FTMotion::loop() { Ai[4] = Ai[0] * K4; const float adj = 1.0f / (Ai[0] + Ai[1] + Ai[2] + Ai[3] + Ai[4]); - for (uint32_t i = 0U; i < 5U; i++) { - Ai[i] *= adj; - } - } - break; + for (uint32_t i = 0; i < 5U; i++) Ai[i] *= adj; + } break; case ftMotionShaper_MZV: { max_i = 2U; @@ -358,13 +349,13 @@ void FTMotion::loop() { void FTMotion::update_shaping_params() { #if HAS_X_AXIS - if ((shaping.x.ena = AXIS_HAS_SHAPER(X))) { + if ((shaping.x.ena = AXIS_IS_SHAPING(X))) { shaping.x.set_axis_shaping_A(cfg.shaper.x, cfg.zeta.x, cfg.vtol.x); shaping.x.set_axis_shaping_N(cfg.shaper.x, cfg.baseFreq.x, cfg.zeta.x); } #endif #if HAS_Y_AXIS - if ((shaping.y.ena = AXIS_HAS_SHAPER(Y))) { + if ((shaping.y.ena = AXIS_IS_SHAPING(Y))) { shaping.y.set_axis_shaping_A(cfg.shaper.y, cfg.zeta.y, cfg.vtol.y); shaping.y.set_axis_shaping_N(cfg.shaper.y, cfg.baseFreq.y, cfg.zeta.y); } @@ -384,10 +375,11 @@ void FTMotion::reset() { endPos_prevBlock.reset(); - makeVector_idx = 0; - makeVector_batchIdx = TERN(FTM_UNIFIED_BWS, 0, _MIN(BATCH_SIDX_IN_WINDOW, FTM_BATCH_SIZE)); + traj_idx_get = 0; + traj_idx_set = TERN(FTM_UNIFIED_BWS, 0, _MIN(BATCH_SIDX_IN_WINDOW, FTM_BATCH_SIZE)); steps.reset(); + step_error_q10.reset(); interpIdx = 0; #if HAS_FTM_SHAPING @@ -429,7 +421,7 @@ void FTMotion::runoutBlock() { startPos = endPos_prevBlock; ratio.reset(); - const int32_t n_to_fill_batch = (FTM_WINDOW_SIZE) - makeVector_batchIdx; + const int32_t n_to_fill_batch = (FTM_WINDOW_SIZE) - traj_idx_set; // This line or function is to be modified for FBS use; do not optimize out. const int32_t n_to_settle_shaper = num_samples_shaper_settle(); @@ -463,9 +455,7 @@ void FTMotion::loadBlockData(block_t * const current_block) { oneOverLength = 1.0f / totalLength; startPos = endPos_prevBlock; - const xyze_pos_t& moveDist = current_block->dist_mm; - ratio = moveDist * oneOverLength; const float spm = totalLength / current_block->step_event_count; // (steps/mm) Distance for each step @@ -563,20 +553,20 @@ void FTMotion::loadBlockData(block_t * const current_block) { } // Generate data points of the trajectory. -void FTMotion::makeVector() { +void FTMotion::generateTrajectoryPointsFromBlock() { do { - float tau = (makeVector_idx + 1) * (FTM_TS); // (s) Time since start of block + float tau = (traj_idx_get + 1) * (FTM_TS); // (s) Time since start of block float dist = 0.0f; // (mm) Distance traveled #if HAS_EXTRUDERS float accel_k = 0.0f; // (mm/s^2) Acceleration K factor #endif - if (makeVector_idx < N1) { + if (traj_idx_get < N1) { // Acceleration phase dist = (f_s * tau) + (0.5f * accel_P * sq(tau)); // (mm) Distance traveled for acceleration phase since start of block TERN_(HAS_EXTRUDERS, accel_k = accel_P); // (mm/s^2) Acceleration K factor from Accel phase } - else if (makeVector_idx < (N1 + N2)) { + else if (traj_idx_get < (N1 + N2)) { // Coasting phase dist = s_1e + F_P * (tau - N1 * (FTM_TS)); // (mm) Distance traveled for coasting phase since start of block //TERN_(HAS_EXTRUDERS, accel_k = 0.0f); @@ -588,17 +578,17 @@ void FTMotion::makeVector() { TERN_(HAS_EXTRUDERS, accel_k = decel_P); // (mm/s^2) Acceleration K factor from Decel phase } - #define _SET_TRAJ(q) traj.q[makeVector_batchIdx] = startPos.q + ratio.q * dist; + #define _SET_TRAJ(q) traj.q[traj_idx_set] = startPos.q + ratio.q * dist; LOGICAL_AXIS_MAP_LC(_SET_TRAJ); #if HAS_EXTRUDERS if (cfg.linearAdvEna) { - float dedt_adj = (traj.e[makeVector_batchIdx] - e_raw_z1) * (FTM_FS); + float dedt_adj = (traj.e[traj_idx_set] - e_raw_z1) * (FTM_FS); if (ratio.e > 0.0f) dedt_adj += accel_k * cfg.linearAdvK * 0.0001f; - e_raw_z1 = traj.e[makeVector_batchIdx]; + e_raw_z1 = traj.e[traj_idx_set]; e_advanced_z1 += dedt_adj * (FTM_TS); - traj.e[makeVector_batchIdx] = e_advanced_z1; + traj.e[traj_idx_set] = e_advanced_z1; } #endif @@ -609,7 +599,7 @@ void FTMotion::makeVector() { #if HAS_DYNAMIC_FREQ_MM case dynFreqMode_Z_BASED: { static float oldz = 0.0f; - const float z = traj.z[makeVector_batchIdx]; + const float z = traj.z[traj_idx_set]; if (z != oldz) { // Only update if Z changed. oldz = z; #if HAS_X_AXIS @@ -629,10 +619,10 @@ void FTMotion::makeVector() { // Update constantly. The optimization done for Z value makes // less sense for E, as E is expected to constantly change. #if HAS_X_AXIS - shaping.x.set_axis_shaping_N(cfg.shaper.x, cfg.baseFreq.x + cfg.dynFreqK.x * traj.e[makeVector_batchIdx], cfg.zeta.x); + shaping.x.set_axis_shaping_N(cfg.shaper.x, cfg.baseFreq.x + cfg.dynFreqK.x * traj.e[traj_idx_set], cfg.zeta.x); #endif #if HAS_Y_AXIS - shaping.y.set_axis_shaping_N(cfg.shaper.y, cfg.baseFreq.y + cfg.dynFreqK.y * traj.e[makeVector_batchIdx], cfg.zeta.y); + shaping.y.set_axis_shaping_N(cfg.shaper.y, cfg.baseFreq.y + cfg.dynFreqK.y * traj.e[traj_idx_set], cfg.zeta.y); #endif break; #endif @@ -644,109 +634,105 @@ void FTMotion::makeVector() { #if HAS_FTM_SHAPING #if HAS_X_AXIS if (shaping.x.ena) { - shaping.x.d_zi[shaping.zi_idx] = traj.x[makeVector_batchIdx]; - traj.x[makeVector_batchIdx] *= shaping.x.Ai[0]; + shaping.x.d_zi[shaping.zi_idx] = traj.x[traj_idx_set]; + traj.x[traj_idx_set] *= shaping.x.Ai[0]; for (uint32_t i = 1U; i <= shaping.x.max_i; i++) { const uint32_t udiffx = shaping.zi_idx - shaping.x.Ni[i]; - traj.x[makeVector_batchIdx] += shaping.x.Ai[i] * shaping.x.d_zi[shaping.x.Ni[i] > shaping.zi_idx ? (FTM_ZMAX) + udiffx : udiffx]; + traj.x[traj_idx_set] += shaping.x.Ai[i] * shaping.x.d_zi[shaping.x.Ni[i] > shaping.zi_idx ? (FTM_ZMAX) + udiffx : udiffx]; } } #endif #if HAS_Y_AXIS if (shaping.y.ena) { - shaping.y.d_zi[shaping.zi_idx] = traj.y[makeVector_batchIdx]; - traj.y[makeVector_batchIdx] *= shaping.y.Ai[0]; + shaping.y.d_zi[shaping.zi_idx] = traj.y[traj_idx_set]; + traj.y[traj_idx_set] *= shaping.y.Ai[0]; for (uint32_t i = 1U; i <= shaping.y.max_i; i++) { const uint32_t udiffy = shaping.zi_idx - shaping.y.Ni[i]; - traj.y[makeVector_batchIdx] += shaping.y.Ai[i] * shaping.y.d_zi[shaping.y.Ni[i] > shaping.zi_idx ? (FTM_ZMAX) + udiffy : udiffy]; + traj.y[traj_idx_set] += shaping.y.Ai[i] * shaping.y.d_zi[shaping.y.Ni[i] > shaping.zi_idx ? (FTM_ZMAX) + udiffy : udiffy]; } } #endif if (++shaping.zi_idx == (FTM_ZMAX)) shaping.zi_idx = 0; + #endif // HAS_FTM_SHAPING // Filled up the queue with regular and shaped steps - if (++makeVector_batchIdx == FTM_WINDOW_SIZE) { - makeVector_batchIdx = BATCH_SIDX_IN_WINDOW; + if (++traj_idx_set == FTM_WINDOW_SIZE) { + traj_idx_set = BATCH_SIDX_IN_WINDOW; batchRdy = true; } - - if (++makeVector_idx == max_intervals) { + if (++traj_idx_get == max_intervals) { blockProcRdy = false; - makeVector_idx = 0; + traj_idx_get = 0; } } while (blockProcRdy && !batchRdy); -} +} // generateTrajectoryPointsFromBlock /** - * Convert to steps - * - Commands are written in a bitmask with step and dir as single bits. - * - Tests for delta are moved outside the loop. - * - Two functions are used for command computation with an array of function pointers. + * @brief Interpolate a single trajectory data point into stepper commands. + * @param idx The index of the trajectory point to convert. + * + * Calculate the required stepper movements for each axis based on the + * difference between the current and previous trajectory points. + * Add up to one stepper command to the buffer with STEP/DIR bits for all axes. */ -static void (*command_set[LOGICAL_AXES])(int32_t&, int32_t&, ft_command_t&, int32_t, int32_t); +void FTMotion::generateStepsFromTrajectory(const uint32_t idx) { + constexpr float INV_FTM_STEPS_PER_UNIT_TIME = 1.0f / (FTM_STEPS_PER_UNIT_TIME); -static void command_set_pos(int32_t &e, int32_t &s, ft_command_t &b, int32_t bd, int32_t bs) { - if (e < FTM_CTS_COMPARE_VAL) return; - s++; - b |= bd | bs; - e -= FTM_STEPS_PER_UNIT_TIME; -} + // q10 per-stepper-slot increment toward this sample’s target step count. + // (traj * steps_per_mm - steps) = steps still due at the start of this UNIT_TIME. + // Convert to q10 (×2^10), then subtract the current accumulator error: step_error_q10 / FTM_STEPS_PER_UNIT_TIME. + // Over FTM_STEPS_PER_UNIT_TIME stepper-slots this sums to the exact target (no drift). + // Any fraction of a step that may remain will be accounted for by the next UNIT_TIME + #define TOSTEPS_q10(A, B) int32_t( \ + (trajMod.A[idx] * planner.settings.axis_steps_per_mm[B] - steps.A) * _BV(10) \ + - step_error_q10.A * INV_FTM_STEPS_PER_UNIT_TIME ) -static void command_set_neg(int32_t &e, int32_t &s, ft_command_t &b, int32_t bd, int32_t bs) { - if (e > -(FTM_CTS_COMPARE_VAL)) return; - s--; - b |= bs; - e += FTM_STEPS_PER_UNIT_TIME; -} + xyze_long_t delta_q10 = LOGICAL_AXIS_ARRAY( + TOSTEPS_q10(e, block_extruder_axis), + TOSTEPS_q10(x, X_AXIS), TOSTEPS_q10(y, Y_AXIS), TOSTEPS_q10(z, Z_AXIS), + TOSTEPS_q10(i, I_AXIS), TOSTEPS_q10(j, J_AXIS), TOSTEPS_q10(k, K_AXIS), + TOSTEPS_q10(u, U_AXIS), TOSTEPS_q10(v, V_AXIS), TOSTEPS_q10(w, W_AXIS) + ); -// Interpolates single data point to stepper commands. -void FTMotion::convertToSteps(const uint32_t idx) { - xyze_long_t err_P = { 0 }; + // Fixed-point denominator for step accumulation + constexpr int32_t denom_q10 = (FTM_STEPS_PER_UNIT_TIME) << 10; - //#define STEPS_ROUNDING - #if ENABLED(STEPS_ROUNDING) - #define TOSTEPS(A,B) int32_t(trajMod.A[idx] * planner.settings.axis_steps_per_mm[B] + (trajMod.A[idx] < 0.0f ? -0.5f : 0.5f)) - const xyze_long_t steps_tar = LOGICAL_AXIS_ARRAY( - TOSTEPS(e, block_extruder_axis), // May be eliminated if guaranteed positive. - TOSTEPS(x, X_AXIS), TOSTEPS(y, Y_AXIS), TOSTEPS(z, Z_AXIS), - TOSTEPS(i, I_AXIS), TOSTEPS(j, J_AXIS), TOSTEPS(k, K_AXIS), - TOSTEPS(u, U_AXIS), TOSTEPS(v, V_AXIS), TOSTEPS(w, W_AXIS) - ); - xyze_long_t delta = steps_tar - steps; - #else - #define TOSTEPS(A,B) int32_t(trajMod.A[idx] * planner.settings.axis_steps_per_mm[B]) - steps.A - xyze_long_t delta = LOGICAL_AXIS_ARRAY( - TOSTEPS(e, block_extruder_axis), - TOSTEPS(x, X_AXIS), TOSTEPS(y, Y_AXIS), TOSTEPS(z, Z_AXIS), - TOSTEPS(i, I_AXIS), TOSTEPS(j, J_AXIS), TOSTEPS(k, K_AXIS), - TOSTEPS(u, U_AXIS), TOSTEPS(v, V_AXIS), TOSTEPS(w, W_AXIS) - ); - #endif + // 1. Subtract one whole step from the accumulated distance + // 2. Accumulate one positive or negative step + // 3. Set the step and direction bits for the stepper command + #define RUN_AXIS(A) \ + do { \ + if (step_error_q10.A >= denom_q10) { \ + step_error_q10.A -= denom_q10; \ + steps.A++; \ + cmd |= _BV(FT_BIT_DIR_##A) | _BV(FT_BIT_STEP_##A); \ + } \ + if (step_error_q10.A <= -denom_q10) { \ + step_error_q10.A += denom_q10; \ + steps.A--; \ + cmd |= _BV(FT_BIT_STEP_##A); /* neg dir implicit */ \ + } \ + } while (0); - #define _COMMAND_SET(AXIS) command_set[_AXIS(AXIS)] = delta[_AXIS(AXIS)] >= 0 ? command_set_pos : command_set_neg; - LOGICAL_AXIS_MAP(_COMMAND_SET); + for (uint32_t i = 0; i < uint32_t(FTM_STEPS_PER_UNIT_TIME); i++) { + // Reference the next stepper command in the circular buffer + ft_command_t& cmd = stepperCmdBuff[stepperCmdBuff_produceIdx]; - for (uint32_t i = 0U; i < (FTM_STEPS_PER_UNIT_TIME); i++) { - - ft_command_t &cmd = stepperCmdBuff[stepperCmdBuff_produceIdx]; - - // Init all step/dir bits to 0 (defaulting to reverse/negative motion) + // Init the command to no STEP (Reverse DIR) cmd = 0; - // Accumulate the errors for all axes - err_P += delta; + // Accumulate the "error" for all axes according the fixed-point distance + step_error_q10 += delta_q10; - // Set up step/dir bits for all axes - #define _COMMAND_RUN(A) command_set[_AXIS(A)](err_P.A, steps.A, cmd, _BV(FT_BIT_DIR_##A), _BV(FT_BIT_STEP_##A)); - LOGICAL_AXIS_MAP(_COMMAND_RUN); + // Where the error has accumulated whole axis steps, add them to the command + LOGICAL_AXIS_MAP(RUN_AXIS); // Next circular buffer index if (++stepperCmdBuff_produceIdx == (FTM_STEPPERCMD_BUFF_SIZE)) stepperCmdBuff_produceIdx = 0; - - } // FTM_STEPS_PER_UNIT_TIME loop + } } #endif // FT_MOTION diff --git a/Marlin/src/module/ft_motion.h b/Marlin/src/module/ft_motion.h index 9d3d5c9833..d438b3a8c5 100644 --- a/Marlin/src/module/ft_motion.h +++ b/Marlin/src/module/ft_motion.h @@ -56,12 +56,14 @@ typedef struct FTConfig { #else static constexpr dynFreqMode_t dynFreqMode = dynFreqMode_DISABLED; #endif + #endif // HAS_FTM_SHAPING #if HAS_EXTRUDERS bool linearAdvEna = FTM_LINEAR_ADV_DEFAULT_ENA; // Linear advance enable configuration. float linearAdvK = FTM_LINEAR_ADV_DEFAULT_K; // Linear advance gain. #endif + } ft_config_t; class FTMotion { @@ -160,14 +162,15 @@ class FTMotion { // Number of batches needed to propagate the current trajectory to the stepper. static constexpr uint32_t PROP_BATCHES = CEIL((FTM_WINDOW_SIZE) / (FTM_BATCH_SIZE)) - 1; - // Make vector variables. - static uint32_t makeVector_idx, - makeVector_batchIdx; + // generateTrajectoryPointsFromBlock variables. + static uint32_t traj_idx_get, + traj_idx_set; // Interpolation variables. static uint32_t interpIdx; static xyze_long_t steps; + static xyze_long_t step_error_q10; #if ENABLED(DISTINCT_E_FACTORS) static uint8_t block_extruder_axis; // Cached extruder axis index @@ -214,8 +217,8 @@ class FTMotion { static void runoutBlock(); static int32_t stepperCmdBuffItems(); static void loadBlockData(block_t *const current_block); - static void makeVector(); - static void convertToSteps(const uint32_t idx); + static void generateTrajectoryPointsFromBlock(); + static void generateStepsFromTrajectory(const uint32_t idx); FORCE_INLINE static int32_t num_samples_shaper_settle() { return ( shaping.x.ena || shaping.y.ena ) ? FTM_ZMAX : 0; } diff --git a/Marlin/src/module/ft_types.h b/Marlin/src/module/ft_types.h index 332a4fdca2..f8d361e1bf 100644 --- a/Marlin/src/module/ft_types.h +++ b/Marlin/src/module/ft_types.h @@ -41,8 +41,8 @@ enum dynFreqMode_t : uint8_t { dynFreqMode_MASS_BASED = 2 }; -#define AXIS_HAS_SHAPER(A) (ftMotion.cfg.shaper[_AXIS(A)] != ftMotionShaper_NONE) -#define AXIS_HAS_EISHAPER(A) WITHIN(ftMotion.cfg.shaper[_AXIS(A)], ftMotionShaper_EI, ftMotionShaper_3HEI) +#define AXIS_IS_SHAPING(A) (ftMotion.cfg.shaper[_AXIS(A)] != ftMotionShaper_NONE) +#define AXIS_IS_EISHAPING(A) WITHIN(ftMotion.cfg.shaper[_AXIS(A)], ftMotionShaper_EI, ftMotionShaper_3HEI) typedef struct XYZEarray xyze_trajectory_t; typedef struct XYZEarray xyze_trajectoryMod_t; diff --git a/Marlin/src/module/stepper.cpp b/Marlin/src/module/stepper.cpp index 4d2fa958e9..c9568267ca 100644 --- a/Marlin/src/module/stepper.cpp +++ b/Marlin/src/module/stepper.cpp @@ -3007,7 +3007,7 @@ hal_timer_t Stepper::block_phase_isr() { 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 + // Approximate Gaussian smoothing via higher order exponential smoothing 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]; } diff --git a/buildroot/share/PlatformIO/scripts/offset_and_rename.py b/buildroot/share/PlatformIO/scripts/offset_and_rename.py index c7bb002b48..29d66151af 100644 --- a/buildroot/share/PlatformIO/scripts/offset_and_rename.py +++ b/buildroot/share/PlatformIO/scripts/offset_and_rename.py @@ -23,18 +23,56 @@ if pioutil.is_pio_build(): LD_FLASH_OFFSET = board.get("build.offset") marlin.relocate_vtab(LD_FLASH_OFFSET) - # Flash size - maximum_flash_size = board.get("upload.maximum_size") // 1024 + # Chip total flash (bytes) from board JSON + _max_flash_bytes = int(board.get("upload.maximum_size")) + + # Keep STM32_FLASH_SIZE as the chip total (KiB) + maximum_flash_size = _max_flash_bytes // 1024 marlin.replace_define('STM32_FLASH_SIZE', maximum_flash_size) + # Also compute available flash after bootloader for Project Inspect + try: + _offset_int = int(str(LD_FLASH_OFFSET), 0) + except Exception: + _offset_int = 0 + + if _max_flash_bytes and _offset_int: + _avail = _max_flash_bytes - _offset_int + if _avail > 0: + # Update in-memory manifest so Advanced Memory Usage shows the correct total + try: + board.manifest.setdefault("upload", {}) + board.manifest["upload"]["maximum_size"] = _avail + except Exception: + pass + # Get upload.maximum_ram_size (defined by /buildroot/share/PlatformIO/boards/VARIOUS.json) maximum_ram_size = board.get("upload.maximum_ram_size") - for i, flag in enumerate(env["LINKFLAGS"]): - if "-Wl,--defsym=LD_FLASH_OFFSET" in flag: - env["LINKFLAGS"][i] = "-Wl,--defsym=LD_FLASH_OFFSET=" + LD_FLASH_OFFSET - if "-Wl,--defsym=LD_MAX_DATA_SIZE" in flag: - env["LINKFLAGS"][i] = "-Wl,--defsym=LD_MAX_DATA_SIZE=" + str(maximum_ram_size - 40) + # Helper: replace existing -Wl,--defsym=NAME=... or append if missing + def _upsert_defsym(name, value): + key = "-Wl,--defsym=" + name + if isinstance(value, int): + val = key + "=" + (hex(value) if value >= 10 else str(value)) + else: + val = key + "=" + str(value) + found = False + for i, flag in enumerate(env["LINKFLAGS"]): + if key in flag: + env["LINKFLAGS"][i] = val + found = True + break + if not found: + env.Append(LINKFLAGS=[val]) + + # Provide the symbols the linker script expects: + # ORIGIN = 0x08000000 + LD_FLASH_OFFSET + # LENGTH = LD_MAX_SIZE - LD_FLASH_OFFSET + _upsert_defsym("LD_FLASH_OFFSET", _offset_int) + _upsert_defsym("LD_MAX_SIZE", _max_flash_bytes) + + if maximum_ram_size: + _upsert_defsym("LD_MAX_DATA_SIZE", int(maximum_ram_size) - 40) # # For build.encrypt_mks rename and encode the firmware file. @@ -62,8 +100,37 @@ if pioutil.is_pio_build(): from pathlib import Path from datetime import datetime from os import path - _newpath = Path(target[0].dir.path, datetime.now().strftime(new_name.replace('{date}', '%Y%m%d').replace('{time}', '%H%M%S'))) - Path(target[0].path).replace(_newpath) - env['PROGNAME'] = path.splitext(_newpath)[0] + + # Build the timestamped base name from your template (may already include ".bin") + base = datetime.now().strftime(new_name.replace('{date}', '%Y%m%d').replace('{time}', '%H%M%S')) + + # Ensure correct extensions for both outputs + if base.lower().endswith('.bin'): + stem = base[:-4] # strip ".bin" for the ELF stem + bin_name = base + else: + stem = base + bin_name = base + '.bin' + + elf_name = stem + '.elf' + + # Current files produced by PlatformIO + bin_old = Path(target[0].path) # e.g. .pio/build//firmware.bin + elf_old = Path(source[0].path) # e.g. .pio/build//firmware.elf + + # New paths in the same directories + bin_new = Path(target[0].dir.path, bin_name) + elf_new = Path(source[0].dir.path, elf_name) + + # Rename both + bin_old.replace(bin_new) + elf_old.replace(elf_new) + + # Update PROGNAME (base without extension) for any later steps that read it + env['PROGNAME'] = path.splitext(str(bin_new))[0] + + # Optional: log the results + print(f"FIRMWARE BIN: {bin_new}") + print(f"FIRMWARE ELF: {elf_new}") marlin.add_post_action(rename_target) diff --git a/buildroot/share/PlatformIO/scripts/preflight-checks.py b/buildroot/share/PlatformIO/scripts/preflight-checks.py index 561b3bc50b..80f0985cfd 100644 --- a/buildroot/share/PlatformIO/scripts/preflight-checks.py +++ b/buildroot/share/PlatformIO/scripts/preflight-checks.py @@ -125,6 +125,12 @@ if pioutil.is_pio_build(): # rm_ofile("inc", "Warnings") + # + # Renew date/time + # + rm_ofile("gcode/host", "M115") + rm_ofile("lcd/menu", "menu_info") + # # Rebuild 'settings.cpp' for EEPROM_INIT_NOW # diff --git a/ini/features.ini b/ini/features.ini index 3b00dc792d..1f09858f07 100644 --- a/ini/features.ini +++ b/ini/features.ini @@ -39,7 +39,7 @@ USES_LIQUIDCRYSTAL_I2C = marcoschwartz/LiquidCrystal_I2C@1.1.4 USES_LIQUIDTWI2 = LiquidTWI2@1.2.7 HAS_LCDPRINT = build_src_filter=+ HAS_MARLINUI_HD44780 = build_src_filter=+ -HAS_MARLINUI_U8GLIB = marlinfirmware/U8glib-HAL@0.5.4 +HAS_MARLINUI_U8GLIB = marlinfirmware/U8glib-HAL@0.5.5 build_src_filter=+ HAS_(FSMC|SPI|LTDC)_TFT = build_src_filter=+ I2C_EEPROM = build_src_filter=+ diff --git a/ini/native.ini b/ini/native.ini index 5f56b1c843..bdfa6827ad 100644 --- a/ini/native.ini +++ b/ini/native.ini @@ -58,7 +58,7 @@ debug_build_flags = -fstack-protector-strong -g -g3 -ggdb lib_compat_mode = off build_src_filter = ${common.default_src_filter} + lib_deps = ${common.lib_deps} - MarlinSimUI=https://github.com/p3p/MarlinSimUI/archive/af62611296.zip + MarlinSimUI=https://github.com/p3p/MarlinSimUI/archive/2e71215018.zip Adafruit NeoPixel=https://github.com/p3p/Adafruit_NeoPixel/archive/c6b319f447.zip LiquidCrystal=https://github.com/p3p/LiquidCrystal/archive/322fb5fc23.zip extra_scripts = ${common.extra_scripts}