diff --git a/.github/workflows/test-builds.yml b/.github/workflows/test-builds.yml index e37f532402..069f36714d 100644 --- a/.github/workflows/test-builds.yml +++ b/.github/workflows/test-builds.yml @@ -113,10 +113,10 @@ jobs: steps: - name: Check out the PR - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Cache pip - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} @@ -124,20 +124,20 @@ jobs: ${{ runner.os }}-pip- - name: Cache PlatformIO - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ~/.platformio key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }} - name: Select Python 3.7 - uses: actions/setup-python@v2 + uses: actions/setup-python@v3 with: python-version: '3.7' # Version range or exact version of a Python version to use, using semvers version range syntax. architecture: 'x64' # optional x64 or x86. Defaults to x64 if not specified - name: Install PlatformIO run: | - pip install -U https://github.com/platformio/platformio-core/archive/develop.zip + pip install -U https://github.com/platformio/platformio-core/archive/v5.2.5.zip platformio update - name: Run ${{ matrix.test-platform }} Tests diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index d545f579f6..e551cce26b 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -6,7 +6,7 @@ // Enable this is you have a raptor 2. // Selects pin file, runout sensor and stock TMC Drivers automatically -//#define RAPTOR2 +#define RAPTOR2 /** * Enable if you replace the stepper drivers with TMC 2208. Be sure to remove MS3 jumper @@ -153,7 +153,7 @@ * * Advanced settings can be found in Configuration_adv.h */ -#define CONFIGURATION_H_VERSION 02000903 +#define CONFIGURATION_H_VERSION 02010000 //=========================================================================== //============================= Getting Started ============================= @@ -288,9 +288,9 @@ //#define MACHINE_UUID "00000000-0000-0000-0000-000000000000" /** - * Define the number of coordinated linear axes. + * Define the number of coordinated axes. * See https://github.com/DerAndere1/Marlin/wiki - * Each linear axis gets its own stepper control and endstop: + * Each axis gets its own stepper control and endstop: * * Steppers: *_STEP_PIN, *_ENABLE_PIN, *_DIR_PIN, *_ENABLE_ON * Endstops: *_STOP_PIN, USE_*MIN_PLUG, USE_*MAX_PLUG @@ -299,31 +299,50 @@ * DEFAULT_MAX_ACCELERATION, AXIS_RELATIVE_MODES, * MICROSTEP_MODES, MANUAL_FEEDRATE * - * :[3, 4, 5, 6] + * :[3, 4, 5, 6, 7, 8, 9] */ -//#define LINEAR_AXES 3 +//#define NUM_AXES 3 /** - * Axis codes for additional axes: - * This defines the axis code that is used in G-code commands to - * reference a specific axis. - * 'A' for rotational axis parallel to X - * 'B' for rotational axis parallel to Y - * 'C' for rotational axis parallel to Z - * 'U' for secondary linear axis parallel to X - * 'V' for secondary linear axis parallel to Y - * 'W' for secondary linear axis parallel to Z - * Regardless of the settings, firmware-internal axis IDs are - * I (AXIS4), J (AXIS5), K (AXIS6). + * Additional Axis Settings + * + * Define AXISn_ROTATES for all axes that rotate or pivot. + * Rotational axis coordinates are expressed in degrees. + * + * AXISn_NAME defines the letter used to refer to the axis in (most) G-code commands. + * By convention the names and roles are typically: + * 'A' : Rotational axis parallel to X + * 'B' : Rotational axis parallel to Y + * 'C' : Rotational axis parallel to Z + * 'U' : Secondary linear axis parallel to X + * 'V' : Secondary linear axis parallel to Y + * 'W' : Secondary linear axis parallel to Z + * + * Regardless of these settings the axes are internally named I, J, K, U, V, W. */ -#if LINEAR_AXES >= 4 +#if NUM_AXES >= 4 #define AXIS4_NAME 'A' // :['A', 'B', 'C', 'U', 'V', 'W'] + #define AXIS4_ROTATES #endif -#if LINEAR_AXES >= 5 - #define AXIS5_NAME 'B' // :['A', 'B', 'C', 'U', 'V', 'W'] +#if NUM_AXES >= 5 + #define AXIS5_NAME 'B' // :['B', 'C', 'U', 'V', 'W'] + #define AXIS5_ROTATES #endif -#if LINEAR_AXES >= 6 - #define AXIS6_NAME 'C' // :['A', 'B', 'C', 'U', 'V', 'W'] +#if NUM_AXES >= 6 + #define AXIS6_NAME 'C' // :['C', 'U', 'V', 'W'] + #define AXIS6_ROTATES +#endif +#if NUM_AXES >= 7 + #define AXIS7_NAME 'U' // :['U', 'V', 'W'] + //#define AXIS7_ROTATES +#endif +#if NUM_AXES >= 8 + #define AXIS8_NAME 'V' // :['V', 'W'] + //#define AXIS8_ROTATES +#endif +#if NUM_AXES >= 9 + #define AXIS9_NAME 'W' // :['W'] + //#define AXIS9_ROTATES #endif // @section extruder @@ -754,10 +773,12 @@ //=========================================================================== //============================= PID Settings ================================ //=========================================================================== -// PID Tuning Guide here: https://reprap.org/wiki/PID_Tuning -// Comment the following line to disable PID and enable bang-bang. -#define PIDTEMP +// Enable PIDTEMP for PID control or MPCTEMP for Predictive Model. +// temperature control. Disable both for bang-bang heating. +#define PIDTEMP // See the PID Tuning Guide at https://reprap.org/wiki/PID_Tuning +//#define MPCTEMP // ** EXPERIMENTAL ** + #define BANG_MAX 255 // Limits current to nozzle while in bang-bang mode; 255=full current #define PID_MAX BANG_MAX // Limits current to nozzle while PID is active (see PID_FUNCTIONAL_RANGE below); 255=full current #define PID_K1 0.95 // Smoothing factor within any PID loop @@ -779,17 +800,45 @@ #define DEFAULT_Ki 1.5 #define DEFAULT_Kd 79.88 #endif - // MakerGear - //#define DEFAULT_Kp 7.0 - //#define DEFAULT_Ki 0.1 - //#define DEFAULT_Kd 12 +#endif - // Mendel Parts V9 on 12V - //#define DEFAULT_Kp 63.0 - //#define DEFAULT_Ki 2.25 - //#define DEFAULT_Kd 440 +/** + * Model Predictive Control for hotend + * + * Use a physical model of the hotend to control temperature. When configured correctly + * this gives better responsiveness and stability than PID and it also removes the need + * for PID_EXTRUSION_SCALING and PID_FAN_SCALING. Use M306 to autotune the model. + */ +#if ENABLED(MPCTEMP) + #define MPC_MAX BANG_MAX // (0..255) Current to nozzle while MPC is active. + #define MPC_HEATER_POWER { 40.0f } // (W) Heat cartridge powers. -#endif // PIDTEMP + #define MPC_INCLUDE_FAN // Model the fan speed? + + // Measured physical constants from M306 + #define MPC_BLOCK_HEAT_CAPACITY { 16.7f } // (J/K) Heat block heat capacities. + #define MPC_SENSOR_RESPONSIVENESS { 0.22f } // (K/s per ∆K) Rate of change of sensor temperature from heat block. + #define MPC_AMBIENT_XFER_COEFF { 0.068f } // (W/K) Heat transfer coefficients from heat block to room air with fan off. + #if ENABLED(MPC_INCLUDE_FAN) + #define MPC_AMBIENT_XFER_COEFF_FAN255 { 0.097f } // (W/K) Heat transfer coefficients from heat block to room air with fan on full. + #endif + + // For one fan and multiple hotends MPC needs to know how to apply the fan cooling effect. + #if ENABLED(MPC_INCLUDE_FAN) + //#define MPC_FAN_0_ALL_HOTENDS + //#define MPC_FAN_0_ACTIVE_HOTEND + #endif + + #define FILAMENT_HEAT_CAPACITY_PERMM 5.6e-3f // 0.0056 J/K/mm for 1.75mm PLA (0.0149 J/K/mm for 2.85mm PLA). + //#define FILAMENT_HEAT_CAPACITY_PERMM 3.6e-3f // 0.0036 J/K/mm for 1.75mm PETG (0.0094 J/K/mm for 2.85mm PETG). + + // Advanced options + #define MPC_SMOOTHING_FACTOR 0.5f // (0.0...1.0) Noisy temperature sensors may need a lower value for stabilization. + #define MPC_MIN_AMBIENT_CHANGE 1.0f // (K/s) Modeled ambient temperature rate of change, when correcting model inaccuracies. + #define MPC_STEADYSTATE 0.5f // (K/s) Temperature change rate for steady state logic to be enforced. + + #define MPC_TUNING_POS { X_CENTER, Y_CENTER, 1.0f } // (mm) M306 Autotuning position, ideally bed center just above the surface. +#endif //=========================================================================== //====================== PID > Bed Temperature Control ====================== @@ -978,12 +1027,18 @@ //#define USE_IMIN_PLUG //#define USE_JMIN_PLUG //#define USE_KMIN_PLUG +//#define USE_UMIN_PLUG +//#define USE_VMIN_PLUG +//#define USE_WMIN_PLUG //#define USE_XMAX_PLUG #define USE_YMAX_PLUG //#define USE_ZMAX_PLUG //#define USE_IMAX_PLUG //#define USE_JMAX_PLUG //#define USE_KMAX_PLUG +//#define USE_UMAX_PLUG +//#define USE_VMAX_PLUG +//#define USE_WMAX_PLUG // Enable pullup for all endstops to prevent a floating state #define ENDSTOPPULLUPS @@ -995,12 +1050,18 @@ //#define ENDSTOPPULLUP_IMIN //#define ENDSTOPPULLUP_JMIN //#define ENDSTOPPULLUP_KMIN + //#define ENDSTOPPULLUP_UMIN + //#define ENDSTOPPULLUP_VMIN + //#define ENDSTOPPULLUP_WMIN //#define ENDSTOPPULLUP_XMAX //#define ENDSTOPPULLUP_YMAX //#define ENDSTOPPULLUP_ZMAX //#define ENDSTOPPULLUP_IMAX //#define ENDSTOPPULLUP_JMAX //#define ENDSTOPPULLUP_KMAX + //#define ENDSTOPPULLUP_UMAX + //#define ENDSTOPPULLUP_VMAX + //#define ENDSTOPPULLUP_WMAX //#define ENDSTOPPULLUP_ZMIN_PROBE #endif @@ -1014,12 +1075,18 @@ //#define ENDSTOPPULLDOWN_IMIN //#define ENDSTOPPULLDOWN_JMIN //#define ENDSTOPPULLDOWN_KMIN + //#define ENDSTOPPULLDOWN_UMIN + //#define ENDSTOPPULLDOWN_VMIN + //#define ENDSTOPPULLDOWN_WMIN //#define ENDSTOPPULLDOWN_XMAX //#define ENDSTOPPULLDOWN_YMAX //#define ENDSTOPPULLDOWN_ZMAX //#define ENDSTOPPULLDOWN_IMAX //#define ENDSTOPPULLDOWN_JMAX //#define ENDSTOPPULLDOWN_KMAX + //#define ENDSTOPPULLDOWN_UMAX + //#define ENDSTOPPULLDOWN_VMAX + //#define ENDSTOPPULLDOWN_WMAX //#define ENDSTOPPULLDOWN_ZMIN_PROBE #endif @@ -1030,12 +1097,18 @@ #define I_MIN_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. #define J_MIN_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. #define K_MIN_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. +#define U_MIN_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. +#define V_MIN_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. +#define W_MIN_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. #define X_MAX_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. #define Y_MAX_ENDSTOP_INVERTING true // Set to true to invert the logic of the endstop. #define Z_MAX_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. #define I_MAX_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. #define J_MAX_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. #define K_MAX_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. +#define U_MAX_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. +#define V_MAX_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. +#define W_MAX_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. #define Z_MIN_PROBE_ENDSTOP_INVERTING false // Set to true to invert the logic of the probe. /** @@ -1101,6 +1174,9 @@ #define E0_DRIVER_TYPE DRV8825 #define E1_DRIVER_TYPE DRV8825 #endif +//#define U_DRIVER_TYPE A4988 +//#define V_DRIVER_TYPE A4988 +//#define W_DRIVER_TYPE A4988 //#define E2_DRIVER_TYPE A4988 //#define E3_DRIVER_TYPE A4988 //#define E4_DRIVER_TYPE A4988 @@ -1150,9 +1226,9 @@ //#define DISTINCT_E_FACTORS /** - * Default Axis Steps Per Unit (steps/mm) + * Default Axis Steps Per Unit (linear=steps/mm, rotational=steps/°) * Override with M92 - * X, Y, Z [, I [, J [, K]]], E0 [, E1[, E2...]] + * X, Y, Z [, I [, J [, K...]]], E0 [, E1[, E2...]] */ #if ENABLED(E3DHemeraExtruder) #if ANY(E_2208, E_4988, E_2209_Uart) @@ -1189,9 +1265,9 @@ #define DEFAULT_AXIS_STEPS_PER_UNIT { 80, Y_STEPSMM, Z_STEPSMM, E_STEPSMM } /** - * Default Max Feed Rate (mm/s) + * Default Max Feed Rate (linear=mm/s, rotational=°/s) * Override with M203 - * X, Y, Z [, I [, J [, K]]], E0 [, E1[, E2...]] + * X, Y, Z [, I [, J [, K...]]], E0 [, E1[, E2...]] */ #define DEFAULT_MAX_FEEDRATE { 300, 150, 5, 70 } @@ -1201,10 +1277,10 @@ #endif /** - * Default Max Acceleration (change/s) change = mm/s + * Default Max Acceleration (speed change with time) (linear=mm/(s^2), rotational=°/(s^2)) * (Maximum start speed for accelerated moves) * Override with M201 - * X, Y, Z [, I [, J [, K]]], E0 [, E1[, E2...]] + * X, Y, Z [, I [, J [, K...]]], E0 [, E1[, E2...]] */ #if(ENABLED(X_2208)) #if(ENABLED(X_SpreadCycle)) @@ -1233,7 +1309,7 @@ #endif /** - * Default Acceleration (change/s) change = mm/s + * Default Acceleration (speed change with time) (linear=mm/(s^2), rotational=°/(s^2)) * Override with M204 * * M204 P Acceleration @@ -1246,7 +1322,7 @@ /** * Default Jerk limits (mm/s) - * Override with M205 X Y Z E + * Override with M205 X Y Z . . . E * * "Jerk" specifies the minimum speed change that requires acceleration. * When changing speed and direction, if the difference is less than the @@ -1260,6 +1336,9 @@ //#define DEFAULT_IJERK 0.3 //#define DEFAULT_JJERK 0.3 //#define DEFAULT_KJERK 0.3 + //#define DEFAULT_UJERK 0.3 + //#define DEFAULT_VJERK 0.3 + //#define DEFAULT_WJERK 0.3 //#define TRAVEL_EXTRA_XYJERK 0.0 // Additional jerk allowance for all travel moves @@ -1607,6 +1686,9 @@ //#define I_ENABLE_ON 0 //#define J_ENABLE_ON 0 //#define K_ENABLE_ON 0 +//#define U_ENABLE_ON 0 +//#define V_ENABLE_ON 0 +//#define W_ENABLE_ON 0 // Disable axis steppers immediately when they're not being stepped. // WARNING: When motors turn off there is a chance of losing position accuracy! @@ -1616,6 +1698,9 @@ //#define DISABLE_I false //#define DISABLE_J false //#define DISABLE_K false +//#define DISABLE_U false +//#define DISABLE_V false +//#define DISABLE_W false // Turn off the display blinking that warns about possible accuracy reduction //#define DISABLE_REDUCED_ACCURACY_WARNING @@ -1646,6 +1731,9 @@ //#define INVERT_I_DIR false //#define INVERT_J_DIR false //#define INVERT_K_DIR false +//#define INVERT_U_DIR false +//#define INVERT_V_DIR false +//#define INVERT_W_DIR false // @section extruder @@ -1689,6 +1777,9 @@ //#define I_HOME_DIR -1 //#define J_HOME_DIR -1 //#define K_HOME_DIR -1 +//#define U_HOME_DIR -1 +//#define V_HOME_DIR -1 +//#define W_HOME_DIR -1 // @section machine @@ -1704,7 +1795,7 @@ #define Y_BED_SIZE 400 #endif -// Travel limits (mm) after homing, corresponding to endstop positions. +// Travel limits (linear=mm, rotational=°) after homing, corresponding to endstop positions. #define X_MIN_POS 0 #define Y_MIN_POS 0 #define Z_MIN_POS 0 @@ -1721,6 +1812,12 @@ //#define J_MAX_POS 50 //#define K_MIN_POS 0 //#define K_MAX_POS 50 +//#define U_MIN_POS 0 +//#define U_MAX_POS 50 +//#define V_MIN_POS 0 +//#define V_MAX_POS 50 +//#define W_MIN_POS 0 +//#define W_MAX_POS 50 /** * Software Endstops @@ -1740,6 +1837,9 @@ #define MIN_SOFTWARE_ENDSTOP_I #define MIN_SOFTWARE_ENDSTOP_J #define MIN_SOFTWARE_ENDSTOP_K + #define MIN_SOFTWARE_ENDSTOP_U + #define MIN_SOFTWARE_ENDSTOP_V + #define MIN_SOFTWARE_ENDSTOP_W #endif // Max software endstops constrain movement within maximum coordinate bounds @@ -1751,6 +1851,9 @@ #define MAX_SOFTWARE_ENDSTOP_I #define MAX_SOFTWARE_ENDSTOP_J #define MAX_SOFTWARE_ENDSTOP_K + #define MAX_SOFTWARE_ENDSTOP_U + #define MAX_SOFTWARE_ENDSTOP_V + #define MAX_SOFTWARE_ENDSTOP_W #endif #if EITHER(MIN_SOFTWARE_ENDSTOPS, MAX_SOFTWARE_ENDSTOPS) @@ -1775,16 +1878,15 @@ #endif #if ENABLED(FILAMENT_RUNOUT_SENSOR) //#define NUM_RUNOUT_SENSORS 1 // Number of sensors, up to one per extruder. Define a FIL_RUNOUT#_PIN for each. - #define FIL_RUNOUT_ENABLED { true } // Default enabled state for sensors E0[, E1[, E2[, E3...]]]. Override with M591 followed by M500. + #define FIL_RUNOUT_ENABLED { true } // Default enabled state for sensors E0[, E1[, E2[, E3...]]]. Override with M591EnnSn followed by M500. #if NONE(RAPTOR2, SKRBoard) #define FIL_RUNOUT_PIN 57 - #define FIL_RUNOUT_MODE { 1 } // Default mode for sensors E0[, E1[, E2[, E3...]]]. 0:NONE 1:Switch NO 2:Switch NC 7:Motion Sensor + #define FIL_RUNOUT_MODE { 1 } // Default mode for sensors E0[, E1[, E2[, E3...]]]. 0:NONE 1:Switch NO 2:Switch NC 7:Motion Sensor Override with M591EnPnn #else - #define FIL_RUNOUT_MODE { 0 } // Default mode for sensors E0[, E1[, E2[, E3...]]]. 0:NONE 1:Switch NO 2:Switch NC 7:Motion Sensor + #define FIL_RUNOUT_MODE { 0 } // Default mode for sensors E0[, E1[, E2[, E3...]]]. 0:NONE 1:Switch NO 2:Switch NC 7:Motion Sensor Override with M591EnPnn #endif - #define FIL_RUNOUT_PULLUP // Use internal pullup for filament runout pins. - //#define WATCH_ALL_RUNOUT_SENSORS // Execute runout script on any triggering sensor, not only for the active extruder. - // This is automatically enabled for MIXING_EXTRUDERs. + //#define WATCH_ALL_RUNOUT_SENSORS // Execute runout script on any triggering sensor, not only for the active extruder. + // This is automatically enabled for MIXING_EXTRUDERs. // Commands to execute on filament runout. // With multiple runout sensors use the %c placeholder for the current tool in commands (e.g., "M600 T%c") @@ -1801,35 +1903,27 @@ //#define FIL_RUNOUT_PULLDOWN // Use internal pulldown for filament runout pins. // Override individually if the runout sensors vary - //#define FIL_RUNOUT1_STATE LOW //#define FIL_RUNOUT1_PULLUP //#define FIL_RUNOUT1_PULLDOWN - //#define FIL_RUNOUT2_STATE LOW //#define FIL_RUNOUT2_PULLUP //#define FIL_RUNOUT2_PULLDOWN - //#define FIL_RUNOUT3_STATE LOW //#define FIL_RUNOUT3_PULLUP //#define FIL_RUNOUT3_PULLDOWN - //#define FIL_RUNOUT4_STATE LOW //#define FIL_RUNOUT4_PULLUP //#define FIL_RUNOUT4_PULLDOWN - //#define FIL_RUNOUT5_STATE LOW //#define FIL_RUNOUT5_PULLUP //#define FIL_RUNOUT5_PULLDOWN - //#define FIL_RUNOUT6_STATE LOW //#define FIL_RUNOUT6_PULLUP //#define FIL_RUNOUT6_PULLDOWN - //#define FIL_RUNOUT7_STATE LOW //#define FIL_RUNOUT7_PULLUP //#define FIL_RUNOUT7_PULLDOWN - //#define FIL_RUNOUT8_STATE LOW //#define FIL_RUNOUT8_PULLUP //#define FIL_RUNOUT8_PULLDOWN #endif @@ -2071,6 +2165,9 @@ //#define MANUAL_I_HOME_POS 0 //#define MANUAL_J_HOME_POS 0 //#define MANUAL_K_HOME_POS 0 +//#define MANUAL_U_HOME_POS 0 +//#define MANUAL_V_HOME_POS 0 +//#define MANUAL_W_HOME_POS 0 /** * Use "Z Safe Homing" to avoid homing with a Z probe outside the bed area. @@ -2086,7 +2183,7 @@ #define Z_SAFE_HOMING_Y_POINT Y_CENTER // Y point for Z homing #endif -// Homing speeds (mm/min) +// Homing speeds (linear=mm/min, rotational=°/min) #define HOMING_FEEDRATE_MM_M { (50*60), (50*60), (4*60) } // Validate that endstops are triggered on homing moves diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index ed5d4f5bc6..ed91707a69 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -30,7 +30,7 @@ * * Basic settings can be found in Configuration.h */ -#define CONFIGURATION_ADV_H_VERSION 02000903 +#define CONFIGURATION_ADV_H_VERSION 02010000 //=========================================================================== //============================= Thermal Settings ============================ @@ -823,18 +823,17 @@ */ //#define DUAL_X_CARRIAGE #if ENABLED(DUAL_X_CARRIAGE) - #define X1_MIN_POS X_MIN_POS // Set to X_MIN_POS - #define X1_MAX_POS X_BED_SIZE // Set a maximum so the first X-carriage can't hit the parked second X-carriage - #define X2_MIN_POS 80 // Set a minimum to ensure the second X-carriage can't hit the parked first X-carriage - #define X2_MAX_POS 353 // Set this to the distance between toolheads when both heads are homed - #define X2_HOME_DIR 1 // Set to 1. The second X-carriage always homes to the maximum endstop position - #define X2_HOME_POS X2_MAX_POS // Default X2 home position. Set to X2_MAX_POS. - // However: In this mode the HOTEND_OFFSET_X value for the second extruder provides a software - // override for X2_HOME_POS. This also allow recalibration of the distance between the two endstops - // without modifying the firmware (through the "M218 T1 X???" command). - // Remember: you should set the second extruder x-offset to 0 in your slicer. + #define X1_MIN_POS X_MIN_POS // Set to X_MIN_POS + #define X1_MAX_POS X_BED_SIZE // A max coordinate so the X1 carriage can't hit the parked X2 carriage + #define X2_MIN_POS 80 // A min coordinate so the X2 carriage can't hit the parked X1 carriage + #define X2_MAX_POS 353 // The max position of the X2 carriage, typically also the home position + #define X2_HOME_DIR 1 // Set to 1. The X2 carriage always homes to the max endstop position + #define X2_HOME_POS X2_MAX_POS // Default X2 home position. Set to X2_MAX_POS. + // NOTE: For Dual X Carriage use M218 T1 Xn to override the X2_HOME_POS. + // This allows recalibration of endstops distance without a rebuild. + // Remember to set the second extruder's X-offset to 0 in your slicer. - // This is the default power-up mode which can be later using M605. + // This is the default power-up mode which can be changed later using M605 S. #define DEFAULT_DUAL_X_CARRIAGE_MODE DXC_AUTO_PARK_MODE // Default x offset in duplication mode (typically set to half print bed width) @@ -856,12 +855,12 @@ * the position of the toolhead relative to the workspace. */ -//#define SENSORLESS_BACKOFF_MM { 2, 2, 0 } // (mm) Backoff from endstops before sensorless homing +//#define SENSORLESS_BACKOFF_MM { 2, 2, 0 } // (linear=mm, rotational=°) Backoff from endstops before sensorless homing -#define HOMING_BUMP_MM { 5, 5, 2 } // (mm) Backoff from endstops after first bump +#define HOMING_BUMP_MM { 5, 5, 2 } // (linear=mm, rotational=°) Backoff from endstops after first bump #define HOMING_BUMP_DIVISOR { 2, 2, 4 } // Re-Bump Speed Divisor (Divides the Homing Feedrate) -//#define HOMING_BACKOFF_POST_MM { 2, 2, 2 } // (mm) Backoff from endstops after homing +//#define HOMING_BACKOFF_POST_MM { 2, 2, 2 } // (linear=mm, rotational=°) Backoff from endstops after homing #define QUICK_HOME // If G28 contains XY do a diagonal move first //#define HOME_Y_BEFORE_X // If G28 contains XY home Y before X @@ -1049,6 +1048,9 @@ #define INVERT_I_STEP_PIN false #define INVERT_J_STEP_PIN false #define INVERT_K_STEP_PIN false +#define INVERT_U_STEP_PIN false +#define INVERT_V_STEP_PIN false +#define INVERT_W_STEP_PIN false #define INVERT_E_STEP_PIN false /** @@ -1063,11 +1065,14 @@ #define DISABLE_INACTIVE_I true #define DISABLE_INACTIVE_J true #define DISABLE_INACTIVE_K true +#define DISABLE_INACTIVE_U true +#define DISABLE_INACTIVE_V true +#define DISABLE_INACTIVE_W true #define DISABLE_INACTIVE_E true // Default Minimum Feedrates for printing and travel moves -#define DEFAULT_MINIMUMFEEDRATE 0.0 // (mm/s) Minimum feedrate. Set with M205 S. -#define DEFAULT_MINTRAVELFEEDRATE 0.0 // (mm/s) Minimum travel feedrate. Set with M205 T. +#define DEFAULT_MINIMUMFEEDRATE 0.0 // (mm/s. °/s for rotational-only moves) Minimum feedrate. Set with M205 S. +#define DEFAULT_MINTRAVELFEEDRATE 0.0 // (mm/s. °/s for rotational-only moves) Minimum travel feedrate. Set with M205 T. // Minimum time that a segment needs to take as the buffer gets emptied #define DEFAULT_MINSEGMENTTIME 20000 // (µs) Set with M205 B. @@ -1104,7 +1109,7 @@ #if ENABLED(BACKLASH_COMPENSATION) // Define values for backlash distance and correction. // If BACKLASH_GCODE is enabled these values are the defaults. - #define BACKLASH_DISTANCE_MM { 0, 0, 0 } // (mm) One value for each linear axis + #define BACKLASH_DISTANCE_MM { 0, 0, 0 } // (linear=mm, rotational=°) One value for each linear axis #define BACKLASH_CORRECTION 0.0 // 0.0 = no correction; 1.0 = full correction // Add steps for motor direction changes on CORE kinematics @@ -1181,6 +1186,12 @@ //#define CALIBRATION_MEASURE_JMAX //#define CALIBRATION_MEASURE_KMIN //#define CALIBRATION_MEASURE_KMAX + //#define CALIBRATION_MEASURE_UMIN + //#define CALIBRATION_MEASURE_UMAX + //#define CALIBRATION_MEASURE_VMIN + //#define CALIBRATION_MEASURE_VMAX + //#define CALIBRATION_MEASURE_WMIN + //#define CALIBRATION_MEASURE_WMAX // Probing at the exact top center only works if the center is flat. If // probing on a screwhead or hollow washer, probe near the edges. @@ -1357,19 +1368,22 @@ #endif #if EITHER(HAS_DISPLAY, DWIN_LCD_PROUI) - // The timeout (in ms) to return to the status screen from sub-menus - #define LCD_TIMEOUT_TO_STATUS 15000 + // The timeout to return to the status screen from sub-menus + #define LCD_TIMEOUT_TO_STATUS 15000 // (ms) #if ENABLED(SHOW_BOOTSCREEN) - #define BOOTSCREEN_TIMEOUT 4000 // (ms) Total Duration to display the boot screen(s) + #define BOOTSCREEN_TIMEOUT 4000 // (ms) Total Duration to display the boot screen(s) #if EITHER(HAS_MARLINUI_U8GLIB, TFT_COLOR_UI) - #define BOOT_MARLIN_LOGO_SMALL // Show a smaller Marlin logo on the Boot Screen (saving lots of flash) + #define BOOT_MARLIN_LOGO_SMALL // Show a smaller Marlin logo on the Boot Screen (saving lots of flash) #endif #endif // Scroll a longer status message into view #define STATUS_MESSAGE_SCROLLING + // Apply a timeout to low-priority status messages + //#define STATUS_MESSAGE_TIMEOUT_SEC 30 // (seconds) + // On the Info Screen, display XY with one decimal place when possible //#define LCD_DECIMAL_SMALL_XY @@ -2037,6 +2051,21 @@ // @section leveling +/** + * Use Safe Bed Leveling coordinates to move axes to a useful position before bed probing. + * For example, after homing a rotational axis the Z probe might not be perpendicular to the bed. + * Choose values the orient the bed horizontally and the Z-probe vertically. + */ +//#define SAFE_BED_LEVELING_START_X 0.0 +//#define SAFE_BED_LEVELING_START_Y 0.0 +//#define SAFE_BED_LEVELING_START_Z 0.0 +//#define SAFE_BED_LEVELING_START_I 0.0 +//#define SAFE_BED_LEVELING_START_J 0.0 +//#define SAFE_BED_LEVELING_START_K 0.0 +//#define SAFE_BED_LEVELING_START_U 0.0 +//#define SAFE_BED_LEVELING_START_V 0.0 +//#define SAFE_BED_LEVELING_START_W 0.0 + /** * Points to probe for all 3-point Leveling procedures. * Override if the automatically selected points are inadequate. @@ -2457,7 +2486,7 @@ /** * Extra G-code to run while executing tool-change commands. Can be used to use an additional - * stepper motor (I axis, see option LINEAR_AXES in Configuration.h) to drive the tool-changer. + * stepper motor (I axis, see option NUM_AXES in Configuration.h) to drive the tool-changer. */ //#define EVENT_GCODE_TOOLCHANGE_T0 "G28 A\nG1 A0" // Extra G-code to run while executing tool-change command T0 //#define EVENT_GCODE_TOOLCHANGE_T1 "G1 A10" // Extra G-code to run while executing tool-change command T1 @@ -2660,6 +2689,24 @@ #define K_MICROSTEPS 16 #endif + #if AXIS_DRIVER_TYPE_U(TMC26X) + #define U_MAX_CURRENT 1000 + #define U_SENSE_RESISTOR 91 + #define U_MICROSTEPS 16 + #endif + + #if AXIS_DRIVER_TYPE_V(TMC26X) + #define V_MAX_CURRENT 1000 + #define V_SENSE_RESISTOR 91 + #define V_MICROSTEPS 16 + #endif + + #if AXIS_DRIVER_TYPE_W(TMC26X) + #define W_MAX_CURRENT 1000 + #define W_SENSE_RESISTOR 91 + #define W_MICROSTEPS 16 + #endif + #if AXIS_DRIVER_TYPE_E0(TMC26X) #define E0_MAX_CURRENT 1000 #define E0_SENSE_RESISTOR 91 @@ -2848,6 +2895,33 @@ //#define K_HOLD_MULTIPLIER 0.5 #endif + #if AXIS_IS_TMC(U) + #define U_CURRENT 800 + #define U_CURRENT_HOME U_CURRENT + #define U_MICROSTEPS 8 + #define U_RSENSE 0.11 + #define U_CHAIN_POS -1 + //#define U_INTERPOLATE true + #endif + + #if AXIS_IS_TMC(V) + #define V_CURRENT 800 + #define V_CURRENT_HOME V_CURRENT + #define V_MICROSTEPS 8 + #define V_RSENSE 0.11 + #define V_CHAIN_POS -1 + //#define V_INTERPOLATE true + #endif + + #if AXIS_IS_TMC(W) + #define W_CURRENT 800 + #define W_CURRENT_HOME W_CURRENT + #define W_MICROSTEPS 8 + #define W_RSENSE 0.11 + #define W_CHAIN_POS -1 + //#define W_INTERPOLATE true + #endif + #if AXIS_IS_TMC(E0) #define E0_CURRENT 800 #define E0_MICROSTEPS 16 @@ -2935,6 +3009,9 @@ //#define I_CS_PIN -1 //#define J_CS_PIN -1 //#define K_CS_PIN -1 + //#define U_CS_PIN -1 + //#define V_CS_PIN -1 + //#define W_CS_PIN -1 //#define E0_CS_PIN -1 //#define E1_CS_PIN -1 //#define E2_CS_PIN -1 @@ -2966,8 +3043,7 @@ * Set *_SERIAL_TX_PIN and *_SERIAL_RX_PIN to match for all drivers * on the same serial port, either here or in your board's pins file. */ - - #if ENABLED(SKRBoard) + #if ENABLED(SKRBoard) #define X_SLAVE_ADDRESS 0 #define Y_SLAVE_ADDRESS 0 #define Z_SLAVE_ADDRESS 0 @@ -2989,19 +3065,25 @@ #define E0_SERIAL_TX_PIN 58 #define E0_SERIAL_RX_PIN 12 #endif - - #define X2_SLAVE_ADDRESS 0 - #define Y2_SLAVE_ADDRESS 0 - #define Z2_SLAVE_ADDRESS 0 - #define Z3_SLAVE_ADDRESS 0 - #define Z4_SLAVE_ADDRESS 0 - #define E1_SLAVE_ADDRESS 0 - #define E2_SLAVE_ADDRESS 0 - #define E3_SLAVE_ADDRESS 0 - #define E4_SLAVE_ADDRESS 0 - #define E5_SLAVE_ADDRESS 0 - #define E6_SLAVE_ADDRESS 0 - #define E7_SLAVE_ADDRESS 0 + //#define X2_SLAVE_ADDRESS 0 + //#define Y2_SLAVE_ADDRESS 0 + //#define Z2_SLAVE_ADDRESS 0 + //#define Z3_SLAVE_ADDRESS 0 + //#define Z4_SLAVE_ADDRESS 0 + //#define I_SLAVE_ADDRESS 0 + //#define J_SLAVE_ADDRESS 0 + //#define K_SLAVE_ADDRESS 0 + //#define U_SLAVE_ADDRESS 0 + //#define V_SLAVE_ADDRESS 0 + //#define W_SLAVE_ADDRESS 0 + //#define E0_SLAVE_ADDRESS 0 + //#define E1_SLAVE_ADDRESS 0 + //#define E2_SLAVE_ADDRESS 0 + //#define E3_SLAVE_ADDRESS 0 + //#define E4_SLAVE_ADDRESS 0 + //#define E5_SLAVE_ADDRESS 0 + //#define E6_SLAVE_ADDRESS 0 + //#define E7_SLAVE_ADDRESS 0 /** * Software enable @@ -3021,6 +3103,9 @@ #define STEALTHCHOP_I #define STEALTHCHOP_J #define STEALTHCHOP_K + #define STEALTHCHOP_U + #define STEALTHCHOP_V + #define STEALTHCHOP_W //#define STEALTHCHOP_E /** @@ -3047,9 +3132,12 @@ //#define CHOPPER_TIMING_Z2 CHOPPER_TIMING_Z //#define CHOPPER_TIMING_Z3 CHOPPER_TIMING_Z //#define CHOPPER_TIMING_Z4 CHOPPER_TIMING_Z - //#define CHOPPER_TIMING_I CHOPPER_TIMING - //#define CHOPPER_TIMING_J CHOPPER_TIMING - //#define CHOPPER_TIMING_K CHOPPER_TIMING + //#define CHOPPER_TIMING_I CHOPPER_TIMING // For I Axis + //#define CHOPPER_TIMING_J CHOPPER_TIMING // For J Axis + //#define CHOPPER_TIMING_K CHOPPER_TIMING // For K Axis + //#define CHOPPER_TIMING_U CHOPPER_TIMING // For U Axis + //#define CHOPPER_TIMING_V CHOPPER_TIMING // For V Axis + //#define CHOPPER_TIMING_W CHOPPER_TIMING // For W Axis //#define CHOPPER_TIMING_E CHOPPER_TIMING // For Extruders (override below) //#define CHOPPER_TIMING_E1 CHOPPER_TIMING_E //#define CHOPPER_TIMING_E2 CHOPPER_TIMING_E @@ -3097,9 +3185,12 @@ #define Z2_HYBRID_THRESHOLD 3 #define Z3_HYBRID_THRESHOLD 3 #define Z4_HYBRID_THRESHOLD 3 - #define I_HYBRID_THRESHOLD 3 - #define J_HYBRID_THRESHOLD 3 - #define K_HYBRID_THRESHOLD 3 + #define I_HYBRID_THRESHOLD 3 // [linear=mm/s, rotational=°/s] + #define J_HYBRID_THRESHOLD 3 // [linear=mm/s, rotational=°/s] + #define K_HYBRID_THRESHOLD 3 // [linear=mm/s, rotational=°/s] + #define U_HYBRID_THRESHOLD 3 // [mm/s] + #define V_HYBRID_THRESHOLD 3 + #define W_HYBRID_THRESHOLD 3 #define E0_HYBRID_THRESHOLD 30 #define E1_HYBRID_THRESHOLD 30 #define E2_HYBRID_THRESHOLD 30 @@ -3149,6 +3240,9 @@ //#define I_STALL_SENSITIVITY 8 //#define J_STALL_SENSITIVITY 8 //#define K_STALL_SENSITIVITY 8 + //#define U_STALL_SENSITIVITY 8 + //#define V_STALL_SENSITIVITY 8 + //#define W_STALL_SENSITIVITY 8 //#define SPI_ENDSTOPS // TMC2130 only //#define IMPROVE_HOMING_RELIABILITY #endif @@ -3316,6 +3410,33 @@ #define K_SLEW_RATE 1 #endif + #if AXIS_IS_L64XX(U) + #define U_MICROSTEPS 128 + #define U_OVERCURRENT 2000 + #define U_STALLCURRENT 1500 + #define U_MAX_VOLTAGE 127 + #define U_CHAIN_POS -1 + #define U_SLEW_RATE 1 + #endif + + #if AXIS_IS_L64XX(V) + #define V_MICROSTEPS 128 + #define V_OVERCURRENT 2000 + #define V_STALLCURRENT 1500 + #define V_MAX_VOLTAGE 127 + #define V_CHAIN_POS -1 + #define V_SLEW_RATE 1 + #endif + + #if AXIS_IS_L64XX(W) + #define W_MICROSTEPS 128 + #define W_OVERCURRENT 2000 + #define W_STALLCURRENT 1500 + #define W_MAX_VOLTAGE 127 + #define W_CHAIN_POS -1 + #define W_SLEW_RATE 1 + #endif + #if AXIS_IS_L64XX(E0) #define E0_MICROSTEPS 128 #define E0_OVERCURRENT 2000 @@ -3522,7 +3643,7 @@ //#define SPINDLE_LASER_USE_PWM // Enable if your controller supports setting the speed/power #if ENABLED(SPINDLE_LASER_USE_PWM) #define SPINDLE_LASER_PWM_INVERT false // Set to "true" if the speed/power goes up when you want it to go slower - #define SPINDLE_LASER_FREQUENCY 2500 // (Hz) Spindle/laser frequency (only on supported HALs: AVR and LPC) + #define SPINDLE_LASER_FREQUENCY 2500 // (Hz) Spindle/laser frequency (only on supported HALs: AVR, ESP32, and LPC) #endif //#define AIR_EVACUATION // Cutter Vacuum / Laser Blower motor control with G-codes M10-M11 @@ -4180,12 +4301,12 @@ /** * Instant freeze / unfreeze functionality - * Specified pin has pullup and connecting to ground will instantly pause motion. * Potentially useful for emergency stop that allows being resumed. */ //#define FREEZE_FEATURE #if ENABLED(FREEZE_FEATURE) //#define FREEZE_PIN 41 // Override the default (KILL) pin here + #define FREEZE_STATE LOW // State of pin indicating freeze #endif /** diff --git a/Marlin/Makefile b/Marlin/Makefile index eee1403b53..f1c89ff7f5 100644 --- a/Marlin/Makefile +++ b/Marlin/Makefile @@ -132,7 +132,7 @@ CC_MIN:=$(shell $(CC) -dM -E - < /dev/null | grep __GNUC_MINOR__ | cut -f3 -d\ ) CC_PATCHLEVEL:=$(shell $(CC) -dM -E - < /dev/null | grep __GNUC_PATCHLEVEL__ | cut -f3 -d\ ) CC_VER:=$(shell echo $$(( $(CC_MAJ) * 10000 + $(CC_MIN) * 100 + $(CC_PATCHLEVEL) ))) ifeq ($(shell test $(CC_VER) -lt 40901 && echo 1),1) - @echo This version of GCC is likely broken. Enabling relocation workaround. + $(warning This GCC version $(CC_VER) is likely broken. Enabling relocation workaround.) RELOC_WORKAROUND = 1 endif diff --git a/Marlin/Version.h b/Marlin/Version.h index b0f2d24db2..bb16cab01e 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 "2022-03-12" +#define STRING_DISTRIBUTION_DATE "2022-04-03" /** * Defines a generic printer name to be output to the LCD after booting Marlin. diff --git a/Marlin/src/HAL/AVR/endstop_interrupts.h b/Marlin/src/HAL/AVR/endstop_interrupts.h index 0ce8574c53..5511aa406f 100644 --- a/Marlin/src/HAL/AVR/endstop_interrupts.h +++ b/Marlin/src/HAL/AVR/endstop_interrupts.h @@ -213,6 +213,51 @@ void setup_endstop_interrupts() { pciSetup(K_MIN_PIN); #endif #endif + #if HAS_U_MAX + #if (digitalPinToInterrupt(U_MAX_PIN) != NOT_AN_INTERRUPT) + _ATTACH(U_MAX_PIN); + #else + static_assert(digitalPinHasPCICR(U_MAX_PIN), "U_MAX_PIN is not interrupt-capable"); + pciSetup(U_MAX_PIN); + #endif + #elif HAS_U_MIN + #if (digitalPinToInterrupt(U_MIN_PIN) != NOT_AN_INTERRUPT) + _ATTACH(U_MIN_PIN); + #else + static_assert(digitalPinHasPCICR(U_MIN_PIN), "U_MIN_PIN is not interrupt-capable"); + pciSetup(U_MIN_PIN); + #endif + #endif + #if HAS_V_MAX + #if (digitalPinToInterrupt(V_MAX_PIN) != NOT_AN_INTERRUPT) + _ATTACH(V_MAX_PIN); + #else + static_assert(digitalPinHasPCICR(V_MAX_PIN), "V_MAX_PIN is not interrupt-capable"); + pciSetup(V_MAX_PIN); + #endif + #elif HAS_V_MIN + #if (digitalPinToInterrupt(V_MIN_PIN) != NOT_AN_INTERRUPT) + _ATTACH(V_MIN_PIN); + #else + static_assert(digitalPinHasPCICR(V_MIN_PIN), "V_MIN_PIN is not interrupt-capable"); + pciSetup(V_MIN_PIN); + #endif + #endif + #if HAS_W_MAX + #if (digitalPinToInterrupt(W_MAX_PIN) != NOT_AN_INTERRUPT) + _ATTACH(W_MAX_PIN); + #else + static_assert(digitalPinHasPCICR(W_MAX_PIN), "W_MAX_PIN is not interrupt-capable"); + pciSetup(W_MAX_PIN); + #endif + #elif HAS_W_MIN + #if (digitalPinToInterrupt(W_MIN_PIN) != NOT_AN_INTERRUPT) + _ATTACH(W_MIN_PIN); + #else + static_assert(digitalPinHasPCICR(W_MIN_PIN), "W_MIN_PIN is not interrupt-capable"); + pciSetup(W_MIN_PIN); + #endif + #endif #if HAS_X2_MAX #if (digitalPinToInterrupt(X2_MAX_PIN) != NOT_AN_INTERRUPT) _ATTACH(X2_MAX_PIN); diff --git a/Marlin/src/HAL/AVR/inc/SanityCheck.h b/Marlin/src/HAL/AVR/inc/SanityCheck.h index 5c1f01a8f4..15a5be4cd2 100644 --- a/Marlin/src/HAL/AVR/inc/SanityCheck.h +++ b/Marlin/src/HAL/AVR/inc/SanityCheck.h @@ -71,3 +71,7 @@ #if ENABLED(POSTMORTEM_DEBUGGING) #error "POSTMORTEM_DEBUGGING is not supported on AVR boards." #endif + +#if USING_PULLDOWNS + #error "PULLDOWN pin mode is not available on AVR boards." +#endif diff --git a/Marlin/src/HAL/DUE/endstop_interrupts.h b/Marlin/src/HAL/DUE/endstop_interrupts.h index 9c7e210488..c1bbcb121b 100644 --- a/Marlin/src/HAL/DUE/endstop_interrupts.h +++ b/Marlin/src/HAL/DUE/endstop_interrupts.h @@ -70,4 +70,10 @@ void setup_endstop_interrupts() { TERN_(HAS_J_MIN, _ATTACH(J_MIN_PIN)); TERN_(HAS_K_MAX, _ATTACH(K_MAX_PIN)); TERN_(HAS_K_MIN, _ATTACH(K_MIN_PIN)); + TERN_(HAS_U_MAX, _ATTACH(U_MAX_PIN)); + TERN_(HAS_U_MIN, _ATTACH(U_MIN_PIN)); + TERN_(HAS_V_MAX, _ATTACH(V_MAX_PIN)); + TERN_(HAS_V_MIN, _ATTACH(V_MIN_PIN)); + TERN_(HAS_W_MAX, _ATTACH(W_MAX_PIN)); + TERN_(HAS_W_MIN, _ATTACH(W_MIN_PIN)); } diff --git a/Marlin/src/HAL/DUE/inc/SanityCheck.h b/Marlin/src/HAL/DUE/inc/SanityCheck.h index 87b09cf292..75480acaf2 100644 --- a/Marlin/src/HAL/DUE/inc/SanityCheck.h +++ b/Marlin/src/HAL/DUE/inc/SanityCheck.h @@ -59,3 +59,7 @@ #if HAS_TMC_SW_SERIAL #error "TMC220x Software Serial is not supported on the DUE platform." #endif + +#if USING_PULLDOWNS + #error "PULLDOWN pin mode is not available on DUE boards." +#endif diff --git a/Marlin/src/HAL/ESP32/HAL.cpp b/Marlin/src/HAL/ESP32/HAL.cpp index 4000dcc908..e204e0b6fe 100644 --- a/Marlin/src/HAL/ESP32/HAL.cpp +++ b/Marlin/src/HAL/ESP32/HAL.cpp @@ -73,9 +73,16 @@ uint16_t MarlinHAL::adc_result; esp_adc_cal_characteristics_t characteristics[ADC_ATTEN_MAX]; adc_atten_t attenuations[ADC1_CHANNEL_MAX] = {}; uint32_t thresholds[ADC_ATTEN_MAX]; -volatile int numPWMUsed = 0, - pwmPins[MAX_PWM_PINS], - pwmValues[MAX_PWM_PINS]; + +volatile int numPWMUsed = 0; +volatile struct { pin_t pin; int value; } pwmState[MAX_PWM_PINS]; + +pin_t chan_pin[CHANNEL_MAX_NUM + 1] = { 0 }; // PWM capable IOpins - not 0 or >33 on ESP32 + +struct { + uint32_t freq; // ledcReadFreq doesn't work if a duty hasn't been set yet! + uint16_t res; +} pwmInfo[(CHANNEL_MAX_NUM + 1) / 2]; // ------------------------ // Public functions @@ -202,19 +209,19 @@ void MarlinHAL::adc_init() { adc1_config_width(ADC_WIDTH_12Bit); // Configure channels only if used as (re-)configuring a pin for ADC that is used elsewhere might have adverse effects - TERN_(HAS_TEMP_ADC_0, adc1_set_attenuation(get_channel(TEMP_0_PIN), ADC_ATTEN_11db)); - TERN_(HAS_TEMP_ADC_1, adc1_set_attenuation(get_channel(TEMP_1_PIN), ADC_ATTEN_11db)); - TERN_(HAS_TEMP_ADC_2, adc1_set_attenuation(get_channel(TEMP_2_PIN), ADC_ATTEN_11db)); - TERN_(HAS_TEMP_ADC_3, adc1_set_attenuation(get_channel(TEMP_3_PIN), ADC_ATTEN_11db)); - TERN_(HAS_TEMP_ADC_4, adc1_set_attenuation(get_channel(TEMP_4_PIN), ADC_ATTEN_11db)); - TERN_(HAS_TEMP_ADC_5, adc1_set_attenuation(get_channel(TEMP_5_PIN), ADC_ATTEN_11db)); - TERN_(HAS_TEMP_ADC_6, adc2_set_attenuation(get_channel(TEMP_6_PIN), ADC_ATTEN_11db)); - TERN_(HAS_TEMP_ADC_7, adc3_set_attenuation(get_channel(TEMP_7_PIN), ADC_ATTEN_11db)); - TERN_(HAS_HEATED_BED, adc1_set_attenuation(get_channel(TEMP_BED_PIN), ADC_ATTEN_11db)); - TERN_(HAS_TEMP_CHAMBER, adc1_set_attenuation(get_channel(TEMP_CHAMBER_PIN), ADC_ATTEN_11db)); - TERN_(HAS_TEMP_PROBE, adc1_set_attenuation(get_channel(TEMP_PROBE_PIN), ADC_ATTEN_11db)); - TERN_(HAS_TEMP_COOLER, adc1_set_attenuation(get_channel(TEMP_COOLER_PIN), ADC_ATTEN_11db)); - TERN_(HAS_TEMP_BOARD, adc1_set_attenuation(get_channel(TEMP_BOARD_PIN), ADC_ATTEN_11db)); + TERN_(HAS_TEMP_ADC_0, adc1_set_attenuation(get_channel(TEMP_0_PIN), ADC_ATTEN_11db)); + TERN_(HAS_TEMP_ADC_1, adc1_set_attenuation(get_channel(TEMP_1_PIN), ADC_ATTEN_11db)); + TERN_(HAS_TEMP_ADC_2, adc1_set_attenuation(get_channel(TEMP_2_PIN), ADC_ATTEN_11db)); + TERN_(HAS_TEMP_ADC_3, adc1_set_attenuation(get_channel(TEMP_3_PIN), ADC_ATTEN_11db)); + TERN_(HAS_TEMP_ADC_4, adc1_set_attenuation(get_channel(TEMP_4_PIN), ADC_ATTEN_11db)); + TERN_(HAS_TEMP_ADC_5, adc1_set_attenuation(get_channel(TEMP_5_PIN), ADC_ATTEN_11db)); + TERN_(HAS_TEMP_ADC_6, adc2_set_attenuation(get_channel(TEMP_6_PIN), ADC_ATTEN_11db)); + TERN_(HAS_TEMP_ADC_7, adc3_set_attenuation(get_channel(TEMP_7_PIN), ADC_ATTEN_11db)); + TERN_(HAS_HEATED_BED, adc1_set_attenuation(get_channel(TEMP_BED_PIN), ADC_ATTEN_11db)); + TERN_(HAS_TEMP_CHAMBER, adc1_set_attenuation(get_channel(TEMP_CHAMBER_PIN), ADC_ATTEN_11db)); + TERN_(HAS_TEMP_PROBE, adc1_set_attenuation(get_channel(TEMP_PROBE_PIN), ADC_ATTEN_11db)); + TERN_(HAS_TEMP_COOLER, adc1_set_attenuation(get_channel(TEMP_COOLER_PIN), ADC_ATTEN_11db)); + TERN_(HAS_TEMP_BOARD, adc1_set_attenuation(get_channel(TEMP_BOARD_PIN), ADC_ATTEN_11db)); TERN_(FILAMENT_WIDTH_SENSOR, adc1_set_attenuation(get_channel(FILWIDTH_PIN), ADC_ATTEN_11db)); // Note that adc2 is shared with the WiFi module, which has higher priority, so the conversion may fail. @@ -229,11 +236,15 @@ void MarlinHAL::adc_init() { } } +#ifndef ADC_REFERENCE_VOLTAGE + #define ADC_REFERENCE_VOLTAGE 3.3 +#endif + void MarlinHAL::adc_start(const pin_t pin) { const adc1_channel_t chan = get_channel(pin); uint32_t mv; esp_adc_cal_get_voltage((adc_channel_t)chan, &characteristics[attenuations[chan]], &mv); - adc_result = mv * 1023.0 / 3300.0; + adc_result = mv * 1023.0f / float(ADC_REFERENCE_VOLTAGE) / 1000.0f; // Change the attenuation level based on the new reading adc_atten_t atten; @@ -250,25 +261,81 @@ void MarlinHAL::adc_start(const pin_t pin) { adc1_set_attenuation(chan, atten); } -void analogWrite(pin_t pin, int value) { - // Use ledc hardware for internal pins - if (pin < 34) { - static int cnt_channel = 1, pin_to_channel[40] = { 0 }; - if (pin_to_channel[pin] == 0) { - ledcAttachPin(pin, cnt_channel); - ledcSetup(cnt_channel, 490, 8); - ledcWrite(cnt_channel, value); - pin_to_channel[pin] = cnt_channel++; +// ------------------------ +// PWM +// ------------------------ + +int8_t channel_for_pin(const uint8_t pin) { + for (int i = 0; i <= CHANNEL_MAX_NUM; i++) + if (chan_pin[i] == pin) return i; + return -1; +} + +// get PWM channel for pin - if none then attach a new one +// return -1 if fail or invalid pin#, channel # (0-15) if success +int8_t get_pwm_channel(const pin_t pin, const uint32_t freq, const uint16_t res) { + if (!WITHIN(pin, 1, MAX_PWM_IOPIN)) return -1; // Not a hardware PWM pin! + int8_t cid = channel_for_pin(pin); + if (cid >= 0) return cid; + + // Find an empty adjacent channel (same timer & freq/res) + for (int i = 0; i <= CHANNEL_MAX_NUM; i++) { + if (chan_pin[i] == 0) { + if (chan_pin[i ^ 0x1] != 0) { + if (pwmInfo[i / 2].freq == freq && pwmInfo[i / 2].res == res) { + chan_pin[i] = pin; // Allocate PWM to this channel + ledcAttachPin(pin, i); + return i; + } + } + else if (cid == -1) // Pair of empty channels? + cid = i & 0xFE; // Save lower channel number } - ledcWrite(pin_to_channel[pin], value); + } + // not attached, is an empty timer slot avail? + if (cid >= 0) { + chan_pin[cid] = pin; + pwmInfo[cid / 2].freq = freq; + pwmInfo[cid / 2].res = res; + ledcSetup(cid, freq, res); + ledcAttachPin(pin, cid); + } + return cid; // -1 if no channel avail +} + +void MarlinHAL::set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size/*=_BV(PWM_RESOLUTION)-1*/, const bool invert/*=false*/) { + const int8_t cid = get_pwm_channel(pin, PWM_FREQUENCY, PWM_RESOLUTION); + if (cid >= 0) { + uint32_t duty = map(invert ? v_size - v : v, 0, v_size, 0, _BV(PWM_RESOLUTION)-1); + ledcWrite(cid, duty); + } +} + +int8_t MarlinHAL::set_pwm_frequency(const pin_t pin, const uint32_t f_desired) { + const int8_t cid = channel_for_pin(pin); + if (cid >= 0) { + if (f_desired == ledcReadFreq(cid)) return cid; // no freq change + ledcDetachPin(chan_pin[cid]); + chan_pin[cid] = 0; // remove old freq channel + } + return get_pwm_channel(pin, f_desired, PWM_RESOLUTION); // try for new one +} + +// use hardware PWM if avail, if not then ISR +void analogWrite(const pin_t pin, const uint16_t value, const uint32_t freq/*=PWM_FREQUENCY*/, const uint16_t res/*=8*/) { // always 8 bit resolution! + // Use ledc hardware for internal pins + const int8_t cid = get_pwm_channel(pin, freq, res); + if (cid >= 0) { + ledcWrite(cid, value); // set duty value return; } + // not a hardware PWM pin OR no PWM channels available int idx = -1; // Search Pin for (int i = 0; i < numPWMUsed; ++i) - if (pwmPins[i] == pin) { idx = i; break; } + if (pwmState[i].pin == pin) { idx = i; break; } // not found ? if (idx < 0) { @@ -277,7 +344,7 @@ void analogWrite(pin_t pin, int value) { // Take new slot for pin idx = numPWMUsed; - pwmPins[idx] = pin; + pwmState[idx].pin = pin; // Start timer on first use if (idx == 0) HAL_timer_start(MF_TIMER_PWM, PWM_TIMER_FREQUENCY); @@ -285,7 +352,7 @@ void analogWrite(pin_t pin, int value) { } // Use 7bit internal value - add 1 to have 100% high at 255 - pwmValues[idx] = (value + 1) / 2; + pwmState[idx].value = (value + 1) / 2; } // Handle PWM timer interrupt @@ -296,9 +363,9 @@ HAL_PWM_TIMER_ISR() { for (int i = 0; i < numPWMUsed; ++i) { if (count == 0) // Start of interval - WRITE(pwmPins[i], pwmValues[i] ? HIGH : LOW); - else if (pwmValues[i] == count) // End of duration - WRITE(pwmPins[i], LOW); + digitalWrite(pwmState[i].pin, pwmState[i].value ? HIGH : LOW); + else if (pwmState[i].value == count) // End of duration + digitalWrite(pwmState[i].pin, LOW); } // 128 for 7 Bit resolution diff --git a/Marlin/src/HAL/ESP32/HAL.h b/Marlin/src/HAL/ESP32/HAL.h index df52e2186c..8b26c3471d 100644 --- a/Marlin/src/HAL/ESP32/HAL.h +++ b/Marlin/src/HAL/ESP32/HAL.h @@ -64,6 +64,12 @@ #define CRITICAL_SECTION_START() portENTER_CRITICAL(&spinlock) #define CRITICAL_SECTION_END() portEXIT_CRITICAL(&spinlock) +#define HAL_CAN_SET_PWM_FREQ // This HAL supports PWM Frequency adjustment +#define PWM_FREQUENCY 1000u // Default PWM frequency when set_pwm_duty() is called without set_pwm_frequency() +#define PWM_RESOLUTION 10u // Default PWM bit resolution +#define CHANNEL_MAX_NUM 15u // max PWM channel # to allocate (7 to only use low speed, 15 to use low & high) +#define MAX_PWM_IOPIN 33u // hardware pwm pins < 34 + // ------------------------ // Types // ------------------------ @@ -83,7 +89,7 @@ typedef Servo hal_servo_t; void tone(const pin_t _pin, const unsigned int frequency, const unsigned long duration=0); void noTone(const pin_t _pin); -void analogWrite(pin_t pin, int value); +void analogWrite(const pin_t pin, const uint16_t value, const uint32_t freq=PWM_FREQUENCY, const uint16_t res=8); // // Pin Mapping for M42, M43, M226 @@ -209,12 +215,17 @@ public: static uint16_t adc_value() { return adc_result; } /** - * Set the PWM duty cycle for the pin to the given value. - * No inverting the duty cycle in this HAL. - * No changing the maximum size of the provided value to enable finer PWM duty control in this HAL. + * If not already allocated, allocate a hardware PWM channel + * to the pin and set the duty cycle.. + * Optionally invert the duty cycle [default = false] + * Optionally change the scale of the provided value to enable finer PWM duty control [default = 255] */ - static void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t=255, const bool=false) { - analogWrite(pin, v); - } + static void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size=255, const bool invert=false); + + /** + * Allocate and set the frequency of a hardware PWM pin + * Returns -1 if no pin available. + */ + static int8_t set_pwm_frequency(const pin_t pin, const uint32_t f_desired); }; diff --git a/Marlin/src/HAL/ESP32/Servo.cpp b/Marlin/src/HAL/ESP32/Servo.cpp index fcf5848581..ca3950d07f 100644 --- a/Marlin/src/HAL/ESP32/Servo.cpp +++ b/Marlin/src/HAL/ESP32/Servo.cpp @@ -31,20 +31,18 @@ // so we only allocate servo channels up high to avoid side effects with regards to analogWrite (fans, leds, laser pwm etc.) int Servo::channel_next_free = 12; -Servo::Servo() { - channel = channel_next_free++; -} +Servo::Servo() {} int8_t Servo::attach(const int inPin) { - if (channel >= CHANNEL_MAX_NUM) return -1; if (inPin > 0) pin = inPin; - - ledcSetup(channel, 50, 16); // channel X, 50 Hz, 16-bit depth - ledcAttachPin(pin, channel); - return true; + channel = get_pwm_channel(pin, 50u, 16u); + return channel; // -1 if no PWM avail. } -void Servo::detach() { ledcDetachPin(pin); } +// leave channel connected to servo - set duty to zero +void Servo::detach() { + if (channel >= 0) ledcWrite(channel, 0); +} int Servo::read() { return degrees; } @@ -52,7 +50,7 @@ void Servo::write(int inDegrees) { degrees = constrain(inDegrees, MIN_ANGLE, MAX_ANGLE); int us = map(degrees, MIN_ANGLE, MAX_ANGLE, MIN_PULSE_WIDTH, MAX_PULSE_WIDTH); int duty = map(us, 0, TAU_USEC, 0, MAX_COMPARE); - ledcWrite(channel, duty); + if (channel >= 0) ledcWrite(channel, duty); // don't save duty for servos! } void Servo::move(const int value) { diff --git a/Marlin/src/HAL/ESP32/Servo.h b/Marlin/src/HAL/ESP32/Servo.h index 8542092d66..1dbb416a83 100644 --- a/Marlin/src/HAL/ESP32/Servo.h +++ b/Marlin/src/HAL/ESP32/Servo.h @@ -30,8 +30,7 @@ class Servo { MAX_PULSE_WIDTH = 2400, // Longest pulse sent to a servo TAU_MSEC = 20, TAU_USEC = (TAU_MSEC * 1000), - MAX_COMPARE = _BV(16) - 1, // 65535 - CHANNEL_MAX_NUM = 16; + MAX_COMPARE = _BV(16) - 1; // 65535 public: Servo(); diff --git a/Marlin/src/HAL/ESP32/endstop_interrupts.h b/Marlin/src/HAL/ESP32/endstop_interrupts.h index 4725df921b..0536864610 100644 --- a/Marlin/src/HAL/ESP32/endstop_interrupts.h +++ b/Marlin/src/HAL/ESP32/endstop_interrupts.h @@ -65,4 +65,10 @@ void setup_endstop_interrupts() { TERN_(HAS_J_MIN, _ATTACH(J_MIN_PIN)); TERN_(HAS_K_MAX, _ATTACH(K_MAX_PIN)); TERN_(HAS_K_MIN, _ATTACH(K_MIN_PIN)); + TERN_(HAS_U_MAX, _ATTACH(U_MAX_PIN)); + TERN_(HAS_U_MIN, _ATTACH(U_MIN_PIN)); + TERN_(HAS_V_MAX, _ATTACH(V_MAX_PIN)); + TERN_(HAS_V_MIN, _ATTACH(V_MIN_PIN)); + TERN_(HAS_W_MAX, _ATTACH(W_MAX_PIN)); + TERN_(HAS_W_MIN, _ATTACH(W_MIN_PIN)); } diff --git a/Marlin/src/HAL/ESP32/inc/SanityCheck.h b/Marlin/src/HAL/ESP32/inc/SanityCheck.h index 8bbc68d871..04d70ec14f 100644 --- a/Marlin/src/HAL/ESP32/inc/SanityCheck.h +++ b/Marlin/src/HAL/ESP32/inc/SanityCheck.h @@ -25,8 +25,8 @@ #error "EMERGENCY_PARSER is not yet implemented for ESP32. Disable EMERGENCY_PARSER to continue." #endif -#if ENABLED(FAST_PWM_FAN) || SPINDLE_LASER_FREQUENCY - #error "Features requiring Hardware PWM (FAST_PWM_FAN, SPINDLE_LASER_FREQUENCY) are not yet supported on ESP32." +#if (ENABLED(SPINDLE_LASER_USE_PWM) && SPINDLE_LASER_FREQUENCY > 78125) || (ENABLED(FAST_PWM_FAN_FREQUENCY) && FAST_PWM_FAN_FREQUENCY > 78125) + #error "SPINDLE_LASER_FREQUENCY and FAST_PWM_FREQUENCY maximum value is 78125Hz for ESP32." #endif #if HAS_TMC_SW_SERIAL @@ -40,3 +40,11 @@ #if ENABLED(POSTMORTEM_DEBUGGING) #error "POSTMORTEM_DEBUGGING is not yet supported on ESP32." #endif + +#if MB(MKS_TINYBEE) && ENABLED(FAST_PWM_FAN) + #error "FAST_PWM_FAN is not available on TinyBee." +#endif + +#if USING_PULLDOWNS + #error "PULLDOWN pin mode is not available on ESP32 boards." +#endif diff --git a/Marlin/src/HAL/LPC1768/endstop_interrupts.h b/Marlin/src/HAL/LPC1768/endstop_interrupts.h index 23bd0cc982..e4ac17f608 100644 --- a/Marlin/src/HAL/LPC1768/endstop_interrupts.h +++ b/Marlin/src/HAL/LPC1768/endstop_interrupts.h @@ -155,4 +155,37 @@ void setup_endstop_interrupts() { #endif _ATTACH(K_MIN_PIN); #endif + #if HAS_U_MAX + #if !LPC1768_PIN_INTERRUPT_M(U_MAX_PIN) + #error "U_MAX_PIN is not INTERRUPT-capable." + #endif + _ATTACH(U_MAX_PIN); + #elif HAS_U_MIN + #if !LPC1768_PIN_INTERRUPT_M(U_MIN_PIN) + #error "U_MIN_PIN is not INTERRUPT-capable." + #endif + _ATTACH(U_MIN_PIN); + #endif + #if HAS_V_MAX + #if !LPC1768_PIN_INTERRUPT_M(V_MAX_PIN) + #error "V_MAX_PIN is not INTERRUPT-capable." + #endif + _ATTACH(V_MAX_PIN); + #elif HAS_V_MIN + #if !LPC1768_PIN_INTERRUPT_M(V_MIN_PIN) + #error "V_MIN_PIN is not INTERRUPT-capable." + #endif + _ATTACH(V_MIN_PIN); + #endif + #if HAS_W_MAX + #if !LPC1768_PIN_INTERRUPT_M(W_MAX_PIN) + #error "W_MAX_PIN is not INTERRUPT-capable." + #endif + _ATTACH(W_MAX_PIN); + #elif HAS_W_MIN + #if !LPC1768_PIN_INTERRUPT_M(W_MIN_PIN) + #error "W_MIN_PIN is not INTERRUPT-capable." + #endif + _ATTACH(W_MIN_PIN); + #endif } diff --git a/Marlin/src/HAL/LPC1768/include/digipot_mcp4451_I2C_routines.c b/Marlin/src/HAL/LPC1768/include/digipot_mcp4451_I2C_routines.c index f442ab71c0..c489c16e5e 100644 --- a/Marlin/src/HAL/LPC1768/include/digipot_mcp4451_I2C_routines.c +++ b/Marlin/src/HAL/LPC1768/include/digipot_mcp4451_I2C_routines.c @@ -29,7 +29,7 @@ #include "../../../inc/MarlinConfigPre.h" -#if MB(MKS_SBASE) +#if ENABLED(DIGIPOT_MCP4451) && MB(MKS_SBASE) #ifdef __cplusplus extern "C" { @@ -37,35 +37,6 @@ #include "digipot_mcp4451_I2C_routines.h" -// These two routines are exact copies of the lpc17xx_i2c.c routines. Couldn't link to -// to the lpc17xx_i2c.c routines so had to copy them into this file & rename them. - -static uint32_t _I2C_Start(LPC_I2C_TypeDef *I2Cx) { - // Reset STA, STO, SI - I2Cx->I2CONCLR = I2C_I2CONCLR_SIC|I2C_I2CONCLR_STOC|I2C_I2CONCLR_STAC; - - // Enter to Master Transmitter mode - I2Cx->I2CONSET = I2C_I2CONSET_STA; - - // Wait for complete - while (!(I2Cx->I2CONSET & I2C_I2CONSET_SI)); - I2Cx->I2CONCLR = I2C_I2CONCLR_STAC; - return (I2Cx->I2STAT & I2C_STAT_CODE_BITMASK); -} - -static void _I2C_Stop(LPC_I2C_TypeDef *I2Cx) { - // Make sure start bit is not active - if (I2Cx->I2CONSET & I2C_I2CONSET_STA) - I2Cx->I2CONCLR = I2C_I2CONCLR_STAC; - - I2Cx->I2CONSET = I2C_I2CONSET_STO|I2C_I2CONSET_AA; - I2Cx->I2CONCLR = I2C_I2CONCLR_SIC; -} - -I2C_M_SETUP_Type transferMCfg; - -#define I2C_status (LPC_I2C1->I2STAT & I2C_STAT_CODE_BITMASK) - uint8_t digipot_mcp4451_start(uint8_t sla) { // send slave address and write bit // Sometimes TX data ACK or NAK status is returned. That mean the start state didn't // happen which means only the value of the slave address was send. Keep looping until @@ -102,5 +73,5 @@ uint8_t digipot_mcp4451_send_byte(uint8_t data) { } #endif -#endif // MB(MKS_SBASE) +#endif // DIGIPOT_MCP4451 && MKS_SBASE #endif // TARGET_LPC1768 diff --git a/Marlin/src/HAL/LPC1768/include/i2c_util.c b/Marlin/src/HAL/LPC1768/include/i2c_util.c index e52fb7c4de..4e24f23236 100644 --- a/Marlin/src/HAL/LPC1768/include/i2c_util.c +++ b/Marlin/src/HAL/LPC1768/include/i2c_util.c @@ -63,6 +63,32 @@ void configure_i2c(const uint8_t clock_option) { I2C_Cmd(I2CDEV_M, I2C_MASTER_MODE, ENABLE); } +////////////////////////////////////////////////////////////////////////////////////// +// These two routines are exact copies of the lpc17xx_i2c.c routines. Couldn't link to +// to the lpc17xx_i2c.c routines so had to copy them into this file & rename them. + +uint32_t _I2C_Start(LPC_I2C_TypeDef *I2Cx) { + // Reset STA, STO, SI + I2Cx->I2CONCLR = I2C_I2CONCLR_SIC|I2C_I2CONCLR_STOC|I2C_I2CONCLR_STAC; + + // Enter to Master Transmitter mode + I2Cx->I2CONSET = I2C_I2CONSET_STA; + + // Wait for complete + while (!(I2Cx->I2CONSET & I2C_I2CONSET_SI)); + I2Cx->I2CONCLR = I2C_I2CONCLR_STAC; + return (I2Cx->I2STAT & I2C_STAT_CODE_BITMASK); +} + +void _I2C_Stop(LPC_I2C_TypeDef *I2Cx) { + /* Make sure start bit is not active */ + if (I2Cx->I2CONSET & I2C_I2CONSET_STA) + I2Cx->I2CONCLR = I2C_I2CONCLR_STAC; + + I2Cx->I2CONSET = I2C_I2CONSET_STO|I2C_I2CONSET_AA; + I2Cx->I2CONCLR = I2C_I2CONCLR_SIC; +} + #ifdef __cplusplus } #endif diff --git a/Marlin/src/HAL/LPC1768/include/i2c_util.h b/Marlin/src/HAL/LPC1768/include/i2c_util.h index a57f68a407..1f1c19f279 100644 --- a/Marlin/src/HAL/LPC1768/include/i2c_util.h +++ b/Marlin/src/HAL/LPC1768/include/i2c_util.h @@ -51,6 +51,11 @@ void configure_i2c(const uint8_t clock_option); +uint32_t _I2C_Start(LPC_I2C_TypeDef *I2Cx); +void _I2C_Stop(LPC_I2C_TypeDef *I2Cx); + +#define I2C_status (LPC_I2C1->I2STAT & I2C_STAT_CODE_BITMASK) + #ifdef __cplusplus } #endif diff --git a/Marlin/src/HAL/LPC1768/u8g/LCD_I2C_routines.cpp b/Marlin/src/HAL/LPC1768/u8g/LCD_I2C_routines.cpp index a48a820dc4..e714c3c16d 100644 --- a/Marlin/src/HAL/LPC1768/u8g/LCD_I2C_routines.cpp +++ b/Marlin/src/HAL/LPC1768/u8g/LCD_I2C_routines.cpp @@ -36,40 +36,7 @@ extern int millis(); ////////////////////////////////////////////////////////////////////////////////////// -// These two routines are exact copies of the lpc17xx_i2c.c routines. Couldn't link to -// to the lpc17xx_i2c.c routines so had to copy them into this file & rename them. - -static uint32_t _I2C_Start(LPC_I2C_TypeDef *I2Cx) { - // Reset STA, STO, SI - I2Cx->I2CONCLR = I2C_I2CONCLR_SIC|I2C_I2CONCLR_STOC|I2C_I2CONCLR_STAC; - - // Enter to Master Transmitter mode - I2Cx->I2CONSET = I2C_I2CONSET_STA; - - // Wait for complete - while (!(I2Cx->I2CONSET & I2C_I2CONSET_SI)); - I2Cx->I2CONCLR = I2C_I2CONCLR_STAC; - return (I2Cx->I2STAT & I2C_STAT_CODE_BITMASK); -} - -static void _I2C_Stop (LPC_I2C_TypeDef *I2Cx) { - /* Make sure start bit is not active */ - if (I2Cx->I2CONSET & I2C_I2CONSET_STA) - I2Cx->I2CONCLR = I2C_I2CONCLR_STAC; - - I2Cx->I2CONSET = I2C_I2CONSET_STO|I2C_I2CONSET_AA; - I2Cx->I2CONCLR = I2C_I2CONCLR_SIC; -} - -////////////////////////////////////////////////////////////////////////////////////// - -#define I2CDEV_S_ADDR 0x78 // from SSD1306 //actual address is 0x3C - shift left 1 with LSB set to 0 to indicate write - -#define BUFFER_SIZE 0x1 // only do single byte transfers with LCDs - -I2C_M_SETUP_Type transferMCfg; - -#define I2C_status (LPC_I2C1->I2STAT & I2C_STAT_CODE_BITMASK) +#define I2CDEV_S_ADDR 0x78 // From SSD1306 (actual address is 0x3C - shift left 1 with LSB set to 0 to indicate write) // Send slave address and write bit uint8_t u8g_i2c_start(const uint8_t sla) { @@ -115,7 +82,6 @@ uint8_t u8g_i2c_send_byte(uint8_t data) { void u8g_i2c_stop() { } - #ifdef __cplusplus } #endif diff --git a/Marlin/src/HAL/SAMD51/endstop_interrupts.h b/Marlin/src/HAL/SAMD51/endstop_interrupts.h index 61a06c0d4b..2f02f404f5 100644 --- a/Marlin/src/HAL/SAMD51/endstop_interrupts.h +++ b/Marlin/src/HAL/SAMD51/endstop_interrupts.h @@ -60,6 +60,12 @@ #define MATCH_J_MIN_EILINE(P) TERN0(HAS_J_MIN, DEFER4(MATCH_EILINE)(P, J_MIN_PIN)) #define MATCH_K_MAX_EILINE(P) TERN0(HAS_K_MAX, DEFER4(MATCH_EILINE)(P, K_MAX_PIN)) #define MATCH_K_MIN_EILINE(P) TERN0(HAS_K_MIN, DEFER4(MATCH_EILINE)(P, K_MIN_PIN)) +#define MATCH_U_MAX_EILINE(P) TERN0(HAS_U_MAX, DEFER4(MATCH_EILINE)(P, U_MAX_PIN)) +#define MATCH_U_MIN_EILINE(P) TERN0(HAS_U_MIN, DEFER4(MATCH_EILINE)(P, U_MIN_PIN)) +#define MATCH_V_MAX_EILINE(P) TERN0(HAS_V_MAX, DEFER4(MATCH_EILINE)(P, V_MAX_PIN)) +#define MATCH_V_MIN_EILINE(P) TERN0(HAS_V_MIN, DEFER4(MATCH_EILINE)(P, V_MIN_PIN)) +#define MATCH_W_MAX_EILINE(P) TERN0(HAS_W_MAX, DEFER4(MATCH_EILINE)(P, W_MAX_PIN)) +#define MATCH_W_MIN_EILINE(P) TERN0(HAS_W_MIN, DEFER4(MATCH_EILINE)(P, W_MIN_PIN)) #define MATCH_Z2_MAX_EILINE(P) TERN0(HAS_Z2_MAX, DEFER4(MATCH_EILINE)(P, Z2_MAX_PIN)) #define MATCH_Z2_MIN_EILINE(P) TERN0(HAS_Z2_MIN, DEFER4(MATCH_EILINE)(P, Z2_MIN_PIN)) #define MATCH_Z3_MAX_EILINE(P) TERN0(HAS_Z3_MAX, DEFER4(MATCH_EILINE)(P, Z3_MAX_PIN)) @@ -75,6 +81,9 @@ && !MATCH_I_MAX_EILINE(P) && !MATCH_I_MIN_EILINE(P) \ && !MATCH_J_MAX_EILINE(P) && !MATCH_J_MIN_EILINE(P) \ && !MATCH_K_MAX_EILINE(P) && !MATCH_K_MIN_EILINE(P) \ + && !MATCH_U_MAX_EILINE(P) && !MATCH_U_MIN_EILINE(P) \ + && !MATCH_V_MAX_EILINE(P) && !MATCH_V_MIN_EILINE(P) \ + && !MATCH_W_MAX_EILINE(P) && !MATCH_W_MIN_EILINE(P) \ && !MATCH_Z2_MAX_EILINE(P) && !MATCH_Z2_MIN_EILINE(P) \ && !MATCH_Z3_MAX_EILINE(P) && !MATCH_Z3_MIN_EILINE(P) \ && !MATCH_Z4_MAX_EILINE(P) && !MATCH_Z4_MIN_EILINE(P) \ @@ -199,4 +208,40 @@ void setup_endstop_interrupts() { #endif attachInterrupt(K_MIN_PIN, endstop_ISR, CHANGE); #endif + #if HAS_U_MAX + #if !AVAILABLE_EILINE(U_MAX_PIN) + #error "U_MAX_PIN has no EXTINT line available." + #endif + attachInterrupt(U_MAX_PIN, endstop_ISR, CHANGE); + #endif + #if HAS_U_MIN + #if !AVAILABLE_EILINE(U_MIN_PIN) + #error "U_MIN_PIN has no EXTINT line available." + #endif + attachInterrupt(U_MIN_PIN, endstop_ISR, CHANGE); + #endif + #if HAS_V_MAX + #if !AVAILABLE_EILINE(V_MAX_PIN) + #error "V_MAX_PIN has no EXTINT line available." + #endif + attachInterrupt(V_MAX_PIN, endstop_ISR, CHANGE); + #endif + #if HAS_V_MIN + #if !AVAILABLE_EILINE(V_MIN_PIN) + #error "V_MIN_PIN has no EXTINT line available." + #endif + attachInterrupt(V_MIN_PIN, endstop_ISR, CHANGE); + #endif + #if HAS_W_MAX + #if !AVAILABLE_EILINE(W_MAX_PIN) + #error "W_MAX_PIN has no EXTINT line available." + #endif + attachInterrupt(W_MAX_PIN, endstop_ISR, CHANGE); + #endif + #if HAS_W_MIN + #if !AVAILABLE_EILINE(W_MIN_PIN) + #error "W_MIN_PIN has no EXTINT line available." + #endif + attachInterrupt(W_MIN_PIN, endstop_ISR, CHANGE); + #endif } diff --git a/Marlin/src/HAL/STM32/endstop_interrupts.h b/Marlin/src/HAL/STM32/endstop_interrupts.h index 90870881fe..d2f20ba1c7 100644 --- a/Marlin/src/HAL/STM32/endstop_interrupts.h +++ b/Marlin/src/HAL/STM32/endstop_interrupts.h @@ -52,4 +52,10 @@ void setup_endstop_interrupts() { TERN_(HAS_J_MIN, _ATTACH(J_MIN_PIN)); TERN_(HAS_K_MAX, _ATTACH(K_MAX_PIN)); TERN_(HAS_K_MIN, _ATTACH(K_MIN_PIN)); + TERN_(HAS_U_MAX, _ATTACH(U_MAX_PIN)); + TERN_(HAS_U_MIN, _ATTACH(U_MIN_PIN)); + TERN_(HAS_V_MAX, _ATTACH(V_MAX_PIN)); + TERN_(HAS_V_MIN, _ATTACH(V_MIN_PIN)); + TERN_(HAS_W_MAX, _ATTACH(W_MAX_PIN)); + TERN_(HAS_W_MIN, _ATTACH(W_MIN_PIN)); } diff --git a/Marlin/src/HAL/STM32F1/HAL.h b/Marlin/src/HAL/STM32F1/HAL.h index 8fbb43c602..ceb17b4884 100644 --- a/Marlin/src/HAL/STM32F1/HAL.h +++ b/Marlin/src/HAL/STM32F1/HAL.h @@ -177,7 +177,7 @@ typedef int8_t pin_t; // ------------------------ #define CRITICAL_SECTION_START() const bool irqon = !__get_primask(); (void)__iCliRetVal() -#define CRITICAL_SECTION_END() if (!primask) (void)__iSeiRetVal() +#define CRITICAL_SECTION_END() if (!irqon) (void)__iSeiRetVal() #define cli() noInterrupts() #define sei() interrupts() diff --git a/Marlin/src/HAL/STM32F1/endstop_interrupts.h b/Marlin/src/HAL/STM32F1/endstop_interrupts.h index 4d7edb9496..a1ef8a8c3a 100644 --- a/Marlin/src/HAL/STM32F1/endstop_interrupts.h +++ b/Marlin/src/HAL/STM32F1/endstop_interrupts.h @@ -77,4 +77,10 @@ void setup_endstop_interrupts() { TERN_(HAS_J_MIN, _ATTACH(J_MIN_PIN)); TERN_(HAS_K_MAX, _ATTACH(K_MAX_PIN)); TERN_(HAS_K_MIN, _ATTACH(K_MIN_PIN)); + TERN_(HAS_U_MAX, _ATTACH(U_MAX_PIN)); + TERN_(HAS_U_MIN, _ATTACH(U_MIN_PIN)); + TERN_(HAS_V_MAX, _ATTACH(V_MAX_PIN)); + TERN_(HAS_V_MIN, _ATTACH(V_MIN_PIN)); + TERN_(HAS_W_MAX, _ATTACH(W_MAX_PIN)); + TERN_(HAS_W_MIN, _ATTACH(W_MIN_PIN)); } diff --git a/Marlin/src/HAL/TEENSY31_32/endstop_interrupts.h b/Marlin/src/HAL/TEENSY31_32/endstop_interrupts.h index 9c7e210488..c1bbcb121b 100644 --- a/Marlin/src/HAL/TEENSY31_32/endstop_interrupts.h +++ b/Marlin/src/HAL/TEENSY31_32/endstop_interrupts.h @@ -70,4 +70,10 @@ void setup_endstop_interrupts() { TERN_(HAS_J_MIN, _ATTACH(J_MIN_PIN)); TERN_(HAS_K_MAX, _ATTACH(K_MAX_PIN)); TERN_(HAS_K_MIN, _ATTACH(K_MIN_PIN)); + TERN_(HAS_U_MAX, _ATTACH(U_MAX_PIN)); + TERN_(HAS_U_MIN, _ATTACH(U_MIN_PIN)); + TERN_(HAS_V_MAX, _ATTACH(V_MAX_PIN)); + TERN_(HAS_V_MIN, _ATTACH(V_MIN_PIN)); + TERN_(HAS_W_MAX, _ATTACH(W_MAX_PIN)); + TERN_(HAS_W_MIN, _ATTACH(W_MIN_PIN)); } diff --git a/Marlin/src/HAL/TEENSY31_32/inc/SanityCheck.h b/Marlin/src/HAL/TEENSY31_32/inc/SanityCheck.h index 1efa76b1e9..dbce187673 100644 --- a/Marlin/src/HAL/TEENSY31_32/inc/SanityCheck.h +++ b/Marlin/src/HAL/TEENSY31_32/inc/SanityCheck.h @@ -40,3 +40,7 @@ #if ENABLED(POSTMORTEM_DEBUGGING) #error "POSTMORTEM_DEBUGGING is not yet supported on Teensy 3.1/3.2." #endif + +#if USING_PULLDOWNS + #error "PULLDOWN pin mode is not available on Teensy 3.1/3.2 boards." +#endif diff --git a/Marlin/src/HAL/TEENSY35_36/endstop_interrupts.h b/Marlin/src/HAL/TEENSY35_36/endstop_interrupts.h index a300248885..48d3bbbfa1 100644 --- a/Marlin/src/HAL/TEENSY35_36/endstop_interrupts.h +++ b/Marlin/src/HAL/TEENSY35_36/endstop_interrupts.h @@ -69,4 +69,10 @@ void setup_endstop_interrupts() { TERN_(HAS_J_MIN, _ATTACH(J_MIN_PIN)); TERN_(HAS_K_MAX, _ATTACH(K_MAX_PIN)); TERN_(HAS_K_MIN, _ATTACH(K_MIN_PIN)); + TERN_(HAS_U_MAX, _ATTACH(U_MAX_PIN)); + TERN_(HAS_U_MIN, _ATTACH(U_MIN_PIN)); + TERN_(HAS_V_MAX, _ATTACH(V_MAX_PIN)); + TERN_(HAS_V_MIN, _ATTACH(V_MIN_PIN)); + TERN_(HAS_W_MAX, _ATTACH(W_MAX_PIN)); + TERN_(HAS_W_MIN, _ATTACH(W_MIN_PIN)); } diff --git a/Marlin/src/HAL/TEENSY35_36/inc/SanityCheck.h b/Marlin/src/HAL/TEENSY35_36/inc/SanityCheck.h index eef2850550..3308707371 100644 --- a/Marlin/src/HAL/TEENSY35_36/inc/SanityCheck.h +++ b/Marlin/src/HAL/TEENSY35_36/inc/SanityCheck.h @@ -40,3 +40,7 @@ #if ENABLED(POSTMORTEM_DEBUGGING) #error "POSTMORTEM_DEBUGGING is not yet supported on Teensy 3.5/3.6." #endif + +#if USING_PULLDOWNS + #error "PULLDOWN pin mode is not available on Teensy 3.5/3.6 boards." +#endif diff --git a/Marlin/src/MarlinCore.cpp b/Marlin/src/MarlinCore.cpp index 4117d3f382..2570e6ebde 100644 --- a/Marlin/src/MarlinCore.cpp +++ b/Marlin/src/MarlinCore.cpp @@ -436,6 +436,9 @@ inline void manage_inactivity(const bool no_stepper_sleep=false) { TERN_(DISABLE_INACTIVE_I, stepper.disable_axis(I_AXIS)); TERN_(DISABLE_INACTIVE_J, stepper.disable_axis(J_AXIS)); TERN_(DISABLE_INACTIVE_K, stepper.disable_axis(K_AXIS)); + TERN_(DISABLE_INACTIVE_U, stepper.disable_axis(U_AXIS)); + TERN_(DISABLE_INACTIVE_V, stepper.disable_axis(V_AXIS)); + TERN_(DISABLE_INACTIVE_W, stepper.disable_axis(W_AXIS)); TERN_(DISABLE_INACTIVE_E, stepper.disable_e_steppers()); TERN_(AUTO_BED_LEVELING_UBL, ubl.steppers_were_disabled()); @@ -476,7 +479,7 @@ inline void manage_inactivity(const bool no_stepper_sleep=false) { #endif #if HAS_FREEZE_PIN - Stepper::frozen = !READ(FREEZE_PIN); + stepper.frozen = READ(FREEZE_PIN) == FREEZE_STATE; #endif #if HAS_HOME @@ -993,6 +996,15 @@ inline void tmc_standby_setup() { #if PIN_EXISTS(K_STDBY) SET_INPUT_PULLDOWN(K_STDBY_PIN); #endif + #if PIN_EXISTS(U_STDBY) + SET_INPUT_PULLDOWN(U_STDBY_PIN); + #endif + #if PIN_EXISTS(V_STDBY) + SET_INPUT_PULLDOWN(V_STDBY_PIN); + #endif + #if PIN_EXISTS(W_STDBY) + SET_INPUT_PULLDOWN(W_STDBY_PIN); + #endif #if PIN_EXISTS(E0_STDBY) SET_INPUT_PULLDOWN(E0_STDBY_PIN); #endif @@ -1166,9 +1178,13 @@ void setup() { #endif #endif - #if HAS_FREEZE_PIN + #if ENABLED(FREEZE_FEATURE) SETUP_LOG("FREEZE_PIN"); - SET_INPUT_PULLUP(FREEZE_PIN); + #if FREEZE_STATE + SET_INPUT_PULLDOWN(FREEZE_PIN); + #else + SET_INPUT_PULLUP(FREEZE_PIN); + #endif #endif #if HAS_SUICIDE diff --git a/Marlin/src/core/boards.h b/Marlin/src/core/boards.h index 3ec24e7760..d1cc971e51 100644 --- a/Marlin/src/core/boards.h +++ b/Marlin/src/core/boards.h @@ -364,6 +364,7 @@ #define BOARD_ZONESTAR_ZM3E4 4061 // Zonestar ZM3E4 V1 (STM32F103VC) #define BOARD_ZONESTAR_ZM3E4V2 4062 // Zonestar ZM3E4 V2 (STM32F103VC) #define BOARD_ERYONE_ERY32_MINI 4063 // Eryone Ery32 mini (STM32F103VE) +#define BOARD_PANDA_PI_V29 4064 // Panda Pi V2.9 - Standalone (STM32F103RC) // // ARM Cortex-M4F diff --git a/Marlin/src/core/drivers.h b/Marlin/src/core/drivers.h index 2e66cc9201..80262d513f 100644 --- a/Marlin/src/core/drivers.h +++ b/Marlin/src/core/drivers.h @@ -63,6 +63,9 @@ #define AXIS_DRIVER_TYPE_I(T) _AXIS_DRIVER_TYPE(I,T) #define AXIS_DRIVER_TYPE_J(T) _AXIS_DRIVER_TYPE(J,T) #define AXIS_DRIVER_TYPE_K(T) _AXIS_DRIVER_TYPE(K,T) +#define AXIS_DRIVER_TYPE_U(T) _AXIS_DRIVER_TYPE(U,T) +#define AXIS_DRIVER_TYPE_V(T) _AXIS_DRIVER_TYPE(V,T) +#define AXIS_DRIVER_TYPE_W(T) _AXIS_DRIVER_TYPE(W,T) #define AXIS_DRIVER_TYPE_X2(T) (EITHER(X_DUAL_STEPPER_DRIVERS, DUAL_X_CARRIAGE) && _AXIS_DRIVER_TYPE(X2,T)) #define AXIS_DRIVER_TYPE_Y2(T) (ENABLED(Y_DUAL_STEPPER_DRIVERS) && _AXIS_DRIVER_TYPE(Y2,T)) @@ -87,6 +90,7 @@ #define HAS_DRIVER(T) ( AXIS_DRIVER_TYPE_X(T) || AXIS_DRIVER_TYPE_Y(T) || AXIS_DRIVER_TYPE_Z(T) \ || AXIS_DRIVER_TYPE_I(T) || AXIS_DRIVER_TYPE_J(T) || AXIS_DRIVER_TYPE_K(T) \ + || AXIS_DRIVER_TYPE_U(T) || AXIS_DRIVER_TYPE_V(T) || AXIS_DRIVER_TYPE_W(T) \ || AXIS_DRIVER_TYPE_X2(T) || AXIS_DRIVER_TYPE_Y2(T) || AXIS_DRIVER_TYPE_Z2(T) \ || AXIS_DRIVER_TYPE_Z3(T) || AXIS_DRIVER_TYPE_Z4(T) || HAS_E_DRIVER(T) ) @@ -161,6 +165,7 @@ || AXIS_HAS_##T(Y) || AXIS_HAS_##T(Y2) \ || AXIS_HAS_##T(Z) || AXIS_HAS_##T(Z2) || AXIS_HAS_##T(Z3) || AXIS_HAS_##T(Z4) \ || AXIS_HAS_##T(I) || AXIS_HAS_##T(J) || AXIS_HAS_##T(K) \ + || AXIS_HAS_##T(U) || AXIS_HAS_##T(V) || AXIS_HAS_##T(W) \ || E_AXIS_HAS(T) ) #if ANY_AXIS_HAS(STEALTHCHOP) @@ -200,4 +205,4 @@ #define HAS_L64XX_NOT_L6474 1 #endif -#define AXIS_IS_L64XX(A) (AXIS_DRIVER_TYPE_##A(L6470) || AXIS_DRIVER_TYPE_##A(L6474) || AXIS_DRIVER_TYPE_##A(L6480) || AXIS_DRIVER_TYPE_##A(POWERSTEP01)) +#define AXIS_IS_L64XX(A) (AXIS_DRIVER_TYPE_##A(L6470) || AXIS_DRIVER_TYPE_##A(L6474) || AXIS_DRIVER_TYPE_##A(L6480) || AXIS_DRIVER_TYPE_##A(POWERSTEP01)) diff --git a/Marlin/src/core/language.h b/Marlin/src/core/language.h index 8e0784f70d..89c0babc25 100644 --- a/Marlin/src/core/language.h +++ b/Marlin/src/core/language.h @@ -444,6 +444,54 @@ #define STR_K "" #endif +#if HAS_U_AXIS + #if AXIS7_NAME == 'U' + #define STR_U "U" + #define STR_U_MIN "u_min" + #define STR_U_MAX "u_max" + #elif AXIS7_NAME == 'V' + #define STR_U "V" + #define STR_U_MIN "v_min" + #define STR_U_MAX "v_max" + #elif AXIS7_NAME == 'W' + #define STR_U "W" + #define STR_U_MIN "w_min" + #define STR_U_MAX "w_max" + #else + #error "AXIS7_NAME can only be one of 'U', 'V', or 'W'." + #endif +#else + #define STR_U "" +#endif + +#if HAS_V_AXIS + #if AXIS8_NAME == 'V' + #define STR_V "V" + #define STR_V_MIN "v_min" + #define STR_V_MAX "v_max" + #elif AXIS8_NAME == 'W' + #define STR_V "W" + #define STR_V_MIN "w_min" + #define STR_V_MAX "w_max" + #else + #error "AXIS8_NAME can only be one of 'V', or 'W'." + #endif +#else + #define STR_V "" +#endif + +#if HAS_W_AXIS + #if AXIS9_NAME == 'W' + #define STR_W "W" + #define STR_W_MIN "w_min" + #define STR_W_MAX "w_max" + #else + #error "AXIS9_NAME can only be 'W'." + #endif +#else + #define STR_W "" +#endif + #if EITHER(HAS_MARLINUI_HD44780, IS_TFTGLCD_PANEL) // Custom characters defined in the first 8 characters of the LCD diff --git a/Marlin/src/core/macros.h b/Marlin/src/core/macros.h index 31808586cf..629486d85f 100644 --- a/Marlin/src/core/macros.h +++ b/Marlin/src/core/macros.h @@ -39,24 +39,36 @@ #define _ISTOP_ 0x04 #define _JSTOP_ 0x05 #define _KSTOP_ 0x06 +#define _USTOP_ 0x07 +#define _VSTOP_ 0x08 +#define _WSTOP_ 0x09 #define _XMIN_ 0x11 #define _YMIN_ 0x12 #define _ZMIN_ 0x13 #define _IMIN_ 0x14 #define _JMIN_ 0x15 #define _KMIN_ 0x16 +#define _UMIN_ 0x17 +#define _VMIN_ 0x18 +#define _WMIN_ 0x19 #define _XMAX_ 0x21 #define _YMAX_ 0x22 #define _ZMAX_ 0x23 #define _IMAX_ 0x24 #define _JMAX_ 0x25 #define _KMAX_ 0x26 +#define _UMAX_ 0x27 +#define _VMAX_ 0x28 +#define _WMAX_ 0x29 #define _XDIAG_ 0x31 #define _YDIAG_ 0x32 #define _ZDIAG_ 0x33 #define _IDIAG_ 0x34 #define _JDIAG_ 0x35 #define _KDIAG_ 0x36 +#define _UDIAG_ 0x37 +#define _VDIAG_ 0x38 +#define _WDIAG_ 0x39 #define _E0DIAG_ 0xE0 #define _E1DIAG_ 0xE1 #define _E2DIAG_ 0xE2 @@ -350,7 +362,7 @@ #define _LIST_N(N,V...) LIST_##N(V) #define LIST_N(N,V...) _LIST_N(N,V) -#define LIST_N_1(N,K) _LIST_N(N,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K) +#define LIST_N_1(N,K) _LIST_N(N,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K) #define ARRAY_N(N,V...) { _LIST_N(N,V) } #define ARRAY_N_1(N,K) { LIST_N_1(N,K) } diff --git a/Marlin/src/core/multi_language.h b/Marlin/src/core/multi_language.h index 2106f946ac..a605a6f024 100644 --- a/Marlin/src/core/multi_language.h +++ b/Marlin/src/core/multi_language.h @@ -80,6 +80,9 @@ typedef const char Language_Str[]; #endif #define GET_TEXT_F(MSG) FPSTR(GET_TEXT(MSG)) +#define GET_EN_TEXT(MSG) GET_LANG(en)::MSG +#define GET_EN_TEXT_F(MSG) FPSTR(GET_EN_TEXT(MSG)) + #define GET_LANGUAGE_NAME(INDEX) GET_LANG(LCD_LANGUAGE_##INDEX)::LANGUAGE #define LANG_CHARSIZE GET_TEXT(CHARSIZE) #define USE_WIDE_GLYPH (LANG_CHARSIZE > 2) diff --git a/Marlin/src/core/serial.cpp b/Marlin/src/core/serial.cpp index 562cddbaa0..819b06968c 100644 --- a/Marlin/src/core/serial.cpp +++ b/Marlin/src/core/serial.cpp @@ -32,14 +32,18 @@ uint8_t marlin_debug_flags = MARLIN_DEBUG_NONE; // Commonly-used strings in serial output PGMSTR(NUL_STR, ""); PGMSTR(SP_P_STR, " P"); PGMSTR(SP_T_STR, " T"); PGMSTR(X_STR, "X"); PGMSTR(Y_STR, "Y"); PGMSTR(Z_STR, "Z"); PGMSTR(E_STR, "E"); +PGMSTR(U_STR, STR_U); PGMSTR(V_STR, STR_V); PGMSTR(W_STR, STR_W); PGMSTR(X_LBL, "X:"); PGMSTR(Y_LBL, "Y:"); PGMSTR(Z_LBL, "Z:"); PGMSTR(E_LBL, "E:"); +PGMSTR(U_LBL, STR_U ":"); PGMSTR(V_LBL, STR_V ":"); PGMSTR(W_LBL, STR_W ":"); PGMSTR(SP_A_STR, " A"); PGMSTR(SP_B_STR, " B"); PGMSTR(SP_C_STR, " C"); PGMSTR(SP_X_STR, " X"); PGMSTR(SP_Y_STR, " Y"); PGMSTR(SP_Z_STR, " Z"); PGMSTR(SP_E_STR, " E"); PGMSTR(SP_X_LBL, " X:"); PGMSTR(SP_Y_LBL, " Y:"); PGMSTR(SP_Z_LBL, " Z:"); PGMSTR(SP_E_LBL, " E:"); PGMSTR(I_STR, STR_I); PGMSTR(J_STR, STR_J); PGMSTR(K_STR, STR_K); PGMSTR(I_LBL, STR_I ":"); PGMSTR(J_LBL, STR_J ":"); PGMSTR(K_LBL, STR_K ":"); PGMSTR(SP_I_STR, " " STR_I); PGMSTR(SP_J_STR, " " STR_J); PGMSTR(SP_K_STR, " " STR_K); +PGMSTR(SP_U_STR, " " STR_U); PGMSTR(SP_V_STR, " " STR_V); PGMSTR(SP_W_STR, " " STR_W); PGMSTR(SP_I_LBL, " " STR_I ":"); PGMSTR(SP_J_LBL, " " STR_J ":"); PGMSTR(SP_K_LBL, " " STR_K ":"); +PGMSTR(SP_U_LBL, " " STR_U ":"); PGMSTR(SP_V_LBL, " " STR_V ":"); PGMSTR(SP_W_LBL, " " STR_W ":"); // Hook Meatpack if it's enabled on the first leaf #if ENABLED(MEATPACK_ON_SERIAL_PORT_1) @@ -102,10 +106,10 @@ void print_bin(uint16_t val) { } } -void print_pos(LINEAR_AXIS_ARGS(const_float_t), FSTR_P const prefix/*=nullptr*/, FSTR_P const suffix/*=nullptr*/) { +void print_pos(NUM_AXIS_ARGS(const_float_t), FSTR_P const prefix/*=nullptr*/, FSTR_P const suffix/*=nullptr*/) { if (prefix) serial_print(prefix); SERIAL_ECHOPGM_P( - LIST_N(DOUBLE(LINEAR_AXES), SP_X_STR, x, SP_Y_STR, y, SP_Z_STR, z, SP_I_STR, i, SP_J_STR, j, SP_K_STR, k) + LIST_N(DOUBLE(NUM_AXES), SP_X_STR, x, SP_Y_STR, y, SP_Z_STR, z, SP_I_STR, i, SP_J_STR, j, SP_K_STR, k, SP_U_STR, u, SP_V_STR, v, SP_W_STR, w) ); if (suffix) serial_print(suffix); else SERIAL_EOL(); } diff --git a/Marlin/src/core/serial.h b/Marlin/src/core/serial.h index 98e82b6d72..2998fe803f 100644 --- a/Marlin/src/core/serial.h +++ b/Marlin/src/core/serial.h @@ -29,17 +29,12 @@ #endif // Commonly-used strings in serial output -extern const char NUL_STR[], - SP_X_STR[], SP_Y_STR[], SP_Z_STR[], - SP_A_STR[], SP_B_STR[], SP_C_STR[], SP_E_STR[], - SP_X_LBL[], SP_Y_LBL[], SP_Z_LBL[], SP_E_LBL[], - SP_I_STR[], SP_J_STR[], SP_K_STR[], - SP_I_LBL[], SP_J_LBL[], SP_K_LBL[], - SP_P_STR[], SP_T_STR[], - X_STR[], Y_STR[], Z_STR[], E_STR[], - I_STR[], J_STR[], K_STR[], - X_LBL[], Y_LBL[], Z_LBL[], E_LBL[], - I_LBL[], J_LBL[], K_LBL[]; +extern const char NUL_STR[], SP_P_STR[], SP_T_STR[], + SP_A_STR[], SP_B_STR[], SP_C_STR[], + SP_X_STR[], SP_Y_STR[], SP_Z_STR[], SP_I_STR[], SP_J_STR[], SP_K_STR[], SP_U_STR[], SP_V_STR[], SP_W_STR[], SP_E_STR[], + SP_X_LBL[], SP_Y_LBL[], SP_Z_LBL[], SP_I_LBL[], SP_J_LBL[], SP_K_LBL[], SP_U_LBL[], SP_V_LBL[], SP_W_LBL[], SP_E_LBL[], + X_STR[], Y_STR[], Z_STR[], I_STR[], J_STR[], K_STR[], U_STR[], V_STR[], W_STR[], E_STR[], + X_LBL[], Y_LBL[], Z_LBL[], I_LBL[], J_LBL[], K_LBL[], U_LBL[], V_LBL[], W_LBL[], E_LBL[]; // // Debugging flags for use by M111 @@ -348,10 +343,10 @@ void serial_spaces(uint8_t count); void serial_offset(const_float_t v, const uint8_t sp=0); // For v==0 draw space (sp==1) or plus (sp==2) void print_bin(const uint16_t val); -void print_pos(LINEAR_AXIS_ARGS(const_float_t), FSTR_P const prefix=nullptr, FSTR_P const suffix=nullptr); +void print_pos(NUM_AXIS_ARGS(const_float_t), FSTR_P const prefix=nullptr, FSTR_P const suffix=nullptr); inline void print_pos(const xyz_pos_t &xyz, FSTR_P const prefix=nullptr, FSTR_P const suffix=nullptr) { - print_pos(LINEAR_AXIS_ELEM(xyz), prefix, suffix); + print_pos(NUM_AXIS_ELEM(xyz), prefix, suffix); } #define SERIAL_POS(SUFFIX,VAR) do { print_pos(VAR, F(" " STRINGIFY(VAR) "="), F(" : " SUFFIX "\n")); }while(0) diff --git a/Marlin/src/core/types.h b/Marlin/src/core/types.h index b95b595659..47a126f165 100644 --- a/Marlin/src/core/types.h +++ b/Marlin/src/core/types.h @@ -36,23 +36,33 @@ struct IF { typedef R type; }; template struct IF { typedef L type; }; -#define LINEAR_AXIS_GANG(V...) GANG_N(LINEAR_AXES, V) -#define LINEAR_AXIS_CODE(V...) CODE_N(LINEAR_AXES, V) -#define LINEAR_AXIS_LIST(V...) LIST_N(LINEAR_AXES, V) -#define LINEAR_AXIS_ARRAY(V...) { LINEAR_AXIS_LIST(V) } -#define LINEAR_AXIS_ARGS(T...) LINEAR_AXIS_LIST(T x, T y, T z, T i, T j, T k) -#define LINEAR_AXIS_ELEM(O) LINEAR_AXIS_LIST(O.x, O.y, O.z, O.i, O.j, O.k) -#define LINEAR_AXIS_DEFS(T,V) LINEAR_AXIS_LIST(T x=V, T y=V, T z=V, T i=V, T j=V, T k=V) +#define NUM_AXIS_GANG(V...) GANG_N(NUM_AXES, V) +#define NUM_AXIS_CODE(V...) CODE_N(NUM_AXES, V) +#define NUM_AXIS_LIST(V...) LIST_N(NUM_AXES, V) +#define NUM_AXIS_ARRAY(V...) { NUM_AXIS_LIST(V) } +#define NUM_AXIS_ARGS(T...) NUM_AXIS_LIST(T x, T y, T z, T i, T j, T k, T u, T v, T w) +#define NUM_AXIS_ELEM(O) NUM_AXIS_LIST(O.x, O.y, O.z, O.i, O.j, O.k, O.u, O.v, O.w) +#define NUM_AXIS_DEFS(T,V) NUM_AXIS_LIST(T x=V, T y=V, T z=V, T i=V, T j=V, T k=V, T u=V, T v=V, T w=V) -#define LOGICAL_AXIS_GANG(E,V...) LINEAR_AXIS_GANG(V) GANG_ITEM_E(E) -#define LOGICAL_AXIS_CODE(E,V...) LINEAR_AXIS_CODE(V) CODE_ITEM_E(E) -#define LOGICAL_AXIS_LIST(E,V...) LINEAR_AXIS_LIST(V) LIST_ITEM_E(E) +#define LOGICAL_AXIS_GANG(E,V...) NUM_AXIS_GANG(V) GANG_ITEM_E(E) +#define LOGICAL_AXIS_CODE(E,V...) NUM_AXIS_CODE(V) CODE_ITEM_E(E) +#define LOGICAL_AXIS_LIST(E,V...) NUM_AXIS_LIST(V) LIST_ITEM_E(E) #define LOGICAL_AXIS_ARRAY(E,V...) { LOGICAL_AXIS_LIST(E,V) } -#define LOGICAL_AXIS_ARGS(T...) LOGICAL_AXIS_LIST(T e, T x, T y, T z, T i, T j, T k) -#define LOGICAL_AXIS_ELEM(O) LOGICAL_AXIS_LIST(O.e, O.x, O.y, O.z, O.i, O.j, O.k) -#define LOGICAL_AXIS_DECL(T,V) LOGICAL_AXIS_LIST(T e=V, T x=V, T y=V, T z=V, T i=V, T j=V, T k=V) +#define LOGICAL_AXIS_ARGS(T...) LOGICAL_AXIS_LIST(T e, T x, T y, T z, T i, T j, T k, T u, T v, T w) +#define LOGICAL_AXIS_ELEM(O) LOGICAL_AXIS_LIST(O.e, O.x, O.y, O.z, O.i, O.j, O.k, O.u, O.v, O.w) +#define LOGICAL_AXIS_DECL(T,V) LOGICAL_AXIS_LIST(T e=V, T x=V, T y=V, T z=V, T i=V, T j=V, T k=V, T u=V, T v=V, T w=V) -#define LOGICAL_AXES_STRING LOGICAL_AXIS_GANG("E", "X", "Y", "Z", STR_I, STR_J, STR_K) +#define LOGICAL_AXES_STRING LOGICAL_AXIS_GANG("E", "X", "Y", "Z", STR_I, STR_J, STR_K, STR_U, STR_V, STR_W) + +#define XYZ_GANG(V...) GANG_N(PRIMARY_LINEAR_AXES, V) +#define XYZ_CODE(V...) CODE_N(PRIMARY_LINEAR_AXES, V) + +#define SECONDARY_AXIS_GANG(V...) GANG_N(SECONDARY_AXES, V) +#define SECONDARY_AXIS_CODE(V...) CODE_N(SECONDARY_AXES, V) + +#if HAS_ROTATIONAL_AXES + #define ROTATIONAL_AXIS_GANG(V...) GANG_N(ROTATIONAL_AXES, V) +#endif #if HAS_EXTRUDERS #define LIST_ITEM_E(N) , N @@ -64,7 +74,7 @@ struct IF { typedef L type; }; #define GANG_ITEM_E(N) #endif -#define AXIS_COLLISION(L) (AXIS4_NAME == L || AXIS5_NAME == L || AXIS6_NAME == L) +#define AXIS_COLLISION(L) (AXIS4_NAME == L || AXIS5_NAME == L || AXIS6_NAME == L || AXIS7_NAME == L || AXIS8_NAME == L || AXIS9_NAME == L) // // Enumerated axis indices @@ -76,7 +86,7 @@ struct IF { typedef L type; }; enum AxisEnum : uint8_t { // Linear axes may be controlled directly or indirectly - LINEAR_AXIS_LIST(X_AXIS, Y_AXIS, Z_AXIS, I_AXIS, J_AXIS, K_AXIS) + NUM_AXIS_LIST(X_AXIS, Y_AXIS, Z_AXIS, I_AXIS, J_AXIS, K_AXIS, U_AXIS, V_AXIS, W_AXIS) // Extruder axes may be considered distinctly #define _EN_ITEM(N) , E##N##_AXIS @@ -110,14 +120,16 @@ enum AxisEnum : uint8_t { }; typedef IF<(NUM_AXIS_ENUMS > 8), uint16_t, uint8_t>::type axis_bits_t; +typedef IF<(NUM_AXES > 8), uint16_t, uint8_t>::type linear_axis_bits_t; // // Loop over axes // #define LOOP_ABC(VAR) LOOP_S_LE_N(VAR, A_AXIS, C_AXIS) -#define LOOP_LINEAR_AXES(VAR) LOOP_S_L_N(VAR, X_AXIS, LINEAR_AXES) +#define LOOP_NUM_AXES(VAR) LOOP_S_L_N(VAR, X_AXIS, NUM_AXES) #define LOOP_LOGICAL_AXES(VAR) LOOP_S_L_N(VAR, X_AXIS, LOGICAL_AXES) #define LOOP_DISTINCT_AXES(VAR) LOOP_S_L_N(VAR, X_AXIS, DISTINCT_AXES) +#define LOOP_DISTINCT_E(VAR) LOOP_L_N(VAR, DISTINCT_E) // // feedRate_t is just a humble float @@ -128,6 +140,7 @@ typedef float feedRate_t; // celsius_t is the native unit of temperature. Signed to handle a disconnected thermistor value (-14). // For more resolition (e.g., for a chocolate printer) this may later be changed to Celsius x 100 // +typedef uint16_t raw_adc_t; typedef int16_t celsius_t; typedef float celsius_float_t; @@ -258,10 +271,10 @@ struct XYval { FI void set(const T px, const T py) { x = px; y = py; } FI void set(const T (&arr)[XY]) { x = arr[0]; y = arr[1]; } #endif - #if LINEAR_AXES > XY - FI void set(const T (&arr)[LINEAR_AXES]) { x = arr[0]; y = arr[1]; } + #if NUM_AXES > XY + FI void set(const T (&arr)[NUM_AXES]) { x = arr[0]; y = arr[1]; } #endif - #if LOGICAL_AXES > LINEAR_AXES + #if LOGICAL_AXES > NUM_AXES FI void set(const T (&arr)[LOGICAL_AXES]) { x = arr[0]; y = arr[1]; } #if DISTINCT_AXES > LOGICAL_AXES FI void set(const T (&arr)[DISTINCT_AXES]) { x = arr[0]; y = arr[1]; } @@ -383,60 +396,69 @@ struct XYval { template struct XYZval { union { - struct { T LINEAR_AXIS_ARGS(); }; - struct { T LINEAR_AXIS_LIST(a, b, c, u, v, w); }; - T pos[LINEAR_AXES]; + struct { T NUM_AXIS_ARGS(); }; + struct { T NUM_AXIS_LIST(a, b, c, _i, _j, _k, _u, _v, _w); }; + T pos[NUM_AXES]; }; // Set all to 0 - FI void reset() { LINEAR_AXIS_GANG(x =, y =, z =, i =, j =, k =) 0; } + FI void reset() { NUM_AXIS_GANG(x =, y =, z =, i =, j =, k =, u =, v =, w =) 0; } // Setters taking struct types and arrays FI void set(const T px) { x = px; } FI void set(const T px, const T py) { x = px; y = py; } FI void set(const XYval pxy) { x = pxy.x; y = pxy.y; } - FI void set(const XYval pxy, const T pz) { LINEAR_AXIS_CODE(x = pxy.x, y = pxy.y, z = pz, NOOP, NOOP, NOOP); } + FI void set(const XYval pxy, const T pz) { NUM_AXIS_CODE(x = pxy.x, y = pxy.y, z = pz, NOOP, NOOP, NOOP, NOOP, NOOP, NOOP); } FI void set(const T (&arr)[XY]) { x = arr[0]; y = arr[1]; } #if HAS_Z_AXIS - FI void set(const T (&arr)[LINEAR_AXES]) { LINEAR_AXIS_CODE(x = arr[0], y = arr[1], z = arr[2], i = arr[3], j = arr[4], k = arr[5]); } - FI void set(LINEAR_AXIS_ARGS(const T)) { LINEAR_AXIS_CODE(a = x, b = y, c = z, u = i, v = j, w = k ); } + FI void set(const T (&arr)[NUM_AXES]) { NUM_AXIS_CODE(x = arr[0], y = arr[1], z = arr[2], i = arr[3], j = arr[4], k = arr[5], u = arr[6], v = arr[7], w = arr[8]); } + FI void set(NUM_AXIS_ARGS(const T)) { NUM_AXIS_CODE(a = x, b = y, c = z, _i = i, _j = j, _k = k, _u = u, _v = v, _w = w ); } #endif - #if LOGICAL_AXES > LINEAR_AXES - FI void set(const T (&arr)[LOGICAL_AXES]) { LINEAR_AXIS_CODE(x = arr[0], y = arr[1], z = arr[2], i = arr[3], j = arr[4], k = arr[5]); } - FI void set(LOGICAL_AXIS_ARGS(const T)) { LINEAR_AXIS_CODE(a = x, b = y, c = z, u = i, v = j, w = k ); } + #if LOGICAL_AXES > NUM_AXES + FI void set(const T (&arr)[LOGICAL_AXES]) { NUM_AXIS_CODE(x = arr[0], y = arr[1], z = arr[2], i = arr[3], j = arr[4], k = arr[5], u = arr[6], v = arr[7], w = arr[8]); } + FI void set(LOGICAL_AXIS_ARGS(const T)) { NUM_AXIS_CODE(a = x, b = y, c = z, _i = i, _j = j, _k = k, _u = u, _v = v, _w = w ); } #if DISTINCT_AXES > LOGICAL_AXES - FI void set(const T (&arr)[DISTINCT_AXES]) { LINEAR_AXIS_CODE(x = arr[0], y = arr[1], z = arr[2], i = arr[3], j = arr[4], k = arr[5]); } + FI void set(const T (&arr)[DISTINCT_AXES]) { NUM_AXIS_CODE(x = arr[0], y = arr[1], z = arr[2], i = arr[3], j = arr[4], k = arr[5], u = arr[6], v = arr[7], w = arr[8]); } #endif #endif #if HAS_I_AXIS - FI void set(const T px, const T py, const T pz) { x = px; y = py; z = pz; } + FI void set(const T px, const T py, const T pz) { x = px; y = py; z = pz; } #endif #if HAS_J_AXIS - FI void set(const T px, const T py, const T pz, const T pi) { x = px; y = py; z = pz; i = pi; } + FI void set(const T px, const T py, const T pz, const T pi) { x = px; y = py; z = pz; i = pi; } #endif #if HAS_K_AXIS FI void set(const T px, const T py, const T pz, const T pi, const T pj) { x = px; y = py; z = pz; i = pi; j = pj; } #endif + #if HAS_U_AXIS + FI void set(const T px, const T py, const T pz, const T pi, const T pj, const T pk) { x = px; y = py; z = pz; i = pi; j = pj; k = pk; } + #endif + #if HAS_V_AXIS + FI void set(const T px, const T py, const T pz, const T pi, const T pj, const T pk, const T pm) { x = px; y = py; z = pz; i = pi; j = pj; k = pk; u = pu; } + #endif + #if HAS_W_AXIS + FI void set(const T px, const T py, const T pz, const T pi, const T pj, const T pk, const T pm, const T po) { x = px; y = py; z = pz; i = pi; j = pj; k = pk; u = pu; v = pv; } + #endif // Length reduced to one dimension - FI T magnitude() const { return (T)sqrtf(LINEAR_AXIS_GANG(x*x, + y*y, + z*z, + i*i, + j*j, + k*k)); } + FI T magnitude() const { return (T)sqrtf(NUM_AXIS_GANG(x*x, + y*y, + z*z, + i*i, + j*j, + k*k, + u*u, + v*v, + w*w)); } // Pointer to the data as a simple array FI operator T* () { return pos; } // If any element is true then it's true - FI operator bool() { return LINEAR_AXIS_GANG(x, || y, || z, || i, || j, || k); } + FI operator bool() { return NUM_AXIS_GANG(x, || y, || z, || i, || j, || k, || u, || v, || w); } // Explicit copy and copies with conversion FI XYZval copy() const { XYZval o = *this; return o; } - FI XYZval ABS() const { return LINEAR_AXIS_ARRAY(T(_ABS(x)), T(_ABS(y)), T(_ABS(z)), T(_ABS(i)), T(_ABS(j)), T(_ABS(k))); } - FI XYZval asInt() { return LINEAR_AXIS_ARRAY(int16_t(x), int16_t(y), int16_t(z), int16_t(i), int16_t(j), int16_t(k)); } - FI XYZval asInt() const { return LINEAR_AXIS_ARRAY(int16_t(x), int16_t(y), int16_t(z), int16_t(i), int16_t(j), int16_t(k)); } - FI XYZval asLong() { return LINEAR_AXIS_ARRAY(int32_t(x), int32_t(y), int32_t(z), int32_t(i), int32_t(j), int32_t(k)); } - FI XYZval asLong() const { return LINEAR_AXIS_ARRAY(int32_t(x), int32_t(y), int32_t(z), int32_t(i), int32_t(j), int32_t(k)); } - FI XYZval ROUNDL() { return LINEAR_AXIS_ARRAY(int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z)), int32_t(LROUND(i)), int32_t(LROUND(j)), int32_t(LROUND(k))); } - FI XYZval ROUNDL() const { return LINEAR_AXIS_ARRAY(int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z)), int32_t(LROUND(i)), int32_t(LROUND(j)), int32_t(LROUND(k))); } - FI XYZval asFloat() { return LINEAR_AXIS_ARRAY(static_cast(x), static_cast(y), static_cast(z), static_cast(i), static_cast(j), static_cast(k)); } - FI XYZval asFloat() const { return LINEAR_AXIS_ARRAY(static_cast(x), static_cast(y), static_cast(z), static_cast(i), static_cast(j), static_cast(k)); } - FI XYZval reciprocal() const { return LINEAR_AXIS_ARRAY(_RECIP(x), _RECIP(y), _RECIP(z), _RECIP(i), _RECIP(j), _RECIP(k)); } + FI XYZval ABS() const { return NUM_AXIS_ARRAY(T(_ABS(x)), T(_ABS(y)), T(_ABS(z)), T(_ABS(i)), T(_ABS(j)), T(_ABS(k)), T(_ABS(u)), T(_ABS(v)), T(_ABS(w))); } + FI XYZval asInt() { return NUM_AXIS_ARRAY(int16_t(x), int16_t(y), int16_t(z), int16_t(i), int16_t(j), int16_t(k), int16_t(u), int16_t(v), int16_t(w)); } + FI XYZval asInt() const { return NUM_AXIS_ARRAY(int16_t(x), int16_t(y), int16_t(z), int16_t(i), int16_t(j), int16_t(k), int16_t(u), int16_t(v), int16_t(w)); } + FI XYZval asLong() { return NUM_AXIS_ARRAY(int32_t(x), int32_t(y), int32_t(z), int32_t(i), int32_t(j), int32_t(k), int32_t(u), int32_t(v), int32_t(w)); } + FI XYZval asLong() const { return NUM_AXIS_ARRAY(int32_t(x), int32_t(y), int32_t(z), int32_t(i), int32_t(j), int32_t(k), int32_t(u), int32_t(v), int32_t(w)); } + FI XYZval ROUNDL() { return NUM_AXIS_ARRAY(int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z)), int32_t(LROUND(i)), int32_t(LROUND(j)), int32_t(LROUND(k)), int32_t(LROUND(u)), int32_t(LROUND(v)), int32_t(LROUND(w))); } + FI XYZval ROUNDL() const { return NUM_AXIS_ARRAY(int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z)), int32_t(LROUND(i)), int32_t(LROUND(j)), int32_t(LROUND(k)), int32_t(LROUND(u)), int32_t(LROUND(v)), int32_t(LROUND(w))); } + FI XYZval asFloat() { return NUM_AXIS_ARRAY(static_cast(x), static_cast(y), static_cast(z), static_cast(i), static_cast(j), static_cast(k), static_cast(u), static_cast(v), static_cast(w)); } + FI XYZval asFloat() const { return NUM_AXIS_ARRAY(static_cast(x), static_cast(y), static_cast(z), static_cast(i), static_cast(j), static_cast(k), static_cast(u), static_cast(v), static_cast(w)); } + FI XYZval reciprocal() const { return NUM_AXIS_ARRAY(_RECIP(x), _RECIP(y), _RECIP(z), _RECIP(i), _RECIP(j), _RECIP(k), _RECIP(u), _RECIP(v), _RECIP(w)); } // Marlin workspace shifting is done with G92 and M206 FI XYZval asLogical() const { XYZval o = asFloat(); toLogical(o); return o; } @@ -447,78 +469,78 @@ struct XYZval { FI operator const XYval&() const { return *(const XYval*)this; } // Cast to a type with more fields by making a new object - FI operator XYZEval() const { return LINEAR_AXIS_ARRAY(x, y, z, i, j, k); } + FI operator XYZEval() const { return NUM_AXIS_ARRAY(x, y, z, i, j, k, u, v, w); } // Accessor via an AxisEnum (or any integer) [index] FI T& operator[](const int n) { return pos[n]; } FI const T& operator[](const int n) const { return pos[n]; } // Assignment operator overrides do the expected thing - FI XYZval& operator= (const T v) { set(ARRAY_N_1(LINEAR_AXES, v)); return *this; } + FI XYZval& operator= (const T v) { set(ARRAY_N_1(NUM_AXES, v)); return *this; } FI XYZval& operator= (const XYval &rs) { set(rs.x, rs.y ); return *this; } - FI XYZval& operator= (const XYZEval &rs) { set(LINEAR_AXIS_ELEM(rs)); return *this; } + FI XYZval& operator= (const XYZEval &rs) { set(NUM_AXIS_ELEM(rs)); return *this; } // Override other operators to get intuitive behaviors - FI XYZval operator+ (const XYval &rs) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, NOOP , NOOP , NOOP , NOOP ); return ls; } - FI XYZval operator+ (const XYval &rs) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, NOOP , NOOP , NOOP , NOOP ); return ls; } - FI XYZval operator- (const XYval &rs) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, NOOP , NOOP , NOOP , NOOP ); return ls; } - FI XYZval operator- (const XYval &rs) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, NOOP , NOOP , NOOP , NOOP ); return ls; } - FI XYZval operator* (const XYval &rs) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, NOOP , NOOP , NOOP , NOOP ); return ls; } - FI XYZval operator* (const XYval &rs) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, NOOP , NOOP , NOOP , NOOP ); return ls; } - FI XYZval operator/ (const XYval &rs) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, NOOP , NOOP , NOOP , NOOP ); return ls; } - FI XYZval operator/ (const XYval &rs) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, NOOP , NOOP , NOOP , NOOP ); return ls; } - FI XYZval operator+ (const XYZval &rs) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k); return ls; } - FI XYZval operator+ (const XYZval &rs) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k); return ls; } - FI XYZval operator- (const XYZval &rs) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k); return ls; } - FI XYZval operator- (const XYZval &rs) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k); return ls; } - FI XYZval operator* (const XYZval &rs) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k); return ls; } - FI XYZval operator* (const XYZval &rs) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k); return ls; } - FI XYZval operator/ (const XYZval &rs) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k); return ls; } - FI XYZval operator/ (const XYZval &rs) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k); return ls; } - FI XYZval operator+ (const XYZEval &rs) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k); return ls; } - FI XYZval operator+ (const XYZEval &rs) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k); return ls; } - FI XYZval operator- (const XYZEval &rs) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k); return ls; } - FI XYZval operator- (const XYZEval &rs) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k); return ls; } - FI XYZval operator* (const XYZEval &rs) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k); return ls; } - FI XYZval operator* (const XYZEval &rs) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k); return ls; } - FI XYZval operator/ (const XYZEval &rs) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k); return ls; } - FI XYZval operator/ (const XYZEval &rs) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k); return ls; } - FI XYZval operator* (const float &v) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x *= v, ls.y *= v, ls.z *= v, ls.i *= v, ls.j *= v, ls.k *= v ); return ls; } - FI XYZval operator* (const float &v) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x *= v, ls.y *= v, ls.z *= v, ls.i *= v, ls.j *= v, ls.k *= v ); return ls; } - FI XYZval operator* (const int &v) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x *= v, ls.y *= v, ls.z *= v, ls.i *= v, ls.j *= v, ls.k *= v ); return ls; } - FI XYZval operator* (const int &v) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x *= v, ls.y *= v, ls.z *= v, ls.i *= v, ls.j *= v, ls.k *= v ); return ls; } - FI XYZval operator/ (const float &v) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x /= v, ls.y /= v, ls.z /= v, ls.i /= v, ls.j /= v, ls.k /= v ); return ls; } - FI XYZval operator/ (const float &v) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x /= v, ls.y /= v, ls.z /= v, ls.i /= v, ls.j /= v, ls.k /= v ); return ls; } - FI XYZval operator/ (const int &v) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x /= v, ls.y /= v, ls.z /= v, ls.i /= v, ls.j /= v, ls.k /= v ); return ls; } - FI XYZval operator/ (const int &v) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x /= v, ls.y /= v, ls.z /= v, ls.i /= v, ls.j /= v, ls.k /= v ); return ls; } - FI XYZval operator>>(const int &v) const { XYZval ls = *this; LINEAR_AXIS_CODE(_RS(ls.x), _RS(ls.y), _RS(ls.z), _RS(ls.i), _RS(ls.j), _RS(ls.k) ); return ls; } - FI XYZval operator>>(const int &v) { XYZval ls = *this; LINEAR_AXIS_CODE(_RS(ls.x), _RS(ls.y), _RS(ls.z), _RS(ls.i), _RS(ls.j), _RS(ls.k) ); return ls; } - FI XYZval operator<<(const int &v) const { XYZval ls = *this; LINEAR_AXIS_CODE(_LS(ls.x), _LS(ls.y), _LS(ls.z), _LS(ls.i), _LS(ls.j), _LS(ls.k) ); return ls; } - FI XYZval operator<<(const int &v) { XYZval ls = *this; LINEAR_AXIS_CODE(_LS(ls.x), _LS(ls.y), _LS(ls.z), _LS(ls.i), _LS(ls.j), _LS(ls.k) ); return ls; } - FI const XYZval operator-() const { XYZval o = *this; LINEAR_AXIS_CODE(o.x = -x, o.y = -y, o.z = -z, o.i = -i, o.j = -j, o.k = -k); return o; } - FI XYZval operator-() { XYZval o = *this; LINEAR_AXIS_CODE(o.x = -x, o.y = -y, o.z = -z, o.i = -i, o.j = -j, o.k = -k); return o; } + FI XYZval operator+ (const XYval &rs) const { XYZval ls = *this; NUM_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, NOOP , NOOP , NOOP , NOOP , NOOP , NOOP , NOOP ); return ls; } + FI XYZval operator+ (const XYval &rs) { XYZval ls = *this; NUM_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, NOOP , NOOP , NOOP , NOOP , NOOP , NOOP , NOOP ); return ls; } + FI XYZval operator- (const XYval &rs) const { XYZval ls = *this; NUM_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, NOOP , NOOP , NOOP , NOOP , NOOP , NOOP , NOOP ); return ls; } + FI XYZval operator- (const XYval &rs) { XYZval ls = *this; NUM_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, NOOP , NOOP , NOOP , NOOP , NOOP , NOOP , NOOP ); return ls; } + FI XYZval operator* (const XYval &rs) const { XYZval ls = *this; NUM_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, NOOP , NOOP , NOOP , NOOP , NOOP , NOOP , NOOP ); return ls; } + FI XYZval operator* (const XYval &rs) { XYZval ls = *this; NUM_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, NOOP , NOOP , NOOP , NOOP , NOOP , NOOP , NOOP ); return ls; } + FI XYZval operator/ (const XYval &rs) const { XYZval ls = *this; NUM_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, NOOP , NOOP , NOOP , NOOP , NOOP , NOOP , NOOP ); return ls; } + FI XYZval operator/ (const XYval &rs) { XYZval ls = *this; NUM_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, NOOP , NOOP , NOOP , NOOP , NOOP , NOOP , NOOP ); return ls; } + FI XYZval operator+ (const XYZval &rs) const { XYZval ls = *this; NUM_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k, ls.u += rs.u, ls.v += rs.v, ls.w += rs.w); return ls; } + FI XYZval operator+ (const XYZval &rs) { XYZval ls = *this; NUM_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k, ls.u += rs.u, ls.v += rs.v, ls.w += rs.w); return ls; } + FI XYZval operator- (const XYZval &rs) const { XYZval ls = *this; NUM_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k, ls.u -= rs.u, ls.v -= rs.v, ls.w -= rs.w); return ls; } + FI XYZval operator- (const XYZval &rs) { XYZval ls = *this; NUM_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k, ls.u -= rs.u, ls.v -= rs.v, ls.w -= rs.w); return ls; } + FI XYZval operator* (const XYZval &rs) const { XYZval ls = *this; NUM_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k, ls.u *= rs.u, ls.v *= rs.v, ls.w *= rs.w); return ls; } + FI XYZval operator* (const XYZval &rs) { XYZval ls = *this; NUM_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k, ls.u *= rs.u, ls.v *= rs.v, ls.w *= rs.w); return ls; } + FI XYZval operator/ (const XYZval &rs) const { XYZval ls = *this; NUM_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k, ls.u /= rs.u, ls.v /= rs.v, ls.w /= rs.w); return ls; } + FI XYZval operator/ (const XYZval &rs) { XYZval ls = *this; NUM_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k, ls.u /= rs.u, ls.v /= rs.v, ls.w /= rs.w); return ls; } + FI XYZval operator+ (const XYZEval &rs) const { XYZval ls = *this; NUM_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k, ls.u += rs.u, ls.v += rs.v, ls.w += rs.w); return ls; } + FI XYZval operator+ (const XYZEval &rs) { XYZval ls = *this; NUM_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k, ls.u += rs.u, ls.v += rs.v, ls.w += rs.w); return ls; } + FI XYZval operator- (const XYZEval &rs) const { XYZval ls = *this; NUM_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k, ls.u -= rs.u, ls.v -= rs.v, ls.w -= rs.w); return ls; } + FI XYZval operator- (const XYZEval &rs) { XYZval ls = *this; NUM_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k, ls.u -= rs.u, ls.v -= rs.v, ls.w -= rs.w); return ls; } + FI XYZval operator* (const XYZEval &rs) const { XYZval ls = *this; NUM_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k, ls.u *= rs.u, ls.v *= rs.v, ls.w *= rs.w); return ls; } + FI XYZval operator* (const XYZEval &rs) { XYZval ls = *this; NUM_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k, ls.u *= rs.u, ls.v *= rs.v, ls.w *= rs.w); return ls; } + FI XYZval operator/ (const XYZEval &rs) const { XYZval ls = *this; NUM_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k, ls.u /= rs.u, ls.v /= rs.v, ls.w /= rs.w); return ls; } + FI XYZval operator/ (const XYZEval &rs) { XYZval ls = *this; NUM_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k, ls.u /= rs.u, ls.v /= rs.v, ls.w /= rs.w); return ls; } + FI XYZval operator* (const float &v) const { XYZval ls = *this; NUM_AXIS_CODE(ls.x *= v, ls.y *= v, ls.z *= v, ls.i *= v, ls.j *= v, ls.k *= v, ls.u *= v, ls.v *= v, ls.w *= v ); return ls; } + FI XYZval operator* (const float &v) { XYZval ls = *this; NUM_AXIS_CODE(ls.x *= v, ls.y *= v, ls.z *= v, ls.i *= v, ls.j *= v, ls.k *= v, ls.u *= v, ls.v *= v, ls.w *= v ); return ls; } + FI XYZval operator* (const int &v) const { XYZval ls = *this; NUM_AXIS_CODE(ls.x *= v, ls.y *= v, ls.z *= v, ls.i *= v, ls.j *= v, ls.k *= v, ls.u *= v, ls.v *= v, ls.w *= v ); return ls; } + FI XYZval operator* (const int &v) { XYZval ls = *this; NUM_AXIS_CODE(ls.x *= v, ls.y *= v, ls.z *= v, ls.i *= v, ls.j *= v, ls.k *= v, ls.u *= v, ls.v *= v, ls.w *= v ); return ls; } + FI XYZval operator/ (const float &v) const { XYZval ls = *this; NUM_AXIS_CODE(ls.x /= v, ls.y /= v, ls.z /= v, ls.i /= v, ls.j /= v, ls.k /= v, ls.u /= v, ls.v /= v, ls.w /= v ); return ls; } + FI XYZval operator/ (const float &v) { XYZval ls = *this; NUM_AXIS_CODE(ls.x /= v, ls.y /= v, ls.z /= v, ls.i /= v, ls.j /= v, ls.k /= v, ls.u /= v, ls.v /= v, ls.w /= v ); return ls; } + FI XYZval operator/ (const int &v) const { XYZval ls = *this; NUM_AXIS_CODE(ls.x /= v, ls.y /= v, ls.z /= v, ls.i /= v, ls.j /= v, ls.k /= v, ls.u /= v, ls.v /= v, ls.w /= v ); return ls; } + FI XYZval operator/ (const int &v) { XYZval ls = *this; NUM_AXIS_CODE(ls.x /= v, ls.y /= v, ls.z /= v, ls.i /= v, ls.j /= v, ls.k /= v, ls.u /= v, ls.v /= v, ls.w /= v ); return ls; } + FI XYZval operator>>(const int &v) const { XYZval ls = *this; NUM_AXIS_CODE(_RS(ls.x), _RS(ls.y), _RS(ls.z), _RS(ls.i), _RS(ls.j), _RS(ls.k), _RS(ls.u), _RS(ls.v), _RS(ls.w) ); return ls; } + FI XYZval operator>>(const int &v) { XYZval ls = *this; NUM_AXIS_CODE(_RS(ls.x), _RS(ls.y), _RS(ls.z), _RS(ls.i), _RS(ls.j), _RS(ls.k), _RS(ls.u), _RS(ls.v), _RS(ls.w) ); return ls; } + FI XYZval operator<<(const int &v) const { XYZval ls = *this; NUM_AXIS_CODE(_LS(ls.x), _LS(ls.y), _LS(ls.z), _LS(ls.i), _LS(ls.j), _LS(ls.k), _LS(ls.u), _LS(ls.v), _LS(ls.w) ); return ls; } + FI XYZval operator<<(const int &v) { XYZval ls = *this; NUM_AXIS_CODE(_LS(ls.x), _LS(ls.y), _LS(ls.z), _LS(ls.i), _LS(ls.j), _LS(ls.k), _LS(ls.u), _LS(ls.v), _LS(ls.w) ); return ls; } + FI const XYZval operator-() const { XYZval o = *this; NUM_AXIS_CODE(o.x = -x, o.y = -y, o.z = -z, o.i = -i, o.j = -j, o.k = -k, o.u = -u, o.v = -v, o.w = -w); return o; } + FI XYZval operator-() { XYZval o = *this; NUM_AXIS_CODE(o.x = -x, o.y = -y, o.z = -z, o.i = -i, o.j = -j, o.k = -k, o.u = -u, o.v = -v, o.w = -w); return o; } // Modifier operators - FI XYZval& operator+=(const XYval &rs) { LINEAR_AXIS_CODE(x += rs.x, y += rs.y, NOOP, NOOP, NOOP, NOOP ); return *this; } - FI XYZval& operator-=(const XYval &rs) { LINEAR_AXIS_CODE(x -= rs.x, y -= rs.y, NOOP, NOOP, NOOP, NOOP ); return *this; } - FI XYZval& operator*=(const XYval &rs) { LINEAR_AXIS_CODE(x *= rs.x, y *= rs.y, NOOP, NOOP, NOOP, NOOP ); return *this; } - FI XYZval& operator/=(const XYval &rs) { LINEAR_AXIS_CODE(x /= rs.x, y /= rs.y, NOOP, NOOP, NOOP, NOOP ); return *this; } - FI XYZval& operator+=(const XYZval &rs) { LINEAR_AXIS_CODE(x += rs.x, y += rs.y, z += rs.z, i += rs.i, j += rs.j, k += rs.k); return *this; } - FI XYZval& operator-=(const XYZval &rs) { LINEAR_AXIS_CODE(x -= rs.x, y -= rs.y, z -= rs.z, i -= rs.i, j -= rs.j, k -= rs.k); return *this; } - FI XYZval& operator*=(const XYZval &rs) { LINEAR_AXIS_CODE(x *= rs.x, y *= rs.y, z *= rs.z, i *= rs.i, j *= rs.j, k *= rs.k); return *this; } - FI XYZval& operator/=(const XYZval &rs) { LINEAR_AXIS_CODE(x /= rs.x, y /= rs.y, z /= rs.z, i /= rs.i, j /= rs.j, k /= rs.k); return *this; } - FI XYZval& operator+=(const XYZEval &rs) { LINEAR_AXIS_CODE(x += rs.x, y += rs.y, z += rs.z, i += rs.i, j += rs.j, k += rs.k); return *this; } - FI XYZval& operator-=(const XYZEval &rs) { LINEAR_AXIS_CODE(x -= rs.x, y -= rs.y, z -= rs.z, i -= rs.i, j -= rs.j, k -= rs.k); return *this; } - FI XYZval& operator*=(const XYZEval &rs) { LINEAR_AXIS_CODE(x *= rs.x, y *= rs.y, z *= rs.z, i *= rs.i, j *= rs.j, k *= rs.k); return *this; } - FI XYZval& operator/=(const XYZEval &rs) { LINEAR_AXIS_CODE(x /= rs.x, y /= rs.y, z /= rs.z, i /= rs.i, j /= rs.j, k /= rs.k); return *this; } - FI XYZval& operator*=(const float &v) { LINEAR_AXIS_CODE(x *= v, y *= v, z *= v, i *= v, j *= v, k *= v); return *this; } - FI XYZval& operator*=(const int &v) { LINEAR_AXIS_CODE(x *= v, y *= v, z *= v, i *= v, j *= v, k *= v); return *this; } - FI XYZval& operator>>=(const int &v) { LINEAR_AXIS_CODE(_RS(x), _RS(y), _RS(z), _RS(i), _RS(j), _RS(k)); return *this; } - FI XYZval& operator<<=(const int &v) { LINEAR_AXIS_CODE(_LS(x), _LS(y), _LS(z), _LS(i), _LS(j), _LS(k)); return *this; } + FI XYZval& operator+=(const XYval &rs) { NUM_AXIS_CODE(x += rs.x, y += rs.y, NOOP, NOOP, NOOP, NOOP, NOOP, NOOP, NOOP ); return *this; } + FI XYZval& operator-=(const XYval &rs) { NUM_AXIS_CODE(x -= rs.x, y -= rs.y, NOOP, NOOP, NOOP, NOOP, NOOP, NOOP, NOOP ); return *this; } + FI XYZval& operator*=(const XYval &rs) { NUM_AXIS_CODE(x *= rs.x, y *= rs.y, NOOP, NOOP, NOOP, NOOP, NOOP, NOOP, NOOP ); return *this; } + FI XYZval& operator/=(const XYval &rs) { NUM_AXIS_CODE(x /= rs.x, y /= rs.y, NOOP, NOOP, NOOP, NOOP, NOOP, NOOP, NOOP ); return *this; } + FI XYZval& operator+=(const XYZval &rs) { NUM_AXIS_CODE(x += rs.x, y += rs.y, z += rs.z, i += rs.i, j += rs.j, k += rs.k, u += rs.u, v += rs.v, w += rs.w); return *this; } + FI XYZval& operator-=(const XYZval &rs) { NUM_AXIS_CODE(x -= rs.x, y -= rs.y, z -= rs.z, i -= rs.i, j -= rs.j, k -= rs.k, u -= rs.u, v -= rs.v, w -= rs.w); return *this; } + FI XYZval& operator*=(const XYZval &rs) { NUM_AXIS_CODE(x *= rs.x, y *= rs.y, z *= rs.z, i *= rs.i, j *= rs.j, k *= rs.k, u *= rs.u, v *= rs.v, w *= rs.w); return *this; } + FI XYZval& operator/=(const XYZval &rs) { NUM_AXIS_CODE(x /= rs.x, y /= rs.y, z /= rs.z, i /= rs.i, j /= rs.j, k /= rs.k, u /= rs.u, v /= rs.v, w /= rs.w); return *this; } + FI XYZval& operator+=(const XYZEval &rs) { NUM_AXIS_CODE(x += rs.x, y += rs.y, z += rs.z, i += rs.i, j += rs.j, k += rs.k, u += rs.u, v += rs.v, w += rs.w); return *this; } + FI XYZval& operator-=(const XYZEval &rs) { NUM_AXIS_CODE(x -= rs.x, y -= rs.y, z -= rs.z, i -= rs.i, j -= rs.j, k -= rs.k, u -= rs.u, v -= rs.v, w -= rs.w); return *this; } + FI XYZval& operator*=(const XYZEval &rs) { NUM_AXIS_CODE(x *= rs.x, y *= rs.y, z *= rs.z, i *= rs.i, j *= rs.j, k *= rs.k, u *= rs.u, v *= rs.v, w *= rs.w); return *this; } + FI XYZval& operator/=(const XYZEval &rs) { NUM_AXIS_CODE(x /= rs.x, y /= rs.y, z /= rs.z, i /= rs.i, j /= rs.j, k /= rs.k, u /= rs.u, v /= rs.v, w /= rs.w); return *this; } + FI XYZval& operator*=(const float &v) { NUM_AXIS_CODE(x *= v, y *= v, z *= v, i *= v, j *= v, k *= v, u *= v, v *= v, w *= v); return *this; } + FI XYZval& operator*=(const int &v) { NUM_AXIS_CODE(x *= v, y *= v, z *= v, i *= v, j *= v, k *= v, u *= v, v *= v, w *= v); return *this; } + FI XYZval& operator>>=(const int &v) { NUM_AXIS_CODE(_RS(x), _RS(y), _RS(z), _RS(i), _RS(j), _RS(k), _RS(u), _RS(v), _RS(w)); return *this; } + FI XYZval& operator<<=(const int &v) { NUM_AXIS_CODE(_LS(x), _LS(y), _LS(z), _LS(i), _LS(j), _LS(k), _LS(u), _LS(v), _LS(w)); return *this; } // Exact comparisons. For floats a "NEAR" operation may be better. - FI bool operator==(const XYZEval &rs) { return true LINEAR_AXIS_GANG(&& x == rs.x, && y == rs.y, && z == rs.z, && i == rs.i, && j == rs.j, && k == rs.k); } - FI bool operator==(const XYZEval &rs) const { return true LINEAR_AXIS_GANG(&& x == rs.x, && y == rs.y, && z == rs.z, && i == rs.i, && j == rs.j, && k == rs.k); } + FI bool operator==(const XYZEval &rs) { return true NUM_AXIS_GANG(&& x == rs.x, && y == rs.y, && z == rs.z, && i == rs.i, && j == rs.j, && k == rs.k, && u == rs.u, && v == rs.v, && w == rs.w); } + FI bool operator==(const XYZEval &rs) const { return true NUM_AXIS_GANG(&& x == rs.x, && y == rs.y, && z == rs.z, && i == rs.i, && j == rs.j, && k == rs.k, && u == rs.u, && v == rs.v, && w == rs.w); } FI bool operator!=(const XYZEval &rs) { return !operator==(rs); } FI bool operator!=(const XYZEval &rs) const { return !operator==(rs); } }; @@ -530,56 +552,66 @@ template struct XYZEval { union { struct { T LOGICAL_AXIS_ARGS(); }; - struct { T LOGICAL_AXIS_LIST(_e, a, b, c, u, v, w); }; + struct { T LOGICAL_AXIS_LIST(_e, a, b, c, _i, _j, _k, _u, _v, _w); }; T pos[LOGICAL_AXES]; }; // Reset all to 0 - FI void reset() { LOGICAL_AXIS_GANG(e =, x =, y =, z =, i =, j =, k =) 0; } + FI void reset() { LOGICAL_AXIS_GANG(e =, x =, y =, z =, i =, j =, k =, u =, v =, w =) 0; } // Setters for some number of linear axes, not all - FI void set(const T px) { x = px; } - FI void set(const T px, const T py) { x = px; y = py; } + FI void set(const T px) { x = px; } + FI void set(const T px, const T py) { x = px; y = py; } #if HAS_I_AXIS - FI void set(const T px, const T py, const T pz) { x = px; y = py; z = pz; } + FI void set(const T px, const T py, const T pz) { x = px; y = py; z = pz; } #endif #if HAS_J_AXIS - FI void set(const T px, const T py, const T pz, const T pi) { x = px; y = py; z = pz; i = pi; } + FI void set(const T px, const T py, const T pz, const T pi) { x = px; y = py; z = pz; i = pi; } #endif #if HAS_K_AXIS - FI void set(const T px, const T py, const T pz, const T pi, const T pj) { x = px; y = py; z = pz; i = pi; j = pj; } + FI void set(const T px, const T py, const T pz, const T pi, const T pj) { x = px; y = py; z = pz; i = pi; j = pj; } #endif + #if HAS_U_AXIS + FI void set(const T px, const T py, const T pz, const T pi, const T pj, const T pk) { x = px; y = py; z = pz; i = pi; j = pj; k = pk; } + #endif + #if HAS_V_AXIS + FI void set(const T px, const T py, const T pz, const T pi, const T pj, const T pk, const T pm) { x = px; y = py; z = pz; i = pi; j = pj; k = pk; u = pu; } + #endif + #if HAS_W_AXIS + FI void set(const T px, const T py, const T pz, const T pi, const T pj, const T pk, const T pm, const T po) { x = px; y = py; z = pz; i = pi; j = pj; k = pk; u = pm; v = pv; } + #endif + // Setters taking struct types and arrays - FI void set(const XYval pxy) { x = pxy.x; y = pxy.y; } - FI void set(const XYZval pxyz) { set(LINEAR_AXIS_ELEM(pxyz)); } + FI void set(const XYval pxy) { x = pxy.x; y = pxy.y; } + FI void set(const XYZval pxyz) { set(NUM_AXIS_ELEM(pxyz)); } #if HAS_Z_AXIS - FI void set(LINEAR_AXIS_ARGS(const T)) { LINEAR_AXIS_CODE(a = x, b = y, c = z, u = i, v = j, w = k); } + FI void set(NUM_AXIS_ARGS(const T)) { NUM_AXIS_CODE(a = x, b = y, c = z, _i = i, _j = j, _k = k, _u = u, _v = v, _w = w); } #endif - FI void set(const XYval pxy, const T pz) { set(pxy); TERN_(HAS_Z_AXIS, z = pz); } - #if LOGICAL_AXES > LINEAR_AXES + FI void set(const XYval pxy, const T pz) { set(pxy); TERN_(HAS_Z_AXIS, z = pz); } + #if LOGICAL_AXES > NUM_AXES FI void set(const XYval pxy, const T pz, const T pe) { set(pxy, pz); e = pe; } - FI void set(const XYZval pxyz, const T pe) { set(pxyz); e = pe; } - FI void set(LOGICAL_AXIS_ARGS(const T)) { LOGICAL_AXIS_CODE(_e = e, a = x, b = y, c = z, u = i, v = j, w = k); } + FI void set(const XYZval pxyz, const T pe) { set(pxyz); e = pe; } + FI void set(LOGICAL_AXIS_ARGS(const T)) { LOGICAL_AXIS_CODE(_e = e, a = x, b = y, c = z, _i = i, _j = j, _k = k, _u = u, _v = v, _w = w); } #endif // Length reduced to one dimension - FI T magnitude() const { return (T)sqrtf(LOGICAL_AXIS_GANG(+ e*e, + x*x, + y*y, + z*z, + i*i, + j*j, + k*k)); } + FI T magnitude() const { return (T)sqrtf(LOGICAL_AXIS_GANG(+ e*e, + x*x, + y*y, + z*z, + i*i, + j*j, + k*k, + u*u, + v*v, + w*w)); } // Pointer to the data as a simple array FI operator T* () { return pos; } // If any element is true then it's true - FI operator bool() { return 0 LOGICAL_AXIS_GANG(|| e, || x, || y, || z, || i, || j, || k); } + FI operator bool() { return 0 LOGICAL_AXIS_GANG(|| e, || x, || y, || z, || i, || j, || k, || u, || v, || w); } // Explicit copy and copies with conversion - FI XYZEval copy() const { XYZEval o = *this; return o; } - FI XYZEval ABS() const { return LOGICAL_AXIS_ARRAY(T(_ABS(e)), T(_ABS(x)), T(_ABS(y)), T(_ABS(z)), T(_ABS(i)), T(_ABS(j)), T(_ABS(k))); } - FI XYZEval asInt() { return LOGICAL_AXIS_ARRAY(int16_t(e), int16_t(x), int16_t(y), int16_t(z), int16_t(i), int16_t(j), int16_t(k)); } - FI XYZEval asInt() const { return LOGICAL_AXIS_ARRAY(int16_t(e), int16_t(x), int16_t(y), int16_t(z), int16_t(i), int16_t(j), int16_t(k)); } - FI XYZEval asLong() { return LOGICAL_AXIS_ARRAY(int32_t(e), int32_t(x), int32_t(y), int32_t(z), int32_t(i), int32_t(j), int32_t(k)); } - FI XYZEval asLong() const { return LOGICAL_AXIS_ARRAY(int32_t(e), int32_t(x), int32_t(y), int32_t(z), int32_t(i), int32_t(j), int32_t(k)); } - FI XYZEval ROUNDL() { return LOGICAL_AXIS_ARRAY(int32_t(LROUND(e)), int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z)), int32_t(LROUND(i)), int32_t(LROUND(j)), int32_t(LROUND(k))); } - FI XYZEval ROUNDL() const { return LOGICAL_AXIS_ARRAY(int32_t(LROUND(e)), int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z)), int32_t(LROUND(i)), int32_t(LROUND(j)), int32_t(LROUND(k))); } - FI XYZEval asFloat() { return LOGICAL_AXIS_ARRAY(static_cast(e), static_cast(x), static_cast(y), static_cast(z), static_cast(i), static_cast(j), static_cast(k)); } - FI XYZEval asFloat() const { return LOGICAL_AXIS_ARRAY(static_cast(e), static_cast(x), static_cast(y), static_cast(z), static_cast(i), static_cast(j), static_cast(k)); } - FI XYZEval reciprocal() const { return LOGICAL_AXIS_ARRAY(_RECIP(e), _RECIP(x), _RECIP(y), _RECIP(z), _RECIP(i), _RECIP(j), _RECIP(k)); } + FI XYZEval copy() const { XYZEval v = *this; return v; } + FI XYZEval ABS() const { return LOGICAL_AXIS_ARRAY(T(_ABS(e)), T(_ABS(x)), T(_ABS(y)), T(_ABS(z)), T(_ABS(i)), T(_ABS(j)), T(_ABS(k)), T(_ABS(u)), T(_ABS(v)), T(_ABS(w))); } + FI XYZEval asInt() { return LOGICAL_AXIS_ARRAY(int16_t(e), int16_t(x), int16_t(y), int16_t(z), int16_t(i), int16_t(j), int16_t(k), int16_t(u), int16_t(v), int16_t(w)); } + FI XYZEval asInt() const { return LOGICAL_AXIS_ARRAY(int16_t(e), int16_t(x), int16_t(y), int16_t(z), int16_t(i), int16_t(j), int16_t(k), int16_t(u), int16_t(v), int16_t(w)); } + FI XYZEval asLong() { return LOGICAL_AXIS_ARRAY(int32_t(e), int32_t(x), int32_t(y), int32_t(z), int32_t(i), int32_t(j), int32_t(k), int32_t(u), int32_t(v), int32_t(w)); } + FI XYZEval asLong() const { return LOGICAL_AXIS_ARRAY(int32_t(e), int32_t(x), int32_t(y), int32_t(z), int32_t(i), int32_t(j), int32_t(k), int32_t(u), int32_t(v), int32_t(w)); } + FI XYZEval ROUNDL() { return LOGICAL_AXIS_ARRAY(int32_t(LROUND(e)), int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z)), int32_t(LROUND(i)), int32_t(LROUND(j)), int32_t(LROUND(k)), int32_t(LROUND(u)), int32_t(LROUND(v)), int32_t(LROUND(w))); } + FI XYZEval ROUNDL() const { return LOGICAL_AXIS_ARRAY(int32_t(LROUND(e)), int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z)), int32_t(LROUND(i)), int32_t(LROUND(j)), int32_t(LROUND(k)), int32_t(LROUND(u)), int32_t(LROUND(v)), int32_t(LROUND(w))); } + FI XYZEval asFloat() { return LOGICAL_AXIS_ARRAY(static_cast(e), static_cast(x), static_cast(y), static_cast(z), static_cast(i), static_cast(j), static_cast(k), static_cast(u), static_cast(v), static_cast(w)); } + FI XYZEval asFloat() const { return LOGICAL_AXIS_ARRAY(static_cast(e), static_cast(x), static_cast(y), static_cast(z), static_cast(i), static_cast(j), static_cast(k), static_cast(u), static_cast(v), static_cast(w)); } + FI XYZEval reciprocal() const { return LOGICAL_AXIS_ARRAY(_RECIP(e), _RECIP(x), _RECIP(y), _RECIP(z), _RECIP(i), _RECIP(j), _RECIP(k), _RECIP(u), _RECIP(v), _RECIP(w)); } // Marlin workspace shifting is done with G92 and M206 FI XYZEval asLogical() const { XYZEval o = asFloat(); toLogical(o); return o; } @@ -596,9 +628,9 @@ struct XYZEval { FI const T& operator[](const int n) const { return pos[n]; } // Assignment operator overrides do the expected thing - FI XYZEval& operator= (const T v) { set(LIST_N_1(LINEAR_AXES, v)); return *this; } + FI XYZEval& operator= (const T v) { set(LIST_N_1(NUM_AXES, v)); return *this; } FI XYZEval& operator= (const XYval &rs) { set(rs.x, rs.y); return *this; } - FI XYZEval& operator= (const XYZval &rs) { set(LINEAR_AXIS_ELEM(rs)); return *this; } + FI XYZEval& operator= (const XYZval &rs) { set(NUM_AXIS_ELEM(rs)); return *this; } // Override other operators to get intuitive behaviors FI XYZEval operator+ (const XYval &rs) const { XYZEval ls = *this; ls.x += rs.x; ls.y += rs.y; return ls; } @@ -609,57 +641,57 @@ struct XYZEval { FI XYZEval operator* (const XYval &rs) { XYZEval ls = *this; ls.x *= rs.x; ls.y *= rs.y; return ls; } FI XYZEval operator/ (const XYval &rs) const { XYZEval ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; } FI XYZEval operator/ (const XYval &rs) { XYZEval ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; } - FI XYZEval operator+ (const XYZval &rs) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k); return ls; } - FI XYZEval operator+ (const XYZval &rs) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k); return ls; } - FI XYZEval operator- (const XYZval &rs) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k); return ls; } - FI XYZEval operator- (const XYZval &rs) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k); return ls; } - FI XYZEval operator* (const XYZval &rs) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k); return ls; } - FI XYZEval operator* (const XYZval &rs) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k); return ls; } - FI XYZEval operator/ (const XYZval &rs) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k); return ls; } - FI XYZEval operator/ (const XYZval &rs) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k); return ls; } - FI XYZEval operator+ (const XYZEval &rs) const { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e += rs.e, ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k); return ls; } - FI XYZEval operator+ (const XYZEval &rs) { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e += rs.e, ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k); return ls; } - FI XYZEval operator- (const XYZEval &rs) const { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e -= rs.e, ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k); return ls; } - FI XYZEval operator- (const XYZEval &rs) { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e -= rs.e, ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k); return ls; } - FI XYZEval operator* (const XYZEval &rs) const { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e *= rs.e, ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k); return ls; } - FI XYZEval operator* (const XYZEval &rs) { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e *= rs.e, ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k); return ls; } - FI XYZEval operator/ (const XYZEval &rs) const { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e /= rs.e, ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k); return ls; } - FI XYZEval operator/ (const XYZEval &rs) { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e /= rs.e, ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k); return ls; } - FI XYZEval operator* (const float &v) const { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e *= v, ls.x *= v, ls.y *= v, ls.z *= v, ls.i *= v, ls.j *= v, ls.k *= v ); return ls; } - FI XYZEval operator* (const float &v) { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e *= v, ls.x *= v, ls.y *= v, ls.z *= v, ls.i *= v, ls.j *= v, ls.k *= v ); return ls; } - FI XYZEval operator* (const int &v) const { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e *= v, ls.x *= v, ls.y *= v, ls.z *= v, ls.i *= v, ls.j *= v, ls.k *= v ); return ls; } - FI XYZEval operator* (const int &v) { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e *= v, ls.x *= v, ls.y *= v, ls.z *= v, ls.i *= v, ls.j *= v, ls.k *= v ); return ls; } - FI XYZEval operator/ (const float &v) const { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e /= v, ls.x /= v, ls.y /= v, ls.z /= v, ls.i /= v, ls.j /= v, ls.k /= v ); return ls; } - FI XYZEval operator/ (const float &v) { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e /= v, ls.x /= v, ls.y /= v, ls.z /= v, ls.i /= v, ls.j /= v, ls.k /= v ); return ls; } - FI XYZEval operator/ (const int &v) const { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e /= v, ls.x /= v, ls.y /= v, ls.z /= v, ls.i /= v, ls.j /= v, ls.k /= v ); return ls; } - FI XYZEval operator/ (const int &v) { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e /= v, ls.x /= v, ls.y /= v, ls.z /= v, ls.i /= v, ls.j /= v, ls.k /= v ); return ls; } - FI XYZEval operator>>(const int &v) const { XYZEval ls = *this; LOGICAL_AXIS_CODE(_RS(ls.e), _RS(ls.x), _RS(ls.y), _RS(ls.z), _RS(ls.i), _RS(ls.j), _RS(ls.k) ); return ls; } - FI XYZEval operator>>(const int &v) { XYZEval ls = *this; LOGICAL_AXIS_CODE(_RS(ls.e), _RS(ls.x), _RS(ls.y), _RS(ls.z), _RS(ls.i), _RS(ls.j), _RS(ls.k) ); return ls; } - FI XYZEval operator<<(const int &v) const { XYZEval ls = *this; LOGICAL_AXIS_CODE(_LS(ls.e), _LS(ls.x), _LS(ls.y), _LS(ls.z), _LS(ls.i), _LS(ls.j), _LS(ls.k) ); return ls; } - FI XYZEval operator<<(const int &v) { XYZEval ls = *this; LOGICAL_AXIS_CODE(_LS(ls.e), _LS(ls.x), _LS(ls.y), _LS(ls.z), _LS(ls.i), _LS(ls.j), _LS(ls.k) ); return ls; } - FI const XYZEval operator-() const { return LOGICAL_AXIS_ARRAY(-e, -x, -y, -z, -i, -j, -k); } - FI XYZEval operator-() { return LOGICAL_AXIS_ARRAY(-e, -x, -y, -z, -i, -j, -k); } + FI XYZEval operator+ (const XYZval &rs) const { XYZval ls = *this; NUM_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k, ls.u += rs.u, ls.v += rs.v, ls.w += rs.w); return ls; } + FI XYZEval operator+ (const XYZval &rs) { XYZval ls = *this; NUM_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k, ls.u += rs.u, ls.v += rs.v, ls.w += rs.w); return ls; } + FI XYZEval operator- (const XYZval &rs) const { XYZval ls = *this; NUM_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k, ls.u -= rs.u, ls.v -= rs.v, ls.w -= rs.w); return ls; } + FI XYZEval operator- (const XYZval &rs) { XYZval ls = *this; NUM_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k, ls.u -= rs.u, ls.v -= rs.v, ls.w -= rs.w); return ls; } + FI XYZEval operator* (const XYZval &rs) const { XYZval ls = *this; NUM_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k, ls.u *= rs.u, ls.v *= rs.v, ls.w *= rs.w); return ls; } + FI XYZEval operator* (const XYZval &rs) { XYZval ls = *this; NUM_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k, ls.u *= rs.u, ls.v *= rs.v, ls.w *= rs.w); return ls; } + FI XYZEval operator/ (const XYZval &rs) const { XYZval ls = *this; NUM_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k, ls.u /= rs.u, ls.v /= rs.v, ls.w /= rs.w); return ls; } + FI XYZEval operator/ (const XYZval &rs) { XYZval ls = *this; NUM_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k, ls.u /= rs.u, ls.v /= rs.v, ls.w /= rs.w); return ls; } + FI XYZEval operator+ (const XYZEval &rs) const { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e += rs.e, ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k, ls.u += rs.u, ls.v += rs.v, ls.w += rs.w); return ls; } + FI XYZEval operator+ (const XYZEval &rs) { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e += rs.e, ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k, ls.u += rs.u, ls.v += rs.v, ls.w += rs.w); return ls; } + FI XYZEval operator- (const XYZEval &rs) const { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e -= rs.e, ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k, ls.u -= rs.u, ls.v -= rs.v, ls.w -= rs.w); return ls; } + FI XYZEval operator- (const XYZEval &rs) { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e -= rs.e, ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k, ls.u -= rs.u, ls.v -= rs.v, ls.w -= rs.w); return ls; } + FI XYZEval operator* (const XYZEval &rs) const { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e *= rs.e, ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k, ls.u *= rs.u, ls.v *= rs.v, ls.w *= rs.w); return ls; } + FI XYZEval operator* (const XYZEval &rs) { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e *= rs.e, ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k, ls.u *= rs.u, ls.v *= rs.v, ls.w *= rs.w); return ls; } + FI XYZEval operator/ (const XYZEval &rs) const { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e /= rs.e, ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k, ls.u /= rs.u, ls.v /= rs.v, ls.w /= rs.w); return ls; } + FI XYZEval operator/ (const XYZEval &rs) { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e /= rs.e, ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k, ls.u /= rs.u, ls.v /= rs.v, ls.w /= rs.w); return ls; } + FI XYZEval operator* (const float &v) const { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e *= v, ls.x *= v, ls.y *= v, ls.z *= v, ls.i *= v, ls.j *= v, ls.k *= v, ls.u *= v, ls.v *= v, ls.w *= v ); return ls; } + FI XYZEval operator* (const float &v) { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e *= v, ls.x *= v, ls.y *= v, ls.z *= v, ls.i *= v, ls.j *= v, ls.k *= v, ls.u *= v, ls.v *= v, ls.w *= v ); return ls; } + FI XYZEval operator* (const int &v) const { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e *= v, ls.x *= v, ls.y *= v, ls.z *= v, ls.i *= v, ls.j *= v, ls.k *= v, ls.u *= v, ls.v *= v, ls.w *= v ); return ls; } + FI XYZEval operator* (const int &v) { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e *= v, ls.x *= v, ls.y *= v, ls.z *= v, ls.i *= v, ls.j *= v, ls.k *= v, ls.u *= v, ls.v *= v, ls.w *= v ); return ls; } + FI XYZEval operator/ (const float &v) const { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e /= v, ls.x /= v, ls.y /= v, ls.z /= v, ls.i /= v, ls.j /= v, ls.k /= v, ls.u /= v, ls.v /= v, ls.w /= v ); return ls; } + FI XYZEval operator/ (const float &v) { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e /= v, ls.x /= v, ls.y /= v, ls.z /= v, ls.i /= v, ls.j /= v, ls.k /= v, ls.u /= v, ls.v /= v, ls.w /= v ); return ls; } + FI XYZEval operator/ (const int &v) const { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e /= v, ls.x /= v, ls.y /= v, ls.z /= v, ls.i /= v, ls.j /= v, ls.k /= v, ls.u /= v, ls.v /= v, ls.w /= v ); return ls; } + FI XYZEval operator/ (const int &v) { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e /= v, ls.x /= v, ls.y /= v, ls.z /= v, ls.i /= v, ls.j /= v, ls.k /= v, ls.u /= v, ls.v /= v, ls.w /= v ); return ls; } + FI XYZEval operator>>(const int &v) const { XYZEval ls = *this; LOGICAL_AXIS_CODE(_RS(ls.e), _RS(ls.x), _RS(ls.y), _RS(ls.z), _RS(ls.i), _RS(ls.j), _RS(ls.k), _RS(ls.u), _RS(ls.v), _RS(ls.w) ); return ls; } + FI XYZEval operator>>(const int &v) { XYZEval ls = *this; LOGICAL_AXIS_CODE(_RS(ls.e), _RS(ls.x), _RS(ls.y), _RS(ls.z), _RS(ls.i), _RS(ls.j), _RS(ls.k), _RS(ls.u), _RS(ls.v), _RS(ls.w) ); return ls; } + FI XYZEval operator<<(const int &v) const { XYZEval ls = *this; LOGICAL_AXIS_CODE(_LS(ls.e), _LS(ls.x), _LS(ls.y), _LS(ls.z), _LS(ls.i), _LS(ls.j), _LS(ls.k), _LS(ls.u), _LS(ls.v), _LS(ls.w) ); return ls; } + FI XYZEval operator<<(const int &v) { XYZEval ls = *this; LOGICAL_AXIS_CODE(_LS(ls.e), _LS(ls.x), _LS(ls.y), _LS(ls.z), _LS(ls.i), _LS(ls.j), _LS(ls.k), _LS(ls.u), _LS(ls.v), _LS(ls.w) ); return ls; } + FI const XYZEval operator-() const { return LOGICAL_AXIS_ARRAY(-e, -x, -y, -z, -i, -j, -k, -u, -v, -w); } + FI XYZEval operator-() { return LOGICAL_AXIS_ARRAY(-e, -x, -y, -z, -i, -j, -k, -u, -v, -w); } // Modifier operators FI XYZEval& operator+=(const XYval &rs) { x += rs.x; y += rs.y; return *this; } FI XYZEval& operator-=(const XYval &rs) { x -= rs.x; y -= rs.y; return *this; } FI XYZEval& operator*=(const XYval &rs) { x *= rs.x; y *= rs.y; return *this; } FI XYZEval& operator/=(const XYval &rs) { x /= rs.x; y /= rs.y; return *this; } - FI XYZEval& operator+=(const XYZval &rs) { LINEAR_AXIS_CODE(x += rs.x, y += rs.y, z += rs.z, i += rs.i, j += rs.j, k += rs.k); return *this; } - FI XYZEval& operator-=(const XYZval &rs) { LINEAR_AXIS_CODE(x -= rs.x, y -= rs.y, z -= rs.z, i -= rs.i, j -= rs.j, k -= rs.k); return *this; } - FI XYZEval& operator*=(const XYZval &rs) { LINEAR_AXIS_CODE(x *= rs.x, y *= rs.y, z *= rs.z, i *= rs.i, j *= rs.j, k *= rs.k); return *this; } - FI XYZEval& operator/=(const XYZval &rs) { LINEAR_AXIS_CODE(x /= rs.x, y /= rs.y, z /= rs.z, i /= rs.i, j /= rs.j, k /= rs.k); return *this; } - FI XYZEval& operator+=(const XYZEval &rs) { LOGICAL_AXIS_CODE(e += rs.e, x += rs.x, y += rs.y, z += rs.z, i += rs.i, j += rs.j, k += rs.k); return *this; } - FI XYZEval& operator-=(const XYZEval &rs) { LOGICAL_AXIS_CODE(e -= rs.e, x -= rs.x, y -= rs.y, z -= rs.z, i -= rs.i, j -= rs.j, k -= rs.k); return *this; } - FI XYZEval& operator*=(const XYZEval &rs) { LOGICAL_AXIS_CODE(e *= rs.e, x *= rs.x, y *= rs.y, z *= rs.z, i *= rs.i, j *= rs.j, k *= rs.k); return *this; } - FI XYZEval& operator/=(const XYZEval &rs) { LOGICAL_AXIS_CODE(e /= rs.e, x /= rs.x, y /= rs.y, z /= rs.z, i /= rs.i, j /= rs.j, k /= rs.k); return *this; } - FI XYZEval& operator*=(const T &v) { LOGICAL_AXIS_CODE(e *= v, x *= v, y *= v, z *= v, i *= v, j *= v, k *= v); return *this; } - FI XYZEval& operator>>=(const int &v) { LOGICAL_AXIS_CODE(_RS(e), _RS(x), _RS(y), _RS(z), _RS(i), _RS(j), _RS(k)); return *this; } - FI XYZEval& operator<<=(const int &v) { LOGICAL_AXIS_CODE(_LS(e), _LS(x), _LS(y), _LS(z), _LS(i), _LS(j), _LS(k)); return *this; } + FI XYZEval& operator+=(const XYZval &rs) { NUM_AXIS_CODE(x += rs.x, y += rs.y, z += rs.z, i += rs.i, j += rs.j, k += rs.k, u += rs.u, v += rs.v, w += rs.w); return *this; } + FI XYZEval& operator-=(const XYZval &rs) { NUM_AXIS_CODE(x -= rs.x, y -= rs.y, z -= rs.z, i -= rs.i, j -= rs.j, k -= rs.k, u -= rs.u, v -= rs.v, w -= rs.w); return *this; } + FI XYZEval& operator*=(const XYZval &rs) { NUM_AXIS_CODE(x *= rs.x, y *= rs.y, z *= rs.z, i *= rs.i, j *= rs.j, k *= rs.k, u *= rs.u, v *= rs.v, w *= rs.w); return *this; } + FI XYZEval& operator/=(const XYZval &rs) { NUM_AXIS_CODE(x /= rs.x, y /= rs.y, z /= rs.z, i /= rs.i, j /= rs.j, k /= rs.k, u /= rs.u, v /= rs.v, w /= rs.w); return *this; } + FI XYZEval& operator+=(const XYZEval &rs) { LOGICAL_AXIS_CODE(e += rs.e, x += rs.x, y += rs.y, z += rs.z, i += rs.i, j += rs.j, k += rs.k, u += rs.u, v += rs.v, w += rs.w); return *this; } + FI XYZEval& operator-=(const XYZEval &rs) { LOGICAL_AXIS_CODE(e -= rs.e, x -= rs.x, y -= rs.y, z -= rs.z, i -= rs.i, j -= rs.j, k -= rs.k, u -= rs.u, v -= rs.v, w -= rs.w); return *this; } + FI XYZEval& operator*=(const XYZEval &rs) { LOGICAL_AXIS_CODE(e *= rs.e, x *= rs.x, y *= rs.y, z *= rs.z, i *= rs.i, j *= rs.j, k *= rs.k, u *= rs.u, v *= rs.v, w *= rs.w); return *this; } + FI XYZEval& operator/=(const XYZEval &rs) { LOGICAL_AXIS_CODE(e /= rs.e, x /= rs.x, y /= rs.y, z /= rs.z, i /= rs.i, j /= rs.j, k /= rs.k, u /= rs.u, v /= rs.v, w /= rs.w); return *this; } + FI XYZEval& operator*=(const T &v) { LOGICAL_AXIS_CODE(e *= v, x *= v, y *= v, z *= v, i *= v, j *= v, k *= v, u *= v, v *= v, w *= v); return *this; } + FI XYZEval& operator>>=(const int &v) { LOGICAL_AXIS_CODE(_RS(e), _RS(x), _RS(y), _RS(z), _RS(i), _RS(j), _RS(k), _RS(u), _RS(v), _RS(w)); return *this; } + FI XYZEval& operator<<=(const int &v) { LOGICAL_AXIS_CODE(_LS(e), _LS(x), _LS(y), _LS(z), _LS(i), _LS(j), _LS(k), _LS(u), _LS(v), _LS(w)); return *this; } // Exact comparisons. For floats a "NEAR" operation may be better. - FI bool operator==(const XYZval &rs) { return true LINEAR_AXIS_GANG(&& x == rs.x, && y == rs.y, && z == rs.z, && i == rs.i, && j == rs.j, && k == rs.k); } - FI bool operator==(const XYZval &rs) const { return true LINEAR_AXIS_GANG(&& x == rs.x, && y == rs.y, && z == rs.z, && i == rs.i, && j == rs.j, && k == rs.k); } + FI bool operator==(const XYZval &rs) { return true NUM_AXIS_GANG(&& x == rs.x, && y == rs.y, && z == rs.z, && i == rs.i, && j == rs.j, && k == rs.k, && u == rs.u, && v == rs.v, && w == rs.w); } + FI bool operator==(const XYZval &rs) const { return true NUM_AXIS_GANG(&& x == rs.x, && y == rs.y, && z == rs.z, && i == rs.i, && j == rs.j, && k == rs.k, && u == rs.u, && v == rs.v, && w == rs.w); } FI bool operator!=(const XYZval &rs) { return !operator==(rs); } FI bool operator!=(const XYZval &rs) const { return !operator==(rs); } }; diff --git a/Marlin/src/core/utility.cpp b/Marlin/src/core/utility.cpp index e3dab5aded..986869aa07 100644 --- a/Marlin/src/core/utility.cpp +++ b/Marlin/src/core/utility.cpp @@ -125,7 +125,7 @@ void safe_delay(millis_t ms) { #endif #if ABL_PLANAR SERIAL_ECHOPGM("ABL Adjustment"); - LOOP_LINEAR_AXES(a) { + LOOP_NUM_AXES(a) { SERIAL_CHAR(' ', AXIS_CHAR(a)); serial_offset(planner.get_axis_position_mm(AxisEnum(a)) - current_position[a]); } @@ -135,7 +135,7 @@ void safe_delay(millis_t ms) { const float rz = ubl.get_z_correction(current_position); #elif ENABLED(AUTO_BED_LEVELING_BILINEAR) SERIAL_ECHOPGM("ABL Adjustment Z"); - const float rz = bilinear_z_offset(current_position); + const float rz = bbl.get_z_correction(current_position); #endif SERIAL_ECHO(ftostr43sign(rz, '+')); #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT) diff --git a/Marlin/src/core/utility.h b/Marlin/src/core/utility.h index d248091ce5..b845cd0412 100644 --- a/Marlin/src/core/utility.h +++ b/Marlin/src/core/utility.h @@ -77,10 +77,13 @@ public: // in the range 0-100 while avoiding rounding artifacts constexpr uint8_t ui8_to_percent(const uint8_t i) { return (int(i) * 100 + 127) / 255; } -const xyze_char_t axis_codes LOGICAL_AXIS_ARRAY('E', 'X', 'Y', 'Z', AXIS4_NAME, AXIS5_NAME, AXIS6_NAME); - -#if LINEAR_AXES <= XYZ +// Axis names for G-code parsing, reports, etc. +const xyze_char_t axis_codes LOGICAL_AXIS_ARRAY('E', 'X', 'Y', 'Z', AXIS4_NAME, AXIS5_NAME, AXIS6_NAME, AXIS7_NAME, AXIS8_NAME, AXIS9_NAME); +#if NUM_AXES <= XYZ #define AXIS_CHAR(A) ((char)('X' + A)) + #define IAXIS_CHAR AXIS_CHAR #else + const xyze_char_t iaxis_codes LOGICAL_AXIS_ARRAY('E', 'X', 'Y', 'Z', 'I', 'J', 'K', 'U', 'V', 'W'); #define AXIS_CHAR(A) axis_codes[A] + #define IAXIS_CHAR(A) iaxis_codes[A] #endif diff --git a/Marlin/src/feature/backlash.cpp b/Marlin/src/feature/backlash.cpp index 84382cf856..876d28a8fe 100644 --- a/Marlin/src/feature/backlash.cpp +++ b/Marlin/src/feature/backlash.cpp @@ -97,7 +97,7 @@ void Backlash::add_correction_steps(const int32_t &da, const int32_t &db, const const float f_corr = float(correction) / all_on; - LOOP_LINEAR_AXES(axis) { + LOOP_NUM_AXES(axis) { if (distance_mm[axis]) { const bool reverse = TEST(dm, axis); @@ -145,7 +145,7 @@ void Backlash::add_correction_steps(const int32_t &da, const int32_t &db, const } int32_t Backlash::get_applied_steps(const AxisEnum axis) { - if (axis >= LINEAR_AXES) return 0; + if (axis >= NUM_AXES) return 0; const bool reverse = TEST(last_direction_bits, axis); @@ -165,11 +165,11 @@ class Backlash::StepAdjuster { xyz_long_t applied_steps; public: StepAdjuster() { - LOOP_LINEAR_AXES(axis) applied_steps[axis] = backlash.get_applied_steps((AxisEnum)axis); + LOOP_NUM_AXES(axis) applied_steps[axis] = backlash.get_applied_steps((AxisEnum)axis); } ~StepAdjuster() { // after backlash compensation parameter changes, ensure applied step count does not change - LOOP_LINEAR_AXES(axis) residual_error[axis] += backlash.get_applied_steps((AxisEnum)axis) - applied_steps[axis]; + LOOP_NUM_AXES(axis) residual_error[axis] += backlash.get_applied_steps((AxisEnum)axis) - applied_steps[axis]; } }; diff --git a/Marlin/src/feature/bedlevel/abl/abl.h b/Marlin/src/feature/bedlevel/abl/abl.h deleted file mode 100644 index 3d54c55695..0000000000 --- a/Marlin/src/feature/bedlevel/abl/abl.h +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Marlin 3D Printer Firmware - * Copyright (c) 2020 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 . - * - */ -#pragma once - -#include "../../../inc/MarlinConfigPre.h" - -extern xy_pos_t bilinear_grid_spacing, bilinear_start; -extern xy_float_t bilinear_grid_factor; -extern bed_mesh_t z_values; -float bilinear_z_offset(const xy_pos_t &raw); - -void extrapolate_unprobed_bed_level(); -void print_bilinear_leveling_grid(); -void refresh_bed_level(); -#if ENABLED(ABL_BILINEAR_SUBDIVISION) - void print_bilinear_leveling_grid_virt(); - void bed_level_virt_interpolate(); -#endif - -#if IS_CARTESIAN && DISABLED(SEGMENT_LEVELED_MOVES) - void bilinear_line_to_destination(const_feedRate_t scaled_fr_mm_s, uint16_t x_splits=0xFFFF, uint16_t y_splits=0xFFFF); -#endif - -#define _GET_MESH_X(I) float(bilinear_start.x + (I) * bilinear_grid_spacing.x) -#define _GET_MESH_Y(J) float(bilinear_start.y + (J) * bilinear_grid_spacing.y) -#define Z_VALUES_ARR z_values diff --git a/Marlin/src/feature/bedlevel/abl/abl.cpp b/Marlin/src/feature/bedlevel/abl/bbl.cpp similarity index 78% rename from Marlin/src/feature/bedlevel/abl/abl.cpp rename to Marlin/src/feature/bedlevel/abl/bbl.cpp index ece7481981..9dcd669128 100644 --- a/Marlin/src/feature/bedlevel/abl/abl.cpp +++ b/Marlin/src/feature/bedlevel/abl/bbl.cpp @@ -35,14 +35,19 @@ #include "../../../lcd/extui/ui_api.h" #endif -xy_pos_t bilinear_grid_spacing, bilinear_start; -xy_float_t bilinear_grid_factor; -bed_mesh_t z_values; +LevelingBilinear bbl; + +xy_pos_t LevelingBilinear::grid_spacing, + LevelingBilinear::grid_start; +xy_float_t LevelingBilinear::grid_factor; +bed_mesh_t LevelingBilinear::z_values; +xy_pos_t LevelingBilinear::cached_rel; +xy_int8_t LevelingBilinear::cached_g; /** * Extrapolate a single point from its neighbors */ -static void extrapolate_one_point(const uint8_t x, const uint8_t y, const int8_t xdir, const int8_t ydir) { +void LevelingBilinear::extrapolate_one_point(const uint8_t x, const uint8_t y, const int8_t xdir, const int8_t ydir) { if (!isnan(z_values[x][y])) return; if (DEBUGGING(LEVELING)) { DEBUG_ECHOPGM("Extrapolate ["); @@ -92,11 +97,26 @@ static void extrapolate_one_point(const uint8_t x, const uint8_t y, const int8_t #endif #endif +void LevelingBilinear::reset() { + grid_start.reset(); + grid_spacing.reset(); + GRID_LOOP(x, y) { + z_values[x][y] = NAN; + TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(x, y, 0)); + } +} + +void LevelingBilinear::set_grid(const xy_pos_t& _grid_spacing, const xy_pos_t& _grid_start) { + grid_spacing = _grid_spacing; + grid_start = _grid_start; + grid_factor = grid_spacing.reciprocal(); +} + /** * Fill in the unprobed points (corners of circular print surface) * using linear extrapolation, away from the center. */ -void extrapolate_unprobed_bed_level() { +void LevelingBilinear::extrapolate_unprobed_bed_level() { #ifdef HALF_IN_X constexpr uint8_t ctrx2 = 0, xend = GRID_MAX_POINTS_X - 1; #else @@ -131,35 +151,31 @@ void extrapolate_unprobed_bed_level() { #endif extrapolate_one_point(x2, y2, -1, -1); // right-above - - } - } -void print_bilinear_leveling_grid() { +void LevelingBilinear::print_leveling_grid(const bed_mesh_t* _z_values /*= NULL*/) { + // print internal grid(s) or just the one passed as a parameter SERIAL_ECHOLNPGM("Bilinear Leveling Grid:"); - print_2d_array(GRID_MAX_POINTS_X, GRID_MAX_POINTS_Y, 3, - [](const uint8_t ix, const uint8_t iy) { return z_values[ix][iy]; } - ); + print_2d_array(GRID_MAX_POINTS_X, GRID_MAX_POINTS_Y, 3, _z_values ? *_z_values[0] : z_values[0]); + + #if ENABLED(ABL_BILINEAR_SUBDIVISION) + if (!_z_values) { + SERIAL_ECHOLNPGM("Subdivided with CATMULL ROM Leveling Grid:"); + print_2d_array(ABL_GRID_POINTS_VIRT_X, ABL_GRID_POINTS_VIRT_Y, 5, z_values_virt[0]); + } + #endif } #if ENABLED(ABL_BILINEAR_SUBDIVISION) - #define ABL_GRID_POINTS_VIRT_X GRID_MAX_CELLS_X * (BILINEAR_SUBDIVISIONS) + 1 - #define ABL_GRID_POINTS_VIRT_Y GRID_MAX_CELLS_Y * (BILINEAR_SUBDIVISIONS) + 1 #define ABL_TEMP_POINTS_X (GRID_MAX_POINTS_X + 2) #define ABL_TEMP_POINTS_Y (GRID_MAX_POINTS_Y + 2) - float z_values_virt[ABL_GRID_POINTS_VIRT_X][ABL_GRID_POINTS_VIRT_Y]; - xy_pos_t bilinear_grid_spacing_virt; - xy_float_t bilinear_grid_factor_virt; - - void print_bilinear_leveling_grid_virt() { - SERIAL_ECHOLNPGM("Subdivided with CATMULL ROM Leveling Grid:"); - print_2d_array(ABL_GRID_POINTS_VIRT_X, ABL_GRID_POINTS_VIRT_Y, 5, - [](const uint8_t ix, const uint8_t iy) { return z_values_virt[ix][iy]; } - ); - } + float LevelingBilinear::z_values_virt[ABL_GRID_POINTS_VIRT_X][ABL_GRID_POINTS_VIRT_Y]; + xy_pos_t LevelingBilinear::grid_spacing_virt; + xy_float_t LevelingBilinear::grid_factor_virt; #define LINEAR_EXTRAPOLATION(E, I) ((E) * 2 - (I)) - float bed_level_virt_coord(const uint8_t x, const uint8_t y) { + float LevelingBilinear::bed_level_virt_coord(const uint8_t x, const uint8_t y) { uint8_t ep = 0, ip = 1; if (x > (GRID_MAX_POINTS_X) + 1 || y > (GRID_MAX_POINTS_Y) + 1) { // The requested point requires extrapolating two points beyond the mesh. @@ -204,7 +220,7 @@ void print_bilinear_leveling_grid() { return z_values[x - 1][y - 1]; } - static float bed_level_virt_cmr(const float p[4], const uint8_t i, const float t) { + float LevelingBilinear::bed_level_virt_cmr(const float p[4], const uint8_t i, const float t) { return ( p[i-1] * -t * sq(1 - t) + p[i] * (2 - 5 * sq(t) + 3 * t * sq(t)) @@ -213,7 +229,7 @@ void print_bilinear_leveling_grid() { ) * 0.5f; } - static float bed_level_virt_2cmr(const uint8_t x, const uint8_t y, const_float_t tx, const_float_t ty) { + float LevelingBilinear::bed_level_virt_2cmr(const uint8_t x, const uint8_t y, const_float_t tx, const_float_t ty) { float row[4], column[4]; LOOP_L_N(i, 4) { LOOP_L_N(j, 4) { @@ -224,9 +240,9 @@ void print_bilinear_leveling_grid() { return bed_level_virt_cmr(row, 1, tx); } - void bed_level_virt_interpolate() { - bilinear_grid_spacing_virt = bilinear_grid_spacing / (BILINEAR_SUBDIVISIONS); - bilinear_grid_factor_virt = bilinear_grid_spacing_virt.reciprocal(); + void LevelingBilinear::bed_level_virt_interpolate() { + grid_spacing_virt = grid_spacing / (BILINEAR_SUBDIVISIONS); + grid_factor_virt = grid_spacing_virt.reciprocal(); LOOP_L_N(y, GRID_MAX_POINTS_Y) LOOP_L_N(x, GRID_MAX_POINTS_X) LOOP_L_N(ty, BILINEAR_SUBDIVISIONS) @@ -244,38 +260,40 @@ void print_bilinear_leveling_grid() { } #endif // ABL_BILINEAR_SUBDIVISION + // Refresh after other values have been updated -void refresh_bed_level() { - bilinear_grid_factor = bilinear_grid_spacing.reciprocal(); +void LevelingBilinear::refresh_bed_level() { TERN_(ABL_BILINEAR_SUBDIVISION, bed_level_virt_interpolate()); + cached_rel.x = cached_rel.y = -999.999; + cached_g.x = cached_g.y = -99; } #if ENABLED(ABL_BILINEAR_SUBDIVISION) - #define ABL_BG_SPACING(A) bilinear_grid_spacing_virt.A - #define ABL_BG_FACTOR(A) bilinear_grid_factor_virt.A + #define ABL_BG_SPACING(A) grid_spacing_virt.A + #define ABL_BG_FACTOR(A) grid_factor_virt.A #define ABL_BG_POINTS_X ABL_GRID_POINTS_VIRT_X #define ABL_BG_POINTS_Y ABL_GRID_POINTS_VIRT_Y #define ABL_BG_GRID(X,Y) z_values_virt[X][Y] #else - #define ABL_BG_SPACING(A) bilinear_grid_spacing.A - #define ABL_BG_FACTOR(A) bilinear_grid_factor.A + #define ABL_BG_SPACING(A) grid_spacing.A + #define ABL_BG_FACTOR(A) grid_factor.A #define ABL_BG_POINTS_X GRID_MAX_POINTS_X #define ABL_BG_POINTS_Y GRID_MAX_POINTS_Y #define ABL_BG_GRID(X,Y) z_values[X][Y] #endif // Get the Z adjustment for non-linear bed leveling -float bilinear_z_offset(const xy_pos_t &raw) { +float LevelingBilinear::get_z_correction(const xy_pos_t &raw) { static float z1, d2, z3, d4, L, D; - static xy_pos_t prev { -999.999, -999.999 }, ratio; + static xy_pos_t ratio; // Whole units for the grid line indices. Constrained within bounds. - static xy_int8_t thisg, nextg, lastg { -99, -99 }; + static xy_int8_t thisg, nextg; // XY relative to the probed area - xy_pos_t rel = raw - bilinear_start.asFloat(); + xy_pos_t rel = raw - grid_start.asFloat(); #if ENABLED(EXTRAPOLATE_BEYOND_GRID) #define FAR_EDGE_OR_BOX 2 // Keep using the last grid box @@ -283,8 +301,8 @@ float bilinear_z_offset(const xy_pos_t &raw) { #define FAR_EDGE_OR_BOX 1 // Just use the grid far edge #endif - if (prev.x != rel.x) { - prev.x = rel.x; + if (cached_rel.x != rel.x) { + cached_rel.x = rel.x; ratio.x = rel.x * ABL_BG_FACTOR(x); const float gx = constrain(FLOOR(ratio.x), 0, ABL_BG_POINTS_X - (FAR_EDGE_OR_BOX)); ratio.x -= gx; // Subtract whole to get the ratio within the grid box @@ -298,10 +316,10 @@ float bilinear_z_offset(const xy_pos_t &raw) { nextg.x = _MIN(thisg.x + 1, ABL_BG_POINTS_X - 1); } - if (prev.y != rel.y || lastg.x != thisg.x) { + if (cached_rel.y != rel.y || cached_g.x != thisg.x) { - if (prev.y != rel.y) { - prev.y = rel.y; + if (cached_rel.y != rel.y) { + cached_rel.y = rel.y; ratio.y = rel.y * ABL_BG_FACTOR(y); const float gy = constrain(FLOOR(ratio.y), 0, ABL_BG_POINTS_Y - (FAR_EDGE_OR_BOX)); ratio.y -= gy; @@ -315,8 +333,8 @@ float bilinear_z_offset(const xy_pos_t &raw) { nextg.y = _MIN(thisg.y + 1, ABL_BG_POINTS_Y - 1); } - if (lastg != thisg) { - lastg = thisg; + if (cached_g != thisg) { + cached_g = thisg; // Z at the box corners z1 = ABL_BG_GRID(thisg.x, thisg.y); // left-front d2 = ABL_BG_GRID(thisg.x, nextg.y) - z1; // left-back (delta) @@ -336,8 +354,8 @@ float bilinear_z_offset(const xy_pos_t &raw) { /* static float last_offset = 0; if (ABS(last_offset - offset) > 0.2) { - SERIAL_ECHOLNPGM("Sudden Shift at x=", rel.x, " / ", bilinear_grid_spacing.x, " -> thisg.x=", thisg.x); - SERIAL_ECHOLNPGM(" y=", rel.y, " / ", bilinear_grid_spacing.y, " -> thisg.y=", thisg.y); + SERIAL_ECHOLNPGM("Sudden Shift at x=", rel.x, " / ", grid_spacing.x, " -> thisg.x=", thisg.x); + SERIAL_ECHOLNPGM(" y=", rel.y, " / ", grid_spacing.y, " -> thisg.y=", thisg.y); SERIAL_ECHOLNPGM(" ratio.x=", ratio.x, " ratio.y=", ratio.y); SERIAL_ECHOLNPGM(" z1=", z1, " z2=", z2, " z3=", z3, " z4=", z4); SERIAL_ECHOLNPGM(" L=", L, " R=", R, " offset=", offset); @@ -350,13 +368,13 @@ float bilinear_z_offset(const xy_pos_t &raw) { #if IS_CARTESIAN && DISABLED(SEGMENT_LEVELED_MOVES) - #define CELL_INDEX(A,V) ((V - bilinear_start.A) * ABL_BG_FACTOR(A)) + #define CELL_INDEX(A,V) ((V - grid_start.A) * ABL_BG_FACTOR(A)) /** * Prepare a bilinear-leveled linear move on Cartesian, * splitting the move where it crosses grid borders. */ - void bilinear_line_to_destination(const_feedRate_t scaled_fr_mm_s, uint16_t x_splits, uint16_t y_splits) { + void LevelingBilinear::line_to_destination(const_feedRate_t scaled_fr_mm_s, uint16_t x_splits, uint16_t y_splits) { // Get current and destination cells for this line xy_int_t c1 { CELL_INDEX(x, current_position.x), CELL_INDEX(y, current_position.y) }, c2 { CELL_INDEX(x, destination.x), CELL_INDEX(y, destination.y) }; @@ -384,7 +402,7 @@ float bilinear_z_offset(const xy_pos_t &raw) { // Split on the X grid line CBI(x_splits, gc.x); end = destination; - destination.x = bilinear_start.x + ABL_BG_SPACING(x) * gc.x; + destination.x = grid_start.x + ABL_BG_SPACING(x) * gc.x; normalized_dist = (destination.x - current_position.x) / (end.x - current_position.x); destination.y = LINE_SEGMENT_END(y); } @@ -393,7 +411,7 @@ float bilinear_z_offset(const xy_pos_t &raw) { // Split on the Y grid line CBI(y_splits, gc.y); end = destination; - destination.y = bilinear_start.y + ABL_BG_SPACING(y) * gc.y; + destination.y = grid_start.y + ABL_BG_SPACING(y) * gc.y; normalized_dist = (destination.y - current_position.y) / (end.y - current_position.y); destination.x = LINE_SEGMENT_END(x); } @@ -409,11 +427,11 @@ float bilinear_z_offset(const xy_pos_t &raw) { destination.e = LINE_SEGMENT_END(e); // Do the split and look for more borders - bilinear_line_to_destination(scaled_fr_mm_s, x_splits, y_splits); + line_to_destination(scaled_fr_mm_s, x_splits, y_splits); // Restore destination from stack destination = end; - bilinear_line_to_destination(scaled_fr_mm_s, x_splits, y_splits); + line_to_destination(scaled_fr_mm_s, x_splits, y_splits); } #endif // IS_CARTESIAN && !SEGMENT_LEVELED_MOVES diff --git a/Marlin/src/feature/bedlevel/abl/bbl.h b/Marlin/src/feature/bedlevel/abl/bbl.h new file mode 100644 index 0000000000..86da5aea10 --- /dev/null +++ b/Marlin/src/feature/bedlevel/abl/bbl.h @@ -0,0 +1,72 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2020 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 . + * + */ +#pragma once + +#include "../../../inc/MarlinConfigPre.h" + +class LevelingBilinear { + static xy_pos_t grid_spacing, grid_start; + static xy_float_t grid_factor; + static bed_mesh_t z_values; + static xy_pos_t cached_rel; + static xy_int8_t cached_g; + + static void extrapolate_one_point(const uint8_t x, const uint8_t y, const int8_t xdir, const int8_t ydir); + + #if ENABLED(ABL_BILINEAR_SUBDIVISION) + #define ABL_GRID_POINTS_VIRT_X (GRID_MAX_CELLS_X * (BILINEAR_SUBDIVISIONS) + 1) + #define ABL_GRID_POINTS_VIRT_Y (GRID_MAX_CELLS_Y * (BILINEAR_SUBDIVISIONS) + 1) + + static float z_values_virt[ABL_GRID_POINTS_VIRT_X][ABL_GRID_POINTS_VIRT_Y]; + static xy_pos_t grid_spacing_virt; + static xy_float_t grid_factor_virt; + + static float bed_level_virt_coord(const uint8_t x, const uint8_t y); + static float bed_level_virt_cmr(const float p[4], const uint8_t i, const float t); + static float bed_level_virt_2cmr(const uint8_t x, const uint8_t y, const_float_t tx, const_float_t ty); + static void bed_level_virt_interpolate(); + #endif + +public: + static void reset(); + static void set_grid(const xy_pos_t& _grid_spacing, const xy_pos_t& _grid_start); + static void extrapolate_unprobed_bed_level(); + static void print_leveling_grid(const bed_mesh_t* _z_values = NULL); + static void refresh_bed_level(); + static bool has_mesh() { return !!grid_spacing.x; } + static bed_mesh_t& get_z_values() { return z_values; } + static const xy_pos_t& get_grid_spacing() { return grid_spacing; } + static const xy_pos_t& get_grid_start() { return grid_start; } + static float get_mesh_x(int16_t i) { return grid_start.x + i * grid_spacing.x; } + static float get_mesh_y(int16_t j) { return grid_start.y + j * grid_spacing.y; } + static float get_z_correction(const xy_pos_t &raw); + + #if IS_CARTESIAN && DISABLED(SEGMENT_LEVELED_MOVES) + static void line_to_destination(const_feedRate_t scaled_fr_mm_s, uint16_t x_splits=0xFFFF, uint16_t y_splits=0xFFFF); + #endif +}; + +extern LevelingBilinear bbl; + +#define _GET_MESH_X(I) bbl.get_mesh_x(I) +#define _GET_MESH_Y(J) bbl.get_mesh_y(J) +#define Z_VALUES_ARR bbl.get_z_values() diff --git a/Marlin/src/feature/bedlevel/bedlevel.cpp b/Marlin/src/feature/bedlevel/bedlevel.cpp index 8e03632de4..2405905d4e 100644 --- a/Marlin/src/feature/bedlevel/bedlevel.cpp +++ b/Marlin/src/feature/bedlevel/bedlevel.cpp @@ -48,7 +48,7 @@ bool leveling_is_valid() { return TERN1(MESH_BED_LEVELING, mbl.has_mesh()) - && TERN1(AUTO_BED_LEVELING_BILINEAR, !!bilinear_grid_spacing.x) + && TERN1(AUTO_BED_LEVELING_BILINEAR, bbl.has_mesh()) && TERN1(AUTO_BED_LEVELING_UBL, ubl.mesh_is_valid()); } @@ -67,12 +67,6 @@ void set_bed_leveling_enabled(const bool enable/*=true*/) { planner.synchronize(); - #if ENABLED(AUTO_BED_LEVELING_BILINEAR) - // Force bilinear_z_offset to re-calculate next time - const xyz_pos_t reset { -9999.999, -9999.999, 0 }; - (void)bilinear_z_offset(reset); - #endif - if (planner.leveling_active) { // leveling from on to off if (DEBUGGING(LEVELING)) DEBUG_POS("Leveling ON", current_position); // change unleveled current_position to physical current_position without moving steppers. @@ -129,12 +123,7 @@ void reset_bed_level() { #if ENABLED(MESH_BED_LEVELING) mbl.reset(); #elif ENABLED(AUTO_BED_LEVELING_BILINEAR) - bilinear_start.reset(); - bilinear_grid_spacing.reset(); - GRID_LOOP(x, y) { - z_values[x][y] = NAN; - TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(x, y, 0)); - } + bbl.reset(); #elif ABL_PLANAR planner.bed_level_matrix.set_to_identity(); #endif @@ -156,7 +145,7 @@ void reset_bed_level() { /** * Print calibration results for plotting or manual frame adjustment. */ - void print_2d_array(const uint8_t sx, const uint8_t sy, const uint8_t precision, element_2d_fn fn) { + void print_2d_array(const uint8_t sx, const uint8_t sy, const uint8_t precision, const float *values) { #ifndef SCAD_MESH_OUTPUT LOOP_L_N(x, sx) { serial_spaces(precision + (x < 10 ? 3 : 2)); @@ -176,7 +165,7 @@ void reset_bed_level() { #endif LOOP_L_N(x, sx) { SERIAL_CHAR(' '); - const float offset = fn(x, y); + const float offset = values[x * sx + y]; if (!isnan(offset)) { if (offset >= 0) SERIAL_CHAR('+'); SERIAL_ECHO_F(offset, int(precision)); diff --git a/Marlin/src/feature/bedlevel/bedlevel.h b/Marlin/src/feature/bedlevel/bedlevel.h index 63f032eee8..f295da1d03 100644 --- a/Marlin/src/feature/bedlevel/bedlevel.h +++ b/Marlin/src/feature/bedlevel/bedlevel.h @@ -62,7 +62,7 @@ class TemporaryBedLevelingState { typedef float bed_mesh_t[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y]; #if ENABLED(AUTO_BED_LEVELING_BILINEAR) - #include "abl/abl.h" + #include "abl/bbl.h" #elif ENABLED(AUTO_BED_LEVELING_UBL) #include "ubl/ubl.h" #elif ENABLED(MESH_BED_LEVELING) @@ -81,7 +81,7 @@ class TemporaryBedLevelingState { /** * Print calibration results for plotting or manual frame adjustment. */ - void print_2d_array(const uint8_t sx, const uint8_t sy, const uint8_t precision, element_2d_fn fn); + void print_2d_array(const uint8_t sx, const uint8_t sy, const uint8_t precision, const float *values); #endif diff --git a/Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.cpp b/Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.cpp index 51cf28f890..fbc3f2785e 100644 --- a/Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.cpp +++ b/Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.cpp @@ -125,9 +125,7 @@ void mesh_bed_leveling::report_mesh() { SERIAL_ECHOPAIR_F(STRINGIFY(GRID_MAX_POINTS_X) "x" STRINGIFY(GRID_MAX_POINTS_Y) " mesh. Z offset: ", z_offset, 5); SERIAL_ECHOLNPGM("\nMeasured points:"); - print_2d_array(GRID_MAX_POINTS_X, GRID_MAX_POINTS_Y, 5, - [](const uint8_t ix, const uint8_t iy) { return z_values[ix][iy]; } - ); + print_2d_array(GRID_MAX_POINTS_X, GRID_MAX_POINTS_Y, 5, z_values[0]); } #endif // MESH_BED_LEVELING diff --git a/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp b/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp index 023d0c5b1d..9d2aaf8247 100644 --- a/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp +++ b/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp @@ -317,6 +317,42 @@ void unified_bed_leveling::G29() { // Send 'N' to force homing before G29 (internal only) if (axes_should_home() || parser.seen_test('N')) gcode.home_all_axes(); TERN_(HAS_MULTI_HOTEND, if (active_extruder != 0) tool_change(0, true)); + + // Position bed horizontally and Z probe vertically. + #if defined(SAFE_BED_LEVELING_START_X) || defined(SAFE_BED_LEVELING_START_Y) || defined(SAFE_BED_LEVELING_START_Z) \ + || defined(SAFE_BED_LEVELING_START_I) || defined(SAFE_BED_LEVELING_START_J) || defined(SAFE_BED_LEVELING_START_K) \ + || defined(SAFE_BED_LEVELING_START_U) || defined(SAFE_BED_LEVELING_START_V) || defined(SAFE_BED_LEVELING_START_W) + xyze_pos_t safe_position = current_position; + #ifdef SAFE_BED_LEVELING_START_X + safe_position.x = SAFE_BED_LEVELING_START_X; + #endif + #ifdef SAFE_BED_LEVELING_START_Y + safe_position.y = SAFE_BED_LEVELING_START_Y; + #endif + #ifdef SAFE_BED_LEVELING_START_Z + safe_position.z = SAFE_BED_LEVELING_START_Z; + #endif + #ifdef SAFE_BED_LEVELING_START_I + safe_position.i = SAFE_BED_LEVELING_START_I; + #endif + #ifdef SAFE_BED_LEVELING_START_J + safe_position.j = SAFE_BED_LEVELING_START_J; + #endif + #ifdef SAFE_BED_LEVELING_START_K + safe_position.k = SAFE_BED_LEVELING_START_K; + #endif + #ifdef SAFE_BED_LEVELING_START_U + safe_position.u = SAFE_BED_LEVELING_START_U; + #endif + #ifdef SAFE_BED_LEVELING_START_V + safe_position.v = SAFE_BED_LEVELING_START_V; + #endif + #ifdef SAFE_BED_LEVELING_START_W + safe_position.w = SAFE_BED_LEVELING_START_W; + #endif + + do_blocking_move_to(safe_position); + #endif } // Invalidate one or more nearby mesh points, possibly all. @@ -367,13 +403,13 @@ void unified_bed_leveling::G29() { case 1: LOOP_L_N(x, GRID_MAX_POINTS_X) { // Create a diagonal line several Mesh cells thick that is raised + const uint8_t x2 = x + (x < (GRID_MAX_POINTS_Y) - 1 ? 1 : -1); z_values[x][x] += 9.999f; - z_values[x][x + (x < (GRID_MAX_POINTS_Y) - 1) ? 1 : -1] += 9.999f; // We want the altered line several mesh points thick + z_values[x][x2] += 9.999f; // We want the altered line several mesh points thick #if ENABLED(EXTENSIBLE_UI) ExtUI::onMeshUpdate(x, x, z_values[x][x]); - ExtUI::onMeshUpdate(x, (x + (x < (GRID_MAX_POINTS_Y) - 1) ? 1 : -1), z_values[x][x + (x < (GRID_MAX_POINTS_Y) - 1) ? 1 : -1]); + ExtUI::onMeshUpdate(x, (x2), z_values[x][x2]); #endif - } break; @@ -1219,6 +1255,7 @@ void unified_bed_leveling::restore_ubl_active_state_and_leave() { } #endif set_bed_leveling_enabled(ubl_state_at_invocation); + TERN_(EXTENSIBLE_UI, ExtUI::onLevelingDone()); } mesh_index_pair unified_bed_leveling::find_furthest_invalid_mesh_point() { diff --git a/Marlin/src/feature/digipot/digipot_mcp4018.cpp b/Marlin/src/feature/digipot/digipot_mcp4018.cpp index 37853ff428..3f2ecbfcdc 100644 --- a/Marlin/src/feature/digipot/digipot_mcp4018.cpp +++ b/Marlin/src/feature/digipot/digipot_mcp4018.cpp @@ -31,9 +31,13 @@ // Settings for the I2C based DIGIPOT (MCP4018) based on WT150 -#define DIGIPOT_A4988_Rsx 0.250 -#define DIGIPOT_A4988_Vrefmax 1.666 -#define DIGIPOT_MCP4018_MAX_VALUE 127 +#ifndef DIGIPOT_A4988_Rsx + #define DIGIPOT_A4988_Rsx 0.250 +#endif +#ifndef DIGIPOT_A4988_Vrefmax + #define DIGIPOT_A4988_Vrefmax 1.666 +#endif +#define DIGIPOT_MCP4018_MAX_VALUE 127 #define DIGIPOT_A4988_Itripmax(Vref) ((Vref) / (8.0 * DIGIPOT_A4988_Rsx)) diff --git a/Marlin/src/feature/encoder_i2c.cpp b/Marlin/src/feature/encoder_i2c.cpp index 2ccd686a99..c1dbb906fd 100644 --- a/Marlin/src/feature/encoder_i2c.cpp +++ b/Marlin/src/feature/encoder_i2c.cpp @@ -337,7 +337,7 @@ bool I2CPositionEncoder::test_axis() { ec = false; xyze_pos_t startCoord, endCoord; - LOOP_LINEAR_AXES(a) { + LOOP_NUM_AXES(a) { startCoord[a] = planner.get_axis_position_mm((AxisEnum)a); endCoord[a] = planner.get_axis_position_mm((AxisEnum)a); } @@ -395,7 +395,7 @@ void I2CPositionEncoder::calibrate_steps_mm(const uint8_t iter) { travelDistance = endDistance - startDistance; xyze_pos_t startCoord, endCoord; - LOOP_LINEAR_AXES(a) { + LOOP_NUM_AXES(a) { startCoord[a] = planner.get_axis_position_mm((AxisEnum)a); endCoord[a] = planner.get_axis_position_mm((AxisEnum)a); } @@ -489,7 +489,7 @@ void I2CPositionEncodersMgr::init() { encoders[i].set_stepper_ticks(I2CPE_ENC_1_TICKS_REV); #endif #ifdef I2CPE_ENC_1_INVERT - encoders[i].set_inverted(I2CPE_ENC_1_INVERT); + encoders[i].set_inverted(ENABLED(I2CPE_ENC_1_INVERT)); #endif #ifdef I2CPE_ENC_1_EC_METHOD encoders[i].set_ec_method(I2CPE_ENC_1_EC_METHOD); @@ -518,7 +518,7 @@ void I2CPositionEncodersMgr::init() { encoders[i].set_stepper_ticks(I2CPE_ENC_2_TICKS_REV); #endif #ifdef I2CPE_ENC_2_INVERT - encoders[i].set_inverted(I2CPE_ENC_2_INVERT); + encoders[i].set_inverted(ENABLED(I2CPE_ENC_2_INVERT)); #endif #ifdef I2CPE_ENC_2_EC_METHOD encoders[i].set_ec_method(I2CPE_ENC_2_EC_METHOD); @@ -547,7 +547,7 @@ void I2CPositionEncodersMgr::init() { encoders[i].set_stepper_ticks(I2CPE_ENC_3_TICKS_REV); #endif #ifdef I2CPE_ENC_3_INVERT - encoders[i].set_inverted(I2CPE_ENC_3_INVERT); + encoders[i].set_inverted(ENABLED(I2CPE_ENC_3_INVERT)); #endif #ifdef I2CPE_ENC_3_EC_METHOD encoders[i].set_ec_method(I2CPE_ENC_3_EC_METHOD); @@ -576,7 +576,7 @@ void I2CPositionEncodersMgr::init() { encoders[i].set_stepper_ticks(I2CPE_ENC_4_TICKS_REV); #endif #ifdef I2CPE_ENC_4_INVERT - encoders[i].set_inverted(I2CPE_ENC_4_INVERT); + encoders[i].set_inverted(ENABLED(I2CPE_ENC_4_INVERT)); #endif #ifdef I2CPE_ENC_4_EC_METHOD encoders[i].set_ec_method(I2CPE_ENC_4_EC_METHOD); @@ -605,7 +605,7 @@ void I2CPositionEncodersMgr::init() { encoders[i].set_stepper_ticks(I2CPE_ENC_5_TICKS_REV); #endif #ifdef I2CPE_ENC_5_INVERT - encoders[i].set_inverted(I2CPE_ENC_5_INVERT); + encoders[i].set_inverted(ENABLED(I2CPE_ENC_5_INVERT)); #endif #ifdef I2CPE_ENC_5_EC_METHOD encoders[i].set_ec_method(I2CPE_ENC_5_EC_METHOD); @@ -634,7 +634,7 @@ void I2CPositionEncodersMgr::init() { encoders[i].set_stepper_ticks(I2CPE_ENC_6_TICKS_REV); #endif #ifdef I2CPE_ENC_6_INVERT - encoders[i].set_inverted(I2CPE_ENC_6_INVERT); + encoders[i].set_inverted(ENABLED(I2CPE_ENC_6_INVERT)); #endif #ifdef I2CPE_ENC_6_EC_METHOD encoders[i].set_ec_method(I2CPE_ENC_6_EC_METHOD); diff --git a/Marlin/src/feature/filwidth.h b/Marlin/src/feature/filwidth.h index e234380e98..9eb1e77762 100644 --- a/Marlin/src/feature/filwidth.h +++ b/Marlin/src/feature/filwidth.h @@ -67,7 +67,7 @@ public: } // Convert raw measurement to mm - static float raw_to_mm(const uint16_t v) { return v * 5.0f * RECIPROCAL(float(MAX_RAW_THERMISTOR_VALUE)); } + static float raw_to_mm(const uint16_t v) { return v * float(ADC_VREF) * RECIPROCAL(float(MAX_RAW_THERMISTOR_VALUE)); } static float raw_to_mm() { return raw_to_mm(raw); } // A scaled reading is ready diff --git a/Marlin/src/feature/fwretract.cpp b/Marlin/src/feature/fwretract.cpp index 4077d8d1c2..bf47a6b2d5 100644 --- a/Marlin/src/feature/fwretract.cpp +++ b/Marlin/src/feature/fwretract.cpp @@ -73,10 +73,10 @@ void FWRetract::reset() { settings.swap_retract_recover_feedrate_mm_s = RETRACT_RECOVER_FEEDRATE_SWAP; current_hop = 0.0; - LOOP_L_N(i, EXTRUDERS) { - retracted[i] = false; - E_TERN_(retracted_swap[i] = false); - current_retract[i] = 0.0; + EXTRUDER_LOOP() { + retracted[e] = false; + E_TERN_(retracted_swap[e] = false); + current_retract[e] = 0.0; } } @@ -111,10 +111,10 @@ void FWRetract::retract(const bool retracting E_OPTARG(bool swapping/*=false*/)) " swapping ", swapping, " active extruder ", active_extruder ); - LOOP_L_N(i, EXTRUDERS) { - SERIAL_ECHOLNPGM("retracted[", i, "] ", AS_DIGIT(retracted[i])); + EXTRUDER_LOOP() { + SERIAL_ECHOLNPGM("retracted[", e, "] ", AS_DIGIT(retracted[e])); #if HAS_MULTI_EXTRUDER - SERIAL_ECHOLNPGM("retracted_swap[", i, "] ", AS_DIGIT(retracted_swap[i])); + SERIAL_ECHOLNPGM("retracted_swap[", e, "] ", AS_DIGIT(retracted_swap[e])); #endif } SERIAL_ECHOLNPGM("current_position.z ", current_position.z); @@ -184,10 +184,10 @@ void FWRetract::retract(const bool retracting E_OPTARG(bool swapping/*=false*/)) SERIAL_ECHOLNPGM("retracting ", AS_DIGIT(retracting)); SERIAL_ECHOLNPGM("swapping ", AS_DIGIT(swapping)); SERIAL_ECHOLNPGM("active_extruder ", active_extruder); - LOOP_L_N(i, EXTRUDERS) { - SERIAL_ECHOLNPGM("retracted[", i, "] ", AS_DIGIT(retracted[i])); + EXTRUDER_LOOP() { + SERIAL_ECHOLNPGM("retracted[", e, "] ", AS_DIGIT(retracted[e])); #if HAS_MULTI_EXTRUDER - SERIAL_ECHOLNPGM("retracted_swap[", i, "] ", AS_DIGIT(retracted_swap[i])); + SERIAL_ECHOLNPGM("retracted_swap[", e, "] ", AS_DIGIT(retracted_swap[e])); #endif } SERIAL_ECHOLNPGM("current_position.z ", current_position.z); diff --git a/Marlin/src/feature/fwretract.h b/Marlin/src/feature/fwretract.h index d6d0432e3a..081ec44c05 100644 --- a/Marlin/src/feature/fwretract.h +++ b/Marlin/src/feature/fwretract.h @@ -64,7 +64,7 @@ public: static void reset(); static void refresh_autoretract() { - LOOP_L_N(i, EXTRUDERS) retracted[i] = false; + EXTRUDER_LOOP() retracted[e] = false; } static void enable_autoretract(const bool enable) { diff --git a/Marlin/src/feature/joystick.cpp b/Marlin/src/feature/joystick.cpp index 7f91c1549b..daa642d32e 100644 --- a/Marlin/src/feature/joystick.cpp +++ b/Marlin/src/feature/joystick.cpp @@ -68,13 +68,13 @@ Joystick joystick; void Joystick::report() { SERIAL_ECHOPGM("Joystick"); #if HAS_JOY_ADC_X - SERIAL_ECHOPGM_P(SP_X_STR, JOY_X(x.raw)); + SERIAL_ECHOPGM_P(SP_X_STR, JOY_X(x.getraw())); #endif #if HAS_JOY_ADC_Y - SERIAL_ECHOPGM_P(SP_Y_STR, JOY_Y(y.raw)); + SERIAL_ECHOPGM_P(SP_Y_STR, JOY_Y(y.getraw())); #endif #if HAS_JOY_ADC_Z - SERIAL_ECHOPGM_P(SP_Z_STR, JOY_Z(z.raw)); + SERIAL_ECHOPGM_P(SP_Z_STR, JOY_Z(z.getraw())); #endif #if HAS_JOY_ADC_EN SERIAL_ECHO_TERNARY(READ(JOY_EN_PIN), " EN=", "HIGH (dis", "LOW (en", "abled)"); @@ -91,29 +91,29 @@ Joystick joystick; if (READ(JOY_EN_PIN)) return; #endif - auto _normalize_joy = [](float &axis_jog, const int16_t raw, const int16_t (&joy_limits)[4]) { + auto _normalize_joy = [](float &axis_jog, const raw_adc_t raw, const raw_adc_t (&joy_limits)[4]) { if (WITHIN(raw, joy_limits[0], joy_limits[3])) { // within limits, check deadzone if (raw > joy_limits[2]) axis_jog = (raw - joy_limits[2]) / float(joy_limits[3] - joy_limits[2]); else if (raw < joy_limits[1]) - axis_jog = (raw - joy_limits[1]) / float(joy_limits[1] - joy_limits[0]); // negative value + axis_jog = int16_t(raw - joy_limits[1]) / float(joy_limits[1] - joy_limits[0]); // negative value // Map normal to jog value via quadratic relationship axis_jog = SIGN(axis_jog) * sq(axis_jog); } }; #if HAS_JOY_ADC_X - static constexpr int16_t joy_x_limits[4] = JOY_X_LIMITS; - _normalize_joy(norm_jog.x, JOY_X(x.raw), joy_x_limits); + static constexpr raw_adc_t joy_x_limits[4] = JOY_X_LIMITS; + _normalize_joy(norm_jog.x, JOY_X(x.getraw()), joy_x_limits); #endif #if HAS_JOY_ADC_Y - static constexpr int16_t joy_y_limits[4] = JOY_Y_LIMITS; - _normalize_joy(norm_jog.y, JOY_Y(y.raw), joy_y_limits); + static constexpr raw_adc_t joy_y_limits[4] = JOY_Y_LIMITS; + _normalize_joy(norm_jog.y, JOY_Y(y.getraw()), joy_y_limits); #endif #if HAS_JOY_ADC_Z - static constexpr int16_t joy_z_limits[4] = JOY_Z_LIMITS; - _normalize_joy(norm_jog.z, JOY_Z(z.raw), joy_z_limits); + static constexpr raw_adc_t joy_z_limits[4] = JOY_Z_LIMITS; + _normalize_joy(norm_jog.z, JOY_Z(z.getraw()), joy_z_limits); #endif } @@ -163,7 +163,7 @@ Joystick joystick; // norm_jog values of [-1 .. 1] maps linearly to [-feedrate .. feedrate] xyz_float_t move_dist{0}; float hypot2 = 0; - LOOP_LINEAR_AXES(i) if (norm_jog[i]) { + LOOP_NUM_AXES(i) if (norm_jog[i]) { move_dist[i] = seg_time * norm_jog[i] * TERN(EXTENSIBLE_UI, manual_feedrate_mm_s, planner.settings.max_feedrate_mm_s)[i]; hypot2 += sq(move_dist[i]); } diff --git a/Marlin/src/feature/leds/neopixel.cpp b/Marlin/src/feature/leds/neopixel.cpp index 3569cb180d..4f104234f1 100644 --- a/Marlin/src/feature/leds/neopixel.cpp +++ b/Marlin/src/feature/leds/neopixel.cpp @@ -44,14 +44,14 @@ Adafruit_NeoPixel Marlin_NeoPixel::adaneo1(NEOPIXEL_PIXELS, NEOPIXEL_PIN, NEOPIX #ifdef NEOPIXEL_BKGD_INDEX_FIRST - void Marlin_NeoPixel::set_background_color(uint8_t r, uint8_t g, uint8_t b, uint8_t w) { - for (int background_led = NEOPIXEL_BKGD_INDEX_FIRST; background_led <= NEOPIXEL_BKGD_INDEX_LAST; background_led++) + void Marlin_NeoPixel::set_background_color(const uint8_t r, const uint8_t g, const uint8_t b, const uint8_t w) { + for (int background_led = NEOPIXEL_BKGD_INDEX_FIRST; background_led <= NEOPIXEL_BKGD_INDEX_LAST; background_led++) set_pixel_color(background_led, adaneo1.Color(r, g, b, w)); } void Marlin_NeoPixel::reset_background_color() { constexpr uint8_t background_color[4] = NEOPIXEL_BKGD_COLOR; - set_background_color(background_color[0], background_color[1], background_color[2], background_color[3]); + set_background_color(background_color); } #endif @@ -108,7 +108,7 @@ void Marlin_NeoPixel::init() { set_color(adaneo1.Color TERN(LED_USER_PRESET_STARTUP, (LED_USER_PRESET_RED, LED_USER_PRESET_GREEN, LED_USER_PRESET_BLUE, LED_USER_PRESET_WHITE), - (0, 0, 0, 0)) + (255, 255, 255, 255)) ); } diff --git a/Marlin/src/feature/leds/neopixel.h b/Marlin/src/feature/leds/neopixel.h index 1a38ed1a19..d71aa25770 100644 --- a/Marlin/src/feature/leds/neopixel.h +++ b/Marlin/src/feature/leds/neopixel.h @@ -88,7 +88,8 @@ public: static void set_color(const uint32_t c); #ifdef NEOPIXEL_BKGD_INDEX_FIRST - static void set_background_color(uint8_t r, uint8_t g, uint8_t b, uint8_t w); + static void set_background_color(const uint8_t r, const uint8_t g, const uint8_t b, const uint8_t w); + static void set_background_color(const uint8_t (&rgbw)[4]) { set_background_color(rgbw[0], rgbw[1], rgbw[2], rgbw[3]); } static void reset_background_color(); #endif diff --git a/Marlin/src/feature/mmu/mmu2.cpp b/Marlin/src/feature/mmu/mmu2.cpp index 911464a5e2..63fd8ae059 100644 --- a/Marlin/src/feature/mmu/mmu2.cpp +++ b/Marlin/src/feature/mmu/mmu2.cpp @@ -143,6 +143,11 @@ uint8_t MMU2::get_current_tool() { #define FILAMENT_PRESENT() (READ(FIL_RUNOUT1_PIN) != runout.out_state()) #endif +void mmu2_attn_buzz(const bool two=false) { + BUZZ(200, 404); + if (two) { BUZZ(10, 0); BUZZ(200, 404); } +} + void MMU2::mmu_loop() { switch (state) { @@ -525,7 +530,7 @@ static void mmu2_not_responding() { while (!thermalManager.wait_for_hotend(active_extruder, false)) safe_delay(100); load_filament_to_nozzle(index); #else - BUZZ(400, 40); + ERR_BUZZ(); #endif } break; @@ -544,7 +549,7 @@ static void mmu2_not_responding() { active_extruder = 0; } #else - BUZZ(400, 40); + ERR_BUZZ(); #endif } break; @@ -613,7 +618,7 @@ static void mmu2_not_responding() { while (!thermalManager.wait_for_hotend(active_extruder, false)) safe_delay(100); load_filament_to_nozzle(index); #else - BUZZ(400, 40); + ERR_BUZZ(); #endif } break; @@ -633,7 +638,7 @@ static void mmu2_not_responding() { extruder = index; active_extruder = 0; #else - BUZZ(400, 40); + ERR_BUZZ(); #endif } break; @@ -707,7 +712,7 @@ static void mmu2_not_responding() { while (!thermalManager.wait_for_hotend(active_extruder, false)) safe_delay(100); load_filament_to_nozzle(index); #else - BUZZ(400, 40); + ERR_BUZZ(); #endif } break; @@ -726,7 +731,7 @@ static void mmu2_not_responding() { extruder = index; active_extruder = 0; #else - BUZZ(400, 40); + ERR_BUZZ(); #endif } break; @@ -811,25 +816,26 @@ void MMU2::manage_response(const bool move_axes, const bool turn_off_nozzle) { if (turn_off_nozzle && resume_hotend_temp) { thermalManager.setTargetHotend(resume_hotend_temp, active_extruder); LCD_MESSAGE(MSG_HEATING); - BUZZ(200, 40); + ERR_BUZZ(); while (!thermalManager.wait_for_hotend(active_extruder, false)) safe_delay(1000); } - if (move_axes && all_axes_homed()) { - LCD_MESSAGE(MSG_MMU2_RESUMING); - BUZZ(198, 404); BUZZ(4, 0); BUZZ(198, 404); + LCD_MESSAGE(MSG_MMU2_RESUMING); + mmu2_attn_buzz(true); + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" + + if (move_axes && all_axes_homed()) { // Move XY to starting position, then Z do_blocking_move_to_xy(resume_position, feedRate_t(NOZZLE_PARK_XY_FEEDRATE)); // Move Z_AXIS to saved position do_blocking_move_to_z(resume_position.z, feedRate_t(NOZZLE_PARK_Z_FEEDRATE)); } - else { - BUZZ(198, 404); BUZZ(4, 0); BUZZ(198, 404); - LCD_MESSAGE(MSG_MMU2_RESUMING); - } + + #pragma GCC diagnostic pop } } } @@ -898,7 +904,7 @@ void MMU2::load_filament(const uint8_t index) { command(MMU_CMD_L0 + index); manage_response(false, false); - BUZZ(200, 404); + mmu2_attn_buzz(); } /** @@ -909,7 +915,7 @@ bool MMU2::load_filament_to_nozzle(const uint8_t index) { if (!_enabled) return false; if (thermalManager.tooColdToExtrude(active_extruder)) { - BUZZ(200, 404); + mmu2_attn_buzz(); LCD_ALERTMESSAGE(MSG_HOTEND_TOO_COLD); return false; } @@ -924,7 +930,7 @@ bool MMU2::load_filament_to_nozzle(const uint8_t index) { extruder = index; active_extruder = 0; load_to_nozzle(); - BUZZ(200, 404); + mmu2_attn_buzz(); } return success; } @@ -945,7 +951,7 @@ bool MMU2::eject_filament(const uint8_t index, const bool recover) { if (!_enabled) return false; if (thermalManager.tooColdToExtrude(active_extruder)) { - BUZZ(200, 404); + mmu2_attn_buzz(); LCD_ALERTMESSAGE(MSG_HOTEND_TOO_COLD); return false; } @@ -961,12 +967,11 @@ bool MMU2::eject_filament(const uint8_t index, const bool recover) { if (recover) { LCD_MESSAGE(MSG_MMU2_EJECT_RECOVER); - BUZZ(200, 404); + mmu2_attn_buzz(); TERN_(HOST_PROMPT_SUPPORT, hostui.prompt_do(PROMPT_USER_CONTINUE, F("MMU2 Eject Recover"), FPSTR(CONTINUE_STR))); TERN_(EXTENSIBLE_UI, ExtUI::onUserConfirmRequired(F("MMU2 Eject Recover"))); TERN_(HAS_RESUME_CONTINUE, wait_for_user_response()); - BUZZ(200, 404); - BUZZ(200, 404); + mmu2_attn_buzz(true); command(MMU_CMD_R0); manage_response(false, false); @@ -979,7 +984,7 @@ bool MMU2::eject_filament(const uint8_t index, const bool recover) { set_runout_valid(false); - BUZZ(200, 404); + mmu2_attn_buzz(); stepper.disable_extruder(); @@ -994,7 +999,7 @@ bool MMU2::unload() { if (!_enabled) return false; if (thermalManager.tooColdToExtrude(active_extruder)) { - BUZZ(200, 404); + mmu2_attn_buzz(); LCD_ALERTMESSAGE(MSG_HOTEND_TOO_COLD); return false; } @@ -1005,7 +1010,7 @@ bool MMU2::unload() { command(MMU_CMD_U0); manage_response(false, true); - BUZZ(200, 404); + mmu2_attn_buzz(); // no active tool extruder = MMU2_NO_TOOL; diff --git a/Marlin/src/feature/pause.cpp b/Marlin/src/feature/pause.cpp index 34ebcbc7f0..8aa1ff4f03 100644 --- a/Marlin/src/feature/pause.cpp +++ b/Marlin/src/feature/pause.cpp @@ -217,8 +217,8 @@ bool load_filament(const_float_t slow_load_length/*=0*/, const_float_t fast_load REPEAT_1(NUM_RUNOUT_SENSORS, _CASE_RUNOUT) #undef _CASE_RUNOUT } - const uint8_t rm = runout.mode[i - 1]; - if (rm != 0 && rm != 7 && extDigitalRead(pin) != runout.out_state(i - 1)) + const RunoutMode rm = runout.mode[i - 1]; + if (rm != RM_NONE && rm != RM_MOTION_SENSOR && extDigitalRead(pin) != runout.out_state(i - 1)) wait_for_user = false; } #else diff --git a/Marlin/src/feature/powerloss.cpp b/Marlin/src/feature/powerloss.cpp index 214c248d35..0fc195e7dd 100644 --- a/Marlin/src/feature/powerloss.cpp +++ b/Marlin/src/feature/powerloss.cpp @@ -196,7 +196,7 @@ void PrintJobRecovery::save(const bool force/*=false*/, const float zraise/*=POW #if DISABLED(NO_VOLUMETRICS) info.flag.volumetric_enabled = parser.volumetric_enabled; #if HAS_MULTI_EXTRUDER - for (int8_t e = 0; e < EXTRUDERS; e++) info.filament_size[e] = planner.filament_size[e]; + EXTRUDER_LOOP() info.filament_size[e] = planner.filament_size[e]; #else if (parser.volumetric_enabled) info.filament_size[0] = planner.filament_size[active_extruder]; #endif @@ -461,7 +461,7 @@ void PrintJobRecovery::resume() { // Recover volumetric extrusion state #if DISABLED(NO_VOLUMETRICS) #if HAS_MULTI_EXTRUDER - for (int8_t e = 0; e < EXTRUDERS; e++) { + EXTRUDER_LOOP() { sprintf_P(cmd, PSTR("M200T%iD%s"), e, dtostrf(info.filament_size[e], 1, 3, str_1)); gcode.process_subcommands_now(cmd); } @@ -511,7 +511,7 @@ void PrintJobRecovery::resume() { // Restore retract and hop state from an active `G10` command #if ENABLED(FWRETRACT) - LOOP_L_N(e, EXTRUDERS) { + EXTRUDER_LOOP() { if (info.retract[e] != 0.0) { fwretract.current_retract[e] = info.retract[e]; fwretract.retracted[e] = true; @@ -562,7 +562,7 @@ void PrintJobRecovery::resume() { TERN_(HAS_HOME_OFFSET, home_offset = info.home_offset); TERN_(HAS_POSITION_SHIFT, position_shift = info.position_shift); #if HAS_HOME_OFFSET || HAS_POSITION_SHIFT - LOOP_LINEAR_AXES(i) update_workspace_offset((AxisEnum)i); + LOOP_NUM_AXES(i) update_workspace_offset((AxisEnum)i); #endif // Relative axis modes @@ -612,7 +612,7 @@ void PrintJobRecovery::resume() { #if HAS_HOME_OFFSET DEBUG_ECHOPGM("home_offset: "); - LOOP_LINEAR_AXES(i) { + LOOP_NUM_AXES(i) { if (i) DEBUG_CHAR(','); DEBUG_DECIMAL(info.home_offset[i]); } @@ -621,7 +621,7 @@ void PrintJobRecovery::resume() { #if HAS_POSITION_SHIFT DEBUG_ECHOPGM("position_shift: "); - LOOP_LINEAR_AXES(i) { + LOOP_NUM_AXES(i) { if (i) DEBUG_CHAR(','); DEBUG_DECIMAL(info.position_shift[i]); } @@ -634,7 +634,7 @@ void PrintJobRecovery::resume() { #if DISABLED(NO_VOLUMETRICS) DEBUG_ECHOPGM("filament_size:"); - LOOP_L_N(i, EXTRUDERS) DEBUG_ECHOLNPGM(" ", info.filament_size[i]); + EXTRUDER_LOOP() DEBUG_ECHOLNPGM(" ", info.filament_size[e]); DEBUG_EOL(); #endif @@ -666,7 +666,7 @@ void PrintJobRecovery::resume() { #if ENABLED(FWRETRACT) DEBUG_ECHOPGM("retract: "); - for (int8_t e = 0; e < EXTRUDERS; e++) { + EXTRUDER_LOOP() { DEBUG_ECHO(info.retract[e]); if (e < EXTRUDERS - 1) DEBUG_CHAR(','); } diff --git a/Marlin/src/feature/runout.cpp b/Marlin/src/feature/runout.cpp index 96238c0f80..aae92d423f 100644 --- a/Marlin/src/feature/runout.cpp +++ b/Marlin/src/feature/runout.cpp @@ -34,7 +34,7 @@ FilamentMonitor runout; bool FilamentMonitorBase::enabled[NUM_RUNOUT_SENSORS], // Initialized by settings.load FilamentMonitorBase::filament_ran_out; // = false -uint8_t FilamentMonitorBase::mode[NUM_RUNOUT_SENSORS]; // Initialized by settings.load +RunoutMode FilamentMonitorBase::mode[NUM_RUNOUT_SENSORS]; // Initialized by settings.load #if ENABLED(HOST_ACTION_COMMANDS) bool FilamentMonitorBase::host_handling; // = false #endif diff --git a/Marlin/src/feature/runout.h b/Marlin/src/feature/runout.h index 72faaef449..261831403b 100644 --- a/Marlin/src/feature/runout.h +++ b/Marlin/src/feature/runout.h @@ -61,12 +61,23 @@ extern FilamentMonitor runout; /*******************************************************************************************/ +enum RunoutMode : uint8_t { + RM_NONE, + RM_OUT_ON_LOW, + RM_OUT_ON_HIGH, + RM_RESERVED3, + RM_RESERVED4, + RM_RESERVED5, + RM_RESERVED6, + RM_MOTION_SENSOR +}; + class FilamentMonitorBase { public: static bool enabled[NUM_RUNOUT_SENSORS], filament_ran_out; - static uint8_t mode[NUM_RUNOUT_SENSORS]; // 0:NONE 1:Switch NC 2:Switch NO 7:Motion Sensor + static RunoutMode mode[NUM_RUNOUT_SENSORS]; - static uint8_t out_state(const uint8_t e=0) { return mode[e] == 2 ? HIGH : LOW; } + static uint8_t out_state(const uint8_t e=0) { return mode[e] == RM_OUT_ON_HIGH ? HIGH : LOW; } #if ENABLED(HOST_ACTION_COMMANDS) static bool host_handling; @@ -111,7 +122,7 @@ class TFilamentMonitor : public FilamentMonitorBase { // Give the response a chance to update its counter. static void run() { - if (enabled[active_extruder] && mode[active_extruder]!=0 && !filament_ran_out && (printingIsActive() || did_pause_print)) { + if (enabled[active_extruder] && mode[active_extruder] != RM_NONE && !filament_ran_out && (printingIsActive() || did_pause_print)) { cli(); // Prevent RunoutResponseDelayed::block_completed from accumulating here response.run(); sensor.run(); @@ -199,6 +210,7 @@ class FilamentSensorBase { #undef _INIT_RUNOUT_PIN #undef INIT_RUNOUT_PIN } + // Return a bitmask of runout pin states static uint8_t poll_runout_pins() { @@ -209,7 +221,7 @@ class FilamentSensorBase { // Return a bitmask of runout flag states (1 bits always indicates runout) static uint8_t poll_runout_states() { - #define _OR_INVERT(N) | (runout.out_state(N) ? 0 : _BV(N)) + #define _OR_INVERT(N) | (runout.out_state(N-1) ? 0 : _BV(N-1)) return poll_runout_pins() ^ uint8_t(0 REPEAT_1(NUM_RUNOUT_SENSORS, _OR_INVERT)); #undef _OR_INVERT } @@ -251,7 +263,7 @@ class FilamentSensorCore : public FilamentSensorBase { public: static void block_completed(const block_t * const b) { - if (runout.mode[active_extruder] != 7) return; + if (runout.mode[active_extruder] != RM_MOTION_SENSOR) return; // If the sensor wheel has moved since the last call to // this method reset the runout counter for the extruder. @@ -263,10 +275,10 @@ class FilamentSensorCore : public FilamentSensorBase { } static void run() { - if (runout.mode[active_extruder] == 7) { + if (runout.mode[active_extruder] == RM_MOTION_SENSOR) { poll_motion_sensor(); } - else if (runout.mode[active_extruder] != 0) { + else if (runout.mode[active_extruder] != RM_NONE) { LOOP_L_N(s, NUM_RUNOUT_SENSORS) { const bool out = poll_runout_state(s); if (!out) filament_present(s); diff --git a/Marlin/src/feature/solenoid.cpp b/Marlin/src/feature/solenoid.cpp index b6795d1a1e..861e44ed05 100644 --- a/Marlin/src/feature/solenoid.cpp +++ b/Marlin/src/feature/solenoid.cpp @@ -27,31 +27,25 @@ #include "solenoid.h" #include "../module/motion.h" // for active_extruder - -// PARKING_EXTRUDER options alter the default behavior of solenoids, this ensures compliance of M380-381 - -#if ENABLED(PARKING_EXTRUDER) - #include "../module/tool_change.h" -#endif +#include "../module/tool_change.h" // Used primarily with MANUAL_SOLENOID_CONTROL -static void set_solenoid(const uint8_t num, const bool active) { - const uint8_t value = active ? PE_MAGNET_ON_STATE : !PE_MAGNET_ON_STATE; - #define _SOL_CASE(N) case N: TERN_(HAS_SOLENOID_##N, OUT_WRITE(SOL##N##_PIN, value)); break; +static void set_solenoid(const uint8_t num, const uint8_t state) { + #define _SOL_CASE(N) case N: TERN_(HAS_SOLENOID_##N, OUT_WRITE(SOL##N##_PIN, state)); break; switch (num) { REPEAT(8, _SOL_CASE) default: SERIAL_ECHO_MSG(STR_INVALID_SOLENOID); break; } #if ENABLED(PARKING_EXTRUDER) - if (!active && active_extruder == num) // If active extruder's solenoid is disabled, carriage is considered parked + if (state == LOW && active_extruder == num) // If active extruder's solenoid is disabled, carriage is considered parked parking_extruder_set_parked(true); #endif } -void enable_solenoid(const uint8_t num) { set_solenoid(num, true); } -void disable_solenoid(const uint8_t num) { set_solenoid(num, false); } -void enable_solenoid_on_active_extruder() { } +// PARKING_EXTRUDER options alter the default behavior of solenoids to ensure compliance of M380-381 +void enable_solenoid(const uint8_t num) { set_solenoid(num, TERN1(PARKING_EXTRUDER, PE_MAGNET_ON_STATE)); } +void disable_solenoid(const uint8_t num) { set_solenoid(num, TERN0(PARKING_EXTRUDER, !PE_MAGNET_ON_STATE)); } void disable_all_solenoids() { #define _SOL_DISABLE(N) TERN_(HAS_SOLENOID_##N, disable_solenoid(N)); diff --git a/Marlin/src/feature/solenoid.h b/Marlin/src/feature/solenoid.h index 2ba4983fb0..3131aeb868 100644 --- a/Marlin/src/feature/solenoid.h +++ b/Marlin/src/feature/solenoid.h @@ -21,7 +21,6 @@ */ #pragma once -void enable_solenoid_on_active_extruder(); void disable_all_solenoids(); void enable_solenoid(const uint8_t num); void disable_solenoid(const uint8_t num); diff --git a/Marlin/src/feature/stepper_driver_safety.cpp b/Marlin/src/feature/stepper_driver_safety.cpp index 11b90954b4..b8762da9b0 100644 --- a/Marlin/src/feature/stepper_driver_safety.cpp +++ b/Marlin/src/feature/stepper_driver_safety.cpp @@ -65,15 +65,18 @@ void stepper_driver_backward_check() { TEST_BACKWARD(I, 8); TEST_BACKWARD(J, 9); TEST_BACKWARD(K, 10); + TEST_BACKWARD(U, 11); + TEST_BACKWARD(V, 12); + TEST_BACKWARD(W, 13); - TEST_BACKWARD(E0, 11); - TEST_BACKWARD(E1, 12); - TEST_BACKWARD(E2, 13); - TEST_BACKWARD(E3, 14); - TEST_BACKWARD(E4, 15); - TEST_BACKWARD(E5, 16); - TEST_BACKWARD(E6, 17); - TEST_BACKWARD(E7, 18); + TEST_BACKWARD(E0, 14); + TEST_BACKWARD(E1, 15); + TEST_BACKWARD(E2, 16); + TEST_BACKWARD(E3, 17); + TEST_BACKWARD(E4, 18); + TEST_BACKWARD(E5, 19); + TEST_BACKWARD(E6, 20); + TEST_BACKWARD(E7, 21); if (!axis_plug_backward) WRITE(SAFE_POWER_PIN, HIGH); @@ -103,15 +106,18 @@ void stepper_driver_backward_report() { REPORT_BACKWARD(I, 8); REPORT_BACKWARD(J, 9); REPORT_BACKWARD(K, 10); + REPORT_BACKWARD(U, 11); + REPORT_BACKWARD(V, 12); + REPORT_BACKWARD(W, 13); - REPORT_BACKWARD(E0, 11); - REPORT_BACKWARD(E1, 12); - REPORT_BACKWARD(E2, 13); - REPORT_BACKWARD(E3, 14); - REPORT_BACKWARD(E4, 15); - REPORT_BACKWARD(E5, 16); - REPORT_BACKWARD(E6, 17); - REPORT_BACKWARD(E7, 18); + REPORT_BACKWARD(E0, 14); + REPORT_BACKWARD(E1, 15); + REPORT_BACKWARD(E2, 16); + REPORT_BACKWARD(E3, 17); + REPORT_BACKWARD(E4, 18); + REPORT_BACKWARD(E5, 19); + REPORT_BACKWARD(E6, 20); + REPORT_BACKWARD(E7, 21); } #endif // HAS_DRIVER_SAFE_POWER_PROTECT diff --git a/Marlin/src/feature/tmc_util.cpp b/Marlin/src/feature/tmc_util.cpp index c69772bebc..cb970c7ebc 100644 --- a/Marlin/src/feature/tmc_util.cpp +++ b/Marlin/src/feature/tmc_util.cpp @@ -429,6 +429,18 @@ if (monitor_tmc_driver(stepperK, need_update_error_counters, need_debug_reporting)) step_current_down(stepperK); #endif + #if AXIS_IS_TMC(U) + if (monitor_tmc_driver(stepperU, need_update_error_counters, need_debug_reporting)) + step_current_down(stepperU); + #endif + #if AXIS_IS_TMC(V) + if (monitor_tmc_driver(stepperV, need_update_error_counters, need_debug_reporting)) + step_current_down(stepperV); + #endif + #if AXIS_IS_TMC(W) + if (monitor_tmc_driver(stepperW, need_update_error_counters, need_debug_reporting)) + step_current_down(stepperW); + #endif #if AXIS_IS_TMC(E0) (void)monitor_tmc_driver(stepperE0, need_update_error_counters, need_debug_reporting); @@ -809,6 +821,15 @@ #if AXIS_IS_TMC(K) if (k) tmc_status(stepperK, n); #endif + #if AXIS_IS_TMC(U) + if (u) tmc_status(stepperU, n); + #endif + #if AXIS_IS_TMC(V) + if (v) tmc_status(stepperV, n); + #endif + #if AXIS_IS_TMC(W) + if (w) tmc_status(stepperW, n); + #endif if (TERN0(HAS_EXTRUDERS, e)) { #if AXIS_IS_TMC(E0) @@ -883,6 +904,15 @@ #if AXIS_IS_TMC(K) if (k) tmc_parse_drv_status(stepperK, n); #endif + #if AXIS_IS_TMC(U) + if (u) tmc_parse_drv_status(stepperU, n); + #endif + #if AXIS_IS_TMC(V) + if (v) tmc_parse_drv_status(stepperV, n); + #endif + #if AXIS_IS_TMC(W) + if (w) tmc_parse_drv_status(stepperW, n); + #endif if (TERN0(HAS_EXTRUDERS, e)) { #if AXIS_IS_TMC(E0) @@ -1088,6 +1118,15 @@ #if AXIS_IS_TMC(K) if (k) tmc_get_registers(stepperK, n); #endif + #if AXIS_IS_TMC(U) + if (u) tmc_get_registers(stepperU, n); + #endif + #if AXIS_IS_TMC(V) + if (v) tmc_get_registers(stepperV, n); + #endif + #if AXIS_IS_TMC(W) + if (w) tmc_get_registers(stepperW, n); + #endif if (TERN0(HAS_EXTRUDERS, e)) { #if AXIS_IS_TMC(E0) @@ -1244,6 +1283,15 @@ void test_tmc_connection(LOGICAL_AXIS_ARGS(const bool)) { #if AXIS_IS_TMC(K) if (k) axis_connection += test_connection(stepperK); #endif + #if AXIS_IS_TMC(U) + if (u) axis_connection += test_connection(stepperU); + #endif + #if AXIS_IS_TMC(V) + if (v) axis_connection += test_connection(stepperV); + #endif + #if AXIS_IS_TMC(W) + if (w) axis_connection += test_connection(stepperW); + #endif if (TERN0(HAS_EXTRUDERS, e)) { #if AXIS_IS_TMC(E0) @@ -1313,6 +1361,15 @@ void test_tmc_connection(LOGICAL_AXIS_ARGS(const bool)) { #if AXIS_HAS_SPI(K) SET_CS_PIN(K); #endif + #if AXIS_HAS_SPI(U) + SET_CS_PIN(U); + #endif + #if AXIS_HAS_SPI(V) + SET_CS_PIN(V); + #endif + #if AXIS_HAS_SPI(W) + SET_CS_PIN(W); + #endif #if AXIS_HAS_SPI(E0) SET_CS_PIN(E0); #endif diff --git a/Marlin/src/feature/tmc_util.h b/Marlin/src/feature/tmc_util.h index fc333b09dd..c10bab6274 100644 --- a/Marlin/src/feature/tmc_util.h +++ b/Marlin/src/feature/tmc_util.h @@ -348,7 +348,7 @@ void test_tmc_connection(LOGICAL_AXIS_DECL(const bool, true)); #if USE_SENSORLESS // Track enabled status of stealthChop and only re-enable where applicable - struct sensorless_t { bool LINEAR_AXIS_ARGS(), x2, y2, z2, z3, z4; }; + struct sensorless_t { bool NUM_AXIS_ARGS(), x2, y2, z2, z3, z4; }; #if ENABLED(IMPROVE_HOMING_RELIABILITY) extern millis_t sg_guard_period; diff --git a/Marlin/src/gcode/bedlevel/M420.cpp b/Marlin/src/gcode/bedlevel/M420.cpp index 3c23e85a1d..c8325b1fc5 100644 --- a/Marlin/src/gcode/bedlevel/M420.cpp +++ b/Marlin/src/gcode/bedlevel/M420.cpp @@ -67,14 +67,17 @@ void GcodeSuite::M420() { const float x_min = probe.min_x(), x_max = probe.max_x(), y_min = probe.min_y(), y_max = probe.max_y(); #if ENABLED(AUTO_BED_LEVELING_BILINEAR) - bilinear_start.set(x_min, y_min); - bilinear_grid_spacing.set((x_max - x_min) / (GRID_MAX_CELLS_X), - (y_max - y_min) / (GRID_MAX_CELLS_Y)); + xy_pos_t start, spacing; + start.set(x_min, y_min); + spacing.set((x_max - x_min) / (GRID_MAX_CELLS_X), + (y_max - y_min) / (GRID_MAX_CELLS_Y)); + bbl.set_grid(spacing, start); #endif GRID_LOOP(x, y) { Z_VALUES(x, y) = 0.001 * random(-200, 200); TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(x, y, Z_VALUES(x, y))); } + TERN_(AUTO_BED_LEVELING_BILINEAR, bbl.refresh_bed_level()); SERIAL_ECHOPGM("Simulated " STRINGIFY(GRID_MAX_POINTS_X) "x" STRINGIFY(GRID_MAX_POINTS_Y) " mesh "); SERIAL_ECHOPGM(" (", x_min); SERIAL_CHAR(','); SERIAL_ECHO(y_min); @@ -178,7 +181,7 @@ void GcodeSuite::M420() { Z_VALUES(x, y) -= zmean; TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(x, y, Z_VALUES(x, y))); } - TERN_(ABL_BILINEAR_SUBDIVISION, bed_level_virt_interpolate()); + TERN_(AUTO_BED_LEVELING_BILINEAR, bbl.refresh_bed_level()); } #endif @@ -199,8 +202,7 @@ void GcodeSuite::M420() { #else if (leveling_is_valid()) { #if ENABLED(AUTO_BED_LEVELING_BILINEAR) - print_bilinear_leveling_grid(); - TERN_(ABL_BILINEAR_SUBDIVISION, print_bilinear_leveling_grid_virt()); + bbl.print_leveling_grid(); #elif ENABLED(MESH_BED_LEVELING) SERIAL_ECHOLNPGM("Mesh Bed Level data:"); mbl.report_mesh(); diff --git a/Marlin/src/gcode/bedlevel/abl/G29.cpp b/Marlin/src/gcode/bedlevel/abl/G29.cpp index 33f45e1c9f..ac8eff0e95 100644 --- a/Marlin/src/gcode/bedlevel/abl/G29.cpp +++ b/Marlin/src/gcode/bedlevel/abl/G29.cpp @@ -124,6 +124,7 @@ public: #if ENABLED(AUTO_BED_LEVELING_BILINEAR) float Z_offset; + bed_mesh_t z_values; #endif #if ENABLED(AUTO_BED_LEVELING_LINEAR) @@ -308,8 +309,8 @@ G29_TYPE GcodeSuite::G29() { if (!isnan(rx) && !isnan(ry)) { // Get nearest i / j from rx / ry - i = (rx - bilinear_start.x + 0.5 * abl.gridSpacing.x) / abl.gridSpacing.x; - j = (ry - bilinear_start.y + 0.5 * abl.gridSpacing.y) / abl.gridSpacing.y; + i = (rx - bbl.get_grid_start().x) / bbl.get_grid_spacing().x + 0.5f; + j = (ry - bbl.get_grid_start().y) / bbl.get_grid_spacing().y + 0.5f; LIMIT(i, 0, (GRID_MAX_POINTS_X) - 1); LIMIT(j, 0, (GRID_MAX_POINTS_Y) - 1); } @@ -318,8 +319,8 @@ G29_TYPE GcodeSuite::G29() { if (WITHIN(i, 0, (GRID_MAX_POINTS_X) - 1) && WITHIN(j, 0, (GRID_MAX_POINTS_Y) - 1)) { set_bed_leveling_enabled(false); - z_values[i][j] = rz; - TERN_(ABL_BILINEAR_SUBDIVISION, bed_level_virt_interpolate()); + Z_VALUES_ARR[i][j] = rz; + bbl.refresh_bed_level(); TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(i, j, rz)); set_bed_leveling_enabled(abl.reenable); if (abl.reenable) report_current_position(); @@ -419,12 +420,13 @@ G29_TYPE GcodeSuite::G29() { planner.synchronize(); + TERN_(EXTENSIBLE_UI, ExtUI::onLevelingStart()); + #if ENABLED(AUTO_BED_LEVELING_3POINT) if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("> 3-point Leveling"); points[0].z = points[1].z = points[2].z = 0; // Probe at 3 arbitrary points #elif ENABLED(AUTO_BED_LEVELING_BILINEAR) - TERN_(EXTENSIBLE_UI, ExtUI::onMeshLevelingStart()); - TERN_(DWIN_LCD_PROUI, DWIN_MeshLevelingStart()); + TERN_(DWIN_CREALITY_LCD_ENHANCED, DWIN_LevelingStart()); #endif if (!faux) { @@ -435,6 +437,42 @@ G29_TYPE GcodeSuite::G29() { #endif } + // Position bed horizontally and Z probe vertically. + #if defined(SAFE_BED_LEVELING_START_X) || defined(SAFE_BED_LEVELING_START_Y) || defined(SAFE_BED_LEVELING_START_Z) \ + || defined(SAFE_BED_LEVELING_START_I) || defined(SAFE_BED_LEVELING_START_J) || defined(SAFE_BED_LEVELING_START_K) \ + || defined(SAFE_BED_LEVELING_START_U) || defined(SAFE_BED_LEVELING_START_V) || defined(SAFE_BED_LEVELING_START_W) + xyze_pos_t safe_position = current_position; + #ifdef SAFE_BED_LEVELING_START_X + safe_position.x = SAFE_BED_LEVELING_START_X; + #endif + #ifdef SAFE_BED_LEVELING_START_Y + safe_position.y = SAFE_BED_LEVELING_START_Y; + #endif + #ifdef SAFE_BED_LEVELING_START_Z + safe_position.z = SAFE_BED_LEVELING_START_Z; + #endif + #ifdef SAFE_BED_LEVELING_START_I + safe_position.i = SAFE_BED_LEVELING_START_I; + #endif + #ifdef SAFE_BED_LEVELING_START_J + safe_position.j = SAFE_BED_LEVELING_START_J; + #endif + #ifdef SAFE_BED_LEVELING_START_K + safe_position.k = SAFE_BED_LEVELING_START_K; + #endif + #ifdef SAFE_BED_LEVELING_START_U + safe_position.u = SAFE_BED_LEVELING_START_U; + #endif + #ifdef SAFE_BED_LEVELING_START_V + safe_position.v = SAFE_BED_LEVELING_START_V; + #endif + #ifdef SAFE_BED_LEVELING_START_W + safe_position.w = SAFE_BED_LEVELING_START_W; + #endif + + do_blocking_move_to(safe_position); + #endif + // Disable auto bed leveling during G29. // Be formal so G29 can be done successively without G28. if (!no_action) set_bed_leveling_enabled(false); @@ -450,16 +488,12 @@ G29_TYPE GcodeSuite::G29() { #endif #if ENABLED(AUTO_BED_LEVELING_BILINEAR) - if (TERN1(PROBE_MANUALLY, !no_action) - && (abl.gridSpacing != bilinear_grid_spacing || abl.probe_position_lf != bilinear_start) + if (!abl.dryrun + && (abl.gridSpacing != bbl.get_grid_spacing() || abl.probe_position_lf != bbl.get_grid_start()) ) { // Reset grid to 0.0 or "not probed". (Also disables ABL) reset_bed_level(); - // Initialize a grid with the given dimensions - bilinear_grid_spacing = abl.gridSpacing; - bilinear_start = abl.probe_position_lf; - // Can't re-enable (on error) until the new grid is written abl.reenable = false; } @@ -530,7 +564,7 @@ G29_TYPE GcodeSuite::G29() { #elif ENABLED(AUTO_BED_LEVELING_BILINEAR) const float newz = abl.measured_z + abl.Z_offset; - z_values[abl.meshCount.x][abl.meshCount.y] = newz; + abl.z_values[abl.meshCount.x][abl.meshCount.y] = newz; TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(abl.meshCount, newz)); if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM_P(PSTR("Save X"), abl.meshCount.x, SP_Y_STR, abl.meshCount.y, SP_Z_STR, abl.measured_z + abl.Z_offset); @@ -577,6 +611,7 @@ G29_TYPE GcodeSuite::G29() { SERIAL_ECHOLNPGM("Grid probing done."); // Re-enable software endstops, if needed SET_SOFT_ENDSTOP_LOOSE(false); + TERN_(EXTENSIBLE_UI, ExtUI::onLevelingDone()); } #elif ENABLED(AUTO_BED_LEVELING_3POINT) @@ -606,6 +641,8 @@ G29_TYPE GcodeSuite::G29() { abl.reenable = false; } + TERN_(EXTENSIBLE_UI, ExtUI::onLevelingDone()); + } #endif // AUTO_BED_LEVELING_3POINT @@ -678,7 +715,7 @@ G29_TYPE GcodeSuite::G29() { #elif ENABLED(AUTO_BED_LEVELING_BILINEAR) const float z = abl.measured_z + abl.Z_offset; - z_values[abl.meshCount.x][abl.meshCount.y] = z; + abl.z_values[abl.meshCount.x][abl.meshCount.y] = z; TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(abl.meshCount, z)); #endif @@ -749,12 +786,16 @@ G29_TYPE GcodeSuite::G29() { if (!isnan(abl.measured_z)) { #if ENABLED(AUTO_BED_LEVELING_BILINEAR) - if (!abl.dryrun) extrapolate_unprobed_bed_level(); - print_bilinear_leveling_grid(); + if (abl.dryrun) + bbl.print_leveling_grid(&abl.z_values); + else { + bbl.set_grid(abl.gridSpacing, abl.probe_position_lf); + COPY(Z_VALUES_ARR, abl.z_values); + TERN_(IS_KINEMATIC, bbl.extrapolate_unprobed_bed_level()); + bbl.refresh_bed_level(); - refresh_bed_level(); - - TERN_(ABL_BILINEAR_SUBDIVISION, print_bilinear_leveling_grid_virt()); + bbl.print_leveling_grid(); + } #elif ENABLED(AUTO_BED_LEVELING_LINEAR) @@ -874,7 +915,7 @@ G29_TYPE GcodeSuite::G29() { // Unapply the offset because it is going to be immediately applied // and cause compensation movement in Z const float fade_scaling_factor = TERN(ENABLE_LEVELING_FADE_HEIGHT, planner.fade_scaling_factor_for_z(current_position.z), 1); - current_position.z -= fade_scaling_factor * bilinear_z_offset(current_position); + current_position.z -= fade_scaling_factor * bbl.get_z_correction(current_position); if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM(" corrected Z:", current_position.z); } @@ -899,7 +940,7 @@ G29_TYPE GcodeSuite::G29() { process_subcommands_now(F(Z_PROBE_END_SCRIPT)); #endif - TERN_(HAS_DWIN_E3V2_BASIC, DWIN_CompletedLeveling()); + TERN_(HAS_DWIN_E3V2_BASIC, DWIN_LevelingDone()); TERN_(HAS_MULTI_HOTEND, if (abl.tool_index != 0) tool_change(abl.tool_index)); diff --git a/Marlin/src/gcode/bedlevel/abl/M421.cpp b/Marlin/src/gcode/bedlevel/abl/M421.cpp index 182dc32515..0c12268cb1 100644 --- a/Marlin/src/gcode/bedlevel/abl/M421.cpp +++ b/Marlin/src/gcode/bedlevel/abl/M421.cpp @@ -58,11 +58,11 @@ void GcodeSuite::M421() { sy = iy >= 0 ? iy : 0, ey = iy >= 0 ? iy : GRID_MAX_POINTS_Y - 1; LOOP_S_LE_N(x, sx, ex) { LOOP_S_LE_N(y, sy, ey) { - z_values[x][y] = zval + (hasQ ? z_values[x][y] : 0); - TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(x, y, z_values[x][y])); + Z_VALUES_ARR[x][y] = zval + (hasQ ? Z_VALUES_ARR[x][y] : 0); + TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(x, y, Z_VALUES_ARR[x][y])); } } - TERN_(ABL_BILINEAR_SUBDIVISION, bed_level_virt_interpolate()); + bbl.refresh_bed_level(); } else SERIAL_ERROR_MSG(STR_ERR_MESH_XY); diff --git a/Marlin/src/gcode/bedlevel/mbl/G29.cpp b/Marlin/src/gcode/bedlevel/mbl/G29.cpp index 3767cef3cf..e04073b122 100644 --- a/Marlin/src/gcode/bedlevel/mbl/G29.cpp +++ b/Marlin/src/gcode/bedlevel/mbl/G29.cpp @@ -104,8 +104,45 @@ void GcodeSuite::G29() { mbl_probe_index = 0; if (!ui.wait_for_move) { queue.inject(parser.seen_test('N') ? F("G28" TERN(CAN_SET_LEVELING_AFTER_G28, "L0", "") "\nG29S2") : F("G29S2")); - TERN_(EXTENSIBLE_UI, ExtUI::onMeshLevelingStart()); - TERN_(DWIN_LCD_PROUI, DWIN_MeshLevelingStart()); + TERN_(EXTENSIBLE_UI, ExtUI::onLevelingStart()); + TERN_(DWIN_LCD_PROUI, DWIN_LevelingStart()); + + // Position bed horizontally and Z probe vertically. + #if defined(SAFE_BED_LEVELING_START_X) || defined(SAFE_BED_LEVELING_START_Y) || defined(SAFE_BED_LEVELING_START_Z) \ + || defined(SAFE_BED_LEVELING_START_I) || defined(SAFE_BED_LEVELING_START_J) || defined(SAFE_BED_LEVELING_START_K) \ + || defined(SAFE_BED_LEVELING_START_U) || defined(SAFE_BED_LEVELING_START_V) || defined(SAFE_BED_LEVELING_START_W) + xyze_pos_t safe_position = current_position; + #ifdef SAFE_BED_LEVELING_START_X + safe_position.x = SAFE_BED_LEVELING_START_X; + #endif + #ifdef SAFE_BED_LEVELING_START_Y + safe_position.y = SAFE_BED_LEVELING_START_Y; + #endif + #ifdef SAFE_BED_LEVELING_START_Z + safe_position.z = SAFE_BED_LEVELING_START_Z; + #endif + #ifdef SAFE_BED_LEVELING_START_I + safe_position.i = SAFE_BED_LEVELING_START_I; + #endif + #ifdef SAFE_BED_LEVELING_START_J + safe_position.j = SAFE_BED_LEVELING_START_J; + #endif + #ifdef SAFE_BED_LEVELING_START_K + safe_position.k = SAFE_BED_LEVELING_START_K; + #endif + #ifdef SAFE_BED_LEVELING_START_U + safe_position.u = SAFE_BED_LEVELING_START_U; + #endif + #ifdef SAFE_BED_LEVELING_START_V + safe_position.v = SAFE_BED_LEVELING_START_V; + #endif + #ifdef SAFE_BED_LEVELING_START_W + safe_position.w = SAFE_BED_LEVELING_START_W; + #endif + + do_blocking_move_to(safe_position); + #endif + return; } state = MeshNext; @@ -118,9 +155,11 @@ void GcodeSuite::G29() { // For each G29 S2... if (mbl_probe_index == 0) { // Move close to the bed before the first point - do_blocking_move_to_z(0.4f + do_blocking_move_to_z( #ifdef MANUAL_PROBE_START_Z - + (MANUAL_PROBE_START_Z) - 0.4f + MANUAL_PROBE_START_Z + #else + 0.4f #endif ); } @@ -155,8 +194,7 @@ void GcodeSuite::G29() { mbl_probe_index = -1; SERIAL_ECHOLNPGM("Mesh probing done."); TERN_(HAS_STATUS_MESSAGE, LCD_MESSAGE(MSG_MESH_DONE)); - BUZZ(100, 659); - BUZZ(100, 698); + OKAY_BUZZ(); home_all_axes(); set_bed_leveling_enabled(true); @@ -168,6 +206,7 @@ void GcodeSuite::G29() { #endif TERN_(LCD_BED_LEVELING, ui.wait_for_move = false); + TERN_(EXTENSIBLE_UI, ExtUI::onLevelingDone()); } break; diff --git a/Marlin/src/gcode/calibrate/G28.cpp b/Marlin/src/gcode/calibrate/G28.cpp index dbbea79353..07896856a1 100644 --- a/Marlin/src/gcode/calibrate/G28.cpp +++ b/Marlin/src/gcode/calibrate/G28.cpp @@ -82,15 +82,13 @@ #if ENABLED(SENSORLESS_HOMING) sensorless_t stealth_states { - LINEAR_AXIS_LIST(tmc_enable_stallguard(stepperX), tmc_enable_stallguard(stepperY), false, false, false, false) - , false - #if AXIS_HAS_STALLGUARD(X2) - || tmc_enable_stallguard(stepperX2) - #endif - , false - #if AXIS_HAS_STALLGUARD(Y2) - || tmc_enable_stallguard(stepperY2) - #endif + NUM_AXIS_LIST( + TERN0(X_SENSORLESS, tmc_enable_stallguard(stepperX)), + TERN0(Y_SENSORLESS, tmc_enable_stallguard(stepperY)), + false, false, false, false + ) + , TERN0(X2_SENSORLESS, tmc_enable_stallguard(stepperX2)) + , TERN0(Y2_SENSORLESS, tmc_enable_stallguard(stepperY2)) }; #endif @@ -101,14 +99,10 @@ current_position.set(0.0, 0.0); #if ENABLED(SENSORLESS_HOMING) && DISABLED(ENDSTOPS_ALWAYS_ON_DEFAULT) - tmc_disable_stallguard(stepperX, stealth_states.x); - tmc_disable_stallguard(stepperY, stealth_states.y); - #if AXIS_HAS_STALLGUARD(X2) - tmc_disable_stallguard(stepperX2, stealth_states.x2); - #endif - #if AXIS_HAS_STALLGUARD(Y2) - tmc_disable_stallguard(stepperY2, stealth_states.y2); - #endif + TERN_(X_SENSORLESS, tmc_disable_stallguard(stepperX, stealth_states.x)); + TERN_(X2_SENSORLESS, tmc_disable_stallguard(stepperX2, stealth_states.x2)); + TERN_(Y_SENSORLESS, tmc_disable_stallguard(stepperY, stealth_states.y)); + TERN_(Y2_SENSORLESS, tmc_disable_stallguard(stepperY2, stealth_states.y2)); #endif } @@ -220,7 +214,7 @@ void GcodeSuite::G28() { #if ENABLED(MARLIN_DEV_MODE) if (parser.seen_test('S')) { - LOOP_LINEAR_AXES(a) set_axis_is_at_home((AxisEnum)a); + LOOP_NUM_AXES(a) set_axis_is_at_home((AxisEnum)a); sync_plan_position(); SERIAL_ECHOLNPGM("Simulated Homing"); report_current_position(); @@ -239,7 +233,7 @@ void GcodeSuite::G28() { set_and_report_grblstate(M_HOMING); #endif - TERN_(HAS_DWIN_E3V2_BASIC, DWIN_StartHoming()); + TERN_(HAS_DWIN_E3V2_BASIC, DWIN_HomingStart()); TERN_(EXTENSIBLE_UI, ExtUI::onHomingStart()); planner.synchronize(); // Wait for planner moves to finish! @@ -264,7 +258,7 @@ void GcodeSuite::G28() { reset_stepper_timeout(); #define HAS_CURRENT_HOME(N) (defined(N##_CURRENT_HOME) && N##_CURRENT_HOME != N##_CURRENT) - #if HAS_CURRENT_HOME(X) || HAS_CURRENT_HOME(X2) || HAS_CURRENT_HOME(Y) || HAS_CURRENT_HOME(Y2) || (ENABLED(DELTA) && HAS_CURRENT_HOME(Z)) || HAS_CURRENT_HOME(I) || HAS_CURRENT_HOME(J) || HAS_CURRENT_HOME(K) + #if HAS_CURRENT_HOME(X) || HAS_CURRENT_HOME(X2) || HAS_CURRENT_HOME(Y) || HAS_CURRENT_HOME(Y2) || (ENABLED(DELTA) && HAS_CURRENT_HOME(Z)) || HAS_CURRENT_HOME(I) || HAS_CURRENT_HOME(J) || HAS_CURRENT_HOME(K) || HAS_CURRENT_HOME(U) || HAS_CURRENT_HOME(V) || HAS_CURRENT_HOME(W) #define HAS_HOMING_CURRENT 1 #endif @@ -292,21 +286,6 @@ void GcodeSuite::G28() { stepperY2.rms_current(Y2_CURRENT_HOME); if (DEBUGGING(LEVELING)) debug_current(F(STR_Y2), tmc_save_current_Y2, Y2_CURRENT_HOME); #endif - #if HAS_CURRENT_HOME(I) - const int16_t tmc_save_current_I = stepperI.getMilliamps(); - stepperI.rms_current(I_CURRENT_HOME); - if (DEBUGGING(LEVELING)) debug_current(F(STR_I), tmc_save_current_I, I_CURRENT_HOME); - #endif - #if HAS_CURRENT_HOME(J) - const int16_t tmc_save_current_J = stepperJ.getMilliamps(); - stepperJ.rms_current(J_CURRENT_HOME); - if (DEBUGGING(LEVELING)) debug_current(F(STR_J), tmc_save_current_J, J_CURRENT_HOME); - #endif - #if HAS_CURRENT_HOME(K) - const int16_t tmc_save_current_K = stepperK.getMilliamps(); - stepperK.rms_current(K_CURRENT_HOME); - if (DEBUGGING(LEVELING)) debug_current(F(STR_K), tmc_save_current_K, K_CURRENT_HOME); - #endif #if HAS_CURRENT_HOME(Z) && ENABLED(DELTA) const int16_t tmc_save_current_Z = stepperZ.getMilliamps(); stepperZ.rms_current(Z_CURRENT_HOME); @@ -327,6 +306,21 @@ void GcodeSuite::G28() { stepperK.rms_current(K_CURRENT_HOME); if (DEBUGGING(LEVELING)) debug_current(F(STR_K), tmc_save_current_K, K_CURRENT_HOME); #endif + #if HAS_CURRENT_HOME(U) + const int16_t tmc_save_current_U = stepperU.getMilliamps(); + stepperU.rms_current(U_CURRENT_HOME); + if (DEBUGGING(LEVELING)) debug_current(F(STR_U), tmc_save_current_U, U_CURRENT_HOME); + #endif + #if HAS_CURRENT_HOME(V) + const int16_t tmc_save_current_V = stepperV.getMilliamps(); + stepperV.rms_current(V_CURRENT_HOME); + if (DEBUGGING(LEVELING)) debug_current(F(STR_V), tmc_save_current_V, V_CURRENT_HOME); + #endif + #if HAS_CURRENT_HOME(W) + const int16_t tmc_save_current_W = stepperW.getMilliamps(); + stepperW.rms_current(W_CURRENT_HOME); + if (DEBUGGING(LEVELING)) debug_current(F(STR_W), tmc_save_current_W, W_CURRENT_HOME); + #endif #endif #if ENABLED(IMPROVE_HOMING_RELIABILITY) @@ -370,23 +364,28 @@ void GcodeSuite::G28() { #define _UNSAFE(A) (homeZ && TERN0(Z_SAFE_HOMING, axes_should_home(_BV(A##_AXIS)))) const bool homeZ = TERN0(HAS_Z_AXIS, parser.seen_test('Z')), - LINEAR_AXIS_LIST( // Other axes should be homed before Z safe-homing + NUM_AXIS_LIST( // Other axes should be homed before Z safe-homing needX = _UNSAFE(X), needY = _UNSAFE(Y), needZ = false, // UNUSED - needI = _UNSAFE(I), needJ = _UNSAFE(J), needK = _UNSAFE(K) + needI = _UNSAFE(I), needJ = _UNSAFE(J), needK = _UNSAFE(K), + needU = _UNSAFE(U), needV = _UNSAFE(V), needW = _UNSAFE(W) ), - LINEAR_AXIS_LIST( // Home each axis if needed or flagged + NUM_AXIS_LIST( // Home each axis if needed or flagged homeX = needX || parser.seen_test('X'), homeY = needY || parser.seen_test('Y'), homeZZ = homeZ, - homeI = needI || parser.seen_test(AXIS4_NAME), homeJ = needJ || parser.seen_test(AXIS5_NAME), homeK = needK || parser.seen_test(AXIS6_NAME) + homeI = needI || parser.seen_test(AXIS4_NAME), homeJ = needJ || parser.seen_test(AXIS5_NAME), + homeK = needK || parser.seen_test(AXIS6_NAME), homeU = needU || parser.seen_test(AXIS7_NAME), + homeV = needV || parser.seen_test(AXIS8_NAME), homeW = needW || parser.seen_test(AXIS9_NAME), ), - home_all = LINEAR_AXIS_GANG( // Home-all if all or none are flagged + home_all = NUM_AXIS_GANG( // Home-all if all or none are flagged homeX == homeX, && homeY == homeX, && homeZ == homeX, - && homeI == homeX, && homeJ == homeX, && homeK == homeX + && homeI == homeX, && homeJ == homeX, && homeK == homeX, + && homeU == homeX, && homeV == homeX, && homeW == homeX ), - LINEAR_AXIS_LIST( + NUM_AXIS_LIST( doX = home_all || homeX, doY = home_all || homeY, doZ = home_all || homeZ, - doI = home_all || homeI, doJ = home_all || homeJ, doK = home_all || homeK + doI = home_all || homeI, doJ = home_all || homeJ, doK = home_all || homeK, + doU = home_all || homeU, doV = home_all || homeV, doW = home_all || homeW ); #if HAS_Z_AXIS @@ -400,7 +399,7 @@ void GcodeSuite::G28() { const bool seenR = parser.seenval('R'); const float z_homing_height = seenR ? parser.value_linear_units() : Z_HOMING_HEIGHT; - if (z_homing_height && (seenR || LINEAR_AXIS_GANG(doX, || doY, || TERN0(Z_SAFE_HOMING, doZ), || doI, || doJ, || doK))) { + if (z_homing_height && (seenR || NUM_AXIS_GANG(doX, || doY, || TERN0(Z_SAFE_HOMING, doZ), || doI, || doJ, || doK, || doU, || doV, || doW))) { // Raise Z before homing any other axes and z is not already high enough (never lower z) if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Raise Z (before homing) by ", z_homing_height); do_z_clearance(z_homing_height); @@ -440,32 +439,52 @@ void GcodeSuite::G28() { #endif } + #if BOTH(FOAMCUTTER_XYUV, HAS_I_AXIS) + // Home I (after X) + if (doI) homeaxis(I_AXIS); + #endif + // Home Y (after X) if (DISABLED(HOME_Y_BEFORE_X) && doY) homeaxis(Y_AXIS); - TERN_(IMPROVE_HOMING_RELIABILITY, end_slow_homing(saved_motion_state)); - - // Home Z last if homing towards the bed - #if HAS_Z_AXIS && DISABLED(HOME_Z_FIRST) - if (doZ) { - #if EITHER(Z_MULTI_ENDSTOPS, Z_STEPPER_AUTO_ALIGN) - stepper.set_all_z_lock(false); - stepper.set_separate_multi_axis(false); - #endif - - #if ENABLED(Z_SAFE_HOMING) - if (TERN1(POWER_LOSS_RECOVERY, !parser.seen_test('H'))) home_z_safely(); else homeaxis(Z_AXIS); - #else - homeaxis(Z_AXIS); - #endif - probe.move_z_after_homing(); - } + #if BOTH(FOAMCUTTER_XYUV, HAS_J_AXIS) + // Home J (after Y) + if (doJ) homeaxis(J_AXIS); #endif - TERN_(HAS_I_AXIS, if (doI) homeaxis(I_AXIS)); - TERN_(HAS_J_AXIS, if (doJ) homeaxis(J_AXIS)); - TERN_(HAS_K_AXIS, if (doK) homeaxis(K_AXIS)); + TERN_(IMPROVE_HOMING_RELIABILITY, end_slow_homing(saved_motion_state)); + + #if ENABLED(FOAMCUTTER_XYUV) + // skip homing of unused Z axis for foamcutters + if (doZ) set_axis_is_at_home(Z_AXIS); + #else + // Home Z last if homing towards the bed + #if HAS_Z_AXIS && DISABLED(HOME_Z_FIRST) + if (doZ) { + #if EITHER(Z_MULTI_ENDSTOPS, Z_STEPPER_AUTO_ALIGN) + stepper.set_all_z_lock(false); + stepper.set_separate_multi_axis(false); + #endif + + #if ENABLED(Z_SAFE_HOMING) + if (TERN1(POWER_LOSS_RECOVERY, !parser.seen_test('H'))) home_z_safely(); else homeaxis(Z_AXIS); + #else + homeaxis(Z_AXIS); + #endif + probe.move_z_after_homing(); + } + #endif + + SECONDARY_AXIS_CODE( + if (doI) homeaxis(I_AXIS), + if (doJ) homeaxis(J_AXIS), + if (doK) homeaxis(K_AXIS), + if (doU) homeaxis(U_AXIS), + if (doV) homeaxis(V_AXIS), + if (doW) homeaxis(W_AXIS) + ); + #endif sync_plan_position(); @@ -548,12 +567,21 @@ void GcodeSuite::G28() { #if HAS_CURRENT_HOME(K) stepperK.rms_current(tmc_save_current_K); #endif + #if HAS_CURRENT_HOME(U) + stepperU.rms_current(tmc_save_current_U); + #endif + #if HAS_CURRENT_HOME(V) + stepperV.rms_current(tmc_save_current_V); + #endif + #if HAS_CURRENT_HOME(W) + stepperW.rms_current(tmc_save_current_W); + #endif #endif // HAS_HOMING_CURRENT ui.refresh(); - TERN_(HAS_DWIN_E3V2_BASIC, DWIN_CompletedHoming()); - TERN_(EXTENSIBLE_UI, ExtUI::onHomingComplete()); + TERN_(HAS_DWIN_E3V2_BASIC, DWIN_HomingDone()); + TERN_(EXTENSIBLE_UI, ExtUI::onHomingDone()); report_current_position(); @@ -568,7 +596,7 @@ void GcodeSuite::G28() { // If not, this will need a PROGMEM directive and an accessor. #define _EN_ITEM(N) , E_AXIS static constexpr AxisEnum L64XX_axis_xref[MAX_L64XX] = { - LINEAR_AXIS_LIST(X_AXIS, Y_AXIS, Z_AXIS, I_AXIS, J_AXIS, K_AXIS), + NUM_AXIS_LIST(X_AXIS, Y_AXIS, Z_AXIS, I_AXIS, J_AXIS, K_AXIS, U_AXIS, V_AXIS, W_AXIS), X_AXIS, Y_AXIS, Z_AXIS, Z_AXIS, Z_AXIS REPEAT(E_STEPPERS, _EN_ITEM) }; diff --git a/Marlin/src/gcode/calibrate/G33.cpp b/Marlin/src/gcode/calibrate/G33.cpp index 506f367947..7f487abd6b 100644 --- a/Marlin/src/gcode/calibrate/G33.cpp +++ b/Marlin/src/gcode/calibrate/G33.cpp @@ -343,7 +343,7 @@ static float auto_tune_a(const float dcr) { abc_float_t delta_e = { 0.0f }, delta_t = { 0.0f }; delta_t.reset(); - LOOP_LINEAR_AXES(axis) { + LOOP_NUM_AXES(axis) { delta_t[axis] = diff; calc_kinematics_diff_probe_points(z_pt, dcr, delta_e, delta_r, delta_t); delta_t[axis] = 0; @@ -536,7 +536,7 @@ void GcodeSuite::G33() { case 1: test_precision = 0.0f; // forced end - LOOP_LINEAR_AXES(axis) e_delta[axis] = +Z4(CEN); + LOOP_NUM_AXES(axis) e_delta[axis] = +Z4(CEN); break; case 2: @@ -584,14 +584,14 @@ void GcodeSuite::G33() { // Normalize angles to least-squares if (_angle_results) { float a_sum = 0.0f; - LOOP_LINEAR_AXES(axis) a_sum += delta_tower_angle_trim[axis]; - LOOP_LINEAR_AXES(axis) delta_tower_angle_trim[axis] -= a_sum / 3.0f; + LOOP_NUM_AXES(axis) a_sum += delta_tower_angle_trim[axis]; + LOOP_NUM_AXES(axis) delta_tower_angle_trim[axis] -= a_sum / 3.0f; } // adjust delta_height and endstops by the max amount const float z_temp = _MAX(delta_endstop_adj.a, delta_endstop_adj.b, delta_endstop_adj.c); delta_height -= z_temp; - LOOP_LINEAR_AXES(axis) delta_endstop_adj[axis] -= z_temp; + LOOP_NUM_AXES(axis) delta_endstop_adj[axis] -= z_temp; } recalc_delta_settings(); NOMORE(zero_std_dev_min, zero_std_dev); diff --git a/Marlin/src/gcode/calibrate/G425.cpp b/Marlin/src/gcode/calibrate/G425.cpp index a2dec64bc3..450a715117 100644 --- a/Marlin/src/gcode/calibrate/G425.cpp +++ b/Marlin/src/gcode/calibrate/G425.cpp @@ -85,10 +85,19 @@ #if ALL(HAS_K_AXIS, CALIBRATION_MEASURE_KMIN, CALIBRATION_MEASURE_KMAX) #define HAS_K_CENTER 1 #endif +#if ALL(HAS_U_AXIS, CALIBRATION_MEASURE_UMIN, CALIBRATION_MEASURE_UMAX) + #define HAS_U_CENTER 1 +#endif +#if ALL(HAS_V_AXIS, CALIBRATION_MEASURE_VMIN, CALIBRATION_MEASURE_VMAX) + #define HAS_V_CENTER 1 +#endif +#if ALL(HAS_W_AXIS, CALIBRATION_MEASURE_WMIN, CALIBRATION_MEASURE_WMAX) + #define HAS_W_CENTER 1 +#endif enum side_t : uint8_t { TOP, RIGHT, FRONT, LEFT, BACK, NUM_SIDES, - LIST_N(DOUBLE(SUB3(LINEAR_AXES)), IMINIMUM, IMAXIMUM, JMINIMUM, JMAXIMUM, KMINIMUM, KMAXIMUM) + LIST_N(DOUBLE(SECONDARY_AXES), IMINIMUM, IMAXIMUM, JMINIMUM, JMAXIMUM, KMINIMUM, KMAXIMUM, UMINIMUM, UMAXIMUM, VMINIMUM, VMAXIMUM, WMINIMUM, WMAXIMUM) }; static constexpr xyz_pos_t true_center CALIBRATION_OBJECT_CENTER; @@ -282,6 +291,15 @@ inline void probe_side(measurements_t &m, const float uncertainty, const side_t #if HAS_K_AXIS && AXIS_CAN_CALIBRATE(K) _PCASE(K); #endif + #if HAS_U_AXIS && AXIS_CAN_CALIBRATE(U) + _PCASE(U); + #endif + #if HAS_V_AXIS && AXIS_CAN_CALIBRATE(V) + _PCASE(V); + #endif + #if HAS_W_AXIS && AXIS_CAN_CALIBRATE(W) + _PCASE(W); + #endif default: return; } @@ -335,6 +353,12 @@ inline void probe_sides(measurements_t &m, const float uncertainty) { TERN_(CALIBRATION_MEASURE_JMAX, probe_side(m, uncertainty, JMAXIMUM, probe_top_at_edge)); TERN_(CALIBRATION_MEASURE_KMIN, probe_side(m, uncertainty, KMINIMUM, probe_top_at_edge)); TERN_(CALIBRATION_MEASURE_KMAX, probe_side(m, uncertainty, KMAXIMUM, probe_top_at_edge)); + TERN_(CALIBRATION_MEASURE_UMIN, probe_side(m, uncertainty, UMINIMUM, probe_top_at_edge)); + TERN_(CALIBRATION_MEASURE_UMAX, probe_side(m, uncertainty, UMAXIMUM, probe_top_at_edge)); + TERN_(CALIBRATION_MEASURE_VMIN, probe_side(m, uncertainty, VMINIMUM, probe_top_at_edge)); + TERN_(CALIBRATION_MEASURE_VMAX, probe_side(m, uncertainty, VMAXIMUM, probe_top_at_edge)); + TERN_(CALIBRATION_MEASURE_WMIN, probe_side(m, uncertainty, WMINIMUM, probe_top_at_edge)); + TERN_(CALIBRATION_MEASURE_WMAX, probe_side(m, uncertainty, WMAXIMUM, probe_top_at_edge)); // Compute the measured center of the calibration object. TERN_(HAS_X_CENTER, m.obj_center.x = (m.obj_side[LEFT] + m.obj_side[RIGHT]) / 2); @@ -342,6 +366,9 @@ inline void probe_sides(measurements_t &m, const float uncertainty) { TERN_(HAS_I_CENTER, m.obj_center.i = (m.obj_side[IMINIMUM] + m.obj_side[IMAXIMUM]) / 2); TERN_(HAS_J_CENTER, m.obj_center.j = (m.obj_side[JMINIMUM] + m.obj_side[JMAXIMUM]) / 2); TERN_(HAS_K_CENTER, m.obj_center.k = (m.obj_side[KMINIMUM] + m.obj_side[KMAXIMUM]) / 2); + TERN_(HAS_U_CENTER, m.obj_center.u = (m.obj_side[UMINIMUM] + m.obj_side[UMAXIMUM]) / 2); + TERN_(HAS_V_CENTER, m.obj_center.v = (m.obj_side[VMINIMUM] + m.obj_side[VMAXIMUM]) / 2); + TERN_(HAS_W_CENTER, m.obj_center.w = (m.obj_side[WMINIMUM] + m.obj_side[WMAXIMUM]) / 2); // Compute the outside diameter of the nozzle at the height // at which it makes contact with the calibration object @@ -352,13 +379,16 @@ inline void probe_sides(measurements_t &m, const float uncertainty) { // The difference between the known and the measured location // of the calibration object is the positional error - LINEAR_AXIS_CODE( + NUM_AXIS_CODE( m.pos_error.x = TERN0(HAS_X_CENTER, true_center.x - m.obj_center.x), m.pos_error.y = TERN0(HAS_Y_CENTER, true_center.y - m.obj_center.y), m.pos_error.z = true_center.z - m.obj_center.z, m.pos_error.i = TERN0(HAS_I_CENTER, true_center.i - m.obj_center.i), m.pos_error.j = TERN0(HAS_J_CENTER, true_center.j - m.obj_center.j), - m.pos_error.k = TERN0(HAS_K_CENTER, true_center.k - m.obj_center.k) + m.pos_error.k = TERN0(HAS_K_CENTER, true_center.k - m.obj_center.k), + m.pos_error.u = TERN0(HAS_U_CENTER, true_center.u - m.obj_center.u), + m.pos_error.v = TERN0(HAS_V_CENTER, true_center.v - m.obj_center.v), + m.pos_error.w = TERN0(HAS_W_CENTER, true_center.w - m.obj_center.w) ); } @@ -406,6 +436,30 @@ inline void probe_sides(measurements_t &m, const float uncertainty) { SERIAL_ECHOLNPGM(" " STR_K_MAX ": ", m.obj_side[KMAXIMUM]); #endif #endif + #if HAS_U_AXIS + #if ENABLED(CALIBRATION_MEASURE_UMIN) + SERIAL_ECHOLNPAIR(" " STR_U_MIN ": ", m.obj_side[UMINIMUM]); + #endif + #if ENABLED(CALIBRATION_MEASURE_UMAX) + SERIAL_ECHOLNPAIR(" " STR_U_MAX ": ", m.obj_side[UMAXIMUM]); + #endif + #endif + #if HAS_V_AXIS + #if ENABLED(CALIBRATION_MEASURE_VMIN) + SERIAL_ECHOLNPAIR(" " STR_V_MIN ": ", m.obj_side[VMINIMUM]); + #endif + #if ENABLED(CALIBRATION_MEASURE_VMAX) + SERIAL_ECHOLNPAIR(" " STR_V_MAX ": ", m.obj_side[VMAXIMUM]); + #endif + #endif + #if HAS_W_AXIS + #if ENABLED(CALIBRATION_MEASURE_WMIN) + SERIAL_ECHOLNPAIR(" " STR_W_MIN ": ", m.obj_side[WMINIMUM]); + #endif + #if ENABLED(CALIBRATION_MEASURE_WMAX) + SERIAL_ECHOLNPAIR(" " STR_W_MAX ": ", m.obj_side[WMAXIMUM]); + #endif + #endif SERIAL_EOL(); } @@ -427,6 +481,15 @@ inline void probe_sides(measurements_t &m, const float uncertainty) { #if HAS_K_CENTER SERIAL_ECHOLNPGM_P(SP_K_STR, m.obj_center.k); #endif + #if HAS_U_CENTER + SERIAL_ECHOLNPGM_P(SP_U_STR, m.obj_center.u); + #endif + #if HAS_V_CENTER + SERIAL_ECHOLNPGM_P(SP_V_STR, m.obj_center.v); + #endif + #if HAS_W_CENTER + SERIAL_ECHOLNPGM_P(SP_W_STR, m.obj_center.w); + #endif SERIAL_EOL(); } @@ -475,6 +538,30 @@ inline void probe_sides(measurements_t &m, const float uncertainty) { SERIAL_ECHOLNPGM(" " STR_K_MAX ": ", m.backlash[KMAXIMUM]); #endif #endif + #if HAS_U_AXIS && AXIS_CAN_CALIBRATE(U) + #if ENABLED(CALIBRATION_MEASURE_UMIN) + SERIAL_ECHOLNPGM(" " STR_U_MIN ": ", m.backlash[UMINIMUM]); + #endif + #if ENABLED(CALIBRATION_MEASURE_UMAX) + SERIAL_ECHOLNPGM(" " STR_U_MAX ": ", m.backlash[UMAXIMUM]); + #endif + #endif + #if HAS_V_AXIS && AXIS_CAN_CALIBRATE(V) + #if ENABLED(CALIBRATION_MEASURE_VMIN) + SERIAL_ECHOLNPGM(" " STR_V_MIN ": ", m.backlash[VMINIMUM]); + #endif + #if ENABLED(CALIBRATION_MEASURE_VMAX) + SERIAL_ECHOLNPGM(" " STR_V_MAX ": ", m.backlash[VMAXIMUM]); + #endif + #endif + #if HAS_W_AXIS && AXIS_CAN_CALIBRATE(W) + #if ENABLED(CALIBRATION_MEASURE_WMIN) + SERIAL_ECHOLNPGM(" " STR_W_MIN ": ", m.backlash[WMINIMUM]); + #endif + #if ENABLED(CALIBRATION_MEASURE_WMAX) + SERIAL_ECHOLNPGM(" " STR_W_MAX ": ", m.backlash[WMAXIMUM]); + #endif + #endif SERIAL_EOL(); } @@ -498,7 +585,16 @@ inline void probe_sides(measurements_t &m, const float uncertainty) { SERIAL_ECHOLNPGM_P(SP_J_STR, m.pos_error.j); #endif #if HAS_K_CENTER && AXIS_CAN_CALIBRATE(K) - SERIAL_ECHOLNPGM_P(SP_Z_STR, m.pos_error.z); + SERIAL_ECHOLNPGM_P(SP_K_STR, m.pos_error.k); + #endif + #if HAS_U_CENTER && AXIS_CAN_CALIBRATE(U) + SERIAL_ECHOLNPGM_P(SP_U_STR, m.pos_error.u); + #endif + #if HAS_V_CENTER && AXIS_CAN_CALIBRATE(V) + SERIAL_ECHOLNPGM_P(SP_V_STR, m.pos_error.v); + #endif + #if HAS_W_CENTER && AXIS_CAN_CALIBRATE(W) + SERIAL_ECHOLNPGM_P(SP_W_STR, m.pos_error.w); #endif SERIAL_EOL(); } @@ -587,6 +683,30 @@ inline void calibrate_backlash(measurements_t &m, const float uncertainty) { backlash.set_distance_mm(K_AXIS, m.backlash[KMAXIMUM]); #endif + #if HAS_U_CENTER + backlash.distance_mm.u = (m.backlash[UMINIMUM] + m.backlash[UMAXIMUM]) / 2; + #elif ENABLED(CALIBRATION_MEASURE_UMIN) + backlash.distance_mm.u = m.backlash[UMINIMUM]; + #elif ENABLED(CALIBRATION_MEASURE_UMAX) + backlash.distance_mm.u = m.backlash[UMAXIMUM]; + #endif + + #if HAS_V_CENTER + backlash.distance_mm.v = (m.backlash[VMINIMUM] + m.backlash[VMAXIMUM]) / 2; + #elif ENABLED(CALIBRATION_MEASURE_VMIN) + backlash.distance_mm.v = m.backlash[VMINIMUM]; + #elif ENABLED(CALIBRATION_MEASURE_UMAX) + backlash.distance_mm.v = m.backlash[VMAXIMUM]; + #endif + + #if HAS_W_CENTER + backlash.distance_mm.w = (m.backlash[WMINIMUM] + m.backlash[WMAXIMUM]) / 2; + #elif ENABLED(CALIBRATION_MEASURE_WMIN) + backlash.distance_mm.w = m.backlash[WMINIMUM]; + #elif ENABLED(CALIBRATION_MEASURE_WMAX) + backlash.distance_mm.w = m.backlash[WMAXIMUM]; + #endif + #endif // BACKLASH_GCODE } @@ -597,9 +717,10 @@ inline void calibrate_backlash(measurements_t &m, const float uncertainty) { // New scope for TEMPORARY_BACKLASH_CORRECTION TEMPORARY_BACKLASH_CORRECTION(backlash.all_on); TEMPORARY_BACKLASH_SMOOTHING(0.0f); - const xyz_float_t move = LINEAR_AXIS_ARRAY( + const xyz_float_t move = NUM_AXIS_ARRAY( AXIS_CAN_CALIBRATE(X) * 3, AXIS_CAN_CALIBRATE(Y) * 3, AXIS_CAN_CALIBRATE(Z) * 3, - AXIS_CAN_CALIBRATE(I) * 3, AXIS_CAN_CALIBRATE(J) * 3, AXIS_CAN_CALIBRATE(K) * 3 + AXIS_CAN_CALIBRATE(I) * 3, AXIS_CAN_CALIBRATE(J) * 3, AXIS_CAN_CALIBRATE(K) * 3, + AXIS_CAN_CALIBRATE(U) * 3, AXIS_CAN_CALIBRATE(V) * 3, AXIS_CAN_CALIBRATE(W) * 3 ); current_position += move; calibration_move(); current_position -= move; calibration_move(); @@ -650,6 +771,9 @@ inline void calibrate_toolhead(measurements_t &m, const float uncertainty, const TERN_(HAS_I_CENTER, update_measurements(m, I_AXIS)); TERN_(HAS_J_CENTER, update_measurements(m, J_AXIS)); TERN_(HAS_K_CENTER, update_measurements(m, K_AXIS)); + TERN_(HAS_U_CENTER, update_measurements(m, U_AXIS)); + TERN_(HAS_V_CENTER, update_measurements(m, V_AXIS)); + TERN_(HAS_W_CENTER, update_measurements(m, W_AXIS)); sync_plan_position(); } diff --git a/Marlin/src/gcode/calibrate/M425.cpp b/Marlin/src/gcode/calibrate/M425.cpp index 6b1f56fcf6..bfceefdbe2 100644 --- a/Marlin/src/gcode/calibrate/M425.cpp +++ b/Marlin/src/gcode/calibrate/M425.cpp @@ -49,21 +49,24 @@ void GcodeSuite::M425() { auto axis_can_calibrate = [](const uint8_t a) { switch (a) { default: return false; - LINEAR_AXIS_CODE( + NUM_AXIS_CODE( case X_AXIS: return AXIS_CAN_CALIBRATE(X), case Y_AXIS: return AXIS_CAN_CALIBRATE(Y), case Z_AXIS: return AXIS_CAN_CALIBRATE(Z), case I_AXIS: return AXIS_CAN_CALIBRATE(I), case J_AXIS: return AXIS_CAN_CALIBRATE(J), - case K_AXIS: return AXIS_CAN_CALIBRATE(K) + case K_AXIS: return AXIS_CAN_CALIBRATE(K), + case U_AXIS: return AXIS_CAN_CALIBRATE(U), + case V_AXIS: return AXIS_CAN_CALIBRATE(V), + case W_AXIS: return AXIS_CAN_CALIBRATE(W) ); } }; - LOOP_LINEAR_AXES(a) { + LOOP_NUM_AXES(a) { if (axis_can_calibrate(a) && parser.seen(AXIS_CHAR(a))) { planner.synchronize(); - backlash.set_distance_mm(AxisEnum(a), parser.has_value() ? parser.value_linear_units() : backlash.get_measurement(AxisEnum(a))); + backlash.set_distance_mm(AxisEnum(a), parser.has_value() ? parser.value_axis_units(AxisEnum(a)) : backlash.get_measurement(AxisEnum(a))); noArgs = false; } } @@ -88,7 +91,7 @@ void GcodeSuite::M425() { SERIAL_ECHOLNPGM("active:"); SERIAL_ECHOLNPGM(" Correction Amount/Fade-out: F", backlash.get_correction(), " (F1.0 = full, F0.0 = none)"); SERIAL_ECHOPGM(" Backlash Distance (mm): "); - LOOP_LINEAR_AXES(a) if (axis_can_calibrate(a)) { + LOOP_NUM_AXES(a) if (axis_can_calibrate(a)) { SERIAL_CHAR(' ', AXIS_CHAR(a)); SERIAL_ECHO(backlash.get_distance_mm(AxisEnum(a))); SERIAL_EOL(); @@ -101,7 +104,7 @@ void GcodeSuite::M425() { #if ENABLED(MEASURE_BACKLASH_WHEN_PROBING) SERIAL_ECHOPGM(" Average measured backlash (mm):"); if (backlash.has_any_measurement()) { - LOOP_LINEAR_AXES(a) if (axis_can_calibrate(a) && backlash.has_measurement(AxisEnum(a))) { + LOOP_NUM_AXES(a) if (axis_can_calibrate(a) && backlash.has_measurement(AxisEnum(a))) { SERIAL_CHAR(' ', AXIS_CHAR(a)); SERIAL_ECHO(backlash.get_measurement(AxisEnum(a))); } @@ -120,13 +123,16 @@ void GcodeSuite::M425_report(const bool forReplay/*=true*/) { #ifdef BACKLASH_SMOOTHING_MM , PSTR(" S"), LINEAR_UNIT(backlash.get_smoothing_mm()) #endif - , LIST_N(DOUBLE(LINEAR_AXES), + , LIST_N(DOUBLE(NUM_AXES), SP_X_STR, LINEAR_UNIT(backlash.get_distance_mm(X_AXIS)), SP_Y_STR, LINEAR_UNIT(backlash.get_distance_mm(Y_AXIS)), SP_Z_STR, LINEAR_UNIT(backlash.get_distance_mm(Z_AXIS)), - SP_I_STR, LINEAR_UNIT(backlash.get_distance_mm(I_AXIS)), - SP_J_STR, LINEAR_UNIT(backlash.get_distance_mm(J_AXIS)), - SP_K_STR, LINEAR_UNIT(backlash.get_distance_mm(K_AXIS)) + SP_I_STR, I_AXIS_UNIT(backlash.get_distance_mm(I_AXIS)), + SP_J_STR, J_AXIS_UNIT(backlash.get_distance_mm(J_AXIS)), + SP_K_STR, K_AXIS_UNIT(backlash.get_distance_mm(K_AXIS)), + SP_U_STR, U_AXIS_UNIT(backlash.get_distance_mm(U_AXIS)), + SP_V_STR, V_AXIS_UNIT(backlash.get_distance_mm(V_AXIS)), + SP_W_STR, W_AXIS_UNIT(backlash.get_distance_mm(W_AXIS)) ) ); } diff --git a/Marlin/src/gcode/calibrate/M666.cpp b/Marlin/src/gcode/calibrate/M666.cpp index 15f8baf109..fe244b21f7 100644 --- a/Marlin/src/gcode/calibrate/M666.cpp +++ b/Marlin/src/gcode/calibrate/M666.cpp @@ -44,7 +44,7 @@ void GcodeSuite::M666() { DEBUG_SECTION(log_M666, "M666", DEBUGGING(LEVELING)); bool is_err = false, is_set = false; - LOOP_LINEAR_AXES(i) { + LOOP_NUM_AXES(i) { if (parser.seen(AXIS_CHAR(i))) { is_set = true; const float v = parser.value_linear_units(); diff --git a/Marlin/src/gcode/config/M200-M205.cpp b/Marlin/src/gcode/config/M200-M205.cpp index 9490e3c625..5e15ff65e8 100644 --- a/Marlin/src/gcode/config/M200-M205.cpp +++ b/Marlin/src/gcode/config/M200-M205.cpp @@ -93,12 +93,12 @@ } #else SERIAL_ECHOLNPGM(" M200 S", parser.volumetric_enabled); - LOOP_L_N(i, EXTRUDERS) { + EXTRUDER_LOOP() { report_echo_start(forReplay); SERIAL_ECHOLNPGM( - " M200 T", i, " D", LINEAR_UNIT(planner.filament_size[i]) + " M200 T", e, " D", LINEAR_UNIT(planner.filament_size[e]) #if ENABLED(VOLUMETRIC_EXTRUDER_LIMIT) - , " L", LINEAR_UNIT(planner.volumetric_extruder_limit[i]) + , " L", LINEAR_UNIT(planner.volumetric_extruder_limit[e]) #endif ); } @@ -135,13 +135,16 @@ void GcodeSuite::M201() { void GcodeSuite::M201_report(const bool forReplay/*=true*/) { report_heading_etc(forReplay, F(STR_MAX_ACCELERATION)); SERIAL_ECHOLNPGM_P( - LIST_N(DOUBLE(LINEAR_AXES), + LIST_N(DOUBLE(NUM_AXES), PSTR(" M201 X"), LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[X_AXIS]), SP_Y_STR, LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[Y_AXIS]), SP_Z_STR, LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[Z_AXIS]), - SP_I_STR, LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[I_AXIS]), - SP_J_STR, LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[J_AXIS]), - SP_K_STR, LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[K_AXIS]) + SP_I_STR, I_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[I_AXIS]), + SP_J_STR, J_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[J_AXIS]), + SP_K_STR, K_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[K_AXIS]), + SP_U_STR, U_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[U_AXIS]), + SP_V_STR, V_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[V_AXIS]), + SP_W_STR, W_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[W_AXIS]), ) #if HAS_EXTRUDERS && DISABLED(DISTINCT_E_FACTORS) , SP_E_STR, VOLUMETRIC_UNIT(planner.settings.max_acceleration_mm_per_s2[E_AXIS]) @@ -180,13 +183,16 @@ void GcodeSuite::M203() { void GcodeSuite::M203_report(const bool forReplay/*=true*/) { report_heading_etc(forReplay, F(STR_MAX_FEEDRATES)); SERIAL_ECHOLNPGM_P( - LIST_N(DOUBLE(LINEAR_AXES), + LIST_N(DOUBLE(NUM_AXES), PSTR(" M203 X"), LINEAR_UNIT(planner.settings.max_feedrate_mm_s[X_AXIS]), SP_Y_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[Y_AXIS]), SP_Z_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[Z_AXIS]), SP_I_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[I_AXIS]), SP_J_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[J_AXIS]), - SP_K_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[K_AXIS]) + SP_K_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[K_AXIS]), + SP_U_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[U_AXIS]), + SP_V_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[V_AXIS]), + SP_W_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[W_AXIS]) ) #if HAS_EXTRUDERS && DISABLED(DISTINCT_E_FACTORS) , SP_E_STR, VOLUMETRIC_UNIT(planner.settings.max_feedrate_mm_s[E_AXIS]) @@ -273,9 +279,12 @@ void GcodeSuite::M205() { if (parser.seenval('X')) planner.set_max_jerk(X_AXIS, parser.value_linear_units()), if (parser.seenval('Y')) planner.set_max_jerk(Y_AXIS, parser.value_linear_units()), if ((seenZ = parser.seenval('Z'))) planner.set_max_jerk(Z_AXIS, parser.value_linear_units()), - if (parser.seenval(AXIS4_NAME)) planner.set_max_jerk(I_AXIS, parser.value_linear_units()), - if (parser.seenval(AXIS5_NAME)) planner.set_max_jerk(J_AXIS, parser.value_linear_units()), - if (parser.seenval(AXIS6_NAME)) planner.set_max_jerk(K_AXIS, parser.value_linear_units()) + if (parser.seenval(AXIS4_NAME)) planner.set_max_jerk(I_AXIS, parser.TERN(AXIS4_ROTATES, value_float, value_linear_units)()), + if (parser.seenval(AXIS5_NAME)) planner.set_max_jerk(J_AXIS, parser.TERN(AXIS5_ROTATES, value_float, value_linear_units)()), + if (parser.seenval(AXIS6_NAME)) planner.set_max_jerk(K_AXIS, parser.TERN(AXIS6_ROTATES, value_float, value_linear_units)()), + if (parser.seenval(AXIS7_NAME)) planner.set_max_jerk(U_AXIS, parser.TERN(AXIS7_ROTATES, value_float, value_linear_units)()), + if (parser.seenval(AXIS8_NAME)) planner.set_max_jerk(V_AXIS, parser.TERN(AXIS8_ROTATES, value_float, value_linear_units)()), + if (parser.seenval(AXIS9_NAME)) planner.set_max_jerk(W_AXIS, parser.TERN(AXIS9_ROTATES, value_float, value_linear_units)()) ); #if HAS_MESH && DISABLED(LIMITED_JERK_EDITING) if (seenZ && planner.max_jerk.z <= 0.1f) @@ -289,9 +298,10 @@ void GcodeSuite::M205_report(const bool forReplay/*=true*/) { "Advanced (B S T" TERN_(HAS_JUNCTION_DEVIATION, " J") #if HAS_CLASSIC_JERK - LINEAR_AXIS_GANG( + NUM_AXIS_GANG( " X", " Y", " Z", - " " STR_I "", " " STR_J "", " " STR_K "" + " " STR_I "", " " STR_J "", " " STR_K "", + " " STR_U "", " " STR_V "", " " STR_W "" ) #endif TERN_(HAS_CLASSIC_E_JERK, " E") @@ -305,13 +315,16 @@ void GcodeSuite::M205_report(const bool forReplay/*=true*/) { , PSTR(" J"), LINEAR_UNIT(planner.junction_deviation_mm) #endif #if HAS_CLASSIC_JERK - , LIST_N(DOUBLE(LINEAR_AXES), + , LIST_N(DOUBLE(NUM_AXES), SP_X_STR, LINEAR_UNIT(planner.max_jerk.x), SP_Y_STR, LINEAR_UNIT(planner.max_jerk.y), SP_Z_STR, LINEAR_UNIT(planner.max_jerk.z), - SP_I_STR, LINEAR_UNIT(planner.max_jerk.i), - SP_J_STR, LINEAR_UNIT(planner.max_jerk.j), - SP_K_STR, LINEAR_UNIT(planner.max_jerk.k) + SP_I_STR, I_AXIS_UNIT(planner.max_jerk.i), + SP_J_STR, J_AXIS_UNIT(planner.max_jerk.j), + SP_K_STR, K_AXIS_UNIT(planner.max_jerk.k), + SP_U_STR, U_AXIS_UNIT(planner.max_jerk.u), + SP_V_STR, V_AXIS_UNIT(planner.max_jerk.v), + SP_W_STR, W_AXIS_UNIT(planner.max_jerk.w) ) #if HAS_CLASSIC_E_JERK , SP_E_STR, LINEAR_UNIT(planner.max_jerk.e) diff --git a/Marlin/src/gcode/config/M217.cpp b/Marlin/src/gcode/config/M217.cpp index 344adc34e3..ad96b2b659 100644 --- a/Marlin/src/gcode/config/M217.cpp +++ b/Marlin/src/gcode/config/M217.cpp @@ -50,9 +50,12 @@ * W[linear] 0/1 Enable park & Z Raise * X[linear] Park X (Requires TOOLCHANGE_PARK) * Y[linear] Park Y (Requires TOOLCHANGE_PARK) - * I[linear] Park I (Requires TOOLCHANGE_PARK and LINEAR_AXES >= 4) - * J[linear] Park J (Requires TOOLCHANGE_PARK and LINEAR_AXES >= 5) - * K[linear] Park K (Requires TOOLCHANGE_PARK and LINEAR_AXES >= 6) + * I[linear] Park I (Requires TOOLCHANGE_PARK and NUM_AXES >= 4) + * J[linear] Park J (Requires TOOLCHANGE_PARK and NUM_AXES >= 5) + * K[linear] Park K (Requires TOOLCHANGE_PARK and NUM_AXES >= 6) + * C[linear] Park U (Requires TOOLCHANGE_PARK and NUM_AXES >= 7) + * H[linear] Park V (Requires TOOLCHANGE_PARK and NUM_AXES >= 8) + * O[linear] Park W (Requires TOOLCHANGE_PARK and NUM_AXES >= 9) * Z[linear] Z Raise * F[linear] Fan Speed 0-255 * G[linear/s] Fan time @@ -95,13 +98,22 @@ void GcodeSuite::M217() { if (parser.seenval('Y')) { const int16_t v = parser.value_linear_units(); toolchange_settings.change_point.y = constrain(v, Y_MIN_POS, Y_MAX_POS); } #endif #if HAS_I_AXIS - if (parser.seenval('I')) { const int16_t v = parser.value_linear_units(); toolchange_settings.change_point.i = constrain(v, I_MIN_POS, I_MAX_POS); } + if (parser.seenval('I')) { const int16_t v = parser.TERN(AXIS4_ROTATES, value_int, value_linear_units)(); toolchange_settings.change_point.i = constrain(v, I_MIN_POS, I_MAX_POS); } #endif #if HAS_J_AXIS - if (parser.seenval('J')) { const int16_t v = parser.value_linear_units(); toolchange_settings.change_point.j = constrain(v, J_MIN_POS, J_MAX_POS); } + if (parser.seenval('J')) { const int16_t v = parser.TERN(AXIS5_ROTATES, value_int, value_linear_units)(); toolchange_settings.change_point.j = constrain(v, J_MIN_POS, J_MAX_POS); } #endif #if HAS_K_AXIS - if (parser.seenval('K')) { const int16_t v = parser.value_linear_units(); toolchange_settings.change_point.k = constrain(v, K_MIN_POS, K_MAX_POS); } + if (parser.seenval('K')) { const int16_t v = parser.TERN(AXIS6_ROTATES, value_int, value_linear_units)(); toolchange_settings.change_point.k = constrain(v, K_MIN_POS, K_MAX_POS); } + #endif + #if HAS_U_AXIS + if (parser.seenval('C')) { const int16_t v = parser.TERN(AXIS7_ROTATES, value_int, value_linear_units)(); toolchange_settings.change_point.u = constrain(v, U_MIN_POS, U_MAX_POS); } + #endif + #if HAS_V_AXIS + if (parser.seenval('H')) { const int16_t v = parser.TERN(AXIS8_ROTATES, value_int, value_linear_units)(); toolchange_settings.change_point.v = constrain(v, V_MIN_POS, V_MAX_POS); } + #endif + #if HAS_W_AXIS + if (parser.seenval('O')) { const int16_t v = parser.TERN(AXIS9_ROTATES, value_int, value_linear_units)(); toolchange_settings.change_point.w = constrain(v, W_MIN_POS, W_MAX_POS); } #endif #endif @@ -167,24 +179,23 @@ void GcodeSuite::M217_report(const bool forReplay/*=true*/) { #endif #if ENABLED(TOOLCHANGE_PARK) - { SERIAL_ECHOPGM(" W", LINEAR_UNIT(toolchange_settings.enable_park)); SERIAL_ECHOPGM_P( SP_X_STR, LINEAR_UNIT(toolchange_settings.change_point.x) #if HAS_Y_AXIS , SP_Y_STR, LINEAR_UNIT(toolchange_settings.change_point.y) #endif - #if HAS_I_AXIS - , SP_I_STR, LINEAR_UNIT(toolchange_settings.change_point.i) - #endif - #if HAS_J_AXIS - , SP_J_STR, LINEAR_UNIT(toolchange_settings.change_point.j) - #endif - #if HAS_K_AXIS - , SP_K_STR, LINEAR_UNIT(toolchange_settings.change_point.k) + #if SECONDARY_AXES >= 1 + , LIST_N(DOUBLE(SECONDARY_AXES), + PSTR(" I"), I_AXIS_UNIT(toolchange_settings.change_point.i), + PSTR(" J"), J_AXIS_UNIT(toolchange_settings.change_point.j), + PSTR(" K"), K_AXIS_UNIT(toolchange_settings.change_point.k), + SP_C_STR, U_AXIS_UNIT(toolchange_settings.change_point.u), + PSTR(" H"), V_AXIS_UNIT(toolchange_settings.change_point.v), + PSTR(" O"), W_AXIS_UNIT(toolchange_settings.change_point.w), + ) #endif ); - } #endif #if ENABLED(TOOLCHANGE_FS_PRIME_FIRST_USED) diff --git a/Marlin/src/gcode/config/M92.cpp b/Marlin/src/gcode/config/M92.cpp index 8f527919fd..cca4f7f12a 100644 --- a/Marlin/src/gcode/config/M92.cpp +++ b/Marlin/src/gcode/config/M92.cpp @@ -24,7 +24,7 @@ #include "../../module/planner.h" /** - * M92: Set axis steps-per-unit for one or more axes, X, Y, Z, [I, [J, [K]]] and E. + * M92: Set axis steps-per-unit for one or more axes, X, Y, Z, [I, [J, [K, [U, [V, [W,]]]]]] and E. * (Follows the same syntax as G92) * * With multiple extruders use T to specify which one. @@ -92,14 +92,17 @@ void GcodeSuite::M92() { void GcodeSuite::M92_report(const bool forReplay/*=true*/, const int8_t e/*=-1*/) { report_heading_etc(forReplay, F(STR_STEPS_PER_UNIT)); - SERIAL_ECHOPGM_P(LIST_N(DOUBLE(LINEAR_AXES), + SERIAL_ECHOPGM_P(LIST_N(DOUBLE(NUM_AXES), PSTR(" M92 X"), LINEAR_UNIT(planner.settings.axis_steps_per_mm[X_AXIS]), SP_Y_STR, LINEAR_UNIT(planner.settings.axis_steps_per_mm[Y_AXIS]), SP_Z_STR, LINEAR_UNIT(planner.settings.axis_steps_per_mm[Z_AXIS]), - SP_I_STR, LINEAR_UNIT(planner.settings.axis_steps_per_mm[I_AXIS]), - SP_J_STR, LINEAR_UNIT(planner.settings.axis_steps_per_mm[J_AXIS]), - SP_K_STR, LINEAR_UNIT(planner.settings.axis_steps_per_mm[K_AXIS])) - ); + SP_I_STR, I_AXIS_UNIT(planner.settings.axis_steps_per_mm[I_AXIS]), + SP_J_STR, J_AXIS_UNIT(planner.settings.axis_steps_per_mm[J_AXIS]), + SP_K_STR, K_AXIS_UNIT(planner.settings.axis_steps_per_mm[K_AXIS]), + SP_U_STR, U_AXIS_UNIT(planner.settings.axis_steps_per_mm[U_AXIS]), + SP_V_STR, V_AXIS_UNIT(planner.settings.axis_steps_per_mm[V_AXIS]), + SP_W_STR, W_AXIS_UNIT(planner.settings.axis_steps_per_mm[W_AXIS]) + )); #if HAS_EXTRUDERS && DISABLED(DISTINCT_E_FACTORS) SERIAL_ECHOPGM_P(SP_E_STR, VOLUMETRIC_UNIT(planner.settings.axis_steps_per_mm[E_AXIS])); #endif diff --git a/Marlin/src/gcode/control/M17_M18_M84.cpp b/Marlin/src/gcode/control/M17_M18_M84.cpp index 4683786f1f..c6473af48f 100644 --- a/Marlin/src/gcode/control/M17_M18_M84.cpp +++ b/Marlin/src/gcode/control/M17_M18_M84.cpp @@ -46,13 +46,16 @@ inline axis_flags_t selected_axis_bits() { selected.bits = selected.e_bits(); } #endif - selected.bits |= LINEAR_AXIS_GANG( + selected.bits |= NUM_AXIS_GANG( (parser.seen_test('X') << X_AXIS), | (parser.seen_test('Y') << Y_AXIS), | (parser.seen_test('Z') << Z_AXIS), | (parser.seen_test(AXIS4_NAME) << I_AXIS), | (parser.seen_test(AXIS5_NAME) << J_AXIS), - | (parser.seen_test(AXIS6_NAME) << K_AXIS) + | (parser.seen_test(AXIS6_NAME) << K_AXIS), + | (parser.seen_test(AXIS7_NAME) << U_AXIS), + | (parser.seen_test(AXIS8_NAME) << V_AXIS), + | (parser.seen_test(AXIS9_NAME) << W_AXIS) ); return selected; } @@ -69,7 +72,7 @@ void do_enable(const axis_flags_t to_enable) { ena_mask_t also_enabled = 0; // Track steppers enabled due to overlap // Enable all flagged axes - LOOP_LINEAR_AXES(a) { + LOOP_NUM_AXES(a) { if (TEST(shall_enable, a)) { stepper.enable_axis(AxisEnum(a)); // Mark and enable the requested axis DEBUG_ECHOLNPGM("Enabled ", axis_codes[a], " (", a, ") with overlap ", hex_word(enable_overlap[a]), " ... Enabled: ", hex_word(stepper.axis_enabled.bits)); @@ -77,7 +80,7 @@ void do_enable(const axis_flags_t to_enable) { } } #if HAS_EXTRUDERS - LOOP_L_N(e, EXTRUDERS) { + EXTRUDER_LOOP() { const uint8_t a = INDEX_OF_AXIS(E_AXIS, e); if (TEST(shall_enable, a)) { stepper.ENABLE_EXTRUDER(e); @@ -89,7 +92,7 @@ void do_enable(const axis_flags_t to_enable) { if ((also_enabled &= ~(shall_enable | was_enabled))) { SERIAL_CHAR('('); - LOOP_LINEAR_AXES(a) if (TEST(also_enabled, a)) SERIAL_CHAR(axis_codes[a], ' '); + LOOP_NUM_AXES(a) if (TEST(also_enabled, a)) SERIAL_CHAR(axis_codes[a], ' '); #if HAS_EXTRUDERS #define _EN_ALSO(N) if (TEST(also_enabled, INDEX_OF_AXIS(E_AXIS, N))) SERIAL_CHAR('E', '0' + N, ' '); REPEAT(EXTRUDERS, _EN_ALSO) @@ -125,13 +128,16 @@ void GcodeSuite::M17() { stepper.enable_e_steppers(); } #endif - LINEAR_AXIS_CODE( + NUM_AXIS_CODE( if (parser.seen_test('X')) stepper.enable_axis(X_AXIS), if (parser.seen_test('Y')) stepper.enable_axis(Y_AXIS), if (parser.seen_test('Z')) stepper.enable_axis(Z_AXIS), if (parser.seen_test(AXIS4_NAME)) stepper.enable_axis(I_AXIS), if (parser.seen_test(AXIS5_NAME)) stepper.enable_axis(J_AXIS), - if (parser.seen_test(AXIS6_NAME)) stepper.enable_axis(K_AXIS) + if (parser.seen_test(AXIS6_NAME)) stepper.enable_axis(K_AXIS), + if (parser.seen_test(AXIS7_NAME)) stepper.enable_axis(U_AXIS), + if (parser.seen_test(AXIS8_NAME)) stepper.enable_axis(V_AXIS), + if (parser.seen_test(AXIS9_NAME)) stepper.enable_axis(W_AXIS) ); } } @@ -149,7 +155,7 @@ void try_to_disable(const axis_flags_t to_disable) { if (!still_enabled) return; // Attempt to disable all flagged axes - LOOP_LINEAR_AXES(a) + LOOP_NUM_AXES(a) if (TEST(to_disable.bits, a)) { DEBUG_ECHOPGM("Try to disable ", axis_codes[a], " (", a, ") with overlap ", hex_word(enable_overlap[a]), " ... "); if (stepper.disable_axis(AxisEnum(a))) { // Mark the requested axis and request to disable @@ -161,7 +167,7 @@ void try_to_disable(const axis_flags_t to_disable) { DEBUG_ECHOLNPGM(" ... still_enabled=", hex_word(still_enabled)); } #if HAS_EXTRUDERS - LOOP_L_N(e, EXTRUDERS) { + EXTRUDER_LOOP() { const uint8_t a = INDEX_OF_AXIS(E_AXIS, e); if (TEST(to_disable.bits, a)) { DEBUG_ECHOPGM("Try to disable E", AS_DIGIT(e), " (", a, ") with overlap ", hex_word(enable_overlap[a]), " ... "); @@ -178,7 +184,7 @@ void try_to_disable(const axis_flags_t to_disable) { auto overlap_warning = [](const ena_mask_t axis_bits) { SERIAL_ECHOPGM(" not disabled. Shared with"); - LOOP_LINEAR_AXES(a) if (TEST(axis_bits, a)) SERIAL_CHAR(' ', axis_codes[a]); + LOOP_NUM_AXES(a) if (TEST(axis_bits, a)) SERIAL_CHAR(' ', axis_codes[a]); #if HAS_EXTRUDERS #define _EN_STILLON(N) if (TEST(axis_bits, INDEX_OF_AXIS(E_AXIS, N))) SERIAL_CHAR(' ', 'E', '0' + N); REPEAT(EXTRUDERS, _EN_STILLON) @@ -187,14 +193,14 @@ void try_to_disable(const axis_flags_t to_disable) { }; // If any of the requested axes are still enabled, give a warning - LOOP_LINEAR_AXES(a) { + LOOP_NUM_AXES(a) { if (TEST(still_enabled, a)) { SERIAL_CHAR(axis_codes[a]); overlap_warning(stepper.axis_enabled.bits & enable_overlap[a]); } } #if HAS_EXTRUDERS - LOOP_L_N(e, EXTRUDERS) { + EXTRUDER_LOOP() { const uint8_t a = INDEX_OF_AXIS(E_AXIS, e); if (TEST(still_enabled, a)) { SERIAL_CHAR('E', '0' + e); @@ -229,13 +235,16 @@ void GcodeSuite::M18_M84() { stepper.disable_e_steppers(); } #endif - LINEAR_AXIS_CODE( + NUM_AXIS_CODE( if (parser.seen_test('X')) stepper.disable_axis(X_AXIS), if (parser.seen_test('Y')) stepper.disable_axis(Y_AXIS), if (parser.seen_test('Z')) stepper.disable_axis(Z_AXIS), if (parser.seen_test(AXIS4_NAME)) stepper.disable_axis(I_AXIS), if (parser.seen_test(AXIS5_NAME)) stepper.disable_axis(J_AXIS), - if (parser.seen_test(AXIS6_NAME)) stepper.disable_axis(K_AXIS) + if (parser.seen_test(AXIS6_NAME)) stepper.disable_axis(K_AXIS), + if (parser.seen_test(AXIS7_NAME)) stepper.disable_axis(U_AXIS), + if (parser.seen_test(AXIS8_NAME)) stepper.disable_axis(V_AXIS), + if (parser.seen_test(AXIS9_NAME)) stepper.disable_axis(W_AXIS) ); } } diff --git a/Marlin/src/gcode/control/M380_M381.cpp b/Marlin/src/gcode/control/M380_M381.cpp index 3f5b252465..6bcec891e2 100644 --- a/Marlin/src/gcode/control/M380_M381.cpp +++ b/Marlin/src/gcode/control/M380_M381.cpp @@ -37,7 +37,7 @@ void GcodeSuite::M380() { #if ENABLED(MANUAL_SOLENOID_CONTROL) enable_solenoid(parser.intval('S', active_extruder)); #else - enable_solenoid_on_active_extruder(); + enable_solenoid(active_extruder); #endif } diff --git a/Marlin/src/gcode/control/M605.cpp b/Marlin/src/gcode/control/M605.cpp index 788659e7e2..a0296bba57 100644 --- a/Marlin/src/gcode/control/M605.cpp +++ b/Marlin/src/gcode/control/M605.cpp @@ -146,7 +146,7 @@ HOTEND_LOOP() { DEBUG_ECHOPGM_P(SP_T_STR, e); - LOOP_LINEAR_AXES(a) DEBUG_ECHOPGM(" hotend_offset[", e, "].", AS_CHAR(AXIS_CHAR(a) | 0x20), "=", hotend_offset[e][a]); + LOOP_NUM_AXES(a) DEBUG_ECHOPGM(" hotend_offset[", e, "].", AS_CHAR(AXIS_CHAR(a) | 0x20), "=", hotend_offset[e][a]); DEBUG_EOL(); } DEBUG_EOL(); diff --git a/Marlin/src/gcode/feature/advance/M900.cpp b/Marlin/src/gcode/feature/advance/M900.cpp index 054ea3617f..8b59e88fb1 100644 --- a/Marlin/src/gcode/feature/advance/M900.cpp +++ b/Marlin/src/gcode/feature/advance/M900.cpp @@ -117,10 +117,10 @@ void GcodeSuite::M900() { #if EXTRUDERS < 2 SERIAL_ECHOLNPGM("Advance S", new_slot, " K", kref, "(S", !new_slot, " K", lref, ")"); #else - LOOP_L_N(i, EXTRUDERS) { - const bool slot = TEST(lin_adv_slot, i); - SERIAL_ECHOLNPGM("Advance T", i, " S", slot, " K", planner.extruder_advance_K[i], - "(S", !slot, " K", other_extruder_advance_K[i], ")"); + EXTRUDER_LOOP() { + const bool slot = TEST(lin_adv_slot, e); + SERIAL_ECHOLNPGM("Advance T", e, " S", slot, " K", planner.extruder_advance_K[e], + "(S", !slot, " K", other_extruder_advance_K[e], ")"); SERIAL_EOL(); } #endif @@ -132,9 +132,9 @@ void GcodeSuite::M900() { SERIAL_ECHOLNPGM("Advance K=", planner.extruder_advance_K[0]); #else SERIAL_ECHOPGM("Advance K"); - LOOP_L_N(i, EXTRUDERS) { - SERIAL_CHAR(' ', '0' + i, ':'); - SERIAL_DECIMAL(planner.extruder_advance_K[i]); + EXTRUDER_LOOP() { + SERIAL_CHAR(' ', '0' + e, ':'); + SERIAL_DECIMAL(planner.extruder_advance_K[e]); } SERIAL_EOL(); #endif @@ -150,9 +150,9 @@ void GcodeSuite::M900_report(const bool forReplay/*=true*/) { report_echo_start(forReplay); SERIAL_ECHOLNPGM(" M900 K", planner.extruder_advance_K[0]); #else - LOOP_L_N(i, EXTRUDERS) { + EXTRUDER_LOOP() { report_echo_start(forReplay); - SERIAL_ECHOLNPGM(" M900 T", i, " K", planner.extruder_advance_K[i]); + SERIAL_ECHOLNPGM(" M900 T", e, " K", planner.extruder_advance_K[e]); } #endif } diff --git a/Marlin/src/gcode/feature/clean/G12.cpp b/Marlin/src/gcode/feature/clean/G12.cpp index a0b87b1abc..999a9b10bd 100644 --- a/Marlin/src/gcode/feature/clean/G12.cpp +++ b/Marlin/src/gcode/feature/clean/G12.cpp @@ -46,7 +46,8 @@ */ void GcodeSuite::G12() { // Don't allow nozzle cleaning without homing first - if (homing_needed_error()) return; + if (homing_needed_error(linear_bits & ~TERN0(NOZZLE_CLEAN_NO_Z, Z_AXIS) & ~TERN0(NOZZLE_CLEAN_NO_Y, Y_AXIS))) + return; #ifdef WIPE_SEQUENCE_COMMANDS if (!parser.seen_any()) { diff --git a/Marlin/src/gcode/feature/digipot/M907-M910.cpp b/Marlin/src/gcode/feature/digipot/M907-M910.cpp index 95adde3ea5..3b66f78593 100644 --- a/Marlin/src/gcode/feature/digipot/M907-M910.cpp +++ b/Marlin/src/gcode/feature/digipot/M907-M910.cpp @@ -39,7 +39,7 @@ #endif /** - * M907: Set digital trimpot motor current using axis codes X [Y] [Z] [E] + * M907: Set digital trimpot motor current using axis codes X [Y] [Z] [I] [J] [K] [U] [V] [W] [E] * B - Special case for 4th (E) axis * S - Special case to set first 3 axes */ @@ -49,15 +49,15 @@ void GcodeSuite::M907() { if (!parser.seen("BS" LOGICAL_AXES_STRING)) return M907_report(); - LOOP_LOGICAL_AXES(i) if (parser.seenval(axis_codes[i])) stepper.set_digipot_current(i, parser.value_int()); + LOOP_LOGICAL_AXES(i) if (parser.seenval(IAXIS_CHAR(i))) stepper.set_digipot_current(i, parser.value_int()); if (parser.seenval('B')) stepper.set_digipot_current(4, parser.value_int()); if (parser.seenval('S')) LOOP_LE_N(i, 4) stepper.set_digipot_current(i, parser.value_int()); #elif HAS_MOTOR_CURRENT_PWM if (!parser.seen( - #if ANY_PIN(MOTOR_CURRENT_PWM_X, MOTOR_CURRENT_PWM_Y, MOTOR_CURRENT_PWM_XY) - "XY" + #if ANY_PIN(MOTOR_CURRENT_PWM_X, MOTOR_CURRENT_PWM_Y, MOTOR_CURRENT_PWM_XY, MOTOR_CURRENT_PWM_I, MOTOR_CURRENT_PWM_J, MOTOR_CURRENT_PWM_K, MOTOR_CURRENT_PWM_U, MOTOR_CURRENT_PWM_V, MOTOR_CURRENT_PWM_W) + "XY" SECONDARY_AXIS_GANG("I", "J", "K", "U", "V", "W") #endif #if PIN_EXISTS(MOTOR_CURRENT_PWM_Z) "Z" @@ -67,8 +67,12 @@ void GcodeSuite::M907() { #endif )) return M907_report(); - #if ANY_PIN(MOTOR_CURRENT_PWM_X, MOTOR_CURRENT_PWM_Y, MOTOR_CURRENT_PWM_XY) - if (parser.seenval('X') || parser.seenval('Y')) stepper.set_digipot_current(0, parser.value_int()); + #if ANY_PIN(MOTOR_CURRENT_PWM_X, MOTOR_CURRENT_PWM_Y, MOTOR_CURRENT_PWM_XY, MOTOR_CURRENT_PWM_I, MOTOR_CURRENT_PWM_J, MOTOR_CURRENT_PWM_K, MOTOR_CURRENT_PWM_U, MOTOR_CURRENT_PWM_V, MOTOR_CURRENT_PWM_W) + if (NUM_AXIS_GANG( + parser.seenval('X'), || parser.seenval('Y'), || false, + || parser.seenval('I'), || parser.seenval('J'), || parser.seenval('K'), + || parser.seenval('U'), || parser.seenval('V'), || parser.seenval('W') + )) stepper.set_digipot_current(0, parser.value_int()); #endif #if PIN_EXISTS(MOTOR_CURRENT_PWM_Z) if (parser.seenval('Z')) stepper.set_digipot_current(1, parser.value_int()); @@ -81,7 +85,7 @@ void GcodeSuite::M907() { #if HAS_MOTOR_CURRENT_I2C // this one uses actual amps in floating point - LOOP_LOGICAL_AXES(i) if (parser.seenval(axis_codes[i])) digipot_i2c.set_current(i, parser.value_float()); + LOOP_LOGICAL_AXES(i) if (parser.seenval(IAXIS_CHAR(i))) digipot_i2c.set_current(i, parser.value_float()); // Additional extruders use B,C,D for channels 4,5,6. // TODO: Change these parameters because 'E' is used. B? #if HAS_EXTRUDERS @@ -95,7 +99,7 @@ void GcodeSuite::M907() { const float dac_percent = parser.value_float(); LOOP_LE_N(i, 4) stepper_dac.set_current_percent(i, dac_percent); } - LOOP_LOGICAL_AXES(i) if (parser.seenval(axis_codes[i])) stepper_dac.set_current_percent(i, parser.value_float()); + LOOP_LOGICAL_AXES(i) if (parser.seenval(IAXIS_CHAR(i))) stepper_dac.set_current_percent(i, parser.value_float()); #endif } @@ -104,15 +108,15 @@ void GcodeSuite::M907() { void GcodeSuite::M907_report(const bool forReplay/*=true*/) { report_heading_etc(forReplay, F(STR_STEPPER_MOTOR_CURRENTS)); #if HAS_MOTOR_CURRENT_PWM - SERIAL_ECHOLNPGM_P( // PWM-based has 3 values: - PSTR(" M907 X"), stepper.motor_current_setting[0] // X and Y + SERIAL_ECHOLNPGM_P( // PWM-based has 3 values: + PSTR(" M907 X"), stepper.motor_current_setting[0] // X, Y, (I, J, K, U, V, W) , SP_Z_STR, stepper.motor_current_setting[1] // Z , SP_E_STR, stepper.motor_current_setting[2] // E ); #elif HAS_MOTOR_CURRENT_SPI SERIAL_ECHOPGM(" M907"); // SPI-based has 5 values: - LOOP_LOGICAL_AXES(q) { // X Y Z (I J K) E (map to X Y Z (I J K) E0 by default) - SERIAL_CHAR(' ', axis_codes[q]); + LOOP_LOGICAL_AXES(q) { // X Y Z (I J K U V W) E (map to X Y Z (I J K U V W) E0 by default) + SERIAL_CHAR(' ', IAXIS_CHAR(q)); SERIAL_ECHO(stepper.motor_current_setting[q]); } SERIAL_CHAR(' ', 'B'); // B (maps to E1 by default) diff --git a/Marlin/src/gcode/feature/pause/G60.cpp b/Marlin/src/gcode/feature/pause/G60.cpp index d4770577a6..9e0962fd34 100644 --- a/Marlin/src/gcode/feature/pause/G60.cpp +++ b/Marlin/src/gcode/feature/pause/G60.cpp @@ -48,10 +48,14 @@ void GcodeSuite::G60() { #if ENABLED(SAVED_POSITIONS_DEBUG) { - DEBUG_ECHOPGM(STR_SAVED_POS " S", slot); const xyze_pos_t &pos = stored_position[slot]; + DEBUG_ECHOPGM(STR_SAVED_POS " S", slot, " :"); DEBUG_ECHOLNPAIR_F_P( - LIST_N(DOUBLE(LINEAR_AXES), PSTR(" : X"), pos.x, SP_Y_STR, pos.y, SP_Z_STR, pos.z, SP_I_STR, pos.i, SP_J_STR, pos.j, SP_K_STR, pos.k) + LIST_N(DOUBLE(NUM_AXES), + SP_Y_STR, pos.x, SP_Y_STR, pos.y, SP_Z_STR, pos.z, + SP_I_STR, pos.i, SP_J_STR, pos.j, SP_K_STR, pos.k, + SP_U_STR, pos.u, SP_V_STR, pos.v, SP_W_STR, pos.w + ) #if HAS_EXTRUDERS , SP_E_STR, pos.e #endif diff --git a/Marlin/src/gcode/feature/pause/G61.cpp b/Marlin/src/gcode/feature/pause/G61.cpp index e0e1983a25..baf96f0d0a 100644 --- a/Marlin/src/gcode/feature/pause/G61.cpp +++ b/Marlin/src/gcode/feature/pause/G61.cpp @@ -68,9 +68,9 @@ void GcodeSuite::G61() { SYNC_E(stored_position[slot].e); } else { - if (parser.seen(LINEAR_AXIS_GANG("X", "Y", "Z", STR_I, STR_J, STR_K))) { + if (parser.seen(NUM_AXIS_GANG("X", "Y", "Z", STR_I, STR_J, STR_K, STR_U, STR_V, STR_W))) { DEBUG_ECHOPGM(STR_RESTORING_POS " S", slot); - LOOP_LINEAR_AXES(i) { + LOOP_NUM_AXES(i) { destination[i] = parser.seen(AXIS_CHAR(i)) ? stored_position[slot][i] + parser.value_axis_units((AxisEnum)i) : current_position[i]; diff --git a/Marlin/src/gcode/feature/pause/M125.cpp b/Marlin/src/gcode/feature/pause/M125.cpp index 940e1b369b..ae450cc5e9 100644 --- a/Marlin/src/gcode/feature/pause/M125.cpp +++ b/Marlin/src/gcode/feature/pause/M125.cpp @@ -52,6 +52,9 @@ * A = Override park position A (requires AXIS*_NAME 'A') * B = Override park position B (requires AXIS*_NAME 'B') * C = Override park position C (requires AXIS*_NAME 'C') + * U = Override park position U (requires AXIS*_NAME 'U') + * V = Override park position V (requires AXIS*_NAME 'V') + * W = Override park position W (requires AXIS*_NAME 'W') * Z = Override Z raise * * With an LCD menu: @@ -64,17 +67,22 @@ void GcodeSuite::M125() { xyz_pos_t park_point = NOZZLE_PARK_POINT; // Move to filament change position or given position - LINEAR_AXIS_CODE( + NUM_AXIS_CODE( if (parser.seenval('X')) park_point.x = RAW_X_POSITION(parser.linearval('X')), if (parser.seenval('Y')) park_point.y = RAW_Y_POSITION(parser.linearval('Y')), NOOP, - if (parser.seenval(AXIS4_NAME)) park_point.i = RAW_I_POSITION(parser.linearval(AXIS4_NAME)), - if (parser.seenval(AXIS5_NAME)) park_point.j = RAW_J_POSITION(parser.linearval(AXIS5_NAME)), - if (parser.seenval(AXIS6_NAME)) park_point.k = RAW_K_POSITION(parser.linearval(AXIS6_NAME)) + if (parser.seenval(AXIS4_NAME)) park_point.i = RAW_X_POSITION(parser.linearval(AXIS4_NAME)), + if (parser.seenval(AXIS5_NAME)) park_point.j = RAW_X_POSITION(parser.linearval(AXIS5_NAME)), + if (parser.seenval(AXIS6_NAME)) park_point.k = RAW_X_POSITION(parser.linearval(AXIS6_NAME)), + if (parser.seenval(AXIS7_NAME)) park_point.u = RAW_X_POSITION(parser.linearval(AXIS7_NAME)), + if (parser.seenval(AXIS8_NAME)) park_point.v = RAW_X_POSITION(parser.linearval(AXIS8_NAME)), + if (parser.seenval(AXIS9_NAME)) park_point.w = RAW_X_POSITION(parser.linearval(AXIS9_NAME)) ); // Lift Z axis - if (parser.seenval('Z')) park_point.z = parser.linearval('Z'); + #if HAS_Z_AXIS + if (parser.seenval('Z')) park_point.z = parser.linearval('Z'); + #endif #if HAS_HOTEND_OFFSET && NONE(DUAL_X_CARRIAGE, DELTA) park_point += hotend_offset[active_extruder]; diff --git a/Marlin/src/gcode/feature/pause/M600.cpp b/Marlin/src/gcode/feature/pause/M600.cpp index e97cc25e99..90ebb61832 100644 --- a/Marlin/src/gcode/feature/pause/M600.cpp +++ b/Marlin/src/gcode/feature/pause/M600.cpp @@ -54,8 +54,14 @@ * * E[distance] - Retract the filament this far * Z[distance] - Move the Z axis by this distance - * X[position] - Move to this X position, with Y - * Y[position] - Move to this Y position, with X + * X[position] - Move to this X position (instead of NOZZLE_PARK_POINT.x) + * Y[position] - Move to this Y position (instead of NOZZLE_PARK_POINT.y) + * I[position] - Move to this I position (instead of NOZZLE_PARK_POINT.i) + * J[position] - Move to this J position (instead of NOZZLE_PARK_POINT.j) + * K[position] - Move to this K position (instead of NOZZLE_PARK_POINT.k) + * C[position] - Move to this U position (instead of NOZZLE_PARK_POINT.u) + * H[position] - Move to this V position (instead of NOZZLE_PARK_POINT.v) + * O[position] - Move to this W position (instead of NOZZLE_PARK_POINT.w) * U[distance] - Retract distance for removal (manual reload) * L[distance] - Extrude distance for insertion (manual reload) * B[count] - Number of times to beep, -1 for indefinite (if equipped with a buzzer) @@ -117,26 +123,25 @@ void GcodeSuite::M600() { xyz_pos_t park_point NOZZLE_PARK_POINT; // Move XY axes to filament change position or given position - LINEAR_AXIS_CODE( + NUM_AXIS_CODE( if (parser.seenval('X')) park_point.x = parser.linearval('X'), if (parser.seenval('Y')) park_point.y = parser.linearval('Y'), if (parser.seenval('Z')) park_point.z = parser.linearval('Z'), // Lift Z axis - if (parser.seenval(AXIS4_NAME)) park_point.i = parser.linearval(AXIS4_NAME), - if (parser.seenval(AXIS5_NAME)) park_point.j = parser.linearval(AXIS5_NAME), - if (parser.seenval(AXIS6_NAME)) park_point.k = parser.linearval(AXIS6_NAME) + if (parser.seenval('I')) park_point.i = parser.linearval('I'), + if (parser.seenval('J')) park_point.j = parser.linearval('J'), + if (parser.seenval('K')) park_point.k = parser.linearval('K'), + if (parser.seenval('C')) park_point.u = parser.linearval('C'), // U axis + if (parser.seenval('H')) park_point.v = parser.linearval('H'), // V axis + if (parser.seenval('O')) park_point.w = parser.linearval('O') // W axis ); #if HAS_HOTEND_OFFSET && NONE(DUAL_X_CARRIAGE, DELTA) park_point += hotend_offset[active_extruder]; #endif - #if ENABLED(MMU2_MENUS) - // For MMU2, when enabled, reset retract value so it doesn't mess with MMU filament handling - const float unload_length = standardM600 ? -ABS(parser.axisunitsval('U', E_AXIS, fc_settings[active_extruder].unload_length)) : 0.5f; - #else - // Unload filament - const float unload_length = -ABS(parser.axisunitsval('U', E_AXIS, fc_settings[active_extruder].unload_length)); - #endif + // Unload filament + // For MMU2, when enabled, reset retract value so it doesn't mess with MMU filament handling + const float unload_length = standardM600 ? -ABS(parser.axisunitsval('U', E_AXIS, fc_settings[active_extruder].unload_length)) : 0.5f; const int beep_count = parser.intval('B', -1 #ifdef FILAMENT_CHANGE_ALERT_BEEPS diff --git a/Marlin/src/gcode/feature/pause/M603.cpp b/Marlin/src/gcode/feature/pause/M603.cpp index 6689749cfb..10d14012f8 100644 --- a/Marlin/src/gcode/feature/pause/M603.cpp +++ b/Marlin/src/gcode/feature/pause/M603.cpp @@ -72,7 +72,7 @@ void GcodeSuite::M603_report(const bool forReplay/*=true*/) { SERIAL_ECHOPGM(" M603 L", LINEAR_UNIT(fc_settings[0].load_length), " U", LINEAR_UNIT(fc_settings[0].unload_length), " ;"); say_units(); #else - LOOP_L_N(e, EXTRUDERS) { + EXTRUDER_LOOP() { report_echo_start(forReplay); SERIAL_ECHOPGM(" M603 T", e, " L", LINEAR_UNIT(fc_settings[e].load_length), " U", LINEAR_UNIT(fc_settings[e].unload_length), " ;"); say_units(); diff --git a/Marlin/src/gcode/feature/runout/M591.cpp b/Marlin/src/gcode/feature/runout/M591.cpp index 0751de879a..e213f16ab8 100644 --- a/Marlin/src/gcode/feature/runout/M591.cpp +++ b/Marlin/src/gcode/feature/runout/M591.cpp @@ -39,7 +39,7 @@ * P : Mode 0 = NONE * 1 = Switch NO (HIGH = filament present) * 2 = Switch NC (LOW = filament present) - * 7 = Encoder / Motion Sensor + * 3 = Encoder / Motion Sensor */ void GcodeSuite::M591() { if (parser.seen("RSDP" TERN_(HOST_ACTION_COMMANDS, "H"))) { @@ -48,19 +48,17 @@ void GcodeSuite::M591() { #endif const bool seenR = parser.seen_test('R'), seenS = parser.seen('S'); if (seenR || seenS) runout.reset(); - #if NUM_RUNOUT_SENSORS > 1 - const uint8_t tool = parser.ushortval('E', active_extruder); - #else - constexpr uint8_t tool = 0; - #endif + const uint8_t tool = TERN0(MULTI_FILAMENT_SENSOR, parser.ushortval('E', active_extruder)); if (seenS) runout.enabled[tool] = parser.value_bool(); - if (parser.seen('D')) runout.set_runout_distance(parser.value_linear_units(), tool); - if (parser.seen('L')) runout.set_runout_distance(parser.value_linear_units(), tool); + if (parser.seen('D') || parser.seen('L')) runout.set_runout_distance(parser.value_linear_units(), tool); if (parser.seen('P')) { - const uint8_t tmp_mode = parser.value_int(); - if (tmp_mode < 3 || tmp_mode == 7) { - runout.mode[tool] = tmp_mode; - runout.reset(); + const RunoutMode tmp_mode = (RunoutMode)parser.value_int(); + switch (tmp_mode) { + case RM_NONE ... RM_OUT_ON_HIGH: + case RM_MOTION_SENSOR: + runout.mode[tool] = tmp_mode; + runout.setup(); + default: break; } } } @@ -83,7 +81,7 @@ void GcodeSuite::M591_report(const bool forReplay/*=true*/) { LOOP_S_L_N(e, 1, NUM_RUNOUT_SENSORS) SERIAL_ECHOLNPGM( " M591" - #if NUM_RUNOUT_SENSORS > 1 + #if MULTI_FILAMENT_SENSOR " E", e, #endif " S", runout.enabled[e] diff --git a/Marlin/src/gcode/feature/trinamic/M569.cpp b/Marlin/src/gcode/feature/trinamic/M569.cpp index 7bfedf8c72..3a325ad264 100644 --- a/Marlin/src/gcode/feature/trinamic/M569.cpp +++ b/Marlin/src/gcode/feature/trinamic/M569.cpp @@ -85,6 +85,15 @@ static void set_stealth_status(const bool enable, const int8_t eindex) { #if K_HAS_STEALTHCHOP case K_AXIS: TMC_SET_STEALTH(K); break; #endif + #if U_HAS_STEALTHCHOP + case U_AXIS: TMC_SET_STEALTH(U); break; + #endif + #if V_HAS_STEALTHCHOP + case V_AXIS: TMC_SET_STEALTH(V); break; + #endif + #if W_HAS_STEALTHCHOP + case W_AXIS: TMC_SET_STEALTH(W); break; + #endif #if E_STEPPERS case E_AXIS: { @@ -115,6 +124,9 @@ static void say_stealth_status() { OPTCODE( I_HAS_STEALTHCHOP, TMC_SAY_STEALTH_STATUS(I)) OPTCODE( J_HAS_STEALTHCHOP, TMC_SAY_STEALTH_STATUS(J)) OPTCODE( K_HAS_STEALTHCHOP, TMC_SAY_STEALTH_STATUS(K)) + OPTCODE( U_HAS_STEALTHCHOP, TMC_SAY_STEALTH_STATUS(U)) + OPTCODE( V_HAS_STEALTHCHOP, TMC_SAY_STEALTH_STATUS(V)) + OPTCODE( W_HAS_STEALTHCHOP, TMC_SAY_STEALTH_STATUS(W)) OPTCODE(E0_HAS_STEALTHCHOP, TMC_SAY_STEALTH_STATUS(E0)) OPTCODE(E1_HAS_STEALTHCHOP, TMC_SAY_STEALTH_STATUS(E1)) OPTCODE(E2_HAS_STEALTHCHOP, TMC_SAY_STEALTH_STATUS(E2)) @@ -157,17 +169,23 @@ void GcodeSuite::M569_report(const bool forReplay/*=true*/) { chop_z = TERN0(Z_HAS_STEALTHCHOP, stepperZ.get_stored_stealthChop()), chop_i = TERN0(I_HAS_STEALTHCHOP, stepperI.get_stored_stealthChop()), chop_j = TERN0(J_HAS_STEALTHCHOP, stepperJ.get_stored_stealthChop()), - chop_k = TERN0(K_HAS_STEALTHCHOP, stepperK.get_stored_stealthChop()); + chop_k = TERN0(K_HAS_STEALTHCHOP, stepperK.get_stored_stealthChop()), + chop_u = TERN0(U_HAS_STEALTHCHOP, stepperU.get_stored_stealthChop()), + chop_v = TERN0(V_HAS_STEALTHCHOP, stepperV.get_stored_stealthChop()), + chop_w = TERN0(W_HAS_STEALTHCHOP, stepperW.get_stored_stealthChop()); - if (chop_x || chop_y || chop_z || chop_i || chop_j || chop_k) { + if (chop_x || chop_y || chop_z || chop_i || chop_j || chop_k || chop_u || chop_v || chop_w) { say_M569(forReplay); - LINEAR_AXIS_CODE( + NUM_AXIS_CODE( if (chop_x) SERIAL_ECHOPGM_P(SP_X_STR), if (chop_y) SERIAL_ECHOPGM_P(SP_Y_STR), if (chop_z) SERIAL_ECHOPGM_P(SP_Z_STR), if (chop_i) SERIAL_ECHOPGM_P(SP_I_STR), if (chop_j) SERIAL_ECHOPGM_P(SP_J_STR), - if (chop_k) SERIAL_ECHOPGM_P(SP_K_STR) + if (chop_k) SERIAL_ECHOPGM_P(SP_K_STR), + if (chop_u) SERIAL_ECHOPGM_P(SP_U_STR), + if (chop_v) SERIAL_ECHOPGM_P(SP_V_STR), + if (chop_w) SERIAL_ECHOPGM_P(SP_W_STR) ); SERIAL_EOL(); } @@ -190,6 +208,9 @@ void GcodeSuite::M569_report(const bool forReplay/*=true*/) { if (TERN0( I_HAS_STEALTHCHOP, stepperI.get_stored_stealthChop())) { say_M569(forReplay, FPSTR(SP_I_STR), true); } if (TERN0( J_HAS_STEALTHCHOP, stepperJ.get_stored_stealthChop())) { say_M569(forReplay, FPSTR(SP_J_STR), true); } if (TERN0( K_HAS_STEALTHCHOP, stepperK.get_stored_stealthChop())) { say_M569(forReplay, FPSTR(SP_K_STR), true); } + if (TERN0( U_HAS_STEALTHCHOP, stepperU.get_stored_stealthChop())) { say_M569(forReplay, FPSTR(SP_U_STR), true); } + if (TERN0( V_HAS_STEALTHCHOP, stepperV.get_stored_stealthChop())) { say_M569(forReplay, FPSTR(SP_V_STR), true); } + if (TERN0( W_HAS_STEALTHCHOP, stepperW.get_stored_stealthChop())) { say_M569(forReplay, FPSTR(SP_W_STR), true); } if (TERN0(E0_HAS_STEALTHCHOP, stepperE0.get_stored_stealthChop())) { say_M569(forReplay, F("T0 E"), true); } if (TERN0(E1_HAS_STEALTHCHOP, stepperE1.get_stored_stealthChop())) { say_M569(forReplay, F("T1 E"), true); } diff --git a/Marlin/src/gcode/feature/trinamic/M906.cpp b/Marlin/src/gcode/feature/trinamic/M906.cpp index 164ff00179..4822b8e268 100644 --- a/Marlin/src/gcode/feature/trinamic/M906.cpp +++ b/Marlin/src/gcode/feature/trinamic/M906.cpp @@ -44,6 +44,9 @@ static void tmc_print_current(TMC &st) { * A[current] - Set mA current for A driver(s) (Requires AXIS*_NAME 'A') * B[current] - Set mA current for B driver(s) (Requires AXIS*_NAME 'B') * C[current] - Set mA current for C driver(s) (Requires AXIS*_NAME 'C') + * U[current] - Set mA current for U driver(s) (Requires AXIS*_NAME 'U') + * V[current] - Set mA current for V driver(s) (Requires AXIS*_NAME 'V') + * W[current] - Set mA current for W driver(s) (Requires AXIS*_NAME 'W') * E[current] - Set mA current for E driver(s) * * I[index] - Axis sub-index (Omit or 0 for X, Y, Z; 1 for X2, Y2, Z2; 2 for Z3; 3 for Z4.) @@ -59,7 +62,7 @@ void GcodeSuite::M906() { #if AXIS_IS_TMC(X2) || AXIS_IS_TMC(Y2) || AXIS_IS_TMC(Z2) || AXIS_IS_TMC(Z3) || AXIS_IS_TMC(Z4) const int8_t index = parser.byteval('I', -1); - #else + #elif AXIS_IS_TMC(X) || AXIS_IS_TMC(Y) || AXIS_IS_TMC(Z) constexpr int8_t index = -1; #endif @@ -114,6 +117,15 @@ void GcodeSuite::M906() { #if AXIS_IS_TMC(K) case K_AXIS: TMC_SET_CURRENT(K); break; #endif + #if AXIS_IS_TMC(U) + case U_AXIS: TMC_SET_CURRENT(U); break; + #endif + #if AXIS_IS_TMC(V) + case V_AXIS: TMC_SET_CURRENT(V); break; + #endif + #if AXIS_IS_TMC(W) + case W_AXIS: TMC_SET_CURRENT(W); break; + #endif #if AXIS_IS_TMC(E0) || AXIS_IS_TMC(E1) || AXIS_IS_TMC(E2) || AXIS_IS_TMC(E3) || AXIS_IS_TMC(E4) || AXIS_IS_TMC(E5) || AXIS_IS_TMC(E6) || AXIS_IS_TMC(E7) case E_AXIS: { @@ -181,6 +193,16 @@ void GcodeSuite::M906() { #if AXIS_IS_TMC(K) TMC_SAY_CURRENT(K); #endif + #if AXIS_IS_TMC(U) + TMC_SAY_CURRENT(U); + #endif + #if AXIS_IS_TMC(V) + TMC_SAY_CURRENT(V); + #endif + #if AXIS_IS_TMC(W) + TMC_SAY_CURRENT(W); + #endif + #if AXIS_IS_TMC(E0) TMC_SAY_CURRENT(E0); #endif @@ -217,7 +239,8 @@ void GcodeSuite::M906_report(const bool forReplay/*=true*/) { }; #if AXIS_IS_TMC(X) || AXIS_IS_TMC(Y) || AXIS_IS_TMC(Z) \ - || AXIS_IS_TMC(I) || AXIS_IS_TMC(J) || AXIS_IS_TMC(K) + || AXIS_IS_TMC(I) || AXIS_IS_TMC(J) || AXIS_IS_TMC(K) \ + || AXIS_IS_TMC(U) || AXIS_IS_TMC(V) || AXIS_IS_TMC(W) say_M906(forReplay); #if AXIS_IS_TMC(X) SERIAL_ECHOPGM_P(SP_X_STR, stepperX.getMilliamps()); @@ -237,6 +260,15 @@ void GcodeSuite::M906_report(const bool forReplay/*=true*/) { #if AXIS_IS_TMC(K) SERIAL_ECHOPGM_P(SP_K_STR, stepperK.getMilliamps()); #endif + #if AXIS_IS_TMC(U) + SERIAL_ECHOPGM_P(SP_U_STR, stepperU.getMilliamps()); + #endif + #if AXIS_IS_TMC(V) + SERIAL_ECHOPGM_P(SP_V_STR, stepperV.getMilliamps()); + #endif + #if AXIS_IS_TMC(W) + SERIAL_ECHOPGM_P(SP_W_STR, stepperW.getMilliamps()); + #endif SERIAL_EOL(); #endif diff --git a/Marlin/src/gcode/feature/trinamic/M911-M914.cpp b/Marlin/src/gcode/feature/trinamic/M911-M914.cpp index 628ae40f48..206e2e456c 100644 --- a/Marlin/src/gcode/feature/trinamic/M911-M914.cpp +++ b/Marlin/src/gcode/feature/trinamic/M911-M914.cpp @@ -53,12 +53,21 @@ #if HAS_K_AXIS && M91x_USE(K) #define M91x_USE_K 1 #endif + #if HAS_U_AXIS && M91x_USE(U) + #define M91x_USE_U 1 + #endif + #if HAS_V_AXIS && M91x_USE(V) + #define M91x_USE_V 1 + #endif + #if HAS_W_AXIS && M91x_USE(W) + #define M91x_USE_W 1 + #endif #if M91x_USE_E(0) || M91x_USE_E(1) || M91x_USE_E(2) || M91x_USE_E(3) || M91x_USE_E(4) || M91x_USE_E(5) || M91x_USE_E(6) || M91x_USE_E(7) #define M91x_SOME_E 1 #endif - #if !M91x_SOME_X && !M91x_SOME_Y && !M91x_SOME_Z && !M91x_USE_I && !M91x_USE_J && !M91x_USE_K && !M91x_SOME_E + #if !M91x_SOME_X && !M91x_SOME_Y && !M91x_SOME_Z && !M91x_USE_I && !M91x_USE_J && !M91x_USE_K && !M91x_USE_U && !M91x_USE_V && !M91x_USE_W && !M91x_SOME_E #error "MONITOR_DRIVER_STATUS requires at least one TMC2130, 2160, 2208, 2209, 2660, 5130, or 5160." #endif @@ -109,6 +118,9 @@ TERN_(M91x_USE_I, tmc_report_otpw(stepperI)); TERN_(M91x_USE_J, tmc_report_otpw(stepperJ)); TERN_(M91x_USE_K, tmc_report_otpw(stepperK)); + TERN_(M91x_USE_U, tmc_report_otpw(stepperU)); + TERN_(M91x_USE_V, tmc_report_otpw(stepperV)); + TERN_(M91x_USE_W, tmc_report_otpw(stepperW)); #if M91x_USE_E(0) tmc_report_otpw(stepperE0); #endif @@ -137,7 +149,7 @@ /** * M912: Clear TMC stepper driver overtemperature pre-warn flag held by the library - * Specify one or more axes with X, Y, Z, X1, Y1, Z1, X2, Y2, Z2, Z3, Z4 and E[index]. + * Specify one or more axes with X, Y, Z, X1, Y1, Z1, X2, Y2, Z2, Z3, Z4, A, B, C, U, V, W, and E[index]. * If no axes are given, clear all. * * Examples: @@ -154,9 +166,12 @@ hasI = TERN0(M91x_USE_I, parser.seen(axis_codes.i)), hasJ = TERN0(M91x_USE_J, parser.seen(axis_codes.j)), hasK = TERN0(M91x_USE_K, parser.seen(axis_codes.k)), + hasU = TERN0(M91x_USE_U, parser.seen(axis_codes.u)), + hasV = TERN0(M91x_USE_V, parser.seen(axis_codes.v)), + hasW = TERN0(M91x_USE_W, parser.seen(axis_codes.w)), hasE = TERN0(M91x_SOME_E, parser.seen(axis_codes.e)); - const bool hasNone = !hasE && !hasX && !hasY && !hasZ && !hasI && !hasJ && !hasK; + const bool hasNone = !hasE && !hasX && !hasY && !hasZ && !hasI && !hasJ && !hasK && !hasU && !hasV && !hasW; #if M91x_SOME_X const int8_t xval = int8_t(parser.byteval(axis_codes.x, 0xFF)); @@ -206,6 +221,18 @@ const int8_t kval = int8_t(parser.byteval(axis_codes.k, 0xFF)); if (hasNone || kval == 1 || (hasK && kval < 0)) tmc_clear_otpw(stepperK); #endif + #if M91x_USE_U + const int8_t uval = int8_t(parser.byteval(axis_codes.u, 0xFF)); + if (hasNone || uval == 1 || (hasU && uval < 0)) tmc_clear_otpw(stepperU); + #endif + #if M91x_USE_V + const int8_t vval = int8_t(parser.byteval(axis_codes.v, 0xFF)); + if (hasNone || vval == 1 || (hasV && vval < 0)) tmc_clear_otpw(stepperV); + #endif + #if M91x_USE_W + const int8_t wval = int8_t(parser.byteval(axis_codes.w, 0xFF)); + if (hasNone || wval == 1 || (hasW && wval < 0)) tmc_clear_otpw(stepperW); + #endif #if M91x_SOME_E const int8_t eval = int8_t(parser.byteval(axis_codes.e, 0xFF)); @@ -258,7 +285,7 @@ bool report = true; #if AXIS_IS_TMC(X2) || AXIS_IS_TMC(Y2) || AXIS_IS_TMC(Z2) || AXIS_IS_TMC(Z3) || AXIS_IS_TMC(Z4) const int8_t index = parser.byteval('I', -1); - #else + #elif AXIS_IS_TMC(X) || AXIS_IS_TMC(Y) || AXIS_IS_TMC(Z) constexpr int8_t index = -1; #endif LOOP_LOGICAL_AXES(i) if (int32_t value = parser.longval(axis_codes[i])) { @@ -296,6 +323,15 @@ #if K_HAS_STEALTHCHOP case K_AXIS: TMC_SET_PWMTHRS(K,K); break; #endif + #if U_HAS_STEALTHCHOP + case U_AXIS: TMC_SET_PWMTHRS(U,U); break; + #endif + #if V_HAS_STEALTHCHOP + case V_AXIS: TMC_SET_PWMTHRS(V,V); break; + #endif + #if W_HAS_STEALTHCHOP + case W_AXIS: TMC_SET_PWMTHRS(W,W); break; + #endif #if E0_HAS_STEALTHCHOP || E1_HAS_STEALTHCHOP || E2_HAS_STEALTHCHOP || E3_HAS_STEALTHCHOP || E4_HAS_STEALTHCHOP || E5_HAS_STEALTHCHOP || E6_HAS_STEALTHCHOP || E7_HAS_STEALTHCHOP case E_AXIS: { @@ -326,6 +362,9 @@ TERN_( I_HAS_STEALTHCHOP, TMC_SAY_PWMTHRS(I,I)); TERN_( J_HAS_STEALTHCHOP, TMC_SAY_PWMTHRS(J,J)); TERN_( K_HAS_STEALTHCHOP, TMC_SAY_PWMTHRS(K,K)); + TERN_( U_HAS_STEALTHCHOP, TMC_SAY_PWMTHRS(U,U)); + TERN_( V_HAS_STEALTHCHOP, TMC_SAY_PWMTHRS(V,V)); + TERN_( W_HAS_STEALTHCHOP, TMC_SAY_PWMTHRS(W,W)); TERN_(E0_HAS_STEALTHCHOP, TMC_SAY_PWMTHRS_E(0)); TERN_(E1_HAS_STEALTHCHOP, TMC_SAY_PWMTHRS_E(1)); @@ -397,6 +436,18 @@ say_M913(forReplay); SERIAL_ECHOLNPGM_P(SP_K_STR, stepperK.get_pwm_thrs()); #endif + #if U_HAS_STEALTHCHOP + say_M913(forReplay); + SERIAL_ECHOLNPGM_P(SP_U_STR, stepperU.get_pwm_thrs()); + #endif + #if V_HAS_STEALTHCHOP + say_M913(forReplay); + SERIAL_ECHOLNPGM_P(SP_V_STR, stepperV.get_pwm_thrs()); + #endif + #if W_HAS_STEALTHCHOP + say_M913(forReplay); + SERIAL_ECHOLNPGM_P(SP_W_STR, stepperW.get_pwm_thrs()); + #endif #if E0_HAS_STEALTHCHOP say_M913(forReplay); @@ -451,98 +502,66 @@ bool report = true; const uint8_t index = parser.byteval('I'); - LOOP_LINEAR_AXES(i) if (parser.seen(AXIS_CHAR(i))) { + LOOP_NUM_AXES(i) if (parser.seen(AXIS_CHAR(i))) { const int16_t value = parser.value_int(); report = false; switch (i) { #if X_SENSORLESS case X_AXIS: - #if AXIS_HAS_STALLGUARD(X) - if (index < 2) stepperX.homing_threshold(value); - #endif - #if AXIS_HAS_STALLGUARD(X2) - if (!(index & 1)) stepperX2.homing_threshold(value); - #endif + if (index < 2) stepperX.homing_threshold(value); + TERN_(X2_SENSORLESS, if (!(index & 1)) stepperX2.homing_threshold(value)); break; #endif #if Y_SENSORLESS case Y_AXIS: - #if AXIS_HAS_STALLGUARD(Y) - if (index < 2) stepperY.homing_threshold(value); - #endif - #if AXIS_HAS_STALLGUARD(Y2) - if (!(index & 1)) stepperY2.homing_threshold(value); - #endif + if (index < 2) stepperY.homing_threshold(value); + TERN_(Y2_SENSORLESS, if (!(index & 1)) stepperY2.homing_threshold(value)); break; #endif #if Z_SENSORLESS case Z_AXIS: - #if AXIS_HAS_STALLGUARD(Z) - if (index < 2) stepperZ.homing_threshold(value); - #endif - #if AXIS_HAS_STALLGUARD(Z2) - if (index == 0 || index == 2) stepperZ2.homing_threshold(value); - #endif - #if AXIS_HAS_STALLGUARD(Z3) - if (index == 0 || index == 3) stepperZ3.homing_threshold(value); - #endif - #if AXIS_HAS_STALLGUARD(Z4) - if (index == 0 || index == 4) stepperZ4.homing_threshold(value); - #endif + if (index < 2) stepperZ.homing_threshold(value); + TERN_(Z2_SENSORLESS, if (index == 0 || index == 2) stepperZ2.homing_threshold(value)); + TERN_(Z3_SENSORLESS, if (index == 0 || index == 3) stepperZ3.homing_threshold(value)); + TERN_(Z4_SENSORLESS, if (index == 0 || index == 4) stepperZ4.homing_threshold(value)); break; #endif - #if I_SENSORLESS && AXIS_HAS_STALLGUARD(I) + #if I_SENSORLESS case I_AXIS: stepperI.homing_threshold(value); break; #endif - #if J_SENSORLESS && AXIS_HAS_STALLGUARD(J) + #if J_SENSORLESS case J_AXIS: stepperJ.homing_threshold(value); break; #endif - #if K_SENSORLESS && AXIS_HAS_STALLGUARD(K) + #if K_SENSORLESS case K_AXIS: stepperK.homing_threshold(value); break; #endif + #if U_SENSORLESS && AXIS_HAS_STALLGUARD(U) + case U_AXIS: stepperU.homing_threshold(value); break; + #endif + #if V_SENSORLESS && AXIS_HAS_STALLGUARD(V) + case V_AXIS: stepperV.homing_threshold(value); break; + #endif + #if W_SENSORLESS && AXIS_HAS_STALLGUARD(W) + case W_AXIS: stepperW.homing_threshold(value); break; + #endif } } if (report) { - #if X_SENSORLESS - #if AXIS_HAS_STALLGUARD(X) - tmc_print_sgt(stepperX); - #endif - #if AXIS_HAS_STALLGUARD(X2) - tmc_print_sgt(stepperX2); - #endif - #endif - #if Y_SENSORLESS - #if AXIS_HAS_STALLGUARD(Y) - tmc_print_sgt(stepperY); - #endif - #if AXIS_HAS_STALLGUARD(Y2) - tmc_print_sgt(stepperY2); - #endif - #endif - #if Z_SENSORLESS - #if AXIS_HAS_STALLGUARD(Z) - tmc_print_sgt(stepperZ); - #endif - #if AXIS_HAS_STALLGUARD(Z2) - tmc_print_sgt(stepperZ2); - #endif - #if AXIS_HAS_STALLGUARD(Z3) - tmc_print_sgt(stepperZ3); - #endif - #if AXIS_HAS_STALLGUARD(Z4) - tmc_print_sgt(stepperZ4); - #endif - #endif - #if I_SENSORLESS && AXIS_HAS_STALLGUARD(I) - tmc_print_sgt(stepperI); - #endif - #if J_SENSORLESS && AXIS_HAS_STALLGUARD(J) - tmc_print_sgt(stepperJ); - #endif - #if K_SENSORLESS && AXIS_HAS_STALLGUARD(K) - tmc_print_sgt(stepperK); - #endif + TERN_(X_SENSORLESS, tmc_print_sgt(stepperX)); + TERN_(X2_SENSORLESS, tmc_print_sgt(stepperX2)); + TERN_(Y_SENSORLESS, tmc_print_sgt(stepperY)); + TERN_(Y2_SENSORLESS, tmc_print_sgt(stepperY2)); + TERN_(Z_SENSORLESS, tmc_print_sgt(stepperZ)); + TERN_(Z2_SENSORLESS, tmc_print_sgt(stepperZ2)); + TERN_(Z3_SENSORLESS, tmc_print_sgt(stepperZ3)); + TERN_(Z4_SENSORLESS, tmc_print_sgt(stepperZ4)); + TERN_(I_SENSORLESS, tmc_print_sgt(stepperI)); + TERN_(J_SENSORLESS, tmc_print_sgt(stepperJ)); + TERN_(K_SENSORLESS, tmc_print_sgt(stepperK)); + TERN_(U_SENSORLESS, tmc_print_sgt(stepperU)); + TERN_(V_SENSORLESS, tmc_print_sgt(stepperV)); + TERN_(W_SENSORLESS, tmc_print_sgt(stepperW)); } } @@ -605,6 +624,18 @@ say_M914(forReplay); SERIAL_ECHOLNPGM_P(SP_K_STR, stepperK.homing_threshold()); #endif + #if U_SENSORLESS + say_M914(forReplay); + SERIAL_ECHOLNPGM_P(SP_U_STR, stepperU.homing_threshold()); + #endif + #if V_SENSORLESS + say_M914(forReplay); + SERIAL_ECHOLNPGM_P(SP_V_STR, stepperV.homing_threshold()); + #endif + #if W_SENSORLESS + say_M914(forReplay); + SERIAL_ECHOLNPGM_P(SP_W_STR, stepperW.homing_threshold()); + #endif } #endif // USE_SENSORLESS diff --git a/Marlin/src/gcode/feature/trinamic/M919.cpp b/Marlin/src/gcode/feature/trinamic/M919.cpp index 4dce28f0ae..d4ba4f74ea 100644 --- a/Marlin/src/gcode/feature/trinamic/M919.cpp +++ b/Marlin/src/gcode/feature/trinamic/M919.cpp @@ -93,7 +93,7 @@ void GcodeSuite::M919() { #if AXIS_IS_TMC(X2) || AXIS_IS_TMC(Y2) || AXIS_IS_TMC(Z2) || AXIS_IS_TMC(Z3) || AXIS_IS_TMC(Z4) const int8_t index = parser.byteval('I'); - #else + #elif AXIS_IS_TMC(X) || AXIS_IS_TMC(Y) || AXIS_IS_TMC(Z) constexpr int8_t index = -1; #endif diff --git a/Marlin/src/gcode/gcode.cpp b/Marlin/src/gcode/gcode.cpp index a31341d036..b16be8eaf0 100644 --- a/Marlin/src/gcode/gcode.cpp +++ b/Marlin/src/gcode/gcode.cpp @@ -85,7 +85,10 @@ axis_bits_t GcodeSuite::axis_relative = 0 LOGICAL_AXIS_GANG( | (ar_init.z << REL_Z), | (ar_init.i << REL_I), | (ar_init.j << REL_J), - | (ar_init.k << REL_K) + | (ar_init.k << REL_K), + | (ar_init.u << REL_U), + | (ar_init.v << REL_V), + | (ar_init.w << REL_W) ); #if EITHER(HAS_AUTO_REPORTING, HOST_KEEPALIVE_FEATURE) @@ -176,7 +179,7 @@ void GcodeSuite::get_destination_from_command() { #endif // Get new XYZ position, whether absolute or relative - LOOP_LINEAR_AXES(i) { + LOOP_NUM_AXES(i) { if ( (seen[i] = parser.seenval(AXIS_CHAR(i))) ) { const float v = parser.value_axis_units((AxisEnum)i); if (skip_move) @@ -787,6 +790,10 @@ void GcodeSuite::process_parsed_command(const bool no_ok/*=false*/) { case 305: M305(); break; // M305: Set user thermistor parameters #endif + #if ENABLED(MPCTEMP) + case 306: M306(); break; // M306: MPC autotune + #endif + #if ENABLED(REPETIER_GCODE_M360) case 360: M360(); break; // M360: Firmware settings #endif diff --git a/Marlin/src/gcode/gcode.h b/Marlin/src/gcode/gcode.h index 1e15756f24..1b2f6ec275 100644 --- a/Marlin/src/gcode/gcode.h +++ b/Marlin/src/gcode/gcode.h @@ -215,12 +215,13 @@ * M303 - PID relay autotune S sets the target temperature. Default 150C. (Requires PIDTEMP) * M304 - Set bed PID parameters P I and D. (Requires PIDTEMPBED) * M305 - Set user thermistor parameters R T and P. (Requires TEMP_SENSOR_x 1000) + * M306 - MPC autotune. (Requires MPCTEMP) * M309 - Set chamber PID parameters P I and D. (Requires PIDTEMPCHAMBER) * M350 - Set microstepping mode. (Requires digital microstepping pins.) * M351 - Toggle MS1 MS2 pins directly. (Requires digital microstepping pins.) * M355 - Set Case Light on/off and set brightness. (Requires CASE_LIGHT_PIN) - * M380 - Activate solenoid on active extruder. (Requires EXT_SOLENOID) - * M381 - Disable all solenoids. (Requires EXT_SOLENOID) + * M380 - Activate solenoid on active tool (Requires EXT_SOLENOID) or the tool specified by 'S' (Requires MANUAL_SOLENOID_CONTROL). + * M381 - Disable solenoids on all tools (Requires EXT_SOLENOID) or the tool specified by 'S' (Requires MANUAL_SOLENOID_CONTROL). * M400 - Finish all moves. * M401 - Deploy and activate Z probe. (Requires a probe) * M402 - Deactivate and stow Z probe. (Requires a probe) @@ -337,7 +338,7 @@ #endif enum AxisRelative : uint8_t { - LOGICAL_AXIS_LIST(REL_E, REL_X, REL_Y, REL_Z, REL_I, REL_J, REL_K) + LOGICAL_AXIS_LIST(REL_E, REL_X, REL_Y, REL_Z, REL_I, REL_J, REL_K, REL_U, REL_V, REL_W) #if HAS_EXTRUDERS , E_MODE_ABS, E_MODE_REL #endif @@ -363,7 +364,8 @@ public: axis_relative = rel ? (0 LOGICAL_AXIS_GANG( | _BV(REL_E), | _BV(REL_X), | _BV(REL_Y), | _BV(REL_Z), - | _BV(REL_I), | _BV(REL_J), | _BV(REL_K) + | _BV(REL_I), | _BV(REL_J), | _BV(REL_K), + | _BV(REL_U), | _BV(REL_V), | _BV(REL_W) )) : 0; } #if HAS_EXTRUDERS @@ -928,6 +930,11 @@ private: static void M305(); #endif + #if ENABLED(MPCTEMP) + static void M306(); + static void M306_report(const bool forReplay=true); + #endif + #if ENABLED(PIDTEMPCHAMBER) static void M309(); static void M309_report(const bool forReplay=true); diff --git a/Marlin/src/gcode/geometry/G53-G59.cpp b/Marlin/src/gcode/geometry/G53-G59.cpp index db2404a28d..092c141228 100644 --- a/Marlin/src/gcode/geometry/G53-G59.cpp +++ b/Marlin/src/gcode/geometry/G53-G59.cpp @@ -39,7 +39,7 @@ bool GcodeSuite::select_coordinate_system(const int8_t _new) { xyz_float_t new_offset{0}; if (WITHIN(_new, 0, MAX_COORDINATE_SYSTEMS - 1)) new_offset = coordinate_system[_new]; - LOOP_LINEAR_AXES(i) { + LOOP_NUM_AXES(i) { if (position_shift[i] != new_offset[i]) { position_shift[i] = new_offset[i]; update_workspace_offset((AxisEnum)i); diff --git a/Marlin/src/gcode/geometry/G92.cpp b/Marlin/src/gcode/geometry/G92.cpp index 3c49fe2a26..2407599239 100644 --- a/Marlin/src/gcode/geometry/G92.cpp +++ b/Marlin/src/gcode/geometry/G92.cpp @@ -29,7 +29,7 @@ #endif /** - * G92: Set the Current Position to the given X [Y [Z [A [B [C [E]]]]]] values. + * G92: Set the Current Position to the given X [Y [Z [A [B [C [U [V [W ]]]]]]]] [E] values. * * Behind the scenes the G92 command may modify the Current Position * or the Position Shift depending on settings and sub-commands. @@ -37,14 +37,14 @@ * Since E has no Workspace Offset, it is always set directly. * * Without Workspace Offsets (e.g., with NO_WORKSPACE_OFFSETS): - * G92 : Set NATIVE Current Position to the given X [Y [Z [A [B [C [E]]]]]]. + * G92 : Set NATIVE Current Position to the given X [Y [Z [A [B [C [U [V [W ]]]]]]]] [E]. * * Using Workspace Offsets (default Marlin behavior): - * G92 : Modify Workspace Offsets so the reported position shows the given X [Y [Z [A [B [C [E]]]]]]. + * G92 : Modify Workspace Offsets so the reported position shows the given X [Y [Z [A [B [C [U [V [W ]]]]]]]] [E]. * G92.1 : Zero XYZ Workspace Offsets (so the reported position = the native position). * * With POWER_LOSS_RECOVERY: - * G92.9 : Set NATIVE Current Position to the given X [Y [Z [A [B [C [E]]]]]]. + * G92.9 : Set NATIVE Current Position to the given X [Y [Z [A [B [C [U [V [W ]]]]]]]] [E]. */ void GcodeSuite::G92() { @@ -64,7 +64,7 @@ void GcodeSuite::G92() { #if ENABLED(CNC_COORDINATE_SYSTEMS) && !IS_SCARA case 1: // G92.1 - Zero the Workspace Offset - LOOP_LINEAR_AXES(i) if (position_shift[i]) { + LOOP_NUM_AXES(i) if (position_shift[i]) { position_shift[i] = 0; update_workspace_offset((AxisEnum)i); } diff --git a/Marlin/src/gcode/geometry/M206_M428.cpp b/Marlin/src/gcode/geometry/M206_M428.cpp index 131dbecf33..f23c83140e 100644 --- a/Marlin/src/gcode/geometry/M206_M428.cpp +++ b/Marlin/src/gcode/geometry/M206_M428.cpp @@ -39,11 +39,17 @@ */ void GcodeSuite::M206() { if (!parser.seen_any()) return M206_report(); - - LOOP_LINEAR_AXES(i) - if (parser.seen(AXIS_CHAR(i))) - set_home_offset((AxisEnum)i, parser.value_linear_units()); - + NUM_AXIS_CODE( + if (parser.seen('X')) set_home_offset(X_AXIS, parser.value_linear_units()), + if (parser.seen('Y')) set_home_offset(Y_AXIS, parser.value_linear_units()), + if (parser.seen('Z')) set_home_offset(Y_AXIS, parser.value_linear_units()), + if (parser.seen(AXIS4_NAME)) set_home_offset(I_AXIS, parser.TERN(AXIS4_ROTATES, value_float, value_linear_units)()), + if (parser.seen(AXIS5_NAME)) set_home_offset(J_AXIS, parser.TERN(AXIS5_ROTATES, value_float, value_linear_units)()), + if (parser.seen(AXIS6_NAME)) set_home_offset(K_AXIS, parser.TERN(AXIS6_ROTATES, value_float, value_linear_units)()), + if (parser.seen(AXIS7_NAME)) set_home_offset(U_AXIS, parser.TERN(AXIS7_ROTATES, value_float, value_linear_units)()), + if (parser.seen(AXIS8_NAME)) set_home_offset(V_AXIS, parser.TERN(AXIS8_ROTATES, value_float, value_linear_units)()), + if (parser.seen(AXIS9_NAME)) set_home_offset(W_AXIS, parser.TERN(AXIS9_ROTATES, value_float, value_linear_units)()) + ); #if ENABLED(MORGAN_SCARA) if (parser.seen('T')) set_home_offset(A_AXIS, parser.value_float()); // Theta if (parser.seen('P')) set_home_offset(B_AXIS, parser.value_float()); // Psi @@ -56,13 +62,16 @@ void GcodeSuite::M206_report(const bool forReplay/*=true*/) { report_heading_etc(forReplay, F(STR_HOME_OFFSET)); SERIAL_ECHOLNPGM_P( #if IS_CARTESIAN - LIST_N(DOUBLE(LINEAR_AXES), + LIST_N(DOUBLE(NUM_AXES), PSTR(" M206 X"), LINEAR_UNIT(home_offset.x), SP_Y_STR, LINEAR_UNIT(home_offset.y), SP_Z_STR, LINEAR_UNIT(home_offset.z), - SP_I_STR, LINEAR_UNIT(home_offset.i), - SP_J_STR, LINEAR_UNIT(home_offset.j), - SP_K_STR, LINEAR_UNIT(home_offset.k) + SP_I_STR, I_AXIS_UNIT(home_offset.i), + SP_J_STR, J_AXIS_UNIT(home_offset.j), + SP_K_STR, K_AXIS_UNIT(home_offset.k), + SP_U_STR, U_AXIS_UNIT(home_offset.u), + SP_V_STR, V_AXIS_UNIT(home_offset.v), + SP_W_STR, W_AXIS_UNIT(home_offset.w) ) #else PSTR(" M206 Z"), LINEAR_UNIT(home_offset.z) @@ -85,23 +94,22 @@ void GcodeSuite::M428() { if (homing_needed_error()) return; xyz_float_t diff; - LOOP_LINEAR_AXES(i) { + LOOP_NUM_AXES(i) { diff[i] = base_home_pos((AxisEnum)i) - current_position[i]; if (!WITHIN(diff[i], -20, 20) && home_dir((AxisEnum)i) > 0) diff[i] = -current_position[i]; if (!WITHIN(diff[i], -20, 20)) { SERIAL_ERROR_MSG(STR_ERR_M428_TOO_FAR); LCD_ALERTMESSAGE_F("Err: Too far!"); - BUZZ(200, 40); + ERR_BUZZ(); return; } } - LOOP_LINEAR_AXES(i) set_home_offset((AxisEnum)i, diff[i]); + LOOP_NUM_AXES(i) set_home_offset((AxisEnum)i, diff[i]); report_current_position(); LCD_MESSAGE(MSG_HOME_OFFSETS_APPLIED); - BUZZ(100, 659); - BUZZ(100, 698); + OKAY_BUZZ(); } #endif // HAS_M206_COMMAND diff --git a/Marlin/src/gcode/host/M114.cpp b/Marlin/src/gcode/host/M114.cpp index cdb9efb71b..41433b510d 100644 --- a/Marlin/src/gcode/host/M114.cpp +++ b/Marlin/src/gcode/host/M114.cpp @@ -47,7 +47,7 @@ void report_linear_axis_pos(const xyz_pos_t &pos, const uint8_t precision=3) { char str[12]; - LOOP_LINEAR_AXES(a) { + LOOP_NUM_AXES(a) { SERIAL_CHAR(' ', AXIS_CHAR(a), ':'); SERIAL_ECHO(dtostrf(pos[a], 1, precision, str)); } @@ -134,6 +134,15 @@ #if AXIS_IS_L64XX(K) REPORT_ABSOLUTE_POS(K); #endif + #if AXIS_IS_L64XX(U) + REPORT_ABSOLUTE_POS(U); + #endif + #if AXIS_IS_L64XX(V) + REPORT_ABSOLUTE_POS(V); + #endif + #if AXIS_IS_L64XX(W) + REPORT_ABSOLUTE_POS(W); + #endif #if AXIS_IS_L64XX(E0) REPORT_ABSOLUTE_POS(E0); #endif @@ -184,7 +193,10 @@ cartes.x, cartes.y, cartes.z, planner.get_axis_position_mm(I_AXIS), planner.get_axis_position_mm(J_AXIS), - planner.get_axis_position_mm(K_AXIS) + planner.get_axis_position_mm(K_AXIS), + planner.get_axis_position_mm(U_AXIS), + planner.get_axis_position_mm(V_AXIS), + planner.get_axis_position_mm(W_AXIS) ); report_all_axis_pos(from_steppers); diff --git a/Marlin/src/gcode/host/M115.cpp b/Marlin/src/gcode/host/M115.cpp index 50ff834d11..ca8af796ef 100644 --- a/Marlin/src/gcode/host/M115.cpp +++ b/Marlin/src/gcode/host/M115.cpp @@ -65,8 +65,8 @@ void GcodeSuite::M115() { "PROTOCOL_VERSION:" PROTOCOL_VERSION " " "MACHINE_TYPE:" MACHINE_NAME " " "EXTRUDER_COUNT:" STRINGIFY(EXTRUDERS) " " - #if LINEAR_AXES != XYZ - "AXIS_COUNT:" STRINGIFY(LINEAR_AXES) " " + #if NUM_AXES != XYZ + "AXIS_COUNT:" STRINGIFY(NUM_AXES) " " #endif #ifdef MACHINE_UUID "UUID:" MACHINE_UUID diff --git a/Marlin/src/gcode/host/M16.cpp b/Marlin/src/gcode/host/M16.cpp index 03e734daaa..07b0c5ef57 100644 --- a/Marlin/src/gcode/host/M16.cpp +++ b/Marlin/src/gcode/host/M16.cpp @@ -26,6 +26,7 @@ #include "../gcode.h" #include "../../MarlinCore.h" +#include "../../lcd/marlinui.h" /** * M16: Expected Printer Check @@ -37,4 +38,4 @@ void GcodeSuite::M16() { } -#endif +#endif // EXPECTED_PRINTER_CHECK diff --git a/Marlin/src/gcode/host/M360.cpp b/Marlin/src/gcode/host/M360.cpp index 1feb57996a..b3a95a35aa 100644 --- a/Marlin/src/gcode/host/M360.cpp +++ b/Marlin/src/gcode/host/M360.cpp @@ -180,7 +180,7 @@ void GcodeSuite::M360() { // config_line(F("NumExtruder"), EXTRUDERS); #if HAS_EXTRUDERS - LOOP_L_N(e, EXTRUDERS) { + EXTRUDER_LOOP() { config_line_e(e, JERK_STR, TERN(HAS_LINEAR_E_JERK, planner.max_e_jerk[E_INDEX_N(e)], TERN(HAS_CLASSIC_JERK, planner.max_jerk.e, DEFAULT_EJERK))); config_line_e(e, F("MaxSpeed"), planner.settings.max_feedrate_mm_s[E_AXIS_N(e)]); config_line_e(e, F("Acceleration"), planner.settings.max_acceleration_mm_per_s2[E_AXIS_N(e)]); diff --git a/Marlin/src/gcode/lcd/M117.cpp b/Marlin/src/gcode/lcd/M117.cpp index f26694bd64..86023e12e3 100644 --- a/Marlin/src/gcode/lcd/M117.cpp +++ b/Marlin/src/gcode/lcd/M117.cpp @@ -33,7 +33,7 @@ void GcodeSuite::M117() { if (parser.string_arg && parser.string_arg[0]) - ui.set_status(parser.string_arg); + ui.set_status(parser.string_arg, true); else ui.reset_status(); diff --git a/Marlin/src/gcode/motion/G0_G1.cpp b/Marlin/src/gcode/motion/G0_G1.cpp index 493fd00da1..d647894d27 100644 --- a/Marlin/src/gcode/motion/G0_G1.cpp +++ b/Marlin/src/gcode/motion/G0_G1.cpp @@ -49,13 +49,16 @@ void GcodeSuite::G0_G1(TERN_(HAS_FAST_MOVES, const bool fast_move/*=false*/)) { if (IsRunning() #if ENABLED(NO_MOTION_BEFORE_HOMING) && !homing_needed_error( - LINEAR_AXIS_GANG( + NUM_AXIS_GANG( (parser.seen_test('X') ? _BV(X_AXIS) : 0), | (parser.seen_test('Y') ? _BV(Y_AXIS) : 0), | (parser.seen_test('Z') ? _BV(Z_AXIS) : 0), | (parser.seen_test(AXIS4_NAME) ? _BV(I_AXIS) : 0), | (parser.seen_test(AXIS5_NAME) ? _BV(J_AXIS) : 0), - | (parser.seen_test(AXIS6_NAME) ? _BV(K_AXIS) : 0)) + | (parser.seen_test(AXIS6_NAME) ? _BV(K_AXIS) : 0), + | (parser.seen_test(AXIS7_NAME) ? _BV(U_AXIS) : 0), + | (parser.seen_test(AXIS8_NAME) ? _BV(V_AXIS) : 0), + | (parser.seen_test(AXIS9_NAME) ? _BV(W_AXIS) : 0)) ) #endif ) { @@ -89,7 +92,7 @@ void GcodeSuite::G0_G1(TERN_(HAS_FAST_MOVES, const bool fast_move/*=false*/)) { if (MIN_AUTORETRACT <= MAX_AUTORETRACT) { // When M209 Autoretract is enabled, convert E-only moves to firmware retract/recover moves if (fwretract.autoretract_enabled && parser.seen_test('E') - && !parser.seen(LINEAR_AXIS_GANG("X", "Y", "Z", STR_I, STR_J, STR_K)) + && !parser.seen(NUM_AXIS_GANG("X", "Y", "Z", STR_I, STR_J, STR_K, STR_U, STR_V, STR_W)) ) { const float echange = destination.e - current_position.e; // Is this a retract or recover move? diff --git a/Marlin/src/gcode/motion/G2_G3.cpp b/Marlin/src/gcode/motion/G2_G3.cpp index 0c7bdc7a3a..dd1c1d1470 100644 --- a/Marlin/src/gcode/motion/G2_G3.cpp +++ b/Marlin/src/gcode/motion/G2_G3.cpp @@ -48,8 +48,8 @@ #define MIN_ARC_SEGMENT_MM MAX_ARC_SEGMENT_MM #endif -#define ARC_LIJK_CODE(L,I,J,K) CODE_N(SUB2(LINEAR_AXES),L,I,J,K) -#define ARC_LIJKE_CODE(L,I,J,K,E) ARC_LIJK_CODE(L,I,J,K); CODE_ITEM_E(E) +#define ARC_LIJKUVW_CODE(L,I,J,K,U,V,W) CODE_N(SUB2(NUM_AXES),L,I,J,K,U,V,W) +#define ARC_LIJKUVWE_CODE(L,I,J,K,U,V,W,E) ARC_LIJKUVW_CODE(L,I,J,K,U,V,W); CODE_ITEM_E(E) /** * Plan an arc in 2 dimensions, with linear motion in the other axes. @@ -82,11 +82,14 @@ void plan_arc( rt_X = cart[axis_p] - center_P, rt_Y = cart[axis_q] - center_Q; - ARC_LIJK_CODE( + ARC_LIJKUVW_CODE( const float start_L = current_position[axis_l], const float start_I = current_position.i, const float start_J = current_position.j, - const float start_K = current_position.k + const float start_K = current_position.k, + const float start_U = current_position.u, + const float start_V = current_position.v, + const float start_W = current_position.w ); // Angle of rotation between position and target from the circle center. @@ -122,11 +125,14 @@ void plan_arc( min_segments = CEIL((MIN_CIRCLE_SEGMENTS) * portion_of_circle); // Minimum segments for the arc } - ARC_LIJKE_CODE( + ARC_LIJKUVWE_CODE( float travel_L = cart[axis_l] - start_L, float travel_I = cart.i - start_I, float travel_J = cart.j - start_J, float travel_K = cart.k - start_K, + float travel_U = cart.u - start_U, + float travel_V = cart.v - start_V, + float travel_W = cart.w - start_W, float travel_E = cart.e - current_position.e ); @@ -135,30 +141,39 @@ void plan_arc( const float total_angular = abs_angular_travel + circles * RADIANS(360), // Total rotation with all circles and remainder part_per_circle = RADIANS(360) / total_angular; // Each circle's part of the total - ARC_LIJKE_CODE( + ARC_LIJKUVWE_CODE( const float per_circle_L = travel_L * part_per_circle, // L movement per circle const float per_circle_I = travel_I * part_per_circle, const float per_circle_J = travel_J * part_per_circle, const float per_circle_K = travel_K * part_per_circle, + const float per_circle_U = travel_U * part_per_circle, + const float per_circle_V = travel_V * part_per_circle, + const float per_circle_W = travel_W * part_per_circle, const float per_circle_E = travel_E * part_per_circle // E movement per circle ); xyze_pos_t temp_position = current_position; for (uint16_t n = circles; n--;) { - ARC_LIJKE_CODE( // Destination Linear Axes + ARC_LIJKUVWE_CODE( // Destination Linear Axes temp_position[axis_l] += per_circle_L, temp_position.i += per_circle_I, temp_position.j += per_circle_J, temp_position.k += per_circle_K, + temp_position.u += per_circle_U, + temp_position.v += per_circle_V, + temp_position.w += per_circle_W, temp_position.e += per_circle_E // Destination E axis ); plan_arc(temp_position, offset, clockwise, 0); // Plan a single whole circle } - ARC_LIJKE_CODE( + ARC_LIJKUVWE_CODE( travel_L = cart[axis_l] - current_position[axis_l], travel_I = cart.i - current_position.i, travel_J = cart.j - current_position.j, travel_K = cart.k - current_position.k, + travel_U = cart.u - current_position.u, + travel_V = cart.v - current_position.v, + travel_W = cart.w - current_position.w, travel_E = cart.e - current_position.e ); } @@ -168,11 +183,14 @@ void plan_arc( // Return if the move is near zero if (flat_mm < 0.0001f - GANG_N(SUB2(LINEAR_AXES), + GANG_N(SUB2(NUM_AXES), && travel_L < 0.0001f, && travel_I < 0.0001f, && travel_J < 0.0001f, - && travel_K < 0.0001f + && travel_K < 0.0001f, + && travel_U < 0.0001f, + && travel_V < 0.0001f, + && travel_W < 0.0001f ) ) return; @@ -236,11 +254,14 @@ void plan_arc( cos_T = 1 - 0.5f * sq_theta_per_segment; // Small angle approximation #if DISABLED(AUTO_BED_LEVELING_UBL) - ARC_LIJK_CODE( + ARC_LIJKUVW_CODE( const float per_segment_L = proportion * travel_L / segments, const float per_segment_I = proportion * travel_I / segments, const float per_segment_J = proportion * travel_J / segments, - const float per_segment_K = proportion * travel_K / segments + const float per_segment_K = proportion * travel_K / segments, + const float per_segment_U = proportion * travel_U / segments, + const float per_segment_V = proportion * travel_V / segments, + const float per_segment_W = proportion * travel_W / segments ); #endif @@ -250,11 +271,14 @@ void plan_arc( if (tooshort) segments++; // Initialize all linear axes and E - ARC_LIJKE_CODE( + ARC_LIJKUVWE_CODE( raw[axis_l] = current_position[axis_l], raw.i = current_position.i, raw.j = current_position.j, raw.k = current_position.k, + raw.u = current_position.u, + raw.v = current_position.v, + raw.w = current_position.w, raw.e = current_position.e ); @@ -303,11 +327,15 @@ void plan_arc( // Update raw location raw[axis_p] = center_P + rvec.a; raw[axis_q] = center_Q + rvec.b; - ARC_LIJKE_CODE( + ARC_LIJKUVWE_CODE( #if ENABLED(AUTO_BED_LEVELING_UBL) - raw[axis_l] = start_L, raw.i = start_I, raw.j = start_J, raw.k = start_K + raw[axis_l] = start_L, + raw.i = start_I, raw.j = start_J, raw.k = start_K, + raw.u = start_U, raw.v = start_V, raw.w = start_V #else - raw[axis_l] += per_segment_L, raw.i += per_segment_I, raw.j += per_segment_J, raw.k += per_segment_K + raw[axis_l] += per_segment_L, + raw.i += per_segment_I, raw.j += per_segment_J, raw.k += per_segment_K, + raw.u += per_segment_U, raw.v += per_segment_V, raw.w += per_segment_W #endif , raw.e += extruder_per_segment ); @@ -325,7 +353,11 @@ void plan_arc( // Ensure last segment arrives at target location. raw = cart; #if ENABLED(AUTO_BED_LEVELING_UBL) - ARC_LIJK_CODE(raw[axis_l] = start_L, raw.i = start_I, raw.j = start_J, raw.k = start_K); + ARC_LIJKUVW_CODE( + raw[axis_l] = start_L, + raw.i = start_I, raw.j = start_J, raw.k = start_K, + raw.u = start_U, raw.v = start_V, raw.w = start_W + ); #endif apply_motion_limits(raw); @@ -337,7 +369,11 @@ void plan_arc( planner.buffer_line(raw, scaled_fr_mm_s, active_extruder, 0 OPTARG(SCARA_FEEDRATE_SCALING, inv_duration)); #if ENABLED(AUTO_BED_LEVELING_UBL) - ARC_LIJK_CODE(raw[axis_l] = start_L, raw.i = start_I, raw.j = start_J, raw.k = start_K); + ARC_LIJKUVW_CODE( + raw[axis_l] = start_L, + raw.i = start_I, raw.j = start_J, raw.k = start_K, + raw.u = start_U, raw.v = start_V, raw.w = start_W + ); #endif current_position = raw; @@ -380,7 +416,7 @@ void GcodeSuite::G2_G3(const bool clockwise) { relative_mode = true; #endif - get_destination_from_command(); // Get X Y [Z[I[J[K]]]] [E] F (and set cutter power) + get_destination_from_command(); // Get X Y [Z[I[J[K...]]]] [E] F (and set cutter power) TERN_(SF_ARC_FIX, relative_mode = relative_mode_backup); diff --git a/Marlin/src/gcode/motion/M290.cpp b/Marlin/src/gcode/motion/M290.cpp index f3d7b7c8dc..8185bf8f78 100644 --- a/Marlin/src/gcode/motion/M290.cpp +++ b/Marlin/src/gcode/motion/M290.cpp @@ -69,7 +69,7 @@ */ void GcodeSuite::M290() { #if ENABLED(BABYSTEP_XY) - LOOP_LINEAR_AXES(a) + LOOP_NUM_AXES(a) if (parser.seenval(AXIS_CHAR(a)) || (a == Z_AXIS && parser.seenval('S'))) { const float offs = constrain(parser.value_axis_units((AxisEnum)a), -2, 2); babystep.add_mm((AxisEnum)a, offs); @@ -87,7 +87,7 @@ void GcodeSuite::M290() { } #endif - if (!parser.seen(LINEAR_AXIS_GANG("X", "Y", "Z", STR_I, STR_J, STR_K)) || parser.seen('R')) { + if (!parser.seen(NUM_AXIS_GANG("X", "Y", "Z", STR_I, STR_J, STR_K, STR_U, STR_V, STR_W)) || parser.seen('R')) { SERIAL_ECHO_START(); #if ENABLED(BABYSTEP_ZPROBE_OFFSET) diff --git a/Marlin/src/gcode/parser.cpp b/Marlin/src/gcode/parser.cpp index 4d4fdae0d6..3fc1fc1625 100644 --- a/Marlin/src/gcode/parser.cpp +++ b/Marlin/src/gcode/parser.cpp @@ -248,7 +248,7 @@ void GCodeParser::parse(char *p) { case 'R': if (!WITHIN(motion_mode_codenum, 2, 3)) return; #endif - LOGICAL_AXIS_GANG(case 'E':, case 'X':, case 'Y':, case 'Z':, case AXIS4_NAME:, case AXIS5_NAME:, case AXIS6_NAME:) + LOGICAL_AXIS_GANG(case 'E':, case 'X':, case 'Y':, case 'Z':, case AXIS4_NAME:, case AXIS5_NAME:, case AXIS6_NAME:, case AXIS7_NAME:, case AXIS8_NAME:, case AXIS9_NAME:) case 'F': if (motion_mode_codenum < 0) return; command_letter = 'G'; diff --git a/Marlin/src/gcode/parser.h b/Marlin/src/gcode/parser.h index 1487c083ec..c91a0de5f2 100644 --- a/Marlin/src/gcode/parser.h +++ b/Marlin/src/gcode/parser.h @@ -309,13 +309,18 @@ public: } static float axis_unit_factor(const AxisEnum axis) { - return ( - #if HAS_EXTRUDERS - axis >= E_AXIS && volumetric_enabled ? volumetric_unit_factor : linear_unit_factor - #else - linear_unit_factor - #endif - ); + if (false + || TERN0(AXIS4_ROTATES, axis == I_AXIS) + || TERN0(AXIS5_ROTATES, axis == J_AXIS) + || TERN0(AXIS6_ROTATES, axis == K_AXIS) + || TERN0(AXIS7_ROTATES, axis == U_AXIS) + || TERN0(AXIS8_ROTATES, axis == V_AXIS) + || TERN0(AXIS9_ROTATES, axis == W_AXIS) + ) return 1.0f; + #if HAS_EXTRUDERS + if (axis >= E_AXIS && volumetric_enabled) return volumetric_unit_factor; + #endif + return linear_unit_factor; } static float linear_value_to_mm(const_float_t v) { return v * linear_unit_factor; } @@ -340,6 +345,13 @@ public: #define LINEAR_UNIT(V) parser.mm_to_linear_unit(V) #define VOLUMETRIC_UNIT(V) parser.mm_to_volumetric_unit(V) + #define I_AXIS_UNIT(V) TERN(AXIS4_ROTATES, (V), LINEAR_UNIT(V)) + #define J_AXIS_UNIT(V) TERN(AXIS5_ROTATES, (V), LINEAR_UNIT(V)) + #define K_AXIS_UNIT(V) TERN(AXIS6_ROTATES, (V), LINEAR_UNIT(V)) + #define U_AXIS_UNIT(V) TERN(AXIS7_ROTATES, (V), LINEAR_UNIT(V)) + #define V_AXIS_UNIT(V) TERN(AXIS8_ROTATES, (V), LINEAR_UNIT(V)) + #define W_AXIS_UNIT(V) TERN(AXIS9_ROTATES, (V), LINEAR_UNIT(V)) + static float value_linear_units() { return linear_value_to_mm(value_float()); } static float value_axis_units(const AxisEnum axis) { return axis_value_to_mm(axis, value_float()); } static float value_per_axis_units(const AxisEnum axis) { return per_axis_value(axis, value_float()); } diff --git a/Marlin/src/gcode/probe/G38.cpp b/Marlin/src/gcode/probe/G38.cpp index 6906805fca..ed24ce3258 100644 --- a/Marlin/src/gcode/probe/G38.cpp +++ b/Marlin/src/gcode/probe/G38.cpp @@ -49,7 +49,7 @@ inline bool G38_run_probe() { #if MULTIPLE_PROBING > 1 // Get direction of move and retract xyz_float_t retract_mm; - LOOP_LINEAR_AXES(i) { + LOOP_NUM_AXES(i) { const float dist = destination[i] - current_position[i]; retract_mm[i] = ABS(dist) < G38_MINIMUM_MOVE ? 0 : home_bump_mm((AxisEnum)i) * (dist > 0 ? -1 : 1); } @@ -119,7 +119,7 @@ void GcodeSuite::G38(const int8_t subcode) { ; // If any axis has enough movement, do the move - LOOP_LINEAR_AXES(i) + LOOP_NUM_AXES(i) if (ABS(destination[i] - current_position[i]) >= G38_MINIMUM_MOVE) { if (!parser.seenval('F')) feedrate_mm_s = homing_feedrate((AxisEnum)i); // If G38.2 fails throw an error diff --git a/Marlin/src/gcode/sd/M1001.cpp b/Marlin/src/gcode/sd/M1001.cpp index 87de89a682..197177882c 100644 --- a/Marlin/src/gcode/sd/M1001.cpp +++ b/Marlin/src/gcode/sd/M1001.cpp @@ -108,7 +108,7 @@ void GcodeSuite::M1001() { process_subcommands_now(F(SD_FINISHED_RELEASECOMMAND)); #endif - TERN_(EXTENSIBLE_UI, ExtUI::onPrintFinished()); + TERN_(EXTENSIBLE_UI, ExtUI::onPrintDone()); TERN_(DWIN_LCD_PROUI, DWIN_Print_Finished()); // Re-select the last printed file in the UI diff --git a/Marlin/src/gcode/temp/M104_M109.cpp b/Marlin/src/gcode/temp/M104_M109.cpp index baaac02100..331ceeb61d 100644 --- a/Marlin/src/gcode/temp/M104_M109.cpp +++ b/Marlin/src/gcode/temp/M104_M109.cpp @@ -126,7 +126,7 @@ void GcodeSuite::M104_M109(const bool isM109) { #endif if (thermalManager.isHeatingHotend(target_extruder) || !no_wait_for_cooling) - thermalManager.set_heating_message(target_extruder); + thermalManager.set_heating_message(target_extruder, !isM109 && got_temp); } TERN_(AUTOTEMP, planner.autotemp_M104_M109()); diff --git a/Marlin/src/gcode/temp/M140_M190.cpp b/Marlin/src/gcode/temp/M140_M190.cpp index 7532defccd..c5e3c00029 100644 --- a/Marlin/src/gcode/temp/M140_M190.cpp +++ b/Marlin/src/gcode/temp/M140_M190.cpp @@ -82,14 +82,18 @@ void GcodeSuite::M140_M190(const bool isM190) { if (!got_temp) return; thermalManager.setTargetBed(temp); + thermalManager.isHeatingBed() ? LCD_MESSAGE(MSG_BED_HEATING) : LCD_MESSAGE(MSG_BED_COOLING); - ui.set_status(thermalManager.isHeatingBed() ? GET_TEXT_F(MSG_BED_HEATING) : GET_TEXT_F(MSG_BED_COOLING)); - - // with PRINTJOB_TIMER_AUTOSTART, M190 can start the timer, and M140 can stop it + // With PRINTJOB_TIMER_AUTOSTART, M190 can start the timer, and M140 can stop it TERN_(PRINTJOB_TIMER_AUTOSTART, thermalManager.auto_job_check_timer(isM190, !isM190)); if (isM190) thermalManager.wait_for_bed(no_wait_for_cooling); + else + ui.set_status_reset_fn([]{ + const celsius_t c = thermalManager.degTargetBed(); + return c < 30 || thermalManager.degBedNear(c); + }); } #endif // HAS_HEATED_BED diff --git a/Marlin/src/gcode/temp/M192.cpp b/Marlin/src/gcode/temp/M192.cpp index a96e2d34a4..04b36a548c 100644 --- a/Marlin/src/gcode/temp/M192.cpp +++ b/Marlin/src/gcode/temp/M192.cpp @@ -49,7 +49,7 @@ void GcodeSuite::M192() { } const celsius_t target_temp = parser.value_celsius(); - ui.set_status(thermalManager.isProbeBelowTemp(target_temp) ? GET_TEXT_F(MSG_PROBE_HEATING) : GET_TEXT_F(MSG_PROBE_COOLING)); + thermalManager.isProbeBelowTemp(target_temp) ? LCD_MESSAGE(MSG_PROBE_HEATING) : LCD_MESSAGE(MSG_PROBE_COOLING); thermalManager.wait_for_probe(target_temp, no_wait_for_cooling); } diff --git a/Marlin/src/gcode/temp/M306.cpp b/Marlin/src/gcode/temp/M306.cpp new file mode 100644 index 0000000000..9e1a8dd8ef --- /dev/null +++ b/Marlin/src/gcode/temp/M306.cpp @@ -0,0 +1,86 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 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(MPCTEMP) + +#include "../gcode.h" +#include "../../module/temperature.h" + +/** + * M306: MPC settings and autotune + * + * T Autotune the active extruder. + * + * A Ambient heat transfer coefficient (no fan). + * C Block heat capacity. + * E Extruder number to set. (Default: E0) + * F Ambient heat transfer coefficient (fan on full). + * P Heater power. + * R Sensor responsiveness (= transfer coefficient / heat capcity). + */ + +void GcodeSuite::M306() { + if (parser.seen_test('T')) { thermalManager.MPC_autotune(); return; } + + if (parser.seen("ACFPR")) { + const heater_id_t hid = (heater_id_t)parser.intval('E', 0); + MPC_t &constants = thermalManager.temp_hotend[hid].constants; + if (parser.seenval('P')) constants.heater_power = parser.value_float(); + if (parser.seenval('C')) constants.block_heat_capacity = parser.value_float(); + if (parser.seenval('R')) constants.sensor_responsiveness = parser.value_float(); + if (parser.seenval('A')) constants.ambient_xfer_coeff_fan0 = parser.value_float(); + #if ENABLED(MPC_INCLUDE_FAN) + if (parser.seenval('F')) constants.fan255_adjustment = parser.value_float() - constants.ambient_xfer_coeff_fan0; + #endif + return; + } + + HOTEND_LOOP() { + SERIAL_ECHOLNPGM("MPC constants for hotend ", e); + MPC_t& constants = thermalManager.temp_hotend[e].constants; + SERIAL_ECHOLNPGM("Heater power: ", constants.heater_power); + SERIAL_ECHOLNPGM("Heatblock heat capacity: ", constants.block_heat_capacity); + SERIAL_ECHOLNPAIR_F("Sensor responsivness: ", constants.sensor_responsiveness, 4); + SERIAL_ECHOLNPAIR_F("Ambient heat transfer coeff. (no fan): ", constants.ambient_xfer_coeff_fan0, 4); + #if ENABLED(MPC_INCLUDE_FAN) + SERIAL_ECHOLNPAIR_F("Ambient heat transfer coeff. (full fan): ", constants.ambient_xfer_coeff_fan0 + constants.fan255_adjustment, 4); + #endif + } +} + +void GcodeSuite::M306_report(const bool forReplay/*=true*/) { + report_heading(forReplay, F("Model predictive control")); + HOTEND_LOOP() { + report_echo_start(forReplay); + MPC_t& constants = thermalManager.temp_hotend[e].constants; + SERIAL_ECHOPGM(" M306 E", e); + SERIAL_ECHOPAIR_F(" P", constants.heater_power, 2); + SERIAL_ECHOPAIR_F(" C", constants.block_heat_capacity, 2); + SERIAL_ECHOPAIR_F(" R", constants.sensor_responsiveness, 4); + SERIAL_ECHOPAIR_F(" A", constants.ambient_xfer_coeff_fan0, 4); + SERIAL_ECHOLNPAIR_F(" F", constants.ambient_xfer_coeff_fan0 + constants.fan255_adjustment, 4); + } +} + +#endif // MPCTEMP diff --git a/Marlin/src/inc/Conditionals_LCD.h b/Marlin/src/inc/Conditionals_LCD.h index e6e92068be..329e585023 100644 --- a/Marlin/src/inc/Conditionals_LCD.h +++ b/Marlin/src/inc/Conditionals_LCD.h @@ -677,22 +677,31 @@ #endif /** - * Number of Linear Axes (e.g., XYZ) + * Number of Linear Axes (e.g., XYZIJKUVW) * All the logical axes except for the tool (E) axis */ -#ifndef LINEAR_AXES - #define LINEAR_AXES XYZ +#ifndef NUM_AXES + #define NUM_AXES XYZ #endif -#if LINEAR_AXES >= XY +#if NUM_AXES >= XY #define HAS_Y_AXIS 1 - #if LINEAR_AXES >= XYZ + #if NUM_AXES >= XYZ #define HAS_Z_AXIS 1 - #if LINEAR_AXES >= 4 + #if NUM_AXES >= 4 #define HAS_I_AXIS 1 - #if LINEAR_AXES >= 5 + #if NUM_AXES >= 5 #define HAS_J_AXIS 1 - #if LINEAR_AXES >= 6 + #if NUM_AXES >= 6 #define HAS_K_AXIS 1 + #if NUM_AXES >= 7 + #define HAS_U_AXIS 1 + #if NUM_AXES >= 8 + #define HAS_V_AXIS 1 + #if NUM_AXES >= 9 + #define HAS_W_AXIS 1 + #endif + #endif + #endif #endif #endif #endif @@ -700,14 +709,58 @@ #endif /** - * Number of Logical Axes (e.g., XYZE) - * All the logical axes that can be commanded directly by G-code. + * Number of Primary Linear Axes (e.g., XYZ) + * X, XY, or XYZ axes. Excluding duplicate axes (X2, Y2. Z2. Z3, Z4) + */ +#if HAS_I_AXIS + #define PRIMARY_LINEAR_AXES 3 +#else + #define PRIMARY_LINEAR_AXES NUM_AXES +#endif + +/** + * Number of Secondary Axes (e.g., IJKUVW) + * All linear/rotational axes between XYZ and E. + */ +#define SECONDARY_AXES SUB3(NUM_AXES) + +/** + * Number of Rotational Axes (e.g., IJK) + * All axes for which AXIS*_ROTATES is defined. + * For these axes, positions are specified in angular degrees. + */ +#if ENABLED(AXIS9_ROTATES) + #define ROTATIONAL_AXES 6 +#elif ENABLED(AXIS8_ROTATES) + #define ROTATIONAL_AXES 5 +#elif ENABLED(AXIS7_ROTATES) + #define ROTATIONAL_AXES 4 +#elif ENABLED(AXIS6_ROTATES) + #define ROTATIONAL_AXES 3 +#elif ENABLED(AXIS5_ROTATES) + #define ROTATIONAL_AXES 2 +#elif ENABLED(AXIS4_ROTATES) + #define ROTATIONAL_AXES 1 +#else + #define ROTATIONAL_AXES 0 +#endif + +/** + * Number of Secondary Linear Axes (e.g., UVW) + * All secondary axes for which AXIS*_ROTATES is not defined. + * Excluding primary axes and excluding duplicate axes (X2, Y2, Z2, Z3, Z4) + */ +#define SECONDARY_LINEAR_AXES (NUM_AXES - PRIMARY_LINEAR_AXES - ROTATIONAL_AXES) + +/** + * Number of Logical Axes (e.g., XYZIJKUVWE) + * All logical axes that can be commanded directly by G-code. * Delta maps stepper-specific values to ABC steppers. */ #if HAS_EXTRUDERS - #define LOGICAL_AXES INCREMENT(LINEAR_AXES) + #define LOGICAL_AXES INCREMENT(NUM_AXES) #else - #define LOGICAL_AXES LINEAR_AXES + #define LOGICAL_AXES NUM_AXES #endif /** @@ -725,7 +778,7 @@ * distinguished. */ #if ENABLED(DISTINCT_E_FACTORS) && E_STEPPERS > 1 - #define DISTINCT_AXES (LINEAR_AXES + E_STEPPERS) + #define DISTINCT_AXES (NUM_AXES + E_STEPPERS) #define DISTINCT_E E_STEPPERS #define E_INDEX_N(E) (E) #else @@ -749,6 +802,7 @@ #endif // Helper macros for extruder and hotend arrays +#define EXTRUDER_LOOP() for (int8_t e = 0; e < EXTRUDERS; e++) #define HOTEND_LOOP() for (int8_t e = 0; e < HOTENDS; e++) #define ARRAY_BY_EXTRUDERS(V...) ARRAY_N(EXTRUDERS, V) #define ARRAY_BY_EXTRUDERS1(v1) ARRAY_N_1(EXTRUDERS, v1) @@ -938,6 +992,21 @@ #elif K_HOME_DIR < 0 #define K_HOME_TO_MIN 1 #endif +#if U_HOME_DIR > 0 + #define U_HOME_TO_MAX 1 +#elif U_HOME_DIR < 0 + #define U_HOME_TO_MIN 1 +#endif +#if V_HOME_DIR > 0 + #define V_HOME_TO_MAX 1 +#elif V_HOME_DIR < 0 + #define V_HOME_TO_MIN 1 +#endif +#if W_HOME_DIR > 0 + #define W_HOME_TO_MAX 1 +#elif W_HOME_DIR < 0 + #define W_HOME_TO_MIN 1 +#endif /** * Conditionals based on the type of Bed Probe @@ -1211,6 +1280,15 @@ #if HAS_K_AXIS && !defined(INVERT_K_DIR) #define INVERT_K_DIR false #endif +#if HAS_U_AXIS && !defined(INVERT_U_DIR) + #define INVERT_U_DIR false +#endif +#if HAS_V_AXIS && !defined(INVERT_V_DIR) + #define INVERT_V_DIR false +#endif +#if HAS_W_AXIS && !defined(INVERT_W_DIR) + #define INVERT_W_DIR false +#endif #if HAS_EXTRUDERS && !defined(INVERT_E_DIR) #define INVERT_E_DIR false #endif diff --git a/Marlin/src/inc/Conditionals_adv.h b/Marlin/src/inc/Conditionals_adv.h index 0c87c94a99..71e74404da 100644 --- a/Marlin/src/inc/Conditionals_adv.h +++ b/Marlin/src/inc/Conditionals_adv.h @@ -544,16 +544,6 @@ #define HAS_SERVICE_INTERVALS 1 #endif -#if ENABLED(FILAMENT_RUNOUT_SENSOR) - #define HAS_FILAMENT_SENSOR 1 - #if NUM_RUNOUT_SENSORS > 1 - #define MULTI_FILAMENT_SENSOR 1 - #endif - #if ENABLED(MIXING_EXTRUDER) - #define WATCH_ALL_RUNOUT_SENSORS - #endif -#endif - // Probe Temperature Compensation #if !TEMP_SENSOR_PROBE #undef PTC_PROBE @@ -585,6 +575,10 @@ #define HAS_PRINT_PROGRESS 1 #endif +#if STATUS_MESSAGE_TIMEOUT_SEC > 0 + #define HAS_STATUS_MESSAGE_TIMEOUT 1 +#endif + #if ENABLED(SDSUPPORT) && SD_PROCEDURE_DEPTH #define HAS_MEDIA_SUBCALLS 1 #endif @@ -908,30 +902,45 @@ #endif // Remove unused STEALTHCHOP flags -#if LINEAR_AXES < 6 - #undef STEALTHCHOP_K - #undef CALIBRATION_MEASURE_KMIN - #undef CALIBRATION_MEASURE_KMAX - #if LINEAR_AXES < 5 - #undef STEALTHCHOP_J - #undef CALIBRATION_MEASURE_JMIN - #undef CALIBRATION_MEASURE_JMAX - #if LINEAR_AXES < 4 - #undef STEALTHCHOP_I - #undef CALIBRATION_MEASURE_IMIN - #undef CALIBRATION_MEASURE_IMAX - #if LINEAR_AXES < 3 - #undef Z_IDLE_HEIGHT - #undef STEALTHCHOP_Z - #undef Z_PROBE_SLED - #undef Z_SAFE_HOMING - #undef HOME_Z_FIRST - #undef HOMING_Z_WITH_PROBE - #undef ENABLE_LEVELING_FADE_HEIGHT - #undef NUM_Z_STEPPER_DRIVERS - #undef CNC_WORKSPACE_PLANES - #if LINEAR_AXES < 2 - #undef STEALTHCHOP_Y +#if NUM_AXES < 9 + #undef STEALTHCHOP_W + #undef CALIBRATION_MEASURE_WMIN + #undef CALIBRATION_MEASURE_WMAX + #if NUM_AXES < 8 + #undef STEALTHCHOP_V + #undef CALIBRATION_MEASURE_VMIN + #undef CALIBRATION_MEASURE_VMAX + #if NUM_AXES < 7 + #undef STEALTHCHOP_U + #undef CALIBRATION_MEASURE_UMIN + #undef CALIBRATION_MEASURE_UMAX + #if NUM_AXES < 6 + #undef STEALTHCHOP_K + #undef CALIBRATION_MEASURE_KMIN + #undef CALIBRATION_MEASURE_KMAX + #if NUM_AXES < 5 + #undef STEALTHCHOP_J + #undef CALIBRATION_MEASURE_JMIN + #undef CALIBRATION_MEASURE_JMAX + #if NUM_AXES < 4 + #undef STEALTHCHOP_I + #undef CALIBRATION_MEASURE_IMIN + #undef CALIBRATION_MEASURE_IMAX + #if NUM_AXES < 3 + #undef Z_IDLE_HEIGHT + #undef STEALTHCHOP_Z + #undef Z_PROBE_SLED + #undef Z_SAFE_HOMING + #undef HOME_Z_FIRST + #undef HOMING_Z_WITH_PROBE + #undef ENABLE_LEVELING_FADE_HEIGHT + #undef NUM_Z_STEPPER_DRIVERS + #undef CNC_WORKSPACE_PLANES + #if NUM_AXES < 2 + #undef STEALTHCHOP_Y + #endif + #endif + #endif #endif #endif #endif diff --git a/Marlin/src/inc/Conditionals_post.h b/Marlin/src/inc/Conditionals_post.h index 547ca36e92..ada2a512b5 100644 --- a/Marlin/src/inc/Conditionals_post.h +++ b/Marlin/src/inc/Conditionals_post.h @@ -87,6 +87,19 @@ #if HAS_K_AXIS && !defined(AXIS6_NAME) #define AXIS6_NAME 'C' #endif +#if HAS_U_AXIS && !defined(AXIS7_NAME) + #define AXIS7_NAME 'U' +#endif +#if HAS_V_AXIS && !defined(AXIS8_NAME) + #define AXIS8_NAME 'V' +#endif +#if HAS_W_AXIS && !defined(AXIS9_NAME) + #define AXIS9_NAME 'W' +#endif + +#if ANY(AXIS4_ROTATES, AXIS5_ROTATES, AXIS6_ROTATES, AXIS7_ROTATES, AXIS8_ROTATES, AXIS9_ROTATES) + #define HAS_ROTATIONAL_AXES 1 +#endif #define X_MAX_LENGTH (X_MAX_POS - (X_MIN_POS)) #if HAS_Y_AXIS @@ -106,6 +119,15 @@ #if HAS_K_AXIS #define K_MAX_LENGTH (K_MAX_POS - (K_MIN_POS)) #endif +#if HAS_U_AXIS + #define U_MAX_LENGTH (U_MAX_POS - (U_MIN_POS)) +#endif +#if HAS_V_AXIS + #define V_MAX_LENGTH (V_MAX_POS - (V_MIN_POS)) +#endif +#if HAS_W_AXIS + #define W_MAX_LENGTH (W_MAX_POS - (W_MIN_POS)) +#endif // Defined only if the sanity-check is bypassed #ifndef X_BED_SIZE @@ -123,6 +145,15 @@ #if HAS_K_AXIS && !defined(K_BED_SIZE) #define K_BED_SIZE K_MAX_LENGTH #endif +#if HAS_U_AXIS && !defined(U_BED_SIZE) + #define U_BED_SIZE U_MAX_LENGTH +#endif +#if HAS_V_AXIS && !defined(V_BED_SIZE) + #define V_BED_SIZE V_MAX_LENGTH +#endif +#if HAS_W_AXIS && !defined(W_BED_SIZE) + #define W_BED_SIZE W_MAX_LENGTH +#endif // Require 0,0 bed center for Delta and SCARA #if IS_KINEMATIC @@ -143,6 +174,15 @@ #if HAS_K_AXIS #define _K_HALF_KMAX ((K_BED_SIZE) / 2) #endif +#if HAS_U_AXIS + #define _U_HALF_UMAX ((U_BED_SIZE) / 2) +#endif +#if HAS_V_AXIS + #define _V_HALF_VMAX ((V_BED_SIZE) / 2) +#endif +#if HAS_W_AXIS + #define _W_HALF_WMAX ((W_BED_SIZE) / 2) +#endif #define X_CENTER TERN(BED_CENTER_AT_0_0, 0, _X_HALF_BED) #if HAS_Y_AXIS @@ -158,6 +198,15 @@ #if HAS_K_AXIS #define K_CENTER TERN(BED_CENTER_AT_0_0, 0, _K_HALF_BED) #endif +#if HAS_U_AXIS + #define U_CENTER TERN(BED_CENTER_AT_0_0, 0, _U_HALF_BED) +#endif +#if HAS_V_AXIS + #define V_CENTER TERN(BED_CENTER_AT_0_0, 0, _V_HALF_BED) +#endif +#if HAS_W_AXIS + #define W_CENTER TERN(BED_CENTER_AT_0_0, 0, _W_HALF_BED) +#endif // Get the linear boundaries of the bed #define X_MIN_BED (X_CENTER - _X_HALF_BED) @@ -178,6 +227,18 @@ #define K_MINIM (K_CENTER - _K_HALF_BED_SIZE) #define K_MAXIM (K_MINIM + K_BED_SIZE) #endif +#if HAS_U_AXIS + #define U_MINIM (U_CENTER - _U_HALF_BED_SIZE) + #define U_MAXIM (U_MINIM + U_BED_SIZE) +#endif +#if HAS_V_AXIS + #define V_MINIM (V_CENTER - _V_HALF_BED_SIZE) + #define V_MAXIM (V_MINIM + V_BED_SIZE) +#endif +#if HAS_W_AXIS + #define W_MINIM (W_CENTER - _W_HALF_BED_SIZE) + #define W_MAXIM (W_MINIM + W_BED_SIZE) +#endif /** * Dual X Carriage @@ -274,6 +335,27 @@ #define K_HOME_POS TERN(K_HOME_TO_MIN, K_MIN_POS, K_MAX_POS) #endif #endif +#if HAS_U_AXIS + #ifdef MANUAL_U_HOME_POS + #define U_HOME_POS MANUAL_U_HOME_POS + #else + #define U_HOME_POS (U_HOME_DIR < 0 ? U_MIN_POS : U_MAX_POS) + #endif +#endif +#if HAS_V_AXIS + #ifdef MANUAL_V_HOME_POS + #define V_HOME_POS MANUAL_V_HOME_POS + #else + #define V_HOME_POS (V_HOME_DIR < 0 ? V_MIN_POS : V_MAX_POS) + #endif +#endif +#if HAS_W_AXIS + #ifdef MANUAL_W_HOME_POS + #define W_HOME_POS MANUAL_W_HOME_POS + #else + #define W_HOME_POS (W_HOME_DIR < 0 ? W_MIN_POS : W_MAX_POS) + #endif +#endif /** * If DELTA_HEIGHT isn't defined use the old setting @@ -459,7 +541,7 @@ #endif -#if PIN_EXISTS(SD_DETECT) && NONE(HAS_GRAPHICAL_TFT, LCD_USE_DMA_FSMC, HAS_FSMC_GRAPHICAL_TFT, HAS_SPI_GRAPHICAL_TFT, IS_DWIN_MARLINUI, EXTENSIBLE_UI) +#if PIN_EXISTS(SD_DETECT) && NONE(HAS_GRAPHICAL_TFT, LCD_USE_DMA_FSMC, HAS_FSMC_GRAPHICAL_TFT, HAS_SPI_GRAPHICAL_TFT, IS_DWIN_MARLINUI, EXTENSIBLE_UI, HAS_DWIN_E3V2) #define REINIT_NOISY_LCD 1 // Have the LCD re-init on SD insertion #endif @@ -1440,6 +1522,15 @@ #if ENABLED(USE_KMAX_PLUG) #define ENDSTOPPULLUP_KMAX #endif + #if ENABLED(USE_UMAX_PLUG) + #define ENDSTOPPULLUP_UMAX + #endif + #if ENABLED(USE_VMAX_PLUG) + #define ENDSTOPPULLUP_VMAX + #endif + #if ENABLED(USE_WMAX_PLUG) + #define ENDSTOPPULLUP_WMAX + #endif #if ENABLED(USE_XMIN_PLUG) #define ENDSTOPPULLUP_XMIN #endif @@ -1458,6 +1549,15 @@ #if ENABLED(USE_KMIN_PLUG) #define ENDSTOPPULLUP_KMIN #endif + #if ENABLED(USE_UMIN_PLUG) + #define ENDSTOPPULLUP_UMIN + #endif + #if ENABLED(USE_VMIN_PLUG) + #define ENDSTOPPULLUP_VMIN + #endif + #if ENABLED(USE_WMIN_PLUG) + #define ENDSTOPPULLUP_WMIN + #endif #endif /** @@ -1680,6 +1780,66 @@ #undef DISABLE_INACTIVE_K #endif +#if HAS_U_AXIS + #if PIN_EXISTS(U_ENABLE) || AXIS_IS_L64XX(U) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(U)) + #define HAS_U_ENABLE 1 + #endif + #if PIN_EXISTS(U_DIR) + #define HAS_U_DIR 1 + #endif + #if PIN_EXISTS(U_STEP) + #define HAS_U_STEP 1 + #endif + #if PIN_EXISTS(U_MS1) + #define HAS_U_MS_PINS 1 + #endif + #if !defined(DISABLE_INACTIVE_U) && ENABLED(DISABLE_U) + #define DISABLE_INACTIVE_U 1 + #endif +#else + #undef DISABLE_INACTIVE_U +#endif + +#if HAS_V_AXIS + #if PIN_EXISTS(V_ENABLE) || AXIS_IS_L64XX(V) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(V)) + #define HAS_V_ENABLE 1 + #endif + #if PIN_EXISTS(V_DIR) + #define HAS_V_DIR 1 + #endif + #if PIN_EXISTS(V_STEP) + #define HAS_V_STEP 1 + #endif + #if PIN_EXISTS(V_MS1) + #define HAS_V_MS_PINS 1 + #endif + #if !defined(DISABLE_INACTIVE_V) && ENABLED(DISABLE_V) + #define DISABLE_INACTIVE_V 1 + #endif +#else + #undef DISABLE_INACTIVE_V +#endif + +#if HAS_W_AXIS + #if PIN_EXISTS(W_ENABLE) || AXIS_IS_L64XX(W) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(W)) + #define HAS_W_ENABLE 1 + #endif + #if PIN_EXISTS(W_DIR) + #define HAS_W_DIR 1 + #endif + #if PIN_EXISTS(W_STEP) + #define HAS_W_STEP 1 + #endif + #if PIN_EXISTS(W_MS1) + #define HAS_W_MS_PINS 1 + #endif + #if !defined(DISABLE_INACTIVE_W) && ENABLED(DISABLE_W) + #define DISABLE_INACTIVE_W 1 + #endif +#else + #undef DISABLE_INACTIVE_W +#endif + // Extruder steppers and solenoids #if HAS_EXTRUDERS @@ -1848,7 +2008,7 @@ // #if HAS_TRINAMIC_CONFIG - #if ANY(STEALTHCHOP_E, STEALTHCHOP_XY, STEALTHCHOP_Z, STEALTHCHOP_I, STEALTHCHOP_J, STEALTHCHOP_K) + #if ANY(STEALTHCHOP_E, STEALTHCHOP_XY, STEALTHCHOP_Z, STEALTHCHOP_I, STEALTHCHOP_J, STEALTHCHOP_K, STEALTHCHOP_U, STEALTHCHOP_V, STEALTHCHOP_W) #define STEALTHCHOP_ENABLED 1 #endif #if EITHER(SENSORLESS_HOMING, SENSORLESS_PROBING) @@ -1937,6 +2097,15 @@ #define Y2_SLAVE_ADDRESS 0 #endif #endif + #if HAS_U_AXIS + #define U_SPI_SENSORLESS U_SENSORLESS + #endif + #if HAS_V_AXIS + #define V_SPI_SENSORLESS V_SENSORLESS + #endif + #if HAS_W_AXIS + #define W_SPI_SENSORLESS W_SENSORLESS + #endif #endif #if AXIS_IS_TMC(Z) @@ -2074,6 +2243,69 @@ #endif #endif + #if AXIS_IS_TMC(U) + #if defined(U_STALL_SENSITIVITY) && AXIS_HAS_STALLGUARD(U) + #define U_SENSORLESS 1 + #endif + #if AXIS_HAS_STEALTHCHOP(U) + #define U_HAS_STEALTHCHOP 1 + #endif + #if ENABLED(SPI_ENDSTOPS) + #define U_SPI_SENSORLESS U_SENSORLESS + #endif + #ifndef U_INTERPOLATE + #define U_INTERPOLATE INTERPOLATE + #endif + #ifndef U_HOLD_MULTIPLIER + #define U_HOLD_MULTIPLIER HOLD_MULTIPLIER + #endif + #ifndef U_SLAVE_ADDRESS + #define U_SLAVE_ADDRESS 0 + #endif + #endif + + #if AXIS_IS_TMC(V) + #if defined(V_STALL_SENSITIVITY) && AXIS_HAS_STALLGUARD(V) + #define V_SENSORLESS 1 + #endif + #if AXIS_HAS_STEALTHCHOP(V) + #define V_HAS_STEALTHCHOP 1 + #endif + #if ENABLED(SPI_ENDSTOPS) + #define V_SPI_SENSORLESS V_SENSORLESS + #endif + #ifndef V_INTERPOLATE + #define V_INTERPOLATE INTERPOLATE + #endif + #ifndef V_HOLD_MULTIPLIER + #define V_HOLD_MULTIPLIER HOLD_MULTIPLIER + #endif + #ifndef V_SLAVE_ADDRESS + #define V_SLAVE_ADDRESS 0 + #endif + #endif + + #if AXIS_IS_TMC(W) + #if defined(W_STALL_SENSITIVITY) && AXIS_HAS_STALLGUARD(W) + #define W_SENSORLESS 1 + #endif + #if AXIS_HAS_STEALTHCHOP(W) + #define W_HAS_STEALTHCHOP 1 + #endif + #if ENABLED(SPI_ENDSTOPS) + #define W_SPI_SENSORLESS W_SENSORLESS + #endif + #ifndef W_INTERPOLATE + #define W_INTERPOLATE INTERPOLATE + #endif + #ifndef W_HOLD_MULTIPLIER + #define W_HOLD_MULTIPLIER HOLD_MULTIPLIER + #endif + #ifndef W_SLAVE_ADDRESS + #define W_SLAVE_ADDRESS 0 + #endif + #endif + #if AXIS_IS_TMC(E0) #if AXIS_HAS_STEALTHCHOP(E0) #define E0_HAS_STEALTHCHOP 1 @@ -2215,6 +2447,7 @@ #define ANY_SERIAL_IS(N) ( CONF_SERIAL_IS(N) \ || TMC_UART_IS(X, N) || TMC_UART_IS(Y , N) || TMC_UART_IS(Z , N) \ || TMC_UART_IS(I, N) || TMC_UART_IS(J , N) || TMC_UART_IS(K , N) \ + || TMC_UART_IS(U, N) || TMC_UART_IS(V , N) || TMC_UART_IS(W , N) \ || TMC_UART_IS(X2, N) || TMC_UART_IS(Y2, N) || TMC_UART_IS(Z2, N) || TMC_UART_IS(Z3, N) || TMC_UART_IS(Z4, N) \ || TMC_UART_IS(E0, N) || TMC_UART_IS(E1, N) || TMC_UART_IS(E2, N) || TMC_UART_IS(E3, N) || TMC_UART_IS(E4, N) ) @@ -2349,6 +2582,24 @@ #if _HAS_STOP(K,MAX) #define HAS_K_MAX 1 #endif +#if _HAS_STOP(U,MIN) + #define HAS_U_MIN 1 +#endif +#if _HAS_STOP(U,MAX) + #define HAS_U_MAX 1 +#endif +#if _HAS_STOP(V,MIN) + #define HAS_V_MIN 1 +#endif +#if _HAS_STOP(V,MAX) + #define HAS_V_MAX 1 +#endif +#if _HAS_STOP(W,MIN) + #define HAS_W_MIN 1 +#endif +#if _HAS_STOP(W,MAX) + #define HAS_W_MAX 1 +#endif #if PIN_EXISTS(X2_MIN) #define HAS_X2_MIN 1 #endif @@ -2824,17 +3075,9 @@ #endif // User Interface -#if ENABLED(FREEZE_FEATURE) - #if !PIN_EXISTS(FREEZE) && PIN_EXISTS(KILL) - #define FREEZE_PIN KILL_PIN - #endif - #if PIN_EXISTS(FREEZE) - #define HAS_FREEZE_PIN 1 - #endif -#else - #undef FREEZE_PIN -#endif -#if PIN_EXISTS(KILL) && TERN1(FREEZE_FEATURE, KILL_PIN != FREEZE_PIN) +#if ENABLED(FREEZE_FEATURE) && !PIN_EXISTS(FREEZE) && PIN_EXISTS(KILL) + #define FREEZE_PIN KILL_PIN +#elif PIN_EXISTS(KILL) && TERN1(FREEZE_FEATURE, KILL_PIN != FREEZE_PIN) #define HAS_KILL 1 #endif #if PIN_EXISTS(HOME) @@ -2857,7 +3100,7 @@ #if HAS_EXTRUDERS && PIN_EXISTS(MOTOR_CURRENT_PWM_E) #define HAS_MOTOR_CURRENT_PWM_E 1 #endif -#if HAS_MOTOR_CURRENT_PWM_E || ANY_PIN(MOTOR_CURRENT_PWM_X, MOTOR_CURRENT_PWM_Y, MOTOR_CURRENT_PWM_XY, MOTOR_CURRENT_PWM_Z, MOTOR_CURRENT_PWM_I, MOTOR_CURRENT_PWM_J, MOTOR_CURRENT_PWM_K) +#if HAS_MOTOR_CURRENT_PWM_E || ANY_PIN(MOTOR_CURRENT_PWM_X, MOTOR_CURRENT_PWM_Y, MOTOR_CURRENT_PWM_XY, MOTOR_CURRENT_PWM_Z, MOTOR_CURRENT_PWM_I, MOTOR_CURRENT_PWM_J, MOTOR_CURRENT_PWM_K, MOTOR_CURRENT_PWM_U, MOTOR_CURRENT_PWM_V, MOTOR_CURRENT_PWM_W) #define HAS_MOTOR_CURRENT_PWM 1 #endif @@ -2867,7 +3110,7 @@ #if ANY(HAS_E0_MS_PINS, HAS_E1_MS_PINS, HAS_E2_MS_PINS, HAS_E3_MS_PINS, HAS_E4_MS_PINS, HAS_E5_MS_PINS, HAS_E6_MS_PINS, HAS_E7_MS_PINS) #define HAS_SOME_E_MS_PINS 1 #endif -#if ANY(HAS_X_MS_PINS, HAS_X2_MS_PINS, HAS_Y_MS_PINS, HAS_Y2_MS_PINS, HAS_SOME_Z_MS_PINS, HAS_I_MS_PINS, HAS_J_MS_PINS, HAS_K_MS_PINS, HAS_SOME_E_MS_PINS) +#if ANY(HAS_X_MS_PINS, HAS_X2_MS_PINS, HAS_Y_MS_PINS, HAS_Y2_MS_PINS, HAS_SOME_Z_MS_PINS, HAS_I_MS_PINS, HAS_J_MS_PINS, HAS_K_MS_PINS, HAS_U_MS_PINS, HAS_V_MS_PINS, HAS_W_MS_PINS, HAS_SOME_E_MS_PINS) #define HAS_MICROSTEPS 1 #endif @@ -3507,3 +3750,14 @@ #if PIN_EXISTS(SAFE_POWER) && DISABLED(DISABLE_DRIVER_SAFE_POWER_PROTECT) #define HAS_DRIVER_SAFE_POWER_PROTECT 1 #endif + +#if ANY(ENDSTOPPULLDOWNS, ENDSTOPPULLDOWN_ZMIN_PROBE, \ + ENDSTOPPULLDOWN_XMIN, ENDSTOPPULLDOWN_YMIN, ENDSTOPPULLDOWN_ZMIN, \ + ENDSTOPPULLDOWN_IMIN, ENDSTOPPULLDOWN_JMIN, ENDSTOPPULLDOWN_KMIN, \ + ENDSTOPPULLDOWN_XMAX, ENDSTOPPULLDOWN_YMAX, ENDSTOPPULLDOWN_ZMAX, \ + ENDSTOPPULLDOWN_IMAX, ENDSTOPPULLDOWN_JMAX, ENDSTOPPULLDOWN_KMAX, \ + POWER_LOSS_PULLDOWN, CALIBRATION_PIN_PULLDOWN, FIL_RUNOUT_PULLDOWN, \ + FIL_RUNOUT1_PULLDOWN, FIL_RUNOUT2_PULLDOWN, FIL_RUNOUT3_PULLDOWN, FIL_RUNOUT4_PULLDOWN, \ + FIL_RUNOUT5_PULLDOWN, FIL_RUNOUT6_PULLDOWN, FIL_RUNOUT7_PULLDOWN, FIL_RUNOUT8_PULLDOWN) + #define USING_PULLDOWNS 1 +#endif diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index 12f5770ab0..3b1a3363e4 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -35,8 +35,8 @@ #endif // Strings for sanity check messages -#define _LINEAR_AXES_STR LINEAR_AXIS_GANG("X ", "Y ", "Z ", "I ", "J ", "K ") -#define _LOGICAL_AXES_STR LOGICAL_AXIS_GANG("E ", "X ", "Y ", "Z ", "I ", "J ", "K ") +#define _NUM_AXES_STR NUM_AXIS_GANG("X ", "Y ", "Z ", "I ", "J ", "K ", "U ", "V ", "W ") +#define _LOGICAL_AXES_STR LOGICAL_AXIS_GANG("E ", "X ", "Y ", "Z ", "I ", "J ", "K ", "U ", "V ", "W ") // Make sure macros aren't borked #define TEST1 @@ -617,6 +617,8 @@ #error "Z_STEPPER_ALIGN_KNOWN_STEPPER_POSITIONS is now just Z_STEPPER_ALIGN_STEPPER_XY." #elif defined(DWIN_CREALITY_LCD_ENHANCED) #error "DWIN_CREALITY_LCD_ENHANCED is now DWIN_LCD_PROUI." +#elif defined(LINEAR_AXES) + #error "LINEAR_AXES is now NUM_AXES (to account for rotational axes)." #endif constexpr float arm[] = AXIS_RELATIVE_MODES; @@ -782,15 +784,6 @@ static_assert(Y_MAX_LENGTH >= Y_BED_SIZE, "Movement bounds (Y_MIN_POS, Y_MAX_POS #endif #endif -#if !defined(TARGET_LPC1768) && ANY( \ - ENDSTOPPULLDOWNS, \ - ENDSTOPPULLDOWN_XMAX, ENDSTOPPULLDOWN_YMAX, \ - ENDSTOPPULLDOWN_ZMAX, ENDSTOPPULLDOWN_XMIN, \ - ENDSTOPPULLDOWN_YMIN, ENDSTOPPULLDOWN_ZMIN \ - ) - #error "PULLDOWN pin mode is not available on the selected board." -#endif - #if BOTH(ENDSTOPPULLUPS, ENDSTOPPULLDOWNS) #error "Enable only one of ENDSTOPPULLUPS or ENDSTOPPULLDOWNS." #elif BOTH(FIL_RUNOUT_PULLUP, FIL_RUNOUT_PULLDOWN) @@ -807,6 +800,12 @@ static_assert(Y_MAX_LENGTH >= Y_BED_SIZE, "Movement bounds (Y_MIN_POS, Y_MAX_POS #error "Enable only one of ENDSTOPPULLUP_J_MAX or ENDSTOPPULLDOWN_J_MAX." #elif BOTH(ENDSTOPPULLUP_KMAX, ENDSTOPPULLDOWN_KMAX) #error "Enable only one of ENDSTOPPULLUP_K_MAX or ENDSTOPPULLDOWN_K_MAX." +#elif BOTH(ENDSTOPPULLUP_UMAX, ENDSTOPPULLDOWN_UMAX) + #error "Enable only one of ENDSTOPPULLUP_U_MAX or ENDSTOPPULLDOWN_U_MAX." +#elif BOTH(ENDSTOPPULLUP_VMAX, ENDSTOPPULLDOWN_VMAX) + #error "Enable only one of ENDSTOPPULLUP_V_MAX or ENDSTOPPULLDOWN_V_MAX." +#elif BOTH(ENDSTOPPULLUP_WMAX, ENDSTOPPULLDOWN_WMAX) + #error "Enable only one of ENDSTOPPULLUP_W_MAX or ENDSTOPPULLDOWN_W_MAX." #elif BOTH(ENDSTOPPULLUP_XMIN, ENDSTOPPULLDOWN_XMIN) #error "Enable only one of ENDSTOPPULLUP_X_MIN or ENDSTOPPULLDOWN_X_MIN." #elif BOTH(ENDSTOPPULLUP_YMIN, ENDSTOPPULLDOWN_YMIN) @@ -819,6 +818,12 @@ static_assert(Y_MAX_LENGTH >= Y_BED_SIZE, "Movement bounds (Y_MIN_POS, Y_MAX_POS #error "Enable only one of ENDSTOPPULLUP_J_MIN or ENDSTOPPULLDOWN_J_MIN." #elif BOTH(ENDSTOPPULLUP_KMIN, ENDSTOPPULLDOWN_KMIN) #error "Enable only one of ENDSTOPPULLUP_K_MIN or ENDSTOPPULLDOWN_K_MIN." +#elif BOTH(ENDSTOPPULLUP_UMIN, ENDSTOPPULLDOWN_UMIN) + #error "Enable only one of ENDSTOPPULLUP_U_MIN or ENDSTOPPULLDOWN_U_MIN." +#elif BOTH(ENDSTOPPULLUP_VMIN, ENDSTOPPULLDOWN_VMIN) + #error "Enable only one of ENDSTOPPULLUP_V_MIN or ENDSTOPPULLDOWN_V_MIN." +#elif BOTH(ENDSTOPPULLUP_WMIN, ENDSTOPPULLDOWN_WMIN) + #error "Enable only one of ENDSTOPPULLUP_W_MIN or ENDSTOPPULLDOWN_W_MIN." #endif /** @@ -862,7 +867,7 @@ static_assert(Y_MAX_LENGTH >= Y_BED_SIZE, "Movement bounds (Y_MIN_POS, Y_MAX_POS /** * Custom Boot and Status screens */ -#if ENABLED(SHOW_CUSTOM_BOOTSCREEN) && NONE(HAS_MARLINUI_U8GLIB, TOUCH_UI_FTDI_EVE) +#if ENABLED(SHOW_CUSTOM_BOOTSCREEN) && NONE(HAS_MARLINUI_U8GLIB, TOUCH_UI_FTDI_EVE, IS_DWIN_MARLINUI) #error "SHOW_CUSTOM_BOOTSCREEN requires Graphical LCD or TOUCH_UI_FTDI_EVE." #elif ENABLED(SHOW_CUSTOM_BOOTSCREEN) && DISABLED(SHOW_BOOTSCREEN) #error "SHOW_CUSTOM_BOOTSCREEN requires SHOW_BOOTSCREEN." @@ -1105,8 +1110,8 @@ static_assert(Y_MAX_LENGTH >= Y_BED_SIZE, "Movement bounds (Y_MIN_POS, Y_MAX_POS /** * Instant Freeze */ -#if ENABLED(FREEZE_FEATURE) && !PIN_EXISTS(FREEZE) - #error "FREEZE_FEATURE requires a FREEZE_PIN to be defined." +#if ENABLED(FREEZE_FEATURE) && !(PIN_EXISTS(FREEZE) && defined(FREEZE_STATE)) + #error "FREEZE_FEATURE requires both FREEZE_PIN and FREEZE_STATE." #endif /** @@ -1207,6 +1212,9 @@ static_assert(Y_MAX_LENGTH >= Y_BED_SIZE, "Movement bounds (Y_MIN_POS, Y_MAX_POS #elif ENABLED(SINGLENOZZLE) #error "SINGLENOZZLE requires 2 or more EXTRUDERS." + #if ENABLED(PID_PARAMS_PER_HOTEND) + #error "PID_PARAMS_PER_HOTEND must be disabled when using any SINGLENOZZLE extruder." + #endif #endif @@ -1218,6 +1226,8 @@ static_assert(Y_MAX_LENGTH >= Y_BED_SIZE, "Movement bounds (Y_MIN_POS, Y_MAX_POS #error "SWITCHING_NOZZLE and DUAL_X_CARRIAGE are incompatible." #elif ENABLED(SINGLENOZZLE) #error "SWITCHING_NOZZLE and SINGLENOZZLE are incompatible." + #elif HAS_PRUSA_MMU2 + #error "SWITCHING_NOZZLE and PRUSA_MMU2(S) are incompatible." #elif EXTRUDERS != 2 #error "SWITCHING_NOZZLE requires exactly 2 EXTRUDERS." #elif NUM_SERVOS < 1 @@ -1454,6 +1464,26 @@ static_assert(Y_MAX_LENGTH >= Y_BED_SIZE, "Movement bounds (Y_MIN_POS, Y_MAX_POS #error "You must set DISPLAY_CHARSET_HD44780 to JAPANESE, WESTERN or CYRILLIC for your LCD controller." #endif +/** + * Extruder temperature control algorithm - There can be only one! + */ +#if BOTH(PIDTEMP, MPCTEMP) + #error "Only enable PIDTEMP or MPCTEMP, but not both." +#endif + +#if ENABLED(MPC_INCLUDE_FAN) + #if FAN_COUNT < 1 + #error "MPC_INCLUDE_FAN requires at least one fan." + #endif + #if FAN_COUNT < HOTENDS + #if COUNT_ENABLED(MPC_FAN_0_ALL_HOTENDS, MPC_FAN_0_ACTIVE_HOTEND) > 1 + #error "Enable either MPC_FAN_0_ALL_HOTENDS or MPC_FAN_0_ACTIVE_HOTEND, not both." + #elif NONE(MPC_FAN_0_ALL_HOTENDS, MPC_FAN_0_ACTIVE_HOTEND) + #error "MPC_INCLUDE_FAN requires MPC_FAN_0_ALL_HOTENDS or MPC_FAN_0_ACTIVE_HOTEND for one fan with multiple hotends." + #endif + #endif +#endif + /** * Bed Heating Options - PID vs Limit Switching */ @@ -1480,16 +1510,18 @@ static_assert(Y_MAX_LENGTH >= Y_BED_SIZE, "Movement bounds (Y_MIN_POS, Y_MAX_POS #endif /** - * Features that require a min/max/specific LINEAR_AXES + * Features that require a min/max/specific NUM_AXES */ #if HAS_LEVELING && !HAS_Z_AXIS #error "Leveling in Marlin requires three or more axes, with Z as the vertical axis." #elif ENABLED(CNC_WORKSPACE_PLANES) && !HAS_Z_AXIS - #error "CNC_WORKSPACE_PLANES currently requires LINEAR_AXES >= 3" -#elif ENABLED(DIRECT_STEPPING) && LINEAR_AXES > XYZ - #error "DIRECT_STEPPING currently requires LINEAR_AXES 3" -#elif ENABLED(FOAMCUTTER_XYUV) && LINEAR_AXES < 5 - #error "FOAMCUTTER_XYUV requires LINEAR_AXES >= 5." + #error "CNC_WORKSPACE_PLANES currently requires NUM_AXES >= 3" +#elif ENABLED(DIRECT_STEPPING) && NUM_AXES > XYZ + #error "DIRECT_STEPPING currently requires NUM_AXES 3" +#elif ENABLED(FOAMCUTTER_XYUV) && NUM_AXES < 5 + #error "FOAMCUTTER_XYUV requires NUM_AXES >= 5." +#elif ENABLED(LINEAR_ADVANCE) && HAS_I_AXIS + #error "LINEAR_ADVANCE currently requires NUM_AXES <= 3." #endif /** @@ -1497,33 +1529,76 @@ static_assert(Y_MAX_LENGTH >= Y_BED_SIZE, "Movement bounds (Y_MIN_POS, Y_MAX_POS */ #if HAS_I_AXIS #if !defined(I_MIN_POS) || !defined(I_MAX_POS) - #error "I_MIN_POS and I_MAX_POS are required with LINEAR_AXES >= 4." + #error "I_MIN_POS and I_MAX_POS are required with NUM_AXES >= 4." #elif !defined(I_HOME_DIR) - #error "I_HOME_DIR is required with LINEAR_AXES >= 4." + #error "I_HOME_DIR is required with NUM_AXES >= 4." #elif HAS_I_ENABLE && !defined(I_ENABLE_ON) - #error "I_ENABLE_ON is required for your I driver with LINEAR_AXES >= 4." + #error "I_ENABLE_ON is required for your I driver with NUM_AXES >= 4." #endif #endif #if HAS_J_AXIS #if AXIS5_NAME == AXIS4_NAME #error "AXIS5_NAME must be unique." + #elif ENABLED(AXIS5_ROTATES) && DISABLED(AXIS4_ROTATES) + #error "AXIS5_ROTATES requires AXIS4_ROTATES." #elif !defined(J_MIN_POS) || !defined(J_MAX_POS) - #error "J_MIN_POS and J_MAX_POS are required with LINEAR_AXES >= 5." + #error "J_MIN_POS and J_MAX_POS are required with NUM_AXES >= 5." #elif !defined(J_HOME_DIR) - #error "J_HOME_DIR is required with LINEAR_AXES >= 5." + #error "J_HOME_DIR is required with NUM_AXES >= 5." #elif HAS_J_ENABLE && !defined(J_ENABLE_ON) - #error "J_ENABLE_ON is required for your J driver with LINEAR_AXES >= 5." + #error "J_ENABLE_ON is required for your J driver with NUM_AXES >= 5." #endif #endif #if HAS_K_AXIS #if AXIS6_NAME == AXIS5_NAME || AXIS6_NAME == AXIS4_NAME #error "AXIS6_NAME must be unique." + #elif ENABLED(AXIS6_ROTATES) && DISABLED(AXIS5_ROTATES) + #error "AXIS6_ROTATES requires AXIS5_ROTATES." #elif !defined(K_MIN_POS) || !defined(K_MAX_POS) - #error "K_MIN_POS and K_MAX_POS are required with LINEAR_AXES >= 6." + #error "K_MIN_POS and K_MAX_POS are required with NUM_AXES >= 6." #elif !defined(K_HOME_DIR) - #error "K_HOME_DIR is required with LINEAR_AXES >= 6." + #error "K_HOME_DIR is required with NUM_AXES >= 6." #elif HAS_K_ENABLE && !defined(K_ENABLE_ON) - #error "K_ENABLE_ON is required for your K driver with LINEAR_AXES >= 6." + #error "K_ENABLE_ON is required for your K driver with NUM_AXES >= 6." + #endif +#endif +#if HAS_U_AXIS + #if AXIS7_NAME == AXIS6_NAME || AXIS7_NAME == AXIS5_NAME || AXIS7_NAME == AXIS4_NAME + #error "AXIS7_NAME must be unique." + #elif ENABLED(AXIS7_ROTATES) && DISABLED(AXIS6_ROTATES) + #error "AXIS7_ROTATES requires AXIS6_ROTATES." + #elif !defined(U_MIN_POS) || !defined(U_MAX_POS) + #error "U_MIN_POS and U_MAX_POS are required with NUM_AXES >= 7." + #elif !defined(U_HOME_DIR) + #error "U_HOME_DIR is required with NUM_AXES >= 7." + #elif HAS_U_ENABLE && !defined(U_ENABLE_ON) + #error "U_ENABLE_ON is required for your U driver with NUM_AXES >= 7." + #endif +#endif +#if HAS_V_AXIS + #if AXIS8_NAME == AXIS7_NAME || AXIS8_NAME == AXIS6_NAME || AXIS8_NAME == AXIS5_NAME || AXIS8_NAME == AXIS4_NAME + #error "AXIS8_NAME must be unique." + #elif ENABLED(AXIS8_ROTATES) && DISABLED(AXIS7_ROTATES) + #error "AXIS8_ROTATES requires AXIS7_ROTATES." + #elif !defined(V_MIN_POS) || !defined(V_MAX_POS) + #error "V_MIN_POS and V_MAX_POS are required with NUM_AXES >= 8." + #elif !defined(V_HOME_DIR) + #error "V_HOME_DIR is required with NUM_AXES >= 8." + #elif HAS_V_ENABLE && !defined(V_ENABLE_ON) + #error "V_ENABLE_ON is required for your V driver with NUM_AXES >= 8." + #endif +#endif +#if HAS_W_AXIS + #if AXIS9_NAME == AXIS8_NAME || AXIS9_NAME == AXIS7_NAME || AXIS9_NAME == AXIS6_NAME || AXIS9_NAME == AXIS5_NAME || AXIS9_NAME == AXIS4_NAME + #error "AXIS9_NAME must be unique." + #elif ENABLED(AXIS9_ROTATES) && DISABLED(AXIS8_ROTATES) + #error "AXIS9_ROTATES requires AXIS8_ROTATES." + #elif !defined(W_MIN_POS) || !defined(W_MAX_POS) + #error "W_MIN_POS and W_MAX_POS are required with NUM_AXES >= 9." + #elif !defined(W_HOME_DIR) + #error "W_HOME_DIR is required with NUM_AXES >= 9." + #elif HAS_W_ENABLE && !defined(W_ENABLE_ON) + #error "W_ENABLE_ON is required for your W driver with NUM_AXES >= 9." #endif #endif @@ -1706,9 +1781,9 @@ static_assert(Y_MAX_LENGTH >= Y_BED_SIZE, "Movement bounds (Y_MIN_POS, Y_MAX_POS * Require pin options and pins to be defined */ #if ENABLED(SENSORLESS_PROBING) - #if ENABLED(DELTA) && !(AXIS_HAS_STALLGUARD(X) && AXIS_HAS_STALLGUARD(Y) && AXIS_HAS_STALLGUARD(Z)) + #if ENABLED(DELTA) && !(X_SENSORLESS && Y_SENSORLESS && Z_SENSORLESS) #error "SENSORLESS_PROBING requires TMC2130/2160/2209/5130/5160 drivers on X, Y, and Z." - #elif !AXIS_HAS_STALLGUARD(Z) + #elif !Z_SENSORLESS #error "SENSORLESS_PROBING requires a TMC2130/2160/2209/5130/5160 driver on Z." #endif #elif ENABLED(Z_MIN_PROBE_USES_Z_MIN_ENDSTOP_PIN) @@ -1913,49 +1988,61 @@ static_assert(Y_MAX_LENGTH >= Y_BED_SIZE, "Movement bounds (Y_MIN_POS, Y_MAX_POS #error "Required setting HOMING_BUMP_DIVISOR is missing!" #else constexpr float hbm[] = HOMING_BUMP_MM, hbd[] = HOMING_BUMP_DIVISOR; - static_assert(COUNT(hbm) == LINEAR_AXES, "HOMING_BUMP_MM must have " _LINEAR_AXES_STR "elements (and no others)."); - LINEAR_AXIS_CODE( + static_assert(COUNT(hbm) == NUM_AXES, "HOMING_BUMP_MM must have " _NUM_AXES_STR "elements (and no others)."); + NUM_AXIS_CODE( static_assert(hbm[X_AXIS] >= 0, "HOMING_BUMP_MM.X must be greater than or equal to 0."), static_assert(hbm[Y_AXIS] >= 0, "HOMING_BUMP_MM.Y must be greater than or equal to 0."), static_assert(hbm[Z_AXIS] >= 0, "HOMING_BUMP_MM.Z must be greater than or equal to 0."), static_assert(hbm[I_AXIS] >= 0, "HOMING_BUMP_MM.I must be greater than or equal to 0."), static_assert(hbm[J_AXIS] >= 0, "HOMING_BUMP_MM.J must be greater than or equal to 0."), - static_assert(hbm[K_AXIS] >= 0, "HOMING_BUMP_MM.K must be greater than or equal to 0.") + static_assert(hbm[K_AXIS] >= 0, "HOMING_BUMP_MM.K must be greater than or equal to 0."), + static_assert(hbm[U_AXIS] >= 0, "HOMING_BUMP_MM.U must be greater than or equal to 0."), + static_assert(hbm[V_AXIS] >= 0, "HOMING_BUMP_MM.V must be greater than or equal to 0."), + static_assert(hbm[W_AXIS] >= 0, "HOMING_BUMP_MM.W must be greater than or equal to 0.") ); - static_assert(COUNT(hbd) == LINEAR_AXES, "HOMING_BUMP_DIVISOR must have " _LINEAR_AXES_STR "elements (and no others)."); - LINEAR_AXIS_CODE( + static_assert(COUNT(hbd) == NUM_AXES, "HOMING_BUMP_DIVISOR must have " _NUM_AXES_STR "elements (and no others)."); + NUM_AXIS_CODE( static_assert(hbd[X_AXIS] >= 1, "HOMING_BUMP_DIVISOR.X must be greater than or equal to 1."), static_assert(hbd[Y_AXIS] >= 1, "HOMING_BUMP_DIVISOR.Y must be greater than or equal to 1."), static_assert(hbd[Z_AXIS] >= 1, "HOMING_BUMP_DIVISOR.Z must be greater than or equal to 1."), static_assert(hbd[I_AXIS] >= 1, "HOMING_BUMP_DIVISOR.I must be greater than or equal to 1."), static_assert(hbd[J_AXIS] >= 1, "HOMING_BUMP_DIVISOR.J must be greater than or equal to 1."), - static_assert(hbd[K_AXIS] >= 1, "HOMING_BUMP_DIVISOR.K must be greater than or equal to 1.") + static_assert(hbd[K_AXIS] >= 1, "HOMING_BUMP_DIVISOR.K must be greater than or equal to 1."), + static_assert(hbd[U_AXIS] >= 1, "HOMING_BUMP_DIVISOR.U must be greater than or equal to 1."), + static_assert(hbd[V_AXIS] >= 1, "HOMING_BUMP_DIVISOR.V must be greater than or equal to 1."), + static_assert(hbd[W_AXIS] >= 1, "HOMING_BUMP_DIVISOR.W must be greater than or equal to 1.") ); #endif #ifdef HOMING_BACKOFF_POST_MM constexpr float hbp[] = HOMING_BACKOFF_POST_MM; - static_assert(COUNT(hbp) == LINEAR_AXES, "HOMING_BACKOFF_POST_MM must have " _LINEAR_AXES_STR "elements (and no others)."); - LINEAR_AXIS_CODE( + static_assert(COUNT(hbp) == NUM_AXES, "HOMING_BACKOFF_POST_MM must have " _NUM_AXES_STR "elements (and no others)."); + NUM_AXIS_CODE( static_assert(hbp[X_AXIS] >= 0, "HOMING_BACKOFF_POST_MM.X must be greater than or equal to 0."), static_assert(hbp[Y_AXIS] >= 0, "HOMING_BACKOFF_POST_MM.Y must be greater than or equal to 0."), static_assert(hbp[Z_AXIS] >= 0, "HOMING_BACKOFF_POST_MM.Z must be greater than or equal to 0."), static_assert(hbp[I_AXIS] >= 0, "HOMING_BACKOFF_POST_MM.I must be greater than or equal to 0."), static_assert(hbp[J_AXIS] >= 0, "HOMING_BACKOFF_POST_MM.J must be greater than or equal to 0."), - static_assert(hbp[K_AXIS] >= 0, "HOMING_BACKOFF_POST_MM.K must be greater than or equal to 0.") + static_assert(hbp[K_AXIS] >= 0, "HOMING_BACKOFF_POST_MM.K must be greater than or equal to 0."), + static_assert(hbp[U_AXIS] >= 0, "HOMING_BACKOFF_POST_MM.U must be greater than or equal to 0."), + static_assert(hbp[V_AXIS] >= 0, "HOMING_BACKOFF_POST_MM.V must be greater than or equal to 0."), + static_assert(hbp[W_AXIS] >= 0, "HOMING_BACKOFF_POST_MM.W must be greater than or equal to 0.") ); #endif #ifdef SENSORLESS_BACKOFF_MM constexpr float sbm[] = SENSORLESS_BACKOFF_MM; - static_assert(COUNT(sbm) == LINEAR_AXES, "SENSORLESS_BACKOFF_MM must have " _LINEAR_AXES_STR "elements (and no others)."); - LINEAR_AXIS_CODE( + static_assert(COUNT(sbm) == NUM_AXES, "SENSORLESS_BACKOFF_MM must have " _NUM_AXES_STR "elements (and no others)."); + NUM_AXIS_CODE( static_assert(sbm[X_AXIS] >= 0, "SENSORLESS_BACKOFF_MM.X must be greater than or equal to 0."), static_assert(sbm[Y_AXIS] >= 0, "SENSORLESS_BACKOFF_MM.Y must be greater than or equal to 0."), static_assert(sbm[Z_AXIS] >= 0, "SENSORLESS_BACKOFF_MM.Z must be greater than or equal to 0."), static_assert(sbm[I_AXIS] >= 0, "SENSORLESS_BACKOFF_MM.I must be greater than or equal to 0."), static_assert(sbm[J_AXIS] >= 0, "SENSORLESS_BACKOFF_MM.J must be greater than or equal to 0."), - static_assert(sbm[K_AXIS] >= 0, "SENSORLESS_BACKOFF_MM.K must be greater than or equal to 0.") + static_assert(sbm[K_AXIS] >= 0, "SENSORLESS_BACKOFF_MM.K must be greater than or equal to 0."), + static_assert(sbm[U_AXIS] >= 0, "SENSORLESS_BACKOFF_MM.U must be greater than or equal to 0."), + static_assert(sbm[V_AXIS] >= 0, "SENSORLESS_BACKOFF_MM.V must be greater than or equal to 0."), + static_assert(sbm[W_AXIS] >= 0, "SENSORLESS_BACKOFF_MM.W must be greater than or equal to 0.") ); #endif @@ -1978,9 +2065,9 @@ static_assert(Y_MAX_LENGTH >= Y_BED_SIZE, "Movement bounds (Y_MIN_POS, Y_MAX_POS /** * Make sure DISABLE_[XYZ] compatible with selected homing options */ -#if ANY(DISABLE_X, DISABLE_Y, DISABLE_Z, DISABLE_I, DISABLE_J, DISABLE_K) +#if ANY(DISABLE_X, DISABLE_Y, DISABLE_Z, DISABLE_I, DISABLE_J, DISABLE_K, DISABLE_U, DISABLE_V, DISABLE_W) #if EITHER(HOME_AFTER_DEACTIVATE, Z_SAFE_HOMING) - #error "DISABLE_[XYZIJK] is not compatible with HOME_AFTER_DEACTIVATE or Z_SAFE_HOMING." + #error "DISABLE_[XYZIJKUVW] is not compatible with HOME_AFTER_DEACTIVATE or Z_SAFE_HOMING." #endif #endif @@ -2494,7 +2581,9 @@ static_assert(Y_MAX_LENGTH >= Y_BED_SIZE, "Movement bounds (Y_MIN_POS, Y_MAX_POS #define _PLUG_UNUSED_TEST(A,P) (DISABLED(USE_##P##MIN_PLUG, USE_##P##MAX_PLUG) \ && !(ENABLED(A##_DUAL_ENDSTOPS) && WITHIN(A##2_USE_ENDSTOP, _##P##MAX_, _##P##MIN_)) \ && !(ENABLED(A##_MULTI_ENDSTOPS) && WITHIN(A##2_USE_ENDSTOP, _##P##MAX_, _##P##MIN_)) ) -#define _AXIS_PLUG_UNUSED_TEST(A) (1 LINEAR_AXIS_GANG(&& _PLUG_UNUSED_TEST(A,X), && _PLUG_UNUSED_TEST(A,Y), && _PLUG_UNUSED_TEST(A,Z), && _PLUG_UNUSED_TEST(A,I), && _PLUG_UNUSED_TEST(A,J), && _PLUG_UNUSED_TEST(A,K) ) ) +#define _AXIS_PLUG_UNUSED_TEST(A) (1 NUM_AXIS_GANG(&& _PLUG_UNUSED_TEST(A,X), && _PLUG_UNUSED_TEST(A,Y), && _PLUG_UNUSED_TEST(A,Z), \ + && _PLUG_UNUSED_TEST(A,I), && _PLUG_UNUSED_TEST(A,J), && _PLUG_UNUSED_TEST(A,K), \ + && _PLUG_UNUSED_TEST(A,U), && _PLUG_UNUSED_TEST(A,V), && _PLUG_UNUSED_TEST(A,W) ) ) // A machine with endstops must have a minimum of 3 #if HAS_ENDSTOPS @@ -2516,6 +2605,15 @@ static_assert(Y_MAX_LENGTH >= Y_BED_SIZE, "Movement bounds (Y_MIN_POS, Y_MAX_POS #if HAS_K_AXIS && _AXIS_PLUG_UNUSED_TEST(K) #error "You must enable USE_KMIN_PLUG or USE_KMAX_PLUG." #endif + #if HAS_U_AXIS && _AXIS_PLUG_UNUSED_TEST(U) + #error "You must enable USE_UMIN_PLUG or USE_UMAX_PLUG." + #endif + #if HAS_V_AXIS && _AXIS_PLUG_UNUSED_TEST(V) + #error "You must enable USE_VMIN_PLUG or USE_VMAX_PLUG." + #endif + #if HAS_W_AXIS && _AXIS_PLUG_UNUSED_TEST(W) + #error "You must enable USE_WMIN_PLUG or USE_WMAX_PLUG." + #endif // Delta and Cartesian use 3 homing endstops #if NONE(IS_SCARA, SPI_ENDSTOPS) @@ -2539,6 +2637,18 @@ static_assert(Y_MAX_LENGTH >= Y_BED_SIZE, "Movement bounds (Y_MIN_POS, Y_MAX_POS #error "Enable USE_KMIN_PLUG when homing K to MIN." #elif HAS_K_AXIS && K_HOME_TO_MAX && DISABLED(USE_KMAX_PLUG) #error "Enable USE_KMAX_PLUG when homing K to MAX." + #elif HAS_U_AXIS && U_HOME_TO_MIN && DISABLED(USE_UMIN_PLUG) + #error "Enable USE_UMIN_PLUG when homing U to MIN." + #elif HAS_U_AXIS && U_HOME_TO_MAX && DISABLED(USE_UMAX_PLUG) + #error "Enable USE_UMAX_PLUG when homing U to MAX." + #elif HAS_V_AXIS && V_HOME_TO_MIN && DISABLED(USE_VMIN_PLUG) + #error "Enable USE_VMIN_PLUG when homing V to MIN." + #elif HAS_V_AXIS && V_HOME_TO_MAX && DISABLED(USE_VMAX_PLUG) + #error "Enable USE_VMAX_PLUG when homing V to MAX." + #elif HAS_W_AXIS && W_HOME_TO_MIN && DISABLED(USE_WMIN_PLUG) + #error "Enable USE_WMIN_PLUG when homing W to MIN." + #elif HAS_W_AXIS && W_HOME_TO_MAX && DISABLED(USE_WMAX_PLUG) + #error "Enable USE_WMAX_PLUG when homing W to MAX." #endif #endif @@ -3022,6 +3132,12 @@ static_assert(Y_MAX_LENGTH >= Y_BED_SIZE, "Movement bounds (Y_MIN_POS, Y_MAX_POS #error "An SPI driven TMC on J requires J_CS_PIN." #elif INVALID_TMC_SPI(K) #error "An SPI driven TMC on K requires K_CS_PIN." +#elif INVALID_TMC_SPI(U) + #error "An SPI driven TMC on U requires U_CS_PIN." +#elif INVALID_TMC_SPI(V) + #error "An SPI driven TMC on V requires V_CS_PIN." +#elif INVALID_TMC_SPI(W) + #error "An SPI driven TMC on W requires W_CS_PIN." #endif #undef INVALID_TMC_SPI @@ -3067,6 +3183,13 @@ static_assert(Y_MAX_LENGTH >= Y_BED_SIZE, "Movement bounds (Y_MIN_POS, Y_MAX_POS #error "TMC2208 or TMC2209 on J requires J_HARDWARE_SERIAL or J_SERIAL_(RX|TX)_PIN." #elif HAS_K_AXIS && INVALID_TMC_UART(K) #error "TMC2208 or TMC2209 on K requires K_HARDWARE_SERIAL or K_SERIAL_(RX|TX)_PIN." +#elif HAS_U_AXIS && INVALID_TMC_UART(U) + #error "TMC2208 or TMC2209 on U requires U_HARDWARE_SERIAL or U_SERIAL_(RX|TX)_PIN." +#elif HAS_V_AXIS && INVALID_TMC_UART(V) + #error "TMC2208 or TMC2209 on V requires V_HARDWARE_SERIAL or V_SERIAL_(RX|TX)_PIN." +#elif HAS_W_AXIS && INVALID_TMC_UART(W) + #error "TMC2208 or TMC2209 on W requires W_HARDWARE_SERIAL or W_SERIAL_(RX|TX)_PIN." + #endif #undef INVALID_TMC_UART @@ -3096,6 +3219,12 @@ static_assert(Y_MAX_LENGTH >= Y_BED_SIZE, "Movement bounds (Y_MIN_POS, Y_MAX_POS INVALID_TMC_ADDRESS(J); #elif AXIS_DRIVER_TYPE_K(TMC2209) INVALID_TMC_ADDRESS(K); +#elif AXIS_DRIVER_TYPE_U(TMC2209) + INVALID_TMC_ADDRESS(U); +#elif AXIS_DRIVER_TYPE_V(TMC2209) + INVALID_TMC_ADDRESS(V); +#elif AXIS_DRIVER_TYPE_W(TMC2209) + INVALID_TMC_ADDRESS(W); #elif AXIS_DRIVER_TYPE_E0(TMC2209) INVALID_TMC_ADDRESS(E0); #elif AXIS_DRIVER_TYPE_E1(TMC2209) @@ -3157,6 +3286,12 @@ static_assert(Y_MAX_LENGTH >= Y_BED_SIZE, "Movement bounds (Y_MIN_POS, Y_MAX_POS INVALID_TMC_MS(J) #elif HAS_K_AXIS && !TMC_MICROSTEP_IS_VALID(K) INVALID_TMC_MS(K) +#elif HAS_U_AXIS && !TMC_MICROSTEP_IS_VALID(U) + INVALID_TMC_MS(U) +#elif HAS_V_AXIS && !TMC_MICROSTEP_IS_VALID(V) + INVALID_TMC_MS(V) +#elif HAS_W_AXIS && !TMC_MICROSTEP_IS_VALID(W) + INVALID_TMC_MS(W) #endif #undef INVALID_TMC_MS #undef TMC_MICROSTEP_IS_VALID @@ -3186,6 +3321,15 @@ static_assert(Y_MAX_LENGTH >= Y_BED_SIZE, "Movement bounds (Y_MIN_POS, Y_MAX_POS #if HAS_K_AXIS #define K_ENDSTOP_INVERTING !AXIS_DRIVER_TYPE(K,TMC2209) #endif + #if HAS_U_AXIS + #define U_ENDSTOP_INVERTING !AXIS_DRIVER_TYPE(U,TMC2209) + #endif + #if HAS_V_AXIS + #define V_ENDSTOP_INVERTING !AXIS_DRIVER_TYPE(V,TMC2209) + #endif + #if HAS_W_AXIS + #define W_ENDSTOP_INVERTING !AXIS_DRIVER_TYPE(W,TMC2209) + #endif #if NONE(SPI_ENDSTOPS, ONBOARD_ENDSTOPPULLUPS, ENDSTOPPULLUPS) #if X_SENSORLESS && X_HOME_TO_MIN && DISABLED(ENDSTOPPULLUP_XMIN) @@ -3212,6 +3356,19 @@ static_assert(Y_MAX_LENGTH >= Y_BED_SIZE, "Movement bounds (Y_MIN_POS, Y_MAX_POS #error "SENSORLESS_HOMING requires ENDSTOPPULLUP_KMIN (or ENDSTOPPULLUPS) when homing to K_MIN." #elif ALL(HAS_K_AXIS, K_SENSORLESS, K_HOME_TO_MAX) && DISABLED(ENDSTOPPULLUP_KMAX) #error "SENSORLESS_HOMING requires ENDSTOPPULLUP_KMAX (or ENDSTOPPULLUPS) when homing to K_MAX." + #elif HAS_U_AXIS && U_SENSORLESS && U_HOME_TO_MIN && DISABLED(ENDSTOPPULLUP_UMIN) + #error "SENSORLESS_HOMING requires ENDSTOPPULLUP_UMIN (or ENDSTOPPULLUPS) when homing to U_MIN." + #elif HAS_U_AXIS && U_SENSORLESS && U_HOME_TO_MAX && DISABLED(ENDSTOPPULLUP_UMAX) + #error "SENSORLESS_HOMING requires ENDSTOPPULLUP_UMAX (or ENDSTOPPULLUPS) when homing to U_MAX." + #elif HAS_V_AXIS && V_SENSORLESS && V_HOME_TO_MIN && DISABLED(ENDSTOPPULLUP_VMIN) + #error "SENSORLESS_HOMING requires ENDSTOPPULLUP_VMIN (or ENDSTOPPULLUPS) when homing to V_MIN." + #elif HAS_V_AXIS && V_SENSORLESS && V_HOME_TO_MAX && DISABLED(ENDSTOPPULLUP_VMAX) + #error "SENSORLESS_HOMING requires ENDSTOPPULLUP_VMAX (or ENDSTOPPULLUPS) when homing to V_MAX." + #elif HAS_W_AXIS && W_SENSORLESS && W_HOME_TO_MIN && DISABLED(ENDSTOPPULLUP_WMIN) + #error "SENSORLESS_HOMING requires ENDSTOPPULLUP_WMIN (or ENDSTOPPULLUPS) when homing to W_MIN." + #elif HAS_W_AXIS && W_SENSORLESS && W_HOME_TO_MAX && DISABLED(ENDSTOPPULLUP_WMAX) + #error "SENSORLESS_HOMING requires ENDSTOPPULLUP_WMAX (or ENDSTOPPULLUPS) when homing to W_MAX." + #endif #endif @@ -3292,6 +3449,42 @@ static_assert(Y_MAX_LENGTH >= Y_BED_SIZE, "Movement bounds (Y_MIN_POS, Y_MAX_POS #else #error "SENSORLESS_HOMING requires K_MAX_ENDSTOP_INVERTING = false when homing TMC2209 to K_MAX." #endif + #elif ALL(HAS_U_AXIS, U_SENSORLESS, U_HOME_TO_MIN) && U_MIN_ENDSTOP_INVERTING != U_ENDSTOP_INVERTING + #if U_ENDSTOP_INVERTING + #error "SENSORLESS_HOMING requires U_MIN_ENDSTOP_INVERTING = true when homing to U_MIN." + #else + #error "SENSORLESS_HOMING requires U_MIN_ENDSTOP_INVERTING = false when homing TMC2209 to U_MIN." + #endif + #elif ALL(HAS_U_AXIS, U_SENSORLESS, U_HOME_TO_MAX) && U_MAX_ENDSTOP_INVERTING != U_ENDSTOP_INVERTING + #if U_ENDSTOP_INVERTING + #error "SENSORLESS_HOMING requires U_MAX_ENDSTOP_INVERTING = true when homing to U_MAX." + #else + #error "SENSORLESS_HOMING requires U_MAX_ENDSTOP_INVERTING = false when homing TMC2209 to U_MAX." + #endif + #elif ALL(HAS_V_AXIS, V_SENSORLESS, V_HOME_TO_MIN) && V_MIN_ENDSTOP_INVERTING != V_ENDSTOP_INVERTING + #if V_ENDSTOP_INVERTING + #error "SENSORLESS_HOMING requires V_MIN_ENDSTOP_INVERTING = true when homing to V_MIN." + #else + #error "SENSORLESS_HOMING requires V_MIN_ENDSTOP_INVERTING = false when homing TMC2209 to V_MIN." + #endif + #elif ALL(HAS_V_AXIS, V_SENSORLESS, V_HOME_TO_MAX) && V_MAX_ENDSTOP_INVERTING != V_ENDSTOP_INVERTING + #if V_ENDSTOP_INVERTING + #error "SENSORLESS_HOMING requires V_MAX_ENDSTOP_INVERTING = true when homing to V_MAX." + #else + #error "SENSORLESS_HOMING requires V_MAX_ENDSTOP_INVERTING = false when homing TMC2209 to V_MAX." + #endif + #elif ALL(HAS_W_AXIS, W_SENSORLESS, W_HOME_TO_MIN) && W_MIN_ENDSTOP_INVERTING != W_ENDSTOP_INVERTING + #if W_ENDSTOP_INVERTING + #error "SENSORLESS_HOMING requires W_MIN_ENDSTOP_INVERTING = true when homing to W_MIN." + #else + #error "SENSORLESS_HOMING requires W_MIN_ENDSTOP_INVERTING = false when homing TMC2209 to W_MIN." + #endif + #elif ALL(HAS_W_AXIS, W_SENSORLESS, W_HOME_TO_MAX0) && W_MAX_ENDSTOP_INVERTING != W_ENDSTOP_INVERTING + #if W_ENDSTOP_INVERTING + #error "SENSORLESS_HOMING requires W_MAX_ENDSTOP_INVERTING = true when homing to W_MAX." + #else + #error "SENSORLESS_HOMING requires W_MAX_ENDSTOP_INVERTING = false when homing TMC2209 to W_MAX." + #endif #endif #endif @@ -3309,6 +3502,9 @@ static_assert(Y_MAX_LENGTH >= Y_BED_SIZE, "Movement bounds (Y_MIN_POS, Y_MAX_POS #undef I_ENDSTOP_INVERTING #undef J_ENDSTOP_INVERTING #undef K_ENDSTOP_INVERTING + #undef U_ENDSTOP_INVERTING + #undef V_ENDSTOP_INVERTING + #undef W_ENDSTOP_INVERTING #endif // Sensorless probing requirements @@ -3377,6 +3573,12 @@ static_assert(Y_MAX_LENGTH >= Y_BED_SIZE, "Movement bounds (Y_MIN_POS, Y_MAX_POS #define CS_COMPARE J_CS_PIN #elif IN_CHAIN(K) #define CS_COMPARE K_CS_PIN + #elif IN_CHAIN(U) + #define CS_COMPARE U_CS_PIN + #elif IN_CHAIN(V) + #define CS_COMPARE V_CS_PIN + #elif IN_CHAIN(W) + #define CS_COMPARE W_CS_PIN #elif IN_CHAIN(E0) #define CS_COMPARE E0_CS_PIN #elif IN_CHAIN(E1) @@ -3397,6 +3599,7 @@ static_assert(Y_MAX_LENGTH >= Y_BED_SIZE, "Movement bounds (Y_MIN_POS, Y_MAX_POS #define BAD_CS_PIN(A) (IN_CHAIN(A) && A##_CS_PIN != CS_COMPARE) #if BAD_CS_PIN(X ) || BAD_CS_PIN(Y ) || BAD_CS_PIN(Z ) || BAD_CS_PIN(X2) || BAD_CS_PIN(Y2) || BAD_CS_PIN(Z2) || BAD_CS_PIN(Z3) || BAD_CS_PIN(Z4) \ || BAD_CS_PIN(I) || BAD_CS_PIN(J) || BAD_CS_PIN(K) \ + || BAD_CS_PIN(U) || BAD_CS_PIN(V) || BAD_CS_PIN(W) \ || BAD_CS_PIN(E0) || BAD_CS_PIN(E1) || BAD_CS_PIN(E2) || BAD_CS_PIN(E3) || BAD_CS_PIN(E4) || BAD_CS_PIN(E5) || BAD_CS_PIN(E6) || BAD_CS_PIN(E7) #error "All chained TMC drivers must use the same CS pin." #endif @@ -3410,8 +3613,8 @@ static_assert(Y_MAX_LENGTH >= Y_BED_SIZE, "Movement bounds (Y_MIN_POS, Y_MAX_POS /** * L64XX requirement */ -#if HAS_L64XX && HAS_I_AXIS - #error "L64XX requires LINEAR_AXES <= 3. Homing with L64XX is not yet implemented for LINEAR_AXES > 3." +#if HAS_L64XX && NUM_AXES > 3 + #error "L64XX requires NUM_AXES <= 3. Homing with L64XX is not yet implemented for NUM_AXES > 3." #endif /** @@ -3435,7 +3638,7 @@ static_assert(Y_MAX_LENGTH >= Y_BED_SIZE, "Movement bounds (Y_MIN_POS, Y_MAX_POS #if HAS_MULTI_EXTRUDER #define _EXTRA_NOTE " (Did you forget to enable DISTINCT_E_FACTORS?)" #else - #define _EXTRA_NOTE " (Should be " STRINGIFY(LINEAR_AXES) "+" STRINGIFY(E_STEPPERS) ")" + #define _EXTRA_NOTE " (Should be " STRINGIFY(NUM_AXES) "+" STRINGIFY(E_STEPPERS) ")" #endif constexpr float sanity_arr_1[] = DEFAULT_AXIS_STEPS_PER_UNIT; @@ -3454,7 +3657,7 @@ static_assert(COUNT(sanity_arr_3) <= DISTINCT_AXES, "DEFAULT_MAX_ACCELERATION ha static_assert(_PLUS_TEST(3), "DEFAULT_MAX_ACCELERATION values must be positive."); constexpr float sanity_arr_4[] = HOMING_FEEDRATE_MM_M; -static_assert(COUNT(sanity_arr_4) == LINEAR_AXES, "HOMING_FEEDRATE_MM_M requires " _LINEAR_AXES_STR "elements (and no others)."); +static_assert(COUNT(sanity_arr_4) == NUM_AXES, "HOMING_FEEDRATE_MM_M requires " _NUM_AXES_STR "elements (and no others)."); static_assert(_PLUS_TEST(4), "HOMING_FEEDRATE_MM_M values must be positive."); #ifdef MAX_ACCEL_EDIT_VALUES @@ -3894,6 +4097,15 @@ static_assert(_PLUS_TEST(4), "HOMING_FEEDRATE_MM_M values must be positive."); #if _BAD_DRIVER(K) #error "K_DRIVER_TYPE is not recognized." #endif +#if _BAD_DRIVER(U) + #error "U_DRIVER_TYPE is not recognized." +#endif +#if _BAD_DRIVER(V) + #error "V_DRIVER_TYPE is not recognized." +#endif +#if _BAD_DRIVER(W) + #error "W_DRIVER_TYPE is not recognized." +#endif #if _BAD_DRIVER(X2) #error "X2_DRIVER_TYPE is not recognized." #endif @@ -3966,7 +4178,7 @@ static_assert(_PLUS_TEST(4), "HOMING_FEEDRATE_MM_M values must be positive."); // Misc. Cleanup #undef _TEST_PWM -#undef _LINEAR_AXES_STR +#undef _NUM_AXES_STR #undef _LOGICAL_AXES_STR // JTAG support in the HAL diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 76889cb40a..250133c435 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 "2022-03-12" + #define STRING_DISTRIBUTION_DATE "2022-04-03" #endif /** @@ -52,7 +52,7 @@ * to alert users to major changes. */ -#define MARLIN_HEX_VERSION 02000903 +#define MARLIN_HEX_VERSION 02010000 #ifndef REQUIRED_CONFIGURATION_H_VERSION #define REQUIRED_CONFIGURATION_H_VERSION MARLIN_HEX_VERSION #endif diff --git a/Marlin/src/inc/Warnings.cpp b/Marlin/src/inc/Warnings.cpp index 9d7b14d763..96f8dc7d54 100644 --- a/Marlin/src/inc/Warnings.cpp +++ b/Marlin/src/inc/Warnings.cpp @@ -532,6 +532,163 @@ #endif #endif + #if AUTO_ASSIGNED_U_STEPPER + #warning "Note: Auto-assigned U STEP/DIR/ENABLE_PINs to unused En_STEP/DIR/ENABLE_PINs. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #endif + #if AUTO_ASSIGNED_U_CS + #warning "Note: Auto-assigned U_CS_PIN to an unused En_CS_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #endif + #if AUTO_ASSIGNED_U_MS1 + #warning "Note: Auto-assigned U_MS1_PIN to an unused En_MS1_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #endif + #if AUTO_ASSIGNED_U_MS2 + #warning "Note: Auto-assigned U_MS2_PIN to an unused En_MS2_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #endif + #if AUTO_ASSIGNED_U_MS3 + #warning "Note: Auto-assigned U_MS3_PIN to an unused En_MS3_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #endif + #if AUTO_ASSIGNED_U_DIAG + #if U_USE_ENDSTOP == _XMIN_ + #warning "Note: Auto-assigned U_DIAG_PIN to X_MIN_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #elif U_USE_ENDSTOP == _XMAX_ + #warning "Note: Auto-assigned U_DIAG_PIN to X_MAX_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #elif K_USE_ENDSTOP == _YMIN_ + #warning "Note: Auto-assigned U_DIAG_PIN to Y_MIN_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #elif U_USE_ENDSTOP == _YMAX_ + #warning "Note: Auto-assigned U_DIAG_PIN to Y_MAX_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #elif U_USE_ENDSTOP == _ZMIN_ + #warning "Note: Auto-assigned U_DIAG_PIN to Z_MIN_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #elif U_USE_ENDSTOP == _ZMAX_ + #warning "Note: Auto-assigned U_DIAG_PIN to Z_MAX_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #elif U_USE_ENDSTOP == _XDIAG_ + #warning "Note: Auto-assigned U_DIAG_PIN to X_DIAG_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #elif U_USE_ENDSTOP == _YDIAG_ + #warning "Note: Auto-assigned U_DIAG_PIN to Y_DIAG_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #elif U_USE_ENDSTOP == _ZDIAG_ + #warning "Note: Auto-assigned U_DIAG_PIN to Z_DIAG_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #elif U_USE_ENDSTOP == _E0DIAG_ + #warning "Note: Auto-assigned U_DIAG_PIN to E0_DIAG_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #elif U_USE_ENDSTOP == _E1DIAG_ + #warning "Note: Auto-assigned U_DIAG_PIN to E1_DIAG_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #elif U_USE_ENDSTOP == _E2DIAG_ + #warning "Note: Auto-assigned U_DIAG_PIN to E2_DIAG_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #elif U_USE_ENDSTOP == _E3DIAG_ + #warning "Note: Auto-assigned U_DIAG_PIN to E3_DIAG_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #elif U_USE_ENDSTOP == _E4DIAG_ + #warning "Note: Auto-assigned U_DIAG_PIN to E4_DIAG_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #elif U_USE_ENDSTOP == _E5DIAG_ + #warning "Note: Auto-assigned U_DIAG_PIN to E5_DIAG_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #elif U_USE_ENDSTOP == _E6DIAG_ + #warning "Note: Auto-assigned U_DIAG_PIN to E6_DIAG_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #elif U_USE_ENDSTOP == _E7DIAG_ + #warning "Note: Auto-assigned U_DIAG_PIN to E7_DIAG_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #endif + #endif + #if AUTO_ASSIGNED_V_STEPPER + #warning "Note: Auto-assigned V STEP/DIR/ENABLE_PINs to unused En_STEP/DIR/ENABLE_PINs. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #endif + #if AUTO_ASSIGNED_V_CS + #warning "Note: Auto-assigned V_CS_PIN to an unused En_CS_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #endif + #if AUTO_ASSIGNED_V_MS1 + #warning "Note: Auto-assigned V_MS1_PIN to an unused En_MS1_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #endif + #if AUTO_ASSIGNED_V_MS2 + #warning "Note: Auto-assigned V_MS2_PIN to an unused En_MS2_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #endif + #if AUTO_ASSIGNED_V_MS3 + #warning "Note: Auto-assigned V_MS3_PIN to an unused En_MS3_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #endif + #if AUTO_ASSIGNED_V_DIAG + #if V_USE_ENDSTOP == _XMIN_ + #warning "Note: Auto-assigned V_DIAG_PIN to X_MIN_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #elif V_USE_ENDSTOP == _XMAX_ + #warning "Note: Auto-assigned V_DIAG_PIN to X_MAX_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #elif V_USE_ENDSTOP == _YMIN_ + #warning "Note: Auto-assigned V_DIAG_PIN to Y_MIN_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #elif V_USE_ENDSTOP == _YMAX_ + #warning "Note: Auto-assigned V_DIAG_PIN to Y_MAX_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #elif V_USE_ENDSTOP == _ZMIN_ + #warning "Note: Auto-assigned V_DIAG_PIN to Z_MIN_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #elif V_USE_ENDSTOP == _ZMAX_ + #warning "Note: Auto-assigned V_DIAG_PIN to Z_MAX_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #elif V_USE_ENDSTOP == _XDIAG_ + #warning "Note: Auto-assigned V_DIAG_PIN to X_DIAG_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #elif V_USE_ENDSTOP == _YDIAG_ + #warning "Note: Auto-assigned V_DIAG_PIN to Y_DIAG_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #elif V_USE_ENDSTOP == _ZDIAG_ + #warning "Note: Auto-assigned V_DIAG_PIN to Z_DIAG_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #elif V_USE_ENDSTOP == _E0DIAG_ + #warning "Note: Auto-assigned V_DIAG_PIN to E0_DIAG_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #elif V_USE_ENDSTOP == _E1DIAG_ + #warning "Note: Auto-assigned V_DIAG_PIN to E1_DIAG_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #elif V_USE_ENDSTOP == _E2DIAG_ + #warning "Note: Auto-assigned V_DIAG_PIN to E2_DIAG_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #elif V_USE_ENDSTOP == _E3DIAG_ + #warning "Note: Auto-assigned V_DIAG_PIN to E3_DIAG_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #elif V_USE_ENDSTOP == _E4DIAG_ + #warning "Note: Auto-assigned V_DIAG_PIN to E4_DIAG_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #elif V_USE_ENDSTOP == _E5DIAG_ + #warning "Note: Auto-assigned V_DIAG_PIN to E5_DIAG_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #elif V_USE_ENDSTOP == _E6DIAG_ + #warning "Note: Auto-assigned V_DIAG_PIN to E6_DIAG_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #elif V_USE_ENDSTOP == _E7DIAG_ + #warning "Note: Auto-assigned V_DIAG_PIN to E7_DIAG_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #endif + #endif + #if AUTO_ASSIGNED_W_STEPPER + #warning "Note: Auto-assigned W STEP/DIR/ENABLE_PINs to unused En_STEP/DIR/ENABLE_PINs. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #endif + #if AUTO_ASSIGNED_W_CS + #warning "Note: Auto-assigned W_CS_PIN to an unused En_CS_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #endif + #if AUTO_ASSIGNED_W_MS1 + #warning "Note: Auto-assigned W_MS1_PIN to an unused En_MS1_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #endif + #if AUTO_ASSIGNED_W_MS2 + #warning "Note: Auto-assigned W_MS2_PIN to an unused En_MS2_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #endif + #if AUTO_ASSIGNED_W_MS3 + #warning "Note: Auto-assigned W_MS3_PIN to an unused En_MS3_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #endif + #if AUTO_ASSIGNED_W_DIAG + #if W_USE_ENDSTOP == _XMIN_ + #warning "Note: Auto-assigned W_DIAG_PIN to X_MIN_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #elif W_USE_ENDSTOP == _XMAX_ + #warning "Note: Auto-assigned W_DIAG_PIN to X_MAX_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #elif W_USE_ENDSTOP == _YMIN_ + #warning "Note: Auto-assigned W_DIAG_PIN to Y_MIN_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #elif W_USE_ENDSTOP == _YMAX_ + #warning "Note: Auto-assigned W_DIAG_PIN to Y_MAX_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #elif W_USE_ENDSTOP == _ZMIN_ + #warning "Note: Auto-assigned W_DIAG_PIN to Z_MIN_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #elif W_USE_ENDSTOP == _ZMAX_ + #warning "Note: Auto-assigned W_DIAG_PIN to Z_MAX_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #elif W_USE_ENDSTOP == _XDIAG_ + #warning "Note: Auto-assigned W_DIAG_PIN to X_DIAG_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #elif W_USE_ENDSTOP == _YDIAG_ + #warning "Note: Auto-assigned W_DIAG_PIN to Y_DIAG_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #elif W_USE_ENDSTOP == _ZDIAG_ + #warning "Note: Auto-assigned W_DIAG_PIN to Z_DIAG_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #elif W_USE_ENDSTOP == _E0DIAG_ + #warning "Note: Auto-assigned W_DIAG_PIN to E0_DIAG_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #elif W_USE_ENDSTOP == _E1DIAG_ + #warning "Note: Auto-assigned W_DIAG_PIN to E1_DIAG_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #elif W_USE_ENDSTOP == _E2DIAG_ + #warning "Note: Auto-assigned W_DIAG_PIN to E2_DIAG_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #elif W_USE_ENDSTOP == _E3DIAG_ + #warning "Note: Auto-assigned W_DIAG_PIN to E3_DIAG_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #elif W_USE_ENDSTOP == _E4DIAG_ + #warning "Note: Auto-assigned W_DIAG_PIN to E4_DIAG_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #elif W_USE_ENDSTOP == _E5DIAG_ + #warning "Note: Auto-assigned W_DIAG_PIN to E5_DIAG_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #elif W_USE_ENDSTOP == _E6DIAG_ + #warning "Note: Auto-assigned W_DIAG_PIN to E6_DIAG_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #elif W_USE_ENDSTOP == _E7DIAG_ + #warning "Note: Auto-assigned W_DIAG_PIN to E7_DIAG_PIN. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" + #endif + #endif + #if ENABLED(CHAMBER_FAN) && !defined(CHAMBER_FAN_INDEX) #warning "Note: Auto-assigned CHAMBER_FAN_INDEX to the first free FAN pin. (Define NO_AUTO_ASSIGN_WARNING to suppress this warning.)" #endif @@ -574,6 +731,10 @@ #warning "Contrast cannot be changed when LCD_CONTRAST_MIN >= LCD_CONTRAST_MAX." #endif +#if PROGRESS_MSG_EXPIRE > 0 && HAS_STATUS_MESSAGE_TIMEOUT + #warning "It is recommended not to combine PROGRESS_MSG_EXPIRE with STATUS_MESSAGE_TIMEOUT_SEC." +#endif + /** * FYSETC backlighting */ diff --git a/Marlin/src/lcd/dogm/dogm_Statusscreen.h b/Marlin/src/lcd/dogm/dogm_Statusscreen.h index f17dd06365..8d0ab4efbe 100644 --- a/Marlin/src/lcd/dogm/dogm_Statusscreen.h +++ b/Marlin/src/lcd/dogm/dogm_Statusscreen.h @@ -37,6 +37,7 @@ #undef STATUS_HEATERS_X #undef STATUS_BED_X + /** * Custom _Statusscreen.h files can define: * - A custom logo image diff --git a/Marlin/src/lcd/dogm/status/combined.h b/Marlin/src/lcd/dogm/status/combined.h index ca18f21af6..070fe6b027 100644 --- a/Marlin/src/lcd/dogm/status/combined.h +++ b/Marlin/src/lcd/dogm/status/combined.h @@ -37,6 +37,7 @@ #if HOTENDS == 0 #define STATUS_HEATERS_WIDTH 96 + #define STATUS_BED_X 74 const unsigned char status_heaters_bmp[] PROGMEM = { B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000100,B00010000,B01000000, @@ -56,6 +57,7 @@ #elif HOTENDS == 1 #define STATUS_HEATERS_WIDTH 96 + #define STATUS_BED_X 74 const unsigned char status_heaters_bmp[] PROGMEM = { B00011111,B11100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000100,B00010000,B01000000, @@ -75,6 +77,7 @@ #elif HOTENDS == 2 #define STATUS_HEATERS_WIDTH 96 + #define STATUS_BED_X 74 const unsigned char status_heaters_bmp[] PROGMEM = { B00011111,B11100000,B00000000,B00011111,B11100000,B00000000,B00000000,B00000000,B00000000,B00000100,B00010000,B01000000, @@ -104,6 +107,7 @@ #elif HOTENDS == 3 #define STATUS_HEATERS_WIDTH 96 + #define STATUS_BED_X 74 const unsigned char status_heaters_bmp[] PROGMEM = { B00011111,B11100000,B00000000,B00011111,B11100000,B00000000,B00011111,B11100000,B00000000,B00000100,B00010000,B01000000, @@ -133,6 +137,7 @@ #else // HOTENDS > 3 #define STATUS_HEATERS_WIDTH 120 + #define STATUS_BED_X 98 const unsigned char status_heaters_bmp[] PROGMEM = { B00011111,B11100000,B00000000,B00011111,B11100000,B00000000,B00011111,B11100000,B00000000,B00011111,B11100000,B00000000,B00000100,B00010000,B01000000, @@ -161,7 +166,8 @@ #endif // HOTENDS - #define STATUS_BED_TEXT_X (STATUS_HEATERS_WIDTH - 10) + #define STATUS_BED_WIDTH 20 + #define STATUS_BED_TEXT_X (STATUS_BED_X + STATUS_BED_WIDTH / 2) #else // !HAS_HEATED_BED || HOTENDS > 3 diff --git a/Marlin/src/lcd/e3v2/common/dwin_api.cpp b/Marlin/src/lcd/e3v2/common/dwin_api.cpp index f6780bba6c..89d7cb4144 100644 --- a/Marlin/src/lcd/e3v2/common/dwin_api.cpp +++ b/Marlin/src/lcd/e3v2/common/dwin_api.cpp @@ -25,6 +25,7 @@ #include "dwin_api.h" #include "dwin_set.h" +#include "dwin_font.h" #include "../../../inc/MarlinConfig.h" @@ -89,6 +90,40 @@ bool DWIN_Handshake() { } #endif +// Get font character width +uint8_t fontWidth(uint8_t cfont) { + switch (cfont) { + case font6x12 : return 6; + case font8x16 : return 8; + case font10x20: return 10; + case font12x24: return 12; + case font14x28: return 14; + case font16x32: return 16; + case font20x40: return 20; + case font24x48: return 24; + case font28x56: return 28; + case font32x64: return 32; + default: return 0; + } +} + +// Get font character height +uint8_t fontHeight(uint8_t cfont) { + switch (cfont) { + case font6x12 : return 12; + case font8x16 : return 16; + case font10x20: return 20; + case font12x24: return 24; + case font14x28: return 28; + case font16x32: return 32; + case font20x40: return 40; + case font24x48: return 48; + case font28x56: return 56; + case font32x64: return 64; + default: return 0; + } +} + // Set screen display direction // dir: 0=0°, 1=90°, 2=180°, 3=270° void DWIN_Frame_SetDir(uint8_t dir) { @@ -199,6 +234,8 @@ void DWIN_Frame_AreaMove(uint8_t mode, uint8_t dir, uint16_t dis, // *string: The string // rlimit: To limit the drawn string length void DWIN_Draw_String(bool bShow, uint8_t size, uint16_t color, uint16_t bColor, uint16_t x, uint16_t y, const char * const string, uint16_t rlimit/*=0xFFFF*/) { + DWIN_Draw_Rectangle(1, bColor, x, y, x + (fontWidth(size) * strlen_P(string)), y + fontHeight(size)); + DWIN_UpdateLCD(); constexpr uint8_t widthAdjust = 0; size_t i = 0; DWIN_Byte(i, 0x11); @@ -213,6 +250,7 @@ void DWIN_Draw_String(bool bShow, uint8_t size, uint16_t color, uint16_t bColor, DWIN_Word(i, y); DWIN_Text(i, string, rlimit); DWIN_Send(i); + DWIN_UpdateLCD(); } // Draw a positive integer @@ -228,6 +266,7 @@ void DWIN_Draw_String(bool bShow, uint8_t size, uint16_t color, uint16_t bColor, void DWIN_Draw_IntValue(uint8_t bShow, bool zeroFill, uint8_t zeroMode, uint8_t size, uint16_t color, uint16_t bColor, uint8_t iNum, uint16_t x, uint16_t y, uint32_t value) { size_t i = 0; + DWIN_Draw_Rectangle(1, bColor, x, y, x + fontWidth(size) * iNum + 1, y + fontHeight(size)); DWIN_Byte(i, 0x14); // Bit 7: bshow // Bit 6: 1 = signed; 0 = unsigned number; @@ -258,6 +297,7 @@ void DWIN_Draw_IntValue(uint8_t bShow, bool zeroFill, uint8_t zeroMode, uint8_t #endif DWIN_Send(i); + DWIN_UpdateLCD(); } // Draw a floating point number @@ -275,6 +315,7 @@ void DWIN_Draw_FloatValue(uint8_t bShow, bool zeroFill, uint8_t zeroMode, uint8_ uint16_t bColor, uint8_t iNum, uint8_t fNum, uint16_t x, uint16_t y, int32_t value) { //uint8_t *fvalue = (uint8_t*)&value; size_t i = 0; + DWIN_Draw_Rectangle(1, bColor, x, y, x + fontWidth(size) * (iNum+fNum+1), y + fontHeight(size)); DWIN_Byte(i, 0x14); DWIN_Byte(i, (bShow * 0x80) | (zeroFill * 0x20) | (zeroMode * 0x10) | size); DWIN_Word(i, color); @@ -291,6 +332,7 @@ void DWIN_Draw_FloatValue(uint8_t bShow, bool zeroFill, uint8_t zeroMode, uint8_ DWIN_Byte(i, fvalue[0]); */ DWIN_Send(i); + DWIN_UpdateLCD(); } // Draw a floating point number diff --git a/Marlin/src/lcd/e3v2/creality/dwin.cpp b/Marlin/src/lcd/e3v2/creality/dwin.cpp index 7dc06d00f2..05ac38d226 100644 --- a/Marlin/src/lcd/e3v2/creality/dwin.cpp +++ b/Marlin/src/lcd/e3v2/creality/dwin.cpp @@ -4281,7 +4281,7 @@ void DWIN_HandleScreen() { } } -void DWIN_CompletedHoming() { +void DWIN_HomingDone() { HMI_flag.home_flag = false; dwin_zoffset = TERN0(HAS_BED_PROBE, probe.offset.z); if (checkkey == Last_Prepare) { @@ -4297,7 +4297,7 @@ void DWIN_CompletedHoming() { } } -void DWIN_CompletedLeveling() { +void DWIN_LevelingDone() { if (checkkey == Leveling) Goto_MainMenu(); } diff --git a/Marlin/src/lcd/e3v2/creality/dwin.h b/Marlin/src/lcd/e3v2/creality/dwin.h index 3ccb70e52f..487f309ed9 100644 --- a/Marlin/src/lcd/e3v2/creality/dwin.h +++ b/Marlin/src/lcd/e3v2/creality/dwin.h @@ -243,7 +243,7 @@ void DWIN_HandleScreen(); void DWIN_StatusChanged(const char * const cstr=nullptr); void DWIN_StatusChanged(FSTR_P const fstr); -inline void DWIN_StartHoming() { HMI_flag.home_flag = true; } +inline void DWIN_HomingStart() { HMI_flag.home_flag = true; } -void DWIN_CompletedHoming(); -void DWIN_CompletedLeveling(); +void DWIN_HomingDone(); +void DWIN_LevelingDone(); diff --git a/Marlin/src/lcd/e3v2/jyersui/dwin.cpp b/Marlin/src/lcd/e3v2/jyersui/dwin.cpp index 1e70a0656c..afe34ac450 100644 --- a/Marlin/src/lcd/e3v2/jyersui/dwin.cpp +++ b/Marlin/src/lcd/e3v2/jyersui/dwin.cpp @@ -958,8 +958,8 @@ void CrealityDWINClass::Update_Status_Bar(bool refresh/*=false*/) { static bool new_msg; static uint8_t msgscrl = 0; static char lastmsg[64]; - if (strcmp_P(lastmsg, statusmsg) != 0 || refresh) { - strcpy_P(lastmsg, statusmsg); + if (strcmp(lastmsg, statusmsg) != 0 || refresh) { + strcpy(lastmsg, statusmsg); msgscrl = 0; new_msg = true; } @@ -3415,7 +3415,7 @@ void CrealityDWINClass::Menu_Item_Handler(uint8_t menu, uint8_t item, bool draw/ Draw_Menu_Item(row, ICON_Back, F("Back")); else { set_bed_leveling_enabled(level_state); - TERN_(AUTO_BED_LEVELING_BILINEAR, refresh_bed_level()); + TERN_(AUTO_BED_LEVELING_BILINEAR, bbl.refresh_bed_level()); Draw_Menu(Leveling, LEVELING_MANUAL); } break; @@ -4693,10 +4693,7 @@ void CrealityDWINClass::Modify_Option(uint8_t value, const char * const * option /* Main Functions */ void CrealityDWINClass::Update_Status(const char * const text) { - char header[4]; - LOOP_L_N(i, 3) header[i] = text[i]; - header[3] = '\0'; - if (strcmp_P(header, PSTR("")) == 0) { + if (strncmp_P(text, PSTR(""), 3) == 0) { LOOP_L_N(i, _MIN((size_t)LONG_FILENAME_LENGTH, strlen(text))) filename[i] = text[i + 3]; filename[_MIN((size_t)LONG_FILENAME_LENGTH - 1, strlen(text))] = '\0'; Draw_Print_Filename(true); @@ -4720,10 +4717,10 @@ void CrealityDWINClass::Start_Print(bool sd) { card.selectFileByName(fname); } #endif - strcpy_P(filename, card.longest_filename()); + strcpy(filename, card.longest_filename()); } else - strcpy_P(filename, "Host Print"); + strcpy_P(filename, PSTR("Host Print")); TERN_(LCD_SET_PROGRESS_MANUALLY, ui.set_progress(0)); TERN_(USE_M73_REMAINING_TIME, ui.set_remaining_time(0)); Draw_Print_Screen(); @@ -4918,18 +4915,10 @@ void CrealityDWINClass::Screen_Update() { } void CrealityDWINClass::AudioFeedback(const bool success/*=true*/) { - if (success) { - if (ui.buzzer_enabled) { - BUZZ(100, 659); - BUZZ( 10, 0); - BUZZ(100, 698); - } - else Update_Status("Success"); - } - else if (ui.buzzer_enabled) - BUZZ(40, 440); + if (ui.buzzer_enabled) + DONE_BUZZ(success); else - Update_Status("Failed"); + Update_Status(success ? "Success" : "Failed"); } void CrealityDWINClass::Save_Settings(char *buff) { diff --git a/Marlin/src/lcd/e3v2/marlinui/dwin_lcd.cpp b/Marlin/src/lcd/e3v2/marlinui/dwin_lcd.cpp index a4cefe4ab9..7154270bff 100644 --- a/Marlin/src/lcd/e3v2/marlinui/dwin_lcd.cpp +++ b/Marlin/src/lcd/e3v2/marlinui/dwin_lcd.cpp @@ -45,8 +45,8 @@ void DWIN_Startup() { const bool success = DWIN_Handshake(); if (success) DEBUG_ECHOLNPGM("ok."); else DEBUG_ECHOLNPGM("error."); DWIN_Frame_SetDir(TERN(DWIN_MARLINUI_LANDSCAPE, 0, 1)); - DWIN_JPG_ShowAndCache(3); DWIN_Frame_Clear(Color_Bg_Black); // MarlinUI handles the bootscreen so just clear here + DWIN_JPG_ShowAndCache(3); DWIN_UpdateLCD(); } diff --git a/Marlin/src/lcd/e3v2/marlinui/ui_common.cpp b/Marlin/src/lcd/e3v2/marlinui/ui_common.cpp index f49d06d396..4e0174705e 100644 --- a/Marlin/src/lcd/e3v2/marlinui/ui_common.cpp +++ b/Marlin/src/lcd/e3v2/marlinui/ui_common.cpp @@ -84,6 +84,7 @@ void MarlinUI::init_lcd() { DWIN_Startup(); } // This LCD should clear where it will draw anew void MarlinUI::clear_lcd() { DWIN_ICON_AnimationControl(0x0000); // disable all icon animations + DWIN_JPG_ShowAndCache(3); DWIN_Frame_Clear(Color_Bg_Black); DWIN_UpdateLCD(); @@ -93,29 +94,39 @@ void MarlinUI::clear_lcd() { #if ENABLED(SHOW_BOOTSCREEN) void MarlinUI::show_bootscreen() { - clear_lcd(); dwin_string.set(F(SHORT_BUILD_VERSION)); + #if ENABLED(SHOW_CUSTOM_BOOTSCREEN) && !defined(CUSTOM_BOOTSCREEN_TIMEOUT) + #define CUSTOM_BOOTSCREEN_TIMEOUT 3000 + #endif + #if ENABLED(DWIN_MARLINUI_PORTRAIT) #define LOGO_CENTER ((LCD_PIXEL_WIDTH) / 2) #define INFO_CENTER LOGO_CENTER #define VERSION_Y 330 - DWIN_ICON_Show(BOOT_ICON, ICON_MarlinBoot, LOGO_CENTER - 266 / 2, 15); + #else + #define LOGO_CENTER (280 / 2) + #define INFO_CENTER ((LCD_PIXEL_WIDTH) - 200 / 2) + #define VERSION_Y 84 + #endif + + DWIN_Draw_String(false, font10x20, Color_Yellow, Color_Bg_Black, INFO_CENTER - (dwin_string.length() * 10) / 2, VERSION_Y, S(dwin_string.string())); + TERN_(SHOW_CUSTOM_BOOTSCREEN, safe_delay(CUSTOM_BOOTSCREEN_TIMEOUT)); + clear_lcd(); + + DWIN_ICON_Show(BOOT_ICON, ICON_MarlinBoot, LOGO_CENTER - 266 / 2, 15); + #if ENABLED(DWIN_MARLINUI_PORTRAIT) DWIN_ICON_Show(BOOT_ICON, ICON_OpenSource, LOGO_CENTER - 174 / 2, 280); DWIN_ICON_Show(BOOT_ICON, ICON_GitHubURL, LOGO_CENTER - 180 / 2, 420); DWIN_ICON_Show(BOOT_ICON, ICON_MarlinURL, LOGO_CENTER - 100 / 2, 440); DWIN_ICON_Show(BOOT_ICON, ICON_Copyright, LOGO_CENTER - 126 / 2, 460); #else - #define LOGO_CENTER (280 / 2) - #define INFO_CENTER ((LCD_PIXEL_WIDTH) - 200 / 2) - #define VERSION_Y 84 DWIN_ICON_Show(BOOT_ICON, ICON_MarlinBoot, LOGO_CENTER - 266 / 2, 15); DWIN_ICON_Show(BOOT_ICON, ICON_OpenSource, INFO_CENTER - 174 / 2, 60); DWIN_ICON_Show(BOOT_ICON, ICON_GitHubURL, INFO_CENTER - 180 / 2, 130); DWIN_ICON_Show(BOOT_ICON, ICON_MarlinURL, INFO_CENTER - 100 / 2, 152); DWIN_ICON_Show(BOOT_ICON, ICON_Copyright, INFO_CENTER - 126 / 2, 200); #endif - DWIN_Draw_String(false, font10x20, Color_Yellow, Color_Bg_Black, INFO_CENTER - (dwin_string.length() * 10) / 2, VERSION_Y, S(dwin_string.string())); DWIN_UpdateLCD(); } @@ -170,6 +181,7 @@ void MarlinUI::draw_status_message(const bool blink) { dwin_font.solid = true; dwin_font.fg = Color_White; dwin_font.bg = Color_Bg_Black; + DWIN_Draw_Box(1, Color_Bg_Black, 0, (LCD_PIXEL_HEIGHT - (STAT_FONT_HEIGHT) - 1), 272, STAT_FONT_HEIGHT + 1); lcd_moveto_xy(0, LCD_PIXEL_HEIGHT - (STAT_FONT_HEIGHT) - 1); constexpr uint8_t max_status_chars = (LCD_PIXEL_WIDTH) / (STAT_FONT_WIDTH); diff --git a/Marlin/src/lcd/e3v2/marlinui/ui_status_480x272.cpp b/Marlin/src/lcd/e3v2/marlinui/ui_status_480x272.cpp index c2948048c1..2a4909d921 100644 --- a/Marlin/src/lcd/e3v2/marlinui/ui_status_480x272.cpp +++ b/Marlin/src/lcd/e3v2/marlinui/ui_status_480x272.cpp @@ -193,11 +193,11 @@ FORCE_INLINE void _draw_heater_status(const heater_id_t heater, const uint16_t x #define HOTEND_STATS 3 #elif HOTENDS > 1 #define HOTEND_STATS 2 - #elif HAS_HOTEND + #else #define HOTEND_STATS 1 #endif static celsius_t old_temp[HOTEND_STATS] = ARRAY_N_1(HOTEND_STATS, 500), - old_target[HOTEND_STATS] = ARRAY_N_1(HOTEND_STATS, 500); + old_target[HOTEND_STATS] = ARRAY_N_1(HOTEND_STATS, 500); static bool old_on[HOTEND_STATS] = ARRAY_N_1(HOTEND_STATS, false); #endif @@ -210,25 +210,27 @@ FORCE_INLINE void _draw_heater_status(const heater_id_t heater, const uint16_t x #endif #if HAS_HOTEND && HAS_HEATED_BED + float tc, tt; + bool c_draw, t_draw, i_draw, ta; const bool isBed = heater < 0; - const float tc = isBed ? thermalManager.degBed() : thermalManager.degHotend(heater), - tt = isBed ? thermalManager.degTargetBed() : thermalManager.degTargetHotend(heater); - const bool ta = isBed ? thermalManager.isHeatingBed() : thermalManager.isHeatingHotend(heater); - - bool c_draw = tc != (isBed ? old_bed_temp : old_temp[heater]), - t_draw = tt != (isBed ? old_bed_target : old_target[heater]), - i_draw = ta != (isBed ? old_bed_on : old_on[heater]); - if (isBed) { - #if HAS_LEVELING - if (!i_draw && planner.leveling_active != old_leveling_on) i_draw = true; - old_leveling_on = planner.leveling_active; - #endif + tc = thermalManager.degBed(); + tt = thermalManager.degTargetBed(); + ta = thermalManager.isHeatingBed(); + c_draw = tc != old_bed_temp; + t_draw = tt != old_bed_target; + i_draw = ta != old_bed_on; old_bed_temp = tc; old_bed_target = tt; old_bed_on = ta; } else { + tc = thermalManager.degHotend(heater); + tt = thermalManager.degTargetHotend(heater); + ta = thermalManager.isHeatingHotend(heater); + c_draw = tc != old_temp[heater]; + t_draw = tt != old_target[heater]; + i_draw = ta != old_on[heater]; old_temp[heater] = tc; old_target[heater] = tt; old_on[heater] = ta; @@ -237,31 +239,41 @@ FORCE_INLINE void _draw_heater_status(const heater_id_t heater, const uint16_t x constexpr bool isBed = false; const float tc = thermalManager.degHotend(heater), tt = thermalManager.degTargetHotend(heater); const uint8_t ta = thermalManager.isHeatingHotend(heater); - const bool c_draw = tc != old_bed_temp, t_draw = tt != old_bed_target, i_draw = ta != old_bed_on; + bool c_draw = tc != old_temp[heater], t_draw = tt != old_target[heater], i_draw = ta != old_on[heater]; old_temp[heater] = tc; old_target[heater] = tt; old_on[heater] = ta; #elif HAS_HEATED_BED constexpr bool isBed = true; const float tc = thermalManager.degBed(), tt = thermalManager.degTargetBed(); const uint8_t ta = thermalManager.isHeatingBed(); - bool c_draw = tc != old_temp[heater], t_draw = tt != old_target[heater], i_draw = ta != old_on[heater]; - #if HAS_LEVELING - if (!idraw && planner.leveling_active != old_leveling_on) i_draw = true; - old_leveling_on = tl; - #endif + bool c_draw = tc != old_bed_temp, t_draw = tt != old_bed_target, i_draw = ta != old_bed_on; old_bed_temp = tc; old_bed_target = tt; old_bed_on = ta; + #else + bool c_draw = false, t_draw = false, i_draw = false; + constexpr float tc = 0, tt = 0; + constexpr uint8_t ta = 0; #endif + #if HAS_HEATED_BED && HAS_LEVELING + if (isBed) { + i_draw |= (planner.leveling_active != old_leveling_on); + old_leveling_on = planner.leveling_active; + } + #endif + + // Draw target temperature, if needed if (!ui.did_first_redraw || t_draw) { dwin_string.set(i16tostr3rj(tt + 0.5)); dwin_string.add(LCD_STR_DEGREE); DWIN_Draw_String(true, font14x28, Color_White, Color_Bg_Black, x, y, S(dwin_string.string())); } - if (!ui.did_first_redraw || i_draw){ + // Draw heater icon with on / off / leveled states + if (!ui.did_first_redraw || i_draw) { const uint8_t ico = isBed ? (TERN0(HAS_LEVELING, planner.leveling_active) ? ICON_BedLevelOff : ICON_BedOff) : ICON_HotendOff; DWIN_ICON_Show(ICON, ico + ta, x, y + STATUS_CHR_HEIGHT + 2); } + // Draw current temperature, if needed if (!ui.did_first_redraw || c_draw) { dwin_string.set(i16tostr3rj(tc + 0.5)); dwin_string.add(LCD_STR_DEGREE); @@ -412,43 +424,45 @@ void MarlinUI::draw_status_screen() { // // Progress Bar // - constexpr int16_t pb_margin = 5, - pb_left = pb_margin + TERN(DWIN_MARLINUI_PORTRAIT, 0, 90), - pb_height = TERN(DWIN_MARLINUI_PORTRAIT, 60, 20), - pb_right = LCD_PIXEL_WIDTH - pb_margin, - pb_bottom = TERN(DWIN_MARLINUI_PORTRAIT, 410, 220), - pb_top = pb_bottom - pb_height, - pb_width = pb_right - pb_left; + #if HAS_PRINT_PROGRESS + constexpr int16_t pb_margin = 5, + pb_left = pb_margin + TERN(DWIN_MARLINUI_PORTRAIT, 0, 90), + pb_height = TERN(DWIN_MARLINUI_PORTRAIT, 60, 20), + pb_right = LCD_PIXEL_WIDTH - pb_margin, + pb_bottom = TERN(DWIN_MARLINUI_PORTRAIT, 410, 220), + pb_top = pb_bottom - pb_height, + pb_width = pb_right - pb_left; - const progress_t progress = TERN(HAS_PRINT_PROGRESS_PERMYRIAD, get_progress_permyriad, get_progress_percent)(); + const progress_t progress = TERN(HAS_PRINT_PROGRESS_PERMYRIAD, get_progress_permyriad, get_progress_percent)(); - if (!ui.did_first_redraw) - DWIN_Draw_Rectangle(0, Select_Color, pb_left, pb_top, pb_right, pb_bottom); // Outline + if (!ui.did_first_redraw) + DWIN_Draw_Rectangle(0, Select_Color, pb_left, pb_top, pb_right, pb_bottom); // Outline - static uint16_t old_solid = 50; - const uint16_t pb_solid = (pb_width - 2) * (progress / (PROGRESS_SCALE)) * 0.01f; - const bool p_draw = !ui.did_first_redraw || old_solid != pb_solid; + static uint16_t old_solid = 50; + const uint16_t pb_solid = (pb_width - 2) * (progress / (PROGRESS_SCALE)) * 0.01f; + const bool p_draw = !ui.did_first_redraw || old_solid != pb_solid; - if (p_draw) { - //if (pb_solid) - DWIN_Draw_Rectangle(1, Select_Color, pb_left + 1, pb_top + 1, pb_left + pb_solid, pb_bottom - 1); // Fill the solid part + if (p_draw) { + //if (pb_solid) + DWIN_Draw_Rectangle(1, Select_Color, pb_left + 1, pb_top + 1, pb_left + pb_solid, pb_bottom - 1); // Fill the solid part - //if (pb_solid < old_solid) - DWIN_Draw_Rectangle(1, Color_Bg_Black, pb_left + 1 + pb_solid, pb_top + 1, pb_right - 1, pb_bottom - 1); // Erase the rest + //if (pb_solid < old_solid) + DWIN_Draw_Rectangle(1, Color_Bg_Black, pb_left + 1 + pb_solid, pb_top + 1, pb_right - 1, pb_bottom - 1); // Erase the rest - #if ENABLED(SHOW_SD_PERCENT) - dwin_string.set(TERN(PRINT_PROGRESS_SHOW_DECIMALS, permyriadtostr4(progress), ui8tostr3rj(progress / (PROGRESS_SCALE)))); - dwin_string.add(PSTR("%")); - DWIN_Draw_String( - false, font16x32, Percent_Color, Color_Bg_Black, - pb_left + (pb_width - dwin_string.length() * 16) / 2, - pb_top + (pb_height - 32) / 2, - S(dwin_string.string()) - ); - #endif + #if ENABLED(SHOW_SD_PERCENT) + dwin_string.set(TERN(PRINT_PROGRESS_SHOW_DECIMALS, permyriadtostr4(progress), ui8tostr3rj(progress / (PROGRESS_SCALE)))); + dwin_string.add(PSTR("%")); + DWIN_Draw_String( + false, font16x32, Percent_Color, Color_Bg_Black, + pb_left + (pb_width - dwin_string.length() * 16) / 2, + pb_top + (pb_height - 32) / 2, + S(dwin_string.string()) + ); + #endif - old_solid = pb_solid; - } + old_solid = pb_solid; + } + #endif // HAS_PRINT_PROGRESS // // Status Message diff --git a/Marlin/src/lcd/e3v2/proui/dwin.cpp b/Marlin/src/lcd/e3v2/proui/dwin.cpp index 93302406d4..8c4dfb6d74 100644 --- a/Marlin/src/lcd/e3v2/proui/dwin.cpp +++ b/Marlin/src/lcd/e3v2/proui/dwin.cpp @@ -1285,17 +1285,7 @@ void HMI_Printing() { #include "../../../libs/buzzer.h" -void HMI_AudioFeedback(const bool success/*=true*/) { - #if HAS_BUZZER - if (success) { - BUZZ(100, 659); - BUZZ(10, 0); - BUZZ(100, 698); - } - else - BUZZ(40, 440); - #endif -} +void HMI_AudioFeedback(const bool success/*=true*/) { DONE_BUZZ(success); } void Draw_Main_Area() { switch (checkkey) { @@ -1542,20 +1532,20 @@ void HMI_SaveProcessID(const uint8_t id) { } } -void DWIN_StartHoming() { +void DWIN_HomingStart() { HMI_flag.home_flag = true; HMI_SaveProcessID(Homing); Title.ShowCaption(GET_TEXT_F(MSG_HOMING)); DWIN_Show_Popup(ICON_BLTouch, GET_TEXT_F(MSG_HOMING), GET_TEXT_F(MSG_PLEASE_WAIT)); } -void DWIN_CompletedHoming() { +void DWIN_HomingDone() { HMI_flag.home_flag = false; dwin_zoffset = TERN0(HAS_BED_PROBE, probe.offset.z); if (HMI_flag.abort_action) DWIN_Print_Aborted(); else HMI_ReturnScreen(); } -void DWIN_MeshLevelingStart() { +void DWIN_LevelingStart() { #if HAS_ONESTEP_LEVELING HMI_SaveProcessID(Leveling); Title.ShowCaption(GET_TEXT_F(MSG_BED_LEVELING)); @@ -1565,7 +1555,7 @@ void DWIN_MeshLevelingStart() { #endif } -void DWIN_CompletedLeveling() { +void DWIN_LevelingDone() { TERN_(HAS_ONESTEP_LEVELING, if (planner.leveling_active) Goto_MeshViewer()); } @@ -2312,7 +2302,7 @@ TERN(HAS_ONESTEP_LEVELING, float, void) Tram(uint8_t point) { inLev = true; zval = probe.probe_at_point(xpos, ypos, PROBE_PT_STOW); if (isnan(zval)) - ui.set_status(F("Position Not Reachable, check offsets")); + LCD_MESSAGE_F("Position Not Reachable, check offsets"); else { sprintf_P(cmd, PSTR("X:%s, Y:%s, Z:%s"), dtostrf(xpos, 1, 1, str_1), @@ -2344,7 +2334,7 @@ void TramC () { Tram(4); } void Trammingwizard() { bed_mesh_t zval = {0}; if (HMI_data.FullManualTramming) { - ui.set_status(F("Disable manual tramming")); + LCD_MESSAGE_F("Disable manual tramming"); return; } zval[0][0] = Tram(0); diff --git a/Marlin/src/lcd/e3v2/proui/dwin.h b/Marlin/src/lcd/e3v2/proui/dwin.h index 9f49fa1825..b61ed846df 100644 --- a/Marlin/src/lcd/e3v2/proui/dwin.h +++ b/Marlin/src/lcd/e3v2/proui/dwin.h @@ -142,13 +142,13 @@ void update_variable(); void DWIN_InitScreen(); void DWIN_HandleScreen(); void DWIN_CheckStatusMessage(); -void DWIN_StartHoming(); -void DWIN_CompletedHoming(); +void DWIN_HomingStart(); +void DWIN_HomingDone(); #if HAS_MESH void DWIN_MeshUpdate(const int8_t xpos, const int8_t ypos, const_float_t zval); #endif -void DWIN_MeshLevelingStart(); -void DWIN_CompletedLeveling(); +void DWIN_LevelingStart(); +void DWIN_LevelingDone(); void DWIN_PidTuning(pidresult_t result); void DWIN_Print_Started(const bool sd=false); void DWIN_Print_Pause(); diff --git a/Marlin/src/lcd/e3v2/proui/endstop_diag.cpp b/Marlin/src/lcd/e3v2/proui/endstop_diag.cpp index 2e4ab6a79c..4c2e4fa200 100644 --- a/Marlin/src/lcd/e3v2/proui/endstop_diag.cpp +++ b/Marlin/src/lcd/e3v2/proui/endstop_diag.cpp @@ -21,15 +21,19 @@ */ /** - * DWIN End Stops diagnostic page for PRO UI + * DWIN Endstops diagnostic page for PRO UI * Author: Miguel A. Risco-Castillo (MRISCOC) * Version: 1.2.2 * Date: 2022/02/24 */ +#include "../../../inc/MarlinConfigPre.h" + +#if ENABLED(DWIN_LCD_PROUI) + #include "dwin_defines.h" -#if BOTH(DWIN_LCD_PROUI, HAS_ESDIAG) +#if HAS_ESDIAG #include "endstop_diag.h" @@ -105,4 +109,5 @@ void ESDiagClass::Update() { DWIN_UpdateLCD(); } -#endif // DWIN_LCD_PROUI && HAS_ESDIAG +#endif // HAS_ESDIAG +#endif // DWIN_LCD_PROUI diff --git a/Marlin/src/lcd/extui/anycubic_chiron/FileNavigator.cpp b/Marlin/src/lcd/extui/anycubic_chiron/FileNavigator.cpp index f49b17acc1..0ef8186668 100644 --- a/Marlin/src/lcd/extui/anycubic_chiron/FileNavigator.cpp +++ b/Marlin/src/lcd/extui/anycubic_chiron/FileNavigator.cpp @@ -155,7 +155,7 @@ void FileNavigator::skiptofileindex(uint16_t skip) { if (currentindex == 0 && currentfolderdepth > 0) { // Add a link to go up a folder // The new panel ignores entries that don't end in .GCO or .gcode so add and pad them. - if (paneltype == AC_panel_new) { + if (paneltype <= AC_panel_new) { TFTSer.println("<<.GCO"); Chiron.SendtoTFTLN(F(".. .gcode")); } @@ -177,7 +177,7 @@ void FileNavigator::skiptofileindex(uint16_t skip) { void FileNavigator::sendFile(panel_type_t paneltype) { if (filelist.isDir()) { // Add mandatory tags for new panel otherwise lines are ignored. - if (paneltype == AC_panel_new) { + if (paneltype <= AC_panel_new) { TFTSer.print(filelist.shortFilename()); TFTSer.println(".GCO"); TFTSer.print(filelist.shortFilename()); diff --git a/Marlin/src/lcd/extui/anycubic_chiron/chiron_extui.cpp b/Marlin/src/lcd/extui/anycubic_chiron/chiron_extui.cpp index 7a58963c11..75061c162a 100644 --- a/Marlin/src/lcd/extui/anycubic_chiron/chiron_extui.cpp +++ b/Marlin/src/lcd/extui/anycubic_chiron/chiron_extui.cpp @@ -57,14 +57,16 @@ namespace ExtUI { void onPrintTimerStarted() { Chiron.TimerEvent(AC_timer_started); } void onPrintTimerPaused() { Chiron.TimerEvent(AC_timer_paused); } - void onPrintTimerStopped() { Chiron.TimerEvent(AC_timer_stopped); } + void onPrintTimerStopped() { Chiron.TimerEvent(AC_timer_stopped); } + void onPrintDone() {} + void onFilamentRunout(const extruder_t) { Chiron.FilamentRunout(); } + void onUserConfirmRequired(const char * const msg) { Chiron.ConfirmationRequest(msg); } void onStatusChanged(const char * const msg) { Chiron.StatusChange(msg); } void onHomingStart() {} - void onHomingComplete() {} - void onPrintFinished() {} + void onHomingDone() {} void onFactoryReset() {} @@ -92,18 +94,19 @@ namespace ExtUI { // Called after loading or resetting stored settings } - void onConfigurationStoreWritten(bool success) { + void onSettingsStored(bool success) { // Called after the entire EEPROM has been written, // whether successful or not. } - void onConfigurationStoreRead(bool success) { + void onSettingsLoaded(bool success) { // Called after the entire EEPROM has been read, // whether successful or not. } #if HAS_MESH - void onMeshLevelingStart() {} + void onLevelingStart() {} + void onLevelingDone() {} void onMeshUpdate(const int8_t xpos, const int8_t ypos, const_float_t zval) { // Called when any mesh points are updated diff --git a/Marlin/src/lcd/extui/anycubic_chiron/chiron_tft.cpp b/Marlin/src/lcd/extui/anycubic_chiron/chiron_tft.cpp index c56d8aa7fb..b2ef733355 100644 --- a/Marlin/src/lcd/extui/anycubic_chiron/chiron_tft.cpp +++ b/Marlin/src/lcd/extui/anycubic_chiron/chiron_tft.cpp @@ -80,19 +80,26 @@ void ChironTFT::Startup() { OUT_WRITE(OUTAGECON_PIN, HIGH); #endif - // Filament runout is handled by Marlin settings in Configuration.h - // opt_set FIL_RUNOUT_STATE HIGH // Pin state indicating that filament is NOT present. - // opt_enable FIL_RUNOUT_PULLUP TFTSer.begin(115200); - // wait for the TFT panel to initialise and finish the animation - delay_ms(250); + // Wait for the TFT panel to initialize and finish the animation + safe_delay(1000); // There are different panels for the Chiron with slightly different commands // So we need to know what we are working with. - // Panel type can be defined otherwise detect it automatically - if (panel_type == AC_panel_unknown) DetectPanelType(); + switch (panel_type) { + case AC_panel_new: + SERIAL_ECHOLNF(AC_msg_new_panel_set); + break; + case AC_panel_standard: + SERIAL_ECHOLNF(AC_msg_old_panel_set); + break; + default: + SERIAL_ECHOLNF(AC_msg_auto_panel_detection); + DetectPanelType(); + break; + } // Signal Board has reset SendtoTFTLN(AC_msg_main_board_has_reset); @@ -358,15 +365,14 @@ bool ChironTFT::ReadTFTCommand() { } int8_t ChironTFT::FindToken(char c) { - int8_t pos = 0; - do { + for (int8_t pos = 0; pos < command_len; pos++) { if (panel_command[pos] == c) { #if ACDEBUG(AC_INFO) SERIAL_ECHOLNPGM("Tpos:", pos, " ", c); #endif return pos; } - } while (++pos < command_len); + } #if ACDEBUG(AC_INFO) SERIAL_ECHOLNPGM("Not found: ", c); #endif @@ -433,7 +439,7 @@ void ChironTFT::SendFileList(int8_t startindex) { } void ChironTFT::SelectFile() { - if (panel_type == AC_panel_new) { + if (panel_type <= AC_panel_new) { strncpy(selectedfile, panel_command + 4, command_len - 3); selectedfile[command_len - 4] = '\0'; } @@ -456,7 +462,7 @@ void ChironTFT::SelectFile() { break; default: // enter sub folder // for new panel remove the '.GCO' tag that was added to the end of the path - if (panel_type == AC_panel_new) + if (panel_type <= AC_panel_new) selectedfile[strlen(selectedfile) - 4] = '\0'; filenavigator.changeDIR(selectedfile); SendtoTFTLN(AC_msg_sd_file_open_failed); @@ -469,8 +475,8 @@ void ChironTFT::ProcessPanelRequest() { // Break these up into logical blocks // as its easier to navigate than one huge switch case! int8_t tpos = FindToken('A'); // Panel request are 'A0' - 'A36' - if (tpos != -1) { - const int8_t req = atoi(&panel_command[tpos+1]); + if (tpos >= 0) { + const int8_t req = atoi(&panel_command[tpos + 1]); // Information requests A0 - A8 and A33 if (req <= 8 || req == 33) PanelInfo(req); @@ -486,16 +492,18 @@ void ChironTFT::ProcessPanelRequest() { // This may be a response to a panel type detection query if (panel_type == AC_panel_unknown) { tpos = FindToken('S'); // old panel will respond to 'SIZE' with 'SXY 480 320' - if (tpos != -1) { - if (panel_command[tpos+1]== 'X' && panel_command[tpos+2]=='Y') { + if (tpos >= 0) { + if (panel_command[tpos + 1] == 'X' && panel_command[tpos + 2] =='Y') { panel_type = AC_panel_standard; SERIAL_ECHOLNF(AC_msg_old_panel_detected); } } else { - tpos = FindToken('['); // new panel will respond to 'J200' with '[0]=0' - if (tpos != -1) { - if (panel_command[tpos+1]== '0' && panel_command[tpos+2]==']') { + // new panel will respond to 'J200' with '[0]=0' + // it seems only after a power cycle so detection assumes a new panel + tpos = FindToken('['); + if (tpos >= 0) { + if (panel_command[tpos + 1] == '0' && panel_command[tpos + 2] ==']') { panel_type = AC_panel_new; SERIAL_ECHOLNF(AC_msg_new_panel_detected); } @@ -623,18 +631,18 @@ void ChironTFT::PanelAction(uint8_t req) { SelectFile(); break; - case 14: { // A14 Start Printing + case 14: // A14 Start Printing // Allows printer to restart the job if we don't want to recover if (printer_state == AC_printer_resuming_from_power_outage) { injectCommands(F("M1000 C")); // Cancel recovery printer_state = AC_printer_idle; } #if ACDebugLevel >= 1 - SERIAL_ECHOLNPAIR_F("Print: ", selectedfile); + SERIAL_ECHOLNPGM("Print: ", selectedfile); #endif printFile(selectedfile); SendtoTFTLN(AC_msg_print_from_sd_card); - } break; + break; case 15: // A15 Resuming from outage if (printer_state == AC_printer_resuming_from_power_outage) { @@ -801,28 +809,25 @@ void ChironTFT::PanelProcess(uint8_t req) { } } break; - case 30: { // A30 Auto leveling - if (FindToken('S') != -1) { // Start probing New panel adds spaces.. + case 30: // A30 Auto leveling + if (FindToken('S') >= 0) { // Start probing New panel adds spaces.. // Ignore request if printing if (isPrinting()) SendtoTFTLN(AC_msg_probing_not_allowed); // forbid auto leveling else { - - SendtoTFTLN(AC_msg_start_probing); injectCommands(F("G28\nG29")); printer_state = AC_printer_probing; } } - else { + else SendtoTFTLN(AC_msg_start_probing); // Just enter levelling menu - } - } break; + break; - case 31: { // A31 Adjust all Probe Points + case 31: // A31 Adjust all Probe Points // The tokens can occur in different places on the new panel so we need to find it. - if (FindToken('C') != -1) { // Restore and apply original offsets + if (FindToken('C') >= 0) { // Restore and apply original offsets if (!isPrinting()) { injectCommands(F("M501\nM420 S1")); selectedmeshpoint.x = selectedmeshpoint.y = 99; @@ -830,7 +835,7 @@ void ChironTFT::PanelProcess(uint8_t req) { } } - else if (FindToken('D') != -1) { // Save Z Offset tables and restore leveling state + else if (FindToken('D') >= 0) { // Save Z Offset tables and restore leveling state if (!isPrinting()) { setAxisPosition_mm(1.0,Z); // Lift nozzle before any further movements are made injectCommands(F("M500")); @@ -839,7 +844,7 @@ void ChironTFT::PanelProcess(uint8_t req) { } } - else if (FindToken('G') != -1) { // Get current offset + else if (FindToken('G') >= 0) { // Get current offset SendtoTFT(F("A31V ")); // When printing use the live z Offset position // we will use babystepping to move the print head @@ -853,7 +858,7 @@ void ChironTFT::PanelProcess(uint8_t req) { else { int8_t tokenpos = FindToken('S'); - if (tokenpos != -1) { // Set offset (adjusts all points by value) + if (tokenpos >= 0) { // Set offset (adjusts all points by value) float Zshift = atof(&panel_command[tokenpos+1]); setSoftEndstopState(false); // disable endstops // Allow temporary Z position nudging during print @@ -907,18 +912,18 @@ void ChironTFT::PanelProcess(uint8_t req) { } } } - } break; + break; - case 32: { // A32 clean leveling beep flag + case 32: // A32 clean leveling beep flag // Ignore request if printing //if (isPrinting()) break; //injectCommands(F("M500\nM420 S1\nG1 Z10 F240\nG1 X0 Y0 F6000")); //TFTSer.println(); - } break; + break; // A33 firmware info request see PanelInfo() - case 34: { // A34 Adjust single mesh point A34 C/S X1 Y1 V123 + case 34: // A34 Adjust single mesh point A34 C/S X1 Y1 V123 if (panel_command[3] == 'C') { // Restore original offsets injectCommands(F("M501\nM420 S1")); selectedmeshpoint.x = selectedmeshpoint.y = 99; @@ -950,7 +955,7 @@ void ChironTFT::PanelProcess(uint8_t req) { } } } - } break; + break; case 36: // A36 Auto leveling for new TFT bet that was a typo in the panel code! SendtoTFTLN(AC_msg_start_probing); diff --git a/Marlin/src/lcd/extui/anycubic_chiron/chiron_tft_defs.h b/Marlin/src/lcd/extui/anycubic_chiron/chiron_tft_defs.h index 0fd7770cdd..e3609b5408 100644 --- a/Marlin/src/lcd/extui/anycubic_chiron/chiron_tft_defs.h +++ b/Marlin/src/lcd/extui/anycubic_chiron/chiron_tft_defs.h @@ -89,6 +89,10 @@ #define AC_msg_mesh_changes_saved F("Mesh changes saved.") #define AC_msg_old_panel_detected F("Standard TFT panel detected!") #define AC_msg_new_panel_detected F("New TFT panel detected!") +#define AC_msg_auto_panel_detection F("Auto detect panel type (assuming new panel)") +#define AC_msg_old_panel_set F("Set for standard TFT panel.") +#define AC_msg_new_panel_set F("Set for new TFT panel.") + #define AC_msg_powerloss_recovery F("Resuming from power outage! select the same SD file then press resume") // Error messages must not contain spaces #define AC_msg_error_bed_temp F("Abnormal_bed_temp") @@ -161,10 +165,10 @@ namespace Anycubic { AC_menu_change_to_file, AC_menu_change_to_command }; - enum panel_type_t : uint8_t { + enum panel_type_t : uint8_t { // order is important here as we assume new panel if type is unknown AC_panel_unknown, - AC_panel_standard, - AC_panel_new + AC_panel_new, + AC_panel_standard }; enum last_error_t : uint8_t { AC_error_none, diff --git a/Marlin/src/lcd/extui/anycubic_i3mega/anycubic_extui.cpp b/Marlin/src/lcd/extui/anycubic_i3mega/anycubic_extui.cpp index c0e1b44578..469202ee22 100644 --- a/Marlin/src/lcd/extui/anycubic_i3mega/anycubic_extui.cpp +++ b/Marlin/src/lcd/extui/anycubic_i3mega/anycubic_extui.cpp @@ -54,8 +54,8 @@ namespace ExtUI { void onStatusChanged(const char * const msg) {} void onHomingStart() {} - void onHomingComplete() {} - void onPrintFinished() {} + void onHomingDone() {} + void onPrintDone() {} void onFactoryReset() {} @@ -83,19 +83,20 @@ namespace ExtUI { // Called after loading or resetting stored settings } - void onConfigurationStoreWritten(bool success) { + void onSettingsStored(bool success) { // Called after the entire EEPROM has been written, // whether successful or not. } - void onConfigurationStoreRead(bool success) { + void onSettingsLoaded(bool success) { // Called after the entire EEPROM has been read, // whether successful or not. } #if HAS_MESH - void onMeshLevelingStart() {} + void onLevelingStart() {} + void onLevelingDone() {} void onMeshUpdate(const int8_t xpos, const int8_t ypos, const_float_t zval) { // Called when any mesh points are updated diff --git a/Marlin/src/lcd/extui/anycubic_i3mega/anycubic_i3mega_lcd.cpp b/Marlin/src/lcd/extui/anycubic_i3mega/anycubic_i3mega_lcd.cpp index 729d4547a8..c382af3fe2 100644 --- a/Marlin/src/lcd/extui/anycubic_i3mega/anycubic_i3mega_lcd.cpp +++ b/Marlin/src/lcd/extui/anycubic_i3mega/anycubic_i3mega_lcd.cpp @@ -85,7 +85,7 @@ void AnycubicTFTClass::OnSetup() { SENDLINE_DBG_PGM("J17", "TFT Serial Debug: Main board reset... J17"); // J17 Main board reset delay_ms(10); - // initialise the state of the key pins running on the tft + // Init the state of the key pins running on the TFT #if ENABLED(SDSUPPORT) && PIN_EXISTS(SD_DETECT) SET_INPUT_PULLUP(SD_DETECT_PIN); #endif diff --git a/Marlin/src/lcd/extui/dgus/dgus_extui.cpp b/Marlin/src/lcd/extui/dgus/dgus_extui.cpp index 04ba6b95c2..b041687a14 100644 --- a/Marlin/src/lcd/extui/dgus/dgus_extui.cpp +++ b/Marlin/src/lcd/extui/dgus/dgus_extui.cpp @@ -73,8 +73,8 @@ namespace ExtUI { void onStatusChanged(const char * const msg) { ScreenHandler.setstatusmessage(msg); } void onHomingStart() {} - void onHomingComplete() {} - void onPrintFinished() {} + void onHomingDone() {} + void onPrintDone() {} void onFactoryReset() {} @@ -102,18 +102,19 @@ namespace ExtUI { // Called after loading or resetting stored settings } - void onConfigurationStoreWritten(bool success) { + void onSettingsStored(bool success) { // Called after the entire EEPROM has been written, // whether successful or not. } - void onConfigurationStoreRead(bool success) { + void onSettingsLoaded(bool success) { // Called after the entire EEPROM has been read, // whether successful or not. } #if HAS_MESH - void onMeshLevelingStart() {} + void onLevelingStart() {} + void onLevelingDone() {} void onMeshUpdate(const int8_t xpos, const int8_t ypos, const_float_t zval) { // Called when any mesh points are updated diff --git a/Marlin/src/lcd/extui/dgus_reloaded/DGUSTxHandler.cpp b/Marlin/src/lcd/extui/dgus_reloaded/DGUSTxHandler.cpp index 8d57038765..961b29ca22 100644 --- a/Marlin/src/lcd/extui/dgus_reloaded/DGUSTxHandler.cpp +++ b/Marlin/src/lcd/extui/dgus_reloaded/DGUSTxHandler.cpp @@ -286,7 +286,7 @@ void DGUSTxHandler::TempMax(DGUS_VP &vp) { } void DGUSTxHandler::StepperStatus(DGUS_VP &vp) { - const bool motor_on = stepper.axis_enabled.bits & (_BV(LINEAR_AXES) - 1); + const bool motor_on = stepper.axis_enabled.bits & (_BV(NUM_AXES) - 1); dgus_display.Write((uint16_t)vp.addr, Swap16(uint16_t(motor_on ? DGUS_Data::Status::ENABLED : DGUS_Data::Status::DISABLED))); } diff --git a/Marlin/src/lcd/extui/dgus_reloaded/dgus_reloaded_extui.cpp b/Marlin/src/lcd/extui/dgus_reloaded/dgus_reloaded_extui.cpp index 61b072a3f7..f6f2c0f89d 100644 --- a/Marlin/src/lcd/extui/dgus_reloaded/dgus_reloaded_extui.cpp +++ b/Marlin/src/lcd/extui/dgus_reloaded/dgus_reloaded_extui.cpp @@ -83,8 +83,8 @@ namespace ExtUI { } void onHomingStart() {} - void onHomingComplete() {} - void onPrintFinished() {} + void onHomingDone() {} + void onPrintDone() {} void onFactoryReset() { dgus_screen_handler.SettingsReset(); @@ -100,16 +100,17 @@ namespace ExtUI { void onPostprocessSettings() {} - void onConfigurationStoreWritten(bool success) { + void onSettingsStored(bool success) { dgus_screen_handler.ConfigurationStoreWritten(success); } - void onConfigurationStoreRead(bool success) { + void onSettingsLoaded(bool success) { dgus_screen_handler.ConfigurationStoreRead(success); } #if HAS_MESH - void onMeshLevelingStart() {} + void onLevelingStart() {} + void onLevelingDone() {} void onMeshUpdate(const int8_t xpos, const int8_t ypos, const_float_t zval) { dgus_screen_handler.MeshUpdate(xpos, ypos); diff --git a/Marlin/src/lcd/extui/example/example.cpp b/Marlin/src/lcd/extui/example/example.cpp index 8f38d2aba6..6ef20cf5f0 100644 --- a/Marlin/src/lcd/extui/example/example.cpp +++ b/Marlin/src/lcd/extui/example/example.cpp @@ -59,8 +59,8 @@ namespace ExtUI { void onStatusChanged(const char * const msg) {} void onHomingStart() {} - void onHomingComplete() {} - void onPrintFinished() {} + void onHomingDone() {} + void onPrintDone() {} void onFactoryReset() {} @@ -88,18 +88,19 @@ namespace ExtUI { // Called after loading or resetting stored settings } - void onConfigurationStoreWritten(bool success) { + void onSettingsStored(bool success) { // Called after the entire EEPROM has been written, // whether successful or not. } - void onConfigurationStoreRead(bool success) { + void onSettingsLoaded(bool success) { // Called after the entire EEPROM has been read, // whether successful or not. } #if HAS_MESH - void onMeshLevelingStart() {} + void onLevelingStart() {} + void onLevelingDone() {} void onMeshUpdate(const int8_t xpos, const int8_t ypos, const_float_t zval) { // Called when any mesh points are updated diff --git a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/archim2-flash/flash_storage.cpp b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/archim2-flash/flash_storage.cpp index 8b0c0f877c..dbee1e034b 100644 --- a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/archim2-flash/flash_storage.cpp +++ b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/archim2-flash/flash_storage.cpp @@ -421,7 +421,7 @@ bool UIFlashStorage::is_present = false; uint32_t addr; uint8_t buff[write_page_size]; - strcpy_P( (char*) buff, (const char*) filename); + strcpy_P((char*)buff, FTOP(filename)); MediaFileReader reader; if (!reader.open((char*) buff)) { diff --git a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/printing_dialog_box.cpp b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/printing_dialog_box.cpp index f0c0a59d36..6d177c5a7b 100644 --- a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/printing_dialog_box.cpp +++ b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/printing_dialog_box.cpp @@ -106,8 +106,8 @@ bool BioPrintingDialogBox::onTouchEnd(uint8_t tag) { } void BioPrintingDialogBox::setStatusMessage(FSTR_P message) { - char buff[strlen_P((const char*)message)+1]; - strcpy_P(buff, (const char*) message); + char buff[strlen_P(FTOP(message)) + 1]; + strcpy_P(buff, FTOP(message)); setStatusMessage(buff); } diff --git a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_extui.cpp b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_extui.cpp index f2ee1e5639..2ce9ed027e 100644 --- a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_extui.cpp +++ b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_extui.cpp @@ -80,7 +80,7 @@ namespace ExtUI { } void onPrintTimerPaused() {} - void onPrintFinished() {} + void onPrintDone() {} void onFilamentRunout(const extruder_t extruder) { char lcd_msg[30]; @@ -90,14 +90,14 @@ namespace ExtUI { } void onHomingStart() {} - void onHomingComplete() {} + void onHomingDone() {} void onFactoryReset() { InterfaceSettingsScreen::defaultSettings(); } void onStoreSettings(char *buff) { InterfaceSettingsScreen::saveSettings(buff); } void onLoadSettings(const char *buff) { InterfaceSettingsScreen::loadSettings(buff); } void onPostprocessSettings() {} // Called after loading or resetting stored settings - void onConfigurationStoreWritten(bool success) { + void onSettingsStored(bool success) { #ifdef ARCHIM2_SPI_FLASH_EEPROM_BACKUP_SIZE if (success && InterfaceSettingsScreen::backupEEPROM()) { SERIAL_ECHOLNPGM("EEPROM backed up to SPI Flash"); @@ -106,7 +106,7 @@ namespace ExtUI { UNUSED(success); #endif } - void onConfigurationStoreRead(bool) {} + void onSettingsLoaded(bool) {} void onPlayTone(const uint16_t frequency, const uint16_t duration) { sound.play_tone(frequency, duration); } @@ -118,7 +118,8 @@ namespace ExtUI { } #if HAS_LEVELING && HAS_MESH - void onMeshLevelingStart() {} + void onLevelingStart() {} + void onLevelingDone() {} void onMeshUpdate(const int8_t x, const int8_t y, const_float_t val) { BedMeshViewScreen::onMeshUpdate(x, y, val); } void onMeshUpdate(const int8_t x, const int8_t y, const ExtUI::probe_state_t state) { BedMeshViewScreen::onMeshUpdate(x, y, state); } #endif diff --git a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/command_processor.h b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/command_processor.h index 24e93982c2..648ed5330a 100644 --- a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/command_processor.h +++ b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/command_processor.h @@ -242,10 +242,10 @@ class CommandProcessor : public CLCD::CommandFifo { } CommandProcessor& toggle2(int16_t x, int16_t y, int16_t w, int16_t h, FSTR_P no, FSTR_P yes, bool state, uint16_t options = FTDI::OPT_3D) { - char text[strlen_P((const char *)no) + strlen_P((const char *)yes) + 2]; - strcpy_P(text, (const char *)no); + char text[strlen_P(FTOP(no)) + strlen_P(FTOP(yes)) + 2]; + strcpy_P(text, FTOP(no)); strcat(text, "\xFF"); - strcat_P(text, (const char *)yes); + strcat_P(text, FTOP(yes)); return toggle(x, y, w, h, text, state, options); } diff --git a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/text_box.cpp b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/text_box.cpp index b4d8156b39..c75cdf1812 100644 --- a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/text_box.cpp +++ b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/text_box.cpp @@ -135,9 +135,9 @@ namespace FTDI { } } - void draw_text_box(CommandProcessor& cmd, int x, int y, int w, int h, FSTR_P pstr, uint16_t options, uint8_t font) { - char str[strlen_P((const char*)pstr) + 1]; - strcpy_P(str, (const char*)pstr); + void draw_text_box(CommandProcessor& cmd, int x, int y, int w, int h, FSTR_P fstr, uint16_t options, uint8_t font) { + char str[strlen_P(FTOP(fstr)) + 1]; + strcpy_P(str, FTOP(fstr)); draw_text_box(cmd, x, y, w, h, (const char*) str, options, font); } } // namespace FTDI diff --git a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/text_ellipsis.cpp b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/text_ellipsis.cpp index 698bcdb150..a6d014b56e 100644 --- a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/text_ellipsis.cpp +++ b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/text_ellipsis.cpp @@ -33,6 +33,7 @@ namespace FTDI { const bool use_utf8 = has_utf8_chars(str); #define CHAR_WIDTH(c) use_utf8 ? utf8_fm.get_char_width(c) : clcd_fm.char_widths[(uint8_t)c] #else + constexpr bool use_utf8 = false; #define CHAR_WIDTH(c) utf8_fm.get_char_width(c) #endif FontMetrics utf8_fm(font); @@ -53,21 +54,17 @@ namespace FTDI { breakPoint = (char*)next; } - if (lineWidth > w) { - *breakPoint = '\0'; - strcpy_P(breakPoint,PSTR("...")); - } + if (lineWidth > w) + strcpy_P(breakPoint, PSTR("...")); cmd.apply_text_alignment(x, y, w, h, options); - #if ENABLED(TOUCH_UI_USE_UTF8) - if (use_utf8) { - draw_utf8_text(cmd, x, y, str, font_size_t::from_romfont(font), options); - } else - #endif - { - cmd.CLCD::CommandFifo::text(x, y, font, options); - cmd.CLCD::CommandFifo::str(str); - } + if (use_utf8) { + TERN_(TOUCH_UI_USE_UTF8, draw_utf8_text(cmd, x, y, str, font_size_t::from_romfont(font), options)); + } + else { + cmd.CLCD::CommandFifo::text(x, y, font, options); + cmd.CLCD::CommandFifo::str(str); + } } /** @@ -80,9 +77,9 @@ namespace FTDI { _draw_text_with_ellipsis(cmd, x, y, w, h, tmp, options, font); } - void draw_text_with_ellipsis(CommandProcessor& cmd, int x, int y, int w, int h, FSTR_P pstr, uint16_t options, uint8_t font) { - char tmp[strlen_P((const char*)pstr) + 3]; - strcpy_P(tmp, (const char*)pstr); + void draw_text_with_ellipsis(CommandProcessor& cmd, int x, int y, int w, int h, FSTR_P fstr, uint16_t options, uint8_t font) { + char tmp[strlen_P(FTOP(fstr)) + 3]; + strcpy_P(tmp, FTOP(fstr)); _draw_text_with_ellipsis(cmd, x, y, w, h, tmp, options, font); } } // namespace FTDI diff --git a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/unicode.cpp b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/unicode.cpp index ca25dea3ca..d428f686b7 100644 --- a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/unicode.cpp +++ b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/unicode.cpp @@ -191,9 +191,9 @@ return render_utf8_text(nullptr, 0, 0, str, fs, maxlen); } - uint16_t FTDI::get_utf8_text_width(FSTR_P pstr, font_size_t fs) { - char str[strlen_P((const char*)pstr) + 1]; - strcpy_P(str, (const char*)pstr); + uint16_t FTDI::get_utf8_text_width(FSTR_P fstr, font_size_t fs) { + char str[strlen_P(FTOP(fstr)) + 1]; + strcpy_P(str, FTOP(fstr)); return get_utf8_text_width(str, fs); } @@ -234,9 +234,9 @@ cmd.cmd(RESTORE_CONTEXT()); } - void FTDI::draw_utf8_text(CommandProcessor& cmd, int x, int y, FSTR_P pstr, font_size_t fs, uint16_t options) { - char str[strlen_P((const char*)pstr) + 1]; - strcpy_P(str, (const char*)pstr); + void FTDI::draw_utf8_text(CommandProcessor& cmd, int x, int y, FSTR_P fstr, font_size_t fs, uint16_t options) { + char str[strlen_P(FTOP(fstr)) + 1]; + strcpy_P(str, FTOP(fstr)); draw_utf8_text(cmd, x, y, (const char*) str, fs, options); } diff --git a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/base_numeric_adjustment_screen.cpp b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/base_numeric_adjustment_screen.cpp index 4415ed50fc..ce3066ae41 100644 --- a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/base_numeric_adjustment_screen.cpp +++ b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/base_numeric_adjustment_screen.cpp @@ -245,8 +245,8 @@ void BaseNumericAdjustmentScreen::widgets_t::adjuster(uint8_t tag, FSTR_P label, } if (_what & FOREGROUND) { - char b[strlen_P(value)+1]; - strcpy_P(b,value); + char b[strlen(value) + 1]; + strcpy(b, value); adjuster_sram_val(tag, label, b, is_enabled); } } diff --git a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/max_acceleration_screen.cpp b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/max_acceleration_screen.cpp index 228bc5f96b..492b908776 100644 --- a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/max_acceleration_screen.cpp +++ b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/max_acceleration_screen.cpp @@ -44,10 +44,10 @@ void MaxAccelerationScreen::onRedraw(draw_mode_t what) { w.color(e_axis).adjuster( 8, F(STR_E0), getAxisMaxAcceleration_mm_s2(E0) ); w.color(e_axis).adjuster(10, F(STR_E1), getAxisMaxAcceleration_mm_s2(E1) ); #if DISTINCT_E > 2 - w.color(e_axis).adjuster(12, F(STR_E2), getAxisMaxAcceleration_mm_s2(E2) ); - #endif - #if DISTINCT_E > 3 - w.color(e_axis).adjuster(14, F(STR_E3), getAxisMaxAcceleration_mm_s2(E3) ); + w.color(e_axis).adjuster(12, F(STR_E2), getAxisMaxAcceleration_mm_s2(E2) ); + #if DISTINCT_E > 3 + w.color(e_axis).adjuster(14, F(STR_E3), getAxisMaxAcceleration_mm_s2(E3) ); + #endif #endif #endif w.increments(); @@ -65,19 +65,18 @@ bool MaxAccelerationScreen::onTouchHeld(uint8_t tag) { case 8: UI_DECREMENT(AxisMaxAcceleration_mm_s2, E0); break; case 9: UI_INCREMENT(AxisMaxAcceleration_mm_s2, E0); break; #if DISTINCT_E > 1 - case 10: UI_DECREMENT(AxisMaxAcceleration_mm_s2, E1); break; - case 11: UI_INCREMENT(AxisMaxAcceleration_mm_s2, E1); break; + case 10: UI_DECREMENT(AxisMaxAcceleration_mm_s2, E1); break; + case 11: UI_INCREMENT(AxisMaxAcceleration_mm_s2, E1); break; + #if DISTINCT_E > 2 + case 12: UI_DECREMENT(AxisMaxAcceleration_mm_s2, E2); break; + case 13: UI_INCREMENT(AxisMaxAcceleration_mm_s2, E2); break; + #if DISTINCT_E > 3 + case 14: UI_DECREMENT(AxisMaxAcceleration_mm_s2, E3); break; + case 15: UI_INCREMENT(AxisMaxAcceleration_mm_s2, E3); break; + #endif + #endif #endif - #if DISTINCT_E > 2 - case 12: UI_DECREMENT(AxisMaxAcceleration_mm_s2, E2); break; - case 13: UI_INCREMENT(AxisMaxAcceleration_mm_s2, E2); break; - #endif - #if DISTINCT_E > 3 - case 14: UI_DECREMENT(AxisMaxAcceleration_mm_s2, E3); break; - case 15: UI_INCREMENT(AxisMaxAcceleration_mm_s2, E3); break; - #endif - default: - return false; + default: return false; } return true; } diff --git a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/max_velocity_screen.cpp b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/max_velocity_screen.cpp index 65dc947b7b..0111276211 100644 --- a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/max_velocity_screen.cpp +++ b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/max_velocity_screen.cpp @@ -46,9 +46,9 @@ void MaxVelocityScreen::onRedraw(draw_mode_t what) { w.color(e_axis) .adjuster( 10, F(STR_E1), getAxisMaxFeedrate_mm_s(E1) ); #if EXTRUDERS > 2 w.color(e_axis).adjuster( 12, F(STR_E2), getAxisMaxFeedrate_mm_s(E2) ); - #endif - #if EXTRUDERS > 3 - w.color(e_axis).adjuster( 14, F(STR_E3), getAxisMaxFeedrate_mm_s(E3) ); + #if EXTRUDERS > 3 + w.color(e_axis).adjuster( 14, F(STR_E3), getAxisMaxFeedrate_mm_s(E3) ); + #endif #endif #endif w.increments(); @@ -63,24 +63,23 @@ bool MaxVelocityScreen::onTouchHeld(uint8_t tag) { case 5: UI_INCREMENT(AxisMaxFeedrate_mm_s, Y); break; case 6: UI_DECREMENT(AxisMaxFeedrate_mm_s, Z); break; case 7: UI_INCREMENT(AxisMaxFeedrate_mm_s, Z); break; - #if DISTINCT_E > 0 - case 8: UI_DECREMENT(AxisMaxFeedrate_mm_s, E0); break; - case 9: UI_INCREMENT(AxisMaxFeedrate_mm_s, E0); break; + #if DISTINCT_E + case 8: UI_DECREMENT(AxisMaxFeedrate_mm_s, E0); break; + case 9: UI_INCREMENT(AxisMaxFeedrate_mm_s, E0); break; + #if DISTINCT_E > 1 + case 10: UI_DECREMENT(AxisMaxFeedrate_mm_s, E1); break; + case 11: UI_INCREMENT(AxisMaxFeedrate_mm_s, E1); break; + #if DISTINCT_E > 2 + case 12: UI_DECREMENT(AxisMaxFeedrate_mm_s, E2); break; + case 13: UI_INCREMENT(AxisMaxFeedrate_mm_s, E2); break; + #if DISTINCT_E > 3 + case 14: UI_DECREMENT(AxisMaxFeedrate_mm_s, E3); break; + case 15: UI_INCREMENT(AxisMaxFeedrate_mm_s, E3); break; + #endif + #endif + #endif #endif - #if DISTINCT_E > 1 - case 10: UI_DECREMENT(AxisMaxFeedrate_mm_s, E1); break; - case 11: UI_INCREMENT(AxisMaxFeedrate_mm_s, E1); break; - #endif - #if DISTINCT_E > 2 - case 12: UI_DECREMENT(AxisMaxFeedrate_mm_s, E2); break; - case 13: UI_INCREMENT(AxisMaxFeedrate_mm_s, E2); break; - #endif - #if DISTINCT_E > 3 - case 14: UI_DECREMENT(AxisMaxFeedrate_mm_s, E3); break; - case 15: UI_INCREMENT(AxisMaxFeedrate_mm_s, E3); break; - #endif - default: - return false; + default: return false; } SaveSettingsDialogBox::settingsChanged(); return true; diff --git a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/status_screen.cpp b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/status_screen.cpp index 4e76450683..7310577995 100644 --- a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/status_screen.cpp +++ b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/status_screen.cpp @@ -345,8 +345,8 @@ void StatusScreen::draw_status_message(draw_mode_t what, const char *message) { } void StatusScreen::setStatusMessage(FSTR_P message) { - char buff[strlen_P((const char * const)message)+1]; - strcpy_P(buff, (const char * const) message); + char buff[strlen_P(FTOP(message)) + 1]; + strcpy_P(buff, FTOP(message)); setStatusMessage((const char *) buff); } diff --git a/Marlin/src/lcd/extui/malyan/malyan_extui.cpp b/Marlin/src/lcd/extui/malyan/malyan_extui.cpp index f323728e27..945ff472e1 100644 --- a/Marlin/src/lcd/extui/malyan/malyan_extui.cpp +++ b/Marlin/src/lcd/extui/malyan/malyan_extui.cpp @@ -141,17 +141,18 @@ namespace ExtUI { void onFilamentRunout(const extruder_t extruder) {} void onUserConfirmRequired(const char * const) {} void onHomingStart() {} - void onHomingComplete() {} - void onPrintFinished() {} + void onHomingDone() {} + void onPrintDone() {} void onFactoryReset() {} void onStoreSettings(char*) {} void onLoadSettings(const char*) {} void onPostprocessSettings() {} - void onConfigurationStoreWritten(bool) {} - void onConfigurationStoreRead(bool) {} + void onSettingsStored(bool) {} + void onSettingsLoaded(bool) {} #if HAS_MESH - void onMeshLevelingStart() {} + void onLevelingStart() {} + void onLevelingDone() {} void onMeshUpdate(const int8_t xpos, const int8_t ypos, const_float_t zval) {} void onMeshUpdate(const int8_t xpos, const int8_t ypos, const ExtUI::probe_state_t state) {} #endif diff --git a/Marlin/src/lcd/extui/nextion/nextion_extui.cpp b/Marlin/src/lcd/extui/nextion/nextion_extui.cpp index c19d3aee46..da54fac383 100644 --- a/Marlin/src/lcd/extui/nextion/nextion_extui.cpp +++ b/Marlin/src/lcd/extui/nextion/nextion_extui.cpp @@ -50,8 +50,8 @@ namespace ExtUI { void onStatusChanged(const char * const msg) { nextion.StatusChange(msg); } void onHomingStart() {} - void onHomingComplete() {} - void onPrintFinished() { nextion.PrintFinished(); } + void onHomingDone() {} + void onPrintDone() { nextion.PrintFinished(); } void onFactoryReset() {} @@ -79,18 +79,19 @@ namespace ExtUI { // Called after loading or resetting stored settings } - void onConfigurationStoreWritten(bool success) { + void onSettingsStored(bool success) { // Called after the entire EEPROM has been written, // whether successful or not. } - void onConfigurationStoreRead(bool success) { + void onSettingsLoaded(bool success) { // Called after the entire EEPROM has been read, // whether successful or not. } #if HAS_MESH - void onMeshLevelingStart() {} + void onLevelingStart() {} + void onLevelingDone() {} void onMeshUpdate(const int8_t xpos, const int8_t ypos, const float zval) { // Called when any mesh points are updated @@ -116,6 +117,7 @@ namespace ExtUI { void onSteppersDisabled() {} void onSteppersEnabled() {} + } #endif // NEXTION_TFT diff --git a/Marlin/src/lcd/extui/ui_api.cpp b/Marlin/src/lcd/extui/ui_api.cpp index 9656e86f97..1a94eb9ab5 100644 --- a/Marlin/src/lcd/extui/ui_api.cpp +++ b/Marlin/src/lcd/extui/ui_api.cpp @@ -389,8 +389,10 @@ namespace ExtUI { return !thermalManager.tooColdToExtrude(extruder - E0); } - GcodeSuite::MarlinBusyState getHostKeepaliveState() { return TERN0(HOST_KEEPALIVE_FEATURE, gcode.busy_state); } - bool getHostKeepaliveIsPaused() { return TERN0(HOST_KEEPALIVE_FEATURE, gcode.host_keepalive_is_paused()); } + #if ENABLED(HOST_KEEPALIVE_FEATURE) + GcodeSuite::MarlinBusyState getHostKeepaliveState() { return gcode.busy_state; } + bool getHostKeepaliveIsPaused() { return gcode.host_keepalive_is_paused(); } + #endif #if HAS_SOFTWARE_ENDSTOPS bool getSoftEndstopState() { return soft_endstop._enabled; } @@ -418,6 +420,15 @@ namespace ExtUI { #if AXIS_IS_TMC(K) case K: return stepperK.getMilliamps(); #endif + #if AXIS_IS_TMC(U) + case U: return stepperU.getMilliamps(); + #endif + #if AXIS_IS_TMC(V) + case V: return stepperV.getMilliamps(); + #endif + #if AXIS_IS_TMC(W) + case W: return stepperW.getMilliamps(); + #endif #if AXIS_IS_TMC(X2) case X2: return stepperX2.getMilliamps(); #endif @@ -487,6 +498,15 @@ namespace ExtUI { #if AXIS_IS_TMC(K) case K: stepperK.rms_current(constrain(mA, 400, 1500)); break; #endif + #if AXIS_IS_TMC(U) + case U: stepperU.rms_current(constrain(mA, 400, 1500)); break; + #endif + #if AXIS_IS_TMC(V) + case V: stepperV.rms_current(constrain(mA, 400, 1500)); break; + #endif + #if AXIS_IS_TMC(W) + case W: stepperW.rms_current(constrain(mA, 400, 1500)); break; + #endif #if AXIS_IS_TMC(X2) case X2: stepperX2.rms_current(constrain(mA, 400, 1500)); break; #endif @@ -544,6 +564,9 @@ namespace ExtUI { OPTCODE(I_SENSORLESS, case I: return stepperI.homing_threshold()) OPTCODE(J_SENSORLESS, case J: return stepperJ.homing_threshold()) OPTCODE(K_SENSORLESS, case K: return stepperK.homing_threshold()) + OPTCODE(U_SENSORLESS, case U: return stepperU.homing_threshold()) + OPTCODE(V_SENSORLESS, case V: return stepperV.homing_threshold()) + OPTCODE(W_SENSORLESS, case W: return stepperW.homing_threshold()) OPTCODE(X2_SENSORLESS, case X2: return stepperX2.homing_threshold()) OPTCODE(Y2_SENSORLESS, case Y2: return stepperY2.homing_threshold()) OPTCODE(Z2_SENSORLESS, case Z2: return stepperZ2.homing_threshold()) @@ -573,6 +596,15 @@ namespace ExtUI { #if K_SENSORLESS case K: stepperK.homing_threshold(value); break; #endif + #if U_SENSORLESS + case U: stepperU.homing_threshold(value); break; + #endif + #if V_SENSORLESS + case V: stepperV.homing_threshold(value); break; + #endif + #if W_SENSORLESS + case W: stepperW.homing_threshold(value); break; + #endif #if X2_SENSORLESS case X2: stepperX2.homing_threshold(value); break; #endif diff --git a/Marlin/src/lcd/extui/ui_api.h b/Marlin/src/lcd/extui/ui_api.h index 3ccf6dea70..da1762830f 100644 --- a/Marlin/src/lcd/extui/ui_api.h +++ b/Marlin/src/lcd/extui/ui_api.h @@ -57,7 +57,7 @@ namespace ExtUI { static constexpr size_t eeprom_data_size = 48; - enum axis_t : uint8_t { X, Y, Z, I, J, K, X2, Y2, Z2, Z3, Z4 }; + enum axis_t : uint8_t { X, Y, Z, I, J, K, U, V, W, X2, Y2, Z2, Z3, Z4 }; enum extruder_t : uint8_t { E0, E1, E2, E3, E4, E5, E6, E7 }; enum heater_t : uint8_t { H0, H1, H2, H3, H4, H5, BED, CHAMBER, COOLER }; enum fan_t : uint8_t { FAN0, FAN1, FAN2, FAN3, FAN4, FAN5, FAN6, FAN7 }; @@ -83,8 +83,10 @@ namespace ExtUI { void injectCommands(char * const); bool commandsInQueue(); - GcodeSuite::MarlinBusyState getHostKeepaliveState(); - bool getHostKeepaliveIsPaused(); + #if ENABLED(HOST_KEEPALIVE_FEATURE) + GcodeSuite::MarlinBusyState getHostKeepaliveState(); + bool getHostKeepaliveIsPaused(); + #endif bool isHeaterIdle(const heater_t); bool isHeaterIdle(const extruder_t); @@ -172,7 +174,8 @@ namespace ExtUI { float getMeshPoint(const xy_uint8_t &pos); void setMeshPoint(const xy_uint8_t &pos, const_float_t zval); void moveToMeshPoint(const xy_uint8_t &pos, const_float_t z); - void onMeshLevelingStart(); + void onLevelingStart(); + void onLevelingDone(); void onMeshUpdate(const int8_t xpos, const int8_t ypos, const_float_t zval); inline void onMeshUpdate(const xy_int8_t &pos, const_float_t zval) { onMeshUpdate(pos.x, pos.y, zval); } @@ -400,22 +403,22 @@ namespace ExtUI { void onPrintTimerStarted(); void onPrintTimerPaused(); void onPrintTimerStopped(); - void onPrintFinished(); + void onPrintDone(); void onFilamentRunout(const extruder_t extruder); void onUserConfirmRequired(const char * const msg); void onUserConfirmRequired(FSTR_P const fstr); void onStatusChanged(const char * const msg); void onStatusChanged(FSTR_P const fstr); void onHomingStart(); - void onHomingComplete(); + void onHomingDone(); void onSteppersDisabled(); void onSteppersEnabled(); void onFactoryReset(); void onStoreSettings(char *); void onLoadSettings(const char *); void onPostprocessSettings(); - void onConfigurationStoreWritten(bool success); - void onConfigurationStoreRead(bool success); + void onSettingsStored(bool success); + void onSettingsLoaded(bool success); #if ENABLED(POWER_LOSS_RECOVERY) void onPowerLossResume(); #endif diff --git a/Marlin/src/lcd/fontutils.h b/Marlin/src/lcd/fontutils.h index 3901d4439f..21aee1e939 100644 --- a/Marlin/src/lcd/fontutils.h +++ b/Marlin/src/lcd/fontutils.h @@ -63,6 +63,7 @@ uint8_t* get_utf8_value_cb(uint8_t *pstart, read_byte_cb_t cb_read_byte, wchar_t /* Returns length of string in CHARACTERS, NOT BYTES */ uint8_t utf8_strlen(const char *pstart); uint8_t utf8_strlen_P(PGM_P pstart); +inline uint8_t utf8_strlen(FSTR_P fstart) { return utf8_strlen_P(FTOP(fstart)); } /* Returns start byte position of desired char number */ uint8_t utf8_byte_pos_by_char_num(const char *pstart, const uint8_t charnum); diff --git a/Marlin/src/lcd/language/language_de.h b/Marlin/src/lcd/language/language_de.h index bf408d436f..a6782bb0ac 100644 --- a/Marlin/src/lcd/language/language_de.h +++ b/Marlin/src/lcd/language/language_de.h @@ -135,6 +135,7 @@ namespace Language_de { LSTR MSG_BED_LEVELING = _UxGT("Bett-Nivellierung"); LSTR MSG_LEVEL_BED = _UxGT("Bett nivellieren"); LSTR MSG_BED_TRAMMING = _UxGT("Bett ausrichten"); + LSTR MSG_BED_TRAMMING_MANUAL = _UxGT("Manuelles ausrichten"); LSTR MSG_BED_TRAMMING_RAISE = _UxGT("Das Bett anpassen, bis zum auslösen."); LSTR MSG_BED_TRAMMING_IN_RANGE = _UxGT("Ecken in der Toleranz. Bett ausger."); LSTR MSG_BED_TRAMMING_GOOD_POINTS = _UxGT("Gute Punkte: "); @@ -387,8 +388,9 @@ namespace Language_de { LSTR MSG_ADVANCE_K = _UxGT("Vorschubfaktor"); LSTR MSG_ADVANCE_K_E = _UxGT("Vorschubfaktor *"); LSTR MSG_CONTRAST = _UxGT("LCD-Kontrast"); - LSTR MSG_BRIGHTNESS = _UxGT("LCD Helligkeit"); + LSTR MSG_BRIGHTNESS = _UxGT("LCD-Helligkeit"); LSTR MSG_LCD_BKL_TIMEOUT = _UxGT("LCD-Ruhezustand (s)"); + LSTR MSG_BRIGHTNESS_OFF = _UxGT("LCD ausschalten"); LSTR MSG_STORE_EEPROM = _UxGT("Konfig. speichern"); LSTR MSG_LOAD_EEPROM = _UxGT("Konfig. laden"); LSTR MSG_RESTORE_DEFAULTS = _UxGT("Standardwerte laden"); @@ -399,7 +401,7 @@ namespace Language_de { LSTR MSG_SETTINGS_STORED = _UxGT("Einstell. gespei."); LSTR MSG_MEDIA_UPDATE = _UxGT("FW Update vom Medium"); LSTR MSG_RESET_PRINTER = _UxGT("Drucker neustarten"); - LSTR MSG_REFRESH = LCD_STR_REFRESH _UxGT("Aktualisieren"); + LSTR MSG_REFRESH = LCD_STR_REFRESH _UxGT("Aktualisieren"); LSTR MSG_INFO_SCREEN = _UxGT("Info"); LSTR MSG_PREPARE = _UxGT("Vorbereitung"); LSTR MSG_TUNE = _UxGT("Justierung"); @@ -415,6 +417,8 @@ namespace Language_de { LSTR MSG_BUTTON_RESET = _UxGT("Reseten"); LSTR MSG_BUTTON_IGNORE = _UxGT("Ignorieren"); LSTR MSG_BUTTON_CANCEL = _UxGT("Abbrechen"); + LSTR MSG_BUTTON_CONFIRM = _UxGT("Bestätigen"); + LSTR MSG_BUTTON_CONTINUE = _UxGT("Fortsetzen"); LSTR MSG_BUTTON_DONE = _UxGT("Fertig"); LSTR MSG_BUTTON_BACK = _UxGT("Zurück"); LSTR MSG_BUTTON_PROCEED = _UxGT("Weiter"); @@ -424,6 +428,7 @@ namespace Language_de { LSTR MSG_BUTTON_PAUSE = _UxGT("Pause"); LSTR MSG_BUTTON_RESUME = _UxGT("Fortsetzen"); LSTR MSG_BUTTON_ADVANCED = _UxGT("Erweitert"); + LSTR MSG_BUTTON_SAVE = _UxGT("Speichern"); LSTR MSG_PAUSING = _UxGT("Pause..."); LSTR MSG_PAUSE_PRINT = _UxGT("SD-Druck pausieren"); LSTR MSG_ADVANCED_PAUSE = _UxGT("Erweiterte Pause"); diff --git a/Marlin/src/lcd/language/language_en.h b/Marlin/src/lcd/language/language_en.h index 1e9a7298ba..3e4109de3f 100644 --- a/Marlin/src/lcd/language/language_en.h +++ b/Marlin/src/lcd/language/language_en.h @@ -103,6 +103,9 @@ namespace Language_en { LSTR MSG_HOME_OFFSET_I = _UxGT("Home Offset ") STR_I; LSTR MSG_HOME_OFFSET_J = _UxGT("Home Offset ") STR_J; LSTR MSG_HOME_OFFSET_K = _UxGT("Home Offset ") STR_K; + LSTR MSG_HOME_OFFSET_U = _UxGT("Home Offset ") STR_U; + LSTR MSG_HOME_OFFSET_V = _UxGT("Home Offset ") STR_V; + LSTR MSG_HOME_OFFSET_W = _UxGT("Home Offset ") STR_W; LSTR MSG_HOME_OFFSETS_APPLIED = _UxGT("Offsets Applied"); LSTR MSG_SET_ORIGIN = _UxGT("Set Origin"); LSTR MSG_TRAMMING_WIZARD = _UxGT("Tramming Wizard"); @@ -288,6 +291,9 @@ namespace Language_en { LSTR MSG_MOVE_I = _UxGT("Move ") STR_I; LSTR MSG_MOVE_J = _UxGT("Move ") STR_J; LSTR MSG_MOVE_K = _UxGT("Move ") STR_K; + LSTR MSG_MOVE_U = _UxGT("Move ") STR_U; + LSTR MSG_MOVE_V = _UxGT("Move ") STR_V; + LSTR MSG_MOVE_W = _UxGT("Move ") STR_W; LSTR MSG_MOVE_E = _UxGT("Move Extruder"); LSTR MSG_MOVE_EN = _UxGT("Move E*"); LSTR MSG_HOTEND_TOO_COLD = _UxGT("Hotend too cold"); @@ -354,6 +360,9 @@ namespace Language_en { LSTR MSG_VI_JERK = _UxGT("Max ") STR_I _UxGT(" Jerk"); LSTR MSG_VJ_JERK = _UxGT("Max ") STR_J _UxGT(" Jerk"); LSTR MSG_VK_JERK = _UxGT("Max ") STR_K _UxGT(" Jerk"); + LSTR MSG_VU_JERK = _UxGT("Max ") STR_U _UxGT(" Jerk"); + LSTR MSG_VV_JERK = _UxGT("Max ") STR_V _UxGT(" Jerk"); + LSTR MSG_VW_JERK = _UxGT("Max ") STR_W _UxGT(" Jerk"); LSTR MSG_VE_JERK = _UxGT("Max E Jerk"); LSTR MSG_JUNCTION_DEVIATION = _UxGT("Junction Dev"); LSTR MSG_VELOCITY = _UxGT("Velocity"); @@ -363,6 +372,9 @@ namespace Language_en { LSTR MSG_VMAX_I = _UxGT("Max ") STR_I _UxGT(" Vel"); LSTR MSG_VMAX_J = _UxGT("Max ") STR_J _UxGT(" Vel"); LSTR MSG_VMAX_K = _UxGT("Max ") STR_K _UxGT(" Vel"); + LSTR MSG_VMAX_U = _UxGT("Max ") STR_U _UxGT(" Vel"); + LSTR MSG_VMAX_V = _UxGT("Max ") STR_V _UxGT(" Vel"); + LSTR MSG_VMAX_W = _UxGT("Max ") STR_W _UxGT(" Vel"); LSTR MSG_VMAX_E = _UxGT("Max ") STR_E _UxGT(" Vel"); LSTR MSG_VMAX_EN = _UxGT("Max * Vel"); LSTR MSG_VMIN = _UxGT("Min Velocity"); @@ -374,6 +386,9 @@ namespace Language_en { LSTR MSG_AMAX_I = _UxGT("Max ") STR_I _UxGT(" Accel"); LSTR MSG_AMAX_J = _UxGT("Max ") STR_J _UxGT(" Accel"); LSTR MSG_AMAX_K = _UxGT("Max ") STR_K _UxGT(" Accel"); + LSTR MSG_AMAX_U = _UxGT("Max ") STR_U _UxGT(" Accel"); + LSTR MSG_AMAX_V = _UxGT("Max ") STR_V _UxGT(" Accel"); + LSTR MSG_AMAX_W = _UxGT("Max ") STR_W _UxGT(" Accel"); LSTR MSG_AMAX_E = _UxGT("Max ") STR_E _UxGT(" Accel"); LSTR MSG_AMAX_EN = _UxGT("Max * Accel"); LSTR MSG_A_RETRACT = _UxGT("Retract Accel"); @@ -387,6 +402,9 @@ namespace Language_en { LSTR MSG_I_STEPS = STR_I _UxGT(" Steps/mm"); LSTR MSG_J_STEPS = STR_J _UxGT(" Steps/mm"); LSTR MSG_K_STEPS = STR_K _UxGT(" Steps/mm"); + LSTR MSG_U_STEPS = STR_U _UxGT(" Steps/mm"); + LSTR MSG_V_STEPS = STR_V _UxGT(" Steps/mm"); + LSTR MSG_W_STEPS = STR_W _UxGT(" Steps/mm"); LSTR MSG_E_STEPS = _UxGT("E steps/mm"); LSTR MSG_EN_STEPS = _UxGT("* Steps/mm"); LSTR MSG_TEMPERATURE = _UxGT("Temperature"); @@ -403,7 +421,8 @@ namespace Language_en { LSTR MSG_ADVANCE_K_E = _UxGT("Advance K *"); LSTR MSG_CONTRAST = _UxGT("LCD Contrast"); LSTR MSG_BRIGHTNESS = _UxGT("LCD Brightness"); - LSTR MSG_BRIGHTNESS_OFF = _UxGT("Turn Off LCD"); + LSTR MSG_LCD_BKL_TIMEOUT = _UxGT("LCD Timeout (s)"); + LSTR MSG_BRIGHTNESS_OFF = _UxGT("Backlight Off"); LSTR MSG_STORE_EEPROM = _UxGT("Store Settings"); LSTR MSG_LOAD_EEPROM = _UxGT("Load Settings"); LSTR MSG_RESTORE_DEFAULTS = _UxGT("Restore Defaults"); @@ -539,6 +558,9 @@ namespace Language_en { LSTR MSG_BABYSTEP_I = _UxGT("Babystep ") STR_I; LSTR MSG_BABYSTEP_J = _UxGT("Babystep ") STR_J; LSTR MSG_BABYSTEP_K = _UxGT("Babystep ") STR_K; + LSTR MSG_BABYSTEP_U = _UxGT("Babystep ") STR_U; + LSTR MSG_BABYSTEP_V = _UxGT("Babystep ") STR_V; + LSTR MSG_BABYSTEP_W = _UxGT("Babystep ") STR_W; LSTR MSG_BABYSTEP_TOTAL = _UxGT("Total"); LSTR MSG_ENDSTOP_ABORT = _UxGT("Endstop Abort"); LSTR MSG_HEATING_FAILED_LCD = _UxGT("Heating Failed"); @@ -638,6 +660,9 @@ namespace Language_en { LSTR MSG_DAC_PERCENT_I = STR_I _UxGT(" Driver %"); LSTR MSG_DAC_PERCENT_J = STR_J _UxGT(" Driver %"); LSTR MSG_DAC_PERCENT_K = STR_K _UxGT(" Driver %"); + LSTR MSG_DAC_PERCENT_U = STR_U _UxGT(" Driver %"); + LSTR MSG_DAC_PERCENT_V = STR_V _UxGT(" Driver %"); + LSTR MSG_DAC_PERCENT_W = STR_W _UxGT(" Driver %"); LSTR MSG_DAC_PERCENT_E = _UxGT("E Driver %"); LSTR MSG_ERROR_TMC = _UxGT("TMC CONNECTION ERROR"); LSTR MSG_DAC_EEPROM_WRITE = _UxGT("DAC EEPROM Write"); @@ -818,6 +843,9 @@ namespace Language_en { LSTR MSG_BACKLASH_I = STR_I; LSTR MSG_BACKLASH_J = STR_J; LSTR MSG_BACKLASH_K = STR_K; + LSTR MSG_BACKLASH_U = STR_U; + LSTR MSG_BACKLASH_V = STR_V; + LSTR MSG_BACKLASH_W = STR_W; } #if FAN_COUNT == 1 diff --git a/Marlin/src/lcd/language/language_fr.h b/Marlin/src/lcd/language/language_fr.h index 02f9d2f549..ca3757f704 100644 --- a/Marlin/src/lcd/language/language_fr.h +++ b/Marlin/src/lcd/language/language_fr.h @@ -336,6 +336,7 @@ namespace Language_fr { LSTR MSG_BRIGHTNESS = _UxGT("Luminosité LCD"); LSTR MSG_CONTRAST = _UxGT("Contraste LCD"); LSTR MSG_LCD_BKL_TIMEOUT = _UxGT("Veille LCD (s)"); + LSTR MSG_BRIGHTNESS_OFF = _UxGT("Éteindre l'écran LCD"); LSTR MSG_STORE_EEPROM = _UxGT("Enregistrer config."); LSTR MSG_LOAD_EEPROM = _UxGT("Charger config."); LSTR MSG_RESTORE_DEFAULTS = _UxGT("Restaurer défauts"); diff --git a/Marlin/src/lcd/language/language_uk.h b/Marlin/src/lcd/language/language_uk.h index 7afc2e031c..e4eef399fe 100644 --- a/Marlin/src/lcd/language/language_uk.h +++ b/Marlin/src/lcd/language/language_uk.h @@ -465,7 +465,15 @@ namespace Language_uk { LSTR MSG_FILAMENT_LOAD = _UxGT("Завантаж., мм"); LSTR MSG_ADVANCE_K = _UxGT("Kоеф. просув."); LSTR MSG_ADVANCE_K_E = _UxGT("Kоеф. просув. *"); - LSTR MSG_CONTRAST = _UxGT("Контраст екрану"); + #if LCD_WIDTH >= 20 || HAS_DWIN_E3V2 + LSTR MSG_CONTRAST = _UxGT("Контраст екрану"); + LSTR MSG_BRIGHTNESS = _UxGT("Яскравість LCD"); + #else + LSTR MSG_CONTRAST = _UxGT("Контраст"); + LSTR MSG_BRIGHTNESS = _UxGT("Яскравість"); + #endif + LSTR MSG_LCD_BKL_TIMEOUT = _UxGT("LCD Таймаут, с"); + LSTR MSG_BRIGHTNESS_OFF = _UxGT("Підсвітка вимк."); LSTR MSG_STORE_EEPROM = _UxGT("Зберегти в EEPROM"); LSTR MSG_LOAD_EEPROM = _UxGT("Зчитати з EEPROM"); LSTR MSG_RESTORE_DEFAULTS = _UxGT("На базові параметри"); @@ -497,10 +505,17 @@ namespace Language_uk { LSTR MSG_BUTTON_RESET = _UxGT("Зкинути"); LSTR MSG_BUTTON_IGNORE = _UxGT("Ігнорув."); LSTR MSG_BUTTON_CANCEL = _UxGT("Відміна"); + LSTR MSG_BUTTON_CONFIRM = _UxGT("Підтвер."); + LSTR MSG_BUTTON_CONTINUE = _UxGT("Продовж."); LSTR MSG_BUTTON_DONE = _UxGT("Готово"); LSTR MSG_BUTTON_BACK = _UxGT("Назад"); - LSTR MSG_BUTTON_PROCEED = _UxGT("Продовжити"); - LSTR MSG_BUTTON_SKIP = _UxGT("Пропустити"); + LSTR MSG_BUTTON_PROCEED = _UxGT("Продовж."); + LSTR MSG_BUTTON_SKIP = _UxGT("Пропуск"); + LSTR MSG_BUTTON_INFO = _UxGT("Інфо"); + LSTR MSG_BUTTON_LEVEL = _UxGT("Рівень"); + LSTR MSG_BUTTON_PAUSE = _UxGT("Пауза"); + LSTR MSG_BUTTON_RESUME = _UxGT("Звіт"); + LSTR MSG_BUTTON_SAVE = _UxGT("Зберегти"); LSTR MSG_PAUSING = _UxGT("Призупинення..."); LSTR MSG_PAUSE_PRINT = _UxGT("Призупинити друк"); @@ -518,6 +533,8 @@ namespace Language_uk { LSTR MSG_USERWAIT = _UxGT("Продовжити..."); LSTR MSG_PRINT_PAUSED = _UxGT("Друк призупинено"); LSTR MSG_PRINTING = _UxGT("Друк..."); + LSTR MSG_STOPPING = _UxGT("Зупинка..."); + LSTR MSG_REMAINING_TIME = _UxGT("Залишилось"); LSTR MSG_PRINT_ABORTED = _UxGT("Друк скасовано"); LSTR MSG_PRINT_DONE = _UxGT("Друк завершено"); LSTR MSG_NO_MOVE = _UxGT("Немає руху."); @@ -702,15 +719,32 @@ namespace Language_uk { LSTR MSG_INFO_COMPLETED_PRINTS = _UxGT("Завершено"); LSTR MSG_INFO_PRINT_FILAMENT = _UxGT("Екструдовано"); + LSTR MSG_PLEASE_PREHEAT = _UxGT("Нагрійте хотенд"); + LSTR MSG_COLORS_GET = _UxGT("Отримати колір"); #if LCD_WIDTH >= 20 || HAS_DWIN_E3V2 + LSTR MSG_MEDIA_NOT_INSERTED = _UxGT("Носій не вставлений"); + LSTR MSG_PLEASE_WAIT_REBOOT = _UxGT("Перезавантаження..."); LSTR MSG_INFO_PRINT_COUNT = _UxGT("Кількість друків"); - LSTR MSG_INFO_PRINT_TIME = _UxGT("Весь час друку"); + LSTR MSG_INFO_PRINT_TIME = _UxGT("Час друку"); LSTR MSG_INFO_PRINT_LONGEST = _UxGT("Найдовший час"); + LSTR MSG_COLORS_SELECT = _UxGT("Обрати кольори"); + LSTR MSG_COLORS_APPLIED = _UxGT("Кольори застосовані"); #else + LSTR MSG_MEDIA_NOT_INSERTED = _UxGT("Немає носія"); + LSTR MSG_PLEASE_WAIT_REBOOT = _UxGT("Перезавантаж..."); LSTR MSG_INFO_PRINT_COUNT = _UxGT("Друків"); LSTR MSG_INFO_PRINT_TIME = _UxGT("Загалом"); LSTR MSG_INFO_PRINT_LONGEST = _UxGT("Найдовше"); + LSTR MSG_COLORS_SELECT = _UxGT("Кольори"); + LSTR MSG_COLORS_APPLIED = _UxGT("Кольори застос."); #endif + LSTR MSG_COLORS_RED = _UxGT("Червоний"); + LSTR MSG_COLORS_GREEN = _UxGT("Зелений"); + LSTR MSG_COLORS_BLUE = _UxGT("Синій"); + LSTR MSG_COLORS_WHITE = _UxGT("Білий"); + LSTR MSG_UI_LANGUAGE = _UxGT("Мова"); + LSTR MSG_SOUND_ENABLE = _UxGT("Дозволити звук"); + LSTR MSG_LOCKSCREEN = _UxGT("Блокувати екран"); LSTR MSG_INFO_MIN_TEMP = _UxGT("Мін. ") LCD_STR_THERMOMETER; LSTR MSG_INFO_MAX_TEMP = _UxGT("Макс. ") LCD_STR_THERMOMETER; diff --git a/Marlin/src/lcd/lcdprint.h b/Marlin/src/lcd/lcdprint.h index c701a59568..d716d035ca 100644 --- a/Marlin/src/lcd/lcdprint.h +++ b/Marlin/src/lcd/lcdprint.h @@ -190,6 +190,9 @@ inline lcd_uint_t lcd_put_u8str_ind_P(const lcd_uint_t col, const lcd_uint_t row lcd_moveto(col, row); return lcd_put_u8str_ind_P(pstr, ind, inStr, maxlen); } +inline lcd_uint_t lcd_put_u8str_ind(FSTR_P const fstr, const int8_t ind, FSTR_P const inFstr=nullptr, const lcd_uint_t maxlen=LCD_WIDTH) { + return lcd_put_u8str_ind_P(FTOP(fstr), ind, FTOP(inFstr), maxlen); +} inline lcd_uint_t lcd_put_u8str_ind(const lcd_uint_t col, const lcd_uint_t row, FSTR_P const fstr, const int8_t ind, FSTR_P const inFstr=nullptr, const lcd_uint_t maxlen=LCD_WIDTH) { return lcd_put_u8str_ind_P(col, row, FTOP(fstr), ind, FTOP(inFstr), maxlen); } diff --git a/Marlin/src/lcd/marlinui.cpp b/Marlin/src/lcd/marlinui.cpp index f0677afd2d..7c97ef791d 100644 --- a/Marlin/src/lcd/marlinui.cpp +++ b/Marlin/src/lcd/marlinui.cpp @@ -73,6 +73,10 @@ constexpr uint8_t epps = ENCODER_PULSES_PER_STEP; #endif char MarlinUI::status_message[MAX_MESSAGE_LENGTH + 1]; uint8_t MarlinUI::alert_level; // = 0 + #if HAS_STATUS_MESSAGE_TIMEOUT + millis_t MarlinUI::status_message_expire_ms; // = 0 + #endif + statusResetFunc_t MarlinUI::status_reset_callback; // = nullptr #endif #if ENABLED(LCD_SET_PROGRESS_MANUALLY) @@ -593,7 +597,7 @@ void MarlinUI::init() { // share the same line on the display. // - #if DISABLED(PROGRESS_MSG_ONCE) || (PROGRESS_MSG_EXPIRE > 0) + #if DISABLED(PROGRESS_MSG_ONCE) || PROGRESS_MSG_EXPIRE > 0 #define GOT_MS const millis_t ms = millis(); #endif @@ -627,6 +631,18 @@ void MarlinUI::init() { #endif // BASIC_PROGRESS_BAR + bool did_expire = status_reset_callback && (*status_reset_callback)(); + + #if HAS_STATUS_MESSAGE_TIMEOUT + #ifndef GOT_MS + #define GOT_MS + const millis_t ms = millis(); + #endif + did_expire |= status_message_expire_ms && ELAPSED(ms, status_message_expire_ms); + #endif + + if (did_expire) reset_status(); + #if HAS_MARLINUI_MENU if (use_click()) { #if BOTH(FILAMENT_LCD_DISPLAY, SDSUPPORT) @@ -1176,7 +1192,7 @@ void MarlinUI::init() { #if HAS_ADC_BUTTONS typedef struct { - uint16_t ADCKeyValueMin, ADCKeyValueMax; + raw_adc_t ADCKeyValueMin, ADCKeyValueMax; uint8_t ADCKeyNo; } _stADCKeypadTable_; @@ -1203,10 +1219,10 @@ void MarlinUI::init() { #endif // Calculate the ADC value for the voltage divider with specified pull-down resistor value - #define ADC_BUTTON_VALUE(r) int(HAL_ADC_RANGE * (ADC_BUTTONS_VALUE_SCALE) * r / (r + ADC_BUTTONS_R_PULLUP)) + #define ADC_BUTTON_VALUE(r) raw_adc_t(HAL_ADC_RANGE * (ADC_BUTTONS_VALUE_SCALE) * r / (r + ADC_BUTTONS_R_PULLUP)) - static constexpr uint16_t adc_button_tolerance = HAL_ADC_RANGE * 25 / 1024, - adc_other_button = HAL_ADC_RANGE * 1000 / 1024; + static constexpr raw_adc_t adc_button_tolerance = HAL_ADC_RANGE * 25 / 1024, + adc_other_button = raw_adc_t(uint32_t(HAL_ADC_RANGE * 1000UL) / 1024UL); static const _stADCKeypadTable_ stADCKeyTable[] PROGMEM = { // VALUE_MIN, VALUE_MAX, KEY { adc_other_button, HAL_ADC_RANGE, 1 + BLEN_KEYPAD_F1 }, // F1 @@ -1226,13 +1242,13 @@ void MarlinUI::init() { uint8_t get_ADC_keyValue() { if (thermalManager.ADCKey_count >= 16) { - const uint16_t currentkpADCValue = thermalManager.current_ADCKey_raw; + const raw_adc_t currentkpADCValue = thermalManager.current_ADCKey_raw; thermalManager.current_ADCKey_raw = HAL_ADC_RANGE; thermalManager.ADCKey_count = 0; if (currentkpADCValue < adc_other_button) LOOP_L_N(i, ADC_KEY_NUM) { - const uint16_t lo = pgm_read_word(&stADCKeyTable[i].ADCKeyValueMin), - hi = pgm_read_word(&stADCKeyTable[i].ADCKeyValueMax); + const raw_adc_t lo = pgm_read_word(&stADCKeyTable[i].ADCKeyValueMin), + hi = pgm_read_word(&stADCKeyTable[i].ADCKeyValueMax); if (WITHIN(currentkpADCValue, lo, hi)) return pgm_read_byte(&stADCKeyTable[i].ADCKeyNo); } } @@ -1420,6 +1436,7 @@ void MarlinUI::init() { #if SERVICE_INTERVAL_3 > 0 static PGMSTR(service3, "> " SERVICE_NAME_3 "!"); #endif + FSTR_P msg; if (printingIsPaused()) msg = GET_TEXT_F(MSG_PRINT_PAUSED); @@ -1450,13 +1467,18 @@ void MarlinUI::init() { set_status(msg, -1); } + /** + * Set Status with a fixed string and alert level. + * @param fstr A constant F-string to set as the status. + * @param level Alert level. Negative to ignore and reset the level. Non-zero never expires. + */ void MarlinUI::set_status(FSTR_P const fstr, int8_t level) { - PGM_P const pstr = FTOP(fstr); + // Alerts block lower priority messages if (level < 0) level = alert_level = 0; if (level < alert_level) return; alert_level = level; - TERN_(HOST_STATUS_NOTIFICATIONS, hostui.notify(fstr)); + PGM_P const pstr = FTOP(fstr); // Since the message is encoded in UTF8 it must // only be cut on a character boundary. @@ -1476,6 +1498,8 @@ void MarlinUI::init() { strncpy_P(status_message, pstr, maxLen); status_message[maxLen] = '\0'; + TERN_(HOST_STATUS_NOTIFICATIONS, hostui.notify(fstr)); + finish_status(level > 0); } @@ -1487,9 +1511,12 @@ void MarlinUI::init() { #include - void MarlinUI::status_printf(const uint8_t level, FSTR_P const fmt, ...) { + void MarlinUI::status_printf(int8_t level, FSTR_P const fmt, ...) { + // Alerts block lower priority messages + if (level < 0) level = alert_level = 0; if (level < alert_level) return; alert_level = level; + va_list args; va_start(args, FTOP(fmt)); vsnprintf_P(status_message, MAX_MESSAGE_LENGTH, FTOP(fmt), args); @@ -1504,6 +1531,10 @@ void MarlinUI::init() { UNUSED(persist); + set_status_reset_fn(); + + TERN_(HAS_STATUS_MESSAGE_TIMEOUT, status_message_expire_ms = persist ? 0 : millis() + (STATUS_MESSAGE_TIMEOUT_SEC) * 1000UL); + #if HAS_WIRED_LCD #if BASIC_PROGRESS_BAR || BOTH(FILAMENT_LCD_DISPLAY, SDSUPPORT) @@ -1551,7 +1582,22 @@ void MarlinUI::init() { #endif -#endif +#else // !HAS_STATUS_MESSAGE + + // + // Send the status line as a host notification + // + void MarlinUI::set_status(const char * const cstr, const bool) { + TERN(HOST_PROMPT_SUPPORT, hostui.notify(cstr), UNUSED(cstr)); + } + void MarlinUI::set_status(FSTR_P const fstr, const int8_t) { + TERN(HOST_PROMPT_SUPPORT, hostui.notify(fstr), UNUSED(fstr)); + } + void MarlinUI::status_printf(int8_t, FSTR_P const fstr, ...) { + TERN(HOST_PROMPT_SUPPORT, hostui.notify(fstr), UNUSED(fstr)); + } + +#endif // !HAS_STATUS_MESSAGE #if HAS_DISPLAY @@ -1663,22 +1709,7 @@ void MarlinUI::init() { #endif -#elif !HAS_STATUS_MESSAGE // && !HAS_DISPLAY - - // - // Send the status line as a host notification - // - void MarlinUI::set_status(const char * const cstr, const bool) { - TERN(HOST_PROMPT_SUPPORT, hostui.notify(cstr), UNUSED(cstr)); - } - void MarlinUI::set_status(FSTR_P const fstr, const int8_t) { - TERN(HOST_PROMPT_SUPPORT, hostui.notify(fstr), UNUSED(fstr)); - } - void MarlinUI::status_printf(const uint8_t, FSTR_P const fstr, ...) { - TERN(HOST_PROMPT_SUPPORT, hostui.notify(fstr), UNUSED(fstr)); - } - -#endif // !HAS_DISPLAY && !HAS_STATUS_MESSAGE +#endif // HAS_DISPLAY #if ENABLED(SDSUPPORT) diff --git a/Marlin/src/lcd/marlinui.h b/Marlin/src/lcd/marlinui.h index 83eb332105..d9404541d2 100644 --- a/Marlin/src/lcd/marlinui.h +++ b/Marlin/src/lcd/marlinui.h @@ -39,10 +39,6 @@ #define HAS_ENCODER_ACTION 1 #endif -#if HAS_STATUS_MESSAGE - #define START_OF_UTF8_CHAR(C) (((C) & 0xC0u) != 0x80U) -#endif - #if E_MANUAL > 1 #define MULTI_E_MANUAL 1 #endif @@ -63,6 +59,8 @@ #define START_OF_UTF8_CHAR(C) (((C) & 0xC0u) != 0x80U) +typedef bool (*statusResetFunc_t)(); + #if HAS_WIRED_LCD enum LCDViewAction : uint8_t { @@ -346,6 +344,10 @@ public: static char status_message[]; static uint8_t alert_level; // Higher levels block lower levels + #if HAS_STATUS_MESSAGE_TIMEOUT + static millis_t status_message_expire_ms; // Reset some status messages after a timeout + #endif + #if ENABLED(STATUS_MESSAGE_SCROLLING) static uint8_t status_scroll_offset; static void advance_status_scroll(); @@ -356,16 +358,20 @@ public: static void reset_status(const bool no_welcome=false); static void set_alert_status(FSTR_P const fstr); static void reset_alert_level() { alert_level = 0; } + + static statusResetFunc_t status_reset_callback; + static void set_status_reset_fn(const statusResetFunc_t fn=nullptr) { status_reset_callback = fn; } #else static constexpr bool has_status() { return false; } static void reset_status(const bool=false) {} static void set_alert_status(FSTR_P const) {} static void reset_alert_level() {} + static void set_status_reset_fn(const statusResetFunc_t=nullptr) {} #endif static void set_status(const char * const cstr, const bool persist=false); static void set_status(FSTR_P const fstr, const int8_t level=0); - static void status_printf(const uint8_t level, FSTR_P const fmt, ...); + static void status_printf(int8_t level, FSTR_P const fmt, ...); #if HAS_DISPLAY @@ -680,7 +686,31 @@ public: #endif static void update_buttons(); - static bool button_pressed() { return BUTTON_CLICK() || TERN(TOUCH_SCREEN, touch_pressed(), false); } + + #if HAS_ENCODER_NOISE + #ifndef ENCODER_SAMPLES + #define ENCODER_SAMPLES 10 + #endif + + /** + * Some printers may have issues with EMI noise especially using a motherboard with 3.3V logic levels + * it may cause the logical LOW to float into the undefined region and register as a logical HIGH + * causing it to erroneously register as if someone clicked the button and in worst case make the + * printer unusable in practice. + */ + static bool hw_button_pressed() { + LOOP_L_N(s, ENCODER_SAMPLES) { + if (!BUTTON_CLICK()) return false; + safe_delay(1); + } + return true; + } + #else + static bool hw_button_pressed() { return BUTTON_CLICK(); } + #endif + + static bool button_pressed() { return hw_button_pressed() || TERN0(TOUCH_SCREEN, touch_pressed()); } + #if EITHER(AUTO_BED_LEVELING_UBL, G26_MESH_VALIDATION) static void wait_for_release(); #endif diff --git a/Marlin/src/lcd/menu/menu.cpp b/Marlin/src/lcd/menu/menu.cpp index 2dca6c1b82..52c43ec5e9 100644 --- a/Marlin/src/lcd/menu/menu.cpp +++ b/Marlin/src/lcd/menu/menu.cpp @@ -276,11 +276,7 @@ void scroll_screen(const uint8_t limit, const bool is_menu) { #if HAS_BUZZER void MarlinUI::completion_feedback(const bool good/*=true*/) { TERN_(HAS_TOUCH_SLEEP, wakeup_screen()); // Wake up on rotary encoder click... - if (good) { - BUZZ(100, 659); - BUZZ(100, 698); - } - else BUZZ(20, 440); + if (good) OKAY_BUZZ(); else ERR_BUZZ(); } #endif diff --git a/Marlin/src/lcd/menu/menu.h b/Marlin/src/lcd/menu/menu.h index 72826262f4..b111236d69 100644 --- a/Marlin/src/lcd/menu/menu.h +++ b/Marlin/src/lcd/menu/menu.h @@ -114,8 +114,8 @@ class MenuItem_confirm : public MenuItemBase { selectFunc_t yesFunc, selectFunc_t noFunc, PGM_P const pref, FSTR_P const string, PGM_P const suff=nullptr ) { - char str[strlen_P((PGM_P)string) + 1]; - strcpy_P(str, (PGM_P)string); + char str[strlen_P(FTOP(string)) + 1]; + strcpy_P(str, FTOP(string)); select_screen(yes, no, yesFunc, noFunc, pref, str, suff); } // Shortcut for prompt with "NO"/ "YES" labels diff --git a/Marlin/src/lcd/menu/menu_advanced.cpp b/Marlin/src/lcd/menu/menu_advanced.cpp index ac2da4d8a6..c59a2aafd6 100644 --- a/Marlin/src/lcd/menu/menu_advanced.cpp +++ b/Marlin/src/lcd/menu/menu_advanced.cpp @@ -39,7 +39,7 @@ #include "../../module/probe.h" #endif -#if ENABLED(PIDTEMP) +#if ANY(PIDTEMP, PIDTEMPBED, PIDTEMPCHAMBER) #include "../../module/temperature.h" #endif @@ -68,7 +68,7 @@ void menu_backlash(); START_MENU(); BACK_ITEM(MSG_ADVANCED_SETTINGS); #define EDIT_DAC_PERCENT(A) EDIT_ITEM(uint8, MSG_DAC_PERCENT_##A, &driverPercent[_AXIS(A)], 0, 100, []{ stepper_dac.set_current_percents(driverPercent); }) - LOGICAL_AXIS_CODE(EDIT_DAC_PERCENT(E), EDIT_DAC_PERCENT(A), EDIT_DAC_PERCENT(B), EDIT_DAC_PERCENT(C), EDIT_DAC_PERCENT(I), EDIT_DAC_PERCENT(J), EDIT_DAC_PERCENT(K)); + LOGICAL_AXIS_CODE(EDIT_DAC_PERCENT(E), EDIT_DAC_PERCENT(A), EDIT_DAC_PERCENT(B), EDIT_DAC_PERCENT(C), EDIT_DAC_PERCENT(I), EDIT_DAC_PERCENT(J), EDIT_DAC_PERCENT(K), EDIT_DAC_PERCENT(U), EDIT_DAC_PERCENT(V), EDIT_DAC_PERCENT(W)); ACTION_ITEM(MSG_DAC_EEPROM_WRITE, stepper_dac.commit_eeprom); END_MENU(); } @@ -99,23 +99,23 @@ void menu_backlash(); #if HAS_FILAMENT_SENSOR + void set_runout_mode_none(const uint8_t e) { runout.mode[e] = RM_NONE; runout.setup(); } + void set_runout_mode_high(const uint8_t e) { runout.mode[e] = RM_OUT_ON_HIGH; runout.setup(); } + void set_runout_mode_low(const uint8_t e) { runout.mode[e] = RM_OUT_ON_LOW; runout.setup(); } + void set_runout_mode_motion(const uint8_t e) { runout.mode[e] = RM_MOTION_SENSOR; runout.setup(); } + #define RUNOUT_EDIT_ITEMS(F) do{ \ - EDIT_ITEM_N(bool, F, MSG_RUNOUT_SENSOR, &runout.enabled[F]); \ - ACTION_ITEM_N(F, MSG_RUNOUT_MODE_NONE, []{ set_runout_mode_none(F);}); \ - ACTION_ITEM_N(F, MSG_RUNOUT_MODE_HIGH, []{ set_runout_mode_high(F);}); \ - ACTION_ITEM_N(F, MSG_RUNOUT_MODE_LOW, []{ set_runout_mode_low(F);}); \ - ACTION_ITEM_N(F, MSG_RUNOUT_MODE_MOTION, []{ set_runout_mode_motion(F);}); \ + EDIT_ITEM(bool, MSG_RUNOUT_SENSOR, &runout.enabled[F]); \ + ACTION_ITEM(MSG_RUNOUT_MODE_NONE, []{ set_runout_mode_none(F); }); \ + ACTION_ITEM(MSG_RUNOUT_MODE_HIGH, []{ set_runout_mode_high(F); }); \ + ACTION_ITEM(MSG_RUNOUT_MODE_LOW, []{ set_runout_mode_low(F); }); \ + ACTION_ITEM(MSG_RUNOUT_MODE_MOTION, []{ set_runout_mode_motion(F); }); \ editable.decimal = runout.runout_distance(F); \ - EDIT_ITEM_FAST_N(float3, F, MSG_RUNOUT_DISTANCE_MM, &editable.decimal, 1, 999, \ + EDIT_ITEM_FAST(float3, MSG_RUNOUT_DISTANCE_MM, &editable.decimal, 1, 999, \ []{ runout.set_runout_distance(editable.decimal, F); }, true \ ); \ }while(0) - void set_runout_mode_none(uint8_t e) { runout.mode[e] = 0; } - void set_runout_mode_high(uint8_t e) { runout.mode[e] = 1; } - void set_runout_mode_low(uint8_t e) { runout.mode[e] = 2; } - void set_runout_mode_motion(uint8_t e) { runout.mode[e] = 7; } - void menu_runout_config() { START_MENU(); BACK_ITEM(MSG_CONFIGURATION); @@ -157,8 +157,8 @@ void menu_backlash(); #if EXTRUDERS == 1 EDIT_ITEM(float42_52, MSG_ADVANCE_K, &planner.extruder_advance_K[0], 0, 10); #elif HAS_MULTI_EXTRUDER - LOOP_L_N(n, EXTRUDERS) - EDIT_ITEM_N(float42_52, n, MSG_ADVANCE_K_E, &planner.extruder_advance_K[n], 0, 10); + EXTRUDER_LOOP() + EDIT_ITEM_N(float42_52, e, MSG_ADVANCE_K_E, &planner.extruder_advance_K[e], 0, 10); #endif #endif @@ -168,16 +168,16 @@ void menu_backlash(); #if ENABLED(VOLUMETRIC_EXTRUDER_LIMIT) EDIT_ITEM_FAST(float42_52, MSG_VOLUMETRIC_LIMIT, &planner.volumetric_extruder_limit[active_extruder], 0.0f, 20.0f, planner.calculate_volumetric_extruder_limits); #if HAS_MULTI_EXTRUDER - LOOP_L_N(n, EXTRUDERS) - EDIT_ITEM_FAST_N(float42_52, n, MSG_VOLUMETRIC_LIMIT_E, &planner.volumetric_extruder_limit[n], 0.0f, 20.00f, planner.calculate_volumetric_extruder_limits); + EXTRUDER_LOOP() + EDIT_ITEM_FAST_N(float42_52, e, MSG_VOLUMETRIC_LIMIT_E, &planner.volumetric_extruder_limit[e], 0.0f, 20.00f, planner.calculate_volumetric_extruder_limits); #endif #endif if (parser.volumetric_enabled) { EDIT_ITEM_FAST(float43, MSG_FILAMENT_DIAM, &planner.filament_size[active_extruder], 1.5f, 3.25f, planner.calculate_volumetric_multipliers); #if HAS_MULTI_EXTRUDER - LOOP_L_N(n, EXTRUDERS) - EDIT_ITEM_FAST_N(float43, n, MSG_FILAMENT_DIAM_E, &planner.filament_size[n], 1.5f, 3.25f, planner.calculate_volumetric_multipliers); + EXTRUDER_LOOP() + EDIT_ITEM_FAST_N(float43, e, MSG_FILAMENT_DIAM_E, &planner.filament_size[e], 1.5f, 3.25f, planner.calculate_volumetric_multipliers); #endif } #endif @@ -187,14 +187,14 @@ void menu_backlash(); EDIT_ITEM_FAST(float4, MSG_FILAMENT_UNLOAD, &fc_settings[active_extruder].unload_length, 0, extrude_maxlength); #if HAS_MULTI_EXTRUDER - LOOP_L_N(n, EXTRUDERS) - EDIT_ITEM_FAST_N(float4, n, MSG_FILAMENTUNLOAD_E, &fc_settings[n].unload_length, 0, extrude_maxlength); + EXTRUDER_LOOP() + EDIT_ITEM_FAST_N(float4, e, MSG_FILAMENTUNLOAD_E, &fc_settings[e].unload_length, 0, extrude_maxlength); #endif EDIT_ITEM_FAST(float4, MSG_FILAMENT_LOAD, &fc_settings[active_extruder].load_length, 0, extrude_maxlength); #if HAS_MULTI_EXTRUDER - LOOP_L_N(n, EXTRUDERS) - EDIT_ITEM_FAST_N(float4, n, MSG_FILAMENTLOAD_E, &fc_settings[n].load_length, 0, extrude_maxlength); + EXTRUDER_LOOP() + EDIT_ITEM_FAST_N(float4, e, MSG_FILAMENTLOAD_E, &fc_settings[e].load_length, 0, extrude_maxlength); #endif #endif @@ -235,7 +235,12 @@ void menu_backlash(); #if ENABLED(PIDTEMPCHAMBER) case H_CHAMBER: tune_temp = autotune_temp_chamber; break; #endif - default: tune_temp = autotune_temp[hid]; break; + default: + #if ENABLED(PIDTEMP) + tune_temp = autotune_temp[hid]; break; + #else + return; + #endif } sprintf_P(cmd, PSTR("M303 U1 E%i S%i"), hid, tune_temp); queue.inject(cmd); @@ -251,14 +256,36 @@ void menu_backlash(); // Helpers for editing PID Ki & Kd values // grab the PID value out of the temp variable; scale it; then update the PID driver void copy_and_scalePID_i(int16_t e) { - UNUSED(e); - PID_PARAM(Ki, e) = scalePID_i(raw_Ki); - thermalManager.updatePID(); + switch (e) { + #if ENABLED(PIDTEMPBED) + case H_BED: thermalManager.temp_bed.pid.Ki = scalePID_i(raw_Ki); break; + #endif + #if ENABLED(PIDTEMPCHAMBER) + case H_CHAMBER: thermalManager.temp_chamber.pid.Ki = scalePID_i(raw_Ki); break; + #endif + default: + #if ENABLED(PIDTEMP) + PID_PARAM(Ki, e) = scalePID_i(raw_Ki); + thermalManager.updatePID(); + #endif + break; + } } void copy_and_scalePID_d(int16_t e) { - UNUSED(e); - PID_PARAM(Kd, e) = scalePID_d(raw_Kd); - thermalManager.updatePID(); + switch (e) { + #if ENABLED(PIDTEMPBED) + case H_BED: thermalManager.temp_bed.pid.Kd = scalePID_d(raw_Kd); break; + #endif + #if ENABLED(PIDTEMPCHAMBER) + case H_CHAMBER: thermalManager.temp_chamber.pid.Kd = scalePID_d(raw_Kd); break; + #endif + default: + #if ENABLED(PIDTEMP) + PID_PARAM(Kd, e) = scalePID_d(raw_Kd); + thermalManager.updatePID(); + #endif + break; + } } #define _DEFINE_PIDTEMP_BASE_FUNCS(N) \ @@ -401,7 +428,7 @@ void menu_backlash(); #elif ENABLED(LIMITED_MAX_FR_EDITING) DEFAULT_MAX_FEEDRATE #else - LOGICAL_AXIS_ARRAY(9999, 9999, 9999, 9999, 9999, 9999, 9999) + LOGICAL_AXIS_ARRAY(9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999) #endif ; #if ENABLED(LIMITED_MAX_FR_EDITING) && !defined(MAX_FEEDRATE_EDIT_VALUES) @@ -414,7 +441,7 @@ void menu_backlash(); BACK_ITEM(MSG_ADVANCED_SETTINGS); #define EDIT_VMAX(N) EDIT_ITEM_FAST(float5, MSG_VMAX_##N, &planner.settings.max_feedrate_mm_s[_AXIS(N)], 1, max_fr_edit_scaled[_AXIS(N)]) - LINEAR_AXIS_CODE(EDIT_VMAX(A), EDIT_VMAX(B), EDIT_VMAX(C), EDIT_VMAX(I), EDIT_VMAX(J), EDIT_VMAX(K)); + NUM_AXIS_CODE(EDIT_VMAX(A), EDIT_VMAX(B), EDIT_VMAX(C), EDIT_VMAX(I), EDIT_VMAX(J), EDIT_VMAX(K), EDIT_VMAX(U), EDIT_VMAX(V), EDIT_VMAX(W)); #if E_STEPPERS EDIT_ITEM_FAST(float5, MSG_VMAX_E, &planner.settings.max_feedrate_mm_s[E_AXIS_N(active_extruder)], 1, max_fr_edit_scaled.e); @@ -444,7 +471,7 @@ void menu_backlash(); #elif ENABLED(LIMITED_MAX_ACCEL_EDITING) DEFAULT_MAX_ACCELERATION #else - LOGICAL_AXIS_ARRAY(99000, 99000, 99000, 99000, 99000, 99000, 99000) + LOGICAL_AXIS_ARRAY(99000, 99000, 99000, 99000, 99000, 99000, 99000, 99000, 99000, 99000) #endif ; #if ENABLED(LIMITED_MAX_ACCEL_EDITING) && !defined(MAX_ACCEL_EDIT_VALUES) @@ -468,9 +495,10 @@ void menu_backlash(); EDIT_ITEM_FAST(float5_25, MSG_A_TRAVEL, &planner.settings.travel_acceleration, 25, max_accel); #define EDIT_AMAX(Q,L) EDIT_ITEM_FAST(long5_25, MSG_AMAX_##Q, &planner.settings.max_acceleration_mm_per_s2[_AXIS(Q)], L, max_accel_edit_scaled[_AXIS(Q)], []{ planner.reset_acceleration_rates(); }) - LINEAR_AXIS_CODE( + NUM_AXIS_CODE( EDIT_AMAX(A, 100), EDIT_AMAX(B, 100), EDIT_AMAX(C, 10), - EDIT_AMAX(I, 10), EDIT_AMAX(J, 10), EDIT_AMAX(K, 10) + EDIT_AMAX(I, 10), EDIT_AMAX(J, 10), EDIT_AMAX(K, 10), + EDIT_AMAX(U, 10), EDIT_AMAX(V, 10), EDIT_AMAX(W, 10) ); #if ENABLED(DISTINCT_E_FACTORS) @@ -513,9 +541,10 @@ void menu_backlash(); #elif ENABLED(LIMITED_JERK_EDITING) { LOGICAL_AXIS_LIST((DEFAULT_EJERK) * 2, (DEFAULT_XJERK) * 2, (DEFAULT_YJERK) * 2, (DEFAULT_ZJERK) * 2, - (DEFAULT_IJERK) * 2, (DEFAULT_JJERK) * 2, (DEFAULT_KJERK) * 2) } + (DEFAULT_IJERK) * 2, (DEFAULT_JJERK) * 2, (DEFAULT_KJERK) * 2, + (DEFAULT_UJERK) * 2, (DEFAULT_VJERK) * 2, (DEFAULT_WJERK) * 2) } #else - { LOGICAL_AXIS_LIST(990, 990, 990, 990, 990, 990, 990) } + { LOGICAL_AXIS_LIST(990, 990, 990, 990, 990, 990, 990, 990, 990, 990) } #endif ; #define EDIT_JERK(N) EDIT_ITEM_FAST(float3, MSG_V##N##_JERK, &planner.max_jerk[_AXIS(N)], 1, max_jerk_edit[_AXIS(N)]) @@ -524,9 +553,10 @@ void menu_backlash(); #else #define EDIT_JERK_C() EDIT_ITEM_FAST(float52sign, MSG_VC_JERK, &planner.max_jerk.c, 0.1f, max_jerk_edit.c) #endif - LINEAR_AXIS_CODE( + NUM_AXIS_CODE( EDIT_JERK(A), EDIT_JERK(B), EDIT_JERK_C(), - EDIT_JERK(I), EDIT_JERK(J), EDIT_JERK(K) + EDIT_JERK(I), EDIT_JERK(J), EDIT_JERK(K), + EDIT_JERK(U), EDIT_JERK(V), EDIT_JERK(W) ); #if HAS_EXTRUDERS @@ -569,9 +599,10 @@ void menu_advanced_steps_per_mm() { BACK_ITEM(MSG_ADVANCED_SETTINGS); #define EDIT_QSTEPS(Q) EDIT_ITEM_FAST(float61, MSG_##Q##_STEPS, &planner.settings.axis_steps_per_mm[_AXIS(Q)], 5, 9999, []{ planner.refresh_positioning(); }) - LINEAR_AXIS_CODE( + NUM_AXIS_CODE( EDIT_QSTEPS(A), EDIT_QSTEPS(B), EDIT_QSTEPS(C), - EDIT_QSTEPS(I), EDIT_QSTEPS(J), EDIT_QSTEPS(K) + EDIT_QSTEPS(I), EDIT_QSTEPS(J), EDIT_QSTEPS(K), + EDIT_QSTEPS(U), EDIT_QSTEPS(V), EDIT_QSTEPS(W) ); #if ENABLED(DISTINCT_E_FACTORS) diff --git a/Marlin/src/lcd/menu/menu_backlash.cpp b/Marlin/src/lcd/menu/menu_backlash.cpp index faed8cf777..07f3c9d704 100644 --- a/Marlin/src/lcd/menu/menu_backlash.cpp +++ b/Marlin/src/lcd/menu/menu_backlash.cpp @@ -66,6 +66,15 @@ void menu_backlash() { #if HAS_K_AXIS && _CAN_CALI(K) EDIT_BACKLASH_DISTANCE(K); #endif + #if HAS_U_AXIS && _CAN_CALI(U) + EDIT_BACKLASH_DISTANCE(U); + #endif + #if HAS_V_AXIS && _CAN_CALI(V) + EDIT_BACKLASH_DISTANCE(V); + #endif + #if HAS_W_AXIS && _CAN_CALI(W) + EDIT_BACKLASH_DISTANCE(W); + #endif #ifdef BACKLASH_SMOOTHING_MM editable.decimal = backlash.get_smoothing_mm(); diff --git a/Marlin/src/lcd/menu/menu_configuration.cpp b/Marlin/src/lcd/menu/menu_configuration.cpp index 9c4164f7b6..349aafbb8a 100644 --- a/Marlin/src/lcd/menu/menu_configuration.cpp +++ b/Marlin/src/lcd/menu/menu_configuration.cpp @@ -145,9 +145,9 @@ void menu_advanced_settings(); EDIT_ITEM(uint8, MSG_TOOL_MIGRATION_END, &migration.last, 0, EXTRUDERS - 1); // Migrate to a chosen extruder - LOOP_L_N(s, EXTRUDERS) { - if (s != active_extruder) { - ACTION_ITEM_N_P(s, msg_migrate, []{ + EXTRUDER_LOOP() { + if (e != active_extruder) { + ACTION_ITEM_N_P(e, msg_migrate, []{ char cmd[12]; sprintf_P(cmd, PSTR("M217 T%i"), int(MenuItemBase::itemIndex)); queue.inject(cmd); diff --git a/Marlin/src/lcd/menu/menu_mmu2.cpp b/Marlin/src/lcd/menu/menu_mmu2.cpp index 4f3728b74e..a2412b0f6a 100644 --- a/Marlin/src/lcd/menu/menu_mmu2.cpp +++ b/Marlin/src/lcd/menu/menu_mmu2.cpp @@ -48,7 +48,7 @@ void _mmu2_load_filament(uint8_t index) { ui.reset_status(); } void action_mmu2_load_all() { - LOOP_L_N(i, EXTRUDERS) _mmu2_load_filament(i); + EXTRUDER_LOOP() _mmu2_load_filament(e); ui.return_to_status(); } @@ -56,14 +56,14 @@ void menu_mmu2_load_filament() { START_MENU(); BACK_ITEM(MSG_MMU2_MENU); ACTION_ITEM(MSG_MMU2_ALL, action_mmu2_load_all); - LOOP_L_N(i, EXTRUDERS) ACTION_ITEM_N(i, MSG_MMU2_FILAMENT_N, []{ _mmu2_load_filament(MenuItemBase::itemIndex); }); + EXTRUDER_LOOP() ACTION_ITEM_N(e, MSG_MMU2_FILAMENT_N, []{ _mmu2_load_filament(MenuItemBase::itemIndex); }); END_MENU(); } void menu_mmu2_load_to_nozzle() { START_MENU(); BACK_ITEM(MSG_MMU2_MENU); - LOOP_L_N(i, EXTRUDERS) ACTION_ITEM_N(i, MSG_MMU2_FILAMENT_N, []{ action_mmu2_load_filament_to_nozzle(MenuItemBase::itemIndex); }); + EXTRUDER_LOOP() ACTION_ITEM_N(e, MSG_MMU2_FILAMENT_N, []{ action_mmu2_load_filament_to_nozzle(MenuItemBase::itemIndex); }); END_MENU(); } @@ -89,7 +89,7 @@ void action_mmu2_unload_filament() { void menu_mmu2_eject_filament() { START_MENU(); BACK_ITEM(MSG_MMU2_MENU); - LOOP_L_N(i, EXTRUDERS) ACTION_ITEM_N(i, MSG_MMU2_FILAMENT_N, []{ _mmu2_eject_filament(MenuItemBase::itemIndex); }); + EXTRUDER_LOOP() ACTION_ITEM_N(e, MSG_MMU2_FILAMENT_N, []{ _mmu2_eject_filament(MenuItemBase::itemIndex); }); END_MENU(); } @@ -130,7 +130,7 @@ void menu_mmu2_choose_filament() { #if LCD_HEIGHT > 2 STATIC_ITEM(MSG_MMU2_CHOOSE_FILAMENT_HEADER, SS_DEFAULT|SS_INVERT); #endif - LOOP_L_N(i, EXTRUDERS) ACTION_ITEM_N(i, MSG_MMU2_FILAMENT_N, []{ action_mmu2_chosen(MenuItemBase::itemIndex); }); + EXTRUDER_LOOP() ACTION_ITEM_N(e, MSG_MMU2_FILAMENT_N, []{ action_mmu2_chosen(MenuItemBase::itemIndex); }); END_MENU(); } diff --git a/Marlin/src/lcd/menu/menu_motion.cpp b/Marlin/src/lcd/menu/menu_motion.cpp index 0a446b1349..baed081036 100644 --- a/Marlin/src/lcd/menu/menu_motion.cpp +++ b/Marlin/src/lcd/menu/menu_motion.cpp @@ -106,6 +106,15 @@ void lcd_move_x() { _lcd_move_xyz(GET_TEXT(MSG_MOVE_X), X_AXIS); } #if HAS_K_AXIS void lcd_move_k() { _lcd_move_xyz(GET_TEXT(MSG_MOVE_K), K_AXIS); } #endif +#if HAS_U_AXIS + void lcd_move_u() { _lcd_move_xyz(GET_TEXT(MSG_MOVE_U), U_AXIS); } +#endif +#if HAS_V_AXIS + void lcd_move_v() { _lcd_move_xyz(GET_TEXT(MSG_MOVE_V), V_AXIS); } +#endif +#if HAS_W_AXIS + void lcd_move_w() { _lcd_move_xyz(GET_TEXT(MSG_MOVE_W), W_AXIS); } +#endif #if E_MANUAL @@ -263,6 +272,15 @@ void menu_move() { #if HAS_K_AXIS SUBMENU(MSG_MOVE_K, []{ _menu_move_distance(K_AXIS, lcd_move_k); }); #endif + #if HAS_U_AXIS + SUBMENU(MSG_MOVE_U, []{ _menu_move_distance(U_AXIS, lcd_move_u); }); + #endif + #if HAS_V_AXIS + SUBMENU(MSG_MOVE_V, []{ _menu_move_distance(V_AXIS, lcd_move_v); }); + #endif + #if HAS_W_AXIS + SUBMENU(MSG_MOVE_W, []{ _menu_move_distance(W_AXIS, lcd_move_w); }); + #endif } else GCODES_ITEM(MSG_AUTO_HOME, G28_STR); @@ -354,6 +372,15 @@ void menu_move() { #if HAS_K_AXIS GCODES_ITEM_N(K_AXIS, MSG_AUTO_HOME_A, PSTR("G28" STR_K)); #endif + #if HAS_U_AXIS + GCODES_ITEM_N(U_AXIS, MSG_AUTO_HOME_A, PSTR("G28" STR_U)); + #endif + #if HAS_V_AXIS + GCODES_ITEM_N(V_AXIS, MSG_AUTO_HOME_A, PSTR("G28" STR_V)); + #endif + #if HAS_W_AXIS + GCODES_ITEM_N(W_AXIS, MSG_AUTO_HOME_A, PSTR("G28" STR_W)); + #endif END_MENU(); } @@ -407,6 +434,15 @@ void menu_motion() { #if HAS_K_AXIS GCODES_ITEM_N(K_AXIS, MSG_AUTO_HOME_A, PSTR("G28" STR_K)); #endif + #if HAS_U_AXIS + GCODES_ITEM_N(U_AXIS, MSG_AUTO_HOME_A, PSTR("G28" STR_U)); + #endif + #if HAS_V_AXIS + GCODES_ITEM_N(V_AXIS, MSG_AUTO_HOME_A, PSTR("G28" STR_V)); + #endif + #if HAS_W_AXIS + GCODES_ITEM_N(W_AXIS, MSG_AUTO_HOME_A, PSTR("G28" STR_W)); + #endif #endif #endif diff --git a/Marlin/src/lcd/menu/menu_tmc.cpp b/Marlin/src/lcd/menu/menu_tmc.cpp index 7e206e8d79..995bc3b195 100644 --- a/Marlin/src/lcd/menu/menu_tmc.cpp +++ b/Marlin/src/lcd/menu/menu_tmc.cpp @@ -134,6 +134,9 @@ void menu_tmc_current() { TERN_( I_SENSORLESS, TMC_EDIT_STORED_SGT(I)); TERN_( J_SENSORLESS, TMC_EDIT_STORED_SGT(J)); TERN_( K_SENSORLESS, TMC_EDIT_STORED_SGT(K)); + TERN_( U_SENSORLESS, TMC_EDIT_STORED_SGT(U)); + TERN_( V_SENSORLESS, TMC_EDIT_STORED_SGT(V)); + TERN_( W_SENSORLESS, TMC_EDIT_STORED_SGT(W)); END_MENU(); } diff --git a/Marlin/src/lcd/menu/menu_tune.cpp b/Marlin/src/lcd/menu/menu_tune.cpp index 854f36985f..7954edf5a1 100644 --- a/Marlin/src/lcd/menu/menu_tune.cpp +++ b/Marlin/src/lcd/menu/menu_tune.cpp @@ -199,8 +199,8 @@ void menu_tune() { EDIT_ITEM(int3, MSG_FLOW, &planner.flow_percentage[active_extruder], 10, 999, []{ planner.refresh_e_factor(active_extruder); }); // Flow En: #if HAS_MULTI_EXTRUDER - LOOP_L_N(n, EXTRUDERS) - EDIT_ITEM_N(int3, n, MSG_FLOW_N, &planner.flow_percentage[n], 10, 999, []{ planner.refresh_e_factor(MenuItemBase::itemIndex); }); + EXTRUDER_LOOP() + EDIT_ITEM_N(int3, e, MSG_FLOW_N, &planner.flow_percentage[e], 10, 999, []{ planner.refresh_e_factor(MenuItemBase::itemIndex); }); #endif #endif @@ -211,8 +211,8 @@ void menu_tune() { #if EXTRUDERS == 1 EDIT_ITEM(float42_52, MSG_ADVANCE_K, &planner.extruder_advance_K[0], 0, 10); #elif HAS_MULTI_EXTRUDER - LOOP_L_N(n, EXTRUDERS) - EDIT_ITEM_N(float42_52, n, MSG_ADVANCE_K_E, &planner.extruder_advance_K[n], 0, 10); + EXTRUDER_LOOP() + EDIT_ITEM_N(float42_52, e, MSG_ADVANCE_K_E, &planner.extruder_advance_K[e], 0, 10); #endif #endif diff --git a/Marlin/src/libs/L64XX/L64XX_Marlin.cpp b/Marlin/src/libs/L64XX/L64XX_Marlin.cpp index a8c2695630..0aa2a85439 100644 --- a/Marlin/src/libs/L64XX/L64XX_Marlin.cpp +++ b/Marlin/src/libs/L64XX/L64XX_Marlin.cpp @@ -37,7 +37,7 @@ L64XX_Marlin L64xxManager; #include "../../module/planner.h" #include "../../HAL/shared/Delay.h" -static const char LINEAR_AXIS_LIST( +static const char NUM_AXIS_LIST( str_X[] PROGMEM = "X ", str_Y[] PROGMEM = "Y ", str_Z[] PROGMEM = "Z ", str_I[] PROGMEM = STR_I " ", str_J[] PROGMEM = STR_J " ", str_K[] PROGMEM = STR_K " " ), @@ -53,7 +53,7 @@ static const char LINEAR_AXIS_LIST( #define _EN_ITEM(N) , str_E##N PGM_P const L64XX_Marlin::index_to_axis[] PROGMEM = { - LINEAR_AXIS_LIST(str_X, str_Y, str_Z, str_I, str_J, str_K), + NUM_AXIS_LIST(str_X, str_Y, str_Z, str_I, str_J, str_K), str_X2, str_Y2, str_Z2, str_Z3, str_Z4 REPEAT(E_STEPPERS, _EN_ITEM) }; @@ -68,7 +68,7 @@ uint8_t L64XX_Marlin::dir_commands[MAX_L64XX]; // array to hold direction comma #define _EN_ITEM(N) , INVERT_E##N##_DIR const uint8_t L64XX_Marlin::index_to_dir[MAX_L64XX] = { - LINEAR_AXIS_LIST(INVERT_X_DIR, INVERT_Y_DIR, INVERT_Z_DIR, INVERT_I_DIR, INVERT_J_DIR, INVERT_K_DIR) + NUM_AXIS_LIST(INVERT_X_DIR, INVERT_Y_DIR, INVERT_Z_DIR, INVERT_I_DIR, INVERT_J_DIR, INVERT_K_DIR) , (INVERT_X_DIR) ^ BOTH(X_DUAL_STEPPER_DRIVERS, INVERT_X2_VS_X_DIR) // X2 , (INVERT_Y_DIR) ^ BOTH(Y_DUAL_STEPPER_DRIVERS, INVERT_Y2_VS_Y_DIR) // Y2 , (INVERT_Z_DIR) ^ ENABLED(INVERT_Z2_VS_Z_DIR) // Z2 diff --git a/Marlin/src/libs/L64XX/L64XX_Marlin.h b/Marlin/src/libs/L64XX/L64XX_Marlin.h index de7c0d6057..d00b5c16cd 100644 --- a/Marlin/src/libs/L64XX/L64XX_Marlin.h +++ b/Marlin/src/libs/L64XX/L64XX_Marlin.h @@ -36,7 +36,7 @@ #define HAS_L64XX_EXTRUDER (AXIS_IS_L64XX(E0) || AXIS_IS_L64XX(E1) || AXIS_IS_L64XX(E2) || AXIS_IS_L64XX(E3) || AXIS_IS_L64XX(E4) || AXIS_IS_L64XX(E5) || AXIS_IS_L64XX(E6) || AXIS_IS_L64XX(E7)) #define _EN_ITEM(N) , E##N -enum L64XX_axis_t : uint8_t { LINEAR_AXIS_LIST(X, Y, Z, I, J, K), X2, Y2, Z2, Z3, Z4 REPEAT(E_STEPPERS, _EN_ITEM), MAX_L64XX }; +enum L64XX_axis_t : uint8_t { NUM_AXIS_LIST(X, Y, Z, I, J, K), X2, Y2, Z2, Z3, Z4 REPEAT(E_STEPPERS, _EN_ITEM), MAX_L64XX }; #undef _EN_ITEM class L64XX_Marlin : public L64XXHelper { diff --git a/Marlin/src/libs/buzzer.h b/Marlin/src/libs/buzzer.h index db5e3ee4ca..73406c0591 100644 --- a/Marlin/src/libs/buzzer.h +++ b/Marlin/src/libs/buzzer.h @@ -127,3 +127,7 @@ #define BUZZ(d,f) NOOP #endif + +#define ERR_BUZZ() BUZZ(400, 40); +#define OKAY_BUZZ() do{ BUZZ(100, 659); BUZZ(10, 0); BUZZ(100, 698); }while(0) +#define DONE_BUZZ(OK) do{ if (OK) OKAY_BUZZ(); else ERR_BUZZ(); }while(0) diff --git a/Marlin/src/module/delta.cpp b/Marlin/src/module/delta.cpp index cd40175da4..39eb15f896 100644 --- a/Marlin/src/module/delta.cpp +++ b/Marlin/src/module/delta.cpp @@ -233,6 +233,9 @@ void home_delta() { TERN_(I_SENSORLESS, sensorless_t stealth_states_i = start_sensorless_homing_per_axis(I_AXIS)); TERN_(J_SENSORLESS, sensorless_t stealth_states_j = start_sensorless_homing_per_axis(J_AXIS)); TERN_(K_SENSORLESS, sensorless_t stealth_states_k = start_sensorless_homing_per_axis(K_AXIS)); + TERN_(U_SENSORLESS, sensorless_t stealth_states_u = start_sensorless_homing_per_axis(U_AXIS)); + TERN_(V_SENSORLESS, sensorless_t stealth_states_v = start_sensorless_homing_per_axis(V_AXIS)); + TERN_(W_SENSORLESS, sensorless_t stealth_states_w = start_sensorless_homing_per_axis(W_AXIS)); #endif // Move all carriages together linearly until an endstop is hit. @@ -249,6 +252,9 @@ void home_delta() { TERN_(I_SENSORLESS, end_sensorless_homing_per_axis(I_AXIS, stealth_states_i)); TERN_(J_SENSORLESS, end_sensorless_homing_per_axis(J_AXIS, stealth_states_j)); TERN_(K_SENSORLESS, end_sensorless_homing_per_axis(K_AXIS, stealth_states_k)); + TERN_(U_SENSORLESS, end_sensorless_homing_per_axis(U_AXIS, stealth_states_u)); + TERN_(V_SENSORLESS, end_sensorless_homing_per_axis(V_AXIS, stealth_states_v)); + TERN_(W_SENSORLESS, end_sensorless_homing_per_axis(W_AXIS, stealth_states_w)); #endif endstops.validate_homing_move(); diff --git a/Marlin/src/module/endstops.cpp b/Marlin/src/module/endstops.cpp index f41a6c9f87..620f51c0f0 100644 --- a/Marlin/src/module/endstops.cpp +++ b/Marlin/src/module/endstops.cpp @@ -323,6 +323,66 @@ void Endstops::init() { #endif #endif + #if HAS_U_MIN + #if ENABLED(ENDSTOPPULLUP_UMIN) + SET_INPUT_PULLUP(U_MIN_PIN); + #elif ENABLED(ENDSTOPPULLDOWN_UMIN) + SET_INPUT_PULLDOWN(U_MIN_PIN); + #else + SET_INPUT(U_MIN_PIN); + #endif + #endif + + #if HAS_U_MAX + #if ENABLED(ENDSTOPPULLUP_UMAX) + SET_INPUT_PULLUP(U_MAX_PIN); + #elif ENABLED(ENDSTOPPULLDOWN_UMIN) + SET_INPUT_PULLDOWN(U_MAX_PIN); + #else + SET_INPUT(U_MAX_PIN); + #endif + #endif + + #if HAS_V_MIN + #if ENABLED(ENDSTOPPULLUP_VMIN) + SET_INPUT_PULLUP(V_MIN_PIN); + #elif ENABLED(ENDSTOPPULLDOWN_VMIN) + SET_INPUT_PULLDOWN(V_MIN_PIN); + #else + SET_INPUT(V_MIN_PIN); + #endif + #endif + + #if HAS_V_MAX + #if ENABLED(ENDSTOPPULLUP_VMAX) + SET_INPUT_PULLUP(V_MAX_PIN); + #elif ENABLED(ENDSTOPPULLDOWN_VMIN) + SET_INPUT_PULLDOWN(V_MAX_PIN); + #else + SET_INPUT(V_MAX_PIN); + #endif + #endif + + #if HAS_W_MIN + #if ENABLED(ENDSTOPPULLUP_WMIN) + SET_INPUT_PULLUP(W_MIN_PIN); + #elif ENABLED(ENDSTOPPULLDOWN_WMIN) + SET_INPUT_PULLDOWN(W_MIN_PIN); + #else + SET_INPUT(W_MIN_PIN); + #endif + #endif + + #if HAS_W_MAX + #if ENABLED(ENDSTOPPULLUP_WMAX) + SET_INPUT_PULLUP(W_MAX_PIN); + #elif ENABLED(ENDSTOPPULLDOWN_WMIN) + SET_INPUT_PULLDOWN(W_MAX_PIN); + #else + SET_INPUT(W_MAX_PIN); + #endif + #endif + #if PIN_EXISTS(CALIBRATION) #if ENABLED(CALIBRATION_PIN_PULLUP) SET_INPUT_PULLUP(CALIBRATION_PIN); @@ -428,7 +488,7 @@ void Endstops::event_handler() { prev_hit_state = hit_state; if (hit_state) { #if HAS_STATUS_MESSAGE - char LINEAR_AXIS_LIST(chrX = ' ', chrY = ' ', chrZ = ' ', chrI = ' ', chrJ = ' ', chrK = ' '), + char NUM_AXIS_LIST(chrX = ' ', chrY = ' ', chrZ = ' ', chrI = ' ', chrJ = ' ', chrK = ' ', chrU = ' ', chrV = ' ', chrW = ' '), chrP = ' '; #define _SET_STOP_CHAR(A,C) (chr## A = C) #else @@ -448,16 +508,22 @@ void Endstops::event_handler() { #define ENDSTOP_HIT_TEST_I() _ENDSTOP_HIT_TEST(I,'I') #define ENDSTOP_HIT_TEST_J() _ENDSTOP_HIT_TEST(J,'J') #define ENDSTOP_HIT_TEST_K() _ENDSTOP_HIT_TEST(K,'K') + #define ENDSTOP_HIT_TEST_U() _ENDSTOP_HIT_TEST(U,'U') + #define ENDSTOP_HIT_TEST_V() _ENDSTOP_HIT_TEST(V,'V') + #define ENDSTOP_HIT_TEST_W() _ENDSTOP_HIT_TEST(W,'W') SERIAL_ECHO_START(); SERIAL_ECHOPGM(STR_ENDSTOPS_HIT); - LINEAR_AXIS_CODE( + NUM_AXIS_CODE( ENDSTOP_HIT_TEST_X(), ENDSTOP_HIT_TEST_Y(), ENDSTOP_HIT_TEST_Z(), _ENDSTOP_HIT_TEST(I,'I'), _ENDSTOP_HIT_TEST(J,'J'), - _ENDSTOP_HIT_TEST(K,'K') + _ENDSTOP_HIT_TEST(K,'K'), + _ENDSTOP_HIT_TEST(U,'U'), + _ENDSTOP_HIT_TEST(V,'V'), + _ENDSTOP_HIT_TEST(W,'W') ); #if USES_Z_MIN_PROBE_PIN @@ -468,9 +534,9 @@ void Endstops::event_handler() { TERN_(HAS_STATUS_MESSAGE, ui.status_printf(0, - F(S_FMT GANG_N_1(LINEAR_AXES, " %c") " %c"), + F(S_FMT GANG_N_1(NUM_AXES, " %c") " %c"), GET_TEXT(MSG_LCD_ENDSTOPS), - LINEAR_AXIS_LIST(chrX, chrY, chrZ, chrI, chrJ, chrK), chrP + NUM_AXIS_LIST(chrX, chrY, chrZ, chrI, chrJ, chrK, chrU, chrV, chrW), chrP ) ); @@ -568,6 +634,24 @@ void _O2 Endstops::report_states() { #if HAS_K_MAX ES_REPORT(K_MAX); #endif + #if HAS_U_MIN + ES_REPORT(U_MIN); + #endif + #if HAS_U_MAX + ES_REPORT(U_MAX); + #endif + #if HAS_V_MIN + ES_REPORT(V_MIN); + #endif + #if HAS_V_MAX + ES_REPORT(V_MAX); + #endif + #if HAS_W_MIN + ES_REPORT(W_MIN); + #endif + #if HAS_W_MAX + ES_REPORT(W_MAX); + #endif #if ENABLED(PROBE_ACTIVATION_SWITCH) print_es_state(probe_switch_activated(), F(STR_PROBE_EN)); #endif @@ -583,20 +667,20 @@ void _O2 Endstops::report_states() { REPEAT_1(NUM_RUNOUT_SENSORS, _CASE_RUNOUT) #undef _CASE_RUNOUT } - const uint8_t rm = runout.mode[i - 1], - state = runout.out_state(i - 1); + const RunoutMode rm = runout.mode[i - 1]; + const uint8_t outval = runout.out_state(i - 1); SERIAL_ECHOPGM(STR_FILAMENT); if (i > 1) SERIAL_CHAR(' ', '0' + i); SERIAL_ECHOPGM(": "); - if (rm == 0) - SERIAL_ECHOLNPGM("DISABLED"); - else if (rm == 7) { + if (rm == RM_NONE) + SERIAL_ECHOLNPGM(STR_OFF); + else if (rm == RM_MOTION_SENSOR) { SERIAL_ECHOPGM("MOTION : "); - print_es_state(extDigitalRead(pin) == state); + print_es_state(extDigitalRead(pin) == outval); } else - SERIAL_ECHOLNPGM_P(extDigitalRead(pin) == state ? PSTR("MISSING") : PSTR("PRESENT")); + SERIAL_ECHOLNPGM_P(extDigitalRead(pin) == outval ? PSTR("OUT") : PSTR("PRESENT")); } #endif @@ -661,6 +745,9 @@ void Endstops::update() { #define I_AXIS_HEAD I_AXIS #define J_AXIS_HEAD J_AXIS #define K_AXIS_HEAD K_AXIS + #define U_AXIS_HEAD U_AXIS + #define V_AXIS_HEAD V_AXIS + #define W_AXIS_HEAD W_AXIS /** * Check and update endstops @@ -847,6 +934,82 @@ void Endstops::update() { #endif #endif + #if HAS_U_MIN && !U_SPI_SENSORLESS + #if ENABLED(U_DUAL_ENDSTOPS) + UPDATE_ENDSTOP_BIT(U, MIN); + #if HAS_U2_MIN + UPDATE_ENDSTOP_BIT(U2, MIN); + #else + COPY_LIVE_STATE(U_MIN, U2_MIN); + #endif + #else + UPDATE_ENDSTOP_BIT(U, MIN); + #endif + #endif + + #if HAS_U_MAX && !U_SPI_SENSORLESS + #if ENABLED(U_DUAL_ENDSTOPS) + UPDATE_ENDSTOP_BIT(U, MAX); + #if HAS_U2_MAX + UPDATE_ENDSTOP_BIT(U2, MAX); + #else + COPY_LIVE_STATE(U_MAX, U2_MAX); + #endif + #else + UPDATE_ENDSTOP_BIT(U, MAX); + #endif + #endif + + #if HAS_V_MIN && !V_SPI_SENSORLESS + #if ENABLED(V_DUAL_ENDSTOPS) + UPDATE_ENDSTOP_BIT(V, MIN); + #if HAS_V2_MIN + UPDATE_ENDSTOP_BIT(V2, MIN); + #else + COPY_LIVE_STATE(V_MIN, V2_MIN); + #endif + #else + UPDATE_ENDSTOP_BIT(V, MIN); + #endif + #endif + #if HAS_V_MAX && !V_SPI_SENSORLESS + #if ENABLED(O_DUAL_ENDSTOPS) + UPDATE_ENDSTOP_BIT(V, MAX); + #if HAS_V2_MAX + UPDATE_ENDSTOP_BIT(V2, MAX); + #else + COPY_LIVE_STATE(V_MAX, V2_MAX); + #endif + #else + UPDATE_ENDSTOP_BIT(V, MAX); + #endif + #endif + + #if HAS_W_MIN && !W_SPI_SENSORLESS + #if ENABLED(W_DUAL_ENDSTOPS) + UPDATE_ENDSTOP_BIT(W, MIN); + #if HAS_W2_MIN + UPDATE_ENDSTOP_BIT(W2, MIN); + #else + COPY_LIVE_STATE(W_MIN, W2_MIN); + #endif + #else + UPDATE_ENDSTOP_BIT(W, MIN); + #endif + #endif + #if HAS_W_MAX && !W_SPI_SENSORLESS + #if ENABLED(W_DUAL_ENDSTOPS) + UPDATE_ENDSTOP_BIT(W, MAX); + #if HAS_W2_MAX + UPDATE_ENDSTOP_BIT(W2, MAX); + #else + COPY_LIVE_STATE(W_MAX, W2_MAX); + #endif + #else + UPDATE_ENDSTOP_BIT(W, MAX); + #endif + #endif + #if ENDSTOP_NOISE_THRESHOLD /** @@ -947,7 +1110,7 @@ void Endstops::update() { #define PROCESS_ENDSTOP_Z(MINMAX) PROCESS_DUAL_ENDSTOP(Z, MINMAX) #endif - #if HAS_G38_PROBE + #if HAS_G38_PROBE // TODO (DerAndere): Add support for HAS_I_AXIS #define _G38_OPEN_STATE TERN(G38_PROBE_AWAY, (G38_move >= 4), LOW) // For G38 moves check the probe's pin for ALL movement if (G38_move && TEST_ENDSTOP(_ENDSTOP(Z, TERN(USES_Z_MIN_PROBE_PIN, MIN_PROBE, MIN))) != _G38_OPEN_STATE) { @@ -1117,6 +1280,51 @@ void Endstops::update() { } } #endif + + #if HAS_U_AXIS + if (stepper.axis_is_moving(U_AXIS)) { + if (stepper.motor_direction(U_AXIS_HEAD)) { // -direction + #if HAS_U_MIN || (U_SPI_SENSORLESS && U_HOME_TO_MIN) + PROCESS_ENDSTOP(U, MIN); + #endif + } + else { // +direction + #if HAS_U_MAX || (U_SPI_SENSORLESS && U_HOME_TO_MAX) + PROCESS_ENDSTOP(U, MAX); + #endif + } + } + #endif + + #if HAS_V_AXIS + if (stepper.axis_is_moving(V_AXIS)) { + if (stepper.motor_direction(V_AXIS_HEAD)) { // -direction + #if HAS_V_MIN || (V_SPI_SENSORLESS && V_HOME_TO_MIN) + PROCESS_ENDSTOP(V, MIN); + #endif + } + else { // +direction + #if HAS_V_MAX || (V_SPI_SENSORLESS && V_HOME_TO_MAX) + PROCESS_ENDSTOP(V, MAX); + #endif + } + } + #endif + + #if HAS_W_AXIS + if (stepper.axis_is_moving(W_AXIS)) { + if (stepper.motor_direction(W_AXIS_HEAD)) { // -direction + #if HAS_W_MIN || (W_SPI_SENSORLESS && W_HOME_TO_MIN) + PROCESS_ENDSTOP(W, MIN); + #endif + } + else { // +direction + #if HAS_W_MAX || (W_SPI_SENSORLESS && W_HOME_TO_MAX) + PROCESS_ENDSTOP(W, MAX); + #endif + } + } + #endif } // Endstops::update() #if ENABLED(SPI_ENDSTOPS) @@ -1178,6 +1386,24 @@ void Endstops::update() { hit = true; } #endif + #if U_SPI_SENSORLESS + if (tmc_spi_homing.u && stepperU.test_stall_status()) { + SBI(live_state, U_ENDSTOP); + hit = true; + } + #endif + #if V_SPI_SENSORLESS + if (tmc_spi_homing.v && stepperV.test_stall_status()) { + SBI(live_state, V_ENDSTOP); + hit = true; + } + #endif + #if W_SPI_SENSORLESS + if (tmc_spi_homing.w && stepperW.test_stall_status()) { + SBI(live_state, W_ENDSTOP); + hit = true; + } + #endif if (TERN0(ENDSTOP_INTERRUPTS_FEATURE, hit)) update(); @@ -1191,6 +1417,9 @@ void Endstops::update() { TERN_(I_SPI_SENSORLESS, CBI(live_state, I_ENDSTOP)); TERN_(J_SPI_SENSORLESS, CBI(live_state, J_ENDSTOP)); TERN_(K_SPI_SENSORLESS, CBI(live_state, K_ENDSTOP)); + TERN_(U_SPI_SENSORLESS, CBI(live_state, U_ENDSTOP)); + TERN_(V_SPI_SENSORLESS, CBI(live_state, V_ENDSTOP)); + TERN_(W_SPI_SENSORLESS, CBI(live_state, W_ENDSTOP)); } #endif // SPI_ENDSTOPS @@ -1285,6 +1514,24 @@ void Endstops::update() { #if HAS_K_MIN ES_GET_STATE(K_MIN); #endif + #if HAS_U_MAX + ES_GET_STATE(U_MAX); + #endif + #if HAS_U_MIN + ES_GET_STATE(U_MIN); + #endif + #if HAS_V_MAX + ES_GET_STATE(V_MAX); + #endif + #if HAS_V_MIN + ES_GET_STATE(V_MIN); + #endif + #if HAS_W_MAX + ES_GET_STATE(W_MAX); + #endif + #if HAS_W_MIN + ES_GET_STATE(W_MIN); + #endif uint16_t endstop_change = live_state_local ^ old_live_state_local; #define ES_REPORT_CHANGE(S) if (TEST(endstop_change, S)) SERIAL_ECHOPGM(" " STRINGIFY(S) ":", TEST(live_state_local, S)) @@ -1359,6 +1606,25 @@ void Endstops::update() { #if HAS_K_MAX ES_REPORT_CHANGE(K_MAX); #endif + #if HAS_U_MIN + ES_REPORT_CHANGE(U_MIN); + #endif + #if HAS_U_MAX + ES_REPORT_CHANGE(U_MAX); + #endif + #if HAS_V_MIN + ES_REPORT_CHANGE(V_MIN); + #endif + #if HAS_V_MAX + ES_REPORT_CHANGE(V_MAX); + #endif + #if HAS_W_MIN + ES_REPORT_CHANGE(W_MIN); + #endif + #if HAS_W_MAX + ES_REPORT_CHANGE(W_MAX); + #endif + SERIAL_ECHOLNPGM("\n"); hal.set_pwm_duty(pin_t(LED_PIN), local_LED_status); local_LED_status ^= 255; diff --git a/Marlin/src/module/endstops.h b/Marlin/src/module/endstops.h index 82a44cf95b..1848e6cdcf 100644 --- a/Marlin/src/module/endstops.h +++ b/Marlin/src/module/endstops.h @@ -45,6 +45,12 @@ enum EndstopEnum : char { _ES_ITEM(HAS_J_MAX, J_MAX) _ES_ITEM(HAS_K_MIN, K_MIN) _ES_ITEM(HAS_K_MAX, K_MAX) + _ES_ITEM(HAS_U_MIN, U_MIN) + _ES_ITEM(HAS_U_MAX, U_MAX) + _ES_ITEM(HAS_V_MIN, V_MIN) + _ES_ITEM(HAS_V_MAX, V_MAX) + _ES_ITEM(HAS_W_MIN, W_MIN) + _ES_ITEM(HAS_W_MAX, W_MAX) // Extra Endstops for XYZ #if ENABLED(X_DUAL_ENDSTOPS) @@ -234,7 +240,7 @@ class Endstops { typedef struct { union { bool any; - struct { bool LINEAR_AXIS_LIST(x:1, y:1, z:1, i:1, j:1, k:1); }; + struct { bool NUM_AXIS_LIST(x:1, y:1, z:1, i:1, j:1, k:1); }; }; } tmc_spi_homing_t; static tmc_spi_homing_t tmc_spi_homing; diff --git a/Marlin/src/module/motion.cpp b/Marlin/src/module/motion.cpp index 4b0c6aba7d..3037c38bb0 100644 --- a/Marlin/src/module/motion.cpp +++ b/Marlin/src/module/motion.cpp @@ -29,9 +29,8 @@ #include "stepper.h" #include "planner.h" #include "temperature.h" - #include "../gcode/gcode.h" - +#include "../lcd/marlinui.h" #include "../inc/MarlinConfig.h" #if IS_SCARA @@ -51,10 +50,6 @@ #include "../feature/bltouch.h" #endif -#if HAS_STATUS_MESSAGE - #include "../lcd/marlinui.h" -#endif - #if HAS_FILAMENT_SENSOR #include "../feature/runout.h" #endif @@ -89,7 +84,7 @@ bool relative_mode; // = false; #define Z_INIT_POS Z_HOME_POS #endif -xyze_pos_t current_position = LOGICAL_AXIS_ARRAY(0, X_HOME_POS, Y_HOME_POS, Z_INIT_POS, I_HOME_POS, J_HOME_POS, K_HOME_POS); +xyze_pos_t current_position = LOGICAL_AXIS_ARRAY(0, X_HOME_POS, Y_HOME_POS, Z_INIT_POS, I_HOME_POS, J_HOME_POS, K_HOME_POS, U_HOME_POS, V_HOME_POS, W_HOME_POS); /** * Cartesian Destination @@ -125,9 +120,7 @@ xyze_pos_t destination; // {0} ); // Transpose from [XYZ][HOTENDS] to [HOTENDS][XYZ] HOTEND_LOOP() LOOP_ABC(a) hotend_offset[e][a] = tmp[a][e]; - #if ENABLED(DUAL_X_CARRIAGE) - hotend_offset[1].x = _MAX(X2_HOME_POS, X2_MAX_POS); - #endif + TERN_(DUAL_X_CARRIAGE, hotend_offset[1].x = _MAX(X2_HOME_POS, X2_MAX_POS)); } #endif @@ -196,13 +189,16 @@ inline void report_more_positions() { inline void report_logical_position(const xyze_pos_t &rpos) { const xyze_pos_t lpos = rpos.asLogical(); SERIAL_ECHOPGM_P( - LIST_N(DOUBLE(LINEAR_AXES), + LIST_N(DOUBLE(NUM_AXES), X_LBL, lpos.x, SP_Y_LBL, lpos.y, SP_Z_LBL, lpos.z, SP_I_LBL, lpos.i, SP_J_LBL, lpos.j, - SP_K_LBL, lpos.k + SP_K_LBL, lpos.k, + SP_U_LBL, lpos.u, + SP_V_LBL, lpos.v, + SP_W_LBL, lpos.w ) #if HAS_EXTRUDERS , SP_E_LBL, lpos.e @@ -217,7 +213,8 @@ void report_real_position() { xyze_pos_t npos = LOGICAL_AXIS_ARRAY( planner.get_axis_position_mm(E_AXIS), cartes.x, cartes.y, cartes.z, - cartes.i, cartes.j, cartes.k + cartes.i, cartes.j, cartes.k, + cartes.u, cartes.v, cartes.w ); TERN_(HAS_POSITION_MODIFIERS, planner.unapply_modifiers(npos, true)); @@ -265,13 +262,16 @@ void report_current_position_projected() { const xyz_pos_t lpos = cartes.asLogical(); SERIAL_ECHOPGM_P( - LIST_N(DOUBLE(LINEAR_AXES), + LIST_N(DOUBLE(NUM_AXES), X_LBL, lpos.x, SP_Y_LBL, lpos.y, SP_Z_LBL, lpos.z, SP_I_LBL, lpos.i, SP_J_LBL, lpos.j, - SP_K_LBL, lpos.k + SP_K_LBL, lpos.k, + SP_U_LBL, lpos.u, + SP_V_LBL, lpos.v, + SP_W_LBL, lpos.w ) #if HAS_EXTRUDERS , SP_E_LBL, current_position.e @@ -362,13 +362,16 @@ void get_cartesian_from_steppers() { ); cartes.z = planner.get_axis_position_mm(Z_AXIS); #else - LINEAR_AXIS_CODE( + NUM_AXIS_CODE( cartes.x = planner.get_axis_position_mm(X_AXIS), cartes.y = planner.get_axis_position_mm(Y_AXIS), cartes.z = planner.get_axis_position_mm(Z_AXIS), cartes.i = planner.get_axis_position_mm(I_AXIS), cartes.j = planner.get_axis_position_mm(J_AXIS), - cartes.k = planner.get_axis_position_mm(K_AXIS) + cartes.k = planner.get_axis_position_mm(K_AXIS), + cartes.u = planner.get_axis_position_mm(U_AXIS), + cartes.v = planner.get_axis_position_mm(V_AXIS), + cartes.w = planner.get_axis_position_mm(W_AXIS) ); #endif } @@ -475,24 +478,23 @@ void _internal_move_to_destination(const_feedRate_t fr_mm_s/*=0.0f*/ * - Delta may lower Z first to get into the free motion zone. * - Before returning, wait for the planner buffer to empty. */ -void do_blocking_move_to(LINEAR_AXIS_ARGS(const float), const_feedRate_t fr_mm_s/*=0.0f*/) { +void do_blocking_move_to(NUM_AXIS_ARGS(const float), const_feedRate_t fr_mm_s/*=0.0f*/) { DEBUG_SECTION(log_move, "do_blocking_move_to", DEBUGGING(LEVELING)); - if (DEBUGGING(LEVELING)) DEBUG_XYZ("> ", LINEAR_AXIS_ARGS()); + if (DEBUGGING(LEVELING)) DEBUG_XYZ("> ", NUM_AXIS_ARGS()); const feedRate_t xy_feedrate = fr_mm_s ?: feedRate_t(XY_PROBE_FEEDRATE_MM_S); #if HAS_Z_AXIS const feedRate_t z_feedrate = fr_mm_s ?: homing_feedrate(Z_AXIS); #endif - #if HAS_I_AXIS - const feedRate_t i_feedrate = fr_mm_s ?: homing_feedrate(I_AXIS); - #endif - #if HAS_J_AXIS - const feedRate_t j_feedrate = fr_mm_s ?: homing_feedrate(J_AXIS); - #endif - #if HAS_K_AXIS - const feedRate_t k_feedrate = fr_mm_s ?: homing_feedrate(K_AXIS); - #endif + SECONDARY_AXIS_CODE( + const feedRate_t i_feedrate = fr_mm_s ?: homing_feedrate(I_AXIS), + const feedRate_t j_feedrate = fr_mm_s ?: homing_feedrate(J_AXIS), + const feedRate_t k_feedrate = fr_mm_s ?: homing_feedrate(K_AXIS), + const feedRate_t u_feedrate = fr_mm_s ?: homing_feedrate(U_AXIS), + const feedRate_t v_feedrate = fr_mm_s ?: homing_feedrate(V_AXIS), + const feedRate_t w_feedrate = fr_mm_s ?: homing_feedrate(W_AXIS) + ); #if IS_KINEMATIC if (!position_is_reachable(x, y)) return; @@ -561,7 +563,18 @@ void do_blocking_move_to(LINEAR_AXIS_ARGS(const float), const_feedRate_t fr_mm_s #if HAS_K_AXIS current_position.k = k; line_to_current_position(k_feedrate); #endif - #if HAS_Z_AXIS // If Z needs to lower, do it after moving XY... + #if HAS_U_AXIS + current_position.u = u; line_to_current_position(u_feedrate); + #endif + #if HAS_V_AXIS + current_position.v = v; line_to_current_position(v_feedrate); + #endif + #if HAS_W_AXIS + current_position.w = w; line_to_current_position(w_feedrate); + #endif + + #if HAS_Z_AXIS + // If Z needs to lower, do it after moving XY if (current_position.z > z) { current_position.z = z; line_to_current_position(z_feedrate); } #endif @@ -571,17 +584,19 @@ void do_blocking_move_to(LINEAR_AXIS_ARGS(const float), const_feedRate_t fr_mm_s } void do_blocking_move_to(const xy_pos_t &raw, const_feedRate_t fr_mm_s/*=0.0f*/) { - do_blocking_move_to(LINEAR_AXIS_LIST(raw.x, raw.y, current_position.z, current_position.i, current_position.j, current_position.k), fr_mm_s); + do_blocking_move_to(NUM_AXIS_LIST(raw.x, raw.y, current_position.z, current_position.i, current_position.j, current_position.k, + current_position.u, current_position.v, current_position.w), fr_mm_s); } void do_blocking_move_to(const xyz_pos_t &raw, const_feedRate_t fr_mm_s/*=0.0f*/) { - do_blocking_move_to(LINEAR_AXIS_ELEM(raw), fr_mm_s); + do_blocking_move_to(NUM_AXIS_ELEM(raw), fr_mm_s); } void do_blocking_move_to(const xyze_pos_t &raw, const_feedRate_t fr_mm_s/*=0.0f*/) { - do_blocking_move_to(LINEAR_AXIS_ELEM(raw), fr_mm_s); + do_blocking_move_to(NUM_AXIS_ELEM(raw), fr_mm_s); } void do_blocking_move_to_x(const_float_t rx, const_feedRate_t fr_mm_s/*=0.0*/) { do_blocking_move_to( - LINEAR_AXIS_LIST(rx, current_position.y, current_position.z, current_position.i, current_position.j, current_position.k), + NUM_AXIS_LIST(rx, current_position.y, current_position.z, current_position.i, current_position.j, current_position.k, + current_position.u, current_position.v, current_position.w), fr_mm_s ); } @@ -589,7 +604,8 @@ void do_blocking_move_to_x(const_float_t rx, const_feedRate_t fr_mm_s/*=0.0*/) { #if HAS_Y_AXIS void do_blocking_move_to_y(const_float_t ry, const_feedRate_t fr_mm_s/*=0.0*/) { do_blocking_move_to( - LINEAR_AXIS_LIST(current_position.x, ry, current_position.z, current_position.i, current_position.j, current_position.k), + NUM_AXIS_LIST(current_position.x, ry, current_position.z, current_position.i, current_position.j, current_position.k, + current_position.u, current_position.v, current_position.w), fr_mm_s ); } @@ -607,7 +623,7 @@ void do_blocking_move_to_x(const_float_t rx, const_feedRate_t fr_mm_s/*=0.0*/) { } void do_blocking_move_to_xyz_i(const xyze_pos_t &raw, const_float_t i, const_feedRate_t fr_mm_s/*=0.0f*/) { do_blocking_move_to( - LINEAR_AXIS_LIST(raw.x, raw.y, raw.z, i, raw.j, raw.k), + NUM_AXIS_LIST(raw.x, raw.y, raw.z, i, raw.j, raw.k, raw.u, raw.v, raw.w), fr_mm_s ); } @@ -619,7 +635,7 @@ void do_blocking_move_to_x(const_float_t rx, const_feedRate_t fr_mm_s/*=0.0*/) { } void do_blocking_move_to_xyzi_j(const xyze_pos_t &raw, const_float_t j, const_feedRate_t fr_mm_s/*=0.0f*/) { do_blocking_move_to( - LINEAR_AXIS_LIST(raw.x, raw.y, raw.z, raw.i, j, raw.k), + NUM_AXIS_LIST(raw.x, raw.y, raw.z, raw.i, j, raw.k, raw.u, raw.v, raw.w), fr_mm_s ); } @@ -631,7 +647,43 @@ void do_blocking_move_to_x(const_float_t rx, const_feedRate_t fr_mm_s/*=0.0*/) { } void do_blocking_move_to_xyzij_k(const xyze_pos_t &raw, const_float_t k, const_feedRate_t fr_mm_s/*=0.0f*/) { do_blocking_move_to( - LINEAR_AXIS_LIST(raw.x, raw.y, raw.z, raw.i, raw.j, k), + NUM_AXIS_LIST(raw.x, raw.y, raw.z, raw.i, raw.j, k, raw.u, raw.v, raw.w), + fr_mm_s + ); + } +#endif + +#if HAS_U_AXIS + void do_blocking_move_to_u(const_float_t ru, const_feedRate_t fr_mm_s/*=0.0*/) { + do_blocking_move_to_xyzijk_u(current_position, ru, fr_mm_s); + } + void do_blocking_move_to_xyzijk_u(const xyze_pos_t &raw, const_float_t u, const_feedRate_t fr_mm_s/*=0.0f*/) { + do_blocking_move_to( + NUM_AXIS_LIST(raw.x, raw.y, raw.z, raw.i, raw.j, raw.k, u, raw.v, raw.w), + fr_mm_s + ); + } +#endif + +#if HAS_V_AXIS + void do_blocking_move_to_v(const_float_t rv, const_feedRate_t fr_mm_s/*=0.0*/) { + do_blocking_move_to_xyzijku_v(current_position, rv, fr_mm_s); + } + void do_blocking_move_to_xyzijku_v(const xyze_pos_t &raw, const_float_t v, const_feedRate_t fr_mm_s/*=0.0f*/) { + do_blocking_move_to( + NUM_AXIS_LIST(raw.x, raw.y, raw.z, raw.i, raw.j, raw.k, raw.u, v, raw.w), + fr_mm_s + ); + } +#endif + +#if HAS_W_AXIS + void do_blocking_move_to_w(const_float_t rw, const_feedRate_t fr_mm_s/*=0.0*/) { + do_blocking_move_to_xyzijkuv_w(current_position, rw, fr_mm_s); + } + void do_blocking_move_to_xyzijkuv_w(const xyze_pos_t &raw, const_float_t w, const_feedRate_t fr_mm_s/*=0.0f*/) { + do_blocking_move_to( + NUM_AXIS_LIST(raw.x, raw.y, raw.z, raw.i, raw.j, raw.k, raw.u, raw.v, w), fr_mm_s ); } @@ -640,7 +692,8 @@ void do_blocking_move_to_x(const_float_t rx, const_feedRate_t fr_mm_s/*=0.0*/) { #if HAS_Y_AXIS void do_blocking_move_to_xy(const_float_t rx, const_float_t ry, const_feedRate_t fr_mm_s/*=0.0*/) { do_blocking_move_to( - LINEAR_AXIS_LIST(rx, ry, current_position.z, current_position.i, current_position.j, current_position.k), + NUM_AXIS_LIST(rx, ry, current_position.z, current_position.i, current_position.j, current_position.k, + current_position.u, current_position.v, current_position.w), fr_mm_s ); } @@ -652,7 +705,8 @@ void do_blocking_move_to_x(const_float_t rx, const_feedRate_t fr_mm_s/*=0.0*/) { #if HAS_Z_AXIS void do_blocking_move_to_xy_z(const xy_pos_t &raw, const_float_t z, const_feedRate_t fr_mm_s/*=0.0f*/) { do_blocking_move_to( - LINEAR_AXIS_LIST(raw.x, raw.y, z, current_position.i, current_position.j, current_position.k), + NUM_AXIS_LIST(raw.x, raw.y, z, current_position.i, current_position.j, current_position.k, + current_position.u, current_position.v, current_position.w), fr_mm_s ); } @@ -687,8 +741,8 @@ void restore_feedrate_and_scaling() { // Software Endstops are based on the configured limits. soft_endstops_t soft_endstop = { true, false, - LINEAR_AXIS_ARRAY(X_MIN_POS, Y_MIN_POS, Z_MIN_POS, I_MIN_POS, J_MIN_POS, K_MIN_POS), - LINEAR_AXIS_ARRAY(X_MAX_BED, Y_MAX_BED, Z_MAX_POS, I_MAX_POS, J_MAX_POS, K_MAX_POS) + NUM_AXIS_ARRAY(X_MIN_POS, Y_MIN_POS, Z_MIN_POS, I_MIN_POS, J_MIN_POS, K_MIN_POS, U_MIN_POS, V_MIN_POS, W_MIN_POS), + NUM_AXIS_ARRAY(X_MAX_BED, Y_MAX_BED, Z_MAX_POS, I_MAX_POS, J_MAX_POS, K_MAX_POS, U_MAX_POS, V_MAX_POS, W_MAX_POS) }; /** @@ -867,6 +921,36 @@ void restore_feedrate_and_scaling() { #endif } #endif + #if HAS_U_AXIS + if (axis_was_homed(U_AXIS)) { + #if !HAS_SOFTWARE_ENDSTOPS || ENABLED(MIN_SOFTWARE_ENDSTOP_U) + NOLESS(target.u, soft_endstop.min.u); + #endif + #if !HAS_SOFTWARE_ENDSTOPS || ENABLED(MAX_SOFTWARE_ENDSTOP_U) + NOMORE(target.u, soft_endstop.max.u); + #endif + } + #endif + #if HAS_V_AXIS + if (axis_was_homed(V_AXIS)) { + #if !HAS_SOFTWARE_ENDSTOPS || ENABLED(MIN_SOFTWARE_ENDSTOP_V) + NOLESS(target.v, soft_endstop.min.v); + #endif + #if !HAS_SOFTWARE_ENDSTOPS || ENABLED(MAX_SOFTWARE_ENDSTOP_V) + NOMORE(target.v, soft_endstop.max.v); + #endif + } + #endif + #if HAS_W_AXIS + if (axis_was_homed(W_AXIS)) { + #if !HAS_SOFTWARE_ENDSTOPS || ENABLED(MIN_SOFTWARE_ENDSTOP_W) + NOLESS(target.w, soft_endstop.min.w); + #endif + #if !HAS_SOFTWARE_ENDSTOPS || ENABLED(MAX_SOFTWARE_ENDSTOP_W) + NOMORE(target.w, soft_endstop.max.w); + #endif + } + #endif } #else // !HAS_SOFTWARE_ENDSTOPS @@ -1116,16 +1200,15 @@ FORCE_INLINE void segment_idle(millis_t &next_idle_ms) { bool idex_mirrored_mode = false; // Used in mode 3 float x_home_pos(const uint8_t extruder) { - if (extruder == 0) - return X_HOME_POS; - else - /** - * In dual carriage mode the extruder offset provides an override of the - * second X-carriage position when homed - otherwise X2_HOME_POS is used. - * This allows soft recalibration of the second extruder home position - * without firmware reflash (through the M218 command). - */ - return hotend_offset[1].x > 0 ? hotend_offset[1].x : X2_HOME_POS; + if (extruder == 0) return X_HOME_POS; + + /** + * In dual carriage mode the extruder offset provides an override of the + * second X-carriage position when homed - otherwise X2_HOME_POS is used. + * This allows soft recalibration of the second extruder home position + * (with M218 T1 Xn) without firmware reflash. + */ + return hotend_offset[1].x > 0 ? hotend_offset[1].x : X2_HOME_POS; } void idex_set_mirrored_mode(const bool mirr) { @@ -1305,9 +1388,10 @@ void prepare_line_to_destination() { CBI(b, a); }; // Clear test bits that are trusted - LINEAR_AXIS_CODE( + NUM_AXIS_CODE( set_should(axis_bits, X_AXIS), set_should(axis_bits, Y_AXIS), set_should(axis_bits, Z_AXIS), - set_should(axis_bits, I_AXIS), set_should(axis_bits, J_AXIS), set_should(axis_bits, K_AXIS) + set_should(axis_bits, I_AXIS), set_should(axis_bits, J_AXIS), set_should(axis_bits, K_AXIS), + set_should(axis_bits, U_AXIS), set_should(axis_bits, V_AXIS), set_should(axis_bits, W_AXIS) ); return axis_bits; } @@ -1317,18 +1401,21 @@ void prepare_line_to_destination() { PGM_P home_first = GET_TEXT(MSG_HOME_FIRST); char msg[strlen_P(home_first)+1]; sprintf_P(msg, home_first, - LINEAR_AXIS_LIST( - TEST(axis_bits, X_AXIS) ? "X" : "", - TEST(axis_bits, Y_AXIS) ? "Y" : "", - TEST(axis_bits, Z_AXIS) ? "Z" : "", + NUM_AXIS_LIST( + TEST(axis_bits, X_AXIS) ? STR_A : "", + TEST(axis_bits, Y_AXIS) ? STR_B : "", + TEST(axis_bits, Z_AXIS) ? STR_C : "", TEST(axis_bits, I_AXIS) ? STR_I : "", TEST(axis_bits, J_AXIS) ? STR_J : "", - TEST(axis_bits, K_AXIS) ? STR_K : "" + TEST(axis_bits, K_AXIS) ? STR_K : "", + TEST(axis_bits, U_AXIS) ? STR_U : "", + TEST(axis_bits, V_AXIS) ? STR_V : "", + TEST(axis_bits, W_AXIS) ? STR_W : "" ) ); SERIAL_ECHO_START(); SERIAL_ECHOLN(msg); - TERN_(HAS_STATUS_MESSAGE, ui.set_status(msg)); + ui.set_status(msg); return true; } return false; @@ -1362,9 +1449,7 @@ void prepare_line_to_destination() { #if X_SENSORLESS case X_AXIS: stealth_states.x = tmc_enable_stallguard(stepperX); - #if AXIS_HAS_STALLGUARD(X2) - stealth_states.x2 = tmc_enable_stallguard(stepperX2); - #endif + TERN_(X2_SENSORLESS, stealth_states.x2 = tmc_enable_stallguard(stepperX2)); #if ANY(CORE_IS_XY, MARKFORGED_XY, MARKFORGED_YX) && Y_SENSORLESS stealth_states.y = tmc_enable_stallguard(stepperY); #elif CORE_IS_XZ && Z_SENSORLESS @@ -1375,9 +1460,7 @@ void prepare_line_to_destination() { #if Y_SENSORLESS case Y_AXIS: stealth_states.y = tmc_enable_stallguard(stepperY); - #if AXIS_HAS_STALLGUARD(Y2) - stealth_states.y2 = tmc_enable_stallguard(stepperY2); - #endif + TERN_(Y2_SENSORLESS, stealth_states.y2 = tmc_enable_stallguard(stepperY2)); #if ANY(CORE_IS_XY, MARKFORGED_XY, MARKFORGED_YX) && X_SENSORLESS stealth_states.x = tmc_enable_stallguard(stepperX); #elif CORE_IS_YZ && Z_SENSORLESS @@ -1388,15 +1471,9 @@ void prepare_line_to_destination() { #if Z_SENSORLESS case Z_AXIS: stealth_states.z = tmc_enable_stallguard(stepperZ); - #if AXIS_HAS_STALLGUARD(Z2) - stealth_states.z2 = tmc_enable_stallguard(stepperZ2); - #endif - #if AXIS_HAS_STALLGUARD(Z3) - stealth_states.z3 = tmc_enable_stallguard(stepperZ3); - #endif - #if AXIS_HAS_STALLGUARD(Z4) - stealth_states.z4 = tmc_enable_stallguard(stepperZ4); - #endif + TERN_(Z2_SENSORLESS, stealth_states.z2 = tmc_enable_stallguard(stepperZ2)); + TERN_(Z3_SENSORLESS, stealth_states.z3 = tmc_enable_stallguard(stepperZ3)); + TERN_(Z4_SENSORLESS, stealth_states.z4 = tmc_enable_stallguard(stepperZ4)); #if CORE_IS_XZ && X_SENSORLESS stealth_states.x = tmc_enable_stallguard(stepperX); #elif CORE_IS_YZ && Y_SENSORLESS @@ -1413,6 +1490,15 @@ void prepare_line_to_destination() { #if K_SENSORLESS case K_AXIS: stealth_states.k = tmc_enable_stallguard(stepperK); break; #endif + #if U_SENSORLESS + case U_AXIS: stealth_states.u = tmc_enable_stallguard(stepperU); break; + #endif + #if V_SENSORLESS + case V_AXIS: stealth_states.v = tmc_enable_stallguard(stepperV); break; + #endif + #if W_SENSORLESS + case W_AXIS: stealth_states.w = tmc_enable_stallguard(stepperW); break; + #endif } #if ENABLED(SPI_ENDSTOPS) @@ -1433,6 +1519,15 @@ void prepare_line_to_destination() { #if HAS_K_AXIS case K_AXIS: if (ENABLED(K_SPI_SENSORLESS)) endstops.tmc_spi_homing.k = true; break; #endif + #if HAS_U_AXIS + case U_AXIS: if (ENABLED(U_SPI_SENSORLESS)) endstops.tmc_spi_homing.u = true; break; + #endif + #if HAS_V_AXIS + case V_AXIS: if (ENABLED(V_SPI_SENSORLESS)) endstops.tmc_spi_homing.v = true; break; + #endif + #if HAS_W_AXIS + case W_AXIS: if (ENABLED(W_SPI_SENSORLESS)) endstops.tmc_spi_homing.w = true; break; + #endif default: break; } #endif @@ -1448,9 +1543,7 @@ void prepare_line_to_destination() { #if X_SENSORLESS case X_AXIS: tmc_disable_stallguard(stepperX, enable_stealth.x); - #if AXIS_HAS_STALLGUARD(X2) - tmc_disable_stallguard(stepperX2, enable_stealth.x2); - #endif + TERN_(X2_SENSORLESS, tmc_disable_stallguard(stepperX2, enable_stealth.x2)); #if ANY(CORE_IS_XY, MARKFORGED_XY, MARKFORGED_YX) && Y_SENSORLESS tmc_disable_stallguard(stepperY, enable_stealth.y); #elif CORE_IS_XZ && Z_SENSORLESS @@ -1461,9 +1554,7 @@ void prepare_line_to_destination() { #if Y_SENSORLESS case Y_AXIS: tmc_disable_stallguard(stepperY, enable_stealth.y); - #if AXIS_HAS_STALLGUARD(Y2) - tmc_disable_stallguard(stepperY2, enable_stealth.y2); - #endif + TERN_(Y2_SENSORLESS, tmc_disable_stallguard(stepperY2, enable_stealth.y2)); #if ANY(CORE_IS_XY, MARKFORGED_XY, MARKFORGED_YX) && X_SENSORLESS tmc_disable_stallguard(stepperX, enable_stealth.x); #elif CORE_IS_YZ && Z_SENSORLESS @@ -1474,15 +1565,9 @@ void prepare_line_to_destination() { #if Z_SENSORLESS case Z_AXIS: tmc_disable_stallguard(stepperZ, enable_stealth.z); - #if AXIS_HAS_STALLGUARD(Z2) - tmc_disable_stallguard(stepperZ2, enable_stealth.z2); - #endif - #if AXIS_HAS_STALLGUARD(Z3) - tmc_disable_stallguard(stepperZ3, enable_stealth.z3); - #endif - #if AXIS_HAS_STALLGUARD(Z4) - tmc_disable_stallguard(stepperZ4, enable_stealth.z4); - #endif + TERN_(Z2_SENSORLESS, tmc_disable_stallguard(stepperZ2, enable_stealth.z2)); + TERN_(Z3_SENSORLESS, tmc_disable_stallguard(stepperZ3, enable_stealth.z3)); + TERN_(Z4_SENSORLESS, tmc_disable_stallguard(stepperZ4, enable_stealth.z4)); #if CORE_IS_XZ && X_SENSORLESS tmc_disable_stallguard(stepperX, enable_stealth.x); #elif CORE_IS_YZ && Y_SENSORLESS @@ -1499,6 +1584,15 @@ void prepare_line_to_destination() { #if K_SENSORLESS case K_AXIS: tmc_disable_stallguard(stepperK, enable_stealth.k); break; #endif + #if U_SENSORLESS + case U_AXIS: tmc_disable_stallguard(stepperU, enable_stealth.u); break; + #endif + #if V_SENSORLESS + case V_AXIS: tmc_disable_stallguard(stepperV, enable_stealth.v); break; + #endif + #if W_SENSORLESS + case W_AXIS: tmc_disable_stallguard(stepperW, enable_stealth.w); break; + #endif } #if ENABLED(SPI_ENDSTOPS) @@ -1519,6 +1613,15 @@ void prepare_line_to_destination() { #if HAS_K_AXIS case K_AXIS: if (ENABLED(K_SPI_SENSORLESS)) endstops.tmc_spi_homing.k = false; break; #endif + #if HAS_U_AXIS + case U_AXIS: if (ENABLED(U_SPI_SENSORLESS)) endstops.tmc_spi_homing.u = false; break; + #endif + #if HAS_V_AXIS + case V_AXIS: if (ENABLED(V_SPI_SENSORLESS)) endstops.tmc_spi_homing.v = false; break; + #endif + #if HAS_W_AXIS + case W_AXIS: if (ENABLED(W_SPI_SENSORLESS)) endstops.tmc_spi_homing.w = false; break; + #endif default: break; } #endif @@ -1695,6 +1798,30 @@ void prepare_line_to_destination() { stepperBackoutDir = INVERT_K_DIR ? effectorBackoutDir : -effectorBackoutDir; break; #endif + #ifdef U_MICROSTEPS + case U_AXIS: + phasePerUStep = PHASE_PER_MICROSTEP(U); + phaseCurrent = stepperU.get_microstep_counter(); + effectorBackoutDir = -U_HOME_DIR; + stepperBackoutDir = INVERT_U_DIR ? effectorBackoutDir : -effectorBackoutDir; + break; + #endif + #ifdef V_MICROSTEPS + case V_AXIS: + phasePerUStep = PHASE_PER_MICROSTEP(V); + phaseCurrent = stepperV.get_microstep_counter(); + effectorBackoutDir = -V_HOME_DIR; + stepperBackoutDir = INVERT_V_DIR ? effectorBackoutDir : -effectorBackoutDir; + break; + #endif + #ifdef W_MICROSTEPS + case W_AXIS: + phasePerUStep = PHASE_PER_MICROSTEP(W); + phaseCurrent = stepperW.get_microstep_counter(); + effectorBackoutDir = -W_HOME_DIR; + stepperBackoutDir = INVERT_W_DIR ? effectorBackoutDir : -effectorBackoutDir; + break; + #endif default: return; } @@ -1751,13 +1878,16 @@ void prepare_line_to_destination() { || TERN0(A##_HOME_TO_MIN, A##_MIN_PIN > -1) \ || TERN0(A##_HOME_TO_MAX, A##_MAX_PIN > -1) \ )) - if (LINEAR_AXIS_GANG( + if (NUM_AXIS_GANG( !_CAN_HOME(X), && !_CAN_HOME(Y), && !_CAN_HOME(Z), && !_CAN_HOME(I), && !_CAN_HOME(J), - && !_CAN_HOME(K)) + && !_CAN_HOME(K), + && !_CAN_HOME(U), + && !_CAN_HOME(V), + && !_CAN_HOME(W)) ) return; #endif @@ -1850,6 +1980,15 @@ void prepare_line_to_destination() { #if HAS_K_AXIS case K_AXIS: es = K_ENDSTOP; break; #endif + #if HAS_U_AXIS + case U_AXIS: es = U_ENDSTOP; break; + #endif + #if HAS_V_AXIS + case V_AXIS: es = V_ENDSTOP; break; + #endif + #if HAS_W_AXIS + case W_AXIS: es = W_ENDSTOP; break; + #endif } if (TEST(endstops.state(), es)) { SERIAL_ECHO_MSG("Bad ", AS_CHAR(AXIS_CHAR(axis)), " Endstop?"); diff --git a/Marlin/src/module/motion.h b/Marlin/src/module/motion.h index 2fbb4ce114..45dae5d609 100644 --- a/Marlin/src/module/motion.h +++ b/Marlin/src/module/motion.h @@ -44,7 +44,7 @@ extern xyze_pos_t current_position, // High-level current tool position // G60/G61 Position Save and Return #if SAVED_POSITIONS - extern uint8_t saved_slots[(SAVED_POSITIONS + 7) >> 3]; // TODO: Add support for LINEAR_AXES >= 4 + extern uint8_t saved_slots[(SAVED_POSITIONS + 7) >> 3]; // TODO: Add support for HAS_I_AXIS extern xyze_pos_t stored_position[SAVED_POSITIONS]; #endif @@ -77,13 +77,16 @@ constexpr xyz_feedrate_t homing_feedrate_mm_m = HOMING_FEEDRATE_MM_M; FORCE_INLINE feedRate_t homing_feedrate(const AxisEnum a) { float v = TERN0(HAS_Z_AXIS, homing_feedrate_mm_m.z); #if DISABLED(DELTA) - LINEAR_AXIS_CODE( + NUM_AXIS_CODE( if (a == X_AXIS) v = homing_feedrate_mm_m.x, else if (a == Y_AXIS) v = homing_feedrate_mm_m.y, else if (a == Z_AXIS) v = homing_feedrate_mm_m.z, else if (a == I_AXIS) v = homing_feedrate_mm_m.i, else if (a == J_AXIS) v = homing_feedrate_mm_m.j, - else if (a == K_AXIS) v = homing_feedrate_mm_m.k + else if (a == K_AXIS) v = homing_feedrate_mm_m.k, + else if (a == U_AXIS) v = homing_feedrate_mm_m.u, + else if (a == V_AXIS) v = homing_feedrate_mm_m.v, + else if (a == W_AXIS) v = homing_feedrate_mm_m.w ); #endif return MMM_TO_MMS(v); @@ -124,7 +127,7 @@ inline int8_t pgm_read_any(const int8_t *p) { return TERN(__IMXRT1062__, *p, pgm #define XYZ_DEFS(T, NAME, OPT) \ inline T NAME(const AxisEnum axis) { \ - static const XYZval NAME##_P DEFS_PROGMEM = LINEAR_AXIS_ARRAY(X_##OPT, Y_##OPT, Z_##OPT, I_##OPT, J_##OPT, K_##OPT); \ + static const XYZval NAME##_P DEFS_PROGMEM = NUM_AXIS_ARRAY(X_##OPT, Y_##OPT, Z_##OPT, I_##OPT, J_##OPT, K_##OPT, U_##OPT, V_##OPT, W_##OPT); \ return pgm_read_any(&NAME##_P[axis]); \ } XYZ_DEFS(float, base_min_pos, MIN_POS); @@ -198,6 +201,24 @@ inline float home_bump_mm(const AxisEnum axis) { TERN_(MIN_SOFTWARE_ENDSTOP_K, amax = max.k); break; #endif + #if HAS_U_AXIS + case U_AXIS: + TERN_(MIN_SOFTWARE_ENDSTOP_U, amin = min.u); + TERN_(MIN_SOFTWARE_ENDSTOP_U, amax = max.u); + break; + #endif + #if HAS_V_AXIS + case V_AXIS: + TERN_(MIN_SOFTWARE_ENDSTOP_V, amin = min.v); + TERN_(MIN_SOFTWARE_ENDSTOP_V, amax = max.v); + break; + #endif + #if HAS_W_AXIS + case W_AXIS: + TERN_(MIN_SOFTWARE_ENDSTOP_W, amin = min.w); + TERN_(MIN_SOFTWARE_ENDSTOP_W, amax = max.w); + break; + #endif default: break; } #endif @@ -323,7 +344,7 @@ inline void prepare_internal_move_to_destination(const_feedRate_t fr_mm_s=0.0f) /** * Blocking movement and shorthand functions */ -void do_blocking_move_to(LINEAR_AXIS_ARGS(const float), const_feedRate_t fr_mm_s=0.0f); +void do_blocking_move_to(NUM_AXIS_ARGS(const float), const_feedRate_t fr_mm_s=0.0f); void do_blocking_move_to(const xy_pos_t &raw, const_feedRate_t fr_mm_s=0.0f); void do_blocking_move_to(const xyz_pos_t &raw, const_feedRate_t fr_mm_s=0.0f); void do_blocking_move_to(const xyze_pos_t &raw, const_feedRate_t fr_mm_s=0.0f); @@ -347,6 +368,18 @@ void do_blocking_move_to_x(const_float_t rx, const_feedRate_t fr_mm_s=0.0f); void do_blocking_move_to_k(const_float_t rk, const_feedRate_t fr_mm_s=0.0f); void do_blocking_move_to_xyzij_k(const xyze_pos_t &raw, const_float_t k, const_feedRate_t fr_mm_s=0.0f); #endif +#if HAS_U_AXIS + void do_blocking_move_to_u(const_float_t ru, const_feedRate_t fr_mm_s=0.0f); + void do_blocking_move_to_xyzijk_u(const xyze_pos_t &raw, const_float_t u, const_feedRate_t fr_mm_s=0.0f); +#endif +#if HAS_V_AXIS + void do_blocking_move_to_v(const_float_t rv, const_feedRate_t fr_mm_s=0.0f); + void do_blocking_move_to_xyzijku_v(const xyze_pos_t &raw, const_float_t v, const_feedRate_t fr_mm_s=0.0f); +#endif +#if HAS_W_AXIS + void do_blocking_move_to_w(const float rw, const feedRate_t &fr_mm_s=0.0f); + void do_blocking_move_to_xyzijkuv_w(const xyze_pos_t &raw, const float w, const feedRate_t &fr_mm_s=0.0f); +#endif #if HAS_Y_AXIS void do_blocking_move_to_xy(const_float_t rx, const_float_t ry, const_feedRate_t fr_mm_s=0.0f); @@ -374,8 +407,8 @@ void restore_feedrate_and_scaling(); /** * Homing and Trusted Axes */ -typedef IF<(LINEAR_AXES > 8), uint16_t, uint8_t>::type linear_axis_bits_t; -constexpr linear_axis_bits_t linear_bits = _BV(LINEAR_AXES) - 1; +typedef IF<(NUM_AXES > 8), uint16_t, uint8_t>::type linear_axis_bits_t; +constexpr linear_axis_bits_t linear_bits = _BV(NUM_AXES) - 1; void set_axis_is_at_home(const AxisEnum axis); @@ -404,7 +437,7 @@ void set_axis_is_at_home(const AxisEnum axis); constexpr linear_axis_bits_t axis_homed = linear_bits, axis_trusted = linear_bits; // Zero-endstop machines are always homed and trusted inline void homeaxis(const AxisEnum axis) {} inline void set_axis_never_homed(const AxisEnum) {} - inline linear_axis_bits_t axes_should_home(linear_axis_bits_t=linear_bits) { return false; } + inline linear_axis_bits_t axes_should_home(linear_axis_bits_t=linear_bits) { return 0; } inline bool homing_needed_error(linear_axis_bits_t=linear_bits) { return false; } inline void set_axis_unhomed(const AxisEnum axis) {} inline void set_axis_untrusted(const AxisEnum axis) {} @@ -490,6 +523,18 @@ void home_if_needed(const bool keeplev=false); #define LOGICAL_K_POSITION(POS) NATIVE_TO_LOGICAL(POS, K_AXIS) #define RAW_K_POSITION(POS) LOGICAL_TO_NATIVE(POS, K_AXIS) #endif +#if HAS_U_AXIS + #define LOGICAL_U_POSITION(POS) NATIVE_TO_LOGICAL(POS, U_AXIS) + #define RAW_U_POSITION(POS) LOGICAL_TO_NATIVE(POS, U_AXIS) +#endif +#if HAS_V_AXIS + #define LOGICAL_V_POSITION(POS) NATIVE_TO_LOGICAL(POS, V_AXIS) + #define RAW_V_POSITION(POS) LOGICAL_TO_NATIVE(POS, V_AXIS) +#endif +#if HAS_W_AXIS + #define LOGICAL_W_POSITION(POS) NATIVE_TO_LOGICAL(POS, W_AXIS) + #define RAW_W_POSITION(POS) LOGICAL_TO_NATIVE(POS, W_AXIS) +#endif /** * position_is_reachable family of functions diff --git a/Marlin/src/module/planner.cpp b/Marlin/src/module/planner.cpp index 51440aac26..42a16603d4 100644 --- a/Marlin/src/module/planner.cpp +++ b/Marlin/src/module/planner.cpp @@ -1300,7 +1300,7 @@ void Planner::recalculate() { */ void Planner::check_axes_activity() { - #if ANY(DISABLE_X, DISABLE_Y, DISABLE_Z, DISABLE_I, DISABLE_J, DISABLE_K, DISABLE_E) + #if ANY(DISABLE_X, DISABLE_Y, DISABLE_Z, DISABLE_I, DISABLE_J, DISABLE_K, DISABLE_U, DISABLE_V, DISABLE_W, DISABLE_E) xyze_bool_t axis_active = { false }; #endif @@ -1350,7 +1350,10 @@ void Planner::check_axes_activity() { if (TERN0(DISABLE_Z, block->steps.z)) axis_active.z = true, if (TERN0(DISABLE_I, block->steps.i)) axis_active.i = true, if (TERN0(DISABLE_J, block->steps.j)) axis_active.j = true, - if (TERN0(DISABLE_K, block->steps.k)) axis_active.k = true + if (TERN0(DISABLE_K, block->steps.k)) axis_active.k = true, + if (TERN0(DISABLE_U, block->steps.u)) axis_active.u = true, + if (TERN0(DISABLE_V, block->steps.v)) axis_active.v = true, + if (TERN0(DISABLE_W, block->steps.w)) axis_active.w = true ); } #endif @@ -1385,7 +1388,10 @@ void Planner::check_axes_activity() { if (TERN0(DISABLE_Z, !axis_active.z)) stepper.disable_axis(Z_AXIS), if (TERN0(DISABLE_I, !axis_active.i)) stepper.disable_axis(I_AXIS), if (TERN0(DISABLE_J, !axis_active.j)) stepper.disable_axis(J_AXIS), - if (TERN0(DISABLE_K, !axis_active.k)) stepper.disable_axis(K_AXIS) + if (TERN0(DISABLE_K, !axis_active.k)) stepper.disable_axis(K_AXIS), + if (TERN0(DISABLE_U, !axis_active.u)) stepper.disable_axis(U_AXIS), + if (TERN0(DISABLE_V, !axis_active.v)) stepper.disable_axis(V_AXIS), + if (TERN0(DISABLE_W, !axis_active.w)) stepper.disable_axis(W_AXIS) ); // @@ -1453,7 +1459,7 @@ void Planner::check_axes_activity() { float high = 0.0; for (uint8_t b = block_buffer_tail; b != block_buffer_head; b = next_block_index(b)) { block_t *block = &block_buffer[b]; - if (LINEAR_AXIS_GANG(block->steps.x, || block->steps.y, || block->steps.z, || block->steps.i, || block->steps.j, || block->steps.k)) { + if (NUM_AXIS_GANG(block->steps.x, || block->steps.y, || block->steps.z, || block->steps.i, || block->steps.j, || block->steps.k, || block->steps.u, || block->steps.v, || block->steps.w)) { const float se = (float)block->steps.e / block->step_event_count * SQRT(block->nominal_speed_sqr); // mm/sec; NOLESS(high, se); } @@ -1505,7 +1511,7 @@ void Planner::check_axes_activity() { volumetric_extruder_feedrate_limit[e] = (lim && siz) ? lim / CIRCLE_AREA(siz * 0.5f) : 0; } void Planner::calculate_volumetric_extruder_limits() { - LOOP_L_N(e, EXTRUDERS) calculate_volumetric_extruder_limit(e); + EXTRUDER_LOOP() calculate_volumetric_extruder_limit(e); } #endif @@ -1591,7 +1597,7 @@ void Planner::check_axes_activity() { #elif ENABLED(AUTO_BED_LEVELING_UBL) fade_scaling_factor ? fade_scaling_factor * ubl.get_z_correction(raw) : 0.0 #elif ENABLED(AUTO_BED_LEVELING_BILINEAR) - fade_scaling_factor ? fade_scaling_factor * bilinear_z_offset(raw) : 0.0 + fade_scaling_factor ? fade_scaling_factor * bbl.get_z_correction(raw) : 0.0 #endif ); @@ -1624,7 +1630,7 @@ void Planner::check_axes_activity() { #elif ENABLED(AUTO_BED_LEVELING_UBL) fade_scaling_factor ? fade_scaling_factor * ubl.get_z_correction(raw) : 0.0 #elif ENABLED(AUTO_BED_LEVELING_BILINEAR) - fade_scaling_factor ? fade_scaling_factor * bilinear_z_offset(raw) : 0.0 + fade_scaling_factor ? fade_scaling_factor * bbl.get_z_correction(raw) : 0.0 #endif ); @@ -1856,15 +1862,22 @@ bool Planner::_populate_block(block_t * const block, bool split_move, dc = target.c - position.c, di = target.i - position.i, dj = target.j - position.j, - dk = target.k - position.k + dk = target.k - position.k, + du = target.u - position.u, + dv = target.v - position.v, + dw = target.w - position.w ); /* <-- add a slash to enable SERIAL_ECHOLNPGM( " _populate_block FR:", fr_mm_s, " A:", target.a, " (", da, " steps)" - " B:", target.b, " (", db, " steps)" - " C:", target.c, " (", dc, " steps)" + #if HAS_Y_AXIS + " B:", target.b, " (", db, " steps)" + #endif + #if HAS_Z_AXIS + " C:", target.c, " (", dc, " steps)" + #endif #if HAS_I_AXIS " " STR_I ":", target.i, " (", di, " steps)" #endif @@ -1874,6 +1887,14 @@ bool Planner::_populate_block(block_t * const block, bool split_move, #if HAS_K_AXIS " " STR_K ":", target.k, " (", dk, " steps)" #endif + #if HAS_U_AXIS + " " STR_U ":", target.u, " (", du, " steps)" + #endif + #if HAS_V_AXIS + " " STR_V ":", target.v, " (", dv, " steps)" + #endif + #if HAS_W_AXIS + " " STR_W ":", target.w, " (", dw, " steps)" #if HAS_EXTRUDERS " E:", target.e, " (", de, " steps)" #endif @@ -1938,15 +1959,6 @@ bool Planner::_populate_block(block_t * const block, bool split_move, if (db + dc < 0) SBI(dm, B_AXIS); // Motor B direction if (CORESIGN(db - dc) < 0) SBI(dm, C_AXIS); // Motor C direction #endif - #if HAS_I_AXIS - if (di < 0) SBI(dm, I_AXIS); - #endif - #if HAS_J_AXIS - if (dj < 0) SBI(dm, J_AXIS); - #endif - #if HAS_K_AXIS - if (dk < 0) SBI(dm, K_AXIS); - #endif #elif ENABLED(MARKFORGED_XY) if (da + db < 0) SBI(dm, A_AXIS); // Motor A direction if (db < 0) SBI(dm, B_AXIS); // Motor B direction @@ -1954,16 +1966,22 @@ bool Planner::_populate_block(block_t * const block, bool split_move, if (da < 0) SBI(dm, A_AXIS); // Motor A direction if (db + da < 0) SBI(dm, B_AXIS); // Motor B direction #else - LINEAR_AXIS_CODE( + XYZ_CODE( if (da < 0) SBI(dm, X_AXIS), if (db < 0) SBI(dm, Y_AXIS), - if (dc < 0) SBI(dm, Z_AXIS), - if (di < 0) SBI(dm, I_AXIS), - if (dj < 0) SBI(dm, J_AXIS), - if (dk < 0) SBI(dm, K_AXIS) + if (dc < 0) SBI(dm, Z_AXIS) ); #endif + SECONDARY_AXIS_CODE( + if (di < 0) SBI(dm, I_AXIS), + if (dj < 0) SBI(dm, J_AXIS), + if (dk < 0) SBI(dm, K_AXIS), + if (du < 0) SBI(dm, U_AXIS), + if (dv < 0) SBI(dm, V_AXIS), + if (dw < 0) SBI(dm, W_AXIS) + ); + #if HAS_EXTRUDERS if (de < 0) SBI(dm, E_AXIS); const float esteps_float = de * e_factor[extruder]; @@ -1988,20 +2006,20 @@ bool Planner::_populate_block(block_t * const block, bool split_move, // Number of steps for each axis // See https://www.corexy.com/theory.html #if CORE_IS_XY - block->steps.set(LINEAR_AXIS_LIST(ABS(da + db), ABS(da - db), ABS(dc), ABS(di), ABS(dj), ABS(dk))); + block->steps.set(NUM_AXIS_LIST(ABS(da + db), ABS(da - db), ABS(dc), ABS(di), ABS(dj), ABS(dk), ABS(du), ABS(dv), ABS(dw))); #elif CORE_IS_XZ - block->steps.set(LINEAR_AXIS_LIST(ABS(da + dc), ABS(db), ABS(da - dc), ABS(di), ABS(dj), ABS(dk))); + block->steps.set(NUM_AXIS_LIST(ABS(da + dc), ABS(db), ABS(da - dc), ABS(di), ABS(dj), ABS(dk), ABS(du), ABS(dv), ABS(dw))); #elif CORE_IS_YZ - block->steps.set(LINEAR_AXIS_LIST(ABS(da), ABS(db + dc), ABS(db - dc), ABS(di), ABS(dj), ABS(dk))); + block->steps.set(NUM_AXIS_LIST(ABS(da), ABS(db + dc), ABS(db - dc), ABS(di), ABS(dj), ABS(dk), ABS(du), ABS(dv), ABS(dw))); #elif ENABLED(MARKFORGED_XY) - block->steps.set(LINEAR_AXIS_LIST(ABS(da + db), ABS(db), ABS(dc), ABS(di), ABS(dj), ABS(dk))); + block->steps.set(NUM_AXIS_LIST(ABS(da + db), ABS(db), ABS(dc), ABS(di), ABS(dj), ABS(dk), ABS(du), ABS(dv), ABS(dw))); #elif ENABLED(MARKFORGED_YX) - block->steps.set(LINEAR_AXIS_LIST(ABS(da), ABS(db + da), ABS(dc), ABS(di), ABS(dj), ABS(dk))); + block->steps.set(NUM_AXIS_LIST(ABS(da), ABS(db + da), ABS(dc), ABS(di), ABS(dj), ABS(dk), ABS(du), ABS(dv), ABS(dw))); #elif IS_SCARA - block->steps.set(LINEAR_AXIS_LIST(ABS(da), ABS(db), ABS(dc), ABS(di), ABS(dj), ABS(dk))); + block->steps.set(NUM_AXIS_LIST(ABS(da), ABS(db), ABS(dc), ABS(di), ABS(dj), ABS(dk), ABS(du), ABS(dv), ABS(dw))); #else // default non-h-bot planning - block->steps.set(LINEAR_AXIS_LIST(ABS(da), ABS(db), ABS(dc), ABS(di), ABS(dj), ABS(dk))); + block->steps.set(NUM_AXIS_LIST(ABS(da), ABS(db), ABS(dc), ABS(di), ABS(dj), ABS(dk), ABS(du), ABS(dv), ABS(dw))); #endif /** @@ -2040,9 +2058,6 @@ bool Planner::_populate_block(block_t * const block, bool split_move, steps_dist_mm.b = (db + dc) * mm_per_step[B_AXIS]; steps_dist_mm.c = CORESIGN(db - dc) * mm_per_step[C_AXIS]; #endif - TERN_(HAS_I_AXIS, steps_dist_mm.i = di * mm_per_step[I_AXIS]); - TERN_(HAS_J_AXIS, steps_dist_mm.j = dj * mm_per_step[J_AXIS]); - TERN_(HAS_K_AXIS, steps_dist_mm.k = dk * mm_per_step[K_AXIS]); #elif ENABLED(MARKFORGED_XY) steps_dist_mm.a = (da - db) * mm_per_step[A_AXIS]; steps_dist_mm.b = db * mm_per_step[B_AXIS]; @@ -2050,27 +2065,40 @@ bool Planner::_populate_block(block_t * const block, bool split_move, steps_dist_mm.a = da * mm_per_step[A_AXIS]; steps_dist_mm.b = (db - da) * mm_per_step[B_AXIS]; #else - LINEAR_AXIS_CODE( + XYZ_CODE( steps_dist_mm.a = da * mm_per_step[A_AXIS], steps_dist_mm.b = db * mm_per_step[B_AXIS], - steps_dist_mm.c = dc * mm_per_step[C_AXIS], - steps_dist_mm.i = di * mm_per_step[I_AXIS], - steps_dist_mm.j = dj * mm_per_step[J_AXIS], - steps_dist_mm.k = dk * mm_per_step[K_AXIS] + steps_dist_mm.c = dc * mm_per_step[C_AXIS] ); #endif + SECONDARY_AXIS_CODE( + steps_dist_mm.i = di * mm_per_step[I_AXIS], + steps_dist_mm.j = dj * mm_per_step[J_AXIS], + steps_dist_mm.k = dk * mm_per_step[K_AXIS], + steps_dist_mm.u = du * mm_per_step[U_AXIS], + steps_dist_mm.v = dv * mm_per_step[V_AXIS], + steps_dist_mm.w = dw * mm_per_step[W_AXIS] + ); + TERN_(HAS_EXTRUDERS, steps_dist_mm.e = esteps_float * mm_per_step[E_AXIS_N(extruder)]); TERN_(LCD_SHOW_E_TOTAL, e_move_accumulator += steps_dist_mm.e); - if (true LINEAR_AXIS_GANG( + #if BOTH(HAS_ROTATIONAL_AXES, INCH_MODE_SUPPORT) + bool cartesian_move = true; + #endif + + if (true NUM_AXIS_GANG( && block->steps.a < MIN_STEPS_PER_SEGMENT, && block->steps.b < MIN_STEPS_PER_SEGMENT, && block->steps.c < MIN_STEPS_PER_SEGMENT, && block->steps.i < MIN_STEPS_PER_SEGMENT, && block->steps.j < MIN_STEPS_PER_SEGMENT, - && block->steps.k < MIN_STEPS_PER_SEGMENT + && block->steps.k < MIN_STEPS_PER_SEGMENT, + && block->steps.u < MIN_STEPS_PER_SEGMENT, + && block->steps.v < MIN_STEPS_PER_SEGMENT, + && block->steps.w < MIN_STEPS_PER_SEGMENT ) ) { block->millimeters = TERN0(HAS_EXTRUDERS, ABS(steps_dist_mm.e)); @@ -2079,36 +2107,71 @@ bool Planner::_populate_block(block_t * const block, bool split_move, if (millimeters) block->millimeters = millimeters; else { - block->millimeters = SQRT( - #if ANY(CORE_IS_XY, MARKFORGED_XY, MARKFORGED_YX) - LINEAR_AXIS_GANG( - sq(steps_dist_mm.head.x), + sq(steps_dist_mm.head.y), + sq(steps_dist_mm.z), - + sq(steps_dist_mm.i), + sq(steps_dist_mm.j), + sq(steps_dist_mm.k) - ) - #elif CORE_IS_XZ - LINEAR_AXIS_GANG( - sq(steps_dist_mm.head.x), + sq(steps_dist_mm.y), + sq(steps_dist_mm.head.z), - + sq(steps_dist_mm.i), + sq(steps_dist_mm.j), + sq(steps_dist_mm.k) - ) - #elif CORE_IS_YZ - LINEAR_AXIS_GANG( - sq(steps_dist_mm.x) + sq(steps_dist_mm.head.y) + sq(steps_dist_mm.head.z) - + sq(steps_dist_mm.i), + sq(steps_dist_mm.j), + sq(steps_dist_mm.k) - ) + /** + * Distance for interpretation of feedrate in accordance with LinuxCNC (the successor of NIST + * RS274NGC interpreter - version 3) and its default CANON_XYZ feed reference mode. + * Assume that X, Y, Z are the primary linear axes and U, V, W are secondary linear axes and A, B, C are + * rotational axes. Then dX, dY, dZ are the displacements of the primary linear axes and dU, dV, dW are the displacements of linear axes and + * dA, dB, dC are the displacements of rotational axes. + * The time it takes to execute move command with feedrate F is t = D/F, where D is the total distance, calculated as follows: + * D^2 = dX^2 + dY^2 + dZ^2 + * if D^2 == 0 (none of XYZ move but any secondary linear axes move, whether other axes are moved or not): + * D^2 = dU^2 + dV^2 + dW^2 + * if D^2 == 0 (only rotational axes are moved): + * D^2 = dA^2 + dB^2 + dC^2 + */ + float distance_sqr = ( + #if ENABLED(ARTICULATED_ROBOT_ARM) + // For articulated robots, interpreting feedrate like LinuxCNC would require inverse kinematics. As a workaround, pretend that motors sit on n mutually orthogonal + // axes and assume that we could think of distance as magnitude of an n-vector in an n-dimensional Euclidian space. + NUM_AXIS_GANG( + sq(steps_dist_mm.x), + sq(steps_dist_mm.y), + sq(steps_dist_mm.z), + + sq(steps_dist_mm.i), + sq(steps_dist_mm.j), + sq(steps_dist_mm.k), + + sq(steps_dist_mm.u), + sq(steps_dist_mm.v), + sq(steps_dist_mm.w) + ); #elif ENABLED(FOAMCUTTER_XYUV) - // Return the largest distance move from either X/Y or I/J plane #if HAS_J_AXIS - _MAX(sq(steps_dist_mm.x) + sq(steps_dist_mm.y), sq(steps_dist_mm.i) + sq(steps_dist_mm.j)) - #else + // Special 5 axis kinematics. Return the largest distance move from either X/Y or I/J plane + _MAX(sq(steps_dist_mm.x) + sq(steps_dist_mm.y), sq(steps_dist_mm.i) + sq(steps_dist_mm.j)) + #else // Foamcutter with only two axes (XY) sq(steps_dist_mm.x) + sq(steps_dist_mm.y) #endif + #elif ANY(CORE_IS_XY, MARKFORGED_XY, MARKFORGED_YX) + XYZ_GANG(sq(steps_dist_mm.head.x), + sq(steps_dist_mm.head.y), + sq(steps_dist_mm.z)) + #elif CORE_IS_XZ + XYZ_GANG(sq(steps_dist_mm.head.x), + sq(steps_dist_mm.y), + sq(steps_dist_mm.head.z)) + #elif CORE_IS_YZ + XYZ_GANG(sq(steps_dist_mm.x), + sq(steps_dist_mm.head.y), + sq(steps_dist_mm.head.z)) #else - LINEAR_AXIS_GANG( - sq(steps_dist_mm.x), + sq(steps_dist_mm.y), + sq(steps_dist_mm.z), - + sq(steps_dist_mm.i), + sq(steps_dist_mm.j), + sq(steps_dist_mm.k) - ) + XYZ_GANG(sq(steps_dist_mm.x), + sq(steps_dist_mm.y), + sq(steps_dist_mm.z)) #endif ); + + #if SECONDARY_LINEAR_AXES >= 1 && NONE(FOAMCUTTER_XYUV, ARTICULATED_ROBOT_ARM) + if (NEAR_ZERO(distance_sqr)) { + // Move does not involve any primary linear axes (xyz) but might involve secondary linear axes + distance_sqr = (0.0 + SECONDARY_AXIS_GANG( + IF_DISABLED(AXIS4_ROTATES, + sq(steps_dist_mm.i)), + IF_DISABLED(AXIS5_ROTATES, + sq(steps_dist_mm.j)), + IF_DISABLED(AXIS6_ROTATES, + sq(steps_dist_mm.k)), + IF_DISABLED(AXIS7_ROTATES, + sq(steps_dist_mm.u)), + IF_DISABLED(AXIS8_ROTATES, + sq(steps_dist_mm.v)), + IF_DISABLED(AXIS9_ROTATES, + sq(steps_dist_mm.w)) + ) + ); + } + #endif + + #if HAS_ROTATIONAL_AXES && NONE(FOAMCUTTER_XYUV, ARTICULATED_ROBOT_ARM) + if (NEAR_ZERO(distance_sqr)) { + // Move involves only rotational axes. Calculate angular distance in accordance with LinuxCNC + TERN_(INCH_MODE_SUPPORT, cartesian_move = false); + distance_sqr = ROTATIONAL_AXIS_GANG(sq(steps_dist_mm.i), + sq(steps_dist_mm.j), + sq(steps_dist_mm.k), + sq(steps_dist_mm.u), + sq(steps_dist_mm.v), + sq(steps_dist_mm.w)); + } + #endif + + block->millimeters = SQRT(distance_sqr); } /** @@ -2125,8 +2188,10 @@ bool Planner::_populate_block(block_t * const block, bool split_move, TERN_(HAS_EXTRUDERS, block->steps.e = esteps); - block->step_event_count = _MAX(LOGICAL_AXIS_LIST( - esteps, block->steps.a, block->steps.b, block->steps.c, block->steps.i, block->steps.j, block->steps.k + block->step_event_count = _MAX(LOGICAL_AXIS_LIST(esteps, + block->steps.a, block->steps.b, block->steps.c, + block->steps.i, block->steps.j, block->steps.k, + block->steps.u, block->steps.v, block->steps.w )); // Bail if this is a zero-length block @@ -2148,13 +2213,16 @@ bool Planner::_populate_block(block_t * const block, bool split_move, E_TERN_(block->extruder = extruder); #if ENABLED(AUTO_POWER_CONTROL) - if (LINEAR_AXIS_GANG( + if (NUM_AXIS_GANG( block->steps.x, || block->steps.y, || block->steps.z, || block->steps.i, || block->steps.j, - || block->steps.k + || block->steps.k, + || block->steps.u, + || block->steps.v, + || block->steps.w )) powerManager.power_on(); #endif @@ -2180,19 +2248,27 @@ bool Planner::_populate_block(block_t * const block, bool split_move, } if (block->steps.x) stepper.enable_axis(X_AXIS); #else - LINEAR_AXIS_CODE( + NUM_AXIS_CODE( if (block->steps.x) stepper.enable_axis(X_AXIS), if (block->steps.y) stepper.enable_axis(Y_AXIS), if (TERN(Z_LATE_ENABLE, 0, block->steps.z)) stepper.enable_axis(Z_AXIS), if (block->steps.i) stepper.enable_axis(I_AXIS), if (block->steps.j) stepper.enable_axis(J_AXIS), - if (block->steps.k) stepper.enable_axis(K_AXIS) + if (block->steps.k) stepper.enable_axis(K_AXIS), + if (block->steps.u) stepper.enable_axis(U_AXIS), + if (block->steps.v) stepper.enable_axis(V_AXIS), + if (block->steps.w) stepper.enable_axis(W_AXIS) ); #endif #if ANY(CORE_IS_XY, MARKFORGED_XY, MARKFORGED_YX) - TERN_(HAS_I_AXIS, if (block->steps.i) stepper.enable_axis(I_AXIS)); - TERN_(HAS_J_AXIS, if (block->steps.j) stepper.enable_axis(J_AXIS)); - TERN_(HAS_K_AXIS, if (block->steps.k) stepper.enable_axis(K_AXIS)); + SECONDARY_AXIS_CODE( + if (block->steps.i) stepper.enable_axis(I_AXIS), + if (block->steps.j) stepper.enable_axis(J_AXIS), + if (block->steps.k) stepper.enable_axis(K_AXIS), + if (block->steps.u) stepper.enable_axis(U_AXIS), + if (block->steps.v) stepper.enable_axis(V_AXIS), + if (block->steps.w) stepper.enable_axis(W_AXIS) + ); #endif // Enable extruder(s) @@ -2239,8 +2315,14 @@ bool Planner::_populate_block(block_t * const block, bool split_move, const float inverse_millimeters = 1.0f / block->millimeters; // Inverse millimeters to remove multiple divides // Calculate inverse time for this move. No divide by zero due to previous checks. - // Example: At 120mm/s a 60mm move takes 0.5s. So this will give 2.0. - float inverse_secs = fr_mm_s * inverse_millimeters; + // Example: At 120mm/s a 60mm move involving XYZ axes takes 0.5s. So this will give 2.0. + // Example 2: At 120°/s a 60° move involving only rotational axes takes 0.5s. So this will give 2.0. + float inverse_secs; + #if BOTH(HAS_ROTATIONAL_AXES, INCH_MODE_SUPPORT) + inverse_secs = inverse_millimeters * (cartesian_move ? fr_mm_s : LINEAR_UNIT(fr_mm_s)); + #else + inverse_secs = fr_mm_s * inverse_millimeters; + #endif // Get the number of non busy movements in queue (non busy means that they can be altered) const uint8_t moves_queued = nonbusy_movesplanned(); @@ -2286,13 +2368,13 @@ bool Planner::_populate_block(block_t * const block, bool split_move, filwidth.advance_e(steps_dist_mm.e); #endif - // Calculate and limit speed in mm/sec + // Calculate and limit speed in mm/sec (linear) or degrees/sec (rotational) xyze_float_t current_speed; float speed_factor = 1.0f; // factor <1 decreases speed // Linear axes first with less logic - LOOP_LINEAR_AXES(i) { + LOOP_NUM_AXES(i) { current_speed[i] = steps_dist_mm[i] * inverse_secs; const feedRate_t cs = ABS(current_speed[i]), max_fr = settings.max_feedrate_mm_s[i]; @@ -2380,9 +2462,10 @@ bool Planner::_populate_block(block_t * const block, bool split_move, // Compute and limit the acceleration rate for the trapezoid generator. const float steps_per_mm = block->step_event_count * inverse_millimeters; uint32_t accel; - if (LINEAR_AXIS_GANG( + if (NUM_AXIS_GANG( !block->steps.a, && !block->steps.b, && !block->steps.c, - && !block->steps.i, && !block->steps.j, && !block->steps.k) + && !block->steps.i, && !block->steps.j, && !block->steps.k, + && !block->steps.u, && !block->steps.v, && !block->steps.w) ) { // Is this a retract / recover move? accel = CEIL(settings.retract_acceleration * steps_per_mm); // Convert to: acceleration steps/sec^2 TERN_(LIN_ADVANCE, block->use_advance_lead = false); // No linear advance for simple retract/recover @@ -2455,7 +2538,10 @@ bool Planner::_populate_block(block_t * const block, bool split_move, LIMIT_ACCEL_LONG(C_AXIS, 0), LIMIT_ACCEL_LONG(I_AXIS, 0), LIMIT_ACCEL_LONG(J_AXIS, 0), - LIMIT_ACCEL_LONG(K_AXIS, 0) + LIMIT_ACCEL_LONG(K_AXIS, 0), + LIMIT_ACCEL_LONG(U_AXIS, 0), + LIMIT_ACCEL_LONG(V_AXIS, 0), + LIMIT_ACCEL_LONG(W_AXIS, 0) ); } else { @@ -2466,7 +2552,10 @@ bool Planner::_populate_block(block_t * const block, bool split_move, LIMIT_ACCEL_FLOAT(C_AXIS, 0), LIMIT_ACCEL_FLOAT(I_AXIS, 0), LIMIT_ACCEL_FLOAT(J_AXIS, 0), - LIMIT_ACCEL_FLOAT(K_AXIS, 0) + LIMIT_ACCEL_FLOAT(K_AXIS, 0), + LIMIT_ACCEL_FLOAT(U_AXIS, 0), + LIMIT_ACCEL_FLOAT(V_AXIS, 0), + LIMIT_ACCEL_FLOAT(W_AXIS, 0) ); } } @@ -2531,7 +2620,7 @@ bool Planner::_populate_block(block_t * const block, bool split_move, #if HAS_DIST_MM_ARG cart_dist_mm #else - LOGICAL_AXIS_ARRAY(steps_dist_mm.e, steps_dist_mm.x, steps_dist_mm.y, steps_dist_mm.z, steps_dist_mm.i, steps_dist_mm.j, steps_dist_mm.k) + LOGICAL_AXIS_ARRAY(steps_dist_mm.e, steps_dist_mm.x, steps_dist_mm.y, steps_dist_mm.z, steps_dist_mm.i, steps_dist_mm.j, steps_dist_mm.k, steps_dist_mm.u, steps_dist_mm.v, steps_dist_mm.w) #endif ; @@ -2557,7 +2646,10 @@ bool Planner::_populate_block(block_t * const block, bool split_move, + (-prev_unit_vec.z * unit_vec.z), + (-prev_unit_vec.i * unit_vec.i), + (-prev_unit_vec.j * unit_vec.j), - + (-prev_unit_vec.k * unit_vec.k) + + (-prev_unit_vec.k * unit_vec.k), + + (-prev_unit_vec.u * unit_vec.u), + + (-prev_unit_vec.v * unit_vec.v), + + (-prev_unit_vec.w * unit_vec.w) ); // NOTE: Computed without any expensive trig, sin() or acos(), by trig half angle identity of cos(theta). @@ -2704,7 +2796,7 @@ bool Planner::_populate_block(block_t * const block, bool split_move, const float extra_xyjerk = TERN0(HAS_EXTRUDERS, de <= 0) ? TRAVEL_EXTRA_XYJERK : 0; uint8_t limited = 0; - TERN(HAS_LINEAR_E_JERK, LOOP_LINEAR_AXES, LOOP_LOGICAL_AXES)(i) { + TERN(HAS_LINEAR_E_JERK, LOOP_NUM_AXES, LOOP_LOGICAL_AXES)(i) { const float jerk = ABS(current_speed[i]), // cs : Starting from zero, change in speed for this axis maxj = (max_jerk[i] + (i == X_AXIS || i == Y_AXIS ? extra_xyjerk : 0.0f)); // mj : The max jerk setting for this axis if (jerk > maxj) { // cs > mj : New current speed too fast? @@ -2742,7 +2834,7 @@ bool Planner::_populate_block(block_t * const block, bool split_move, vmax_junction = previous_nominal_speed; // Now limit the jerk in all axes. - TERN(HAS_LINEAR_E_JERK, LOOP_LINEAR_AXES, LOOP_LOGICAL_AXES)(axis) { + TERN(HAS_LINEAR_E_JERK, LOOP_NUM_AXES, LOOP_LOGICAL_AXES)(axis) { // Limit an axis. We have to differentiate: coasting, reversal of an axis, full stop. float v_exit = previous_speed[axis] * smaller_speed_factor, v_entry = current_speed[axis]; @@ -2844,7 +2936,7 @@ void Planner::buffer_sync_block(TERN_(LASER_SYNCHRONOUS_M106_M107, uint8_t sync_ block->position = position; #if ENABLED(BACKLASH_COMPENSATION) - LOOP_LINEAR_AXES(axis) block->position[axis] += backlash.get_applied_steps((AxisEnum)axis); + LOOP_NUM_AXES(axis) block->position[axis] += backlash.get_applied_steps((AxisEnum)axis); #endif #if BOTH(HAS_FAN, LASER_SYNCHRONOUS_M106_M107) @@ -2906,7 +2998,10 @@ bool Planner::buffer_segment(const abce_pos_t &abce int32_t(LROUND(abce.c * settings.axis_steps_per_mm[C_AXIS])), int32_t(LROUND(abce.i * settings.axis_steps_per_mm[I_AXIS])), int32_t(LROUND(abce.j * settings.axis_steps_per_mm[J_AXIS])), - int32_t(LROUND(abce.k * settings.axis_steps_per_mm[K_AXIS])) + int32_t(LROUND(abce.k * settings.axis_steps_per_mm[K_AXIS])), + int32_t(LROUND(abce.u * settings.axis_steps_per_mm[U_AXIS])), + int32_t(LROUND(abce.v * settings.axis_steps_per_mm[V_AXIS])), + int32_t(LROUND(abce.w * settings.axis_steps_per_mm[W_AXIS])) ) }; @@ -2958,6 +3053,21 @@ bool Planner::buffer_segment(const abce_pos_t &abce SERIAL_ECHOPGM(" (", position.k, "->", target.k); SERIAL_CHAR(')'); #endif + #if HAS_U_AXIS + SERIAL_ECHOPGM_P(SP_U_LBL, abce.u); + SERIAL_ECHOPGM(" (", position.u, "->", target.u); + SERIAL_CHAR(')'); + #endif + #if HAS_V_AXIS + SERIAL_ECHOPGM_P(SP_V_LBL, abce.v); + SERIAL_ECHOPGM(" (", position.v, "->", target.v); + SERIAL_CHAR(')'); + #endif + #if HAS_W_AXIS + SERIAL_ECHOPGM_P(SP_W_LBL, abce.w); + SERIAL_ECHOPGM(" (", position.w, "->", target.w); + SERIAL_CHAR(')'); + #endif #if HAS_EXTRUDERS SERIAL_ECHOPGM_P(SP_E_LBL, abce.e); SERIAL_ECHOLNPGM(" (", position.e, "->", target.e, ")"); @@ -3000,12 +3110,14 @@ bool Planner::buffer_line(const xyze_pos_t &cart, const_feedRate_t fr_mm_s, cons const xyze_pos_t cart_dist_mm = LOGICAL_AXIS_ARRAY( cart.e - position_cart.e, cart.x - position_cart.x, cart.y - position_cart.y, cart.z - position_cart.z, - cart.i - position_cart.i, cart.j - position_cart.j, cart.j - position_cart.k + cart.i - position_cart.i, cart.j - position_cart.j, cart.k - position_cart.k, + cart.u - position_cart.u, cart.v - position_cart.v, cart.w - position_cart.w ); #else - const xyz_pos_t cart_dist_mm = LINEAR_AXIS_ARRAY( + const xyz_pos_t cart_dist_mm = NUM_AXIS_ARRAY( cart.x - position_cart.x, cart.y - position_cart.y, cart.z - position_cart.z, - cart.i - position_cart.i, cart.j - position_cart.j, cart.j - position_cart.k + cart.i - position_cart.i, cart.j - position_cart.j, cart.k - position_cart.k, + cart.u - position_cart.u, cart.v - position_cart.v, cart.w - position_cart.w ); #endif @@ -3110,7 +3222,10 @@ void Planner::set_machine_position_mm(const abce_pos_t &abce) { LROUND(abce.c * settings.axis_steps_per_mm[C_AXIS]), LROUND(abce.i * settings.axis_steps_per_mm[I_AXIS]), LROUND(abce.j * settings.axis_steps_per_mm[J_AXIS]), - LROUND(abce.k * settings.axis_steps_per_mm[K_AXIS]) + LROUND(abce.k * settings.axis_steps_per_mm[K_AXIS]), + LROUND(abce.u * settings.axis_steps_per_mm[U_AXIS]), + LROUND(abce.v * settings.axis_steps_per_mm[V_AXIS]), + LROUND(abce.w * settings.axis_steps_per_mm[W_AXIS]) ) ); @@ -3122,7 +3237,7 @@ void Planner::set_machine_position_mm(const abce_pos_t &abce) { else { #if ENABLED(BACKLASH_COMPENSATION) abce_long_t stepper_pos = position; - LOOP_LINEAR_AXES(axis) stepper_pos[axis] += backlash.get_applied_steps((AxisEnum)axis); + LOOP_NUM_AXES(axis) stepper_pos[axis] += backlash.get_applied_steps((AxisEnum)axis); stepper.set_position(stepper_pos); #else stepper.set_position(position); diff --git a/Marlin/src/module/planner.h b/Marlin/src/module/planner.h index f29604bea8..eb4a34cec9 100644 --- a/Marlin/src/module/planner.h +++ b/Marlin/src/module/planner.h @@ -84,7 +84,8 @@ constexpr xyze_feedrate_t _mf = MANUAL_FEEDRATE, manual_feedrate_mm_s = LOGICAL_AXIS_ARRAY(_mf.e / 60.0f, _mf.x / 60.0f, _mf.y / 60.0f, _mf.z / 60.0f, - _mf.i / 60.0f, _mf.j / 60.0f, _mf.k / 60.0f); + _mf.i / 60.0f, _mf.j / 60.0f, _mf.k / 60.0f, + _mf.u / 60.0f, _mf.v / 60.0f, _mf.w / 60.0f); #endif #if IS_KINEMATIC && HAS_JUNCTION_DEVIATION @@ -843,7 +844,8 @@ class Planner { const abce_pos_t out = LOGICAL_AXIS_ARRAY( get_axis_position_mm(E_AXIS), get_axis_position_mm(A_AXIS), get_axis_position_mm(B_AXIS), get_axis_position_mm(C_AXIS), - get_axis_position_mm(I_AXIS), get_axis_position_mm(J_AXIS), get_axis_position_mm(K_AXIS) + get_axis_position_mm(I_AXIS), get_axis_position_mm(J_AXIS), get_axis_position_mm(K_AXIS), + get_axis_position_mm(U_AXIS), get_axis_position_mm(V_AXIS), get_axis_position_mm(W_AXIS) ); return out; } @@ -928,8 +930,8 @@ class Planner { #if HAS_LINEAR_E_JERK FORCE_INLINE static void recalculate_max_e_jerk() { const float prop = junction_deviation_mm * SQRT(0.5) / (1.0f - SQRT(0.5)); - LOOP_L_N(i, EXTRUDERS) - max_e_jerk[E_INDEX_N(i)] = SQRT(prop * settings.max_acceleration_mm_per_s2[E_INDEX_N(i)]); + EXTRUDER_LOOP() + max_e_jerk[E_INDEX_N(e)] = SQRT(prop * settings.max_acceleration_mm_per_s2[E_INDEX_N(e)]); } #endif diff --git a/Marlin/src/module/planner_bezier.cpp b/Marlin/src/module/planner_bezier.cpp index 848906705f..fa7e16a387 100644 --- a/Marlin/src/module/planner_bezier.cpp +++ b/Marlin/src/module/planner_bezier.cpp @@ -188,7 +188,10 @@ void cubic_b_spline( interp(position.z, target.z, t), // FIXME. Wrong, since t is not linear in the distance. interp(position.i, target.i, t), // FIXME. Wrong, since t is not linear in the distance. interp(position.j, target.j, t), // FIXME. Wrong, since t is not linear in the distance. - interp(position.k, target.k, t) // FIXME. Wrong, since t is not linear in the distance. + interp(position.k, target.k, t), // FIXME. Wrong, since t is not linear in the distance. + interp(position.u, target.u, t), // FIXME. Wrong, since t is not linear in the distance. + interp(position.v, target.v, t), // FIXME. Wrong, since t is not linear in the distance. + interp(position.w, target.w, t) // FIXME. Wrong, since t is not linear in the distance. ); apply_motion_limits(new_bez); bez_target = new_bez; diff --git a/Marlin/src/module/printcounter.cpp b/Marlin/src/module/printcounter.cpp index affb608780..fbf5401d67 100644 --- a/Marlin/src/module/printcounter.cpp +++ b/Marlin/src/module/printcounter.cpp @@ -151,7 +151,7 @@ void PrintCounter::loadStats() { if (data.nextService3 == 0) doBuzz = _service_warn(PSTR(" " SERVICE_NAME_3)); #endif #if HAS_BUZZER && SERVICE_WARNING_BUZZES > 0 - if (doBuzz) for (int i = 0; i < SERVICE_WARNING_BUZZES; i++) BUZZ(200, 404); + if (doBuzz) for (int i = 0; i < SERVICE_WARNING_BUZZES; i++) { BUZZ(200, 404); BUZZ(10, 0); } #else UNUSED(doBuzz); #endif @@ -171,7 +171,7 @@ void PrintCounter::saveStats() { persistentStore.write_data(address + sizeof(uint8_t), (uint8_t*)&data, sizeof(printStatistics)); persistentStore.access_finish(); - TERN_(EXTENSIBLE_UI, ExtUI::onConfigurationStoreWritten(true)); + TERN_(EXTENSIBLE_UI, ExtUI::onSettingsStored(true)); } #if HAS_SERVICE_INTERVALS diff --git a/Marlin/src/module/probe.cpp b/Marlin/src/module/probe.cpp index 8793ea49dc..f9a64a02d3 100644 --- a/Marlin/src/module/probe.cpp +++ b/Marlin/src/module/probe.cpp @@ -306,17 +306,16 @@ FORCE_INLINE void probe_specific_action(const bool deploy) { if (deploy != PROBE_TRIGGERED()) break; #endif - BUZZ(100, 659); - BUZZ(100, 698); + OKAY_BUZZ(); FSTR_P const ds_str = deploy ? GET_TEXT_F(MSG_MANUAL_DEPLOY) : GET_TEXT_F(MSG_MANUAL_STOW); ui.return_to_status(); // To display the new status message ui.set_status(ds_str, 99); - SERIAL_ECHOLNF(ds_str); + SERIAL_ECHOLNF(deploy ? GET_EN_TEXT_F(MSG_MANUAL_DEPLOY) : GET_EN_TEXT_F(MSG_MANUAL_STOW)); - TERN_(HOST_PROMPT_SUPPORT, hostui.prompt_do(PROMPT_USER_CONTINUE, F("Stow Probe"), FPSTR(CONTINUE_STR))); - TERN_(EXTENSIBLE_UI, ExtUI::onUserConfirmRequired(F("Stow Probe"))); - TERN_(DWIN_LCD_PROUI, DWIN_Popup_Confirm(ICON_BLTouch, F("Stow Probe"), FPSTR(CONTINUE_STR))); + TERN_(HOST_PROMPT_SUPPORT, hostui.prompt_do(PROMPT_USER_CONTINUE, ds_str, FPSTR(CONTINUE_STR))); + TERN_(EXTENSIBLE_UI, ExtUI::onUserConfirmRequired(ds_str)); + TERN_(DWIN_LCD_PROUI, DWIN_Popup_Confirm(ICON_BLTouch, ds_str, FPSTR(CONTINUE_STR))); TERN_(HAS_RESUME_CONTINUE, wait_for_user_response()); ui.reset_status(); @@ -795,9 +794,10 @@ float Probe::probe_at_point(const_float_t rx, const_float_t ry, const ProbePtRai #endif // On delta keep Z below clip height or do_blocking_move_to will abort - xyz_pos_t npos = LINEAR_AXIS_ARRAY( + xyz_pos_t npos = NUM_AXIS_ARRAY( rx, ry, TERN(DELTA, _MIN(delta_clip_start_height, current_position.z), current_position.z), - current_position.i, current_position.j, current_position.k + current_position.i, current_position.j, current_position.k, + current_position.u, current_position.v, current_position.w ); if (!can_reach(npos, probe_relative)) { if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Position Not Reachable"); @@ -889,7 +889,7 @@ float Probe::probe_at_point(const_float_t rx, const_float_t ry, const ProbePtRai */ void Probe::set_homing_current(const bool onoff) { #define HAS_CURRENT_HOME(N) (defined(N##_CURRENT_HOME) && N##_CURRENT_HOME != N##_CURRENT) - #if HAS_CURRENT_HOME(X) || HAS_CURRENT_HOME(Y) || HAS_CURRENT_HOME(Z) + #if HAS_CURRENT_HOME(X) || HAS_CURRENT_HOME(Y) || HAS_CURRENT_HOME(Z) || HAS_CURRENT_HOME(I) || HAS_CURRENT_HOME(J) || HAS_CURRENT_HOME(K) || HAS_CURRENT_HOME(U) || HAS_CURRENT_HOME(V) || HAS_CURRENT_HOME(W) #if ENABLED(DELTA) static int16_t saved_current_X, saved_current_Y; #endif diff --git a/Marlin/src/module/probe.h b/Marlin/src/module/probe.h index 752e83f467..c802411be3 100644 --- a/Marlin/src/module/probe.h +++ b/Marlin/src/module/probe.h @@ -138,7 +138,7 @@ public: #else - static constexpr xyz_pos_t offset = xyz_pos_t(LINEAR_AXIS_ARRAY(0, 0, 0, 0, 0, 0)); // See #16767 + static constexpr xyz_pos_t offset = xyz_pos_t(NUM_AXIS_ARRAY(0, 0, 0, 0, 0, 0)); // See #16767 static bool set_deployed(const bool) { return false; } @@ -188,6 +188,15 @@ public: } #endif + /** + * The nozzle is only able to move within the physical bounds of the machine. + * If the PROBE has an OFFSET Marlin may need to apply additional limits so + * the probe can be prevented from going to unreachable points. + * + * e.g., If the PROBE is to the LEFT of the NOZZLE, it will be limited in how + * close it can get the RIGHT edge of the bed (unless the nozzle is able move + * far enough past the right edge). + */ static constexpr float _min_x(const xy_pos_t &probe_offset_xy=offset_xy) { return TERN(IS_KINEMATIC, (X_CENTER) - probe_radius(probe_offset_xy), diff --git a/Marlin/src/module/scara.cpp b/Marlin/src/module/scara.cpp index 2527292e16..bc42b85fbe 100644 --- a/Marlin/src/module/scara.cpp +++ b/Marlin/src/module/scara.cpp @@ -254,7 +254,7 @@ float segments_per_second = TERN(AXEL_TPARA, TPARA_SEGMENTS_PER_SECOND, SCARA_SE // Do this here all at once for Delta, because // XYZ isn't ABC. Applying this per-tower would // give the impression that they are the same. - LOOP_LINEAR_AXES(i) set_axis_is_at_home((AxisEnum)i); + LOOP_NUM_AXES(i) set_axis_is_at_home((AxisEnum)i); sync_plan_position(); } diff --git a/Marlin/src/module/settings.cpp b/Marlin/src/module/settings.cpp index 7c10698ccc..5cd592bddc 100644 --- a/Marlin/src/module/settings.cpp +++ b/Marlin/src/module/settings.cpp @@ -112,9 +112,6 @@ #if HAS_FILAMENT_SENSOR #include "../feature/runout.h" - #define NRS NUM_RUNOUT_SENSORS -#else - #define NRS 1 #endif #if ENABLED(EXTRA_LIN_ADVANCE_K) @@ -179,10 +176,10 @@ #define _EN_ITEM(N) , E##N -typedef struct { uint16_t LINEAR_AXIS_LIST(X, Y, Z, I, J, K), X2, Y2, Z2, Z3, Z4 REPEAT(E_STEPPERS, _EN_ITEM); } tmc_stepper_current_t; -typedef struct { uint32_t LINEAR_AXIS_LIST(X, Y, Z, I, J, K), X2, Y2, Z2, Z3, Z4 REPEAT(E_STEPPERS, _EN_ITEM); } tmc_hybrid_threshold_t; -typedef struct { int16_t LINEAR_AXIS_LIST(X, Y, Z, I, J, K), X2, Y2, Z2, Z3, Z4; } tmc_sgt_t; -typedef struct { bool LINEAR_AXIS_LIST(X, Y, Z, I, J, K), X2, Y2, Z2, Z3, Z4 REPEAT(E_STEPPERS, _EN_ITEM); } tmc_stealth_enabled_t; +typedef struct { uint16_t NUM_AXIS_LIST(X, Y, Z, I, J, K, U, V, W), X2, Y2, Z2, Z3, Z4 REPEAT(E_STEPPERS, _EN_ITEM); } tmc_stepper_current_t; +typedef struct { uint32_t NUM_AXIS_LIST(X, Y, Z, I, J, K, U, V, W), X2, Y2, Z2, Z3, Z4 REPEAT(E_STEPPERS, _EN_ITEM); } tmc_hybrid_threshold_t; +typedef struct { int16_t NUM_AXIS_LIST(X, Y, Z, I, J, K, U, V, W), X2, Y2, Z2, Z3, Z4; } tmc_sgt_t; +typedef struct { bool NUM_AXIS_LIST(X, Y, Z, I, J, K, U, V, W), X2, Y2, Z2, Z3, Z4 REPEAT(E_STEPPERS, _EN_ITEM); } tmc_stealth_enabled_t; #undef _EN_ITEM @@ -210,7 +207,7 @@ typedef struct SettingsDataStruct { // // DISTINCT_E_FACTORS // - uint8_t e_factors; // DISTINCT_AXES - LINEAR_AXES + uint8_t e_factors; // DISTINCT_AXES - NUM_AXES // // Planner settings @@ -235,9 +232,11 @@ typedef struct SettingsDataStruct { // // FILAMENT_RUNOUT_SENSOR // - bool runout_enabled[NRS]; // M591 S - float runout_distance_mm[NRS]; // M591 D - uint8_t runout_mode[NRS]; // M591 P + #if HAS_FILAMENT_SENSOR + bool runout_enabled[NUM_RUNOUT_SENSORS]; // M591 S + float runout_distance_mm[NUM_RUNOUT_SENSORS]; // M591 D + uint8_t runout_mode[NUM_RUNOUT_SENSORS]; // M591 P + #endif // // ENABLE_LEVELING_FADE_HEIGHT @@ -278,7 +277,9 @@ typedef struct SettingsDataStruct { // X_AXIS_TWIST_COMPENSATION // #if ENABLED(X_AXIS_TWIST_COMPENSATION) - XATC xatc; // M423 X Z + float xatc_spacing; // M423 X Z + float xatc_start; + xatc_array_t xatc_z_offset; #endif // @@ -443,7 +444,7 @@ typedef struct SettingsDataStruct { // HAS_MOTOR_CURRENT_PWM // #ifndef MOTOR_CURRENT_COUNT - #define MOTOR_CURRENT_COUNT LINEAR_AXES + #define MOTOR_CURRENT_COUNT NUM_AXES #endif uint32_t motor_current_setting[MOTOR_CURRENT_COUNT]; // M907 X Z E ... @@ -553,6 +554,13 @@ typedef struct SettingsDataStruct { uint8_t ui_language; // M414 S #endif + // + // Model predictive control + // + #if ENABLED(MPCTEMP) + MPC_t mpc_constants[HOTENDS]; // M306 + #endif + } SettingsData; //static_assert(sizeof(SettingsData) <= MARLIN_EEPROM_SIZE, "EEPROM too small to contain SettingsData!"); @@ -589,14 +597,14 @@ void MarlinSettings::postprocess() { #endif // Software endstops depend on home_offset - LOOP_LINEAR_AXES(i) { + LOOP_NUM_AXES(i) { update_workspace_offset((AxisEnum)i); update_software_endstops((AxisEnum)i); } TERN_(ENABLE_LEVELING_FADE_HEIGHT, set_z_fade_height(new_z_fade_height, false)); // false = no report - TERN_(AUTO_BED_LEVELING_BILINEAR, refresh_bed_level()); + TERN_(AUTO_BED_LEVELING_BILINEAR, bbl.refresh_bed_level()); TERN_(HAS_MOTOR_CURRENT_PWM, stepper.refresh_motor_power()); @@ -737,7 +745,7 @@ void MarlinSettings::postprocess() { working_crc = 0; // clear before first "real data" - const uint8_t e_factors = DISTINCT_AXES - (LINEAR_AXES); + const uint8_t e_factors = DISTINCT_AXES - (NUM_AXES); _FIELD_TEST(e_factors); EEPROM_WRITE(e_factors); @@ -754,7 +762,7 @@ void MarlinSettings::postprocess() { EEPROM_WRITE(dummyf); #endif #else - const xyze_pos_t planner_max_jerk = LOGICAL_AXIS_ARRAY(float(DEFAULT_EJERK), 10, 10, 0.4, 0.4, 0.4, 0.4); + const xyze_pos_t planner_max_jerk = LOGICAL_AXIS_ARRAY(float(DEFAULT_EJERK), 10, 10, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4); EEPROM_WRITE(planner_max_jerk); #endif @@ -781,29 +789,23 @@ void MarlinSettings::postprocess() { // // Hotend Offsets, if any // - { - #if HAS_HOTEND_OFFSET - // Skip hotend 0 which must be 0 - LOOP_S_L_N(e, 1, HOTENDS) - EEPROM_WRITE(hotend_offset[e]); - #endif - } + #if HAS_HOTEND_OFFSET + // Skip hotend 0 which must be 0 + LOOP_S_L_N(e, 1, HOTENDS) + EEPROM_WRITE(hotend_offset[e]); + #endif // // Filament Runout Sensor // + #if HAS_FILAMENT_SENSOR { _FIELD_TEST(runout_enabled); - #if HAS_FILAMENT_SENSOR - LOOP_L_N(e, NRS) EEPROM_WRITE(runout.enabled[e]); - LOOP_L_N(e, NRS) EEPROM_WRITE(runout.runout_distance(e)); - LOOP_L_N(e, NRS) EEPROM_WRITE(runout.mode[e]); - #else - EEPROM_WRITE((int8_t)-1); - EEPROM_WRITE((float)-0.0f); - EEPROM_WRITE((uint8_t)0); - #endif + LOOP_L_N(e, NUM_RUNOUT_SENSORS) EEPROM_WRITE(runout.enabled[e]); + LOOP_L_N(e, NUM_RUNOUT_SENSORS) EEPROM_WRITE(runout.runout_distance(e)); + LOOP_L_N(e, NUM_RUNOUT_SENSORS) EEPROM_WRITE(runout.mode[e]); } + #endif // // Global Leveling @@ -871,22 +873,26 @@ void MarlinSettings::postprocess() { { #if ENABLED(AUTO_BED_LEVELING_BILINEAR) static_assert( - sizeof(z_values) == (GRID_MAX_POINTS) * sizeof(z_values[0][0]), + sizeof(Z_VALUES_ARR) == (GRID_MAX_POINTS) * sizeof(Z_VALUES_ARR[0][0]), "Bilinear Z array is the wrong size." ); - #else - const xy_pos_t bilinear_start{0}, bilinear_grid_spacing{0}; #endif const uint8_t grid_max_x = TERN(AUTO_BED_LEVELING_BILINEAR, GRID_MAX_POINTS_X, 3), grid_max_y = TERN(AUTO_BED_LEVELING_BILINEAR, GRID_MAX_POINTS_Y, 3); EEPROM_WRITE(grid_max_x); EEPROM_WRITE(grid_max_y); - EEPROM_WRITE(bilinear_grid_spacing); - EEPROM_WRITE(bilinear_start); + #if ENABLED(AUTO_BED_LEVELING_BILINEAR) + EEPROM_WRITE(bbl.get_grid_spacing()); + EEPROM_WRITE(bbl.get_grid_start()); + #else + const xy_pos_t bilinear_start{0}, bilinear_grid_spacing{0}; + EEPROM_WRITE(bilinear_grid_spacing); + EEPROM_WRITE(bilinear_start); + #endif #if ENABLED(AUTO_BED_LEVELING_BILINEAR) - EEPROM_WRITE(z_values); // 9-256 floats + EEPROM_WRITE(Z_VALUES_ARR); // 9-256 floats #else dummyf = 0; for (uint16_t q = grid_max_x * grid_max_y; q--;) EEPROM_WRITE(dummyf); @@ -897,7 +903,7 @@ void MarlinSettings::postprocess() { // X Axis Twist Compensation // #if ENABLED(X_AXIS_TWIST_COMPENSATION) - _FIELD_TEST(xatc); + _FIELD_TEST(xatc_spacing); EEPROM_WRITE(xatc.spacing); EEPROM_WRITE(xatc.start); EEPROM_WRITE(xatc.z_offset); @@ -1225,6 +1231,15 @@ void MarlinSettings::postprocess() { #if AXIS_IS_TMC(K) tmc_stepper_current.K = stepperK.getMilliamps(); #endif + #if AXIS_IS_TMC(U) + tmc_stepper_current.U = stepperU.getMilliamps(); + #endif + #if AXIS_IS_TMC(V) + tmc_stepper_current.V = stepperV.getMilliamps(); + #endif + #if AXIS_IS_TMC(W) + tmc_stepper_current.W = stepperW.getMilliamps(); + #endif #if AXIS_IS_TMC(X2) tmc_stepper_current.X2 = stepperX2.getMilliamps(); #endif @@ -1282,6 +1297,9 @@ void MarlinSettings::postprocess() { TERN_(I_HAS_STEALTHCHOP, tmc_hybrid_threshold.I = stepperI.get_pwm_thrs()); TERN_(J_HAS_STEALTHCHOP, tmc_hybrid_threshold.J = stepperJ.get_pwm_thrs()); TERN_(K_HAS_STEALTHCHOP, tmc_hybrid_threshold.K = stepperK.get_pwm_thrs()); + TERN_(U_HAS_STEALTHCHOP, tmc_hybrid_threshold.U = stepperU.get_pwm_thrs()); + TERN_(V_HAS_STEALTHCHOP, tmc_hybrid_threshold.V = stepperV.get_pwm_thrs()); + TERN_(W_HAS_STEALTHCHOP, tmc_hybrid_threshold.W = stepperW.get_pwm_thrs()); TERN_(X2_HAS_STEALTHCHOP, tmc_hybrid_threshold.X2 = stepperX2.get_pwm_thrs()); TERN_(Y2_HAS_STEALTHCHOP, tmc_hybrid_threshold.Y2 = stepperY2.get_pwm_thrs()); TERN_(Z2_HAS_STEALTHCHOP, tmc_hybrid_threshold.Z2 = stepperZ2.get_pwm_thrs()); @@ -1298,7 +1316,7 @@ void MarlinSettings::postprocess() { #else #define _EN_ITEM(N) , .E##N = 30 const tmc_hybrid_threshold_t tmc_hybrid_threshold = { - LINEAR_AXIS_LIST(.X = 100, .Y = 100, .Z = 3, .I = 3, .J = 3, .K = 3), + NUM_AXIS_LIST(.X = 100, .Y = 100, .Z = 3, .I = 3, .J = 3, .K = 3, .U = 3, .V = 3, .W = 3), .X2 = 100, .Y2 = 100, .Z2 = 3, .Z3 = 3, .Z4 = 3 REPEAT(E_STEPPERS, _EN_ITEM) }; @@ -1313,13 +1331,16 @@ void MarlinSettings::postprocess() { { tmc_sgt_t tmc_sgt{0}; #if USE_SENSORLESS - LINEAR_AXIS_CODE( + NUM_AXIS_CODE( TERN_(X_SENSORLESS, tmc_sgt.X = stepperX.homing_threshold()), TERN_(Y_SENSORLESS, tmc_sgt.Y = stepperY.homing_threshold()), TERN_(Z_SENSORLESS, tmc_sgt.Z = stepperZ.homing_threshold()), TERN_(I_SENSORLESS, tmc_sgt.I = stepperI.homing_threshold()), TERN_(J_SENSORLESS, tmc_sgt.J = stepperJ.homing_threshold()), - TERN_(K_SENSORLESS, tmc_sgt.K = stepperK.homing_threshold()) + TERN_(K_SENSORLESS, tmc_sgt.K = stepperK.homing_threshold()), + TERN_(U_SENSORLESS, tmc_sgt.U = stepperU.homing_threshold()), + TERN_(V_SENSORLESS, tmc_sgt.V = stepperV.homing_threshold()), + TERN_(W_SENSORLESS, tmc_sgt.W = stepperW.homing_threshold()) ); TERN_(X2_SENSORLESS, tmc_sgt.X2 = stepperX2.homing_threshold()); TERN_(Y2_SENSORLESS, tmc_sgt.Y2 = stepperY2.homing_threshold()); @@ -1343,6 +1364,9 @@ void MarlinSettings::postprocess() { TERN_(I_HAS_STEALTHCHOP, tmc_stealth_enabled.I = stepperI.get_stored_stealthChop()); TERN_(J_HAS_STEALTHCHOP, tmc_stealth_enabled.J = stepperJ.get_stored_stealthChop()); TERN_(K_HAS_STEALTHCHOP, tmc_stealth_enabled.K = stepperK.get_stored_stealthChop()); + TERN_(U_HAS_STEALTHCHOP, tmc_stealth_enabled.U = stepperU.get_stored_stealthChop()); + TERN_(V_HAS_STEALTHCHOP, tmc_stealth_enabled.V = stepperV.get_stored_stealthChop()); + TERN_(W_HAS_STEALTHCHOP, tmc_stealth_enabled.W = stepperW.get_stored_stealthChop()); TERN_(X2_HAS_STEALTHCHOP, tmc_stealth_enabled.X2 = stepperX2.get_stored_stealthChop()); TERN_(Y2_HAS_STEALTHCHOP, tmc_stealth_enabled.Y2 = stepperY2.get_stored_stealthChop()); TERN_(Z2_HAS_STEALTHCHOP, tmc_stealth_enabled.Z2 = stepperZ2.get_stored_stealthChop()); @@ -1432,7 +1456,7 @@ void MarlinSettings::postprocess() { { #if ENABLED(BACKLASH_GCODE) xyz_float_t backlash_distance_mm; - LOOP_LINEAR_AXES(axis) backlash_distance_mm[axis] = backlash.get_distance_mm((AxisEnum)axis); + LOOP_NUM_AXES(axis) backlash_distance_mm[axis] = backlash.get_distance_mm((AxisEnum)axis); const uint8_t backlash_correction = backlash.get_correction_uint8(); #else const xyz_float_t backlash_distance_mm{0}; @@ -1554,6 +1578,14 @@ void MarlinSettings::postprocess() { EEPROM_WRITE(ui.language); #endif + // + // Model predictive control + // + #if ENABLED(MPCTEMP) + HOTEND_LOOP() + EEPROM_WRITE(thermalManager.temp_hotend[e].constants); + #endif + // // Report final CRC and Data Size // @@ -1590,7 +1622,7 @@ void MarlinSettings::postprocess() { TERN_(HOST_PROMPT_SUPPORT, hostui.notify(GET_TEXT_F(MSG_SETTINGS_STORED))); } - TERN_(EXTENSIBLE_UI, ExtUI::onConfigurationStoreWritten(!eeprom_error)); + TERN_(EXTENSIBLE_UI, ExtUI::onSettingsStored(!eeprom_error)); return !eeprom_error; } @@ -1644,16 +1676,16 @@ void MarlinSettings::postprocess() { { // Get only the number of E stepper parameters previously stored // Any steppers added later are set to their defaults - uint32_t tmp1[LINEAR_AXES + e_factors]; - float tmp2[LINEAR_AXES + e_factors]; - feedRate_t tmp3[LINEAR_AXES + e_factors]; + uint32_t tmp1[NUM_AXES + e_factors]; + float tmp2[NUM_AXES + e_factors]; + feedRate_t tmp3[NUM_AXES + e_factors]; EEPROM_READ((uint8_t *)tmp1, sizeof(tmp1)); // max_acceleration_mm_per_s2 EEPROM_READ(planner.settings.min_segment_time_us); EEPROM_READ((uint8_t *)tmp2, sizeof(tmp2)); // axis_steps_per_mm EEPROM_READ((uint8_t *)tmp3, sizeof(tmp3)); // max_feedrate_mm_s if (!validating) LOOP_DISTINCT_AXES(i) { - const bool in = (i < e_factors + LINEAR_AXES); + const bool in = (i < e_factors + NUM_AXES); planner.settings.max_acceleration_mm_per_s2[i] = in ? tmp1[i] : pgm_read_dword(&_DMA[ALIM(i, _DMA)]); planner.settings.axis_steps_per_mm[i] = in ? tmp2[i] : pgm_read_float(&_DASU[ALIM(i, _DASU)]); planner.settings.max_feedrate_mm_s[i] = in ? tmp3[i] : pgm_read_float(&_DMF[ALIM(i, _DMF)]); @@ -1707,30 +1739,28 @@ void MarlinSettings::postprocess() { // // Filament Runout Sensor // + #if HAS_FILAMENT_SENSOR { _FIELD_TEST(runout_enabled); - int8_t runout_enabled[NRS]; - float runout_distance_mm[NRS]; - uint8_t runout_mode[NRS]; + bool runout_enabled[NUM_RUNOUT_SENSORS]; + float runout_distance_mm[NUM_RUNOUT_SENSORS]; + RunoutMode runout_mode[NUM_RUNOUT_SENSORS]; - LOOP_S_L_N(e, 0, NRS) EEPROM_READ(runout_enabled[e]); - LOOP_S_L_N(e, 0, NRS) EEPROM_READ(runout_distance_mm[e]); - LOOP_S_L_N(e, 0, NRS) EEPROM_READ(runout_mode[e]); + EEPROM_READ(runout_enabled); + EEPROM_READ(runout_distance_mm); + EEPROM_READ(runout_mode); - #if HAS_FILAMENT_SENSOR - if (!validating) { - LOOP_S_L_N(e, 0, NRS) { - if (runout_enabled[e] >= 0) { - runout.enabled[e] = (runout_enabled[e] > 0); - runout.set_runout_distance(runout_distance_mm[e], e); - runout.mode[e] = runout_mode[e]; - } - } - runout.reset(); + if (!validating) { + LOOP_S_L_N(e, 0, NUM_RUNOUT_SENSORS) { + runout.enabled[e] = runout_enabled[e]; + runout.set_runout_distance(runout_distance_mm[e], e); + runout.mode[e] = runout_mode[e]; } - #endif + runout.reset(); + } } + #endif // // Global Leveling @@ -1794,20 +1824,19 @@ void MarlinSettings::postprocess() { uint8_t grid_max_x, grid_max_y; EEPROM_READ_ALWAYS(grid_max_x); // 1 byte EEPROM_READ_ALWAYS(grid_max_y); // 1 byte + xy_pos_t spacing, start; + EEPROM_READ(spacing); // 2 ints + EEPROM_READ(start); // 2 ints #if ENABLED(AUTO_BED_LEVELING_BILINEAR) if (grid_max_x == (GRID_MAX_POINTS_X) && grid_max_y == (GRID_MAX_POINTS_Y)) { if (!validating) set_bed_leveling_enabled(false); - EEPROM_READ(bilinear_grid_spacing); // 2 ints - EEPROM_READ(bilinear_start); // 2 ints - EEPROM_READ(z_values); // 9 to 256 floats + bbl.set_grid(spacing, start); + EEPROM_READ(Z_VALUES_ARR); // 9 to 256 floats } else // EEPROM data is stale #endif // AUTO_BED_LEVELING_BILINEAR { // Skip past disabled (or stale) Bilinear Grid data - xy_pos_t bgs, bs; - EEPROM_READ(bgs); - EEPROM_READ(bs); for (uint16_t q = grid_max_x * grid_max_y; q--;) EEPROM_READ(dummyf); } } @@ -1816,7 +1845,7 @@ void MarlinSettings::postprocess() { // X Axis Twist Compensation // #if ENABLED(X_AXIS_TWIST_COMPENSATION) - _FIELD_TEST(xatc); + _FIELD_TEST(xatc_spacing); EEPROM_READ(xatc.spacing); EEPROM_READ(xatc.start); EEPROM_READ(xatc.z_offset); @@ -2175,6 +2204,15 @@ void MarlinSettings::postprocess() { #if AXIS_IS_TMC(K) SET_CURR(K); #endif + #if AXIS_IS_TMC(U) + SET_CURR(U); + #endif + #if AXIS_IS_TMC(V) + SET_CURR(V); + #endif + #if AXIS_IS_TMC(W) + SET_CURR(W); + #endif #if AXIS_IS_TMC(E0) SET_CURR(E0); #endif @@ -2222,6 +2260,9 @@ void MarlinSettings::postprocess() { TERN_(I_HAS_STEALTHCHOP, stepperI.set_pwm_thrs(tmc_hybrid_threshold.I)); TERN_(J_HAS_STEALTHCHOP, stepperJ.set_pwm_thrs(tmc_hybrid_threshold.J)); TERN_(K_HAS_STEALTHCHOP, stepperK.set_pwm_thrs(tmc_hybrid_threshold.K)); + TERN_(U_HAS_STEALTHCHOP, stepperU.set_pwm_thrs(tmc_hybrid_threshold.U)); + TERN_(V_HAS_STEALTHCHOP, stepperV.set_pwm_thrs(tmc_hybrid_threshold.V)); + TERN_(W_HAS_STEALTHCHOP, stepperW.set_pwm_thrs(tmc_hybrid_threshold.W)); TERN_(E0_HAS_STEALTHCHOP, stepperE0.set_pwm_thrs(tmc_hybrid_threshold.E0)); TERN_(E1_HAS_STEALTHCHOP, stepperE1.set_pwm_thrs(tmc_hybrid_threshold.E1)); TERN_(E2_HAS_STEALTHCHOP, stepperE2.set_pwm_thrs(tmc_hybrid_threshold.E2)); @@ -2243,13 +2284,16 @@ void MarlinSettings::postprocess() { EEPROM_READ(tmc_sgt); #if USE_SENSORLESS if (!validating) { - LINEAR_AXIS_CODE( + NUM_AXIS_CODE( TERN_(X_SENSORLESS, stepperX.homing_threshold(tmc_sgt.X)), TERN_(Y_SENSORLESS, stepperY.homing_threshold(tmc_sgt.Y)), TERN_(Z_SENSORLESS, stepperZ.homing_threshold(tmc_sgt.Z)), TERN_(I_SENSORLESS, stepperI.homing_threshold(tmc_sgt.I)), TERN_(J_SENSORLESS, stepperJ.homing_threshold(tmc_sgt.J)), - TERN_(K_SENSORLESS, stepperK.homing_threshold(tmc_sgt.K)) + TERN_(K_SENSORLESS, stepperK.homing_threshold(tmc_sgt.K)), + TERN_(U_SENSORLESS, stepperU.homing_threshold(tmc_sgt.U)), + TERN_(V_SENSORLESS, stepperV.homing_threshold(tmc_sgt.V)), + TERN_(W_SENSORLESS, stepperW.homing_threshold(tmc_sgt.W)) ); TERN_(X2_SENSORLESS, stepperX2.homing_threshold(tmc_sgt.X2)); TERN_(Y2_SENSORLESS, stepperY2.homing_threshold(tmc_sgt.Y2)); @@ -2277,6 +2321,9 @@ void MarlinSettings::postprocess() { TERN_(I_HAS_STEALTHCHOP, SET_STEPPING_MODE(I)); TERN_(J_HAS_STEALTHCHOP, SET_STEPPING_MODE(J)); TERN_(K_HAS_STEALTHCHOP, SET_STEPPING_MODE(K)); + TERN_(U_HAS_STEALTHCHOP, SET_STEPPING_MODE(U)); + TERN_(V_HAS_STEALTHCHOP, SET_STEPPING_MODE(V)); + TERN_(W_HAS_STEALTHCHOP, SET_STEPPING_MODE(W)); TERN_(X2_HAS_STEALTHCHOP, SET_STEPPING_MODE(X2)); TERN_(Y2_HAS_STEALTHCHOP, SET_STEPPING_MODE(Y2)); TERN_(Z2_HAS_STEALTHCHOP, SET_STEPPING_MODE(Z2)); @@ -2397,7 +2444,7 @@ void MarlinSettings::postprocess() { EEPROM_READ(backlash_smoothing_mm); #if ENABLED(BACKLASH_GCODE) - LOOP_LINEAR_AXES(axis) backlash.set_distance_mm((AxisEnum)axis, backlash_distance_mm[axis]); + LOOP_NUM_AXES(axis) backlash.set_distance_mm((AxisEnum)axis, backlash_distance_mm[axis]); backlash.set_correction_uint8(backlash_correction); #ifdef BACKLASH_SMOOTHING_MM backlash.set_smoothing_mm(backlash_smoothing_mm); @@ -2513,6 +2560,16 @@ void MarlinSettings::postprocess() { } #endif + // + // Model predictive control + // + #if ENABLED(MPCTEMP) + { + HOTEND_LOOP() + EEPROM_READ(thermalManager.temp_hotend[e].constants); + } + #endif + // // Validate Final Size and CRC // @@ -2601,7 +2658,7 @@ void MarlinSettings::postprocess() { bool MarlinSettings::load() { if (validate()) { const bool success = _load(); - TERN_(EXTENSIBLE_UI, ExtUI::onConfigurationStoreRead(success)); + TERN_(EXTENSIBLE_UI, ExtUI::onSettingsLoaded(success)); return success; } reset(); @@ -2773,8 +2830,17 @@ void MarlinSettings::reset() { #if HAS_K_AXIS && !defined(DEFAULT_KJERK) #define DEFAULT_KJERK 0 #endif + #if HAS_U_AXIS && !defined(DEFAULT_UJERK) + #define DEFAULT_UJERK 0 + #endif + #if HAS_V_AXIS && !defined(DEFAULT_VJERK) + #define DEFAULT_VJERK 0 + #endif + #if HAS_W_AXIS && !defined(DEFAULT_WJERK) + #define DEFAULT_WJERK 0 + #endif planner.max_jerk.set( - LINEAR_AXIS_LIST(DEFAULT_XJERK, DEFAULT_YJERK, DEFAULT_ZJERK, DEFAULT_IJERK, DEFAULT_JJERK, DEFAULT_KJERK) + NUM_AXIS_LIST(DEFAULT_XJERK, DEFAULT_YJERK, DEFAULT_ZJERK, DEFAULT_IJERK, DEFAULT_JJERK, DEFAULT_KJERK, DEFAULT_UJERK, DEFAULT_VJERK, DEFAULT_WJERK) ); TERN_(HAS_CLASSIC_E_JERK, planner.max_jerk.e = DEFAULT_EJERK); #endif @@ -2797,12 +2863,12 @@ void MarlinSettings::reset() { constexpr bool fred[] = FIL_RUNOUT_ENABLED; constexpr uint8_t frm[] = FIL_RUNOUT_MODE; constexpr float frd[] = FIL_RUNOUT_DISTANCE_MM; - static_assert(COUNT(fred) == NRS, "FIL_RUNOUT_ENABLED must have NUM_RUNOUT_SENSORS values."); - static_assert(COUNT(frm) == NRS, "FIL_RUNOUT_MODE must have NUM_RUNOUT_SENSORS values."); - static_assert(COUNT(frd) == NRS, "FIL_RUNOUT_DISTANCE_MM must have NUM_RUNOUT_SENSORS values."); + static_assert(COUNT(fred) == NUM_RUNOUT_SENSORS, "FIL_RUNOUT_ENABLED must have NUM_RUNOUT_SENSORS values."); + static_assert(COUNT(frm) == NUM_RUNOUT_SENSORS, "FIL_RUNOUT_MODE must have NUM_RUNOUT_SENSORS values."); + static_assert(COUNT(frd) == NUM_RUNOUT_SENSORS, "FIL_RUNOUT_DISTANCE_MM must have NUM_RUNOUT_SENSORS values."); COPY(runout.enabled, fred); COPY(runout.mode, frm); - LOOP_L_N(e, NRS) runout.set_runout_distance(frd[e], e); + LOOP_L_N(e, NUM_RUNOUT_SENSORS) runout.set_runout_distance(frd[e], e); runout.reset(); #endif @@ -2843,7 +2909,7 @@ void MarlinSettings::reset() { #if ENABLED(BACKLASH_GCODE) backlash.set_correction(BACKLASH_CORRECTION); constexpr xyz_float_t tmp = BACKLASH_DISTANCE_MM; - LOOP_LINEAR_AXES(axis) backlash.set_distance_mm((AxisEnum)axis, tmp[axis]); + LOOP_NUM_AXES(axis) backlash.set_distance_mm((AxisEnum)axis, tmp[axis]); #ifdef BACKLASH_SMOOTHING_MM backlash.set_smoothing_mm(BACKLASH_SMOOTHING_MM); #endif @@ -2888,11 +2954,11 @@ void MarlinSettings::reset() { // #if HAS_BED_PROBE constexpr float dpo[] = NOZZLE_TO_PROBE_OFFSET; - static_assert(COUNT(dpo) == LINEAR_AXES, "NOZZLE_TO_PROBE_OFFSET must contain offsets for each linear axis X, Y, Z...."); + static_assert(COUNT(dpo) == NUM_AXES, "NOZZLE_TO_PROBE_OFFSET must contain offsets for each linear axis X, Y, Z...."); #if HAS_PROBE_XY_OFFSET - LOOP_LINEAR_AXES(a) probe.offset[a] = dpo[a]; + LOOP_NUM_AXES(a) probe.offset[a] = dpo[a]; #else - probe.offset.set(LINEAR_AXIS_LIST(0, 0, dpo[Z_AXIS], 0, 0, 0)); + probe.offset.set(NUM_AXIS_LIST(0, 0, dpo[Z_AXIS], 0, 0, 0, 0, 0, 0)); #endif #endif @@ -3148,9 +3214,9 @@ void MarlinSettings::reset() { // #if ENABLED(LIN_ADVANCE) - LOOP_L_N(i, EXTRUDERS) { - planner.extruder_advance_K[i] = LIN_ADVANCE_K; - TERN_(EXTRA_LIN_ADVANCE_K, other_extruder_advance_K[i] = LIN_ADVANCE_K); + EXTRUDER_LOOP() { + planner.extruder_advance_K[e] = LIN_ADVANCE_K; + TERN_(EXTRA_LIN_ADVANCE_K, other_extruder_advance_K[e] = LIN_ADVANCE_K); } #endif @@ -3195,7 +3261,7 @@ void MarlinSettings::reset() { // Advanced Pause filament load & unload lengths // #if ENABLED(ADVANCED_PAUSE_FEATURE) - LOOP_L_N(e, EXTRUDERS) { + EXTRUDER_LOOP() { fc_settings[e].unload_length = FILAMENT_CHANGE_UNLOAD_LENGTH; fc_settings[e].load_length = FILAMENT_CHANGE_FAST_LOAD_LENGTH; } @@ -3229,6 +3295,37 @@ void MarlinSettings::reset() { #endif TERN_(EXTENSIBLE_UI, ExtUI::onFactoryReset()); + + // + // Model predictive control + // + #if ENABLED(MPCTEMP) + constexpr float _mpc_heater_power[] = MPC_HEATER_POWER; + constexpr float _mpc_block_heat_capacity[] = MPC_BLOCK_HEAT_CAPACITY; + constexpr float _mpc_sensor_responsiveness[] = MPC_SENSOR_RESPONSIVENESS; + constexpr float _mpc_ambient_xfer_coeff[] = MPC_AMBIENT_XFER_COEFF; + #if ENABLED(MPC_INCLUDE_FAN) + constexpr float _mpc_ambient_xfer_coeff_fan255[] = MPC_AMBIENT_XFER_COEFF_FAN255; + #endif + + static_assert(COUNT(_mpc_heater_power) == HOTENDS, "MPC_HEATER_POWER must have HOTENDS items."); + static_assert(COUNT(_mpc_block_heat_capacity) == HOTENDS, "MPC_BLOCK_HEAT_CAPACITY must have HOTENDS items."); + static_assert(COUNT(_mpc_sensor_responsiveness) == HOTENDS, "MPC_SENSOR_RESPONSIVENESS must have HOTENDS items."); + static_assert(COUNT(_mpc_ambient_xfer_coeff) == HOTENDS, "MPC_AMBIENT_XFER_COEFF must have HOTENDS items."); + #if ENABLED(MPC_INCLUDE_FAN) + static_assert(COUNT(_mpc_ambient_xfer_coeff_fan255) == HOTENDS, "MPC_AMBIENT_XFER_COEFF_FAN255 must have HOTENDS items."); + #endif + + HOTEND_LOOP() { + thermalManager.temp_hotend[e].constants.heater_power = _mpc_heater_power[e]; + thermalManager.temp_hotend[e].constants.block_heat_capacity = _mpc_block_heat_capacity[e]; + thermalManager.temp_hotend[e].constants.sensor_responsiveness = _mpc_sensor_responsiveness[e]; + thermalManager.temp_hotend[e].constants.ambient_xfer_coeff_fan0 = _mpc_ambient_xfer_coeff[e]; + #if ENABLED(MPC_INCLUDE_FAN) + thermalManager.temp_hotend[e].constants.fan255_adjustment = _mpc_ambient_xfer_coeff_fan255[e] - _mpc_ambient_xfer_coeff[e]; + #endif + } + #endif } #if DISABLED(DISABLE_M503) @@ -3347,7 +3444,7 @@ void MarlinSettings::reset() { LOOP_L_N(px, GRID_MAX_POINTS_X) { CONFIG_ECHO_START(); SERIAL_ECHOPGM(" G29 W I", px, " J", py); - SERIAL_ECHOLNPAIR_F_P(SP_Z_STR, LINEAR_UNIT(z_values[px][py]), 5); + SERIAL_ECHOLNPAIR_F_P(SP_Z_STR, LINEAR_UNIT(Z_VALUES_ARR[px][py]), 5); } } } @@ -3505,6 +3602,11 @@ void MarlinSettings::reset() { #endif TERN_(HAS_MULTI_LANGUAGE, gcode.M414_report(forReplay)); + + // + // Model predictive control + // + TERN_(MPCTEMP, gcode.M306_report(forReplay)); } #endif // !DISABLE_M503 diff --git a/Marlin/src/module/stepper.cpp b/Marlin/src/module/stepper.cpp index 46a17b6591..74246a3f10 100644 --- a/Marlin/src/module/stepper.cpp +++ b/Marlin/src/module/stepper.cpp @@ -189,7 +189,7 @@ bool Stepper::abort_current_block; uint32_t Stepper::acceleration_time, Stepper::deceleration_time; uint8_t Stepper::steps_per_isr; -#if HAS_FREEZE_PIN +#if ENABLED(FREEZE_FEATURE) bool Stepper::frozen; // = false #endif @@ -447,6 +447,18 @@ xyze_int8_t Stepper::count_direction{0}; #define K_APPLY_DIR(v,Q) K_DIR_WRITE(v) #define K_APPLY_STEP(v,Q) K_STEP_WRITE(v) #endif +#if HAS_U_AXIS + #define U_APPLY_DIR(v,Q) U_DIR_WRITE(v) + #define U_APPLY_STEP(v,Q) U_STEP_WRITE(v) +#endif +#if HAS_V_AXIS + #define V_APPLY_DIR(v,Q) V_DIR_WRITE(v) + #define V_APPLY_STEP(v,Q) V_STEP_WRITE(v) +#endif +#if HAS_W_AXIS + #define W_APPLY_DIR(v,Q) W_DIR_WRITE(v) + #define W_APPLY_STEP(v,Q) W_STEP_WRITE(v) +#endif #if DISABLED(MIXING_EXTRUDER) #define E_APPLY_STEP(v,Q) E_STEP_WRITE(stepper_extruder, v) @@ -486,9 +498,10 @@ xyze_int8_t Stepper::count_direction{0}; void Stepper::enable_axis(const AxisEnum axis) { #define _CASE_ENABLE(N) case N##_AXIS: ENABLE_AXIS_##N(); break; switch (axis) { - LINEAR_AXIS_CODE( + NUM_AXIS_CODE( _CASE_ENABLE(X), _CASE_ENABLE(Y), _CASE_ENABLE(Z), - _CASE_ENABLE(I), _CASE_ENABLE(J), _CASE_ENABLE(K) + _CASE_ENABLE(I), _CASE_ENABLE(J), _CASE_ENABLE(K), + _CASE_ENABLE(U), _CASE_ENABLE(V), _CASE_ENABLE(W) ); default: break; } @@ -505,9 +518,10 @@ bool Stepper::disable_axis(const AxisEnum axis) { if (can_disable) { #define _CASE_DISABLE(N) case N##_AXIS: DISABLE_AXIS_##N(); break; switch (axis) { - LINEAR_AXIS_CODE( + NUM_AXIS_CODE( _CASE_DISABLE(X), _CASE_DISABLE(Y), _CASE_DISABLE(Z), - _CASE_DISABLE(I), _CASE_DISABLE(J), _CASE_DISABLE(K) + _CASE_DISABLE(I), _CASE_DISABLE(J), _CASE_DISABLE(K), + _CASE_DISABLE(U), _CASE_DISABLE(V), _CASE_DISABLE(W) ); default: break; } @@ -550,9 +564,10 @@ bool Stepper::disable_axis(const AxisEnum axis) { void Stepper::enable_all_steppers() { TERN_(AUTO_POWER_CONTROL, powerManager.power_on()); - LINEAR_AXIS_CODE( + NUM_AXIS_CODE( enable_axis(X_AXIS), enable_axis(Y_AXIS), enable_axis(Z_AXIS), - enable_axis(I_AXIS), enable_axis(J_AXIS), enable_axis(K_AXIS) + enable_axis(I_AXIS), enable_axis(J_AXIS), enable_axis(K_AXIS), + enable_axis(U_AXIS), enable_axis(V_AXIS), enable_axis(W_AXIS) ); enable_e_steppers(); @@ -560,9 +575,10 @@ void Stepper::enable_all_steppers() { } void Stepper::disable_all_steppers() { - LINEAR_AXIS_CODE( + NUM_AXIS_CODE( disable_axis(X_AXIS), disable_axis(Y_AXIS), disable_axis(Z_AXIS), - disable_axis(I_AXIS), disable_axis(J_AXIS), disable_axis(K_AXIS) + disable_axis(I_AXIS), disable_axis(J_AXIS), disable_axis(K_AXIS), + disable_axis(U_AXIS), disable_axis(V_AXIS), disable_axis(W_AXIS) ); disable_e_steppers(); @@ -596,6 +612,9 @@ void Stepper::set_directions() { TERN_(HAS_I_DIR, SET_STEP_DIR(I)); TERN_(HAS_J_DIR, SET_STEP_DIR(J)); TERN_(HAS_K_DIR, SET_STEP_DIR(K)); + TERN_(HAS_U_DIR, SET_STEP_DIR(U)); + TERN_(HAS_V_DIR, SET_STEP_DIR(V)); + TERN_(HAS_W_DIR, SET_STEP_DIR(W)); #if DISABLED(LIN_ADVANCE) #if ENABLED(MIXING_EXTRUDER) @@ -1643,7 +1662,7 @@ void Stepper::pulse_phase_isr() { if (!current_block) return; // Skipping step processing causes motion to freeze - if (TERN0(HAS_FREEZE_PIN, frozen)) return; + if (TERN0(FREEZE_FEATURE, frozen)) return; // Count of pending loops and events for this iteration const uint32_t pending_events = step_event_count - step_events_completed; @@ -1816,6 +1835,15 @@ void Stepper::pulse_phase_isr() { #if HAS_K_STEP PULSE_PREP(K); #endif + #if HAS_U_STEP + PULSE_PREP(U); + #endif + #if HAS_V_STEP + PULSE_PREP(V); + #endif + #if HAS_W_STEP + PULSE_PREP(W); + #endif #if EITHER(LIN_ADVANCE, MIXING_EXTRUDER) delta_error.e += advance_dividend.e; @@ -1860,6 +1888,15 @@ void Stepper::pulse_phase_isr() { #if HAS_K_STEP PULSE_START(K); #endif + #if HAS_U_STEP + PULSE_START(U); + #endif + #if HAS_V_STEP + PULSE_START(V); + #endif + #if HAS_W_STEP + PULSE_START(W); + #endif #if DISABLED(LIN_ADVANCE) #if ENABLED(MIXING_EXTRUDER) @@ -1898,6 +1935,15 @@ void Stepper::pulse_phase_isr() { #if HAS_K_STEP PULSE_STOP(K); #endif + #if HAS_U_STEP + PULSE_STOP(U); + #endif + #if HAS_V_STEP + PULSE_STOP(V); + #endif + #if HAS_W_STEP + PULSE_STOP(W); + #endif #if DISABLED(LIN_ADVANCE) #if ENABLED(MIXING_EXTRUDER) @@ -2243,13 +2289,16 @@ uint32_t Stepper::block_phase_isr() { #endif axis_bits_t axis_bits = 0; - LINEAR_AXIS_CODE( + NUM_AXIS_CODE( if (X_MOVE_TEST) SBI(axis_bits, A_AXIS), if (Y_MOVE_TEST) SBI(axis_bits, B_AXIS), if (Z_MOVE_TEST) SBI(axis_bits, C_AXIS), if (current_block->steps.i) SBI(axis_bits, I_AXIS), if (current_block->steps.j) SBI(axis_bits, J_AXIS), - if (current_block->steps.k) SBI(axis_bits, K_AXIS) + if (current_block->steps.k) SBI(axis_bits, K_AXIS), + if (current_block->steps.u) SBI(axis_bits, U_AXIS), + if (current_block->steps.v) SBI(axis_bits, V_AXIS), + if (current_block->steps.w) SBI(axis_bits, W_AXIS) ); //if (current_block->steps.e) SBI(axis_bits, E_AXIS); //if (current_block->steps.a) SBI(axis_bits, X_HEAD); @@ -2589,6 +2638,15 @@ void Stepper::init() { #if HAS_K_DIR K_DIR_INIT(); #endif + #if HAS_U_DIR + U_DIR_INIT(); + #endif + #if HAS_V_DIR + V_DIR_INIT(); + #endif + #if HAS_W_DIR + W_DIR_INIT(); + #endif #if HAS_E0_DIR E0_DIR_INIT(); #endif @@ -2659,6 +2717,18 @@ void Stepper::init() { K_ENABLE_INIT(); if (!K_ENABLE_ON) K_ENABLE_WRITE(HIGH); #endif + #if HAS_U_ENABLE + U_ENABLE_INIT(); + if (!U_ENABLE_ON) U_ENABLE_WRITE(HIGH); + #endif + #if HAS_V_ENABLE + V_ENABLE_INIT(); + if (!V_ENABLE_ON) V_ENABLE_WRITE(HIGH); + #endif + #if HAS_W_ENABLE + W_ENABLE_INIT(); + if (!W_ENABLE_ON) W_ENABLE_WRITE(HIGH); + #endif #if HAS_E0_ENABLE E0_ENABLE_INIT(); if (!E_ENABLE_ON) E0_ENABLE_WRITE(HIGH); @@ -2744,6 +2814,15 @@ void Stepper::init() { #if HAS_K_STEP AXIS_INIT(K, K); #endif + #if HAS_U_STEP + AXIS_INIT(U, U); + #endif + #if HAS_V_STEP + AXIS_INIT(V, V); + #endif + #if HAS_W_STEP + AXIS_INIT(W, W); + #endif #if E_STEPPERS && HAS_E0_STEP E_AXIS_INIT(0); @@ -2778,13 +2857,16 @@ void Stepper::init() { // Init direction bits for first moves set_directions(0 - LINEAR_AXIS_GANG( + NUM_AXIS_GANG( | TERN0(INVERT_X_DIR, _BV(X_AXIS)), | TERN0(INVERT_Y_DIR, _BV(Y_AXIS)), | TERN0(INVERT_Z_DIR, _BV(Z_AXIS)), | TERN0(INVERT_I_DIR, _BV(I_AXIS)), | TERN0(INVERT_J_DIR, _BV(J_AXIS)), - | TERN0(INVERT_K_DIR, _BV(K_AXIS)) + | TERN0(INVERT_K_DIR, _BV(K_AXIS)), + | TERN0(INVERT_U_DIR, _BV(U_AXIS)), + | TERN0(INVERT_V_DIR, _BV(V_AXIS)), + | TERN0(INVERT_W_DIR, _BV(W_AXIS)) ) ); @@ -2820,6 +2902,14 @@ void Stepper::_set_position(const abce_long_t &spos) { #elif ENABLED(MARKFORGED_YX) count_position.set(spos.a, spos.b - spos.a, spos.c); #endif + SECONDARY_AXIS_CODE( + count_position.i = spos.i, + count_position.j = spos.j, + count_position.k = spos.k, + count_position.u = spos.u, + count_position.v = spos.v, + count_position.w = spos.w + ); TERN_(HAS_EXTRUDERS, count_position.e = spos.e); #else // default non-h-bot planning @@ -2934,13 +3024,16 @@ int32_t Stepper::triggered_position(const AxisEnum axis) { void Stepper::report_a_position(const xyz_long_t &pos) { SERIAL_ECHOLNPGM_P( - LIST_N(DOUBLE(LINEAR_AXES), + LIST_N(DOUBLE(NUM_AXES), TERN(SAYS_A, PSTR(STR_COUNT_A), PSTR(STR_COUNT_X)), pos.x, TERN(SAYS_B, PSTR("B:"), SP_Y_LBL), pos.y, TERN(SAYS_C, PSTR("C:"), SP_Z_LBL), pos.z, SP_I_LBL, pos.i, SP_J_LBL, pos.j, - SP_K_LBL, pos.k + SP_K_LBL, pos.k, + SP_U_LBL, pos.u, + SP_V_LBL, pos.v, + SP_W_LBL, pos.w ) ); } @@ -3091,16 +3184,18 @@ void Stepper::report_positions() { const bool z_direction = direction ^ BABYSTEP_INVERT_Z; - LINEAR_AXIS_CODE( + NUM_AXIS_CODE( enable_axis(X_AXIS), enable_axis(Y_AXIS), enable_axis(Z_AXIS), - enable_axis(I_AXIS), enable_axis(J_AXIS), enable_axis(K_AXIS) + enable_axis(I_AXIS), enable_axis(J_AXIS), enable_axis(K_AXIS), + enable_axis(U_AXIS), enable_axis(V_AXIS), enable_axis(W_AXIS) ); DIR_WAIT_BEFORE(); - const xyz_byte_t old_dir = LINEAR_AXIS_ARRAY( + const xyz_byte_t old_dir = NUM_AXIS_ARRAY( X_DIR_READ(), Y_DIR_READ(), Z_DIR_READ(), - I_DIR_READ(), J_DIR_READ(), K_DIR_READ() + I_DIR_READ(), J_DIR_READ(), K_DIR_READ(), + U_DIR_READ(), V_DIR_READ(), W_DIR_READ() ); X_DIR_WRITE(INVERT_X_DIR ^ z_direction); @@ -3119,6 +3214,15 @@ void Stepper::report_positions() { #ifdef K_DIR_WRITE K_DIR_WRITE(INVERT_K_DIR ^ z_direction); #endif + #ifdef U_DIR_WRITE + U_DIR_WRITE(INVERT_U_DIR ^ z_direction); + #endif + #ifdef V_DIR_WRITE + V_DIR_WRITE(INVERT_V_DIR ^ z_direction); + #endif + #ifdef W_DIR_WRITE + W_DIR_WRITE(INVERT_W_DIR ^ z_direction); + #endif DIR_WAIT_AFTER(); @@ -3140,6 +3244,15 @@ void Stepper::report_positions() { #ifdef K_STEP_WRITE K_STEP_WRITE(!INVERT_K_STEP_PIN); #endif + #ifdef U_STEP_WRITE + U_STEP_WRITE(!INVERT_U_STEP_PIN); + #endif + #ifdef V_STEP_WRITE + V_STEP_WRITE(!INVERT_V_STEP_PIN); + #endif + #ifdef W_STEP_WRITE + W_STEP_WRITE(!INVERT_W_STEP_PIN); + #endif _PULSE_WAIT(); @@ -3159,6 +3272,15 @@ void Stepper::report_positions() { #ifdef K_STEP_WRITE K_STEP_WRITE(INVERT_K_STEP_PIN); #endif + #ifdef U_STEP_WRITE + U_STEP_WRITE(INVERT_U_STEP_PIN); + #endif + #ifdef V_STEP_WRITE + V_STEP_WRITE(INVERT_V_STEP_PIN); + #endif + #ifdef W_STEP_WRITE + W_STEP_WRITE(INVERT_W_STEP_PIN); + #endif // Restore direction bits EXTRA_DIR_WAIT_BEFORE(); @@ -3179,6 +3301,15 @@ void Stepper::report_positions() { #ifdef K_DIR_WRITE K_DIR_WRITE(old_dir.k); #endif + #ifdef U_DIR_WRITE + U_DIR_WRITE(old_dir.u); + #endif + #ifdef V_DIR_WRITE + V_DIR_WRITE(old_dir.v); + #endif + #ifdef W_DIR_WRITE + W_DIR_WRITE(old_dir.w); + #endif EXTRA_DIR_WAIT_AFTER(); @@ -3195,6 +3326,15 @@ void Stepper::report_positions() { #if HAS_K_AXIS case K_AXIS: BABYSTEP_AXIS(K, 0, direction); break; #endif + #if HAS_U_AXIS + case U_AXIS: BABYSTEP_AXIS(U, 0, direction); break; + #endif + #if HAS_V_AXIS + case V_AXIS: BABYSTEP_AXIS(V, 0, direction); break; + #endif + #if HAS_W_AXIS + case W_AXIS: BABYSTEP_AXIS(W, 0, direction); break; + #endif default: break; } @@ -3423,6 +3563,24 @@ void Stepper::report_positions() { SET_OUTPUT(K_MS3_PIN); #endif #endif + #if HAS_U_MS_PINS + SET_OUTPUT(U_MS1_PIN); SET_OUTPUT(U_MS2_PIN); + #if PIN_EXISTS(U_MS3) + SET_OUTPUT(U_MS3_PIN); + #endif + #endif + #if HAS_V_MS_PINS + SET_OUTPUT(V_MS1_PIN); SET_OUTPUT(V_MS2_PIN); + #if PIN_EXISTS(V_MS3) + SET_OUTPUT(V_MS3_PIN); + #endif + #endif + #if HAS_W_MS_PINS + SET_OUTPUT(W_MS1_PIN); SET_OUTPUT(W_MS2_PIN); + #if PIN_EXISTS(W_MS3) + SET_OUTPUT(W_MS3_PIN); + #endif + #endif #if HAS_E0_MS_PINS SET_OUTPUT(E0_MS1_PIN); SET_OUTPUT(E0_MS2_PIN); #if PIN_EXISTS(E0_MS3) @@ -3548,6 +3706,15 @@ void Stepper::report_positions() { #if HAS_K_MS_PINS case 13: WRITE(K_MS1_PIN, ms1); break #endif + #if HAS_U_MS_PINS + case 14: WRITE(U_MS1_PIN, ms1); break + #endif + #if HAS_V_MS_PINS + case 15: WRITE(V_MS1_PIN, ms1); break + #endif + #if HAS_W_MS_PINS + case 16: WRITE(W_MS1_PIN, ms1); break + #endif } if (ms2 >= 0) switch (driver) { #if HAS_X_MS_PINS || HAS_X2_MS_PINS @@ -3619,6 +3786,15 @@ void Stepper::report_positions() { #if HAS_K_MS_PINS case 13: WRITE(K_MS2_PIN, ms2); break #endif + #if HAS_U_MS_PINS + case 14: WRITE(U_MS2_PIN, ms2); break + #endif + #if HAS_V_MS_PINS + case 15: WRITE(V_MS2_PIN, ms2); break + #endif + #if HAS_W_MS_PINS + case 16: WRITE(W_MS2_PIN, ms2); break + #endif } if (ms3 >= 0) switch (driver) { #if HAS_X_MS_PINS || HAS_X2_MS_PINS @@ -3755,6 +3931,24 @@ void Stepper::report_positions() { PIN_CHAR(K_MS3); #endif #endif + #if HAS_U_MS_PINS + MS_LINE(U); + #if PIN_EXISTS(U_MS3) + PIN_CHAR(U_MS3); + #endif + #endif + #if HAS_V_MS_PINS + MS_LINE(V); + #if PIN_EXISTS(V_MS3) + PIN_CHAR(V_MS3); + #endif + #endif + #if HAS_W_MS_PINS + MS_LINE(W); + #if PIN_EXISTS(W_MS3) + PIN_CHAR(W_MS3); + #endif + #endif #if HAS_E0_MS_PINS MS_LINE(E0); #if PIN_EXISTS(E0_MS3) diff --git a/Marlin/src/module/stepper.h b/Marlin/src/module/stepper.h index 99aa714ca0..8cc8610fd4 100644 --- a/Marlin/src/module/stepper.h +++ b/Marlin/src/module/stepper.h @@ -159,12 +159,21 @@ #if HAS_K_STEP #define ISR_K_STEPPER_CYCLES ISR_STEPPER_CYCLES #endif +#if HAS_U_STEP + #define ISR_U_STEPPER_CYCLES ISR_STEPPER_CYCLES +#endif +#if HAS_V_STEP + #define ISR_V_STEPPER_CYCLES ISR_STEPPER_CYCLES +#endif +#if HAS_W_STEP + #define ISR_W_STEPPER_CYCLES ISR_STEPPER_CYCLES +#endif #if HAS_EXTRUDERS #define ISR_E_STEPPER_CYCLES ISR_STEPPER_CYCLES // E is always interpolated, even for mixing extruders #endif // And the total minimum loop time, not including the base -#define MIN_ISR_LOOP_CYCLES (ISR_MIXING_STEPPER_CYCLES LOGICAL_AXIS_GANG(+ ISR_E_STEPPER_CYCLES, + ISR_X_STEPPER_CYCLES, + ISR_Y_STEPPER_CYCLES, + ISR_Z_STEPPER_CYCLES, + ISR_I_STEPPER_CYCLES, + ISR_J_STEPPER_CYCLES, + ISR_K_STEPPER_CYCLES)) +#define MIN_ISR_LOOP_CYCLES (ISR_MIXING_STEPPER_CYCLES LOGICAL_AXIS_GANG(+ ISR_E_STEPPER_CYCLES, + ISR_X_STEPPER_CYCLES, + ISR_Y_STEPPER_CYCLES, + ISR_Z_STEPPER_CYCLES, + ISR_I_STEPPER_CYCLES, + ISR_J_STEPPER_CYCLES, + ISR_K_STEPPER_CYCLES, + ISR_U_STEPPER_CYCLES, + ISR_V_STEPPER_CYCLES, + ISR_W_STEPPER_CYCLES)) // Calculate the minimum MPU cycles needed per pulse to enforce, limited to the max stepper rate #define _MIN_STEPPER_PULSE_CYCLES(N) _MAX(uint32_t((F_CPU) / (MAXIMUM_STEPPER_RATE)), ((F_CPU) / 500000UL) * (N)) @@ -236,7 +245,7 @@ // Perhaps DISABLE_MULTI_STEPPING should be required with ADAPTIVE_STEP_SMOOTHING. #define MIN_STEP_ISR_FREQUENCY (MAX_STEP_ISR_FREQUENCY_1X / 2) -#define ENABLE_COUNT (LINEAR_AXES + E_STEPPERS) +#define ENABLE_COUNT (NUM_AXES + E_STEPPERS) typedef IF<(ENABLE_COUNT > 8), uint16_t, uint8_t>::type ena_mask_t; // Axis flags type, for enabled state or other simple state @@ -244,25 +253,25 @@ typedef struct { union { ena_mask_t bits; struct { - bool LINEAR_AXIS_LIST(X:1, Y:1, Z:1, I:1, J:1, K:1); + bool NUM_AXIS_LIST(X:1, Y:1, Z:1, I:1, J:1, K:1, U:1, V:1, W:1); #if HAS_EXTRUDERS bool LIST_N(EXTRUDERS, E0:1, E1:1, E2:1, E3:1, E4:1, E5:1, E6:1, E7:1); #endif }; }; - constexpr ena_mask_t linear_bits() { return _BV(LINEAR_AXES) - 1; } - constexpr ena_mask_t e_bits() { return (_BV(EXTRUDERS) - 1) << LINEAR_AXES; } + constexpr ena_mask_t linear_bits() { return _BV(NUM_AXES) - 1; } + constexpr ena_mask_t e_bits() { return (_BV(EXTRUDERS) - 1) << NUM_AXES; } } axis_flags_t; // All the stepper enable pins constexpr pin_t ena_pins[] = { - LINEAR_AXIS_LIST(X_ENABLE_PIN, Y_ENABLE_PIN, Z_ENABLE_PIN, I_ENABLE_PIN, J_ENABLE_PIN, K_ENABLE_PIN), + NUM_AXIS_LIST(X_ENABLE_PIN, Y_ENABLE_PIN, Z_ENABLE_PIN, I_ENABLE_PIN, J_ENABLE_PIN, K_ENABLE_PIN, U_ENABLE_PIN, V_ENABLE_PIN, W_ENABLE_PIN), LIST_N(E_STEPPERS, E0_ENABLE_PIN, E1_ENABLE_PIN, E2_ENABLE_PIN, E3_ENABLE_PIN, E4_ENABLE_PIN, E5_ENABLE_PIN, E6_ENABLE_PIN, E7_ENABLE_PIN) }; // Index of the axis or extruder element in a combined array constexpr uint8_t index_of_axis(const AxisEnum axis E_OPTARG(const uint8_t eindex=0)) { - return uint8_t(axis) + (E_TERN0(axis < LINEAR_AXES ? 0 : eindex)); + return uint8_t(axis) + (E_TERN0(axis < NUM_AXES ? 0 : eindex)); } //#define __IAX_N(N,V...) _IAX_##N(V) //#define _IAX_N(N,V...) __IAX_N(N,V) @@ -292,7 +301,7 @@ constexpr bool any_enable_overlap(const uint8_t a=0) { // (e.g., CoreXY, Dual XYZ, or E with multiple steppers, etc.). constexpr ena_mask_t enable_overlap[] = { #define _OVERLAP(N) ena_overlap(INDEX_OF_AXIS(AxisEnum(N))), - REPEAT(LINEAR_AXES, _OVERLAP) + REPEAT(NUM_AXES, _OVERLAP) #if HAS_EXTRUDERS #define _E_OVERLAP(N) ena_overlap(INDEX_OF_AXIS(E_AXIS, N)), REPEAT(E_STEPPERS, _E_OVERLAP) @@ -320,7 +329,7 @@ class Stepper { #ifndef MOTOR_CURRENT_PWM_FREQUENCY #define MOTOR_CURRENT_PWM_FREQUENCY 31400 #endif - #define MOTOR_CURRENT_COUNT LINEAR_AXES + #define MOTOR_CURRENT_COUNT NUM_AXES #elif HAS_MOTOR_CURRENT_SPI static constexpr uint32_t digipot_count[] = DIGIPOT_MOTOR_CURRENT; #define MOTOR_CURRENT_COUNT COUNT(Stepper::digipot_count) @@ -336,7 +345,7 @@ class Stepper { static constexpr uint8_t last_moved_extruder = 0; #endif - #if HAS_FREEZE_PIN + #if ENABLED(FREEZE_FEATURE) static bool frozen; // Set this flag to instantly freeze motion #endif diff --git a/Marlin/src/module/stepper/L64xx.cpp b/Marlin/src/module/stepper/L64xx.cpp index 27816fb4f7..5b60746396 100644 --- a/Marlin/src/module/stepper/L64xx.cpp +++ b/Marlin/src/module/stepper/L64xx.cpp @@ -64,6 +64,15 @@ #if AXIS_IS_L64XX(K) L64XX_CLASS(K) stepperK(L6470_CHAIN_SS_PIN); #endif +#if AXIS_IS_L64XX(U) + L64XX_CLASS(u) stepperU(L6470_CHAIN_SS_PIN); +#endif +#if AXIS_IS_L64XX(V) + L64XX_CLASS(v) stepperV(L6470_CHAIN_SS_PIN); +#endif +#if AXIS_IS_L64XX(W) + L64XX_CLASS(w) stepperW(L6470_CHAIN_SS_PIN); +#endif #if AXIS_IS_L64XX(E0) L64XX_CLASS(E0) stepperE0(L6470_CHAIN_SS_PIN); #endif @@ -217,6 +226,15 @@ void L64XX_Marlin::init_to_defaults() { #if AXIS_IS_L64XX(K) L6470_INIT_CHIP(K); #endif + #if AXIS_IS_L64XX(U) + L6470_INIT_CHIP(U); + #endif + #if AXIS_IS_L64XX(V) + L6470_INIT_CHIP(V); + #endif + #if AXIS_IS_L64XX(W) + L6470_INIT_CHIP(W); + #endif #if AXIS_IS_L64XX(E0) L6470_INIT_CHIP(E0); #endif diff --git a/Marlin/src/module/stepper/L64xx.h b/Marlin/src/module/stepper/L64xx.h index 9f7e6623b1..870b0414f8 100644 --- a/Marlin/src/module/stepper/L64xx.h +++ b/Marlin/src/module/stepper/L64xx.h @@ -266,6 +266,72 @@ #endif #endif +// U Stepper +#if HAS_U_AXIS + #if AXIS_IS_L64XX(U) + extern L64XX_CLASS(U) stepperU; + #define U_ENABLE_INIT() NOOP + #define U_ENABLE_WRITE(STATE) (STATE ? stepperU.hardStop() : stepperU.free()) + #define U_ENABLE_READ() (stepperU.getStatus() & STATUS_HIZ) + #if AXIS_DRIVER_TYPE_U(L6474) + #define U_DIR_INIT() SET_OUTPUT(U_DIR_PIN) + #define U_DIR_WRITE(STATE) L6474_DIR_WRITE(U, STATE) + #define U_DIR_READ() READ(U_DIR_PIN) + #else + #define U_DIR_INIT() NOOP + #define U_DIR_WRITE(STATE) L64XX_DIR_WRITE(U, STATE) + #define U_DIR_READ() (stepper##U.getStatus() & STATUS_DIR); + #if AXIS_DRIVER_TYPE_U(L6470) + #define DISABLE_STEPPER_U() stepperU.free() + #endif + #endif + #endif +#endif + +// V Stepper +#if HAS_V_AXIS + #if AXIS_IS_L64XX(V) + extern L64XX_CLASS(V) stepperV; + #define V_ENABLE_INIT() NOOP + #define V_ENABLE_WRITE(STATE) (STATE ? stepperV.hardStop() : stepperV.free()) + #define V_ENABLE_READ() (stepperV.getStatus() & STATUS_HIZ) + #if AXIS_DRIVER_TYPE_V(L6474) + #define V_DIR_INIT() SET_OUTPUT(V_DIR_PIN) + #define V_DIR_WRITE(STATE) L6474_DIR_WRITE(V, STATE) + #define V_DIR_READ() READ(V_DIR_PIN) + #else + #define V_DIR_INIT() NOOP + #define V_DIR_WRITE(STATE) L64XX_DIR_WRITE(V, STATE) + #define V_DIR_READ() (stepper##V.getStatus() & STATUS_DIR); + #if AXIS_DRIVER_TYPE_V(L6470) + #define DISABLE_STEPPER_V() stepperV.free() + #endif + #endif + #endif +#endif + +// W Stepper +#if HAS_W_AXIS + #if AXIS_IS_L64XX(W) + extern L64XX_CLASS(w) stepperW; + #define W_ENABLE_INIT() NOOP + #define W_ENABLE_WRITE(STATE) (STATE ? stepperW.hardStop() : stepperW.free()) + #define W_ENABLE_READ() (stepperW.getStatus() & STATUS_HIZ) + #if AXIS_DRIVER_TYPE_W(L6474) + #define W_DIR_INIT() SET_OUTPUT(W_DIR_PIN) + #define W_DIR_WRITE(STATE) L6474_DIR_WRITE(W, STATE) + #define W_DIR_READ() READ(W_DIR_PIN) + #else + #define W_DIR_INIT() NOOP + #define W_DIR_WRITE(STATE) L64XX_DIR_WRITE(W, STATE) + #define W_DIR_READ() (stepper##W.getStatus() & STATUS_DIR); + #if AXIS_DRIVER_TYPE_W(L6470) + #define DISABLE_STEPPER_W() stepperW.free() + #endif + #endif + #endif +#endif + // E0 Stepper #if AXIS_IS_L64XX(E0) extern L64XX_CLASS(E0) stepperE0; diff --git a/Marlin/src/module/stepper/TMC26X.cpp b/Marlin/src/module/stepper/TMC26X.cpp index 26f91bfeb9..52d84f8410 100644 --- a/Marlin/src/module/stepper/TMC26X.cpp +++ b/Marlin/src/module/stepper/TMC26X.cpp @@ -69,6 +69,15 @@ #if AXIS_DRIVER_TYPE_K(TMC26X) _TMC26X_DEFINE(K); #endif +#if AXIS_DRIVER_TYPE_U(TMC26X) + _TMC26X_DEFINE(U); +#endif +#if AXIS_DRIVER_TYPE_V(TMC26X) + _TMC26X_DEFINE(V); +#endif +#if AXIS_DRIVER_TYPE_W(TMC26X) + _TMC26X_DEFINE(W); +#endif #if AXIS_DRIVER_TYPE_E0(TMC26X) _TMC26X_DEFINE(E0); #endif @@ -133,6 +142,15 @@ void tmc26x_init_to_defaults() { #if AXIS_DRIVER_TYPE_K(TMC26X) _TMC26X_INIT(K); #endif + #if AXIS_DRIVER_TYPE_U(TMC26X) + _TMC26X_INIT(U); + #endif + #if AXIS_DRIVER_TYPE_V(TMC26X) + _TMC26X_INIT(V); + #endif + #if AXIS_DRIVER_TYPE_W(TMC26X) + _TMC26X_INIT(W); + #endif #if AXIS_DRIVER_TYPE_E0(TMC26X) _TMC26X_INIT(E0); #endif diff --git a/Marlin/src/module/stepper/TMC26X.h b/Marlin/src/module/stepper/TMC26X.h index 988bebe0f2..1fd94b26a8 100644 --- a/Marlin/src/module/stepper/TMC26X.h +++ b/Marlin/src/module/stepper/TMC26X.h @@ -123,6 +123,30 @@ void tmc26x_init_to_defaults(); #define K_ENABLE_READ() stepperK.isEnabled() #endif +// U Stepper +#if HAS_U_ENABLE && AXIS_DRIVER_TYPE_U(TMC26X) + extern TMC26XStepper stepperU; + #define U_ENABLE_INIT() NOOP + #define U_ENABLE_WRITE(STATE) stepperU.setEnabled(STATE) + #define U_ENABLE_READ() stepperU.isEnabled() +#endif + +// V Stepper +#if HAS_V_ENABLE && AXIS_DRIVER_TYPE_V(TMC26X) + extern TMC26XStepper stepperV; + #define V_ENABLE_INIT() NOOP + #define V_ENABLE_WRITE(STATE) stepperV.setEnabled(STATE) + #define V_ENABLE_READ() stepperV.isEnabled() +#endif + +// W Stepper +#if HAS_W_ENABLE && AXIS_DRIVER_TYPE_W(TMC26X) + extern TMC26XStepper stepperW; + #define W_ENABLE_INIT() NOOP + #define W_ENABLE_WRITE(STATE) stepperW.setEnabled(STATE) + #define W_ENABLE_READ() stepperW.isEnabled() +#endif + // E0 Stepper #if AXIS_DRIVER_TYPE_E0(TMC26X) extern TMC26XStepper stepperE0; diff --git a/Marlin/src/module/stepper/indirection.h b/Marlin/src/module/stepper/indirection.h index 7aea677534..879185ca14 100644 --- a/Marlin/src/module/stepper/indirection.h +++ b/Marlin/src/module/stepper/indirection.h @@ -262,6 +262,63 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset #define K_STEP_READ() bool(READ(K_STEP_PIN)) #endif +// U Stepper +#if HAS_U_AXIS + #ifndef U_ENABLE_INIT + #define U_ENABLE_INIT() SET_OUTPUT(U_ENABLE_PIN) + #define U_ENABLE_WRITE(STATE) WRITE(U_ENABLE_PIN,STATE) + #define U_ENABLE_READ() bool(READ(U_ENABLE_PIN)) + #endif + #ifndef U_DIR_INIT + #define U_DIR_INIT() SET_OUTPUT(U_DIR_PIN) + #define U_DIR_WRITE(STATE) WRITE(U_DIR_PIN,STATE) + #define U_DIR_READ() bool(READ(U_DIR_PIN)) + #endif + #define U_STEP_INIT() SET_OUTPUT(U_STEP_PIN) + #ifndef U_STEP_WRITE + #define U_STEP_WRITE(STATE) WRITE(U_STEP_PIN,STATE) + #endif + #define U_STEP_READ() bool(READ(U_STEP_PIN)) +#endif + +// V Stepper +#if HAS_V_AXIS + #ifndef V_ENABLE_INIT + #define V_ENABLE_INIT() SET_OUTPUT(V_ENABLE_PIN) + #define V_ENABLE_WRITE(STATE) WRITE(V_ENABLE_PIN,STATE) + #define V_ENABLE_READ() bool(READ(V_ENABLE_PIN)) + #endif + #ifndef V_DIR_INIT + #define V_DIR_INIT() SET_OUTPUT(V_DIR_PIN) + #define V_DIR_WRITE(STATE) WRITE(V_DIR_PIN,STATE) + #define V_DIR_READ() bool(READ(V_DIR_PIN)) + #endif + #define V_STEP_INIT() SET_OUTPUT(V_STEP_PIN) + #ifndef V_STEP_WRITE + #define V_STEP_WRITE(STATE) WRITE(V_STEP_PIN,STATE) + #endif + #define V_STEP_READ() bool(READ(V_STEP_PIN)) +#endif + +// W Stepper +#if HAS_W_AXIS + #ifndef W_ENABLE_INIT + #define W_ENABLE_INIT() SET_OUTPUT(W_ENABLE_PIN) + #define W_ENABLE_WRITE(STATE) WRITE(W_ENABLE_PIN,STATE) + #define W_ENABLE_READ() bool(READ(W_ENABLE_PIN)) + #endif + #ifndef W_DIR_INIT + #define W_DIR_INIT() SET_OUTPUT(W_DIR_PIN) + #define W_DIR_WRITE(STATE) WRITE(W_DIR_PIN,STATE) + #define W_DIR_READ() bool(READ(W_DIR_PIN)) + #endif + #define W_STEP_INIT() SET_OUTPUT(W_STEP_PIN) + #ifndef W_STEP_WRITE + #define W_STEP_WRITE(STATE) WRITE(W_STEP_PIN,STATE) + #endif + #define W_STEP_READ() bool(READ(W_STEP_PIN)) +#endif + // E0 Stepper #ifndef E0_ENABLE_INIT #define E0_ENABLE_INIT() SET_OUTPUT(E0_ENABLE_PIN) @@ -743,6 +800,51 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset #define DISABLE_STEPPER_K() TERN(HAS_K_ENABLE, K_ENABLE_WRITE(!K_ENABLE_ON), NOOP) #endif +#ifndef ENABLE_STEPPER_U + #if HAS_U_ENABLE + #define ENABLE_STEPPER_U() U_ENABLE_WRITE( U_ENABLE_ON) + #else + #define ENABLE_STEPPER_U() NOOP + #endif +#endif +#ifndef DISABLE_STEPPER_U + #if HAS_U_ENABLE + #define DISABLE_STEPPER_U() U_ENABLE_WRITE(!U_ENABLE_ON) + #else + #define DISABLE_STEPPER_U() NOOP + #endif +#endif + +#ifndef ENABLE_STEPPER_V + #if HAS_V_ENABLE + #define ENABLE_STEPPER_V() V_ENABLE_WRITE( V_ENABLE_ON) + #else + #define ENABLE_STEPPER_V() NOOP + #endif +#endif +#ifndef DISABLE_STEPPER_V + #if HAS_V_ENABLE + #define DISABLE_STEPPER_V() V_ENABLE_WRITE(!V_ENABLE_ON) + #else + #define DISABLE_STEPPER_V() NOOP + #endif +#endif + +#ifndef ENABLE_STEPPER_W + #if HAS_W_ENABLE + #define ENABLE_STEPPER_W() W_ENABLE_WRITE( W_ENABLE_ON) + #else + #define ENABLE_STEPPER_W() NOOP + #endif +#endif +#ifndef DISABLE_STEPPER_W + #if HAS_W_ENABLE + #define DISABLE_STEPPER_W() W_ENABLE_WRITE(!W_ENABLE_ON) + #else + #define DISABLE_STEPPER_W() NOOP + #endif +#endif + #ifndef ENABLE_STEPPER_E0 #define ENABLE_STEPPER_E0() TERN(HAS_E0_ENABLE, E0_ENABLE_WRITE( E_ENABLE_ON), NOOP) #endif @@ -917,6 +1019,28 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset #define DISABLE_AXIS_K() NOOP #endif +#if HAS_U_AXIS + #define ENABLE_AXIS_U() if (SHOULD_ENABLE(u)) { ENABLE_STEPPER_U(); AFTER_CHANGE(u, true); } + #define DISABLE_AXIS_U() if (SHOULD_DISABLE(u)) { DISABLE_STEPPER_U(); AFTER_CHANGE(u, false); set_axis_untrusted(U_AXIS); } +#else + #define ENABLE_AXIS_U() NOOP + #define DISABLE_AXIS_U() NOOP +#endif +#if HAS_V_AXIS + #define ENABLE_AXIS_V() if (SHOULD_ENABLE(v)) { ENABLE_STEPPER_V(); AFTER_CHANGE(v, true); } + #define DISABLE_AXIS_V() if (SHOULD_DISABLE(v)) { DISABLE_STEPPER_V(); AFTER_CHANGE(v, false); set_axis_untrusted(V_AXIS); } +#else + #define ENABLE_AXIS_V() NOOP + #define DISABLE_AXIS_V() NOOP +#endif +#if HAS_W_AXIS + #define ENABLE_AXIS_W() if (SHOULD_ENABLE(w)) { ENABLE_STEPPER_W(); AFTER_CHANGE(w, true); } + #define DISABLE_AXIS_W() if (SHOULD_DISABLE(w)) { DISABLE_STEPPER_W(); AFTER_CHANGE(w, false); set_axis_untrusted(W_AXIS); } +#else + #define ENABLE_AXIS_W() NOOP + #define DISABLE_AXIS_W() NOOP +#endif + // // Extruder steppers enable / disable macros // diff --git a/Marlin/src/module/stepper/trinamic.cpp b/Marlin/src/module/stepper/trinamic.cpp index 7baa2108f0..ee156a1986 100644 --- a/Marlin/src/module/stepper/trinamic.cpp +++ b/Marlin/src/module/stepper/trinamic.cpp @@ -36,7 +36,7 @@ #include enum StealthIndex : uint8_t { - LOGICAL_AXIS_LIST(STEALTH_AXIS_E, STEALTH_AXIS_X, STEALTH_AXIS_Y, STEALTH_AXIS_Z, STEALTH_AXIS_I, STEALTH_AXIS_J, STEALTH_AXIS_K) + LOGICAL_AXIS_LIST(STEALTH_AXIS_E, STEALTH_AXIS_X, STEALTH_AXIS_Y, STEALTH_AXIS_Z, STEALTH_AXIS_I, STEALTH_AXIS_J, STEALTH_AXIS_K, STEALTH_AXIS_U, STEALTH_AXIS_V, STEALTH_AXIS_W) }; #define TMC_INIT(ST, STEALTH_INDEX) tmc_init(stepper##ST, ST##_CURRENT, ST##_MICROSTEPS, ST##_HYBRID_THRESHOLD, stealthchop_by_axis[STEALTH_INDEX], chopper_timing_##ST, ST##_INTERPOLATE, ST##_HOLD_MULTIPLIER) @@ -106,6 +106,15 @@ enum StealthIndex : uint8_t { #if AXIS_HAS_SPI(K) TMC_SPI_DEFINE(K, K); #endif +#if AXIS_HAS_SPI(U) + TMC_SPI_DEFINE(U, U); +#endif +#if AXIS_HAS_SPI(V) + TMC_SPI_DEFINE(V, V); +#endif +#if AXIS_HAS_SPI(W) + TMC_SPI_DEFINE(W, W); +#endif #if AXIS_HAS_SPI(E0) TMC_SPI_DEFINE_E(0); #endif @@ -173,6 +182,15 @@ enum StealthIndex : uint8_t { #ifndef TMC_K_BAUD_RATE #define TMC_K_BAUD_RATE TMC_BAUD_RATE #endif +#ifndef TMC_U_BAUD_RATE + #define TMC_U_BAUD_RATE TMC_BAUD_RATE +#endif +#ifndef TMC_V_BAUD_RATE + #define TMC_V_BAUD_RATE TMC_BAUD_RATE +#endif +#ifndef TMC_W_BAUD_RATE + #define TMC_W_BAUD_RATE TMC_BAUD_RATE +#endif #ifndef TMC_E0_BAUD_RATE #define TMC_E0_BAUD_RATE TMC_BAUD_RATE #endif @@ -374,6 +392,32 @@ enum StealthIndex : uint8_t { #define K_HAS_SW_SERIAL 1 #endif #endif + #if AXIS_HAS_UART(U) + #ifdef U_HARDWARE_SERIAL + TMC_UART_DEFINE(HW, U, U); + #define U_HAS_HW_SERIAL 1 + #else + TMC_UART_DEFINE(SW, U, U); + #define U_HAS_SW_SERIAL 1 + #endif + #endif + #if AXIS_HAS_UART(V) + #ifdef V_HARDWARE_SERIAL + TMC_UART_DEFINE(HW, V, V); + #else + TMC_UART_DEFINE(SW, V, V); + #define V_HAS_SW_SERIAL 1 + #endif + #endif + #if AXIS_HAS_UART(W) + #ifdef W_HARDWARE_SERIAL + TMC_UART_DEFINE(HW, W, W); + #define W_HAS_HW_SERIAL 1 + #else + TMC_UART_DEFINE(SW, W, W); + #define W_HAS_SW_SERIAL 1 + #endif + #endif #if AXIS_HAS_UART(E0) #ifdef E0_HARDWARE_SERIAL @@ -449,7 +493,7 @@ enum StealthIndex : uint8_t { #endif #define _EN_ITEM(N) , E##N - enum TMCAxis : uint8_t { LINEAR_AXIS_LIST(X, Y, Z, I, J, K), X2, Y2, Z2, Z3, Z4 REPEAT(EXTRUDERS, _EN_ITEM), TOTAL }; + enum TMCAxis : uint8_t { NUM_AXIS_LIST(X, Y, Z, I, J, K, U, V, W), X2, Y2, Z2, Z3, Z4 REPEAT(EXTRUDERS, _EN_ITEM), TOTAL }; #undef _EN_ITEM void tmc_serial_begin() { @@ -543,6 +587,27 @@ enum StealthIndex : uint8_t { stepperK.beginSerial(TMC_BAUD_RATE); #endif #endif + #if AXIS_HAS_UART(U) + #ifdef U_HARDWARE_SERIAL + HW_SERIAL_BEGIN(U); + #else + stepperU.beginSerial(TMC_BAUD_RATE); + #endif + #endif + #if AXIS_HAS_UART(V) + #ifdef V_HARDWARE_SERIAL + HW_SERIAL_BEGIN(V); + #else + stepperV.beginSerial(TMC_BAUD_RATE); + #endif + #endif + #if AXIS_HAS_UART(W) + #ifdef W_HARDWARE_SERIAL + HW_SERIAL_BEGIN(W); + #else + stepperW.beginSerial(TMC_BAUD_RATE); + #endif + #endif #if AXIS_HAS_UART(E0) #ifdef E0_HARDWARE_SERIAL HW_SERIAL_BEGIN(E0); @@ -814,6 +879,15 @@ void restore_trinamic_drivers() { #if AXIS_IS_TMC(K) stepperK.push(); #endif + #if AXIS_IS_TMC(U) + stepperU.push(); + #endif + #if AXIS_IS_TMC(V) + stepperV.push(); + #endif + #if AXIS_IS_TMC(W) + stepperW.push(); + #endif #if AXIS_IS_TMC(E0) stepperE0.push(); #endif @@ -844,7 +918,8 @@ void reset_trinamic_drivers() { static constexpr bool stealthchop_by_axis[] = LOGICAL_AXIS_ARRAY( ENABLED(STEALTHCHOP_E), ENABLED(STEALTHCHOP_XY), ENABLED(STEALTHCHOP_XY), ENABLED(STEALTHCHOP_Z), - ENABLED(STEALTHCHOP_I), ENABLED(STEALTHCHOP_J), ENABLED(STEALTHCHOP_K) + ENABLED(STEALTHCHOP_I), ENABLED(STEALTHCHOP_J), ENABLED(STEALTHCHOP_K), + ENABLED(STEALTHCHOP_U), ENABLED(STEALTHCHOP_V), ENABLED(STEALTHCHOP_W) ); #if AXIS_IS_TMC(X) @@ -880,6 +955,15 @@ void reset_trinamic_drivers() { #if AXIS_IS_TMC(K) TMC_INIT(K, STEALTH_AXIS_K); #endif + #if AXIS_IS_TMC(U) + TMC_INIT(U, STEALTH_AXIS_U); + #endif + #if AXIS_IS_TMC(V) + TMC_INIT(V, STEALTH_AXIS_V); + #endif + #if AXIS_IS_TMC(W) + TMC_INIT(W, STEALTH_AXIS_W); + #endif #if AXIS_IS_TMC(E0) TMC_INIT(E0, STEALTH_AXIS_E); #endif @@ -906,49 +990,21 @@ void reset_trinamic_drivers() { #endif #if USE_SENSORLESS - #if X_SENSORLESS - stepperX.homing_threshold(X_STALL_SENSITIVITY); - #if AXIS_HAS_STALLGUARD(X2) - stepperX2.homing_threshold(CAT(TERN(X2_SENSORLESS, X2, X), _STALL_SENSITIVITY)); - #endif - #endif - #if Y_SENSORLESS - stepperY.homing_threshold(Y_STALL_SENSITIVITY); - #if AXIS_HAS_STALLGUARD(Y2) - stepperY2.homing_threshold(CAT(TERN(Y2_SENSORLESS, Y2, Y), _STALL_SENSITIVITY)); - #endif - #endif - #if Z_SENSORLESS - stepperZ.homing_threshold(Z_STALL_SENSITIVITY); - #if AXIS_HAS_STALLGUARD(Z2) - stepperZ2.homing_threshold(CAT(TERN(Z2_SENSORLESS, Z2, Z), _STALL_SENSITIVITY)); - #endif - #if AXIS_HAS_STALLGUARD(Z3) - stepperZ3.homing_threshold(CAT(TERN(Z3_SENSORLESS, Z3, Z), _STALL_SENSITIVITY)); - #endif - #if AXIS_HAS_STALLGUARD(Z4) - stepperZ4.homing_threshold(CAT(TERN(Z4_SENSORLESS, Z4, Z), _STALL_SENSITIVITY)); - #endif - #endif - #if I_SENSORLESS - stepperI.homing_threshold(I_STALL_SENSITIVITY); - #if AXIS_HAS_STALLGUARD(I) - stepperI.homing_threshold(CAT(TERN(I_SENSORLESS, I, I), _STALL_SENSITIVITY)); - #endif - #endif - #if J_SENSORLESS - stepperJ.homing_threshold(J_STALL_SENSITIVITY); - #if AXIS_HAS_STALLGUARD(J) - stepperJ.homing_threshold(CAT(TERN(J_SENSORLESS, J, J), _STALL_SENSITIVITY)); - #endif - #endif - #if K_SENSORLESS - stepperK.homing_threshold(K_STALL_SENSITIVITY); - #if AXIS_HAS_STALLGUARD(K) - stepperK.homing_threshold(CAT(TERN(K_SENSORLESS, K, K), _STALL_SENSITIVITY)); - #endif - #endif - #endif // USE SENSORLESS + TERN_(X_SENSORLESS, stepperX.homing_threshold(X_STALL_SENSITIVITY)); + TERN_(X2_SENSORLESS, stepperX2.homing_threshold(CAT(TERN(X2_SENSORLESS, X2, X), _STALL_SENSITIVITY))); + TERN_(Y_SENSORLESS, stepperY.homing_threshold(Y_STALL_SENSITIVITY)); + TERN_(Y2_SENSORLESS, stepperY2.homing_threshold(CAT(TERN(Y2_SENSORLESS, Y2, Y), _STALL_SENSITIVITY))); + TERN_(Z_SENSORLESS, stepperZ.homing_threshold(Z_STALL_SENSITIVITY)); + TERN_(Z2_SENSORLESS, stepperZ2.homing_threshold(CAT(TERN(Z2_SENSORLESS, Z2, Z), _STALL_SENSITIVITY))); + TERN_(Z3_SENSORLESS, stepperZ3.homing_threshold(CAT(TERN(Z3_SENSORLESS, Z3, Z), _STALL_SENSITIVITY))); + TERN_(Z4_SENSORLESS, stepperZ4.homing_threshold(CAT(TERN(Z4_SENSORLESS, Z4, Z), _STALL_SENSITIVITY))); + TERN_(I_SENSORLESS, stepperI.homing_threshold(I_STALL_SENSITIVITY)); + TERN_(J_SENSORLESS, stepperJ.homing_threshold(J_STALL_SENSITIVITY)); + TERN_(K_SENSORLESS, stepperK.homing_threshold(K_STALL_SENSITIVITY)); + TERN_(U_SENSORLESS, stepperU.homing_threshold(U_STALL_SENSITIVITY)); + TERN_(V_SENSORLESS, stepperV.homing_threshold(V_STALL_SENSITIVITY)); + TERN_(W_SENSORLESS, stepperW.homing_threshold(W_STALL_SENSITIVITY)); + #endif #ifdef TMC_ADV TMC_ADV() @@ -977,7 +1033,7 @@ void reset_trinamic_drivers() { TMC_HW_DETAIL(X), TMC_HW_DETAIL(X2), TMC_HW_DETAIL(Y), TMC_HW_DETAIL(Y2), TMC_HW_DETAIL(Z), TMC_HW_DETAIL(Z2), TMC_HW_DETAIL(Z3), TMC_HW_DETAIL(Z4), - TMC_HW_DETAIL(I), TMC_HW_DETAIL(J), TMC_HW_DETAIL(K), + TMC_HW_DETAIL(I), TMC_HW_DETAIL(J), TMC_HW_DETAIL(K), TMC_HW_DETAIL(U), TMC_HW_DETAIL(V), TMC_HW_DETAIL(W), TMC_HW_DETAIL(E0), TMC_HW_DETAIL(E1), TMC_HW_DETAIL(E2), TMC_HW_DETAIL(E3), TMC_HW_DETAIL(E4), TMC_HW_DETAIL(E5), TMC_HW_DETAIL(E6), TMC_HW_DETAIL(E7) }; @@ -1000,7 +1056,7 @@ void reset_trinamic_drivers() { SA_NO_TMC_HW_C(X); SA_NO_TMC_HW_C(X2); SA_NO_TMC_HW_C(Y); SA_NO_TMC_HW_C(Y2); SA_NO_TMC_HW_C(Z); SA_NO_TMC_HW_C(Z2); SA_NO_TMC_HW_C(Z3); SA_NO_TMC_HW_C(Z4); - SA_NO_TMC_HW_C(I); SA_NO_TMC_HW_C(J); SA_NO_TMC_HW_C(K); + SA_NO_TMC_HW_C(I); SA_NO_TMC_HW_C(J); SA_NO_TMC_HW_C(K); SA_NO_TMC_HW_C(U); SA_NO_TMC_HW_C(V); SA_NO_TMC_HW_C(W); SA_NO_TMC_HW_C(E0); SA_NO_TMC_HW_C(E1); SA_NO_TMC_HW_C(E2); SA_NO_TMC_HW_C(E3); SA_NO_TMC_HW_C(E4); SA_NO_TMC_HW_C(E5); SA_NO_TMC_HW_C(E6); SA_NO_TMC_HW_C(E7); #endif @@ -1012,7 +1068,7 @@ void reset_trinamic_drivers() { TMC_SW_DETAIL(X), TMC_SW_DETAIL(X2), TMC_SW_DETAIL(Y), TMC_SW_DETAIL(Y2), TMC_SW_DETAIL(Z), TMC_SW_DETAIL(Z2), TMC_SW_DETAIL(Z3), TMC_SW_DETAIL(Z4), - TMC_SW_DETAIL(I), TMC_SW_DETAIL(J), TMC_SW_DETAIL(K), + TMC_SW_DETAIL(I), TMC_SW_DETAIL(J), TMC_SW_DETAIL(K), TMC_SW_DETAIL(U), TMC_SW_DETAIL(V), TMC_SW_DETAIL(W), TMC_SW_DETAIL(E0), TMC_SW_DETAIL(E1), TMC_SW_DETAIL(E2), TMC_SW_DETAIL(E3), TMC_SW_DETAIL(E4), TMC_SW_DETAIL(E5), TMC_SW_DETAIL(E6), TMC_SW_DETAIL(E7) }; @@ -1030,7 +1086,7 @@ void reset_trinamic_drivers() { SA_NO_TMC_SW_C(X); SA_NO_TMC_SW_C(X2); SA_NO_TMC_SW_C(Y); SA_NO_TMC_SW_C(Y2); SA_NO_TMC_SW_C(Z); SA_NO_TMC_SW_C(Z2); SA_NO_TMC_SW_C(Z3); SA_NO_TMC_SW_C(Z4); - SA_NO_TMC_SW_C(I); SA_NO_TMC_SW_C(J); SA_NO_TMC_SW_C(K); + SA_NO_TMC_SW_C(I); SA_NO_TMC_SW_C(J); SA_NO_TMC_SW_C(K); SA_NO_TMC_SW_C(U); SA_NO_TMC_SW_C(V); SA_NO_TMC_SW_C(W); SA_NO_TMC_SW_C(E0); SA_NO_TMC_SW_C(E1); SA_NO_TMC_SW_C(E2); SA_NO_TMC_SW_C(E3); SA_NO_TMC_SW_C(E4); SA_NO_TMC_SW_C(E5); SA_NO_TMC_SW_C(E6); SA_NO_TMC_SW_C(E7); #endif diff --git a/Marlin/src/module/stepper/trinamic.h b/Marlin/src/module/stepper/trinamic.h index dd3a64240f..95bab7652c 100644 --- a/Marlin/src/module/stepper/trinamic.h +++ b/Marlin/src/module/stepper/trinamic.h @@ -49,6 +49,9 @@ #define TMC_I_LABEL 'I', '0' #define TMC_J_LABEL 'J', '0' #define TMC_K_LABEL 'K', '0' +#define TMC_U_LABEL 'U', '0' +#define TMC_V_LABEL 'V', '0' +#define TMC_W_LABEL 'W', '0' #define TMC_X2_LABEL 'X', '2' #define TMC_Y2_LABEL 'Y', '2' @@ -92,6 +95,15 @@ #if HAS_K_AXIS && !defined(CHOPPER_TIMING_K) #define CHOPPER_TIMING_K CHOPPER_TIMING #endif +#if HAS_U_AXIS && !defined(CHOPPER_TIMING_U) + #define CHOPPER_TIMING_U CHOPPER_TIMING +#endif +#if HAS_V_AXIS && !defined(CHOPPER_TIMING_V) + #define CHOPPER_TIMING_V CHOPPER_TIMING +#endif +#if HAS_W_AXIS && !defined(CHOPPER_TIMING_W) + #define CHOPPER_TIMING_W CHOPPER_TIMING +#endif #if HAS_EXTRUDERS && !defined(CHOPPER_TIMING_E) #define CHOPPER_TIMING_E CHOPPER_TIMING #endif @@ -274,6 +286,48 @@ void reset_trinamic_drivers(); #endif #endif +// U Stepper +#if AXIS_IS_TMC(U) + extern TMC_CLASS(U, U) stepperU; + static constexpr chopper_timing_t chopper_timing_U = CHOPPER_TIMING_U; + #if ENABLED(SOFTWARE_DRIVER_ENABLE) + #define U_ENABLE_INIT() NOOP + #define U_ENABLE_WRITE(STATE) stepperU.toff((STATE)==U_ENABLE_ON ? chopper_timing_U.toff : 0) + #define U_ENABLE_READ() stepperU.isEnabled() + #endif + #if AXIS_HAS_SQUARE_WAVE(U) + #define U_STEP_WRITE(STATE) do{ if(STATE) TOGGLE(U_STEP_PIN); }while(0) + #endif +#endif + +// V Stepper +#if AXIS_IS_TMC(V) + extern TMC_CLASS(V, V) stepperV; + static constexpr chopper_timing_t chopper_timing_V = CHOPPER_TIMING_V; + #if ENABLED(SOFTWARE_DRIVER_ENABLE) + #define V_ENABLE_INIT() NOOP + #define V_ENABLE_WRITE(STATE) stepperV.toff((STATE)==V_ENABLE_ON ? chopper_timing_V.toff : 0) + #define V_ENABLE_READ() stepperV.isEnabled() + #endif + #if AXIS_HAS_SQUARE_WAVE(V) + #define V_STEP_WRITE(STATE) do{ if(STATE) TOGGLE(V_STEP_PIN); }while(0) + #endif +#endif + +// W Stepper +#if AXIS_IS_TMC(W) + extern TMC_CLASS(W, W) stepperW; + static constexpr chopper_timing_t chopper_timing_W = CHOPPER_TIMING_W; + #if ENABLED(SOFTWARE_DRIVER_ENABLE) + #define W_ENABLE_INIT() NOOP + #define W_ENABLE_WRITE(STATE) stepperW.toff((STATE)==W_ENABLE_ON ? chopper_timing_W.toff : 0) + #define W_ENABLE_READ() stepperW.isEnabled() + #endif + #if AXIS_HAS_SQUARE_WAVE(W) + #define W_STEP_WRITE(STATE) do{ if(STATE) TOGGLE(W_STEP_PIN); }while(0) + #endif +#endif + // E0 Stepper #if AXIS_IS_TMC(E0) extern TMC_CLASS_E(0) stepperE0; diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp index 653b3179b0..4bd43705ad 100644 --- a/Marlin/src/module/temperature.cpp +++ b/Marlin/src/module/temperature.cpp @@ -141,7 +141,8 @@ #endif #endif -#if ENABLED(PID_EXTRUSION_SCALING) +#if EITHER(MPCTEMP, PID_EXTRUSION_SCALING) + #include #include "stepper.h" #endif @@ -437,8 +438,8 @@ PGMSTR(str_t_heating_failed, STR_T_HEATING_FAILED); #if HAS_HEATED_BED bed_info_t Temperature::temp_bed; // = { 0 } // Init min and max temp with extreme values to prevent false errors during startup - int16_t Temperature::mintemp_raw_BED = TEMP_SENSOR_BED_RAW_LO_TEMP, - Temperature::maxtemp_raw_BED = TEMP_SENSOR_BED_RAW_HI_TEMP; + raw_adc_t Temperature::mintemp_raw_BED = TEMP_SENSOR_BED_RAW_LO_TEMP, + Temperature::maxtemp_raw_BED = TEMP_SENSOR_BED_RAW_HI_TEMP; TERN_(WATCH_BED, bed_watch_t Temperature::watch_bed); // = { 0 } IF_DISABLED(PIDTEMPBED, millis_t Temperature::next_bed_check_ms); #endif @@ -448,8 +449,8 @@ PGMSTR(str_t_heating_failed, STR_T_HEATING_FAILED); #if HAS_HEATED_CHAMBER millis_t next_cool_check_ms_2 = 0; celsius_float_t old_temp = 9999; - int16_t Temperature::mintemp_raw_CHAMBER = TEMP_SENSOR_CHAMBER_RAW_LO_TEMP, - Temperature::maxtemp_raw_CHAMBER = TEMP_SENSOR_CHAMBER_RAW_HI_TEMP; + raw_adc_t Temperature::mintemp_raw_CHAMBER = TEMP_SENSOR_CHAMBER_RAW_LO_TEMP, + Temperature::maxtemp_raw_CHAMBER = TEMP_SENSOR_CHAMBER_RAW_HI_TEMP; TERN_(WATCH_CHAMBER, chamber_watch_t Temperature::watch_chamber{0}); IF_DISABLED(PIDTEMPCHAMBER, millis_t Temperature::next_chamber_check_ms); #endif @@ -461,8 +462,8 @@ PGMSTR(str_t_heating_failed, STR_T_HEATING_FAILED); bool flag_cooler_state; //bool flag_cooler_excess = false; celsius_float_t previous_temp = 9999; - int16_t Temperature::mintemp_raw_COOLER = TEMP_SENSOR_COOLER_RAW_LO_TEMP, - Temperature::maxtemp_raw_COOLER = TEMP_SENSOR_COOLER_RAW_HI_TEMP; + raw_adc_t Temperature::mintemp_raw_COOLER = TEMP_SENSOR_COOLER_RAW_LO_TEMP, + Temperature::maxtemp_raw_COOLER = TEMP_SENSOR_COOLER_RAW_HI_TEMP; #if WATCH_COOLER cooler_watch_t Temperature::watch_cooler{0}; #endif @@ -477,8 +478,8 @@ PGMSTR(str_t_heating_failed, STR_T_HEATING_FAILED); #if HAS_TEMP_BOARD board_info_t Temperature::temp_board; // = { 0 } #if ENABLED(THERMAL_PROTECTION_BOARD) - int16_t Temperature::mintemp_raw_BOARD = TEMP_SENSOR_BOARD_RAW_LO_TEMP, - Temperature::maxtemp_raw_BOARD = TEMP_SENSOR_BOARD_RAW_HI_TEMP; + raw_adc_t Temperature::mintemp_raw_BOARD = TEMP_SENSOR_BOARD_RAW_LO_TEMP, + Temperature::maxtemp_raw_BOARD = TEMP_SENSOR_BOARD_RAW_HI_TEMP; #endif #endif @@ -503,11 +504,16 @@ PGMSTR(str_t_heating_failed, STR_T_HEATING_FAILED); volatile bool Temperature::raw_temps_ready = false; #if ENABLED(PID_EXTRUSION_SCALING) - int32_t Temperature::last_e_position, Temperature::lpq[LPQ_MAX_LEN]; + int32_t Temperature::pes_e_position, Temperature::lpq[LPQ_MAX_LEN]; lpq_ptr_t Temperature::lpq_ptr = 0; #endif +#if ENABLED(MPCTEMP) + int32_t Temperature::mpc_e_position; // = 0 +#endif + #define TEMPDIR(N) ((TEMP_SENSOR_##N##_RAW_LO_TEMP) < (TEMP_SENSOR_##N##_RAW_HI_TEMP) ? 1 : -1) +#define TP_CMP(S,A,B) (TEMPDIR(S) < 0 ? ((A)<(B)) : ((A)>(B))) #if HAS_HOTEND // Init mintemp and maxtemp with extreme values to prevent false errors during startup @@ -580,8 +586,8 @@ volatile bool Temperature::raw_temps_ready = false; PID_t tune_pid = { 0, 0, 0 }; celsius_float_t maxT = 0, minT = 10000; - const bool isbed = (heater_id == H_BED); - const bool ischamber = (heater_id == H_CHAMBER); + const bool isbed = (heater_id == H_BED), + ischamber = (heater_id == H_CHAMBER); #if ENABLED(PIDTEMPCHAMBER) #define C_TERN(T,A,B) ((T) ? (A) : (B)) @@ -650,7 +656,7 @@ volatile bool Temperature::raw_temps_ready = false; // PID Tuning loop wait_for_heatup = true; // Can be interrupted with M108 - TERN_(HAS_STATUS_MESSAGE, ui.set_status(F("Wait for heat up..."))); + LCD_MESSAGE(MSG_HEATING); while (wait_for_heatup) { const millis_t ms = millis(); @@ -839,6 +845,198 @@ volatile bool Temperature::raw_temps_ready = false; #endif // HAS_PID_HEATING +#if ENABLED(MPCTEMP) + + void Temperature::MPC_autotune() { + auto housekeeping = [] (millis_t& ms, celsius_float_t& current_temp, millis_t& next_report_ms) { + ms = millis(); + + if (updateTemperaturesIfReady()) { // temp sample ready + current_temp = degHotend(active_extruder); + TERN_(HAS_FAN_LOGIC, manage_extruder_fans(ms)); + } + + if (ELAPSED(ms, next_report_ms)) { + next_report_ms += 1000UL; + SERIAL_ECHOLNPGM("Temperature ", current_temp); + } + + hal.idletask(); + }; + + SERIAL_ECHOLNPGM("Measuring MPC constants for E", active_extruder); + MPCHeaterInfo& hotend = temp_hotend[active_extruder]; + MPC_t& constants = hotend.constants; + + // move to center of bed, just above bed height and cool with max fan + SERIAL_ECHOLNPGM("Moving to tuning position"); + TERN_(HAS_FAN, zero_fan_speeds()); + disable_all_heaters(); + TERN_(HAS_FAN, set_fan_speed(ANY(MPC_FAN_0_ALL_HOTENDS, MPC_FAN_0_ACTIVE_HOTEND) ? 0 : active_extruder, 255)); + TERN_(HAS_FAN, planner.sync_fan_speeds(fan_speed)); + gcode.home_all_axes(true); + const xyz_pos_t tuningpos = MPC_TUNING_POS; + do_blocking_move_to(tuningpos); + + SERIAL_ECHOLNPGM("Cooling to ambient"); + millis_t ms = millis(), next_report_ms = ms, next_test_ms = ms + 10000UL; + celsius_float_t current_temp = degHotend(active_extruder), + ambient_temp = current_temp; + + wait_for_heatup = true; // Can be interrupted with M108 + while (wait_for_heatup) { + housekeeping(ms, current_temp, next_report_ms); + + if (ELAPSED(ms, next_test_ms)) { + if (current_temp >= ambient_temp) { + ambient_temp = (ambient_temp + current_temp) / 2.0f; + break; + } + ambient_temp = current_temp; + next_test_ms += 10000UL; + } + } + TERN_(HAS_FAN, set_fan_speed(ANY(MPC_FAN_0_ALL_HOTENDS, MPC_FAN_0_ACTIVE_HOTEND) ? 0 : active_extruder, 0)); + TERN_(HAS_FAN, planner.sync_fan_speeds(fan_speed)); + + hotend.modeled_ambient_temp = ambient_temp; + + SERIAL_ECHOLNPGM("Heating to 200C"); + hotend.soft_pwm_amount = MPC_MAX >> 1; + const millis_t heat_start_time = ms; + next_test_ms = ms; + celsius_float_t temp_samples[16]; + uint8_t sample_count = 0; + uint16_t sample_distance = 1; + float t1_time = 0; + + while (wait_for_heatup) { + housekeeping(ms, current_temp, next_report_ms); + + if (ELAPSED(ms, next_test_ms)) { + // record samples between 100C and 200C + if (current_temp >= 100.0f) { + // if there are too many samples, space them more widely + if (sample_count == COUNT(temp_samples)) { + for (uint8_t i = 0; i < COUNT(temp_samples) / 2; i++) + temp_samples[i] = temp_samples[i*2]; + sample_count /= 2; + sample_distance *= 2; + } + + if (sample_count == 0) t1_time = float(ms - heat_start_time) / 1000.0f; + temp_samples[sample_count++] = current_temp; + } + + if (current_temp >= 200.0f) break; + + next_test_ms += 1000UL * sample_distance; + } + } + hotend.soft_pwm_amount = 0; + + // calculate physical constants from three equally spaced samples + sample_count = (sample_count + 1) / 2 * 2 - 1; + const float t1 = temp_samples[0], + t2 = temp_samples[(sample_count - 1) >> 1], + t3 = temp_samples[sample_count - 1], + asymp_temp = (t2 * t2 - t1 * t3) / (2 * t2 - t1 - t3), + block_responsiveness = -log((t2 - asymp_temp) / (t1 - asymp_temp)) / (sample_distance * (sample_count >> 1)); + + constants.ambient_xfer_coeff_fan0 = constants.heater_power * MPC_MAX / 255 / (asymp_temp - ambient_temp); + constants.fan255_adjustment = 0.0f; + constants.block_heat_capacity = constants.ambient_xfer_coeff_fan0 / block_responsiveness; + constants.sensor_responsiveness = block_responsiveness / (1.0f - (ambient_temp - asymp_temp) * exp(-block_responsiveness * t1_time) / (t1 - asymp_temp)); + + hotend.modeled_block_temp = asymp_temp + (ambient_temp - asymp_temp) * exp(-block_responsiveness * (ms - heat_start_time) / 1000.0f); + hotend.modeled_sensor_temp = current_temp; + + // let the system stabilise under MPC control then get a better measure of ambient loss without and with fan + SERIAL_ECHOLNPGM("Measuring ambient heatloss at target ", hotend.modeled_block_temp); + hotend.target = hotend.modeled_block_temp; + next_test_ms = ms + MPC_dT * 1000; + constexpr millis_t settle_time = 20000UL, + test_length = 20000UL; + millis_t settle_end_ms = ms + settle_time, + test_end_ms = settle_end_ms + test_length; + float total_energy_fan0 = 0.0f; + #if HAS_FAN + bool fan0_done = false; + float total_energy_fan255 = 0.0f; + #endif + float last_temp = current_temp; + + while (wait_for_heatup) { + housekeeping(ms, current_temp, next_report_ms); + + if (ELAPSED(ms, next_test_ms)) { + // use MPC to control the temperature, let it settle for 30s and then track power output for 10s + hotend.soft_pwm_amount = (int)get_pid_output_hotend(active_extruder) >> 1; + + if (ELAPSED(ms, settle_end_ms) && !ELAPSED(ms, test_end_ms) && TERN1(HAS_FAN, !fan0_done)) + total_energy_fan0 += constants.heater_power * hotend.soft_pwm_amount / 127 * MPC_dT + (last_temp - current_temp) * constants.block_heat_capacity; + #if HAS_FAN + else if (ELAPSED(ms, test_end_ms) && !fan0_done) { + SERIAL_ECHOLNPGM("Measuring ambient heatloss with full fan"); + set_fan_speed(ANY(MPC_FAN_0_ALL_HOTENDS, MPC_FAN_0_ACTIVE_HOTEND) ? 0 : active_extruder, 255); + planner.sync_fan_speeds(fan_speed); + settle_end_ms = ms + settle_time; + test_end_ms = settle_end_ms + test_length; + fan0_done = true; + } + else if (ELAPSED(ms, settle_end_ms) && !ELAPSED(ms, test_end_ms)) + total_energy_fan255 += constants.heater_power * hotend.soft_pwm_amount / 127 * MPC_dT + (last_temp - current_temp) * constants.block_heat_capacity; + #endif + else if (ELAPSED(ms, test_end_ms)) break; + + last_temp = current_temp; + next_test_ms += MPC_dT * 1000; + } + + if (!WITHIN(current_temp, hotend.target - 15.0f, hotend.target + 15.0f)) { + SERIAL_ECHOLNPGM("Temperature error while measuring ambient loss"); + break; + } + } + + const float power_fan0 = total_energy_fan0 * 1000 / test_length; + constants.ambient_xfer_coeff_fan0 = power_fan0 / (hotend.target - ambient_temp); + + #if HAS_FAN + const float power_fan255 = total_energy_fan255 * 1000 / test_length, + ambient_xfer_coeff_fan255 = power_fan255 / (hotend.target - ambient_temp); + constants.fan255_adjustment = ambient_xfer_coeff_fan255 - constants.ambient_xfer_coeff_fan0; + #endif + + hotend.target = 0.0f; + hotend.soft_pwm_amount = 0; + TERN_(HAS_FAN, set_fan_speed(ANY(MPC_FAN_0_ALL_HOTENDS, MPC_FAN_0_ACTIVE_HOTEND) ? 0 : active_extruder, 0)); + TERN_(HAS_FAN, planner.sync_fan_speeds(fan_speed)); + + if (!wait_for_heatup) SERIAL_ECHOLNPGM("Test was interrupted"); + + wait_for_heatup = false; + + SERIAL_ECHOLNPGM("Done"); + + /* <-- add a slash to enable + SERIAL_ECHOLNPGM("t1_time ", t1_time); + SERIAL_ECHOLNPGM("sample_count ", sample_count); + SERIAL_ECHOLNPGM("sample_distance ", sample_distance); + for (uint8_t i = 0; i < sample_count; i++) + SERIAL_ECHOLNPGM("sample ", i, " : ", temp_samples[i]); + SERIAL_ECHOLNPGM("t1 ", t1, " t2 ", t2, " t3 ", t3); + SERIAL_ECHOLNPGM("asymp_temp ", asymp_temp); + SERIAL_ECHOLNPAIR_F("block_responsiveness ", block_responsiveness, 4); + //*/ + SERIAL_ECHOLNPGM("MPC_BLOCK_HEAT_CAPACITY ", constants.block_heat_capacity); + SERIAL_ECHOLNPAIR_F("MPC_SENSOR_RESPONSIVENESS ", constants.sensor_responsiveness, 4); + SERIAL_ECHOLNPAIR_F("MPC_AMBIENT_XFER_COEFF ", constants.ambient_xfer_coeff_fan0, 4); + TERN_(HAS_FAN, SERIAL_ECHOLNPAIR_F("MPC_AMBIENT_XFER_COEFF_FAN255 ", ambient_xfer_coeff_fan255, 4)); + } + +#endif // MPCTEMP + int16_t Temperature::getHeaterPower(const heater_id_t heater_id) { switch (heater_id) { #if HAS_HEATED_BED @@ -1098,7 +1296,7 @@ void Temperature::min_temp_error(const heater_id_t heater_id) { pid_reset[ee] = true; } else if (pid_error > PID_FUNCTIONAL_RANGE) { - pid_output = BANG_MAX; + pid_output = PID_MAX; pid_reset[ee] = true; } else { @@ -1125,9 +1323,9 @@ void Temperature::min_temp_error(const heater_id_t heater_id) { work_pid[ee].Kc = 0; if (this_hotend) { const long e_position = stepper.position(E_AXIS); - if (e_position > last_e_position) { - lpq[lpq_ptr] = e_position - last_e_position; - last_e_position = e_position; + if (e_position > pes_e_position) { + lpq[lpq_ptr] = e_position - pes_e_position; + pes_e_position = e_position; } else lpq[lpq_ptr] = 0; @@ -1170,7 +1368,86 @@ void Temperature::min_temp_error(const heater_id_t heater_id) { } #endif - #else // No PID enabled + #elif ENABLED(MPCTEMP) + MPCHeaterInfo& hotend = temp_hotend[ee]; + MPC_t& constants = hotend.constants; + + // At startup, initialize modeled temperatures + if (isnan(hotend.modeled_block_temp)) { + hotend.modeled_ambient_temp = min(30.0f, hotend.celsius); // cap initial value at reasonable max room temperature of 30C + hotend.modeled_block_temp = hotend.modeled_sensor_temp = hotend.celsius; + } + + #if HOTENDS == 1 + constexpr bool this_hotend = true; + #else + const bool this_hotend = (ee == active_extruder); + #endif + + float ambient_xfer_coeff = constants.ambient_xfer_coeff_fan0; + #if ENABLED(MPC_INCLUDE_FAN) + const uint8_t fan_index = ANY(MPC_FAN_0_ACTIVE_HOTEND, MPC_FAN_0_ALL_HOTENDS) ? 0 : ee; + const float fan_fraction = TERN_(MPC_FAN_0_ACTIVE_HOTEND, !this_hotend ? 0.0f : ) fan_speed[fan_index] * RECIPROCAL(255); + ambient_xfer_coeff += fan_fraction * constants.fan255_adjustment; + #endif + + if (this_hotend) { + const int32_t e_position = stepper.position(E_AXIS); + const float e_speed = (e_position - mpc_e_position) * planner.mm_per_step[E_AXIS] / MPC_dT; + + // the position can appear to make big jumps when, e.g. homing + if (fabs(e_speed) > planner.settings.max_feedrate_mm_s[E_AXIS]) + mpc_e_position = e_position; + else if (e_speed > 0.0f) { // ignore retract/recover moves + ambient_xfer_coeff += e_speed * FILAMENT_HEAT_CAPACITY_PERMM; + mpc_e_position = e_position; + } + } + + // update the modeled temperatures + float blocktempdelta = hotend.soft_pwm_amount * constants.heater_power * (MPC_dT / 127) / constants.block_heat_capacity; + blocktempdelta += (hotend.modeled_ambient_temp - hotend.modeled_block_temp) * ambient_xfer_coeff * MPC_dT / constants.block_heat_capacity; + hotend.modeled_block_temp += blocktempdelta; + + const float sensortempdelta = (hotend.modeled_block_temp - hotend.modeled_sensor_temp) * (constants.sensor_responsiveness * MPC_dT); + hotend.modeled_sensor_temp += sensortempdelta; + + // Any delta between hotend.modeled_sensor_temp and hotend.celsius is either model + // error diverging slowly or (fast) noise. Slowly correct towards this temperature and noise will average out. + const float delta_to_apply = (hotend.celsius - hotend.modeled_sensor_temp) * (MPC_SMOOTHING_FACTOR); + hotend.modeled_block_temp += delta_to_apply; + hotend.modeled_sensor_temp += delta_to_apply; + + // only correct ambient when close to steady state (output power is not clipped or asymptotic temperature is reached) + if (WITHIN(hotend.soft_pwm_amount, 1, 126) || fabs(blocktempdelta + delta_to_apply) < (MPC_STEADYSTATE * MPC_dT)) + hotend.modeled_ambient_temp += delta_to_apply > 0.f ? max(delta_to_apply, MPC_MIN_AMBIENT_CHANGE * MPC_dT) : min(delta_to_apply, -MPC_MIN_AMBIENT_CHANGE * MPC_dT); + + float power = 0.0; + if (hotend.target != 0 && TERN1(HEATER_IDLE_HANDLER, !heater_idle[ee].timed_out)) { + // plan power level to get to target temperature in 2 seconds + power = (hotend.target - hotend.modeled_block_temp) * constants.block_heat_capacity / 2.0f; + power -= (hotend.modeled_ambient_temp - hotend.modeled_block_temp) * ambient_xfer_coeff; + } + + float pid_output = power * 254.0f / constants.heater_power + 1.0f; // ensure correct quantization into a range of 0 to 127 + pid_output = constrain(pid_output, 0, MPC_MAX); + + /* <-- add a slash to enable + static uint32_t nexttime = millis() + 1000; + if (ELAPSED(millis(), nexttime)) { + nexttime += 1000; + SERIAL_ECHOLNPGM("block temp ", hotend.modeled_block_temp, + ", celsius ", hotend.celsius, + ", blocktempdelta ", blocktempdelta, + ", delta_to_apply ", delta_to_apply, + ", ambient ", hotend.modeled_ambient_temp, + ", power ", power, + ", pid_output ", pid_output, + ", pwm ", (int)pid_output >> 1); + } + //*/ + + #else // No PID or MPC enabled const bool is_idling = TERN0(HEATER_IDLE_HANDLER, heater_idle[ee].timed_out); const float pid_output = (!is_idling && temp_hotend[ee].celsius < temp_hotend[ee].target) ? BANG_MAX : 0; @@ -1689,8 +1966,8 @@ void Temperature::manage_heater() { m = (l + r) >> 1; \ if (!m) return celsius_t(pgm_read_word(&TBL[0].celsius)); \ if (m == l || m == r) return celsius_t(pgm_read_word(&TBL[LEN-1].celsius)); \ - int16_t v00 = pgm_read_word(&TBL[m-1].value), \ - v10 = pgm_read_word(&TBL[m-0].value); \ + raw_adc_t v00 = pgm_read_word(&TBL[m-1].value), \ + v10 = pgm_read_word(&TBL[m-0].value); \ if (raw < v00) r = m; \ else if (raw > v10) l = m; \ else { \ @@ -1784,7 +2061,7 @@ void Temperature::manage_heater() { SERIAL_EOL(); } - celsius_float_t Temperature::user_thermistor_to_deg_c(const uint8_t t_index, const int16_t raw) { + celsius_float_t Temperature::user_thermistor_to_deg_c(const uint8_t t_index, const raw_adc_t raw) { if (!WITHIN(t_index, 0, COUNT(user_thermistor) - 1)) return 25; @@ -1799,8 +2076,8 @@ void Temperature::manage_heater() { } // maximum adc value .. take into account the over sampling - const int adc_max = MAX_RAW_THERMISTOR_VALUE, - adc_raw = constrain(raw, 1, adc_max - 1); // constrain to prevent divide-by-zero + constexpr raw_adc_t adc_max = MAX_RAW_THERMISTOR_VALUE; + const raw_adc_t adc_raw = constrain(raw, 1, adc_max - 1); // constrain to prevent divide-by-zero const float adc_inverse = (adc_max - adc_raw) - 0.5f, resistance = t.series_res * (adc_raw + 0.5f) / adc_inverse, @@ -1820,7 +2097,7 @@ void Temperature::manage_heater() { #if HAS_HOTEND // Derived from RepRap FiveD extruder::getTemperature() // For hot end temperature measurement. - celsius_float_t Temperature::analog_to_celsius_hotend(const int16_t raw, const uint8_t e) { + celsius_float_t Temperature::analog_to_celsius_hotend(const raw_adc_t raw, const uint8_t e) { if (e >= HOTENDS) { SERIAL_ERROR_START(); SERIAL_ECHO(e); @@ -1836,11 +2113,11 @@ void Temperature::manage_heater() { #elif TEMP_SENSOR_0_IS_MAX_TC #if TEMP_SENSOR_0_IS_MAX31865 return TERN(LIB_INTERNAL_MAX31865, - max31865_0.temperature((uint16_t)raw), + max31865_0.temperature(raw), max31865_0.temperature(MAX31865_SENSOR_OHMS_0, MAX31865_CALIBRATION_OHMS_0) ); #else - return raw * 0.25; + return (int16_t)raw * 0.25; #endif #elif TEMP_SENSOR_0_IS_AD595 return TEMP_AD595(raw); @@ -1855,11 +2132,11 @@ void Temperature::manage_heater() { #elif TEMP_SENSOR_1_IS_MAX_TC #if TEMP_SENSOR_0_IS_MAX31865 return TERN(LIB_INTERNAL_MAX31865, - max31865_1.temperature((uint16_t)raw), + max31865_1.temperature(raw), max31865_1.temperature(MAX31865_SENSOR_OHMS_1, MAX31865_CALIBRATION_OHMS_1) ); #else - return raw * 0.25; + return (int16_t)raw * 0.25; #endif #elif TEMP_SENSOR_1_IS_AD595 return TEMP_AD595(raw); @@ -1943,7 +2220,7 @@ void Temperature::manage_heater() { #if HAS_HEATED_BED // For bed temperature measurement. - celsius_float_t Temperature::analog_to_celsius_bed(const int16_t raw) { + celsius_float_t Temperature::analog_to_celsius_bed(const raw_adc_t raw) { #if TEMP_SENSOR_BED_IS_CUSTOM return user_thermistor_to_deg_c(CTI_BED, raw); #elif TEMP_SENSOR_BED_IS_THERMISTOR @@ -1961,7 +2238,7 @@ void Temperature::manage_heater() { #if HAS_TEMP_CHAMBER // For chamber temperature measurement. - celsius_float_t Temperature::analog_to_celsius_chamber(const int16_t raw) { + celsius_float_t Temperature::analog_to_celsius_chamber(const raw_adc_t raw) { #if TEMP_SENSOR_CHAMBER_IS_CUSTOM return user_thermistor_to_deg_c(CTI_CHAMBER, raw); #elif TEMP_SENSOR_CHAMBER_IS_THERMISTOR @@ -1979,7 +2256,7 @@ void Temperature::manage_heater() { #if HAS_TEMP_COOLER // For cooler temperature measurement. - celsius_float_t Temperature::analog_to_celsius_cooler(const int16_t raw) { + celsius_float_t Temperature::analog_to_celsius_cooler(const raw_adc_t raw) { #if TEMP_SENSOR_COOLER_IS_CUSTOM return user_thermistor_to_deg_c(CTI_COOLER, raw); #elif TEMP_SENSOR_COOLER_IS_THERMISTOR @@ -1997,7 +2274,7 @@ void Temperature::manage_heater() { #if HAS_TEMP_PROBE // For probe temperature measurement. - celsius_float_t Temperature::analog_to_celsius_probe(const int16_t raw) { + celsius_float_t Temperature::analog_to_celsius_probe(const raw_adc_t raw) { #if TEMP_SENSOR_PROBE_IS_CUSTOM return user_thermistor_to_deg_c(CTI_PROBE, raw); #elif TEMP_SENSOR_PROBE_IS_THERMISTOR @@ -2015,7 +2292,7 @@ void Temperature::manage_heater() { #if HAS_TEMP_BOARD // For motherboard temperature measurement. - celsius_float_t Temperature::analog_to_celsius_board(const int16_t raw) { + celsius_float_t Temperature::analog_to_celsius_board(const raw_adc_t raw) { #if TEMP_SENSOR_BOARD_IS_CUSTOM return user_thermistor_to_deg_c(CTI_BOARD, raw); #elif TEMP_SENSOR_BOARD_IS_THERMISTOR @@ -2033,13 +2310,13 @@ void Temperature::manage_heater() { #if HAS_TEMP_REDUNDANT // For redundant temperature measurement. - celsius_float_t Temperature::analog_to_celsius_redundant(const int16_t raw) { + celsius_float_t Temperature::analog_to_celsius_redundant(const raw_adc_t raw) { #if TEMP_SENSOR_REDUNDANT_IS_CUSTOM return user_thermistor_to_deg_c(CTI_REDUNDANT, raw); #elif TEMP_SENSOR_REDUNDANT_IS_MAX_TC && REDUNDANT_TEMP_MATCH(SOURCE, E0) - return TERN(TEMP_SENSOR_REDUNDANT_IS_MAX31865, max31865_0.temperature((uint16_t)raw), raw * 0.25); + return TERN(TEMP_SENSOR_REDUNDANT_IS_MAX31865, max31865_0.temperature(raw), (int16_t)raw * 0.25); #elif TEMP_SENSOR_REDUNDANT_IS_MAX_TC && REDUNDANT_TEMP_MATCH(SOURCE, E1) - return TERN(TEMP_SENSOR_REDUNDANT_IS_MAX31865, max31865_1.temperature((uint16_t)raw), raw * 0.25); + return TERN(TEMP_SENSOR_REDUNDANT_IS_MAX31865, max31865_1.temperature(raw), (int16_t)raw * 0.25); #elif TEMP_SENSOR_REDUNDANT_IS_THERMISTOR SCAN_THERMISTOR_TABLE(TEMPTABLE_REDUNDANT, TEMPTABLE_REDUNDANT_LEN); #elif TEMP_SENSOR_REDUNDANT_IS_AD595 @@ -2069,20 +2346,20 @@ void Temperature::updateTemperaturesFromRawValues() { watchdog_refresh(); // Reset because raw_temps_ready was set by the interrupt - TERN_(TEMP_SENSOR_0_IS_MAX_TC, temp_hotend[0].raw = READ_MAX_TC(0)); - TERN_(TEMP_SENSOR_1_IS_MAX_TC, temp_hotend[1].raw = READ_MAX_TC(1)); - TERN_(TEMP_SENSOR_REDUNDANT_IS_MAX_TC, temp_redundant.raw = READ_MAX_TC(HEATER_ID(TEMP_SENSOR_REDUNDANT_SOURCE))); + TERN_(TEMP_SENSOR_0_IS_MAX_TC, temp_hotend[0].setraw(READ_MAX_TC(0))); + TERN_(TEMP_SENSOR_1_IS_MAX_TC, temp_hotend[1].setraw(READ_MAX_TC(1))); + TERN_(TEMP_SENSOR_REDUNDANT_IS_MAX_TC, temp_redundant.setraw(READ_MAX_TC(HEATER_ID(TEMP_SENSOR_REDUNDANT_SOURCE)))); #if HAS_HOTEND - HOTEND_LOOP() temp_hotend[e].celsius = analog_to_celsius_hotend(temp_hotend[e].raw, e); + HOTEND_LOOP() temp_hotend[e].celsius = analog_to_celsius_hotend(temp_hotend[e].getraw(), e); #endif - TERN_(HAS_HEATED_BED, temp_bed.celsius = analog_to_celsius_bed(temp_bed.raw)); - TERN_(HAS_TEMP_CHAMBER, temp_chamber.celsius = analog_to_celsius_chamber(temp_chamber.raw)); - TERN_(HAS_TEMP_COOLER, temp_cooler.celsius = analog_to_celsius_cooler(temp_cooler.raw)); - TERN_(HAS_TEMP_PROBE, temp_probe.celsius = analog_to_celsius_probe(temp_probe.raw)); - TERN_(HAS_TEMP_BOARD, temp_board.celsius = analog_to_celsius_board(temp_board.raw)); - TERN_(HAS_TEMP_REDUNDANT, temp_redundant.celsius = analog_to_celsius_redundant(temp_redundant.raw)); + TERN_(HAS_HEATED_BED, temp_bed.celsius = analog_to_celsius_bed(temp_bed.getraw())); + TERN_(HAS_TEMP_CHAMBER, temp_chamber.celsius = analog_to_celsius_chamber(temp_chamber.getraw())); + TERN_(HAS_TEMP_COOLER, temp_cooler.celsius = analog_to_celsius_cooler(temp_cooler.getraw())); + TERN_(HAS_TEMP_PROBE, temp_probe.celsius = analog_to_celsius_probe(temp_probe.getraw())); + TERN_(HAS_TEMP_BOARD, temp_board.celsius = analog_to_celsius_board(temp_board.getraw())); + TERN_(HAS_TEMP_REDUNDANT, temp_redundant.celsius = analog_to_celsius_redundant(temp_redundant.getraw())); TERN_(FILAMENT_WIDTH_SENSOR, filwidth.update_measured_mm()); TERN_(HAS_POWER_MONITOR, power_monitor.capture_values()); @@ -2108,46 +2385,45 @@ void Temperature::updateTemperaturesFromRawValues() { }; LOOP_L_N(e, COUNT(temp_dir)) { - const int8_t tdir = temp_dir[e]; - if (tdir) { - const int16_t rawtemp = temp_hotend[e].raw * tdir; // normal direction, +rawtemp, else -rawtemp - if (rawtemp > temp_range[e].raw_max * tdir) max_temp_error((heater_id_t)e); + const raw_adc_t r = temp_hotend[e].getraw(); + const bool neg = temp_dir[e] < 0, pos = temp_dir[e] > 0; + if ((neg && r < temp_range[e].raw_max) || (pos && r > temp_range[e].raw_max)) + max_temp_error((heater_id_t)e); - const bool heater_on = temp_hotend[e].target > 0; - if (heater_on && rawtemp < temp_range[e].raw_min * tdir && !is_preheating(e)) { - #if MAX_CONSECUTIVE_LOW_TEMPERATURE_ERROR_ALLOWED > 1 - if (++consecutive_low_temperature_error[e] >= MAX_CONSECUTIVE_LOW_TEMPERATURE_ERROR_ALLOWED) - #endif - min_temp_error((heater_id_t)e); - } + const bool heater_on = temp_hotend[e].target > 0; + if (heater_on && ((neg && r > temp_range[e].raw_min) || (pos && r < temp_range[e].raw_min))) { #if MAX_CONSECUTIVE_LOW_TEMPERATURE_ERROR_ALLOWED > 1 - else - consecutive_low_temperature_error[e] = 0; + if (++consecutive_low_temperature_error[e] >= MAX_CONSECUTIVE_LOW_TEMPERATURE_ERROR_ALLOWED) #endif + min_temp_error((heater_id_t)e); } + #if MAX_CONSECUTIVE_LOW_TEMPERATURE_ERROR_ALLOWED > 1 + else + consecutive_low_temperature_error[e] = 0; + #endif } #endif // HAS_HOTEND #define TP_CMP(S,A,B) (TEMPDIR(S) < 0 ? ((A)<(B)) : ((A)>(B))) #if ENABLED(THERMAL_PROTECTION_BED) - if (TP_CMP(BED, temp_bed.raw, maxtemp_raw_BED)) max_temp_error(H_BED); - if (temp_bed.target > 0 && TP_CMP(BED, mintemp_raw_BED, temp_bed.raw)) min_temp_error(H_BED); + if (TP_CMP(BED, temp_bed.getraw(), maxtemp_raw_BED)) max_temp_error(H_BED); + if (temp_bed.target > 0 && TP_CMP(BED, mintemp_raw_BED, temp_bed.getraw())) min_temp_error(H_BED); #endif #if BOTH(HAS_HEATED_CHAMBER, THERMAL_PROTECTION_CHAMBER) - if (TP_CMP(CHAMBER, temp_chamber.raw, maxtemp_raw_CHAMBER)) max_temp_error(H_CHAMBER); - if (temp_chamber.target > 0 && TP_CMP(CHAMBER, mintemp_raw_CHAMBER, temp_chamber.raw)) min_temp_error(H_CHAMBER); + if (TP_CMP(CHAMBER, temp_chamber.getraw(), maxtemp_raw_CHAMBER)) max_temp_error(H_CHAMBER); + if (temp_chamber.target > 0 && TP_CMP(CHAMBER, mintemp_raw_CHAMBER, temp_chamber.getraw())) min_temp_error(H_CHAMBER); #endif #if BOTH(HAS_COOLER, THERMAL_PROTECTION_COOLER) - if (cutter.unitPower > 0 && TP_CMP(COOLER, temp_cooler.raw, maxtemp_raw_COOLER)) max_temp_error(H_COOLER); - if (TP_CMP(COOLER, mintemp_raw_COOLER, temp_cooler.raw)) min_temp_error(H_COOLER); + if (cutter.unitPower > 0 && TP_CMP(COOLER, temp_cooler.getraw(), maxtemp_raw_COOLER)) max_temp_error(H_COOLER); + if (TP_CMP(COOLER, mintemp_raw_COOLER, temp_cooler.getraw())) min_temp_error(H_COOLER); #endif #if BOTH(HAS_TEMP_BOARD, THERMAL_PROTECTION_BOARD) - if (TP_CMP(BOARD, temp_board.raw, maxtemp_raw_BOARD)) max_temp_error(H_BOARD); - if (TP_CMP(BOARD, mintemp_raw_BOARD, temp_board.raw)) min_temp_error(H_BOARD); + if (TP_CMP(BOARD, temp_board.getraw(), maxtemp_raw_BOARD)) max_temp_error(H_BOARD); + if (TP_CMP(BOARD, mintemp_raw_BOARD, temp_board.getraw())) min_temp_error(H_BOARD); #endif #undef TP_CMP @@ -2176,7 +2452,7 @@ void Temperature::init() { TERN_(PROBING_HEATERS_OFF, paused_for_probing = false); #if BOTH(PIDTEMP, PID_EXTRUSION_SCALING) - last_e_position = 0; + pes_e_position = 0; #endif // Init (and disable) SPI thermocouples @@ -2246,6 +2522,10 @@ void Temperature::init() { )); #endif + #if ENABLED(MPCTEMP) + HOTEND_LOOP() temp_hotend[e].modeled_block_temp = NAN; + #endif + #if HAS_HEATER_0 #ifdef BOARD_OPENDRAIN_MOSFETS OUT_WRITE_OD(HEATER_0_PIN, HEATER_0_INVERTING); @@ -2731,7 +3011,7 @@ void Temperature::disable_all_heaters() { * @param hindex the hotend we're referencing (if MULTI_MAX_TC) * @return integer representing the board's buffer, to be converted later if needed */ - int16_t Temperature::read_max_tc(TERN_(HAS_MULTI_MAX_TC, const uint8_t hindex/*=0*/)) { + raw_adc_t Temperature::read_max_tc(TERN_(HAS_MULTI_MAX_TC, const uint8_t hindex/*=0*/)) { #define MAXTC_HEAT_INTERVAL 250UL #if HAS_MAX31855 @@ -2750,7 +3030,7 @@ void Temperature::disable_all_heaters() { #if HAS_MULTI_MAX_TC // Needed to return the correct temp when this is called between readings - static int16_t max_tc_temp_previous[MAX_TC_COUNT] = { 0 }; + static raw_adc_t max_tc_temp_previous[MAX_TC_COUNT] = { 0 }; #define THERMO_TEMP(I) max_tc_temp_previous[I] #define THERMO_SEL(A,B) (hindex ? (B) : (A)) #define MAXTC_CS_WRITE(V) do{ switch (hindex) { case 1: WRITE(TEMP_1_CS_PIN, V); break; default: WRITE(TEMP_0_CS_PIN, V); } }while(0) @@ -2779,7 +3059,7 @@ void Temperature::disable_all_heaters() { // Return last-read value between readings millis_t ms = millis(); if (PENDING(ms, next_max_tc_ms[hindex])) - return (int16_t)THERMO_TEMP(hindex); + return THERMO_TEMP(hindex); next_max_tc_ms[hindex] = ms + MAXTC_HEAT_INTERVAL; @@ -2876,7 +3156,7 @@ void Temperature::disable_all_heaters() { THERMO_TEMP(hindex) = max_tc_temp; - return (int16_t)max_tc_temp; + return max_tc_temp; } #endif // HAS_MAX_TC @@ -3017,7 +3297,7 @@ void Temperature::isr() { uint8_t pwm_count_tmp = pwm_count; #if HAS_ADC_BUTTONS - static unsigned int raw_ADCKey_value = 0; + static raw_adc_t raw_ADCKey_value = 0; static bool ADCKey_pressed = false; #endif @@ -3631,7 +3911,7 @@ void Temperature::isr() { #endif #if HAS_HOTEND && HAS_STATUS_MESSAGE - void Temperature::set_heating_message(const uint8_t e) { + void Temperature::set_heating_message(const uint8_t e, const bool isM104/*=false*/) { const bool heating = isHeatingHotend(e); ui.status_printf(0, #if HAS_MULTI_HOTEND @@ -3641,6 +3921,14 @@ void Temperature::isr() { #endif , heating ? GET_TEXT(MSG_HEATING) : GET_TEXT(MSG_COOLING) ); + + if (isM104) { + static uint8_t wait_e; wait_e = e; + ui.set_status_reset_fn([]{ + const celsius_t c = degTargetHotend(wait_e); + return c < 30 || degHotendNear(wait_e, c); + }); + } } #endif diff --git a/Marlin/src/module/temperature.h b/Marlin/src/module/temperature.h index eb2f4337c0..aa80bd0a23 100644 --- a/Marlin/src/module/temperature.h +++ b/Marlin/src/module/temperature.h @@ -94,6 +94,18 @@ hotend_pid_t; #define _PID_Kf(H) 0 #endif +#if ENABLED(MPCTEMP) + typedef struct { + float heater_power; // M306 P + float block_heat_capacity; // M306 C + float sensor_responsiveness; // M306 R + float ambient_xfer_coeff_fan0; // M306 A + #if ENABLED(MPC_INCLUDE_FAN) + float fan255_adjustment; // M306 F + #endif + } MPC_t; +#endif + /** * States for ADC reading in the ISR */ @@ -177,7 +189,7 @@ enum ADCSensorState : char { #if HAS_PID_HEATING #define PID_K2 (1-float(PID_K1)) - #define PID_dT ((OVERSAMPLENR * float(ACTUAL_ADC_SAMPLES)) / TEMP_TIMER_FREQUENCY) + #define PID_dT ((OVERSAMPLENR * float(ACTUAL_ADC_SAMPLES)) / (TEMP_TIMER_FREQUENCY)) // Apply the scale factors to the PID values #define scalePID_i(i) ( float(i) * PID_dT ) @@ -186,18 +198,26 @@ enum ADCSensorState : char { #define unscalePID_d(d) ( float(d) * PID_dT ) #endif +#if ENABLED(MPCTEMP) + #define MPC_dT ((OVERSAMPLENR * float(ACTUAL_ADC_SAMPLES)) / (TEMP_TIMER_FREQUENCY)) +#endif + #if ENABLED(G26_MESH_VALIDATION) && EITHER(HAS_MARLINUI_MENU, EXTENSIBLE_UI) #define G26_CLICK_CAN_CANCEL 1 #endif // A temperature sensor typedef struct TempInfo { - uint16_t acc; - int16_t raw; +private: + raw_adc_t acc; + raw_adc_t raw; +public: celsius_float_t celsius; inline void reset() { acc = 0; } - inline void sample(const uint16_t s) { acc += s; } + inline void sample(const raw_adc_t s) { acc += s; } inline void update() { raw = acc; } + void setraw(const raw_adc_t r) { raw = r; } + raw_adc_t getraw() { return raw; } } temp_info_t; #if HAS_TEMP_REDUNDANT @@ -219,8 +239,19 @@ struct PIDHeaterInfo : public HeaterInfo { T pid; // Initialized by settings.load() }; +#if ENABLED(MPCTEMP) + struct MPCHeaterInfo : public HeaterInfo { + MPC_t constants; + float modeled_ambient_temp, + modeled_block_temp, + modeled_sensor_temp; + }; +#endif + #if ENABLED(PIDTEMP) typedef struct PIDHeaterInfo hotend_info_t; +#elif ENABLED(MPCTEMP) + typedef struct MPCHeaterInfo hotend_info_t; #else typedef heater_info_t hotend_info_t; #endif @@ -287,9 +318,7 @@ struct HeaterWatch { #endif // Temperature sensor read value ranges -typedef struct { int16_t raw_min, raw_max; } raw_range_t; -typedef struct { celsius_t mintemp, maxtemp; } celsius_range_t; -typedef struct { int16_t raw_min, raw_max; celsius_t mintemp, maxtemp; } temp_range_t; +typedef struct { raw_adc_t raw_min, raw_max; celsius_t mintemp, maxtemp; } temp_range_t; #define THERMISTOR_ABS_ZERO_C -273.15f // bbbbrrrrr cold ! #define THERMISTOR_RESISTANCE_NOMINAL_C 25.0f // mmmmm comfortable @@ -479,10 +508,14 @@ class Temperature { #endif #if ENABLED(PID_EXTRUSION_SCALING) - static int32_t last_e_position, lpq[LPQ_MAX_LEN]; + static int32_t pes_e_position, lpq[LPQ_MAX_LEN]; static lpq_ptr_t lpq_ptr; #endif + #if ENABLED(MPCTEMP) + static int32_t mpc_e_position; + #endif + #if HAS_HOTEND static temp_range_t temp_range[HOTENDS]; #endif @@ -492,7 +525,7 @@ class Temperature { static bed_watch_t watch_bed; #endif IF_DISABLED(PIDTEMPBED, static millis_t next_bed_check_ms); - static int16_t mintemp_raw_BED, maxtemp_raw_BED; + static raw_adc_t mintemp_raw_BED, maxtemp_raw_BED; #endif #if HAS_HEATED_CHAMBER @@ -500,7 +533,7 @@ class Temperature { static chamber_watch_t watch_chamber; #endif TERN(PIDTEMPCHAMBER,,static millis_t next_chamber_check_ms); - static int16_t mintemp_raw_CHAMBER, maxtemp_raw_CHAMBER; + static raw_adc_t mintemp_raw_CHAMBER, maxtemp_raw_CHAMBER; #endif #if HAS_COOLER @@ -508,11 +541,11 @@ class Temperature { static cooler_watch_t watch_cooler; #endif static millis_t next_cooler_check_ms, cooler_fan_flush_ms; - static int16_t mintemp_raw_COOLER, maxtemp_raw_COOLER; + static raw_adc_t mintemp_raw_COOLER, maxtemp_raw_COOLER; #endif #if HAS_TEMP_BOARD && ENABLED(THERMAL_PROTECTION_BOARD) - static int16_t mintemp_raw_BOARD, maxtemp_raw_BOARD; + static raw_adc_t mintemp_raw_BOARD, maxtemp_raw_BOARD; #endif #if MAX_CONSECUTIVE_LOW_TEMPERATURE_ERROR_ALLOWED > 1 @@ -566,7 +599,7 @@ class Temperature { static user_thermistor_t user_thermistor[USER_THERMISTORS]; static void M305_report(const uint8_t t_index, const bool forReplay=true); static void reset_user_thermistors(); - static celsius_float_t user_thermistor_to_deg_c(const uint8_t t_index, const int16_t raw); + static celsius_float_t user_thermistor_to_deg_c(const uint8_t t_index, const raw_adc_t raw); static bool set_pull_up_res(int8_t t_index, float value) { //if (!WITHIN(t_index, 0, USER_THERMISTORS - 1)) return false; if (!WITHIN(value, 1, 1000000)) return false; @@ -594,25 +627,25 @@ class Temperature { #endif #if HAS_HOTEND - static celsius_float_t analog_to_celsius_hotend(const int16_t raw, const uint8_t e); + static celsius_float_t analog_to_celsius_hotend(const raw_adc_t raw, const uint8_t e); #endif #if HAS_HEATED_BED - static celsius_float_t analog_to_celsius_bed(const int16_t raw); + static celsius_float_t analog_to_celsius_bed(const raw_adc_t raw); #endif #if HAS_TEMP_CHAMBER - static celsius_float_t analog_to_celsius_chamber(const int16_t raw); + static celsius_float_t analog_to_celsius_chamber(const raw_adc_t raw); #endif #if HAS_TEMP_PROBE - static celsius_float_t analog_to_celsius_probe(const int16_t raw); + static celsius_float_t analog_to_celsius_probe(const raw_adc_t raw); #endif #if HAS_TEMP_COOLER - static celsius_float_t analog_to_celsius_cooler(const int16_t raw); + static celsius_float_t analog_to_celsius_cooler(const raw_adc_t raw); #endif #if HAS_TEMP_BOARD - static celsius_float_t analog_to_celsius_board(const int16_t raw); + static celsius_float_t analog_to_celsius_board(const raw_adc_t raw); #endif #if HAS_TEMP_REDUNDANT - static celsius_float_t analog_to_celsius_redundant(const int16_t raw); + static celsius_float_t analog_to_celsius_redundant(const raw_adc_t raw); #endif #if HAS_FAN @@ -707,8 +740,8 @@ class Temperature { } #if ENABLED(SHOW_TEMP_ADC_VALUES) - static int16_t rawHotendTemp(const uint8_t E_NAME) { - return TERN0(HAS_HOTEND, temp_hotend[HOTEND_INDEX].raw); + static raw_adc_t rawHotendTemp(const uint8_t E_NAME) { + return TERN0(HAS_HOTEND, temp_hotend[HOTEND_INDEX].getraw()); } #endif @@ -770,7 +803,7 @@ class Temperature { #if HAS_HEATED_BED #if ENABLED(SHOW_TEMP_ADC_VALUES) - static int16_t rawBedTemp() { return temp_bed.raw; } + static raw_adc_t rawBedTemp() { return temp_bed.getraw(); } #endif static celsius_float_t degBed() { return temp_bed.celsius; } static celsius_t wholeDegBed() { return static_cast(degBed() + 0.5f); } @@ -801,7 +834,7 @@ class Temperature { #if HAS_TEMP_PROBE #if ENABLED(SHOW_TEMP_ADC_VALUES) - static int16_t rawProbeTemp() { return temp_probe.raw; } + static raw_adc_t rawProbeTemp() { return temp_probe.getraw(); } #endif static celsius_float_t degProbe() { return temp_probe.celsius; } static celsius_t wholeDegProbe() { return static_cast(degProbe() + 0.5f); } @@ -812,7 +845,7 @@ class Temperature { #if HAS_TEMP_CHAMBER #if ENABLED(SHOW_TEMP_ADC_VALUES) - static int16_t rawChamberTemp() { return temp_chamber.raw; } + static raw_adc_t rawChamberTemp() { return temp_chamber.getraw(); } #endif static celsius_float_t degChamber() { return temp_chamber.celsius; } static celsius_t wholeDegChamber() { return static_cast(degChamber() + 0.5f); } @@ -835,7 +868,7 @@ class Temperature { #if HAS_TEMP_COOLER #if ENABLED(SHOW_TEMP_ADC_VALUES) - static int16_t rawCoolerTemp() { return temp_cooler.raw; } + static raw_adc_t rawCoolerTemp() { return temp_cooler.getraw(); } #endif static celsius_float_t degCooler() { return temp_cooler.celsius; } static celsius_t wholeDegCooler() { return static_cast(temp_cooler.celsius + 0.5f); } @@ -849,7 +882,7 @@ class Temperature { #if HAS_TEMP_BOARD #if ENABLED(SHOW_TEMP_ADC_VALUES) - static int16_t rawBoardTemp() { return temp_board.raw; } + static raw_adc_t rawBoardTemp() { return temp_board.getraw(); } #endif static celsius_float_t degBoard() { return temp_board.celsius; } static celsius_t wholeDegBoard() { return static_cast(temp_board.celsius + 0.5f); } @@ -857,8 +890,7 @@ class Temperature { #if HAS_TEMP_REDUNDANT #if ENABLED(SHOW_TEMP_ADC_VALUES) - static int16_t rawRedundantTemp() { return temp_redundant.raw; } - static int16_t rawRedundanTargetTemp() { return (*temp_redundant.target).raw; } + static raw_adc_t rawRedundantTemp() { return temp_redundant.getraw(); } #endif static celsius_float_t degRedundant() { return temp_redundant.celsius; } static celsius_float_t degRedundantTarget() { return (*temp_redundant.target).celsius; } @@ -923,12 +955,16 @@ class Temperature { */ #if ENABLED(PIDTEMP) static void updatePID() { - TERN_(PID_EXTRUSION_SCALING, last_e_position = 0); + TERN_(PID_EXTRUSION_SCALING, pes_e_position = 0); } #endif #endif + #if ENABLED(MPCTEMP) + void MPC_autotune(); + #endif + #if ENABLED(PROBING_HEATERS_OFF) static void pause_heaters(const bool p); #endif @@ -960,9 +996,9 @@ class Temperature { #endif #if HAS_HOTEND && HAS_STATUS_MESSAGE - static void set_heating_message(const uint8_t e); + static void set_heating_message(const uint8_t e, const bool isM104=false); #else - static void set_heating_message(const uint8_t) {} + static void set_heating_message(const uint8_t, const bool=false) {} #endif #if HAS_MARLINUI_MENU && HAS_TEMPERATURE @@ -991,7 +1027,7 @@ class Temperature { #else #define READ_MAX_TC(N) read_max_tc() #endif - static int16_t read_max_tc(TERN_(HAS_MULTI_MAX_TC, const uint8_t hindex=0)); + static raw_adc_t read_max_tc(TERN_(HAS_MULTI_MAX_TC, const uint8_t hindex=0)); #endif #if HAS_AUTO_FAN diff --git a/Marlin/src/module/thermistor/thermistors.h b/Marlin/src/module/thermistor/thermistors.h index 9f2ebce49a..a38b7f381f 100644 --- a/Marlin/src/module/thermistor/thermistors.h +++ b/Marlin/src/module/thermistor/thermistors.h @@ -27,22 +27,20 @@ #define THERMISTOR_TABLE_SCALE (HAL_ADC_RANGE / _BV(THERMISTOR_TABLE_ADC_RESOLUTION)) #if ENABLED(HAL_ADC_FILTERED) #define OVERSAMPLENR 1 -#elif HAL_ADC_RESOLUTION > 10 - #define OVERSAMPLENR (20 - HAL_ADC_RESOLUTION) #else #define OVERSAMPLENR 16 #endif -#define MAX_RAW_THERMISTOR_VALUE (HAL_ADC_RANGE * (OVERSAMPLENR) - 1) -// Currently Marlin stores all oversampled ADC values as int16_t, make sure the HAL settings do not overflow 15bit -#if MAX_RAW_THERMISTOR_VALUE > ((1 << 15) - 1) - #error "MAX_RAW_THERMISTOR_VALUE is too large for int16_t. Reduce OVERSAMPLENR or HAL_ADC_RESOLUTION." +// Currently Marlin stores all oversampled ADC values as uint16_t, make sure the HAL settings do not overflow 16 bit +#if (HAL_ADC_RANGE) * (OVERSAMPLENR) > 1 << 16 + #error "MAX_RAW_THERMISTOR_VALUE is too large for uint16_t. Reduce OVERSAMPLENR or HAL_ADC_RESOLUTION." #endif +#define MAX_RAW_THERMISTOR_VALUE (uint16_t(HAL_ADC_RANGE) * (OVERSAMPLENR) - 1) -#define OV_SCALE(N) (N) -#define OV(N) int16_t(OV_SCALE(N) * (OVERSAMPLENR) * (THERMISTOR_TABLE_SCALE)) +#define OV_SCALE(N) float(N) +#define OV(N) raw_adc_t(OV_SCALE(N) * (OVERSAMPLENR) * (THERMISTOR_TABLE_SCALE)) -typedef struct { int16_t value; celsius_t celsius; } temp_entry_t; +typedef struct { raw_adc_t value; celsius_t celsius; } temp_entry_t; // Pt1000 and Pt100 handling // diff --git a/Marlin/src/module/tool_change.cpp b/Marlin/src/module/tool_change.cpp index f2767f2b5b..8a62d00782 100644 --- a/Marlin/src/module/tool_change.cpp +++ b/Marlin/src/module/tool_change.cpp @@ -385,65 +385,59 @@ void fast_line_to_current(const AxisEnum fr_axis) { _line_to_current(fr_axis, 0. #endif // PARKING_EXTRUDER -#if ENABLED(SWITCHING_TOOLHEAD) +#if ENABLED(TOOL_SENSOR) + + bool tool_sensor_disabled; // = false // Return a bitmask of tool sensor states inline uint8_t poll_tool_sensor_pins() { return (0 - #if ENABLED(TOOL_SENSOR) - #if PIN_EXISTS(TOOL_SENSOR1) - | (READ(TOOL_SENSOR1_PIN) << 0) - #endif - #if PIN_EXISTS(TOOL_SENSOR2) - | (READ(TOOL_SENSOR2_PIN) << 1) - #endif - #if PIN_EXISTS(TOOL_SENSOR3) - | (READ(TOOL_SENSOR3_PIN) << 2) - #endif - #if PIN_EXISTS(TOOL_SENSOR4) - | (READ(TOOL_SENSOR4_PIN) << 3) - #endif - #if PIN_EXISTS(TOOL_SENSOR5) - | (READ(TOOL_SENSOR5_PIN) << 4) - #endif - #if PIN_EXISTS(TOOL_SENSOR6) - | (READ(TOOL_SENSOR6_PIN) << 5) - #endif - #if PIN_EXISTS(TOOL_SENSOR7) - | (READ(TOOL_SENSOR7_PIN) << 6) - #endif - #if PIN_EXISTS(TOOL_SENSOR8) - | (READ(TOOL_SENSOR8_PIN) << 7) - #endif + #if PIN_EXISTS(TOOL_SENSOR1) + | (READ(TOOL_SENSOR1_PIN) << 0) + #endif + #if PIN_EXISTS(TOOL_SENSOR2) + | (READ(TOOL_SENSOR2_PIN) << 1) + #endif + #if PIN_EXISTS(TOOL_SENSOR3) + | (READ(TOOL_SENSOR3_PIN) << 2) + #endif + #if PIN_EXISTS(TOOL_SENSOR4) + | (READ(TOOL_SENSOR4_PIN) << 3) + #endif + #if PIN_EXISTS(TOOL_SENSOR5) + | (READ(TOOL_SENSOR5_PIN) << 4) + #endif + #if PIN_EXISTS(TOOL_SENSOR6) + | (READ(TOOL_SENSOR6_PIN) << 5) + #endif + #if PIN_EXISTS(TOOL_SENSOR7) + | (READ(TOOL_SENSOR7_PIN) << 6) + #endif + #if PIN_EXISTS(TOOL_SENSOR8) + | (READ(TOOL_SENSOR8_PIN) << 7) #endif ); } - #if ENABLED(TOOL_SENSOR) - - bool tool_sensor_disabled; // = false - - uint8_t check_tool_sensor_stats(const uint8_t tool_index, const bool kill_on_error/*=false*/, const bool disable/*=false*/) { - static uint8_t sensor_tries; // = 0 - for (;;) { - if (poll_tool_sensor_pins() == _BV(tool_index)) { - sensor_tries = 0; - return tool_index; - } - else if (kill_on_error && (!tool_sensor_disabled || disable)) { - sensor_tries++; - if (sensor_tries > 10) kill(F("Tool Sensor error")); - safe_delay(5); - } - else { - sensor_tries++; - if (sensor_tries > 10) return -1; - safe_delay(5); - } + uint8_t check_tool_sensor_stats(const uint8_t tool_index, const bool kill_on_error/*=false*/, const bool disable/*=false*/) { + static uint8_t sensor_tries; // = 0 + for (;;) { + if (poll_tool_sensor_pins() == _BV(tool_index)) { + sensor_tries = 0; + return tool_index; + } + else if (kill_on_error && (!tool_sensor_disabled || disable)) { + sensor_tries++; + if (sensor_tries > 10) kill(F("Tool Sensor error")); + safe_delay(5); + } + else { + sensor_tries++; + if (sensor_tries > 10) return -1; + safe_delay(5); } } - - #endif + } inline void switching_toolhead_lock(const bool locked) { #ifdef SWITCHING_TOOLHEAD_SERVO_ANGLES @@ -496,9 +490,13 @@ void fast_line_to_current(const AxisEnum fr_axis) { _line_to_current(fr_axis, 0. switching_toolhead_lock(true); } LCD_MESSAGE_F("TC Success"); - #endif + #endif // TOOL_SENSOR } +#endif // TOOL_SENSOR + +#if ENABLED(SWITCHING_TOOLHEAD) + inline void switching_toolhead_tool_change(const uint8_t new_tool, bool no_move/*=false*/) { if (no_move) return; @@ -928,6 +926,16 @@ void fast_line_to_current(const AxisEnum fr_axis) { _line_to_current(fr_axis, 0. if (ok) { IF_DISABLED(TOOLCHANGE_PARK_Y_ONLY, current_position.x = toolchange_settings.change_point.x); IF_DISABLED(TOOLCHANGE_PARK_X_ONLY, current_position.y = toolchange_settings.change_point.y); + #if NONE(TOOLCHANGE_PARK_X_ONLY, TOOLCHANGE_PARK_Y_ONLY) + SECONDARY_AXIS_CODE( + current_position.i = toolchange_settings.change_point.i, + current_position.j = toolchange_settings.change_point.j, + current_position.k = toolchange_settings.change_point.k, + current_position.u = toolchange_settings.change_point.u, + current_position.v = toolchange_settings.change_point.v, + current_position.w = toolchange_settings.change_point.w, + ); + #endif planner.buffer_line(current_position, MMM_TO_MMS(TOOLCHANGE_PARK_XY_FEEDRATE), active_extruder); planner.synchronize(); } @@ -1123,6 +1131,16 @@ void tool_change(const uint8_t new_tool, bool no_move/*=false*/) { if (can_move_away && toolchange_settings.enable_park) { IF_DISABLED(TOOLCHANGE_PARK_Y_ONLY, current_position.x = toolchange_settings.change_point.x); IF_DISABLED(TOOLCHANGE_PARK_X_ONLY, current_position.y = toolchange_settings.change_point.y); + #if NONE(TOOLCHANGE_PARK_X_ONLY, TOOLCHANGE_PARK_Y_ONLY) + SECONDARY_AXIS_CODE( + current_position.i = toolchange_settings.change_point.i, + current_position.j = toolchange_settings.change_point.j, + current_position.k = toolchange_settings.change_point.k, + current_position.u = toolchange_settings.change_point.u, + current_position.v = toolchange_settings.change_point.v, + current_position.w = toolchange_settings.change_point.w, + ); + #endif planner.buffer_line(current_position, MMM_TO_MMS(TOOLCHANGE_PARK_XY_FEEDRATE), old_tool); planner.synchronize(); } @@ -1177,7 +1195,7 @@ void tool_change(const uint8_t new_tool, bool no_move/*=false*/) { sync_plan_position(); #if ENABLED(DELTA) - //LOOP_LINEAR_AXES(i) update_software_endstops(i); // or modify the constrain function + //LOOP_NUM_AXES(i) update_software_endstops(i); // or modify the constrain function const bool safe_to_move = current_position.z < delta_clip_start_height - 1; #else constexpr bool safe_to_move = true; @@ -1292,7 +1310,7 @@ void tool_change(const uint8_t new_tool, bool no_move/*=false*/) { #if ENABLED(EXT_SOLENOID) && DISABLED(PARKING_EXTRUDER) disable_all_solenoids(); - enable_solenoid_on_active_extruder(); + enable_solenoid(active_extruder); #endif #if HAS_PRUSA_MMU1 diff --git a/Marlin/src/module/tool_change.h b/Marlin/src/module/tool_change.h index bbdc0b6862..82ed0d6105 100644 --- a/Marlin/src/module/tool_change.h +++ b/Marlin/src/module/tool_change.h @@ -34,7 +34,7 @@ #endif #if ENABLED(TOOLCHANGE_PARK) bool enable_park; - xy_pos_t change_point; + xyz_pos_t change_point; #endif float z_raise; } toolchange_settings_t; diff --git a/Marlin/src/pins/esp32/pins_MKS_TINYBEE.h b/Marlin/src/pins/esp32/pins_MKS_TINYBEE.h index 122dad2146..68b8ed4ac8 100644 --- a/Marlin/src/pins/esp32/pins_MKS_TINYBEE.h +++ b/Marlin/src/pins/esp32/pins_MKS_TINYBEE.h @@ -113,6 +113,11 @@ //#define E0_AUTO_FAN_PIN 148 // need to update Configuration_adv.h @section extruder //#define E1_AUTO_FAN_PIN 149 // need to update Configuration_adv.h @section extruder +// +// ADC Reference Voltage +// +#define ADC_REFERENCE_VOLTAGE 2.5 // 2.5V reference VDDA + // // MicroSD card // diff --git a/Marlin/src/pins/esp32/pins_MRR_ESPE.h b/Marlin/src/pins/esp32/pins_MRR_ESPE.h index 60c8405dfe..9b9b54e3ae 100644 --- a/Marlin/src/pins/esp32/pins_MRR_ESPE.h +++ b/Marlin/src/pins/esp32/pins_MRR_ESPE.h @@ -55,7 +55,9 @@ #define I2S_WS 26 #define I2S_BCK 25 #define I2S_DATA 27 -#undef LIN_ADVANCE // Currently, I2S stream does not work with linear advance +#if ENABLED(LIN_ADVANCE) + #error "I2S stream is currently incompatible with LIN_ADVANCE." +#endif // // Steppers diff --git a/Marlin/src/pins/mega/pins_MIGHTYBOARD_REVE.h b/Marlin/src/pins/mega/pins_MIGHTYBOARD_REVE.h index f2a95baf01..13ffc94486 100644 --- a/Marlin/src/pins/mega/pins_MIGHTYBOARD_REVE.h +++ b/Marlin/src/pins/mega/pins_MIGHTYBOARD_REVE.h @@ -149,10 +149,10 @@ #define MOSFET_1_PIN 6 // Plug EX1 Pin 1-2 -> PH3 #15 -> Logical 06 #define MOSFET_2_PIN 7 // Plug EX1 Pin 3-4 -> PH4 #16 -> Logical 07 -#define MOSFET_3_PIN 12 // Plug EX2 1-2 -> PB5 #25 -> Logical 12 -#define MOSFET_4_PIN 11 // Plug EX2 3-4 -> PB6 #24 -> Logical 11 +#define MOSFET_3_PIN 11 // Plug EX2 1-2 -> PB6 #24 -> Logical 11 +#define MOSFET_4_PIN 12 // Plug EX2 3-4 -> PB5 #25 -> Logical 12 #define MOSFET_5_PIN 45 // Plug HBD 1-2 -> PL4 #39 -> Logical 45 -#define MOSFET_6_PIN 13 // Plug Extra 1-2 -> PL5 #40 -> Logical 44 (FET not soldered in all boards) +#define MOSFET_6_PIN 44 // Plug Extra 1-2 -> PL5 #40 -> Logical 44 (FET not soldered in all boards) // // Heaters / Fans (24V) diff --git a/Marlin/src/pins/pins.h b/Marlin/src/pins/pins.h index 7f0eac8c88..426ce1e48e 100644 --- a/Marlin/src/pins/pins.h +++ b/Marlin/src/pins/pins.h @@ -601,6 +601,8 @@ #include "stm32f1/pins_ZM3E4_V2_0.h" // STM32F1 env:STM32F103VE_ZM3E4V2_USB env:STM32F103VE_ZM3E4V2_USB_maple #elif MB(ERYONE_ERY32_MINI) #include "stm32f1/pins_ERYONE_ERY32_MINI.h" // STM32F103VET6 env:ERYONE_ERY32_MINI_maple +#elif MB(PANDA_PI_V29) + #include "stm32f1/pins_PANDA_PI_V29.h" // STM32F103RCT6 env:PANDA_PI_V29 // // ARM Cortex-M4F diff --git a/Marlin/src/pins/pinsDebug.h b/Marlin/src/pins/pinsDebug.h index e5db7f7b54..b662f09ba9 100644 --- a/Marlin/src/pins/pinsDebug.h +++ b/Marlin/src/pins/pinsDebug.h @@ -19,6 +19,7 @@ * along with this program. If not, see . * */ +#pragma once #include "../inc/MarlinConfig.h" diff --git a/Marlin/src/pins/pinsDebug_list.h b/Marlin/src/pins/pinsDebug_list.h index 2328a826ef..8969997e9a 100644 --- a/Marlin/src/pins/pinsDebug_list.h +++ b/Marlin/src/pins/pinsDebug_list.h @@ -823,7 +823,7 @@ #if HAS_KILL REPORT_NAME_DIGITAL(__LINE__, KILL_PIN) #endif -#if HAS_FREEZE_PIN +#if PIN_EXISTS(FREEZE) REPORT_NAME_DIGITAL(__LINE__, FREEZE_PIN) #endif #if PIN_EXISTS(LCD_BACKLIGHT) @@ -1547,6 +1547,105 @@ #if PIN_EXISTS(K_STOP) REPORT_NAME_DIGITAL(__LINE__, K_STOP_PIN) #endif +#if PIN_EXISTS(U_ATT) + REPORT_NAME_DIGITAL(__LINE__, U_ATT_PIN) +#endif +#if PIN_EXISTS(U_CS) + REPORT_NAME_DIGITAL(__LINE__, U_CS_PIN) +#endif +#if PIN_EXISTS(U_DIR) + REPORT_NAME_DIGITAL(__LINE__, U_DIR_PIN) +#endif +#if PIN_EXISTS(U_ENABLE) + REPORT_NAME_DIGITAL(__LINE__, U_ENABLE_PIN) +#endif +#if PIN_EXISTS(U_MAX) + REPORT_NAME_DIGITAL(__LINE__, U_MAX_PIN) +#endif +#if PIN_EXISTS(U_MIN) + REPORT_NAME_DIGITAL(__LINE__, U_MIN_PIN) +#endif +#if PIN_EXISTS(U_MS1) + REPORT_NAME_DIGITAL(__LINE__, U_MS1_PIN) +#endif +#if PIN_EXISTS(U_MS2) + REPORT_NAME_DIGITAL(__LINE__, U_MS2_PIN) +#endif +#if PIN_EXISTS(U_MS3) + REPORT_NAME_DIGITAL(__LINE__, U_MS3_PIN) +#endif +#if PIN_EXISTS(U_STEP) + REPORT_NAME_DIGITAL(__LINE__, U_STEP_PIN) +#endif +#if PIN_EXISTS(U_STOP) + REPORT_NAME_DIGITAL(__LINE__, U_STOP_PIN) +#endif +#if PIN_EXISTS(V_ATT) + REPORT_NAME_DIGITAL(__LINE__, V_ATT_PIN) +#endif +#if PIN_EXISTS(V_CS) + REPORT_NAME_DIGITAL(__LINE__, V_CS_PIN) +#endif +#if PIN_EXISTS(V_DIR) + REPORT_NAME_DIGITAL(__LINE__, V_DIR_PIN) +#endif +#if PIN_EXISTS(V_ENABLE) + REPORT_NAME_DIGITAL(__LINE__, V_ENABLE_PIN) +#endif +#if PIN_EXISTS(V_MAX) + REPORT_NAME_DIGITAL(__LINE__, V_MAX_PIN) +#endif +#if PIN_EXISTS(V_MIN) + REPORT_NAME_DIGITAL(__LINE__, V_MIN_PIN) +#endif +#if PIN_EXISTS(V_MS1) + REPORT_NAME_DIGITAL(__LINE__, V_MS1_PIN) +#endif +#if PIN_EXISTS(V_MS2) + REPORT_NAME_DIGITAL(__LINE__, V_MS2_PIN) +#endif +#if PIN_EXISTS(V_MS3) + REPORT_NAME_DIGITAL(__LINE__, V_MS3_PIN) +#endif +#if PIN_EXISTS(V_STEP) + REPORT_NAME_DIGITAL(__LINE__, V_STEP_PIN) +#endif +#if PIN_EXISTS(V_STOP) + REPORT_NAME_DIGITAL(__LINE__, V_STOP_PIN) +#endif +#if PIN_EXISTS(W_ATT) + REPORT_NAME_DIGITAL(__LINE__, W_ATT_PIN) +#endif +#if PIN_EXISTS(W_CS) + REPORT_NAME_DIGITAL(__LINE__, W_CS_PIN) +#endif +#if PIN_EXISTS(W_DIR) + REPORT_NAME_DIGITAL(__LINE__, W_DIR_PIN) +#endif +#if PIN_EXISTS(W_ENABLE) + REPORT_NAME_DIGITAL(__LINE__, W_ENABLE_PIN) +#endif +#if PIN_EXISTS(W_MAX) + REPORT_NAME_DIGITAL(__LINE__, W_MAX_PIN) +#endif +#if PIN_EXISTS(W_MIN) + REPORT_NAME_DIGITAL(__LINE__, W_MIN_PIN) +#endif +#if PIN_EXISTS(W_MS1) + REPORT_NAME_DIGITAL(__LINE__, W_MS1_PIN) +#endif +#if PIN_EXISTS(W_MS2) + REPORT_NAME_DIGITAL(__LINE__, W_MS2_PIN) +#endif +#if PIN_EXISTS(W_MS3) + REPORT_NAME_DIGITAL(__LINE__, W_MS3_PIN) +#endif +#if PIN_EXISTS(W_STEP) + REPORT_NAME_DIGITAL(__LINE__, W_STEP_PIN) +#endif +#if PIN_EXISTS(W_STOP) + REPORT_NAME_DIGITAL(__LINE__, W_STOP_PIN) +#endif #if PIN_EXISTS(ZRIB_V20_D6) REPORT_NAME_DIGITAL(__LINE__, ZRIB_V20_D6_PIN) #endif @@ -1619,6 +1718,24 @@ #if PIN_EXISTS(K_SERIAL_RX) REPORT_NAME_DIGITAL(__LINE__, K_SERIAL_RX_PIN) #endif +#if PIN_EXISTS(U_SERIAL_TX) + REPORT_NAME_DIGITAL(__LINE__, U_SERIAL_TX_PIN) +#endif +#if PIN_EXISTS(U_SERIAL_RX) + REPORT_NAME_DIGITAL(__LINE__, U_SERIAL_RX_PIN) +#endif +#if PIN_EXISTS(V_SERIAL_TX) + REPORT_NAME_DIGITAL(__LINE__, V_SERIAL_TX_PIN) +#endif +#if PIN_EXISTS(V_SERIAL_RX) + REPORT_NAME_DIGITAL(__LINE__, V_SERIAL_RX_PIN) +#endif +#if PIN_EXISTS(W_SERIAL_TX) + REPORT_NAME_DIGITAL(__LINE__, W_SERIAL_TX_PIN) +#endif +#if PIN_EXISTS(W_SERIAL_RX) + REPORT_NAME_DIGITAL(__LINE__, W_SERIAL_RX_PIN) +#endif #if PIN_EXISTS(E0_DIAG) REPORT_NAME_DIGITAL(__LINE__, E0_DIAG_PIN) #endif diff --git a/Marlin/src/pins/pins_postprocess.h b/Marlin/src/pins/pins_postprocess.h index aabe0da858..8da2b969bc 100644 --- a/Marlin/src/pins/pins_postprocess.h +++ b/Marlin/src/pins/pins_postprocess.h @@ -221,6 +221,15 @@ #if !AXIS_HAS_SPI(K) #undef K_CS_PIN #endif +#if !AXIS_HAS_SPI(U) + #undef U_CS_PIN +#endif +#if !AXIS_HAS_SPI(V) + #undef V_CS_PIN +#endif +#if !AXIS_HAS_SPI(W) + #undef W_CS_PIN +#endif #if E_STEPPERS && !AXIS_HAS_SPI(E0) #undef E0_CS_PIN #endif @@ -264,6 +273,15 @@ #ifndef K_CS_PIN #define K_CS_PIN -1 #endif +#ifndef U_CS_PIN + #define U_CS_PIN -1 +#endif +#ifndef V_CS_PIN + #define V_CS_PIN -1 +#endif +#ifndef W_CS_PIN + #define W_CS_PIN -1 +#endif #ifndef E0_CS_PIN #define E0_CS_PIN -1 #endif @@ -546,6 +564,75 @@ #undef K_MAX_PIN #endif +#if HAS_U_AXIS + #ifdef U_STOP_PIN + #if U_HOME_TO_MIN + #define U_MIN_PIN U_STOP_PIN + #ifndef U_MAX_PIN + #define U_MAX_PIN -1 + #endif + #else + #define U_MAX_PIN U_STOP_PIN + #ifndef U_MIN_PIN + #define U_MIN_PIN -1 + #endif + #endif + #elif U_HOME_TO_MIN + #define U_STOP_PIN U_MIN_PIN + #else + #define U_STOP_PIN U_MAX_PIN + #endif +#else + #undef U_MIN_PIN + #undef U_MAX_PIN +#endif + +#if HAS_V_AXIS + #ifdef V_STOP_PIN + #if V_HOME_TO_MIN + #define V_MIN_PIN V_STOP_PIN + #ifndef V_MAX_PIN + #define V_MAX_PIN -1 + #endif + #else + #define V_MAX_PIN V_STOP_PIN + #ifndef V_MIN_PIN + #define V_MIN_PIN -1 + #endif + #endif + #elif V_HOME_TO_MIN + #define V_STOP_PIN V_MIN_PIN + #else + #define V_STOP_PIN V_MAX_PIN + #endif +#else + #undef V_MIN_PIN + #undef V_MAX_PIN +#endif + +#if HAS_W_AXIS + #ifdef W_STOP_PIN + #if W_HOME_TO_MIN + #define W_MIN_PIN W_STOP_PIN + #ifndef W_MAX_PIN + #define W_MAX_PIN -1 + #endif + #else + #define W_MAX_PIN W_STOP_PIN + #ifndef W_MIN_PIN + #define W_MIN_PIN -1 + #endif + #endif + #elif W_HOME_TO_MIN + #define W_STOP_PIN W_MIN_PIN + #else + #define W_STOP_PIN W_MAX_PIN + #endif +#else + #undef W_MIN_PIN + #undef W_MAX_PIN +#endif + // Filament Sensor first pin alias #if HAS_FILAMENT_SENSOR #define FIL_RUNOUT1_PIN FIL_RUNOUT_PIN // Filament Sensor first pin alias @@ -1204,6 +1291,12 @@ #define J_MS3_PIN -1 #endif +#if HAS_K_AXIS && !defined(K_DIAG_PIN) && !defined(K_STEP_PIN) && !PIN_EXISTS(K_CS_PIN) + #define U_E_INDEX INCREMENT(K_E_INDEX) +#else + #define U_E_INDEX K_E_INDEX +#endif + // The K axis, if any, should be the next open extruder port #if HAS_K_AXIS #ifndef K_STEP_PIN @@ -1284,6 +1377,258 @@ #define K_MS3_PIN -1 #endif +#if HAS_U_AXIS && !defined(U_DIAG_PIN) && !defined(U_STEP_PIN) && !PIN_EXISTS(U_CS_PIN) + #define V_E_INDEX INCREMENT(U_E_INDEX) +#else + #define V_E_INDEX U_E_INDEX +#endif + +// The U axis, if any, should be the next open extruder port +#if HAS_U_AXIS + #ifndef U_STEP_PIN + #define U_STEP_PIN _EPIN(U_E_INDEX, STEP) + #define U_DIR_PIN _EPIN(U_E_INDEX, DIR) + #define U_ENABLE_PIN _EPIN(U_E_INDEX, ENABLE) + #if M_E_INDEX >= MAX_E_STEPPERS || !PIN_EXISTS(U_STEP) + #error "No E stepper plug left for U!" + #else + #define AUTO_ASSIGNED_U_STEPPER 1 + #endif + #endif + #if AXIS_HAS_SPI(U) && !defined(U_CS_PIN) + #define U_CS_PIN _EPIN(U_E_INDEX, CS) + #if PIN_EXISTS(U_CS) + #define AUTO_ASSIGNED_U_CS 1 + #endif + #endif + #ifndef U_MS1_PIN + #define U_MS1_PIN _EPIN(U_E_INDEX, MS1) + #if PIN_EXISTS(U_MS1) + #define AUTO_ASSIGNED_U_MS1 1 + #endif + #endif + #ifndef U_MS2_PIN + #define U_MS2_PIN _EPIN(U_E_INDEX, MS2) + #if PIN_EXISTS(U_MS2) + #define AUTO_ASSIGNED_U_MS2 1 + #endif + #endif + #ifndef U_MS3_PIN + #define U_MS3_PIN _EPIN(U_E_INDEX, MS3) + #if PIN_EXISTS(U_MS3) + #define AUTO_ASSIGNED_U_MS3 1 + #endif + #endif + #if AXIS_HAS_UART(U) + #ifndef U_SERIAL_TX_PIN + #define U_SERIAL_TX_PIN _EPIN(U_E_INDEX, SERIAL_TX) + #endif + #ifndef U_SERIAL_RX_PIN + #define U_SERIAL_RX_PIN _EPIN(U_E_INDEX, SERIAL_RX) + #endif + #endif + // Auto-assign pins for stallGuard sensorless homing + #if !defined(U_DIAG_PIN) && !defined(U_USE_ENDSTOP) && defined(U_STALL_SENSITIVITY) && _PEXI(U_E_INDEX, DIAG) + #define U_DIAG_PIN _EPIN(U_E_INDEX, DIAG) + #if DIAG_REMAPPED(U, X_MIN) + #define U_USE_ENDSTOP _XMIN_ + #elif DIAG_REMAPPED(U, Y_MIN) + #define U_USE_ENDSTOP _YMIN_ + #elif DIAG_REMAPPED(U, Z_MIN) + #define U_USE_ENDSTOP _ZMIN_ + #elif DIAG_REMAPPED(U, X_MAX) + #define U_USE_ENDSTOP _XMAX_ + #elif DIAG_REMAPPED(U, Y_MAX) + #define U_USE_ENDSTOP _YMAX_ + #elif DIAG_REMAPPED(U, Z_MAX) + #define U_USE_ENDSTOP _ZMAX_ + #else + #define U_USE_ENDSTOP _En_DIAG_(U_E_INDEX) + #endif + #define AUTO_ASSIGNED_U_DIAG 1 + #undef U_DIAG_PIN // Defined in Conditionals_post.h based on U_USE_ENDSTOP + #endif +#endif + +#ifndef U_CS_PIN + #define U_CS_PIN -1 +#endif +#ifndef U_MS1_PIN + #define U_MS1_PIN -1 +#endif +#ifndef U_MS2_PIN + #define U_MS2_PIN -1 +#endif +#ifndef U_MS3_PIN + #define U_MS3_PIN -1 +#endif + +#if HAS_V_AXIS && !defined(V_DIAG_PIN) && !defined(V_STEP_PIN) && !PIN_EXISTS(V_CS_PIN) + #define W_E_INDEX INCREMENT(V_E_INDEX) +#else + #define W_E_INDEX V_E_INDEX +#endif + +// The V axis, if any, should be the next open extruder port +#if HAS_V_AXIS + #ifndef V_STEP_PIN + #define V_STEP_PIN _EPIN(V_E_INDEX, STEP) + #define V_DIR_PIN _EPIN(V_E_INDEX, DIR) + #define V_ENABLE_PIN _EPIN(V_E_INDEX, ENABLE) + #if V_E_INDEX >= MAX_E_STEPPERS || !PIN_EXISTS(V_STEP) + #error "No E stepper plug left for V!" + #else + #define AUTO_ASSIGNED_V_STEPPER 1 + #endif + #endif + #if AXIS_HAS_SPI(V) && !defined(V_CS_PIN) + #define V_CS_PIN _EPIN(V_E_INDEX, CS) + #if PIN_EXISTS(V_CS) + #define AUTO_ASSIGNED_V_CS 1 + #endif + #endif + #ifndef V_MS1_PIN + #define V_MS1_PIN _EPIN(V_E_INDEX, MS1) + #if PIN_EXISTS(V_MS1) + #define AUTO_ASSIGNED_V_MS1 1 + #endif + #endif + #ifndef V_MS2_PIN + #define V_MS2_PIN _EPIN(V_E_INDEX, MS2) + #if PIN_EXISTS(V_MS2) + #define AUTO_ASSIGNED_V_MS2 1 + #endif + #endif + #ifndef V_MS3_PIN + #define V_MS3_PIN _EPIN(V_E_INDEX, MS3) + #if PIN_EXISTS(V_MS3) + #define AUTO_ASSIGNED_V_MS3 1 + #endif + #endif + #if AXIS_HAS_UART(V) + #ifndef V_SERIAL_TX_PIN + #define V_SERIAL_TX_PIN _EPIN(V_E_INDEX, SERIAL_TX) + #endif + #ifndef V_SERIAL_RX_PIN + #define V_SERIAL_RX_PIN _EPIN(V_E_INDEX, SERIAL_RX) + #endif + #endif + // Auto-assign pins for stallGuard sensorless homing + #if !defined(V_DIAG_PIN) && !defined(V_USE_ENDSTOP) && defined(V_STALL_SENSITIVITY) && _PEXI(V_E_INDEX, DIAG) + #define V_DIAG_PIN _EPIN(V_E_INDEX, DIAG) + #if DIAG_REMAPPED(V, X_MIN) + #define V_USE_ENDSTOP _XMIN_ + #elif DIAG_REMAPPED(V, Y_MIN) + #define V_USE_ENDSTOP _YMIN_ + #elif DIAG_REMAPPED(V, Z_MIN) + #define V_USE_ENDSTOP _ZMIN_ + #elif DIAG_REMAPPED(V, X_MAX) + #define V_USE_ENDSTOP _XMAX_ + #elif DIAG_REMAPPED(V, Y_MAX) + #define V_USE_ENDSTOP _YMAX_ + #elif DIAG_REMAPPED(V, Z_MAX) + #define V_USE_ENDSTOP _ZMAX_ + #else + #define V_USE_ENDSTOP _En_DIAG_(V_E_INDEX) + #endif + #define AUTO_ASSIGNED_V_DIAG 1 + #undef V_DIAG_PIN // Defined in Conditionals_post.h based on O_USE_ENDSTOP + #endif +#endif + +#ifndef V_CS_PIN + #define V_CS_PIN -1 +#endif +#ifndef V_MS1_PIN + #define V_MS1_PIN -1 +#endif +#ifndef V_MS2_PIN + #define V_MS2_PIN -1 +#endif +#ifndef V_MS3_PIN + #define V_MS3_PIN -1 +#endif + +// The W axis, if any, should be the next open extruder port +#if HAS_W_AXIS + #ifndef W_STEP_PIN + #define W_STEP_PIN _EPIN(W_E_INDEX, STEP) + #define W_DIR_PIN _EPIN(W_E_INDEX, DIR) + #define W_ENABLE_PIN _EPIN(W_E_INDEX, ENABLE) + #if W_E_INDEX >= MAX_E_STEPPERS || !PIN_EXISTS(W_STEP) + #error "No E stepper plug left for W!" + #else + #define AUTO_ASSIGNED_W_STEPPER 1 + #endif + #endif + #if AXIS_HAS_SPI(W) && !defined(W_CS_PIN) + #define W_CS_PIN _EPIN(W_E_INDEX, CS) + #if PIN_EXISTS(W_CS) + #define AUTO_ASSIGNED_W_CS 1 + #endif + #endif + #ifndef W_MS1_PIN + #define W_MS1_PIN _EPIN(W_E_INDEX, MS1) + #if PIN_EXISTS(W_MS1) + #define AUTO_ASSIGNED_W_MS1 1 + #endif + #endif + #ifndef W_MS2_PIN + #define W_MS2_PIN _EPIN(W_E_INDEX, MS2) + #if PIN_EXISTS(W_MS2) + #define AUTO_ASSIGNED_W_MS2 1 + #endif + #endif + #ifndef W_MS3_PIN + #define W_MS3_PIN _EPIN(W_E_INDEX, MS3) + #if PIN_EXISTS(W_MS3) + #define AUTO_ASSIGNED_W_MS3 1 + #endif + #endif + #if AXIS_HAS_UART(W) + #ifndef W_SERIAL_TX_PIN + #define W_SERIAL_TX_PIN _EPIN(W_E_INDEX, SERIAL_TX) + #endif + #ifndef W_SERIAL_RX_PIN + #define W_SERIAL_RX_PIN _EPIN(W_E_INDEX, SERIAL_RX) + #endif + #endif + // Auto-assign pins for stallGuard sensorless homing + #if !defined(W_DIAG_PIN) && !defined(W_USE_ENDSTOP) && defined(W_STALL_SENSITIVITY) && _PEXI(W_E_INDEX, DIAG) + #define W_DIAG_PIN _EPIN(W_E_INDEX, DIAG) + #if DIAG_REMAPPED(W, X_MIN) + #define W_USE_ENDSTOP _XMIN_ + #elif DIAG_REMAPPED(W, Y_MIN) + #define W_USE_ENDSTOP _YMIN_ + #elif DIAG_REMAPPED(W, Z_MIN) + #define W_USE_ENDSTOP _ZMIN_ + #elif DIAG_REMAPPED(W, X_MAX) + #define W_USE_ENDSTOP _XMAX_ + #elif DIAG_REMAPPED(W, Y_MAX) + #define W_USE_ENDSTOP _YMAX_ + #elif DIAG_REMAPPED(W, Z_MAX) + #define W_USE_ENDSTOP _ZMAX_ + #else + #define W_USE_ENDSTOP _En_DIAG_(W_E_INDEX) + #endif + #define AUTO_ASSIGNED_W_DIAG 1 + #undef W_DIAG_PIN // Defined in Conditionals_post.h based on Q_USE_ENDSTOP + #endif +#endif + +#ifndef W_CS_PIN + #define W_CS_PIN -1 +#endif +#ifndef W_MS1_PIN + #define W_MS1_PIN -1 +#endif +#ifndef W_MS2_PIN + #define W_MS2_PIN -1 +#endif +#ifndef W_MS3_PIN + #define W_MS3_PIN -1 +#endif + // // Disable unused endstop / probe pins // @@ -1359,6 +1704,30 @@ #undef K_MAX_PIN #define K_MAX_PIN -1 #endif +#if DISABLED(USE_UMIN_PLUG) + #undef U_MIN_PIN + #define U_MIN_PIN -1 +#endif +#if DISABLED(USE_UMAX_PLUG) + #undef U_MAX_PIN + #define U_MAX_PIN -1 +#endif +#if DISABLED(USE_VMIN_PLUG) + #undef V_MIN_PIN + #define V_MIN_PIN -1 +#endif +#if DISABLED(USE_VMAX_PLUG) + #undef V_MAX_PIN + #define V_MAX_PIN -1 +#endif +#if DISABLED(USE_WMIN_PLUG) + #undef W_MIN_PIN + #define W_MIN_PIN -1 +#endif +#if DISABLED(USE_WMAX_PLUG) + #undef W_MAX_PIN + #define W_MAX_PIN -1 +#endif #if DISABLED(X_DUAL_ENDSTOPS) || X_HOME_TO_MAX #undef X2_MIN_PIN diff --git a/Marlin/src/pins/ramps/pins_MKS_GEN_L.h b/Marlin/src/pins/ramps/pins_MKS_GEN_L.h index 522a34cda1..4dca1ca187 100644 --- a/Marlin/src/pins/ramps/pins_MKS_GEN_L.h +++ b/Marlin/src/pins/ramps/pins_MKS_GEN_L.h @@ -37,6 +37,12 @@ // Power outputs EFBF or EFBE #define MOSFET_D_PIN 7 +// Hotend, Hotend, Bed + Fan on D9 +#if FET_ORDER_EEB + #define MOSFET_B_PIN 7 + #define FAN_PIN 9 +#endif + // // CS Pins wired to avoid conflict with the LCD // See https://www.thingiverse.com/asset:66604 diff --git a/Marlin/src/pins/ramps/pins_RAMPS.h b/Marlin/src/pins/ramps/pins_RAMPS.h index 29caaf0533..c7ef0be99e 100644 --- a/Marlin/src/pins/ramps/pins_RAMPS.h +++ b/Marlin/src/pins/ramps/pins_RAMPS.h @@ -270,7 +270,7 @@ // M3/M4/M5 - Spindle/Laser Control // #if HAS_CUTTER && !defined(SPINDLE_LASER_ENA_PIN) - #if !NUM_SERVOS // Use servo connector if possible + #if NUM_SERVOS < 2 // Use servo connector if possible #define SPINDLE_LASER_ENA_PIN 4 // Pullup or pulldown! #define SPINDLE_LASER_PWM_PIN 6 // Hardware PWM #define SPINDLE_DIR_PIN 5 diff --git a/Marlin/src/pins/sensitive_pins.h b/Marlin/src/pins/sensitive_pins.h index f9911cc863..db6cb2353b 100644 --- a/Marlin/src/pins/sensitive_pins.h +++ b/Marlin/src/pins/sensitive_pins.h @@ -293,6 +293,126 @@ #endif +#if HAS_U_AXIS + #if PIN_EXISTS(U_MIN) + #define _U_MIN U_MIN_PIN, + #else + #define _U_MIN + #endif + #if PIN_EXISTS(U_MAX) + #define _U_MAX U_MAX_PIN, + #else + #define _U_MAX + #endif + #if PIN_EXISTS(U_CS) && AXIS_HAS_SPI(U) + #define _U_CS U_CS_PIN, + #else + #define _U_CS + #endif + #if PIN_EXISTS(U_MS1) + #define _U_MS1 U_MS1_PIN, + #else + #define _U_MS1 + #endif + #if PIN_EXISTS(U_MS2) + #define _U_MS2 U_MS2_PIN, + #else + #define _U_MS2 + #endif + #if PIN_EXISTS(U_MS3) + #define _U_MS3 U_MS3_PIN, + #else + #define _U_MS3 + #endif + + #define _U_PINS U_STEP_PIN, U_DIR_PIN, U_ENABLE_PIN, _U_MIN _U_MAX _U_MS1 _U_MS2 _U_MS3 _U_CS + +#else + + #define _U_PINS + +#endif + +#if HAS_V_AXIS + #if PIN_EXISTS(V_MIN) + #define _V_MIN V_MIN_PIN, + #else + #define _V_MIN + #endif + #if PIN_EXISTS(V_MAX) + #define _V_MAX V_MAX_PIN, + #else + #define _V_MAX + #endif + #if PIN_EXISTS(V_CS) && AXIS_HAS_SPI(V) + #define _V_CS V_CS_PIN, + #else + #define _V_CS + #endif + #if PIN_EXISTS(V_MS1) + #define _V_MS1 V_MS1_PIN, + #else + #define _V_MS1 + #endif + #if PIN_EXISTS(V_MS2) + #define _V_MS2 V_MS2_PIN, + #else + #define _V_MS2 + #endif + #if PIN_EXISTS(V_MS3) + #define _V_MS3 V_MS3_PIN, + #else + #define _V_MS3 + #endif + + #define _V_PINS V_STEP_PIN, V_DIR_PIN, V_ENABLE_PIN, _V_MIN _V_MAX _V_MS1 _V_MS2 _V_MS3 _V_CS + +#else + + #define _V_PINS + +#endif + +#if HAS_W_AXIS + #if PIN_EXISTS(W_MIN) + #define _W_MIN W_MIN_PIN, + #else + #define _W_MIN + #endif + #if PIN_EXISTS(W_MAX) + #define _W_MAX W_MAX_PIN, + #else + #define _W_MAX + #endif + #if PIN_EXISTS(W_CS) && AXIS_HAS_SPI(W) + #define _W_CS W_CS_PIN, + #else + #define _W_CS + #endif + #if PIN_EXISTS(W_MS1) + #define _W_MS1 W_MS1_PIN, + #else + #define _W_MS1 + #endif + #if PIN_EXISTS(W_MS2) + #define _W_MS2 W_MS2_PIN, + #else + #define _W_MS2 + #endif + #if PIN_EXISTS(W_MS3) + #define _W_MS3 W_MS3_PIN, + #else + #define _W_MS3 + #endif + + #define _W_PINS W_STEP_PIN, W_DIR_PIN, W_ENABLE_PIN, _W_MIN _W_MAX _W_MS1 _W_MS2 _W_MS3 _W_CS + +#else + + #define _W_PINS + +#endif + // // Extruder Chip Select, Digital Micro-steps // @@ -886,7 +1006,7 @@ #endif #define SENSITIVE_PINS \ - _X_PINS _Y_PINS _Z_PINS _I_PINS _J_PINS _K_PINS \ + _X_PINS _Y_PINS _Z_PINS _I_PINS _J_PINS _K_PINS _U_PINS _V_PINS _W_PINS \ _X2_PINS _Y2_PINS _Z2_PINS _Z3_PINS _Z4_PINS _Z_PROBE \ _E0_PINS _E1_PINS _E2_PINS _E3_PINS _E4_PINS _E5_PINS _E6_PINS _E7_PINS \ _H0_PINS _H1_PINS _H2_PINS _H3_PINS _H4_PINS _H5_PINS _H6_PINS _H7_PINS \ diff --git a/Marlin/src/pins/stm32f1/pins_BTT_SKR_MINI_V1_1.h b/Marlin/src/pins/stm32f1/pins_BTT_SKR_MINI_V1_1.h index a92de805f7..4f52dfb4fc 100644 --- a/Marlin/src/pins/stm32f1/pins_BTT_SKR_MINI_V1_1.h +++ b/Marlin/src/pins/stm32f1/pins_BTT_SKR_MINI_V1_1.h @@ -80,6 +80,23 @@ #endif #endif +#if HAS_TMC_UART // Shared with EXP1 + #define X_SERIAL_TX_PIN PC10 + #define X_SERIAL_RX_PIN X_SERIAL_TX_PIN + + #define Y_SERIAL_TX_PIN PC11 + #define Y_SERIAL_RX_PIN Y_SERIAL_TX_PIN + + #define Z_SERIAL_TX_PIN PC12 + #define Z_SERIAL_RX_PIN Z_SERIAL_TX_PIN + + #define E0_SERIAL_TX_PIN PC14 + #define E0_SERIAL_RX_PIN E0_SERIAL_TX_PIN + + // Reduce baud rate to improve software serial reliability + #define TMC_BAUD_RATE 19200 +#endif + // // Heaters / Fans // diff --git a/Marlin/src/pins/stm32f1/pins_PANDA_PI_V29.h b/Marlin/src/pins/stm32f1/pins_PANDA_PI_V29.h new file mode 100644 index 0000000000..7f4aa563b0 --- /dev/null +++ b/Marlin/src/pins/stm32f1/pins_PANDA_PI_V29.h @@ -0,0 +1,222 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 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 . + * + */ +#pragma once + +#include "env_validate.h" + +#define BOARD_INFO_NAME "PANDA PI V2.9" + +// Release PB3/PB4 (TMC_SW Pins) from JTAG pins +#define DISABLE_JTAG + +// Ignore temp readings during development. +//#define BOGUS_TEMPERATURE_GRACE_PERIOD 2000 + +#if EITHER(NO_EEPROM_SELECTED, FLASH_EEPROM_EMULATION) + #define FLASH_EEPROM_EMULATION + #define EEPROM_PAGE_SIZE (0x800U) // 2KB + #define EEPROM_START_ADDRESS (0x8000000UL + (STM32_FLASH_SIZE) * 1024UL - (EEPROM_PAGE_SIZE) * 2UL) + #define MARLIN_EEPROM_SIZE EEPROM_PAGE_SIZE // 2KB +#endif + +// +// Servos +// +#define SERVO0_PIN PA11 // SERVOS + +// +// Limit Switches +// +#define X_STOP_PIN PA3 // X-STOP +#define Y_STOP_PIN PC9 // Y-STOP +#define Z_STOP_PIN PA1 // Z-STOP + +// +// Z Probe must be this pin +// +//#define Z_MIN_PROBE_PIN PA1 // PROBE + +// +// Filament Runout Sensor +// +//#ifndef FIL_RUNOUT_PIN +// #define FIL_RUNOUT_PIN PC2 // E0-STOP +//#endif + +// +// Steppers +// +#define X_ENABLE_PIN PC12 +#define X_STEP_PIN PC11 +#define X_DIR_PIN PB6 + +#define Y_ENABLE_PIN PC12 +#define Y_STEP_PIN PB5 +#define Y_DIR_PIN PB4 + +#define Z_ENABLE_PIN PC12 +#define Z_STEP_PIN PB3 +#define Z_DIR_PIN PA15 + +#define E0_ENABLE_PIN PC12 +#define E0_STEP_PIN PB15 +#define E0_DIR_PIN PB14 + +// +// Software SPI pins for TMC2130 stepper drivers +// +#if ENABLED(TMC_USE_SW_SPI) + #ifndef TMC_SW_MOSI + #define TMC_SW_MOSI PB5 + #endif + #ifndef TMC_SW_MISO + #define TMC_SW_MISO PB4 + #endif + #ifndef TMC_SW_SCK + #define TMC_SW_SCK PB3 + #endif +#endif + +#if HAS_TMC_UART + /** + * TMC2208/TMC2209 stepper drivers + * + * Hardware serial communication ports. + * If undefined software serial is used according to the pins below + */ + //#define X_HARDWARE_SERIAL MSerial1 + //#define Y_HARDWARE_SERIAL MSerial1 + //#define Z_HARDWARE_SERIAL MSerial1 + //#define E0_HARDWARE_SERIAL MSerial1 + + #define X_SERIAL_TX_PIN PC10 + #define X_SERIAL_RX_PIN X_SERIAL_TX_PIN + + #define Y_SERIAL_TX_PIN PC11 + #define Y_SERIAL_RX_PIN Y_SERIAL_TX_PIN + + #define Z_SERIAL_TX_PIN PC12 + #define Z_SERIAL_RX_PIN Z_SERIAL_TX_PIN + + #define E0_SERIAL_TX_PIN PD2 + #define E0_SERIAL_RX_PIN E0_SERIAL_TX_PIN + + // Reduce baud rate to improve software serial reliability + #define TMC_BAUD_RATE 19200 +#endif + +// +// Temperature Sensors +// +#define TEMP_0_PIN PB0 // Analog Input "TH0" +#define TEMP_BED_PIN PB1 // Analog Input "TB0" +#define TEMP_1_PIN PA2 + +// +// Heaters / Fans +// +#define HEATER_0_PIN PB12 // "HE" +#define HEATER_BED_PIN PB13 // "HB" +#define FAN_PIN PA8 // "FAN0" +#define HEATER_1_PIN PA12 + +// +// SD Support +// +#define ONBOARD_SPI_DEVICE 1 // SPI1 +#define ONBOARD_SD_CS_PIN PA4 // Chip select for "System" SD card +#define SDSS ONBOARD_SD_CS_PIN + +#ifndef SDCARD_CONNECTION + #define SDCARD_CONNECTION ONBOARD +#endif +#if SD_CONNECTION_IS(ONBOARD) + //#define SD_DETECT_PIN PA4 + #define SD_SCK_PIN PA5 + #define SD_MISO_PIN PA6 + #define SD_MOSI_PIN PA7 +#elif SD_CONNECTION_IS(CUSTOM_CABLE) + #error "SD CUSTOM_CABLE is not compatible with SKR E3 DIP." +#endif + +// +// LCD / Controller +// +#if HAS_WIRED_LCD + #define BTN_ENC PA0 + #define BTN_EN1 PC4 + #define BTN_EN2 PC5 + + #define LCD_PINS_RS PC0 + #define LCD_PINS_ENABLE PC2 + #define LCD_PINS_D4 PC1 +#endif + +#if BOTH(TOUCH_UI_FTDI_EVE, LCD_FYSETC_TFT81050) + + #error "CAUTION! LCD_FYSETC_TFT81050 requires wiring modifications. See 'pins_BTT_SKR_E3_DIP.h' for details. Comment out this line to continue." + + /** FYSETC TFT TFT81050 display pinout + * + * Board Display + * ----- ----- + * 5V | 1 2 | GND (SPI1-MISO) MISO | 1 2 | SCK (SPI1-SCK) + * (FREE) PB7 | 3 4 | PB8 (LCD_CS) (PA9) MOD_RESET | 3 4 | SD_CS (PA10) + * (FREE) PB9 | 5 6 PA10 (SD_CS) (PB8) LCD_CS | 5 6 MOSI (SPI1-MOSI) + * RESET | 7 8 | PA9 (MOD_RESET) (PA15) SD_DET | 7 8 | RESET + * (BEEPER) PB6 | 9 10| PA15 (SD_DET) GND | 9 10| 5V + * ----- ----- + * EXP1 EXP1 + * + * Needs custom cable: + * + * Board Adapter Display + * _________ + * EXP1-1 ----------- EXP1-10 + * EXP1-2 ----------- EXP1-9 + * SPI1-4 ----------- EXP1-6 + * EXP1-4 ----------- EXP1-5 + * SP11-3 ----------- EXP1-2 + * EXP1-6 ----------- EXP1-4 + * EXP1-7 ----------- EXP1-8 + * EXP1-8 ----------- EXP1-3 + * SPI1-1 ----------- EXP1-1 + * EXP1-10 ----------- EXP1-7 + */ + + #define CLCD_SPI_BUS 1 // SPI1 connector + + #define BEEPER_PIN PB6 + + #define CLCD_MOD_RESET PA9 + #define CLCD_SPI_CS PB8 + + #if SD_CONNECTION_IS(LCD) && BOTH(TOUCH_UI_FTDI_EVE, LCD_FYSETC_TFT81050) + #define SD_DETECT_PIN PA15 + #define SD_SS_PIN PA10 + #endif + +#elif HAS_WIRED_LCD + + #define BEEPER_PIN PC3 + +#endif diff --git a/Marlin/src/pins/stm32f4/pins_BTT_SKR_V2_0_common.h b/Marlin/src/pins/stm32f4/pins_BTT_SKR_V2_0_common.h index 4f5ed6c1b4..d526c75b63 100644 --- a/Marlin/src/pins/stm32f4/pins_BTT_SKR_V2_0_common.h +++ b/Marlin/src/pins/stm32f4/pins_BTT_SKR_V2_0_common.h @@ -23,6 +23,8 @@ #include "env_validate.h" +#define USES_DIAG_JUMPERS + // If you have the BigTreeTech driver expansion module, enable BTT_MOTOR_EXPANSION // https://github.com/bigtreetech/BTT-Expansion-module/tree/master/BTT%20EXP-MOT //#define BTT_MOTOR_EXPANSION diff --git a/Marlin/src/pins/stm32g0/pins_BTT_SKR_MINI_E3_V3_0.h b/Marlin/src/pins/stm32g0/pins_BTT_SKR_MINI_E3_V3_0.h index 2589a316b6..2fddb68a7c 100644 --- a/Marlin/src/pins/stm32g0/pins_BTT_SKR_MINI_E3_V3_0.h +++ b/Marlin/src/pins/stm32g0/pins_BTT_SKR_MINI_E3_V3_0.h @@ -256,8 +256,51 @@ #endif + #elif ENABLED(FYSETC_MINI_12864_2_1) + + #error "CAUTION! FYSETC_MINI_12864_2_1 and clones require wiring modifications. See 'pins_BTT_SKR_MINI_E3_V3_0.h' for details. Comment out this line to continue." + + /** + * + * Board Display + * ------ ------ + * (EN2) PB5 |10 9 | PA15(BTN_ENC) 5V |10 9 | GND + * (LCD_CS) PA9 | 8 7 | RST (RESET) -- | 8 7 | -- + * (LCD_A0) PA10 |#6 5 | PB9 (EN1) (DIN) | 6 5#| (RESET) + * (LCD_SCK)PB8 | 4 3 | PD6 (MOSI) (LCD_A0) | 4 3 | (LCD_CS) + * GND | 2 1 | 5V (BTN_ENC) | 2 1 | -- + * ------ ------ + * EXP1 EXP1 + * + * ------ + * -- |10 9 | -- + * --- (RESET) | 8 7 | -- + * | 3 | (MOSI) | 6 5#| (EN2) + * | 2 | (DIN) -- | 4 3 | (EN1) + * | 1 | (LCD_SCK)| 2 1 | -- + * --- ------ + * Neopixel EXP2 + * + * Needs custom cable. Connect EN2-EN2, LCD_CS-LCD_CS and so on. + * + * Check twice index position!!! (marked as # here) + * On BTT boards pins from IDC10 connector are numbered in unusual order. + */ + #define BTN_ENC EXP1_09_PIN + #define BTN_EN1 PB9 + #define BTN_EN2 PB5 + #define BEEPER_PIN -1 + + #define DOGLCD_CS PA9 + #define DOGLCD_A0 PA10 + #define DOGLCD_SCK PB8 + #define DOGLCD_MOSI PD6 + + #define FORCE_SOFT_SPI + #define LCD_BACKLIGHT_PIN -1 + #else - #error "Only CR10_STOCKDISPLAY, ZONESTAR_LCD, ENDER2_STOCKDISPLAY, MKS_MINI_12864, and TFTGLCD_PANEL_(SPI|I2C) are currently supported on the BIGTREE_SKR_MINI_E3." + #error "Only CR10_STOCKDISPLAY, ZONESTAR_LCD, ENDER2_STOCKDISPLAY, MKS_MINI_12864, FYSETC_MINI_12864_2_1, and TFTGLCD_PANEL_(SPI|I2C) are currently supported on the BIGTREE_SKR_MINI_E3." #endif #endif // HAS_WIRED_LCD diff --git a/Marlin/src/sd/cardreader.cpp b/Marlin/src/sd/cardreader.cpp index 724de8f82a..652a44e526 100644 --- a/Marlin/src/sd/cardreader.cpp +++ b/Marlin/src/sd/cardreader.cpp @@ -458,7 +458,7 @@ void CardReader::mount() { cdroot(); #if ENABLED(USB_FLASH_DRIVE_SUPPORT) || PIN_EXISTS(SD_DETECT) else if (marlin_state != MF_INITIALIZING) - ui.set_status(GET_TEXT_F(MSG_MEDIA_INIT_FAIL), -1); + LCD_ALERTMESSAGE(MSG_MEDIA_INIT_FAIL); #endif ui.refresh(); diff --git a/buildroot/bin/build_example b/buildroot/bin/build_example index 8ebb58f972..cff8ea253e 100755 --- a/buildroot/bin/build_example +++ b/buildroot/bin/build_example @@ -24,6 +24,6 @@ cp "$SUB"/_Statusscreen.h Marlin/ 2>/dev/null echo "Building the firmware now..." HERE=`dirname "$0"` -$HERE/mftest -a -n1 || { echo "Failed"; exit 1; } +$HERE/mftest -s -a -n1 || { echo "Failed"; exit 1; } echo "Success" diff --git a/buildroot/bin/mftest b/buildroot/bin/mftest index 77e53ff9ac..9aa5e12732 100755 --- a/buildroot/bin/mftest +++ b/buildroot/bin/mftest @@ -17,6 +17,7 @@ usage() { Usage: mftest [-t|--env=] [-n|--num=] [-m|--make] [-y|--build=] mftest [-a|--autobuild] mftest [-r|--rebuild] + mftest [-s|--silent] mftest [-u|--autoupload] [-n|--num=] OPTIONS @@ -30,7 +31,7 @@ OPTIONS -v --verbose Extra output for debugging. -s --silent Silence build output from PlatformIO. -env shortcuts: tree due esp lin lpc|lpc8 lpc9 m128 m256|mega stm|f1 f4 f7 s6 teensy|t31|t32 t35|t36 t40|t41 +env shortcuts: tree due esp lin lp8|lpc8 lp9|lpc9 m128 m256|mega stm|f1 f4 f7 s6 teensy|t31|t32 t35|t36 t40|t41 " } @@ -52,7 +53,7 @@ TESTENV='-' CHOICE=0 DEBUG=0 -while getopts 'abhmruvyn:t:-:' OFLAG; do +while getopts 'abhmrsuvyn:t:-:' OFLAG; do case "${OFLAG}" in a) AUTO_BUILD=1 ; bugout "Auto-Build target..." ;; h) EXIT_USAGE=1 ;; @@ -84,6 +85,7 @@ while getopts 'abhmruvyn:t:-:' OFLAG; do esac ;; rebuild) REBUILD=1 ; bugout "Rebuilding previous..." ;; + silent) SILENT_FLAG="-s" ;; make) USE_MAKE=1 ; bugout "Using make with Docker..." ;; debug|verbose) DEBUG=1 ; bugout "Debug ON" ;; build) case "$OVAL" in diff --git a/ini/features.ini b/ini/features.ini index 9150ff5451..fac9cf9b57 100644 --- a/ini/features.ini +++ b/ini/features.ini @@ -24,7 +24,7 @@ HAS_STEALTHCHOP = src_filter=+ -HAS_TMC26X = TMC26XStepper=https://github.com/trinamic/TMC26XStepper/archive/master.zip +HAS_TMC26X = TMC26XStepper=https://github.com/MarlinFirmware/TMC26XStepper/archive/master.zip src_filter=+ HAS_L64XX = Arduino-L6470@0.8.0 src_filter=+ + + + @@ -199,11 +199,11 @@ AUTO_REPORT_POSITION = src_filter=+ REPETIER_GCODE_M360 = src_filter=+ HAS_GCODE_M876 = src_filter=+ HAS_RESUME_CONTINUE = src_filter=+ +LCD_SET_PROGRESS_MANUALLY = src_filter=+ HAS_STATUS_MESSAGE = src_filter=+ HAS_LCD_CONTRAST = src_filter=+ HAS_LCD_BRIGHTNESS = src_filter=+ HAS_BUZZER = src_filter=+ -LCD_SET_PROGRESS_MANUALLY = src_filter=+ TOUCH_SCREEN_CALIBRATION = src_filter=+ ARC_SUPPORT = src_filter=+ GCODE_MOTION_MODES = src_filter=+ @@ -218,6 +218,7 @@ HAS_EXTRUDERS = src_filter=+ HAS_COOLER = src_filter=+ AUTO_REPORT_TEMPERATURES = src_filter=+ +MPCTEMP = src_filter=+ INCH_MODE_SUPPORT = src_filter=+ TEMPERATURE_UNITS_SUPPORT = src_filter=+ NEED_HEX_PRINT = src_filter=+ diff --git a/ini/stm32f1.ini b/ini/stm32f1.ini index 07b75e4e94..9002f81a81 100644 --- a/ini/stm32f1.ini +++ b/ini/stm32f1.ini @@ -73,6 +73,17 @@ build_flags = ${env:STM32F103RC_btt.build_flags} -DUSBD_USE_CDC_MSC build_unflags = ${common_stm32.build_unflags} -DUSBD_USE_CDC +# +# Panda Pi V2.9 - Standalone (STM32F103RC) +# Headless, without direct Pi control, but potentially hosting OctoPrint, stepdaemon, etc. +# +[env:PANDA_PI_V29] +extends = common_STM32F103RC_variant +build_flags = ${common_STM32F103RC_variant.build_flags} + -DTIMER_SERVO=TIM1 +board_build.offset = 0x5000 +board_upload.offset_address = 0x08005000 + # # MKS Robin (STM32F103ZET6) # Uses HAL STM32 to support Marlin UI for TFT screen with optional touch panel diff --git a/ini/stm32f4.ini b/ini/stm32f4.ini index 9e6e213427..d7c160d639 100644 --- a/ini/stm32f4.ini +++ b/ini/stm32f4.ini @@ -298,9 +298,8 @@ extends = env:BIGTREE_OCTOPUS_PRO_V1_F429 platform_packages = ${stm_flash_drive.platform_packages} build_unflags = -DUSBD_USE_CDC build_flags = ${stm_flash_drive.build_flags} - -DSTM32F446_5VX -DUSE_USB_HS_IN_FS - -DUSE_USBHOST_HS -DUSBD_IRQ_PRIO=5 - -DUSBD_IRQ_SUBPRIO=6 + -DUSE_USB_HS_IN_FS -DUSE_USBHOST_HS + -DUSBD_IRQ_PRIO=5 -DUSBD_IRQ_SUBPRIO=6 -DUSBD_USE_CDC_MSC # diff --git a/platformio.ini b/platformio.ini index 0e50da2b73..79ef54bd47 100644 --- a/platformio.ini +++ b/platformio.ini @@ -215,11 +215,11 @@ default_src_filter = + - - + - - - + - - - - - - - - - - - @@ -239,6 +239,7 @@ default_src_filter = + - - + - - - + - - - -