diff --git a/Marlin/Conditionals_LCD.h b/Marlin/Conditionals_LCD.h index 2cd7504326..7d8dabb310 100644 --- a/Marlin/Conditionals_LCD.h +++ b/Marlin/Conditionals_LCD.h @@ -439,10 +439,20 @@ */ #if ENABLED(DISTINCT_E_FACTORS) && E_STEPPERS > 1 #define XYZE_N (XYZ + E_STEPPERS) + #if ENABLED(HANGPRINTER) + #define NUM_AXIS_N (ABCD + E_STEPPERS) + #else + #define NUM_AXIS_N (XYZ + E_STEPPERS) + #endif #define E_AXIS_N (E_AXIS + extruder) #else #undef DISTINCT_E_FACTORS #define XYZE_N XYZE + #if ENABLED(HANGPRINTER) + #define NUM_AXIS_N ABCDE + #else + #define NUM_AXIS_N XYZE + #endif #define E_AXIS_N E_AXIS #endif @@ -496,7 +506,7 @@ * Set flags for enabled probes */ #define HAS_BED_PROBE (ENABLED(FIX_MOUNTED_PROBE) || ENABLED(Z_PROBE_ALLEN_KEY) || HAS_Z_SERVO_PROBE || ENABLED(Z_PROBE_SLED) || ENABLED(SOLENOID_PROBE)) -#define PROBE_SELECTED (HAS_BED_PROBE || ENABLED(PROBE_MANUALLY)) +#define PROBE_SELECTED (HAS_BED_PROBE || ENABLED(PROBE_MANUALLY) || ENABLED(MESH_BED_LEVELING)) #if !HAS_BED_PROBE // Clear probe pin settings when no probe is selected diff --git a/Marlin/Conditionals_post.h b/Marlin/Conditionals_post.h index 924ac46ba6..3707d77413 100644 --- a/Marlin/Conditionals_post.h +++ b/Marlin/Conditionals_post.h @@ -29,7 +29,7 @@ #define CONDITIONALS_POST_H #define IS_SCARA (ENABLED(MORGAN_SCARA) || ENABLED(MAKERARM_SCARA)) -#define IS_KINEMATIC (ENABLED(DELTA) || IS_SCARA) +#define IS_KINEMATIC (ENABLED(DELTA) || IS_SCARA || ENABLED(HANGPRINTER)) #define IS_CARTESIAN !IS_KINEMATIC /** @@ -47,7 +47,7 @@ #define Y_BED_SIZE Y_MAX_LENGTH #endif -// Require 0,0 bed center for Delta and SCARA +// Require 0,0 bed center for Delta, SCARA, and HANGPRINTER #if IS_KINEMATIC #define BED_CENTER_AT_0_0 #endif @@ -68,6 +68,18 @@ #define Y_MIN_BED (Y_CENTER - (Y_BED_SIZE) / 2) #define Y_MAX_BED (Y_CENTER + (Y_BED_SIZE) / 2) +/** + * Dual X Carriage + */ +#if ENABLED(DUAL_X_CARRIAGE) + #ifndef X1_MIN_POS + #define X1_MIN_POS X_MIN_POS + #endif + #ifndef X1_MAX_POS + #define X1_MAX_POS X_BED_SIZE + #endif +#endif + /** * CoreXY, CoreXZ, and CoreYZ - and their reverse */ @@ -117,7 +129,7 @@ #ifdef MANUAL_X_HOME_POS #define X_HOME_POS MANUAL_X_HOME_POS #elif ENABLED(BED_CENTER_AT_0_0) - #if ENABLED(DELTA) + #if ENABLED(DELTA) || ENABLED(HANGPRINTER) #define X_HOME_POS 0 #else #define X_HOME_POS ((X_BED_SIZE) * (X_HOME_DIR) * 0.5) @@ -133,7 +145,7 @@ #ifdef MANUAL_Y_HOME_POS #define Y_HOME_POS MANUAL_Y_HOME_POS #elif ENABLED(BED_CENTER_AT_0_0) - #if ENABLED(DELTA) + #if (ENABLED(DELTA) || ENABLED(HANGPRINTER)) #define Y_HOME_POS 0 #else #define Y_HOME_POS ((Y_BED_SIZE) * (Y_HOME_DIR) * 0.5) @@ -400,6 +412,63 @@ #define ARRAY_BY_HOTENDS(...) ARRAY_N(HOTENDS, __VA_ARGS__) #define ARRAY_BY_HOTENDS1(v1) ARRAY_BY_HOTENDS(v1, v1, v1, v1, v1, v1) +/** + * Driver Timings + * NOTE: Driver timing order is longest-to-shortest duration. + * Preserve this ordering when adding new drivers. + */ +#ifndef MINIMUM_STEPPER_DIR_DELAY + #if HAS_DRIVER(TB6560) + #define MINIMUM_STEPPER_DIR_DELAY 15000 + #elif HAS_DRIVER(TB6600) + #define MINIMUM_STEPPER_DIR_DELAY 1500 + #elif HAS_DRIVER(DRV8825) + #define MINIMUM_STEPPER_DIR_DELAY 650 + #elif HAS_DRIVER(LV8729) + #define MINIMUM_STEPPER_DIR_DELAY 500 + #elif HAS_DRIVER(A4988) + #define MINIMUM_STEPPER_DIR_DELAY 200 + #elif HAS_TRINAMIC || HAS_DRIVER(TMC2660) || HAS_DRIVER(TMC2130_STANDALONE) || HAS_DRIVER(TMC2208_STANDALONE) || HAS_DRIVER(TMC26X_STANDALONE) || HAS_DRIVER(TMC2660_STANDALONE) + #define MINIMUM_STEPPER_DIR_DELAY 20 + #else + #define MINIMUM_STEPPER_DIR_DELAY 200 // Expect at least 10µS since one Stepper ISR must transpire + #endif +#endif + +#ifndef MINIMUM_STEPPER_PULSE + #if HAS_DRIVER(TB6560) + #define MINIMUM_STEPPER_PULSE 30 + #elif HAS_DRIVER(TB6600) + #define MINIMUM_STEPPER_PULSE 3 + #elif HAS_DRIVER(DRV8825) + #define MINIMUM_STEPPER_PULSE 2 + #elif HAS_DRIVER(A4988) || HAS_DRIVER(LV8729) + #define MINIMUM_STEPPER_PULSE 1 + #elif HAS_TRINAMIC || HAS_DRIVER(TMC2660) || HAS_DRIVER(TMC2130_STANDALONE) || HAS_DRIVER(TMC2208_STANDALONE) || HAS_DRIVER(TMC26X_STANDALONE) || HAS_DRIVER(TMC2660_STANDALONE) + #define MINIMUM_STEPPER_PULSE 0 + #else + #define MINIMUM_STEPPER_PULSE 1 + #endif +#endif + +#ifndef MAXIMUM_STEPPER_RATE + #if HAS_DRIVER(TB6560) + #define MAXIMUM_STEPPER_RATE 15000 + #elif HAS_DRIVER(LV8729) + #define MAXIMUM_STEPPER_RATE 130000 + #elif HAS_DRIVER(TB6600) + #define MAXIMUM_STEPPER_RATE 150000 + #elif HAS_DRIVER(DRV8825) + #define MAXIMUM_STEPPER_RATE 250000 + #elif HAS_TRINAMIC || HAS_DRIVER(TMC2660) || HAS_DRIVER(TMC2130_STANDALONE) || HAS_DRIVER(TMC2208_STANDALONE) || HAS_DRIVER(TMC26X_STANDALONE) || HAS_DRIVER(TMC2660_STANDALONE) + #define MAXIMUM_STEPPER_RATE 400000 + #elif HAS_DRIVER(A4988) + #define MAXIMUM_STEPPER_RATE 500000 + #else + #define MAXIMUM_STEPPER_RATE 500000 + #endif +#endif + /** * X_DUAL_ENDSTOPS endstop reassignment */ @@ -660,28 +729,42 @@ #define HAS_E4_MICROSTEPS (PIN_EXISTS(E4_MS1)) #define HAS_SOLENOID_4 (PIN_EXISTS(SOL4)) +#if ENABLED(HANGPRINTER) + #define HAS_A_ENABLE (PIN_EXISTS(A_ENABLE)) + #define HAS_A_DIR (PIN_EXISTS(A_DIR)) + #define HAS_A_STEP (PIN_EXISTS(A_STEP)) + #define HAS_A_MICROSTEPS (PIN_EXISTS(A_MS1)) + + #define HAS_B_ENABLE (PIN_EXISTS(B_ENABLE)) + #define HAS_B_DIR (PIN_EXISTS(B_DIR)) + #define HAS_B_STEP (PIN_EXISTS(B_STEP)) + #define HAS_B_MICROSTEPS (PIN_EXISTS(B_MS1)) + + #define HAS_C_ENABLE (PIN_EXISTS(C_ENABLE)) + #define HAS_C_DIR (PIN_EXISTS(C_DIR)) + #define HAS_C_STEP (PIN_EXISTS(C_STEP)) + #define HAS_C_MICROSTEPS (PIN_EXISTS(C_MS1)) + + #define HAS_D_ENABLE (PIN_EXISTS(D_ENABLE)) + #define HAS_D_DIR (PIN_EXISTS(D_DIR)) + #define HAS_D_STEP (PIN_EXISTS(D_STEP)) + #define HAS_D_MICROSTEPS (PIN_EXISTS(D_MS1)) +#endif + // Trinamic Stepper Drivers -#define HAS_TRINAMIC (ENABLED(HAVE_TMC2130) || ENABLED(HAVE_TMC2208) || ENABLED(IS_TRAMS)) -#define X_IS_TRINAMIC (ENABLED( X_IS_TMC2130) || ENABLED( X_IS_TMC2208) || ENABLED(IS_TRAMS)) -#define X2_IS_TRINAMIC (ENABLED(X2_IS_TMC2130) || ENABLED(X2_IS_TMC2208)) -#define Y_IS_TRINAMIC (ENABLED( Y_IS_TMC2130) || ENABLED( Y_IS_TMC2208) || ENABLED(IS_TRAMS)) -#define Y2_IS_TRINAMIC (ENABLED(Y2_IS_TMC2130) || ENABLED(Y2_IS_TMC2208)) -#define Z_IS_TRINAMIC (ENABLED( Z_IS_TMC2130) || ENABLED( Z_IS_TMC2208) || ENABLED(IS_TRAMS)) -#define Z2_IS_TRINAMIC (ENABLED(Z2_IS_TMC2130) || ENABLED(Z2_IS_TMC2208)) -#define E0_IS_TRINAMIC (ENABLED(E0_IS_TMC2130) || ENABLED(E0_IS_TMC2208) || ENABLED(IS_TRAMS)) -#define E1_IS_TRINAMIC (ENABLED(E1_IS_TMC2130) || ENABLED(E1_IS_TMC2208)) -#define E2_IS_TRINAMIC (ENABLED(E2_IS_TMC2130) || ENABLED(E2_IS_TMC2208)) -#define E3_IS_TRINAMIC (ENABLED(E3_IS_TMC2130) || ENABLED(E3_IS_TMC2208)) -#define E4_IS_TRINAMIC (ENABLED(E4_IS_TMC2130) || ENABLED(E4_IS_TMC2208)) +#define HAS_STEALTHCHOP (HAS_DRIVER(TMC2130) || HAS_DRIVER(TMC2208)) +#define HAS_STALLGUARD HAS_DRIVER(TMC2130) +#define AXIS_HAS_STEALTHCHOP(ST) ( AXIS_DRIVER_TYPE(ST, TMC2130) || AXIS_DRIVER_TYPE(ST, TMC2208) ) +#define AXIS_HAS_STALLGUARD(ST) AXIS_DRIVER_TYPE(ST, TMC2130) #if ENABLED(SENSORLESS_HOMING) // Disable Z axis sensorless homing if a probe is used to home the Z axis #if HOMING_Z_WITH_PROBE #undef Z_HOMING_SENSITIVITY #endif - #define X_SENSORLESS (ENABLED(X_IS_TMC2130) && defined(X_HOMING_SENSITIVITY)) - #define Y_SENSORLESS (ENABLED(Y_IS_TMC2130) && defined(Y_HOMING_SENSITIVITY)) - #define Z_SENSORLESS (ENABLED(Z_IS_TMC2130) && defined(Z_HOMING_SENSITIVITY)) + #define X_SENSORLESS (AXIS_HAS_STALLGUARD(X) && defined(X_HOMING_SENSITIVITY)) + #define Y_SENSORLESS (AXIS_HAS_STALLGUARD(Y) && defined(Y_HOMING_SENSITIVITY)) + #define Z_SENSORLESS (AXIS_HAS_STALLGUARD(Z) && defined(Z_HOMING_SENSITIVITY)) #endif // Endstops and bed probe @@ -1233,13 +1316,19 @@ #define Z_HOMING_HEIGHT Z_CLEARANCE_BETWEEN_PROBES #endif #endif -#ifndef Z_CLEARANCE_BETWEEN_PROBES - #define Z_CLEARANCE_BETWEEN_PROBES Z_HOMING_HEIGHT -#endif -#if Z_CLEARANCE_BETWEEN_PROBES > Z_HOMING_HEIGHT - #define MANUAL_PROBE_HEIGHT Z_CLEARANCE_BETWEEN_PROBES -#else - #define MANUAL_PROBE_HEIGHT Z_HOMING_HEIGHT + +#if PROBE_SELECTED + #ifndef Z_CLEARANCE_BETWEEN_PROBES + #define Z_CLEARANCE_BETWEEN_PROBES Z_HOMING_HEIGHT + #endif + #if Z_CLEARANCE_BETWEEN_PROBES > Z_HOMING_HEIGHT + #define MANUAL_PROBE_HEIGHT Z_CLEARANCE_BETWEEN_PROBES + #else + #define MANUAL_PROBE_HEIGHT Z_HOMING_HEIGHT + #endif + #ifndef Z_CLEARANCE_MULTI_PROBE + #define Z_CLEARANCE_MULTI_PROBE Z_CLEARANCE_BETWEEN_PROBES + #endif #endif // Updated G92 behavior shifts the workspace @@ -1312,4 +1401,17 @@ #define HAS_FOLDER_SORTING (FOLDER_SORTING || ENABLED(SDSORT_GCODE)) #endif +/** + * MOV_AXIS: number of independent axes driving the tool head's translational movement + * NUM_AXIS: number of movement axes + 1 + * NUM_AXIS_N: number of movement axes + number of extruders (defined elsewhere) + */ +#if ENABLED(HANGPRINTER) + #define MOV_AXIS ABCD + #define NUM_AXIS ABCDE +#else + #define MOV_AXIS XYZ + #define NUM_AXIS XYZE +#endif + #endif // CONDITIONALS_POST_H diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index d12d36fccf..8c48b2e21e 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -6,7 +6,7 @@ // CUSTOMIZE FOR YOUR MACHINE BELOW /** - * Enable if you replace the stepper drivers with TMC 2208. Be sure to remove MS3 jumper + * Enable if you replace the stepper drivers with TMC 2208. Be sure to remove MS3 jumper * underneath the stepper driver! Plug and Play will result in Stealth Chop 2 Mode enabled * Stealthchop with 2208 on E will disabe inear Advance! Please enable stealthchop if * you require Linear Advance with a TMC2208 on the extruder! @@ -30,6 +30,7 @@ * Enable if you install a filament runout sensor from www.formbotusa.com */ //#define RunoutSensor +//#define ledgeFilSensor //Modify filament sensor contact type for TM3D V2 sensors /** * Enable if you wish to change the auto level strategy to Unified Bed Leveling. Under CUSTOM COMMANDS, run Step 1 and 2 before setting Z Offset @@ -952,7 +953,11 @@ #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_PIN 57 - #define FIL_RUNOUT_INVERTING true // set to true to invert the logic of the sensor. + #if ENABLED(ledgeFilSensor) + #define FIL_RUNOUT_INVERTING false // set to true to invert the logic of the sensor. + #else + #define FIL_RUNOUT_INVERTING true // set to true to invert the logic of the sensor. + #endif #define FIL_RUNOUT_PULLUP // Use internal pullup for filament runout pins. #define FILAMENT_RUNOUT_SCRIPT "M600" #endif @@ -1141,7 +1146,7 @@ #endif // Add a menu item to move between bed corners for manual bed adjustment -//#define LEVEL_BED_CORNERS +#define LEVEL_BED_CORNERS /** * Commands to execute at the end of G29 probing. diff --git a/Marlin/G26_Mesh_Validation_Tool.cpp b/Marlin/G26_Mesh_Validation_Tool.cpp index 8a3f951c8c..1d902f8dce 100644 --- a/Marlin/G26_Mesh_Validation_Tool.cpp +++ b/Marlin/G26_Mesh_Validation_Tool.cpp @@ -198,7 +198,7 @@ destination[X_AXIS] = current_position[X_AXIS]; destination[Y_AXIS] = current_position[Y_AXIS]; destination[Z_AXIS] = z; // We know the last_z==z or we wouldn't be in this block of code. - destination[E_AXIS] = current_position[E_AXIS]; + destination[E_CART] = current_position[E_CART]; G26_line_to_destination(feed_value); set_destination_from_current(); @@ -212,7 +212,7 @@ destination[X_AXIS] = rx; destination[Y_AXIS] = ry; - destination[E_AXIS] += e_delta; + destination[E_CART] += e_delta; G26_line_to_destination(feed_value); set_destination_from_current(); @@ -254,7 +254,7 @@ while (!is_lcd_clicked()) { lcd_chirp(); - destination[E_AXIS] += 0.25; + destination[E_CART] += 0.25; #ifdef PREVENT_LENGTHY_EXTRUDE Total_Prime += 0.25; if (Total_Prime >= EXTRUDE_MAXLENGTH) return G26_ERR; @@ -283,7 +283,7 @@ lcd_quick_feedback(true); #endif set_destination_from_current(); - destination[E_AXIS] += g26_prime_length; + destination[E_CART] += g26_prime_length; G26_line_to_destination(planner.max_feedrate_mm_s[E_AXIS] / 15.0); set_destination_from_current(); retract_filament(destination); @@ -697,7 +697,7 @@ if (turn_on_heaters() != G26_OK) goto LEAVE; - current_position[E_AXIS] = 0.0; + current_position[E_CART] = 0.0; sync_plan_position_e(); if (g26_prime_flag && prime_nozzle() != G26_OK) goto LEAVE; @@ -812,7 +812,7 @@ const float endpoint[XYZE] = { ex, ey, g26_layer_height, - current_position[E_AXIS] + (arc_length * g26_e_axis_feedrate * g26_extrusion_multiplier) + current_position[E_CART] + (arc_length * g26_e_axis_feedrate * g26_extrusion_multiplier) }; if (dist_start > 2.0) { diff --git a/Marlin/HAL.h b/Marlin/HAL.h index bb985881c9..d5f79cd0f7 100644 --- a/Marlin/HAL.h +++ b/Marlin/HAL.h @@ -152,8 +152,6 @@ FORCE_INLINE void HAL_timer_start(const uint8_t timer_num, const uint32_t freque #define _CAT(a, ...) a ## __VA_ARGS__ #define HAL_timer_set_compare(timer, compare) (_CAT(TIMER_OCR_, timer) = compare) -#define HAL_timer_restrain(timer, interval_ticks) NOLESS(_CAT(TIMER_OCR_, timer), _CAT(TIMER_COUNTER_, timer) + interval_ticks) - #define HAL_timer_get_compare(timer) _CAT(TIMER_OCR_, timer) #define HAL_timer_get_count(timer) _CAT(TIMER_COUNTER_, timer) @@ -327,7 +325,8 @@ inline void HAL_adc_init(void) { #define HAL_START_ADC(pin) ADCSRB = 0; SET_ADMUX_ADCSRA(pin) #endif -#define HAL_READ_ADC ADC +#define HAL_READ_ADC() ADC +#define HAL_ADC_READY() !TEST(ADCSRA, ADSC) #define GET_PIN_MAP_PIN(index) index #define GET_PIN_MAP_INDEX(pin) pin diff --git a/Marlin/Makefile b/Marlin/Makefile index dfa65b7601..68fd055ab1 100644 --- a/Marlin/Makefile +++ b/Marlin/Makefile @@ -530,9 +530,8 @@ CSTANDARD = -std=gnu99 CXXSTANDARD = -std=gnu++11 CDEBUG = -g$(DEBUG) CWARN = -Wall -Wstrict-prototypes -CTUNING = -funsigned-char -funsigned-bitfields -fpack-struct \ - -fshort-enums -w -ffunction-sections -fdata-sections \ - -flto \ +CTUNING = -w -fsigned-char -funsigned-bitfields -fpack-struct \ + -fshort-enums -ffunction-sections -fdata-sections -flto \ -DARDUINO=$(ARDUINO_VERSION) ifneq ($(HARDWARE_MOTHERBOARD),) CTUNING += -DMOTHERBOARD=${HARDWARE_MOTHERBOARD} diff --git a/Marlin/Marlin.h b/Marlin/Marlin.h index ef4c0f2b06..46037b8455 100644 --- a/Marlin/Marlin.h +++ b/Marlin/Marlin.h @@ -96,7 +96,10 @@ extern const char axis_codes[XYZE]; /** * Mixing steppers synchronize their enable (and direction) together */ - #if MIXING_STEPPERS > 3 + #if MIXING_STEPPERS > 4 + #define enable_E0() { E0_ENABLE_WRITE( E_ENABLE_ON); E1_ENABLE_WRITE( E_ENABLE_ON); E2_ENABLE_WRITE( E_ENABLE_ON); E3_ENABLE_WRITE( E_ENABLE_ON); E4_ENABLE_WRITE( E_ENABLE_ON); } + #define disable_E0() { E0_ENABLE_WRITE(!E_ENABLE_ON); E1_ENABLE_WRITE(!E_ENABLE_ON); E2_ENABLE_WRITE(!E_ENABLE_ON); E3_ENABLE_WRITE(!E_ENABLE_ON); E4_ENABLE_WRITE(!E_ENABLE_ON); } + #elif MIXING_STEPPERS > 3 #define enable_E0() { E0_ENABLE_WRITE( E_ENABLE_ON); E1_ENABLE_WRITE( E_ENABLE_ON); E2_ENABLE_WRITE( E_ENABLE_ON); E3_ENABLE_WRITE( E_ENABLE_ON); } #define disable_E0() { E0_ENABLE_WRITE(!E_ENABLE_ON); E1_ENABLE_WRITE(!E_ENABLE_ON); E2_ENABLE_WRITE(!E_ENABLE_ON); E3_ENABLE_WRITE(!E_ENABLE_ON); } #elif MIXING_STEPPERS > 2 @@ -159,6 +162,42 @@ extern const char axis_codes[XYZE]; #endif // !MIXING_EXTRUDER +#if ENABLED(HANGPRINTER) + + #define enable_A() enable_X() + #define enable_B() enable_Y() + #define enable_C() enable_Z() + #define __D_ENABLE(p) E##p##_ENABLE_WRITE(E_ENABLE_ON) + #define _D_ENABLE(p) __D_ENABLE(p) + #define enable_D() _D_ENABLE(EXTRUDERS) + + // Don't allow any axes to be disabled + #undef disable_X + #undef disable_Y + #undef disable_Z + #define disable_X() NOOP + #define disable_Y() NOOP + #define disable_Z() NOOP + + #if EXTRUDERS >= 1 + #undef disable_E1 + #define disable_E1() NOOP + #if EXTRUDERS >= 2 + #undef disable_E2 + #define disable_E2() NOOP + #if EXTRUDERS >= 3 + #undef disable_E3 + #define disable_E3() NOOP + #if EXTRUDERS >= 4 + #undef disable_E4 + #define disable_E4() NOOP + #endif // EXTRUDERS >= 4 + #endif // EXTRUDERS >= 3 + #endif // EXTRUDERS >= 2 + #endif // EXTRUDERS >= 1 + +#endif // HANGPRINTER + #if ENABLED(G38_PROBE_TARGET) extern bool G38_move, // flag to tell the interrupt handler that a G38 command is being run G38_endstop_hit; // flag from the interrupt handler to indicate if the endstop went active @@ -193,8 +232,8 @@ extern bool Running; inline bool IsRunning() { return Running; } inline bool IsStopped() { return !Running; } -bool enqueue_and_echo_command(const char* cmd, bool say_ok=false); // Add a single command to the end of the buffer. Return false on failure. -void enqueue_and_echo_commands_P(const char * const cmd); // Set one or more commands to be prioritized over the next Serial/SD command. +bool enqueue_and_echo_command(const char* cmd); // Add a single command to the end of the buffer. Return false on failure. +void enqueue_and_echo_commands_P(const char * const cmd); // Set one or more commands to be prioritized over the next Serial/SD command. void clear_command_queue(); #if ENABLED(M100_FREE_MEMORY_WATCHER) || ENABLED(POWER_LOSS_RECOVERY) @@ -299,10 +338,18 @@ extern float soft_endstop_min[XYZ], soft_endstop_max[XYZ]; bool select_coordinate_system(const int8_t _new); #endif +void tool_change(const uint8_t tmp_extruder, const float fr_mm_s=0.0, bool no_move=false); + +void home_all_axes(); + void report_current_position(); #if IS_KINEMATIC - extern float delta[ABC]; + #if ENABLED(HANGPRINTER) + extern float line_lengths[ABCD]; + #else + extern float delta[ABC]; + #endif void inverse_kinematics(const float raw[XYZ]); #endif @@ -335,6 +382,51 @@ void report_current_position(); delta[C_AXIS] = DELTA_Z(V, C_AXIS); \ }while(0) +#elif ENABLED(HANGPRINTER) + + // Don't collect anchor positions in array because there are no A_x, D_x or D_y + extern float anchor_A_y, + anchor_A_z, + anchor_B_x, + anchor_B_y, + anchor_B_z, + anchor_C_x, + anchor_C_y, + anchor_C_z, + anchor_D_z, + delta_segments_per_second, + line_lengths_origin[ABCD]; + + void recalc_hangprinter_settings(); + + #define HANGPRINTER_IK(V) do { \ + line_lengths[A_AXIS] = SQRT(sq(anchor_A_z - V[Z_AXIS]) \ + + sq(anchor_A_y - V[Y_AXIS]) \ + + sq( V[X_AXIS])); \ + line_lengths[B_AXIS] = SQRT(sq(anchor_B_z - V[Z_AXIS]) \ + + sq(anchor_B_y - V[Y_AXIS]) \ + + sq(anchor_B_x - V[X_AXIS])); \ + line_lengths[C_AXIS] = SQRT(sq(anchor_C_z - V[Z_AXIS]) \ + + sq(anchor_C_y - V[Y_AXIS]) \ + + sq(anchor_C_x - V[X_AXIS])); \ + line_lengths[D_AXIS] = SQRT(sq( V[X_AXIS]) \ + + sq( V[Y_AXIS]) \ + + sq(anchor_D_z - V[Z_AXIS])); \ + }while(0) + + // Inverse kinematics at origin + #define HANGPRINTER_IK_ORIGIN(LL) do { \ + LL[A_AXIS] = SQRT(sq(anchor_A_z) \ + + sq(anchor_A_y)); \ + LL[B_AXIS] = SQRT(sq(anchor_B_z) \ + + sq(anchor_B_y) \ + + sq(anchor_B_x)); \ + LL[C_AXIS] = SQRT(sq(anchor_C_z) \ + + sq(anchor_C_y) \ + + sq(anchor_C_x)); \ + LL[D_AXIS] = anchor_D_z; \ + }while(0) + #elif IS_SCARA void forward_kinematics_SCARA(const float &a, const float &b); #endif @@ -499,6 +591,9 @@ void do_blocking_move_to_xy(const float &rx, const float &ry, const float &fr_mm inline bool position_is_reachable(const float &rx, const float &ry, const float inset=0) { #if ENABLED(DELTA) return HYPOT2(rx, ry) <= sq(DELTA_PRINTABLE_RADIUS - inset); + #elif ENABLED(HANGPRINTER) + // TODO: This is over simplified. Hangprinter's build volume is _not_ cylindrical. + return HYPOT2(rx, ry) <= sq(HANGPRINTER_PRINTABLE_RADIUS - inset); #elif IS_SCARA const float R2 = HYPOT2(rx - SCARA_OFFSET_X, ry - SCARA_OFFSET_Y); return ( diff --git a/Marlin/Marlin.ino b/Marlin/Marlin.ino index 1491c4efd5..e18a07b8cc 100644 --- a/Marlin/Marlin.ino +++ b/Marlin/Marlin.ino @@ -9,7 +9,7 @@ ================================================================================ -Greetings! Thank you for choosing Marlin 2 as your 3D printer firmware. +Greetings! Thank you for choosing Marlin as your 3D printer firmware. To configure Marlin you must edit Configuration.h and Configuration_adv.h located in the root 'Marlin' folder. Check the example_configurations folder to diff --git a/Marlin/MarlinConfig.h b/Marlin/MarlinConfig.h index f0aa130443..e1988fe637 100644 --- a/Marlin/MarlinConfig.h +++ b/Marlin/MarlinConfig.h @@ -28,6 +28,7 @@ #include "Version.h" #include "Configuration.h" #include "Conditionals_LCD.h" +#include "drivers.h" #include "Configuration_adv.h" #if USE_MARLINSERIAL diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 3897f79577..e116ec6f0a 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -51,6 +51,7 @@ * G3 - CCW ARC * G4 - Dwell S or P * G5 - Cubic B-spline with XYZE destination and IJPQ offsets + * G6 - Direct stepper move (Requires UNREGISTERED_MOVE_SUPPORT). Hangprinter defaults to relative moves. Others default to absolute moves. * G10 - Retract filament according to settings of M207 (Requires FWRETRACT) * G11 - Retract recover filament according to settings of M208 (Requires FWRETRACT) * G12 - Clean tool (Requires NOZZLE_CLEAN_FEATURE) @@ -72,6 +73,8 @@ * G90 - Use Absolute Coordinates * G91 - Use Relative Coordinates * G92 - Set current position to coordinates given + * G95 - Set torque mode (Requires MECHADUINO_I2C_COMMANDS enabled) + * G96 - Set encoder reference point (Requires MECHADUINO_I2C_COMMANDS enabled) * * "M" Codes * @@ -130,13 +133,14 @@ * M112 - Emergency stop. * M113 - Get or set the timeout interval for Host Keepalive "busy" messages. (Requires HOST_KEEPALIVE_FEATURE) * M114 - Report current position. + * - S1 Compute length traveled since last G96 using encoder position data (Requires MECHADUINO_I2C_COMMANDS, only kinematic axes) * M115 - Report capabilities. (Extended capabilities requires EXTENDED_CAPABILITIES_REPORT) * M117 - Display a message on the controller screen. (Requires an LCD) * M118 - Display a message in the host console. * M119 - Report endstops status. * M120 - Enable endstops detection. * M121 - Disable endstops detection. - * M122 - Debug stepper (Requires HAVE_TMC2130 or HAVE_TMC2208) + * M122 - Debug stepper (Requires at least one _DRIVER_TYPE defined as TMC2130/TMC2208/TMC2660) * M125 - Save current position and move to filament change position. (Requires PARK_HEAD_ON_PAUSE) * M126 - Solenoid Air Valve Open. (Requires BARICUDA) * M127 - Solenoid Air Valve Closed. (Requires BARICUDA) @@ -148,8 +152,8 @@ * M150 - Set Status LED Color as R U B P. Values 0-255. (Requires BLINKM, RGB_LED, RGBW_LED, NEOPIXEL_LED, or PCA9632). * M155 - Auto-report temperatures with interval of S. (Requires AUTO_REPORT_TEMPERATURES) * M163 - Set a single proportion for a mixing extruder. (Requires MIXING_EXTRUDER) - * M164 - Save the mix as a virtual extruder. (Requires MIXING_EXTRUDER and MIXING_VIRTUAL_TOOLS) - * M165 - Set the proportions for a mixing extruder. Use parameters ABCDHI to set the mixing factors. (Requires MIXING_EXTRUDER) + * M164 - Commit the mix (Req. MIXING_EXTRUDER) and optionally save as a virtual tool (Req. MIXING_VIRTUAL_TOOLS > 1) + * M165 - Set the mix for a mixing extruder wuth parameters ABCDHI. (Requires MIXING_EXTRUDER and DIRECT_MIXING_IN_G1) * M190 - Sxxx Wait for bed current temp to reach target temp. ** Waits only when heating! ** * Rxxx Wait for bed current temp to reach target temp. ** Waits for heating or cooling. ** * M200 - Set filament diameter, D, setting E axis units to cubic. (Use S0 to revert to linear units.) @@ -159,7 +163,7 @@ * M204 - Set default acceleration in units/sec^2: P R T * M205 - Set advanced settings. Current units apply: S T minimum speeds - B + Q X, Y, Z, E * M206 - Set additional homing offset. (Disabled by NO_WORKSPACE_OFFSETS or DELTA) * M207 - Set Retract Length: S, Feedrate: F, and Z lift: Z. (Requires FWRETRACT) @@ -206,7 +210,8 @@ * M600 - Pause for filament change: "M600 X Y Z E L". (Requires ADVANCED_PAUSE_FEATURE) * M603 - Configure filament change: "M603 T U L". (Requires ADVANCED_PAUSE_FEATURE) * M605 - Set Dual X-Carriage movement mode: "M605 S [X] [R]". (Requires DUAL_X_CARRIAGE) - * M665 - Set delta configurations: "M665 H L R S B X Y Z (Requires DELTA) + * M665 - Set Delta configurations: "M665 H L R S B X Y Z (Requires DELTA) + * M665 - Set Hangprinter configurations: "M665 W E R T Y U I O P S" (Requires HANGPRINTER) * M666 - Set/get endstop offsets for delta (Requires DELTA) or dual endstops (Requires [XYZ]_DUAL_ENDSTOPS). * M701 - Load filament (requires FILAMENT_LOAD_UNLOAD_GCODES) * M702 - Unload filament (requires FILAMENT_LOAD_UNLOAD_GCODES) @@ -223,13 +228,13 @@ * M868 - Report or set position encoder module error correction threshold. * M869 - Report position encoder module error. * M900 - Get or Set Linear Advance K-factor. (Requires LIN_ADVANCE) - * M906 - Set or get motor current in milliamps using axis codes X, Y, Z, E. Report values if no axis codes given. (Requires HAVE_TMC2130 or HAVE_TMC2208) + * M906 - Set or get motor current in milliamps using axis codes X, Y, Z, E. Report values if no axis codes given. (Requires at least one _DRIVER_TYPE defined as TMC2130/TMC2208/TMC2660) * M907 - Set digital trimpot motor current using axis codes. (Requires a board with digital trimpots) * M908 - Control digital trimpot directly. (Requires DAC_STEPPER_CURRENT or DIGIPOTSS_PIN) * M909 - Print digipot/DAC current value. (Requires DAC_STEPPER_CURRENT) * M910 - Commit digipot/DAC value to external EEPROM via I2C. (Requires DAC_STEPPER_CURRENT) - * M911 - Report stepper driver overtemperature pre-warn condition. (Requires HAVE_TMC2130 or HAVE_TMC2208) - * M912 - Clear stepper driver overtemperature pre-warn condition flag. (Requires HAVE_TMC2130 or HAVE_TMC2208) + * M911 - Report stepper driver overtemperature pre-warn condition. (Requires at least one _DRIVER_TYPE defined as TMC2130/TMC2208/TMC2660) + * M912 - Clear stepper driver overtemperature pre-warn condition flag. (Requires at least one _DRIVER_TYPE defined as TMC2130/TMC2208/TMC2660) * M913 - Set HYBRID_THRESHOLD speed. (Requires HYBRID_THRESHOLD) * M914 - Set SENSORLESS_HOMING sensitivity. (Requires SENSORLESS_HOMING) * @@ -437,12 +442,17 @@ static const char *injected_commands_P = NULL; * but the planner and stepper like mm/s units. */ static const float homing_feedrate_mm_s[] PROGMEM = { - #if ENABLED(DELTA) - MMM_TO_MMS(HOMING_FEEDRATE_Z), MMM_TO_MMS(HOMING_FEEDRATE_Z), + #if ENABLED(HANGPRINTER) + MMM_TO_MMS(DUMMY_HOMING_FEEDRATE), MMM_TO_MMS(DUMMY_HOMING_FEEDRATE), + MMM_TO_MMS(DUMMY_HOMING_FEEDRATE), MMM_TO_MMS(DUMMY_HOMING_FEEDRATE), 0 #else - MMM_TO_MMS(HOMING_FEEDRATE_XY), MMM_TO_MMS(HOMING_FEEDRATE_XY), + #if ENABLED(DELTA) + MMM_TO_MMS(HOMING_FEEDRATE_Z), MMM_TO_MMS(HOMING_FEEDRATE_Z), + #else + MMM_TO_MMS(HOMING_FEEDRATE_XY), MMM_TO_MMS(HOMING_FEEDRATE_XY), + #endif + MMM_TO_MMS(HOMING_FEEDRATE_Z), 0 #endif - MMM_TO_MMS(HOMING_FEEDRATE_Z), 0 }; FORCE_INLINE float homing_feedrate(const AxisEnum a) { return pgm_read_float(&homing_feedrate_mm_s[a]); } @@ -515,6 +525,13 @@ volatile bool wait_for_heatup = true; const char axis_codes[XYZE] = { 'X', 'Y', 'Z', 'E' }; +#if ENABLED(HANGPRINTER) + const char axis_codes_hangprinter[ABCDE] = { 'A', 'B', 'C', 'D', 'E' }; + #define RAW_AXIS_CODES(I) axis_codes_hangprinter[I] +#else + #define RAW_AXIS_CODES(I) axis_codes[I] +#endif + // Number of characters read in the current line of serial input static int serial_count; // = 0; @@ -617,6 +634,21 @@ uint8_t target_extruder; float delta_safe_distance_from_top(); +#elif ENABLED(HANGPRINTER) + + float anchor_A_y, + anchor_A_z, + anchor_B_x, + anchor_B_y, + anchor_B_z, + anchor_C_x, + anchor_C_y, + anchor_C_z, + anchor_D_z, + line_lengths[ABCD], + line_lengths_origin[ABCD], + delta_segments_per_second; + #endif #if ENABLED(AUTO_BED_LEVELING_BILINEAR) @@ -742,7 +774,6 @@ void set_current_from_steppers_for_axis(const AxisEnum axis); void plan_cubic_move(const float (&cart)[XYZE], const float (&offset)[4]); #endif -void tool_change(const uint8_t tmp_extruder, const float fr_mm_s=0.0, bool no_move=false); void report_current_position(); void report_current_position_detail(); @@ -770,14 +801,18 @@ void report_current_position_detail(); * * Set the planner/stepper positions directly from current_position with * no kinematic translation. Used for homing axes and cartesian/core syncing. + * + * This is not possible for Hangprinter because current_position and position are different sizes */ void sync_plan_position() { - #if ENABLED(DEBUG_LEVELING_FEATURE) - if (DEBUGGING(LEVELING)) DEBUG_POS("sync_plan_position", current_position); + #if DISABLED(HANGPRINTER) + #if ENABLED(DEBUG_LEVELING_FEATURE) + if (DEBUGGING(LEVELING)) DEBUG_POS("sync_plan_position", current_position); + #endif + planner.set_position_mm(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_CART]); #endif - planner.set_position_mm(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); } -void sync_plan_position_e() { planner.set_e_position_mm(current_position[E_AXIS]); } +void sync_plan_position_e() { planner.set_e_position_mm(current_position[E_CART]); } #if IS_KINEMATIC inline void sync_plan_position_kinematic() { @@ -799,10 +834,10 @@ extern "C" { int freeMemory() { int free_memory; - if ((int)__brkval == 0) - free_memory = ((int)&free_memory) - ((int)&__bss_end); + if (int(__brkval) == 0) + free_memory = (int(&free_memory)) - (int(&__bss_end)); else - free_memory = ((int)&free_memory) - ((int)__brkval); + free_memory = (int(&free_memory)) - (int(__brkval)); return free_memory; } } @@ -872,8 +907,8 @@ inline bool _enqueuecommand(const char* cmd, bool say_ok=false) { /** * Enqueue with Serial Echo */ -bool enqueue_and_echo_command(const char* cmd, bool say_ok/*=false*/) { - if (_enqueuecommand(cmd, say_ok)) { +bool enqueue_and_echo_command(const char* cmd) { + if (_enqueuecommand(cmd)) { SERIAL_ECHO_START(); SERIAL_ECHOPAIR(MSG_ENQUEUEING, cmd); SERIAL_CHAR('"'); @@ -1040,44 +1075,40 @@ inline void get_serial_commands() { gcode_N = strtol(npos + 1, NULL, 10); - if (gcode_N != gcode_LastN + 1 && !M110) { - gcode_line_error(PSTR(MSG_ERR_LINE_NO)); - return; - } + if (gcode_N != gcode_LastN + 1 && !M110) + return gcode_line_error(PSTR(MSG_ERR_LINE_NO)); char *apos = strrchr(command, '*'); if (apos) { uint8_t checksum = 0, count = uint8_t(apos - command); while (count) checksum ^= command[--count]; - if (strtol(apos + 1, NULL, 10) != checksum) { - gcode_line_error(PSTR(MSG_ERR_CHECKSUM_MISMATCH)); - return; - } - } - else { - gcode_line_error(PSTR(MSG_ERR_NO_CHECKSUM)); - return; + if (strtol(apos + 1, NULL, 10) != checksum) + return gcode_line_error(PSTR(MSG_ERR_CHECKSUM_MISMATCH)); } + else + return gcode_line_error(PSTR(MSG_ERR_NO_CHECKSUM)); gcode_LastN = gcode_N; } #if ENABLED(SDSUPPORT) - else if (card.saving) { - gcode_line_error(PSTR(MSG_ERR_NO_CHECKSUM)); - return; - } + else if (card.saving && strcmp(command, "M29") != 0) // No line number with M29 in Pronterface + return gcode_line_error(PSTR(MSG_ERR_NO_CHECKSUM)); #endif // Movement commands alert when stopped if (IsStopped()) { char* gpos = strchr(command, 'G'); if (gpos) { - const int codenum = strtol(gpos + 1, NULL, 10); - switch (codenum) { + switch (strtol(gpos + 1, NULL, 10)) { case 0: case 1: - case 2: - case 3: + #if ENABLED(ARC_SUPPORT) + case 2: + case 3: + #endif + #if ENABLED(BEZIER_CURVE_SUPPORT) + case 5: + #endif SERIAL_ERRORLNPGM(MSG_ERR_STOPPED); LCD_MESSAGEPGM(MSG_STOPPED); break; @@ -1330,7 +1361,7 @@ bool get_target_extruder_from_command(const uint16_t code) { if (axis == X_AXIS) { // In Dual X mode hotend_offset[X] is T1's home position - float dual_max_x = MAX(hotend_offset[X_AXIS][1], X2_MAX_POS); + const float dual_max_x = MAX(hotend_offset[X_AXIS][1], X2_MAX_POS); if (active_extruder != 0) { // T1 can move from X2_MIN_POS to X2_MAX_POS or X2 home position (whichever is larger) @@ -1554,9 +1585,13 @@ inline float get_homing_bump_feedrate(const AxisEnum axis) { /** * Move the planner to the current position from wherever it last moved * (or from wherever it has been told it is located). + * + * Impossible on Hangprinter because current_position and position are of different sizes */ inline void buffer_line_to_current_position() { - planner.buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], feedrate_mm_s, active_extruder); + #if DISABLED(HANGPRINTER) // emptying this function probably breaks do_blocking_move_to() + planner.buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_CART], feedrate_mm_s, active_extruder); + #endif } /** @@ -1564,7 +1599,11 @@ inline void buffer_line_to_current_position() { * used by G0/G1/G2/G3/G5 and many other functions to set a destination. */ inline void buffer_line_to_destination(const float &fr_mm_s) { - planner.buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], fr_mm_s, active_extruder); + #if ENABLED(HANGPRINTER) + UNUSED(fr_mm_s); + #else + planner.buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_CART], fr_mm_s, active_extruder); + #endif } #if IS_KINEMATIC @@ -1583,7 +1622,7 @@ inline void buffer_line_to_destination(const float &fr_mm_s) { if ( current_position[X_AXIS] == destination[X_AXIS] && current_position[Y_AXIS] == destination[Y_AXIS] && current_position[Z_AXIS] == destination[Z_AXIS] - && current_position[E_AXIS] == destination[E_AXIS] + && current_position[E_CART] == destination[E_CART] ) return; planner.buffer_line_kinematic(destination, MMS_SCALED(fr_mm_s ? fr_mm_s : feedrate_mm_s), active_extruder); @@ -2294,7 +2333,7 @@ void clean_up_after_endstop_or_probe_move() { #endif // move up to make clearance for the probe - do_blocking_move_to_z(current_position[Z_AXIS] + Z_CLEARANCE_BETWEEN_PROBES, MMM_TO_MMS(Z_PROBE_SPEED_FAST)); + do_blocking_move_to_z(current_position[Z_AXIS] + Z_CLEARANCE_MULTI_PROBE, MMM_TO_MMS(Z_PROBE_SPEED_FAST)); #else @@ -2328,7 +2367,7 @@ void clean_up_after_endstop_or_probe_move() { #if MULTIPLE_PROBING > 2 probes_total += current_position[Z_AXIS]; - if (p > 1) do_blocking_move_to_z(current_position[Z_AXIS] + Z_CLEARANCE_BETWEEN_PROBES, MMM_TO_MMS(Z_PROBE_SPEED_FAST)); + if (p > 1) do_blocking_move_to_z(current_position[Z_AXIS] + Z_CLEARANCE_MULTI_PROBE, MMM_TO_MMS(Z_PROBE_SPEED_FAST)); } #endif @@ -2482,6 +2521,8 @@ void clean_up_after_endstop_or_probe_move() { if (can_change && enable != planner.leveling_active) { + planner.synchronize(); + #if ENABLED(MESH_BED_LEVELING) if (!enable) @@ -2619,7 +2660,7 @@ void clean_up_after_endstop_or_probe_move() { for (uint8_t x = 0; x < sx; x++) { for (uint8_t i = 0; i < precision + 2 + (x < 10 ? 1 : 0); i++) SERIAL_PROTOCOLCHAR(' '); - SERIAL_PROTOCOL((int)x); + SERIAL_PROTOCOL(int(x)); } SERIAL_EOL(); #endif @@ -2631,14 +2672,14 @@ void clean_up_after_endstop_or_probe_move() { SERIAL_PROTOCOLPGM(" ["); // open sub-array #else if (y < 10) SERIAL_PROTOCOLCHAR(' '); - SERIAL_PROTOCOL((int)y); + SERIAL_PROTOCOL(int(y)); #endif for (uint8_t x = 0; x < sx; x++) { SERIAL_PROTOCOLCHAR(' '); const float offset = fn(x, y); if (!isnan(offset)) { if (offset >= 0) SERIAL_PROTOCOLCHAR('+'); - SERIAL_PROTOCOL_F(offset, precision); + SERIAL_PROTOCOL_F(offset, int(precision)); } else { #ifdef SCAD_MESH_OUTPUT @@ -2679,11 +2720,11 @@ void clean_up_after_endstop_or_probe_move() { if (DEBUGGING(LEVELING)) { SERIAL_ECHOPGM("Extrapolate ["); if (x < 10) SERIAL_CHAR(' '); - SERIAL_ECHO((int)x); + SERIAL_ECHO(int(x)); SERIAL_CHAR(xdir ? (xdir > 0 ? '+' : '-') : ' '); SERIAL_CHAR(' '); if (y < 10) SERIAL_CHAR(' '); - SERIAL_ECHO((int)y); + SERIAL_ECHO(int(y)); SERIAL_CHAR(ydir ? (ydir > 0 ? '+' : '-') : ' '); SERIAL_CHAR(']'); } @@ -2968,16 +3009,9 @@ static void do_homing_move(const AxisEnum axis, const float distance, const floa if (is_home_dir) { - if (axis == Z_AXIS) { - #if HOMING_Z_WITH_PROBE - #if ENABLED(BLTOUCH) - set_bltouch_deployed(true); - #endif - #if QUIET_PROBING - probing_pause(true); - #endif - #endif - } + #if HOMING_Z_WITH_PROBE && QUIET_PROBING + if (axis == Z_AXIS) probing_pause(true); + #endif // Disable stealthChop if used. Enable diag1 pin on driver. #if ENABLED(SENSORLESS_HOMING) @@ -2993,27 +3027,25 @@ static void do_homing_move(const AxisEnum axis, const float distance, const floa SYNC_PLAN_POSITION_KINEMATIC(); current_position[axis] = distance; inverse_kinematics(current_position); - planner.buffer_line(delta[A_AXIS], delta[B_AXIS], delta[C_AXIS], current_position[E_AXIS], fr_mm_s ? fr_mm_s : homing_feedrate(axis), active_extruder); + planner.buffer_line(delta[A_AXIS], delta[B_AXIS], delta[C_AXIS], current_position[E_CART], fr_mm_s ? fr_mm_s : homing_feedrate(axis), active_extruder); + #elif ENABLED(HANGPRINTER) // TODO: Hangprinter homing is not finished (Jan 7, 2018) + SYNC_PLAN_POSITION_KINEMATIC(); + current_position[axis] = distance; + inverse_kinematics(current_position); + planner.buffer_line(line_lengths[A_AXIS], line_lengths[B_AXIS], line_lengths[C_AXIS], line_lengths[D_AXIS], current_position[E_CART], fr_mm_s ? fr_mm_s : homing_feedrate(axis), active_extruder); #else sync_plan_position(); current_position[axis] = distance; // Set delta/cartesian axes directly - planner.buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], fr_mm_s ? fr_mm_s : homing_feedrate(axis), active_extruder); + planner.buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_CART], fr_mm_s ? fr_mm_s : homing_feedrate(axis), active_extruder); #endif planner.synchronize(); if (is_home_dir) { - if (axis == Z_AXIS) { - #if HOMING_Z_WITH_PROBE - #if QUIET_PROBING - probing_pause(false); - #endif - #if ENABLED(BLTOUCH) - set_bltouch_deployed(false); - #endif - #endif - } + #if HOMING_Z_WITH_PROBE && QUIET_PROBING + if (axis == Z_AXIS) probing_pause(false); + #endif endstops.validate_homing_move(); @@ -3095,8 +3127,19 @@ static void homeaxis(const AxisEnum axis) { #if ENABLED(DEBUG_LEVELING_FEATURE) if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("Home 1 Fast:"); #endif + + #if HOMING_Z_WITH_PROBE && ENABLED(BLTOUCH) + // BLTOUCH needs to be deployed every time + if (axis == Z_AXIS && set_bltouch_deployed(true)) return; + #endif + do_homing_move(axis, 1.5f * max_length(axis) * axis_home_dir); + #if HOMING_Z_WITH_PROBE && ENABLED(BLTOUCH) + // BLTOUCH needs to be stowed after trigger to rearm itself + if (axis == Z_AXIS) set_bltouch_deployed(false); + #endif + // When homing Z with probe respect probe clearance const float bump = axis_home_dir * ( #if HOMING_Z_WITH_PROBE @@ -3121,7 +3164,18 @@ static void homeaxis(const AxisEnum axis) { #if ENABLED(DEBUG_LEVELING_FEATURE) if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("Home 2 Slow:"); #endif + + #if HOMING_Z_WITH_PROBE && ENABLED(BLTOUCH) + // BLTOUCH needs to be deployed every time + if (axis == Z_AXIS && set_bltouch_deployed(true)) return; + #endif + do_homing_move(axis, 2 * bump, get_homing_bump_feedrate(axis)); + + #if HOMING_Z_WITH_PROBE && ENABLED(BLTOUCH) + // BLTOUCH needs to be stowed after trigger to rearm itself + if (axis == Z_AXIS) set_bltouch_deployed(false); + #endif } /** @@ -3132,28 +3186,34 @@ static void homeaxis(const AxisEnum axis) { #if ENABLED(X_DUAL_ENDSTOPS) if (axis == X_AXIS) { const float adj = ABS(endstops.x_endstop_adj); - if (pos_dir ? (endstops.x_endstop_adj > 0) : (endstops.x_endstop_adj < 0)) stepper.set_x_lock(true); else stepper.set_x2_lock(true); - do_homing_move(axis, pos_dir ? -adj : adj); - stepper.set_x_lock(false); - stepper.set_x2_lock(false); + if (adj) { + if (pos_dir ? (endstops.x_endstop_adj > 0) : (endstops.x_endstop_adj < 0)) stepper.set_x_lock(true); else stepper.set_x2_lock(true); + do_homing_move(axis, pos_dir ? -adj : adj); + stepper.set_x_lock(false); + stepper.set_x2_lock(false); + } } #endif #if ENABLED(Y_DUAL_ENDSTOPS) if (axis == Y_AXIS) { const float adj = ABS(endstops.y_endstop_adj); - if (pos_dir ? (endstops.y_endstop_adj > 0) : (endstops.y_endstop_adj < 0)) stepper.set_y_lock(true); else stepper.set_y2_lock(true); - do_homing_move(axis, pos_dir ? -adj : adj); - stepper.set_y_lock(false); - stepper.set_y2_lock(false); + if (adj) { + if (pos_dir ? (endstops.y_endstop_adj > 0) : (endstops.y_endstop_adj < 0)) stepper.set_y_lock(true); else stepper.set_y2_lock(true); + do_homing_move(axis, pos_dir ? -adj : adj); + stepper.set_y_lock(false); + stepper.set_y2_lock(false); + } } #endif #if ENABLED(Z_DUAL_ENDSTOPS) if (axis == Z_AXIS) { const float adj = ABS(endstops.z_endstop_adj); - if (pos_dir ? (endstops.z_endstop_adj > 0) : (endstops.z_endstop_adj < 0)) stepper.set_z_lock(true); else stepper.set_z2_lock(true); - do_homing_move(axis, pos_dir ? -adj : adj); - stepper.set_z_lock(false); - stepper.set_z2_lock(false); + if (adj) { + if (pos_dir ? (endstops.z_endstop_adj > 0) : (endstops.z_endstop_adj < 0)) stepper.set_z_lock(true); else stepper.set_z2_lock(true); + do_homing_move(axis, pos_dir ? -adj : adj); + stepper.set_z_lock(false); + stepper.set_z2_lock(false); + } } #endif stepper.set_homing_dual_axis(false); @@ -3216,11 +3276,12 @@ static void homeaxis(const AxisEnum axis) { void normalize_mix() { float mix_total = 0.0; - for (uint8_t i = 0; i < MIXING_STEPPERS; i++) mix_total += RECIPROCAL(mixing_factor[i]); + for (uint8_t i = 0; i < MIXING_STEPPERS; i++) mix_total += mixing_factor[i]; // Scale all values if they don't add up to ~1.0 if (!NEAR(mix_total, 1.0)) { SERIAL_PROTOCOLLNPGM("Warning: Mix factors must add up to 1.0. Scaling."); - for (uint8_t i = 0; i < MIXING_STEPPERS; i++) mixing_factor[i] *= mix_total; + const float inverse_sum = RECIPROCAL(mix_total); + for (uint8_t i = 0; i < MIXING_STEPPERS; i++) mixing_factor[i] *= inverse_sum; } } @@ -3229,14 +3290,25 @@ static void homeaxis(const AxisEnum axis) { // The total "must" be 1.0 (but it will be normalized) // If no mix factors are given, the old mix is preserved void gcode_get_mix() { - const char* mixing_codes = "ABCDHI"; + const char mixing_codes[] = { 'A', 'B' + #if MIXING_STEPPERS > 2 + , 'C' + #if MIXING_STEPPERS > 3 + , 'D' + #if MIXING_STEPPERS > 4 + , 'H' + #if MIXING_STEPPERS > 5 + , 'I' + #endif // MIXING_STEPPERS > 5 + #endif // MIXING_STEPPERS > 4 + #endif // MIXING_STEPPERS > 3 + #endif // MIXING_STEPPERS > 2 + }; byte mix_bits = 0; for (uint8_t i = 0; i < MIXING_STEPPERS; i++) { if (parser.seenval(mixing_codes[i])) { SBI(mix_bits, i); - float v = parser.value_float(); - NOLESS(v, 0.0); - mixing_factor[i] = RECIPROCAL(v); + mixing_factor[i] = MAX(parser.value_float(), 0.0); } } // If any mixing factors were included, clear the rest @@ -3270,7 +3342,7 @@ void gcode_get_destination() { const float v = parser.value_axis_units((AxisEnum)i); destination[i] = (axis_relative_modes[i] || relative_mode) ? current_position[i] + v - : (i == E_AXIS) ? v : LOGICAL_TO_NATIVE(v, i); + : (i == E_CART) ? v : LOGICAL_TO_NATIVE(v, i); } else destination[i] = current_position[i]; @@ -3281,7 +3353,7 @@ void gcode_get_destination() { #if ENABLED(PRINTCOUNTER) if (!DEBUGGING(DRYRUN)) - print_job_timer.incFilamentUsed(destination[E_AXIS] - current_position[E_AXIS]); + print_job_timer.incFilamentUsed(destination[E_CART] - current_position[E_CART]); #endif // Get ABCDHI mixing factors @@ -3349,10 +3421,10 @@ inline void gcode_G0_G1( if (MIN_AUTORETRACT <= MAX_AUTORETRACT) { // When M209 Autoretract is enabled, convert E-only moves to firmware retract/prime moves if (fwretract.autoretract_enabled && parser.seen('E') && !(parser.seen('X') || parser.seen('Y') || parser.seen('Z'))) { - const float echange = destination[E_AXIS] - current_position[E_AXIS]; + const float echange = destination[E_CART] - current_position[E_CART]; // Is this a retract or prime move? if (WITHIN(ABS(echange), MIN_AUTORETRACT, MAX_AUTORETRACT) && fwretract.retracted[active_extruder] == (echange > 0.0)) { - current_position[E_AXIS] = destination[E_AXIS]; // Hide a G1-based retract/prime from calculations + current_position[E_CART] = destination[E_CART]; // Hide a G1-based retract/prime from calculations sync_plan_position_e(); // AND from the planner return fwretract.retract(echange < 0.0); // Firmware-based retract/prime (double-retract ignored) } @@ -3540,6 +3612,74 @@ inline void gcode_G4() { #endif // BEZIER_CURVE_SUPPORT +#if ENABLED(UNREGISTERED_MOVE_SUPPORT) + + /** + * G6 implementation for Hangprinter based on + * http://reprap.org/wiki/GCodes#G6:_Direct_Stepper_Move + * Accessed Jan 8, 2018 + * + * G6 is used frequently to tighten lines with Hangprinter, so Hangprinter default is relative moves. + * Hangprinter uses switches + * S1 for absolute moves + * S2 for saving recording new line length after unregistered move + * (typically used while tuning LINE_BUILDUP_COMPENSATION_FEATURE parameters) + */ + + /** + * G6: Direct Stepper Move + */ + inline void gcode_G6() { + bool count_it = false; + #if ENABLED(NO_MOTION_BEFORE_HOMING) + if (axis_unhomed_error()) return; + #endif + if (IsRunning()) { + float go[MOV_AXIS] = { 0.0 }, + tmp_fr_mm_s = 0.0; + + LOOP_MOV_AXIS(i) + if (parser.seen(RAW_AXIS_CODES(i))) + go[i] = parser.value_axis_units((AxisEnum)i); + + #if ENABLED(HANGPRINTER) + #define GO_SRC line_lengths + #elif ENABLED(DELTA) + #define GO_SRC delta + #else + #define GO_SRC current_position + #endif + + if ( + #if ENABLED(HANGPRINTER) // Sending R to another machine is the same as not sending S1 to Hangprinter + parser.byteval('S') != 2 + #else + parser.seen('R') + #endif + ) + LOOP_MOV_AXIS(i) go[i] += GO_SRC[i]; + else + LOOP_MOV_AXIS(i) if (!parser.seen(RAW_AXIS_CODES(i))) go[i] += GO_SRC[i]; + + tmp_fr_mm_s = parser.linearval('F') > 0.0 ? MMM_TO_MMS(parser.value_feedrate()) : feedrate_mm_s; + + #if ENABLED(HANGPRINTER) + if (parser.byteval('S') == 2) { + LOOP_MOV_AXIS(i) line_lengths[i] = go[i]; + count_it = true; + } + #endif + + planner.buffer_segment(go[A_AXIS], go[B_AXIS], go[C_AXIS] + #if ENABLED(HANGPRINTER) + , go[D_AXIS] + #endif + , current_position[E_CART], tmp_fr_mm_s, active_extruder, 0.0, count_it + ); + } + } +#endif + #if ENABLED(FWRETRACT) /** @@ -3952,7 +4092,15 @@ inline void gcode_G4() { #endif } -#endif // DELTA +#elif ENABLED(HANGPRINTER) + /** + * A hangprinter cannot home itself + */ + inline void home_hangprinter() { + SERIAL_ECHOLNPGM("Warning: G28 is not implemented for Hangprinter."); + } + +#endif #ifdef Z_AFTER_PROBING void move_z_after_probing() { @@ -4102,6 +4250,7 @@ inline void gcode_G28(const bool always_home_all) { #endif #if ENABLED(BLTOUCH) + // Make sure any BLTouch error condition is cleared bltouch_command(BLTOUCH_RESET); set_bltouch_deployed(false); #endif @@ -4129,7 +4278,12 @@ inline void gcode_G28(const bool always_home_all) { home_delta(); UNUSED(always_home_all); - #else // NOT DELTA + #elif ENABLED(HANGPRINTER) + + home_hangprinter(); + UNUSED(always_home_all); + + #else // NOT Delta or Hangprinter const bool homeX = always_home_all || parser.seen('X'), homeY = always_home_all || parser.seen('Y'), @@ -4287,7 +4441,14 @@ void home_all_axes() { gcode_G28(true); } inline void _manual_goto_xy(const float &rx, const float &ry) { - #if MANUAL_PROBE_HEIGHT > 0 + #ifdef MANUAL_PROBE_START_Z + #if MANUAL_PROBE_HEIGHT > 0 + do_blocking_move_to(rx, ry, MANUAL_PROBE_HEIGHT); + do_blocking_move_to_z(MAX(0,MANUAL_PROBE_START_Z)); + #else + do_blocking_move_to(rx, ry, MAX(0,MANUAL_PROBE_START_Z)); + #endif + #elif MANUAL_PROBE_HEIGHT > 0 const float prev_z = current_position[Z_AXIS]; do_blocking_move_to(rx, ry, MANUAL_PROBE_HEIGHT); do_blocking_move_to_z(prev_z); @@ -4810,10 +4971,10 @@ void home_all_axes() { gcode_G28(true); } xy_probe_feedrate_mm_s = MMM_TO_MMS(parser.linearval('S', XY_PROBE_SPEED)); - left_probe_bed_position = parser.seenval('L') ? (int)RAW_X_POSITION(parser.value_linear_units()) : LEFT_PROBE_BED_POSITION; - right_probe_bed_position = parser.seenval('R') ? (int)RAW_X_POSITION(parser.value_linear_units()) : RIGHT_PROBE_BED_POSITION; - front_probe_bed_position = parser.seenval('F') ? (int)RAW_Y_POSITION(parser.value_linear_units()) : FRONT_PROBE_BED_POSITION; - back_probe_bed_position = parser.seenval('B') ? (int)RAW_Y_POSITION(parser.value_linear_units()) : BACK_PROBE_BED_POSITION; + left_probe_bed_position = parser.seenval('L') ? int(RAW_X_POSITION(parser.value_linear_units())) : LEFT_PROBE_BED_POSITION; + right_probe_bed_position = parser.seenval('R') ? int(RAW_X_POSITION(parser.value_linear_units())) : RIGHT_PROBE_BED_POSITION; + front_probe_bed_position = parser.seenval('F') ? int(RAW_Y_POSITION(parser.value_linear_units())) : FRONT_PROBE_BED_POSITION; + back_probe_bed_position = parser.seenval('B') ? int(RAW_Y_POSITION(parser.value_linear_units())) : BACK_PROBE_BED_POSITION; if ( #if IS_SCARA || ENABLED(DELTA) @@ -5650,7 +5811,7 @@ void home_all_axes() { gcode_G28(true); } #endif } - #if HAS_BED_PROBE + #if HAS_BED_PROBE && ENABLED(ULTIPANEL) static float probe_z_shift(const float center) { STOW_PROBE(); endstops.enable_z_probe(false); @@ -6034,7 +6195,7 @@ void home_all_axes() { gcode_G28(true); } switch (probe_points) { case -1: - #if HAS_BED_PROBE + #if HAS_BED_PROBE && ENABLED(ULTIPANEL) zprobe_zoffset += probe_z_shift(z_at_pt[CEN]); #endif @@ -6126,9 +6287,9 @@ void home_all_axes() { gcode_G28(true); } char mess[21]; strcpy_P(mess, PSTR("Calibration sd:")); if (zero_std_dev_min < 1) - sprintf_P(&mess[15], PSTR("0.%03i"), (int)LROUND(zero_std_dev_min * 1000.0)); + sprintf_P(&mess[15], PSTR("0.%03i"), int(LROUND(zero_std_dev_min * 1000.0))); else - sprintf_P(&mess[15], PSTR("%03i.x"), (int)LROUND(zero_std_dev_min)); + sprintf_P(&mess[15], PSTR("%03i.x"), int(LROUND(zero_std_dev_min))); lcd_setstatus(mess); print_calibration_settings(_endstop_results, _angle_results); serialprintPGM(save_message); @@ -6137,7 +6298,7 @@ void home_all_axes() { gcode_G28(true); } else { // !end iterations char mess[15]; if (iterations < 31) - sprintf_P(mess, PSTR("Iteration : %02i"), (int)iterations); + sprintf_P(mess, PSTR("Iteration : %02i"), int(iterations)); else strcpy_P(mess, PSTR("No convergence")); SERIAL_PROTOCOL(mess); @@ -6162,9 +6323,9 @@ void home_all_axes() { gcode_G28(true); } strcpy_P(mess, enddryrun); strcpy_P(&mess[11], PSTR(" sd:")); if (zero_std_dev < 1) - sprintf_P(&mess[15], PSTR("0.%03i"), (int)LROUND(zero_std_dev * 1000.0)); + sprintf_P(&mess[15], PSTR("0.%03i"), int(LROUND(zero_std_dev * 1000.0))); else - sprintf_P(&mess[15], PSTR("%03i.x"), (int)LROUND(zero_std_dev)); + sprintf_P(&mess[15], PSTR("%03i.x"), int(LROUND(zero_std_dev))); lcd_setstatus(mess); } ac_home(); @@ -6338,7 +6499,7 @@ inline void gcode_G92() { #endif bool didE = false; - #if IS_SCARA || !HAS_POSITION_SHIFT + #if IS_SCARA || !HAS_POSITION_SHIFT || ENABLED(HANGPRINTER) bool didXYZ = false; #else constexpr bool didXYZ = false; @@ -6347,16 +6508,20 @@ inline void gcode_G92() { if (IS_G92_0) LOOP_XYZE(i) { if (parser.seenval(axis_codes[i])) { const float l = parser.value_axis_units((AxisEnum)i), - v = i == E_AXIS ? l : LOGICAL_TO_NATIVE(l, i), + v = i == E_CART ? l : LOGICAL_TO_NATIVE(l, i), d = v - current_position[i]; - if (!NEAR_ZERO(d)) { - #if IS_SCARA || !HAS_POSITION_SHIFT - if (i == E_AXIS) didE = true; else didXYZ = true; + if (!NEAR_ZERO(d) + #if ENABLED(HANGPRINTER) + || true // Hangprinter needs to update its line lengths whether current_position changed or not + #endif + ) { + #if IS_SCARA || !HAS_POSITION_SHIFT || ENABLED(HANGPRINTER) + if (i == E_CART) didE = true; else didXYZ = true; current_position[i] = v; // Without workspaces revert to Marlin 1.0 behavior #elif HAS_POSITION_SHIFT - if (i == E_AXIS) { + if (i == E_CART) { didE = true; - current_position[E_AXIS] = v; // When using coordinate spaces, only E is set directly + current_position[E_CART] = v; // When using coordinate spaces, only E is set directly } else { position_shift[i] += d; // Other axes simply offset the coordinate space @@ -6380,6 +6545,184 @@ inline void gcode_G92() { report_current_position(); } +#if ENABLED(MECHADUINO_I2C_COMMANDS) + /** + * G95: Set torque mode + */ + inline void gcode_G95() { + i2cFloat torques[NUM_AXIS]; // Assumes 4-byte floats here and in Mechaduino firmware + LOOP_NUM_AXIS(i) + torques[i].fval = parser.floatval(RAW_AXIS_CODES(i), 999.9); // 999.9 chosen to satisfy fabs(999.9) > 255.0 + + // 0x5f == 95 + #define G95_SEND(LETTER) do { \ + if (fabs(torques[_AXIS(LETTER)].fval) < 255.0){ \ + torques[_AXIS(LETTER)].fval = -fabs(torques[_AXIS(LETTER)].fval); \ + if(!INVERT_##LETTER##_DIR) torques[_AXIS(LETTER)].fval = -torques[_AXIS(LETTER)].fval; \ + i2c.address(LETTER##_MOTOR_I2C_ADDR); \ + i2c.reset(); \ + i2c.addbyte(0x5f); \ + i2c.addbytes(torques[_AXIS(LETTER)].bval, sizeof(float)); \ + i2c.send(); \ + }} while(0) + + #if ENABLED(HANGPRINTER) + #if ENABLED(A_IS_MECHADUINO) + G95_SEND(A); + #endif + #if ENABLED(B_IS_MECHADUINO) + G95_SEND(B); + #endif + #if ENABLED(C_IS_MECHADUINO) + G95_SEND(C); + #endif + #if ENABLED(D_IS_MECHADUINO) + G95_SEND(D); + #endif + #else + #if ENABLED(X_IS_MECHADUINO) + G95_SEND(X); + #endif + #if ENABLED(Y_IS_MECHADUINO) + G95_SEND(Y); + #endif + #if ENABLED(Z_IS_MECHADUINO) + G95_SEND(Z); + #endif + #endif + #if ENABLED(E_IS_MECHADUINO) + G95_SEND(E); + #endif + } + + /** + * G96: Mark encoder reference point + */ + inline void gcode_G96() { + bool mark[NUM_AXIS] = { false }; + if (!parser.seen_any()) + LOOP_NUM_AXIS(i) + mark[i] = true; + else + LOOP_NUM_AXIS(i) + if (parser.seen(RAW_AXIS_CODES(i))) + mark[i] = true; + + // 0x60 == 96 + #define G96_SEND(LETTER) do {\ + if (mark[LETTER##_AXIS]){ \ + i2c.address(LETTER##_MOTOR_I2C_ADDR); \ + i2c.reset(); \ + i2c.addbyte(0x60); \ + i2c.send(); \ + }} while(0) + + #if ENABLED(HANGPRINTER) + #if ENABLED(A_IS_MECHADUINO) + G96_SEND(A); + #endif + #if ENABLED(B_IS_MECHADUINO) + G96_SEND(B); + #endif + #if ENABLED(C_IS_MECHADUINO) + G96_SEND(C); + #endif + #if ENABLED(D_IS_MECHADUINO) + G96_SEND(D); + #endif + #else + #if ENABLED(X_IS_MECHADUINO) + G96_SEND(X); + #endif + #if ENABLED(Y_IS_MECHADUINO) + G96_SEND(Y); + #endif + #if ENABLED(Z_IS_MECHADUINO) + G96_SEND(Z); + #endif + #endif + #if ENABLED(E_IS_MECHADUINO) + G96_SEND(E); // E ref point not used by any other commands (Feb 7, 2018) + #endif + } + + float ang_to_mm(float ang, const AxisEnum axis) { + const float abs_step_in_origin = + #if ENABLED(LINE_BUILDUP_COMPENSATION_FEATURE) + planner.k0[axis] * (SQRT(planner.k1[axis] + planner.k2[axis] * line_lengths_origin[axis]) - planner.sqrtk1[axis]) + #else + line_lengths_origin[axis] * planner.axis_steps_per_mm[axis] + #endif + ; + const float c = abs_step_in_origin + ang * float(STEPS_PER_MOTOR_REVOLUTION) / 360.0; // current step count + return + #if ENABLED(LINE_BUILDUP_COMPENSATION_FEATURE) + // Inverse function found in planner.cpp, where target[AXIS_A] is calculated + ((c / planner.k0[axis] + planner.sqrtk1[axis]) * (c / planner.k0[axis] + planner.sqrtk1[axis]) - planner.k1[axis]) / planner.k2[axis] - line_lengths_origin[axis] + #else + c / planner.axis_steps_per_mm[axis] - line_lengths_origin[axis] + #endif + ; + } + + void report_axis_position_from_encoder_data() { + i2cFloat ang; + + #define M114_S1_RECEIVE(LETTER) do { \ + i2c.address(LETTER##_MOTOR_I2C_ADDR); \ + i2c.request(sizeof(float)); \ + i2c.capture(ang.bval, sizeof(float)); \ + if(LETTER##_INVERT_REPORTED_ANGLE == INVERT_##LETTER##_DIR) ang.fval = -ang.fval; \ + SERIAL_PROTOCOL(ang_to_mm(ang.fval, LETTER##_AXIS)); \ + } while(0) + + SERIAL_CHAR('['); + #if ENABLED(HANGPRINTER) + #if ENABLED(A_IS_MECHADUINO) + M114_S1_RECEIVE(A); + #endif + #if ENABLED(B_IS_MECHADUINO) + SERIAL_PROTOCOLPGM(", "); + M114_S1_RECEIVE(B); + #endif + #if ENABLED(C_IS_MECHADUINO) + SERIAL_PROTOCOLPGM(", "); + M114_S1_RECEIVE(C); + #endif + #if ENABLED(D_IS_MECHADUINO) + SERIAL_PROTOCOLPGM(", "); + M114_S1_RECEIVE(D); + #endif + #else + #if ENABLED(X_IS_MECHADUINO) + M114_S1_RECEIVE(X); + #endif + #if ENABLED(Y_IS_MECHADUINO) + SERIAL_PROTOCOLPGM(", "); + M114_S1_RECEIVE(Y); + #endif + #if ENABLED(Z_IS_MECHADUINO) + SERIAL_PROTOCOLPGM(", "); + M114_S1_RECEIVE(Z); + #endif + #endif + SERIAL_CHAR(']'); + SERIAL_EOL(); + } + +#endif // MECHADUINO_I2C_COMMANDS + + +void report_xyz_from_stepper_position() { + get_cartesian_from_steppers(); // writes to cartes[XYZ] + SERIAL_CHAR('['); + SERIAL_PROTOCOL(cartes[X_AXIS]); + SERIAL_PROTOCOLPAIR(", ", cartes[Y_AXIS]); + SERIAL_PROTOCOLPAIR(", ", cartes[Z_AXIS]); + SERIAL_CHAR(']'); + SERIAL_EOL(); +} + #if HAS_RESUME_CONTINUE /** @@ -6575,7 +6918,7 @@ inline void gcode_M17() { void do_pause_e_move(const float &length, const float &fr) { set_destination_from_current(); - destination[E_AXIS] += length / planner.e_factor[active_extruder]; + destination[E_CART] += length / planner.e_factor[active_extruder]; planner.buffer_line_kinematic(destination, fr, active_extruder); set_current_from_destination(); planner.synchronize(); @@ -6876,11 +7219,9 @@ inline void gcode_M17() { if (retract && thermalManager.hotEnoughToExtrude(active_extruder)) do_pause_e_move(retract, PAUSE_PARK_RETRACT_FEEDRATE); - #if ENABLED(NO_MOTION_BEFORE_HOMING) - if (!axis_unhomed_error()) - #endif - // Park the nozzle by moving up by z_lift and then moving to (x_pos, y_pos) - Nozzle::park(2, park_point); + // Park the nozzle by moving up by z_lift and then moving to (x_pos, y_pos) + if (!axis_unhomed_error()) + Nozzle::park(2, park_point); // Unload the filament if (unload_length) @@ -7028,7 +7369,7 @@ inline void gcode_M17() { #endif // If resume_position is negative - if (resume_position[E_AXIS] < 0) do_pause_e_move(resume_position[E_AXIS], PAUSE_PARK_RETRACT_FEEDRATE); + if (resume_position[E_CART] < 0) do_pause_e_move(resume_position[E_CART], PAUSE_PARK_RETRACT_FEEDRATE); // Move XY to starting position, then Z do_blocking_move_to_xy(resume_position[X_AXIS], resume_position[Y_AXIS], NOZZLE_PARK_XY_FEEDRATE); @@ -7038,7 +7379,7 @@ inline void gcode_M17() { // Now all extrusion positions are resumed and ready to be confirmed // Set extruder to saved position - planner.set_e_position_mm((destination[E_AXIS] = current_position[E_AXIS] = resume_position[E_AXIS])); + planner.set_e_position_mm((destination[E_CART] = current_position[E_CART] = resume_position[E_CART])); #if ENABLED(FILAMENT_RUNOUT_SENSOR) runout.reset(); @@ -7290,6 +7631,7 @@ inline void protected_pin_err() { * * P Pin number (LED if omitted) * S Pin status from 0 - 255 + * I Flag to ignore Marlin's pin protection */ inline void gcode_M42() { if (!parser.seenval('S')) return; @@ -7298,7 +7640,7 @@ inline void gcode_M42() { const pin_t pin_number = parser.byteval('P', LED_PIN); if (pin_number < 0) return; - if (pin_is_protected(pin_number)) return protected_pin_err(); + if (!parser.boolval('I') && pin_is_protected(pin_number)) return protected_pin_err(); pinMode(pin_number, OUTPUT); digitalWrite(pin_number, pin_status); @@ -7793,7 +8135,7 @@ inline void gcode_M42() { if (verbose_level > 1) { SERIAL_PROTOCOL(n + 1); SERIAL_PROTOCOLPGM(" of "); - SERIAL_PROTOCOL((int)n_samples); + SERIAL_PROTOCOL(int(n_samples)); SERIAL_PROTOCOLPGM(": z: "); SERIAL_PROTOCOL_F(sample_set[n], 3); if (verbose_level > 2) { @@ -8074,8 +8416,9 @@ inline void gcode_M109() { if (target_extruder != active_extruder) return; #endif - const bool no_wait_for_cooling = parser.seenval('S'); - if (no_wait_for_cooling || parser.seenval('R')) { + const bool no_wait_for_cooling = parser.seenval('S'), + set_temp = no_wait_for_cooling || parser.seenval('R'); + if (set_temp) { const int16_t temp = parser.value_celsius(); thermalManager.setTargetHotend(temp, target_extruder); @@ -8108,12 +8451,13 @@ inline void gcode_M109() { #endif #endif } - else return; #if ENABLED(AUTOTEMP) planner.autotemp_M104_M109(); #endif + if (!set_temp) return; + #if TEMP_RESIDENCY_TIME > 0 millis_t residency_start_ms = 0; // Loop until the temperature has stabilized @@ -8592,12 +8936,12 @@ inline void gcode_M81() { /** * M82: Set E codes absolute (default) */ -inline void gcode_M82() { axis_relative_modes[E_AXIS] = false; } +inline void gcode_M82() { axis_relative_modes[E_CART] = false; } /** * M83: Set E codes relative while in Absolute Coordinates (G90) mode */ -inline void gcode_M83() { axis_relative_modes[E_AXIS] = true; } +inline void gcode_M83() { axis_relative_modes[E_CART] = true; } /** * M18, M84: Disable stepper motors @@ -8647,20 +8991,20 @@ inline void gcode_M85() { /** * M92: Set axis steps-per-unit for one or more axes, X, Y, Z, and E. + * (for Hangprinter: A, B, C, D, and E) * (Follows the same syntax as G92) * * With multiple extruders use T to specify which one. */ inline void gcode_M92() { - GET_TARGET_EXTRUDER(92); - LOOP_XYZE(i) { - if (parser.seen(axis_codes[i])) { + LOOP_NUM_AXIS(i) { + if (parser.seen(RAW_AXIS_CODES(i))) { if (i == E_AXIS) { const float value = parser.value_per_axis_unit((AxisEnum)(E_AXIS + TARGET_EXTRUDER)); if (value < 20) { - float factor = planner.axis_steps_per_mm[E_AXIS + TARGET_EXTRUDER] / value; // increase e constants if M92 E14 is given for netfab. + const float factor = planner.axis_steps_per_mm[E_AXIS + TARGET_EXTRUDER] / value; // increase e constants if M92 E14 is given for netfab. #if DISABLED(JUNCTION_DEVIATION) planner.max_jerk[E_AXIS] *= factor; #endif @@ -8670,6 +9014,11 @@ inline void gcode_M92() { planner.axis_steps_per_mm[E_AXIS + TARGET_EXTRUDER] = value; } else { + #if ENABLED(LINE_BUILDUP_COMPENSATION_FEATURE) + SERIAL_ECHOLNPGM("Warning: " + "M92 A, B, C, and D only affect acceleration planning " + "when BUILDUP_COMPENSATION_FEATURE is enabled."); + #endif planner.axis_steps_per_mm[i] = parser.value_per_axis_unit((AxisEnum)i); } } @@ -8681,14 +9030,18 @@ inline void gcode_M92() { * Output the current position to serial */ void report_current_position() { - SERIAL_PROTOCOLPGM("X:"); - SERIAL_PROTOCOL(LOGICAL_X_POSITION(current_position[X_AXIS])); - SERIAL_PROTOCOLPGM(" Y:"); - SERIAL_PROTOCOL(LOGICAL_Y_POSITION(current_position[Y_AXIS])); - SERIAL_PROTOCOLPGM(" Z:"); - SERIAL_PROTOCOL(LOGICAL_Z_POSITION(current_position[Z_AXIS])); - SERIAL_PROTOCOLPGM(" E:"); - SERIAL_PROTOCOL(current_position[E_AXIS]); + SERIAL_PROTOCOLPAIR("X:", LOGICAL_X_POSITION(current_position[X_AXIS])); + SERIAL_PROTOCOLPAIR(" Y:", LOGICAL_Y_POSITION(current_position[Y_AXIS])); + SERIAL_PROTOCOLPAIR(" Z:", LOGICAL_Z_POSITION(current_position[Z_AXIS])); + SERIAL_PROTOCOLPAIR(" E:", current_position[E_CART]); + + #if ENABLED(HANGPRINTER) + SERIAL_EOL(); + SERIAL_PROTOCOLPAIR("A:", line_lengths[A_AXIS]); + SERIAL_PROTOCOLPAIR(" B:", line_lengths[B_AXIS]); + SERIAL_PROTOCOLPAIR(" C:", line_lengths[C_AXIS]); + SERIAL_PROTOCOLLNPAIR(" D:", line_lengths[D_AXIS]); + #endif stepper.report_positions(); @@ -8753,9 +9106,9 @@ void report_current_position() { planner.synchronize(); SERIAL_PROTOCOLPGM("Stepper:"); - LOOP_XYZE(i) { + LOOP_NUM_AXIS(i) { SERIAL_CHAR(' '); - SERIAL_CHAR(axis_codes[i]); + SERIAL_CHAR(RAW_AXIS_CODES(i)); SERIAL_CHAR(':'); SERIAL_PROTOCOL(stepper.position((AxisEnum)i)); } @@ -8779,7 +9132,7 @@ void report_current_position() { from_steppers[X_AXIS] - leveled[X_AXIS], from_steppers[Y_AXIS] - leveled[Y_AXIS], from_steppers[Z_AXIS] - leveled[Z_AXIS], - from_steppers[E_AXIS] - current_position[E_AXIS] + from_steppers[E_CART] - current_position[E_CART] }; SERIAL_PROTOCOLPGM("Differ: "); report_xyze(diff); @@ -8792,13 +9145,19 @@ void report_current_position() { inline void gcode_M114() { #ifdef M114_DETAIL - if (parser.seen('D')) { - report_current_position_detail(); - return; - } + if (parser.seen('D')) return report_current_position_detail(); #endif planner.synchronize(); + + const uint16_t sval = parser.ushortval('S'); + + #if ENABLED(MECHADUINO_I2C_COMMANDS) + if (sval == 1) return report_axis_position_from_encoder_data(); + #endif + + if (sval == 2) return report_xyz_from_stepper_position(); + report_current_position(); } @@ -9094,8 +9453,8 @@ inline void gcode_M201() { GET_TARGET_EXTRUDER(201); - LOOP_XYZE(i) { - if (parser.seen(axis_codes[i])) { + LOOP_NUM_AXIS(i) { + if (parser.seen(RAW_AXIS_CODES(i))) { const uint8_t a = i + (i == E_AXIS ? TARGET_EXTRUDER : 0); planner.max_acceleration_mm_per_s2[a] = parser.value_axis_units((AxisEnum)a); } @@ -9122,8 +9481,8 @@ inline void gcode_M203() { GET_TARGET_EXTRUDER(203); - LOOP_XYZE(i) - if (parser.seen(axis_codes[i])) { + LOOP_NUM_AXIS(i) + if (parser.seen(RAW_AXIS_CODES(i))) { const uint8_t a = i + (i == E_AXIS ? TARGET_EXTRUDER : 0); planner.max_feedrate_mm_s[a] = parser.value_axis_units((AxisEnum)a); } @@ -9164,7 +9523,7 @@ inline void gcode_M204() { /** * M205: Set Advanced Settings * - * B = Min Segment Time (µs) + * Q = Min Segment Time (µs) * S = Min Feed Rate (units/s) * T = Min Travel Feed Rate (units/s) * X = Max X Jerk (units/sec^2) @@ -9174,7 +9533,7 @@ inline void gcode_M204() { * J = Junction Deviation (mm) (Requires JUNCTION_DEVIATION) */ inline void gcode_M205() { - if (parser.seen('B')) planner.min_segment_time_us = parser.value_ulong(); + if (parser.seen('Q')) planner.min_segment_time_us = parser.value_ulong(); if (parser.seen('S')) planner.min_feedrate_mm_s = parser.value_linear_units(); if (parser.seen('T')) planner.min_travel_feedrate_mm_s = parser.value_linear_units(); #if ENABLED(JUNCTION_DEVIATION) @@ -9190,15 +9549,22 @@ inline void gcode_M205() { } } #else - if (parser.seen('X')) planner.max_jerk[X_AXIS] = parser.value_linear_units(); - if (parser.seen('Y')) planner.max_jerk[Y_AXIS] = parser.value_linear_units(); - if (parser.seen('Z')) { - planner.max_jerk[Z_AXIS] = parser.value_linear_units(); - #if HAS_MESH - if (planner.max_jerk[Z_AXIS] <= 0.1f) - SERIAL_ECHOLNPGM("WARNING! Low Z Jerk may lead to unwanted pauses."); - #endif - } + #if ENABLED(HANGPRINTER) + if (parser.seen('A')) planner.max_jerk[A_AXIS] = parser.value_linear_units(); + if (parser.seen('B')) planner.max_jerk[B_AXIS] = parser.value_linear_units(); + if (parser.seen('C')) planner.max_jerk[C_AXIS] = parser.value_linear_units(); + if (parser.seen('D')) planner.max_jerk[D_AXIS] = parser.value_linear_units(); + #else + if (parser.seen('X')) planner.max_jerk[X_AXIS] = parser.value_linear_units(); + if (parser.seen('Y')) planner.max_jerk[Y_AXIS] = parser.value_linear_units(); + if (parser.seen('Z')) { + planner.max_jerk[Z_AXIS] = parser.value_linear_units(); + #if HAS_MESH + if (planner.max_jerk[Z_AXIS] <= 0.1f) + SERIAL_ECHOLNPGM("WARNING! Low Z Jerk may lead to unwanted pauses."); + #endif + } + #endif if (parser.seen('E')) planner.max_jerk[E_AXIS] = parser.value_linear_units(); #endif } @@ -9317,6 +9683,42 @@ inline void gcode_M205() { } } +#elif ENABLED(HANGPRINTER) + /** + * M665: Set HANGPRINTER settings + * + * Parameters: + * + * W[anchor_A_y] - A-anchor's y coordinate (see note) + * E[anchor_A_z] - A-anchor's z coordinate (see note) + * R[anchor_B_x] - B-anchor's x coordinate (see note) + * T[anchor_B_y] - B-anchor's y coordinate (see note) + * Y[anchor_B_z] - B-anchor's z coordinate (see note) + * U[anchor_C_x] - C-anchor's x coordinate (see note) + * I[anchor_C_y] - C-anchor's y coordinate (see note) + * O[anchor_C_z] - C-anchor's z coordinate (see note) + * P[anchor_D_z] - D-anchor's z coordinate (see note) + * S[segments-per-second] - Segments-per-second + * + * Note: All xyz coordinates are measured relative to the line's pivot point in the mover, + * when it is at its home position (nozzle in (0,0,0), and lines tight). + * The y-axis is defined to be horizontal right above/below the A-lines when mover is at home. + * The z-axis is along the vertical direction. + */ + inline void gcode_M665() { + if (parser.seen('W')) anchor_A_y = parser.value_float(); + if (parser.seen('E')) anchor_A_z = parser.value_float(); + if (parser.seen('R')) anchor_B_x = parser.value_float(); + if (parser.seen('T')) anchor_B_y = parser.value_float(); + if (parser.seen('Y')) anchor_B_z = parser.value_float(); + if (parser.seen('U')) anchor_C_x = parser.value_float(); + if (parser.seen('I')) anchor_C_y = parser.value_float(); + if (parser.seen('O')) anchor_C_z = parser.value_float(); + if (parser.seen('P')) anchor_D_z = parser.value_float(); + if (parser.seen('S')) delta_segments_per_second = parser.value_float(); + recalc_hangprinter_settings(); + } + #elif ENABLED(X_DUAL_ENDSTOPS) || ENABLED(Y_DUAL_ENDSTOPS) || ENABLED(Z_DUAL_ENDSTOPS) /** @@ -10734,7 +11136,7 @@ inline void gcode_M502() { inline void gcode_M605() { planner.synchronize(); - extruder_duplication_enabled = parser.intval('S') == (int)DXC_DUPLICATION_MODE; + extruder_duplication_enabled = parser.intval('S') == int(DXC_DUPLICATION_MODE); SERIAL_ECHO_START(); SERIAL_ECHOLNPAIR(MSG_DUPLICATION_MODE, extruder_duplication_enabled ? MSG_ON : MSG_OFF); } @@ -10880,31 +11282,60 @@ inline void gcode_M502() { #if ENABLED(MAX7219_GCODE) /** * M7219: Control the Max7219 LED matrix - * + * * I - Initialize (clear) the matrix + * F - Fill the matrix (set all bits) + * P - Dump the LEDs[] array values * C - Set a column to the 8-bit value V * R - Set a row to the 8-bit value V * X - X position of an LED to set or toggle * Y - Y position of an LED to set or toggle - * V - The 8-bit value or on/off state to set + * V - The potentially 32-bit value or on/off state to set + * (for example: a chain of 4 Max7219 devices can have 32 bit + * rows or columns depending upon rotation) */ inline void gcode_M7219() { - if (parser.seen('I')) - Max7219_Clear(); - else if (parser.seenval('R')) { - const uint8_t r = parser.value_int(); - Max7219_Set_Row(r, parser.byteval('V')); + if (parser.seen('I')) { + max7219.register_setup(); + max7219.clear(); + } + + if (parser.seen('F')) max7219.fill(); + + const uint32_t v = parser.ulongval('V'); + + if (parser.seenval('R')) { + const uint8_t r = parser.value_byte(); + max7219.set_row(r, v); } else if (parser.seenval('C')) { - const uint8_t c = parser.value_int(); - Max7219_Set_Column(c, parser.byteval('V')); + const uint8_t c = parser.value_byte(); + max7219.set_column(c, v); } else if (parser.seenval('X') || parser.seenval('Y')) { const uint8_t x = parser.byteval('X'), y = parser.byteval('Y'); if (parser.seenval('V')) - Max7219_LED_Set(x, y, parser.boolval('V')); + max7219.led_set(x, y, parser.boolval('V')); else - Max7219_LED_Toggle(x, y); + max7219.led_toggle(x, y); + } + else if (parser.seen('D')) { + const uint8_t line = parser.byteval('D') + (parser.byteval('U') << 3); + if (line < MAX7219_LINES) { + max7219.led_line[line] = v; + return max7219.refresh_line(line); + } + } + + if (parser.seen('P')) { + for (uint8_t r = 0; r < MAX7219_LINES; r++) { + SERIAL_ECHOPGM("led_line["); + if (r < 10) SERIAL_CHAR(' '); + SERIAL_ECHO(int(r)); + SERIAL_ECHOPGM("]="); + for (uint8_t b = 8; b--;) SERIAL_CHAR('0' + TEST(max7219.led_line[r], b)); + SERIAL_EOL(); + } } } #endif // MAX7219_GCODE @@ -10944,6 +11375,7 @@ inline void gcode_M502() { /** * M906: Set motor current in milliamps using axis codes X, Y, Z, E + * Uses axis codes A, B, C, D, E for Hangprinter * Report driver currents when no axis specified */ inline void gcode_M906() { @@ -10952,132 +11384,170 @@ inline void gcode_M502() { bool report = true; const uint8_t index = parser.byteval('I'); - LOOP_XYZE(i) if (uint16_t value = parser.intval(axis_codes[i])) { + LOOP_NUM_AXIS(i) if (uint16_t value = parser.intval(RAW_AXIS_CODES(i))) { + report = false; switch (i) { + // Assumes {A_AXIS, B_AXIS, C_AXIS} == {X_AXIS, Y_AXIS, Z_AXIS} case X_AXIS: - #if X_IS_TRINAMIC - if (index == 0) TMC_SET_CURRENT(X); + #if AXIS_IS_TMC(X) + if (index < 2) TMC_SET_CURRENT(X); #endif - #if X2_IS_TRINAMIC - if (index == 1) TMC_SET_CURRENT(X2); + #if AXIS_IS_TMC(X2) + if (!(index & 1)) TMC_SET_CURRENT(X2); #endif break; case Y_AXIS: - #if Y_IS_TRINAMIC - if (index == 0) TMC_SET_CURRENT(Y); + #if AXIS_IS_TMC(Y) + if (index < 2) TMC_SET_CURRENT(Y); #endif - #if Y2_IS_TRINAMIC - if (index == 1) TMC_SET_CURRENT(Y2); + #if AXIS_IS_TMC(Y2) + if (!(index & 1)) TMC_SET_CURRENT(Y2); #endif break; case Z_AXIS: - #if Z_IS_TRINAMIC - if (index == 0) TMC_SET_CURRENT(Z); + #if AXIS_IS_TMC(Z) + if (index < 2) TMC_SET_CURRENT(Z); #endif - #if Z2_IS_TRINAMIC - if (index == 1) TMC_SET_CURRENT(Z2); + #if AXIS_IS_TMC(Z2) + if (!(index & 1)) TMC_SET_CURRENT(Z2); #endif break; case E_AXIS: { if (get_target_extruder_from_command(906)) return; switch (target_extruder) { - #if E0_IS_TRINAMIC + #if AXIS_IS_TMC(E0) case 0: TMC_SET_CURRENT(E0); break; #endif - #if E1_IS_TRINAMIC - case 1: TMC_SET_CURRENT(E1); break; - #endif - #if E2_IS_TRINAMIC - case 2: TMC_SET_CURRENT(E2); break; - #endif - #if E3_IS_TRINAMIC - case 3: TMC_SET_CURRENT(E3); break; - #endif - #if E4_IS_TRINAMIC - case 4: TMC_SET_CURRENT(E4); break; + #if ENABLED(HANGPRINTER) + // Avoid setting the D-current + #if AXIS_IS_TMC(E1) && EXTRUDERS > 1 + case 1: TMC_SET_CURRENT(E1); break; + #endif + #if AXIS_IS_TMC(E2) && EXTRUDERS > 2 + case 2: TMC_SET_CURRENT(E2); break; + #endif + #if AXIS_IS_TMC(E3) && EXTRUDERS > 3 + case 3: TMC_SET_CURRENT(E3); break; + #endif + #if AXIS_IS_TMC(E4) && EXTRUDERS > 4 + case 4: TMC_SET_CURRENT(E4); break; + #endif + #else + #if AXIS_IS_TMC(E1) + case 1: TMC_SET_CURRENT(E1); break; + #endif + #if AXIS_IS_TMC(E2) + case 2: TMC_SET_CURRENT(E2); break; + #endif + #if AXIS_IS_TMC(E3) + case 3: TMC_SET_CURRENT(E3); break; + #endif + #if AXIS_IS_TMC(E4) + case 4: TMC_SET_CURRENT(E4); break; + #endif #endif } } break; + #if ENABLED(HANGPRINTER) + case D_AXIS: + // D is connected on the first of E1, E2, E3, E4 output that is not an extruder + #if AXIS_IS_TMC(E1) && EXTRUDERS == 1 + TMC_SET_CURRENT(E1); break; + #endif + #if AXIS_IS_TMC(E2) && EXTRUDERS == 2 + TMC_SET_CURRENT(E2); break; + #endif + #if AXIS_IS_TMC(E3) && EXTRUDERS == 3 + TMC_SET_CURRENT(E3); break; + #endif + #if AXIS_IS_TMC(E4) && EXTRUDERS == 4 + TMC_SET_CURRENT(E4); break; + #endif + #endif } } - if (report) LOOP_XYZE(i) switch (i) { - case X_AXIS: - #if X_IS_TRINAMIC - TMC_SAY_CURRENT(X); - #endif - #if X2_IS_TRINAMIC - TMC_SAY_CURRENT(X2); - #endif - break; - case Y_AXIS: - #if Y_IS_TRINAMIC - TMC_SAY_CURRENT(Y); - #endif - #if Y2_IS_TRINAMIC - TMC_SAY_CURRENT(Y2); - #endif - break; - case Z_AXIS: - #if Z_IS_TRINAMIC - TMC_SAY_CURRENT(Z); - #endif - #if Z2_IS_TRINAMIC - TMC_SAY_CURRENT(Z2); - #endif - break; - case E_AXIS: - #if E0_IS_TRINAMIC - TMC_SAY_CURRENT(E0); - #endif - #if E1_IS_TRINAMIC + if (report) { + #if AXIS_IS_TMC(X) + TMC_SAY_CURRENT(X); + #endif + #if AXIS_IS_TMC(X2) + TMC_SAY_CURRENT(X2); + #endif + #if AXIS_IS_TMC(Y) + TMC_SAY_CURRENT(Y); + #endif + #if AXIS_IS_TMC(Y2) + TMC_SAY_CURRENT(Y2); + #endif + #if AXIS_IS_TMC(Z) + TMC_SAY_CURRENT(Z); + #endif + #if AXIS_IS_TMC(Z2) + TMC_SAY_CURRENT(Z2); + #endif + #if AXIS_IS_TMC(E0) + TMC_SAY_CURRENT(E0); + #endif + #if ENABLED(HANGPRINTER) + // D is connected on the first of E1, E2, E3, E4 output that is not an extruder + #if AXIS_IS_TMC(E1) && EXTRUDERS == 1 TMC_SAY_CURRENT(E1); #endif - #if E2_IS_TRINAMIC + #if AXIS_IS_TMC(E2) && EXTRUDERS == 2 TMC_SAY_CURRENT(E2); #endif - #if E3_IS_TRINAMIC + #if AXIS_IS_TMC(E3) && EXTRUDERS == 3 TMC_SAY_CURRENT(E3); #endif - #if E4_IS_TRINAMIC + #if AXIS_IS_TMC(E4) && EXTRUDERS == 4 TMC_SAY_CURRENT(E4); #endif - break; + #else + #if AXIS_IS_TMC(E1) + TMC_SAY_CURRENT(E1); + #endif + #if AXIS_IS_TMC(E2) + TMC_SAY_CURRENT(E2); + #endif + #if AXIS_IS_TMC(E3) + TMC_SAY_CURRENT(E3); + #endif + #if AXIS_IS_TMC(E4) + TMC_SAY_CURRENT(E4); + #endif + #endif } } - #define M91x_USE(A) (ENABLED(A##_IS_TMC2130) || (ENABLED(A##_IS_TMC2208) && PIN_EXISTS(A##_SERIAL_RX))) + #define M91x_USE(ST) (AXIS_DRIVER_TYPE(ST, TMC2130) || (AXIS_DRIVER_TYPE(ST, TMC2208) && PIN_EXISTS(ST##_SERIAL_RX))) #define M91x_USE_E(N) (E_STEPPERS > N && M91x_USE(E##N)) - #define M91x_USE_X (ENABLED(IS_TRAMS) || M91x_USE(X)) - #define M91x_USE_Y (ENABLED(IS_TRAMS) || M91x_USE(Y)) - #define M91x_USE_Z (ENABLED(IS_TRAMS) || M91x_USE(Z)) - #define M91x_USE_E0 (ENABLED(IS_TRAMS) || M91x_USE_E(0)) /** * M911: Report TMC stepper driver overtemperature pre-warn flag * This flag is held by the library, persisting until cleared by M912 */ inline void gcode_M911() { - #if M91x_USE_X + #if M91x_USE(X) tmc_report_otpw(stepperX, TMC_X); #endif #if M91x_USE(X2) tmc_report_otpw(stepperX2, TMC_X2); #endif - #if M91x_USE_Y + #if M91x_USE(Y) tmc_report_otpw(stepperY, TMC_Y); #endif #if M91x_USE(Y2) tmc_report_otpw(stepperY2, TMC_Y2); #endif - #if M91x_USE_Z + #if M91x_USE(Z) tmc_report_otpw(stepperZ, TMC_Z); #endif #if M91x_USE(Z2) tmc_report_otpw(stepperZ2, TMC_Z2); #endif - #if M91x_USE_E0 + #if M91x_USE_E(0) tmc_report_otpw(stepperE0, TMC_E0); #endif #if M91x_USE_E(1) @@ -11110,12 +11580,12 @@ inline void gcode_M502() { const bool hasX = parser.seen(axis_codes[X_AXIS]), hasY = parser.seen(axis_codes[Y_AXIS]), hasZ = parser.seen(axis_codes[Z_AXIS]), - hasE = parser.seen(axis_codes[E_AXIS]), + hasE = parser.seen(axis_codes[E_CART]), hasNone = !hasX && !hasY && !hasZ && !hasE; - #if M91x_USE_X || M91x_USE(X2) + #if M91x_USE(X) || M91x_USE(X2) const uint8_t xval = parser.byteval(axis_codes[X_AXIS], 10); - #if M91x_USE_X + #if M91x_USE(X) if (hasNone || xval == 1 || (hasX && xval == 10)) tmc_clear_otpw(stepperX, TMC_X); #endif #if M91x_USE(X2) @@ -11123,9 +11593,9 @@ inline void gcode_M502() { #endif #endif - #if M91x_USE_Y || M91x_USE(Y2) + #if M91x_USE(Y) || M91x_USE(Y2) const uint8_t yval = parser.byteval(axis_codes[Y_AXIS], 10); - #if M91x_USE_Y + #if M91x_USE(Y) if (hasNone || yval == 1 || (hasY && yval == 10)) tmc_clear_otpw(stepperY, TMC_Y); #endif #if M91x_USE(Y2) @@ -11133,9 +11603,9 @@ inline void gcode_M502() { #endif #endif - #if M91x_USE_Z || M91x_USE(Z2) + #if M91x_USE(Z) || M91x_USE(Z2) const uint8_t zval = parser.byteval(axis_codes[Z_AXIS], 10); - #if M91x_USE_Z + #if M91x_USE(Z) if (hasNone || zval == 1 || (hasZ && zval == 10)) tmc_clear_otpw(stepperZ, TMC_Z); #endif #if M91x_USE(Z2) @@ -11143,9 +11613,10 @@ inline void gcode_M502() { #endif #endif - #if M91x_USE_E0 || M91x_USE_E(1) || M91x_USE_E(2) || M91x_USE_E(3) || M91x_USE_E(4) + // TODO: If this is a Hangprinter, E_AXIS will not correspond to E0, E1, etc in this way + #if M91x_USE_E(0) || M91x_USE_E(1) || M91x_USE_E(2) || M91x_USE_E(3) || M91x_USE_E(4) const uint8_t eval = parser.byteval(axis_codes[E_AXIS], 10); - #if M91x_USE_E0 + #if M91x_USE_E(0) if (hasNone || eval == 0 || (hasE && eval == 10)) tmc_clear_otpw(stepperE0, TMC_E0); #endif #if M91x_USE_E(1) @@ -11179,45 +11650,45 @@ inline void gcode_M502() { report = false; switch (i) { case X_AXIS: - #if X_IS_TRINAMIC - if (index == 0) TMC_SET_PWMTHRS(X,X); + #if AXIS_HAS_STEALTHCHOP(X) + if (index < 2) TMC_SET_PWMTHRS(X,X); #endif - #if X2_IS_TRINAMIC - if (index == 1) TMC_SET_PWMTHRS(X,X2); + #if AXIS_HAS_STEALTHCHOP(X2) + if (!(index & 1)) TMC_SET_PWMTHRS(X,X2); #endif break; case Y_AXIS: - #if Y_IS_TRINAMIC - if (index == 0) TMC_SET_PWMTHRS(Y,Y); + #if AXIS_HAS_STEALTHCHOP(Y) + if (index < 2) TMC_SET_PWMTHRS(Y,Y); #endif - #if Y2_IS_TRINAMIC - if (index == 1) TMC_SET_PWMTHRS(Y,Y2); + #if AXIS_HAS_STEALTHCHOP(Y2) + if (!(index & 1)) TMC_SET_PWMTHRS(Y,Y2); #endif break; case Z_AXIS: - #if Z_IS_TRINAMIC - if (index == 0) TMC_SET_PWMTHRS(Z,Z); + #if AXIS_HAS_STEALTHCHOP(Z) + if (index < 2) TMC_SET_PWMTHRS(Z,Z); #endif - #if Z2_IS_TRINAMIC - if (index == 1) TMC_SET_PWMTHRS(Z,Z2); + #if AXIS_HAS_STEALTHCHOP(Z2) + if (!(index & 1)) TMC_SET_PWMTHRS(Z,Z2); #endif break; - case E_AXIS: { + case E_CART: { if (get_target_extruder_from_command(913)) return; switch (target_extruder) { - #if E0_IS_TRINAMIC + #if AXIS_HAS_STEALTHCHOP(E0) case 0: TMC_SET_PWMTHRS_E(0); break; #endif - #if E_STEPPERS > 1 && E1_IS_TRINAMIC + #if E_STEPPERS > 1 && AXIS_HAS_STEALTHCHOP(E1) case 1: TMC_SET_PWMTHRS_E(1); break; #endif - #if E_STEPPERS > 2 && E2_IS_TRINAMIC + #if E_STEPPERS > 2 && AXIS_HAS_STEALTHCHOP(E2) case 2: TMC_SET_PWMTHRS_E(2); break; #endif - #if E_STEPPERS > 3 && E3_IS_TRINAMIC + #if E_STEPPERS > 3 && AXIS_HAS_STEALTHCHOP(E3) case 3: TMC_SET_PWMTHRS_E(3); break; #endif - #if E_STEPPERS > 4 && E4_IS_TRINAMIC + #if E_STEPPERS > 4 && AXIS_HAS_STEALTHCHOP(E4) case 4: TMC_SET_PWMTHRS_E(4); break; #endif } @@ -11225,48 +11696,40 @@ inline void gcode_M502() { } } - if (report) LOOP_XYZE(i) switch (i) { - case X_AXIS: - #if X_IS_TRINAMIC - TMC_SAY_PWMTHRS(X,X); - #endif - #if X2_IS_TRINAMIC - TMC_SAY_PWMTHRS(X,X2); - #endif - break; - case Y_AXIS: - #if Y_IS_TRINAMIC - TMC_SAY_PWMTHRS(Y,Y); - #endif - #if Y2_IS_TRINAMIC - TMC_SAY_PWMTHRS(Y,Y2); - #endif - break; - case Z_AXIS: - #if Z_IS_TRINAMIC - TMC_SAY_PWMTHRS(Z,Z); - #endif - #if Z2_IS_TRINAMIC - TMC_SAY_PWMTHRS(Z,Z2); - #endif - break; - case E_AXIS: - #if E0_IS_TRINAMIC - TMC_SAY_PWMTHRS_E(0); - #endif - #if E_STEPPERS > 1 && E1_IS_TRINAMIC - TMC_SAY_PWMTHRS_E(1); - #endif - #if E_STEPPERS > 2 && E2_IS_TRINAMIC - TMC_SAY_PWMTHRS_E(2); - #endif - #if E_STEPPERS > 3 && E3_IS_TRINAMIC - TMC_SAY_PWMTHRS_E(3); - #endif - #if E_STEPPERS > 4 && E4_IS_TRINAMIC - TMC_SAY_PWMTHRS_E(4); - #endif - break; + if (report) { + #if AXIS_HAS_STEALTHCHOP(X) + TMC_SAY_PWMTHRS(X,X); + #endif + #if AXIS_HAS_STEALTHCHOP(X2) + TMC_SAY_PWMTHRS(X,X2); + #endif + #if AXIS_HAS_STEALTHCHOP(Y) + TMC_SAY_PWMTHRS(Y,Y); + #endif + #if AXIS_HAS_STEALTHCHOP(Y2) + TMC_SAY_PWMTHRS(Y,Y2); + #endif + #if AXIS_HAS_STEALTHCHOP(Z) + TMC_SAY_PWMTHRS(Z,Z); + #endif + #if AXIS_HAS_STEALTHCHOP(Z2) + TMC_SAY_PWMTHRS(Z,Z2); + #endif + #if AXIS_HAS_STEALTHCHOP(E0) + TMC_SAY_PWMTHRS_E(0); + #endif + #if E_STEPPERS > 1 && AXIS_HAS_STEALTHCHOP(E1) + TMC_SAY_PWMTHRS_E(1); + #endif + #if E_STEPPERS > 2 && AXIS_HAS_STEALTHCHOP(E2) + TMC_SAY_PWMTHRS_E(2); + #endif + #if E_STEPPERS > 3 && AXIS_HAS_STEALTHCHOP(E3) + TMC_SAY_PWMTHRS_E(3); + #endif + #if E_STEPPERS > 4 && AXIS_HAS_STEALTHCHOP(E4) + TMC_SAY_PWMTHRS_E(4); + #endif } } #endif // HYBRID_THRESHOLD @@ -11287,67 +11750,61 @@ inline void gcode_M502() { switch (i) { #if X_SENSORLESS case X_AXIS: - #if ENABLED(X_IS_TMC2130) || ENABLED(IS_TRAMS) - if (index == 0) TMC_SET_SGT(X); + #if AXIS_HAS_STALLGUARD(X) + if (index < 2) TMC_SET_SGT(X); #endif - #if ENABLED(X2_IS_TMC2130) - if (index == 1) TMC_SET_SGT(X2); + #if AXIS_HAS_STALLGUARD(X2) + if (!(index & 1)) TMC_SET_SGT(X2); #endif break; #endif #if Y_SENSORLESS case Y_AXIS: - #if ENABLED(Y_IS_TMC2130) || ENABLED(IS_TRAMS) - if (index == 0) TMC_SET_SGT(Y); + #if AXIS_HAS_STALLGUARD(Y) + if (index < 2) TMC_SET_SGT(Y); #endif - #if ENABLED(Y2_IS_TMC2130) - if (index == 1) TMC_SET_SGT(Y2); + #if AXIS_HAS_STALLGUARD(Y2) + if (!(index & 1)) TMC_SET_SGT(Y2); #endif break; #endif #if Z_SENSORLESS case Z_AXIS: - #if ENABLED(Z_IS_TMC2130) || ENABLED(IS_TRAMS) - if (index == 0) TMC_SET_SGT(Z); + #if AXIS_HAS_STALLGUARD(Z) + if (index < 2) TMC_SET_SGT(Z); #endif - #if ENABLED(Z2_IS_TMC2130) - if (index == 1) TMC_SET_SGT(Z2); + #if AXIS_HAS_STALLGUARD(Z2) + if (!(index & 1)) TMC_SET_SGT(Z2); #endif break; #endif } } - if (report) LOOP_XYZ(i) switch (i) { + if (report) { #if X_SENSORLESS - case X_AXIS: - #if ENABLED(X_IS_TMC2130) || ENABLED(IS_TRAMS) - TMC_SAY_SGT(X); - #endif - #if ENABLED(X2_IS_TMC2130) - TMC_SAY_SGT(X2); - #endif - break; + #if AXIS_HAS_STALLGUARD(X) + TMC_SAY_SGT(X); + #endif + #if AXIS_HAS_STALLGUARD(X2) + TMC_SAY_SGT(X2); + #endif #endif #if Y_SENSORLESS - case Y_AXIS: - #if ENABLED(Y_IS_TMC2130) || ENABLED(IS_TRAMS) - TMC_SAY_SGT(Y); - #endif - #if ENABLED(Y2_IS_TMC2130) - TMC_SAY_SGT(Y2); - #endif - break; + #if AXIS_HAS_STALLGUARD(Y) + TMC_SAY_SGT(Y); + #endif + #if AXIS_HAS_STALLGUARD(Y2) + TMC_SAY_SGT(Y2); + #endif #endif #if Z_SENSORLESS - case Z_AXIS: - #if ENABLED(Z_IS_TMC2130) || ENABLED(IS_TRAMS) - TMC_SAY_SGT(Z); - #endif - #if ENABLED(Z2_IS_TMC2130) - TMC_SAY_SGT(Z2); - #endif - break; + #if AXIS_HAS_STALLGUARD(Z) + TMC_SAY_SGT(Z); + #endif + #if AXIS_HAS_STALLGUARD(Z2) + TMC_SAY_SGT(Z2); + #endif #endif } } @@ -11366,11 +11823,11 @@ inline void gcode_M502() { return; } - #if Z_IS_TRINAMIC + #if AXIS_IS_TMC(Z) const uint16_t Z_current_1 = stepperZ.getCurrent(); stepperZ.setCurrent(_rms, R_SENSE, HOLD_MULTIPLIER); #endif - #if Z2_IS_TRINAMIC + #if AXIS_IS_TMC(Z2) const uint16_t Z2_current_1 = stepperZ2.getCurrent(); stepperZ2.setCurrent(_rms, R_SENSE, HOLD_MULTIPLIER); #endif @@ -11381,10 +11838,10 @@ inline void gcode_M502() { do_blocking_move_to_z(Z_MAX_POS+_z); - #if Z_IS_TRINAMIC + #if AXIS_IS_TMC(Z) stepperZ.setCurrent(Z_current_1, R_SENSE, HOLD_MULTIPLIER); #endif - #if Z2_IS_TRINAMIC + #if AXIS_IS_TMC(Z2) stepperZ2.setCurrent(Z2_current_1, R_SENSE, HOLD_MULTIPLIER); #endif @@ -11566,7 +12023,7 @@ inline void gcode_M355() { } else { if (!USEABLE_HARDWARE_PWM(CASE_LIGHT_PIN)) SERIAL_ECHOLNPGM("Case light: on"); - else SERIAL_ECHOLNPAIR("Case light: ", (int)case_light_brightness); + else SERIAL_ECHOLNPAIR("Case light: ", int(case_light_brightness)); } #else @@ -11580,44 +12037,39 @@ inline void gcode_M355() { /** * M163: Set a single mix factor for a mixing extruder * This is called "weight" by some systems. + * The 'P' values must sum to 1.0 or must be followed by M164 to normalize them. * * S[index] The channel index to set * P[float] The mix value - * */ inline void gcode_M163() { const int mix_index = parser.intval('S'); - if (mix_index < MIXING_STEPPERS) { - float mix_value = parser.floatval('P'); - NOLESS(mix_value, 0.0); - mixing_factor[mix_index] = RECIPROCAL(mix_value); - } + if (mix_index < MIXING_STEPPERS) + mixing_factor[mix_index] = MAX(parser.floatval('P'), 0.0); } - #if MIXING_VIRTUAL_TOOLS > 1 - - /** - * M164: Store the current mix factors as a virtual tool. - * - * S[index] The virtual tool to store - * - */ - inline void gcode_M164() { - const int tool_index = parser.intval('S'); - if (tool_index < MIXING_VIRTUAL_TOOLS) { - normalize_mix(); + /** + * M164: Normalize and commit the mix. + * If 'S' is given store as a virtual tool. (Requires MIXING_VIRTUAL_TOOLS > 1) + * + * S[index] The virtual tool to store + */ + inline void gcode_M164() { + normalize_mix(); + #if MIXING_VIRTUAL_TOOLS > 1 + const int tool_index = parser.intval('S', -1); + if (WITHIN(tool_index, 0, MIXING_VIRTUAL_TOOLS - 1)) { for (uint8_t i = 0; i < MIXING_STEPPERS; i++) mixing_virtual_tool_mix[tool_index][i] = mixing_factor[i]; } - } - - #endif + #endif + } #if ENABLED(DIRECT_MIXING_IN_G1) /** * M165: Set multiple mix factors for a mixing extruder. * Factors that are left out will be set to 0. - * All factors together must add up to 1.0. + * All factors should sum to 1.0, but they will be normalized regardless. * * A[factor] Mix factor for extruder stepper 1 * B[factor] Mix factor for extruder stepper 2 @@ -11625,7 +12077,6 @@ inline void gcode_M355() { * D[factor] Mix factor for extruder stepper 4 * H[factor] Mix factor for extruder stepper 5 * I[factor] Mix factor for extruder stepper 6 - * */ inline void gcode_M165() { gcode_get_mix(); } #endif @@ -11792,7 +12243,7 @@ inline void invalid_extruder_error(const uint8_t e) { i == 0 ? current_position[X_AXIS] : xhome, current_position[Y_AXIS], i == 2 ? current_position[Z_AXIS] : raised_z, - current_position[E_AXIS], + current_position[E_CART], planner.max_feedrate_mm_s[i == 1 ? X_AXIS : Z_AXIS], active_extruder ); @@ -11863,7 +12314,7 @@ inline void invalid_extruder_error(const uint8_t e) { #if ENABLED(PARKING_EXTRUDER) - inline void parking_extruder_tool_change(const uint8_t tmp_extruder, const float fr_mm_s/*=0.0*/, bool no_move/*=false*/) { + inline void parking_extruder_tool_change(const uint8_t tmp_extruder, bool no_move) { constexpr float z_raise = PARKING_EXTRUDER_SECURITY_RAISE; if (!no_move) { @@ -11977,6 +12428,14 @@ inline void invalid_extruder_error(const uint8_t e) { * previous tool out of the way and the new tool into place. */ void tool_change(const uint8_t tmp_extruder, const float fr_mm_s/*=0.0*/, bool no_move/*=false*/) { + planner.synchronize(); + + #if HAS_LEVELING + // Set current position to the physical position + const bool leveling_was_active = planner.leveling_active; + set_bed_leveling_enabled(false); + #endif + #if ENABLED(MIXING_EXTRUDER) && MIXING_VIRTUAL_TOOLS > 1 mixing_tool_change(tmp_extruder); @@ -12000,22 +12459,27 @@ void tool_change(const uint8_t tmp_extruder, const float fr_mm_s/*=0.0*/, bool n #endif } - // Save current position to destination, for use later - set_destination_from_current(); - - #if HAS_LEVELING - // Set current position to the physical position - const bool leveling_was_active = planner.leveling_active; - set_bed_leveling_enabled(false); - #endif - #if ENABLED(DUAL_X_CARRIAGE) + #if HAS_SOFTWARE_ENDSTOPS + // Update the X software endstops early + active_extruder = tmp_extruder; + update_software_endstops(X_AXIS); + active_extruder = !tmp_extruder; + #endif + + // Don't move the new extruder out of bounds + if (!WITHIN(current_position[X_AXIS], soft_endstop_min[X_AXIS], soft_endstop_max[X_AXIS])) + no_move = true; + + if (!no_move) set_destination_from_current(); dualx_tool_change(tmp_extruder, no_move); // Can modify no_move #else // !DUAL_X_CARRIAGE - #if ENABLED(PARKING_EXTRUDER) // Dual Parking extruder + set_destination_from_current(); + + #if ENABLED(PARKING_EXTRUDER) parking_extruder_tool_change(tmp_extruder, no_move); #endif @@ -12052,11 +12516,6 @@ void tool_change(const uint8_t tmp_extruder, const float fr_mm_s/*=0.0*/, bool n current_position[Z_AXIS] -= zdiff; #endif - #if HAS_LEVELING - // Restore leveling to re-establish the logical position - set_bed_leveling_enabled(leveling_was_active); - #endif - // Tell the planner the new "current position" SYNC_PLAN_POSITION_KINEMATIC(); @@ -12100,6 +12559,10 @@ void tool_change(const uint8_t tmp_extruder, const float fr_mm_s/*=0.0*/, bool n feedrate_mm_s = old_feedrate_mm_s; + #if HAS_SOFTWARE_ENDSTOPS && ENABLED(DUAL_X_CARRIAGE) + update_software_endstops(X_AXIS); + #endif + #else // HOTENDS <= 1 UNUSED(fr_mm_s); @@ -12126,8 +12589,13 @@ void tool_change(const uint8_t tmp_extruder, const float fr_mm_s/*=0.0*/, bool n fanmux_switch(active_extruder); #endif + #if HAS_LEVELING + // Restore leveling to re-establish the logical position + set_bed_leveling_enabled(leveling_was_active); + #endif + SERIAL_ECHO_START(); - SERIAL_ECHOLNPAIR(MSG_ACTIVE_EXTRUDER, (int)active_extruder); + SERIAL_ECHOLNPAIR(MSG_ACTIVE_EXTRUDER, int(active_extruder)); #endif // !MIXING_EXTRUDER || MIXING_VIRTUAL_TOOLS <= 1 } @@ -12197,6 +12665,10 @@ void process_parsed_command() { case 5: gcode_G5(); break; // G5: Cubic B_spline #endif + #if ENABLED(UNREGISTERED_MOVE_SUPPORT) + case 6: gcode_G6(); break; // G6: Direct stepper move + #endif + #if ENABLED(FWRETRACT) case 10: gcode_G10(); break; // G10: Retract case 11: gcode_G11(); break; // G11: Prime @@ -12259,6 +12731,10 @@ void process_parsed_command() { case 91: relative_mode = true; break; // G91: Relative coordinates case 92: gcode_G92(); break; // G92: Set Position + #if ENABLED(MECHADUINO_I2C_COMMANDS) + case 95: gcode_G95(); break; // G95: Set torque mode + case 96: gcode_G96(); break; // G96: Mark encoder reference point + #endif #if ENABLED(DEBUG_GCODE_PARSER) case 800: parser.debug(); break; // G800: GCode Parser Test for G @@ -12339,6 +12815,8 @@ void process_parsed_command() { case 108: gcode_M108(); break; // M108: Cancel Waiting case 112: gcode_M112(); break; // M112: Emergency Stop case 410: gcode_M410(); break; // M410: Quickstop. Abort all planned moves + #else + case 108: case 112: case 410: break; // Silently drop as handled by emergency parser #endif #if ENABLED(HOST_KEEPALIVE_FEATURE) @@ -12552,8 +13030,8 @@ void process_parsed_command() { case 605: gcode_M605(); break; // M605: Set Dual X Carriage movement mode #endif - #if ENABLED(DELTA) - case 665: gcode_M665(); break; // M665: Delta Configuration + #if ENABLED(DELTA) || ENABLED(HANGPRINTER) + case 665: gcode_M665(); break; // M665: Delta / Hangprinter Configuration #endif #if ENABLED(DELTA) || ENABLED(X_DUAL_ENDSTOPS) || ENABLED(Y_DUAL_ENDSTOPS) || ENABLED(Z_DUAL_ENDSTOPS) case 666: gcode_M666(); break; // M666: DELTA/Dual Endstop Adjustment @@ -12607,7 +13085,7 @@ void process_parsed_command() { #endif #endif - #if ENABLED(HAVE_TMC2130) || ENABLED(HAVE_TMC2208) + #if HAS_DRIVER(TMC2130) || HAS_DRIVER(TMC2208) #if ENABLED(TMC_DEBUG) case 122: gcode_M122(); break; // M122: Debug TMC steppers #endif @@ -13004,6 +13482,115 @@ void ok_to_send() { #endif // DELTA +#if ENABLED(HANGPRINTER) + + /** + * Recalculate factors used for hangprinter kinematics whenever + * settings have been changed (e.g., by M665). + */ + void recalc_hangprinter_settings(){ + HANGPRINTER_IK_ORIGIN(line_lengths_origin); + + #if ENABLED(LINE_BUILDUP_COMPENSATION_FEATURE) + + const uint8_t mech_adv_tmp[MOV_AXIS] = MECHANICAL_ADVANTAGE, + actn_pts_tmp[MOV_AXIS] = ACTION_POINTS; + const uint16_t m_g_t_tmp[MOV_AXIS] = MOTOR_GEAR_TEETH, + s_g_t_tmp[MOV_AXIS] = SPOOL_GEAR_TEETH; + const float mnt_l_tmp[MOV_AXIS] = MOUNTED_LINE; + float s_r2_tmp[MOV_AXIS] = SPOOL_RADII, + steps_per_unit_times_r_tmp[MOV_AXIS]; + uint8_t nr_lines_dir_tmp[MOV_AXIS]; + + LOOP_MOV_AXIS(i){ + steps_per_unit_times_r_tmp[i] = (float(mech_adv_tmp[i])*STEPS_PER_MOTOR_REVOLUTION*s_g_t_tmp[i])/(2*M_PI*m_g_t_tmp[i]); + nr_lines_dir_tmp[i] = mech_adv_tmp[i]*actn_pts_tmp[i]; + s_r2_tmp[i] *= s_r2_tmp[i]; + planner.k2[i] = -(float)nr_lines_dir_tmp[i]*SPOOL_BUILDUP_FACTOR; + planner.k0[i] = 2.0*steps_per_unit_times_r_tmp[i]/planner.k2[i]; + } + + // Assumes spools are mounted near D-anchor in ceiling + #define HYP3D(x,y,z) SQRT(sq(x) + sq(y) + sq(z)) + float line_on_spool_origin_tmp[MOV_AXIS]; + line_on_spool_origin_tmp[A_AXIS] = actn_pts_tmp[A_AXIS] * mnt_l_tmp[A_AXIS] + - actn_pts_tmp[A_AXIS] * HYPOT(anchor_A_y, anchor_D_z - anchor_A_z) + - nr_lines_dir_tmp[A_AXIS] * line_lengths_origin[A_AXIS]; + line_on_spool_origin_tmp[B_AXIS] = actn_pts_tmp[B_AXIS] * mnt_l_tmp[B_AXIS] + - actn_pts_tmp[B_AXIS] * HYP3D(anchor_B_x, anchor_B_y, anchor_D_z - anchor_B_z) + - nr_lines_dir_tmp[B_AXIS] * line_lengths_origin[B_AXIS]; + line_on_spool_origin_tmp[C_AXIS] = actn_pts_tmp[C_AXIS] * mnt_l_tmp[C_AXIS] + - actn_pts_tmp[C_AXIS] * HYP3D(anchor_C_x, anchor_C_y, anchor_D_z - anchor_C_z) + - nr_lines_dir_tmp[C_AXIS] * line_lengths_origin[C_AXIS]; + line_on_spool_origin_tmp[D_AXIS] = actn_pts_tmp[D_AXIS] * mnt_l_tmp[D_AXIS] + - nr_lines_dir_tmp[D_AXIS] * line_lengths_origin[D_AXIS]; + + LOOP_MOV_AXIS(i) { + planner.axis_steps_per_mm[i] = steps_per_unit_times_r_tmp[i] / + SQRT((SPOOL_BUILDUP_FACTOR) * line_on_spool_origin_tmp[i] + s_r2_tmp[i]); + planner.k1[i] = (SPOOL_BUILDUP_FACTOR) * + (line_on_spool_origin_tmp[i] + nr_lines_dir_tmp[i] * line_lengths_origin[i]) + s_r2_tmp[i]; + + planner.sqrtk1[i] = SQRT(planner.k1[i]); + } + planner.axis_steps_per_mm[E_AXIS] = DEFAULT_E_AXIS_STEPS_PER_UNIT; + + #endif // LINE_BUILDUP_COMPENSATION_FEATURE + + SYNC_PLAN_POSITION_KINEMATIC(); // recalcs line lengths in case anchor was moved + } + + /** + * Hangprinter inverse kinematics + */ + void inverse_kinematics(const float raw[XYZ]) { + HANGPRINTER_IK(raw); + } + + /** + * Hangprinter forward kinematics + * Basic idea is to subtract squared line lengths to get linear equations. + * Subtracting d*d from a*a, b*b, and c*c gives the cleanest derivation: + * + * a*a - d*d = k1 + k2*y + k3*z <---- a line (I) + * b*b - d*d = k4 + k5*x + k6*y + k7*z <---- a plane (II) + * c*c - d*d = k8 + k9*x + k10*y + k11*z <---- a plane (III) + * + * Use (I) to reduce (II) and (III) into lines. Eliminate y, keep z. + * + * (II): b*b - d*d = k12 + k13*x + k14*z + * <=> x = k0b + k1b*z, <---- a line (IV) + * + * (III): c*c - d*d = k15 + k16*x + k17*z + * <=> x = k0c + k1c*z, <---- a line (V) + * + * where k1, k2, ..., k17, k0b, k0c, k1b, and k1c are known constants. + * + * These two straight lines are not parallel, so they will cross in exactly one point. + * Find z by setting (IV) = (V) + * Find x by inserting z into (V) + * Find y by inserting z into (I) + * + * Warning: truncation errors will typically be in the order of a few tens of microns. + */ + void forward_kinematics_HANGPRINTER(float a, float b, float c, float d){ + const float Asq = sq(anchor_A_y) + sq(anchor_A_z), + Bsq = sq(anchor_B_x) + sq(anchor_B_y) + sq(anchor_B_z), + Csq = sq(anchor_C_x) + sq(anchor_C_y) + sq(anchor_C_z), + Dsq = sq(anchor_D_z), + aa = sq(a), + dd = sq(d), + k0b = (-sq(b) + Bsq - Dsq + dd) / (2.0 * anchor_B_x) + (anchor_B_y / (2.0 * anchor_A_y * anchor_B_x)) * (Dsq - Asq + aa - dd), + k0c = (-sq(c) + Csq - Dsq + dd) / (2.0 * anchor_C_x) + (anchor_C_y / (2.0 * anchor_A_y * anchor_C_x)) * (Dsq - Asq + aa - dd), + k1b = (anchor_B_y * (anchor_A_z - anchor_D_z)) / (anchor_A_y * anchor_B_x) + (anchor_D_z - anchor_B_z) / anchor_B_x, + k1c = (anchor_C_y * (anchor_A_z - anchor_D_z)) / (anchor_A_y * anchor_C_x) + (anchor_D_z - anchor_C_z) / anchor_C_x; + + cartes[Z_AXIS] = (k0b - k0c) / (k1c - k1b); + cartes[X_AXIS] = k0c + k1c * cartes[Z_AXIS]; + cartes[Y_AXIS] = (Asq - Dsq - aa + dd) / (2.0 * anchor_A_y) + ((anchor_D_z - anchor_A_z) / anchor_A_y) * cartes[Z_AXIS]; + } +#endif // HANGPRINTER + /** * Get the stepper positions in the cartes[] array. * Forward kinematics are applied for DELTA and SCARA. @@ -13020,6 +13607,13 @@ void get_cartesian_from_steppers() { planner.get_axis_position_mm(B_AXIS), planner.get_axis_position_mm(C_AXIS) ); + #elif ENABLED(HANGPRINTER) + forward_kinematics_HANGPRINTER( + planner.get_axis_position_mm(A_AXIS), + planner.get_axis_position_mm(B_AXIS), + planner.get_axis_position_mm(C_AXIS), + planner.get_axis_position_mm(D_AXIS) + ); #else #if IS_SCARA forward_kinematics_SCARA( @@ -13079,7 +13673,7 @@ void set_current_from_steppers_for_axis(const AxisEnum axis) { // Remaining cartesian distances const float zdiff = destination[Z_AXIS] - current_position[Z_AXIS], - ediff = destination[E_AXIS] - current_position[E_AXIS]; + ediff = destination[E_CART] - current_position[E_CART]; // Get the linear distance in XYZ // If the move is very short, check the E move distance @@ -13154,6 +13748,7 @@ void set_current_from_steppers_for_axis(const AxisEnum axis) { } #define MBL_SEGMENT_END(A) (current_position[_AXIS(A)] + (destination[_AXIS(A)] - current_position[_AXIS(A)]) * normalized_dist) + #define MBL_SEGMENT_END_E (current_position[E_CART] + (destination[E_CART] - current_position[E_CART]) * normalized_dist) float normalized_dist, end[XYZE]; const int8_t gcx = MAX(cx1, cx2), gcy = MAX(cy1, cy2); @@ -13185,7 +13780,7 @@ void set_current_from_steppers_for_axis(const AxisEnum axis) { } destination[Z_AXIS] = MBL_SEGMENT_END(Z); - destination[E_AXIS] = MBL_SEGMENT_END(E); + destination[E_CART] = MBL_SEGMENT_END_E; // Do the split and look for more borders mesh_line_to_destination(fr_mm_s, x_splits, y_splits); @@ -13222,6 +13817,7 @@ void set_current_from_steppers_for_axis(const AxisEnum axis) { } #define LINE_SEGMENT_END(A) (current_position[_AXIS(A)] + (destination[_AXIS(A)] - current_position[_AXIS(A)]) * normalized_dist) + #define LINE_SEGMENT_END_E (current_position[E_CART] + (destination[E_CART] - current_position[E_CART]) * normalized_dist) float normalized_dist, end[XYZE]; const int8_t gcx = MAX(cx1, cx2), gcy = MAX(cy1, cy2); @@ -13253,7 +13849,7 @@ void set_current_from_steppers_for_axis(const AxisEnum axis) { } destination[Z_AXIS] = LINE_SEGMENT_END(Z); - destination[E_AXIS] = LINE_SEGMENT_END(E); + destination[E_CART] = LINE_SEGMENT_END_E; // Do the split and look for more borders bilinear_line_to_destination(fr_mm_s, x_splits, y_splits); @@ -13284,10 +13880,10 @@ void set_current_from_steppers_for_axis(const AxisEnum axis) { #endif /** - * Prepare a linear move in a DELTA or SCARA setup. + * Prepare a linear move in a DELTA, SCARA or HANGPRINTER setup. * * This calls planner.buffer_line several times, adding - * small incremental moves for DELTA or SCARA. + * small incremental moves for DELTA, SCARA or HANGPRINTER. * * For Unified Bed Leveling (Delta or Segmented Cartesian) * the ubl.prepare_segmented_line_to method replaces this. @@ -13298,10 +13894,18 @@ void set_current_from_steppers_for_axis(const AxisEnum axis) { const float _feedrate_mm_s = MMS_SCALED(feedrate_mm_s); const float xdiff = rtarget[X_AXIS] - current_position[X_AXIS], - ydiff = rtarget[Y_AXIS] - current_position[Y_AXIS]; + ydiff = rtarget[Y_AXIS] - current_position[Y_AXIS] + #if ENABLED(HANGPRINTER) + , zdiff = rtarget[Z_AXIS] - current_position[Z_AXIS] + #endif + ; - // If the move is only in Z/E don't split up the move - if (!xdiff && !ydiff) { + // If the move is only in Z/E (for Hangprinter only in E) don't split up the move + if (!xdiff && !ydiff + #if ENABLED(HANGPRINTER) + && !zdiff + #endif + ) { planner.buffer_line_kinematic(rtarget, _feedrate_mm_s, active_extruder); return false; // caller will update current_position } @@ -13310,8 +13914,11 @@ void set_current_from_steppers_for_axis(const AxisEnum axis) { if (!position_is_reachable(rtarget[X_AXIS], rtarget[Y_AXIS])) return true; // Remaining cartesian distances - const float zdiff = rtarget[Z_AXIS] - current_position[Z_AXIS], - ediff = rtarget[E_AXIS] - current_position[E_AXIS]; + const float + #if DISABLED(HANGPRINTER) + zdiff = rtarget[Z_AXIS] - current_position[Z_AXIS], + #endif + ediff = rtarget[E_CART] - current_position[E_CART]; // Get the linear distance in XYZ // If the move is very short, check the E move distance @@ -13405,6 +14012,8 @@ void set_current_from_steppers_for_axis(const AxisEnum axis) { LOOP_XYZE(i) raw[i] += segment_distance[i]; #if ENABLED(DELTA) && HOTENDS < 2 DELTA_IK(raw); // Delta can inline its kinematics + #elif ENABLED(HANGPRINTER) + HANGPRINTER_IK(raw); // Modifies line_lengths[ABCD] #else inverse_kinematics(raw); #endif @@ -13414,7 +14023,7 @@ void set_current_from_steppers_for_axis(const AxisEnum axis) { #if ENABLED(SCARA_FEEDRATE_SCALING) // For SCARA scale the feed rate from mm/s to degrees/s // i.e., Complete the angular vector in the given time. - if (!planner.buffer_segment(delta[A_AXIS], delta[B_AXIS], raw[Z_AXIS], raw[E_AXIS], HYPOT(delta[A_AXIS] - oldA, delta[B_AXIS] - oldB) * inverse_secs, active_extruder)) + if (!planner.buffer_segment(delta[A_AXIS], delta[B_AXIS], raw[Z_AXIS], raw[E_CART], HYPOT(delta[A_AXIS] - oldA, delta[B_AXIS] - oldB) * inverse_secs, active_extruder, segment_length)) break; /* SERIAL_ECHO(segments); @@ -13427,7 +14036,7 @@ void set_current_from_steppers_for_axis(const AxisEnum axis) { #elif ENABLED(DELTA_FEEDRATE_SCALING) // For DELTA scale the feed rate from Effector mm/s to Carriage mm/s // i.e., Complete the linear vector in the given time. - if (!planner.buffer_segment(delta[A_AXIS], delta[B_AXIS], delta[C_AXIS], raw[E_AXIS], SQRT(sq(delta[A_AXIS] - oldA) + sq(delta[B_AXIS] - oldB) + sq(delta[C_AXIS] - oldC)) * inverse_secs, active_extruder)) + if (!planner.buffer_segment(delta[A_AXIS], delta[B_AXIS], delta[C_AXIS], raw[E_AXIS], SQRT(sq(delta[A_AXIS] - oldA) + sq(delta[B_AXIS] - oldB) + sq(delta[C_AXIS] - oldC)) * inverse_secs, active_extruder, segment_length)) break; /* SERIAL_ECHO(segments); @@ -13437,8 +14046,11 @@ void set_current_from_steppers_for_axis(const AxisEnum axis) { safe_delay(5); //*/ oldA = delta[A_AXIS]; oldB = delta[B_AXIS]; oldC = delta[C_AXIS]; + #elif ENABLED(HANGPRINTER) + if (!planner.buffer_line(line_lengths[A_AXIS], line_lengths[B_AXIS], line_lengths[C_AXIS], line_lengths[D_AXIS], raw[E_CART], _feedrate_mm_s, active_extruder, cartesian_segment_mm)) + break; #else - if (!planner.buffer_line(delta[A_AXIS], delta[B_AXIS], delta[C_AXIS], raw[E_AXIS], _feedrate_mm_s, active_extruder, cartesian_segment_mm)) + if (!planner.buffer_line(delta[A_AXIS], delta[B_AXIS], delta[C_AXIS], raw[E_CART], _feedrate_mm_s, active_extruder, cartesian_segment_mm)) break; #endif } @@ -13452,7 +14064,7 @@ void set_current_from_steppers_for_axis(const AxisEnum axis) { #if ENABLED(SCARA_FEEDRATE_SCALING) const float diff2 = HYPOT2(delta[A_AXIS] - oldA, delta[B_AXIS] - oldB); if (diff2) { - planner.buffer_segment(delta[A_AXIS], delta[B_AXIS], rtarget[Z_AXIS], rtarget[E_AXIS], SQRT(diff2) * inverse_secs, active_extruder); + planner.buffer_segment(delta[A_AXIS], delta[B_AXIS], rtarget[Z_AXIS], rtarget[E_CART], SQRT(diff2) * inverse_secs, active_extruder, segment_length); /* SERIAL_ECHOPAIR("final: A=", delta[A_AXIS]); SERIAL_ECHOPAIR(" B=", delta[B_AXIS]); SERIAL_ECHOPAIR(" adiff=", delta[A_AXIS] - oldA); SERIAL_ECHOPAIR(" bdiff=", delta[B_AXIS] - oldB); @@ -13464,7 +14076,7 @@ void set_current_from_steppers_for_axis(const AxisEnum axis) { #elif ENABLED(DELTA_FEEDRATE_SCALING) const float diff2 = sq(delta[A_AXIS] - oldA) + sq(delta[B_AXIS] - oldB) + sq(delta[C_AXIS] - oldC); if (diff2) { - planner.buffer_segment(delta[A_AXIS], delta[B_AXIS], delta[C_AXIS], rtarget[E_AXIS], SQRT(diff2) * inverse_secs, active_extruder); + planner.buffer_segment(delta[A_AXIS], delta[B_AXIS], delta[C_AXIS], rtarget[E_AXIS], SQRT(diff2) * inverse_secs, active_extruder, segment_length); /* SERIAL_ECHOPAIR("final: A=", delta[A_AXIS]); SERIAL_ECHOPAIR(" B=", delta[B_AXIS]); SERIAL_ECHOPAIR(" C=", delta[C_AXIS]); SERIAL_ECHOPAIR(" adiff=", delta[A_AXIS] - oldA); SERIAL_ECHOPAIR(" bdiff=", delta[B_AXIS] - oldB); SERIAL_ECHOPAIR(" cdiff=", delta[C_AXIS] - oldC); @@ -13535,7 +14147,7 @@ void set_current_from_steppers_for_axis(const AxisEnum axis) { case DXC_FULL_CONTROL_MODE: break; case DXC_AUTO_PARK_MODE: - if (current_position[E_AXIS] == destination[E_AXIS]) { + if (current_position[E_CART] == destination[E_CART]) { // This is a travel move (with no extrusion) // Skip it, but keep track of the current position // (so it can be used as the start of the next non-travel move) @@ -13552,7 +14164,7 @@ void set_current_from_steppers_for_axis(const AxisEnum axis) { i == 0 ? raised_parked_position[X_AXIS] : current_position[X_AXIS], i == 0 ? raised_parked_position[Y_AXIS] : current_position[Y_AXIS], i == 2 ? current_position[Z_AXIS] : raised_parked_position[Z_AXIS], - current_position[E_AXIS], + current_position[E_CART], i == 1 ? PLANNER_XY_FEEDRATE() : planner.max_feedrate_mm_s[Z_AXIS], active_extruder) ) break; @@ -13572,10 +14184,10 @@ void set_current_from_steppers_for_axis(const AxisEnum axis) { } #endif // move duplicate extruder into correct duplication position. - planner.set_position_mm(inactive_extruder_x_pos, current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + planner.set_position_mm(inactive_extruder_x_pos, current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_CART]); if (!planner.buffer_line( current_position[X_AXIS] + duplicate_extruder_x_offset, - current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], + current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_CART], planner.max_feedrate_mm_s[X_AXIS], 1) ) break; planner.synchronize(); @@ -13602,7 +14214,7 @@ void set_current_from_steppers_for_axis(const AxisEnum axis) { * Prepare a single move and get ready for the next one * * This may result in several calls to planner.buffer_line to - * do smaller moves for DELTA, SCARA, mesh moves, etc. + * do smaller moves for DELTA, SCARA, HANGPRINTER, mesh moves, etc. * * Make sure current_position[E] and destination[E] are good * before calling or cold/lengthy extrusion may get missed. @@ -13613,17 +14225,17 @@ void prepare_move_to_destination() { #if ENABLED(PREVENT_COLD_EXTRUSION) || ENABLED(PREVENT_LENGTHY_EXTRUDE) if (!DEBUGGING(DRYRUN)) { - if (destination[E_AXIS] != current_position[E_AXIS]) { + if (destination[E_CART] != current_position[E_CART]) { #if ENABLED(PREVENT_COLD_EXTRUSION) if (thermalManager.tooColdToExtrude(active_extruder)) { - current_position[E_AXIS] = destination[E_AXIS]; // Behave as if the move really took place, but ignore E part + current_position[E_CART] = destination[E_CART]; // Behave as if the move really took place, but ignore E part SERIAL_ECHO_START(); SERIAL_ECHOLNPGM(MSG_ERR_COLD_EXTRUDE_STOP); } #endif // PREVENT_COLD_EXTRUSION #if ENABLED(PREVENT_LENGTHY_EXTRUDE) - if (ABS(destination[E_AXIS] - current_position[E_AXIS]) * planner.e_factor[active_extruder] > (EXTRUDE_MAXLENGTH)) { - current_position[E_AXIS] = destination[E_AXIS]; // Behave as if the move really took place, but ignore E part + if (ABS(destination[E_CART] - current_position[E_CART]) * planner.e_factor[active_extruder] > (EXTRUDE_MAXLENGTH)) { + current_position[E_CART] = destination[E_CART]; // Behave as if the move really took place, but ignore E part SERIAL_ECHO_START(); SERIAL_ECHOLNPGM(MSG_ERR_LONG_EXTRUDE_STOP); } @@ -13692,7 +14304,7 @@ void prepare_move_to_destination() { rt_X = cart[p_axis] - center_P, rt_Y = cart[q_axis] - center_Q, linear_travel = cart[l_axis] - current_position[l_axis], - extruder_travel = cart[E_AXIS] - current_position[E_AXIS]; + extruder_travel = cart[E_CART] - current_position[E_CART]; // CCW angle of rotation between position and target from the circle center. Only one atan2() trig computation required. float angular_travel = ATAN2(r_P * rt_Y - r_Q * rt_X, r_P * rt_X + r_Q * rt_Y); @@ -13748,7 +14360,7 @@ void prepare_move_to_destination() { raw[l_axis] = current_position[l_axis]; // Initialize the extruder axis - raw[E_AXIS] = current_position[E_AXIS]; + raw[E_CART] = current_position[E_CART]; const float fr_mm_s = MMS_SCALED(feedrate_mm_s); @@ -13805,7 +14417,7 @@ void prepare_move_to_destination() { raw[p_axis] = center_P + r_P; raw[q_axis] = center_Q + r_Q; raw[l_axis] += linear_per_segment; - raw[E_AXIS] += extruder_per_segment; + raw[E_CART] += extruder_per_segment; clamp_to_software_endstops(raw); @@ -13817,19 +14429,19 @@ void prepare_move_to_destination() { #if ENABLED(SCARA_FEEDRATE_SCALING) // For SCARA scale the feed rate from mm/s to degrees/s // i.e., Complete the angular vector in the given time. - if (!planner.buffer_segment(delta[A_AXIS], delta[B_AXIS], raw[Z_AXIS], raw[E_AXIS], HYPOT(delta[A_AXIS] - oldA, delta[B_AXIS] - oldB) * inverse_secs, active_extruder)) + if (!planner.buffer_segment(delta[A_AXIS], delta[B_AXIS], raw[Z_AXIS], raw[E_CART], HYPOT(delta[A_AXIS] - oldA, delta[B_AXIS] - oldB) * inverse_secs, active_extruder, MM_PER_ARC_SEGMENT)) break; oldA = delta[A_AXIS]; oldB = delta[B_AXIS]; #elif ENABLED(DELTA_FEEDRATE_SCALING) // For DELTA scale the feed rate from Effector mm/s to Carriage mm/s // i.e., Complete the linear vector in the given time. - if (!planner.buffer_segment(delta[A_AXIS], delta[B_AXIS], delta[C_AXIS], raw[E_AXIS], SQRT(sq(delta[A_AXIS] - oldA) + sq(delta[B_AXIS] - oldB) + sq(delta[C_AXIS] - oldC)) * inverse_secs, active_extruder)) + if (!planner.buffer_segment(delta[A_AXIS], delta[B_AXIS], delta[C_AXIS], raw[E_AXIS], SQRT(sq(delta[A_AXIS] - oldA) + sq(delta[B_AXIS] - oldB) + sq(delta[C_AXIS] - oldC)) * inverse_secs, active_extruder, MM_PER_ARC_SEGMENT)) break; oldA = delta[A_AXIS]; oldB = delta[B_AXIS]; oldC = delta[C_AXIS]; #elif HAS_UBL_AND_CURVES float pos[XYZ] = { raw[X_AXIS], raw[Y_AXIS], raw[Z_AXIS] }; planner.apply_leveling(pos); - if (!planner.buffer_segment(pos[X_AXIS], pos[Y_AXIS], pos[Z_AXIS], raw[E_AXIS], fr_mm_s, active_extruder)) + if (!planner.buffer_segment(pos[X_AXIS], pos[Y_AXIS], pos[Z_AXIS], raw[E_CART], fr_mm_s, active_extruder, MM_PER_ARC_SEGMENT)) break; #else if (!planner.buffer_line_kinematic(raw, fr_mm_s, active_extruder)) @@ -13846,15 +14458,15 @@ void prepare_move_to_destination() { #if ENABLED(SCARA_FEEDRATE_SCALING) const float diff2 = HYPOT2(delta[A_AXIS] - oldA, delta[B_AXIS] - oldB); if (diff2) - planner.buffer_segment(delta[A_AXIS], delta[B_AXIS], cart[Z_AXIS], cart[E_AXIS], SQRT(diff2) * inverse_secs, active_extruder); + planner.buffer_segment(delta[A_AXIS], delta[B_AXIS], cart[Z_AXIS], cart[E_CART], SQRT(diff2) * inverse_secs, active_extruder, MM_PER_ARC_SEGMENT); #elif ENABLED(DELTA_FEEDRATE_SCALING) const float diff2 = sq(delta[A_AXIS] - oldA) + sq(delta[B_AXIS] - oldB) + sq(delta[C_AXIS] - oldC); if (diff2) - planner.buffer_segment(delta[A_AXIS], delta[B_AXIS], delta[C_AXIS], cart[E_AXIS], SQRT(diff2) * inverse_secs, active_extruder); + planner.buffer_segment(delta[A_AXIS], delta[B_AXIS], delta[C_AXIS], cart[E_CART], SQRT(diff2) * inverse_secs, active_extruder, MM_PER_ARC_SEGMENT); #elif HAS_UBL_AND_CURVES float pos[XYZ] = { cart[X_AXIS], cart[Y_AXIS], cart[Z_AXIS] }; planner.apply_leveling(pos); - planner.buffer_segment(pos[X_AXIS], pos[Y_AXIS], pos[Z_AXIS], cart[E_AXIS], fr_mm_s, active_extruder); + planner.buffer_segment(pos[X_AXIS], pos[Y_AXIS], pos[Z_AXIS], cart[E_CART], fr_mm_s, active_extruder, MM_PER_ARC_SEGMENT); #else planner.buffer_line_kinematic(cart, fr_mm_s, active_extruder); #endif @@ -13881,26 +14493,34 @@ void prepare_move_to_destination() { const millis_t ms = millis(); if (ELAPSED(ms, nextMotorCheck)) { nextMotorCheck = ms + 2500UL; // Not a time critical function, so only check every 2.5s + + // If any of the drivers or the bed are enabled... if (X_ENABLE_READ == X_ENABLE_ON || Y_ENABLE_READ == Y_ENABLE_ON || Z_ENABLE_READ == Z_ENABLE_ON #if HAS_HEATED_BED || thermalManager.soft_pwm_amount_bed > 0 #endif - || E0_ENABLE_READ == E_ENABLE_ON // If any of the drivers are enabled... + #if HAS_X2_ENABLE + || X2_ENABLE_READ == X_ENABLE_ON + #endif + #if HAS_Y2_ENABLE + || Y2_ENABLE_READ == Y_ENABLE_ON + #endif + #if HAS_Z2_ENABLE + || Z2_ENABLE_READ == Z_ENABLE_ON + #endif + || E0_ENABLE_READ == E_ENABLE_ON #if E_STEPPERS > 1 || E1_ENABLE_READ == E_ENABLE_ON - #if HAS_X2_ENABLE - || X2_ENABLE_READ == X_ENABLE_ON - #endif #if E_STEPPERS > 2 - || E2_ENABLE_READ == E_ENABLE_ON + || E2_ENABLE_READ == E_ENABLE_ON #if E_STEPPERS > 3 - || E3_ENABLE_READ == E_ENABLE_ON + || E3_ENABLE_READ == E_ENABLE_ON #if E_STEPPERS > 4 - || E4_ENABLE_READ == E_ENABLE_ON - #endif // E_STEPPERS > 4 - #endif // E_STEPPERS > 3 - #endif // E_STEPPERS > 2 - #endif // E_STEPPERS > 1 + || E4_ENABLE_READ == E_ENABLE_ON + #endif + #endif + #endif + #endif ) { lastMotorOn = ms; //... set time to NOW so the fan will turn on } @@ -14033,14 +14653,21 @@ void enable_all_steppers() { #if ENABLED(AUTO_POWER_CONTROL) powerManager.power_on(); #endif - enable_X(); - enable_Y(); - enable_Z(); + #if ENABLED(HANGPRINTER) + enable_A(); + enable_B(); + enable_C(); + enable_D(); + #else + enable_X(); + enable_Y(); + enable_Z(); + enable_E4(); + #endif enable_E0(); enable_E1(); enable_E2(); enable_E3(); - enable_E4(); } void disable_e_stepper(const uint8_t e) { @@ -14214,10 +14841,10 @@ void manage_inactivity(const bool ignore_stepper_queue/*=false*/) { } #endif // !SWITCHING_EXTRUDER - const float olde = current_position[E_AXIS]; - current_position[E_AXIS] += EXTRUDER_RUNOUT_EXTRUDE; + const float olde = current_position[E_CART]; + current_position[E_CART] += EXTRUDER_RUNOUT_EXTRUDE; planner.buffer_line_kinematic(current_position, MMM_TO_MMS(EXTRUDER_RUNOUT_SPEED), active_extruder); - current_position[E_AXIS] = olde; + current_position[E_CART] = olde; planner.set_e_position_mm(olde); planner.synchronize(); @@ -14283,7 +14910,7 @@ void idle( #endif ) { #if ENABLED(MAX7219_DEBUG) - Max7219_idle_tasks(); + max7219.idle_tasks(); #endif lcd_update(); @@ -14407,7 +15034,7 @@ void stop() { void setup() { #if ENABLED(MAX7219_DEBUG) - Max7219_init(); + max7219.init(); #endif #if ENABLED(DISABLE_JTAG) @@ -14433,10 +15060,10 @@ void setup() { SERIAL_ECHO_START(); // Prepare communication for TMC drivers - #if ENABLED(HAVE_TMC2130) + #if HAS_DRIVER(TMC2130) tmc_init_cs_pins(); #endif - #if ENABLED(HAVE_TMC2208) + #if HAS_DRIVER(TMC2208) tmc2208_serial_begin(); #endif @@ -14465,7 +15092,7 @@ void setup() { SERIAL_ECHO_START(); SERIAL_ECHOPAIR(MSG_FREE_MEMORY, freeMemory()); - SERIAL_ECHOLNPAIR(MSG_PLANNER_BUFFER_BYTES, (int)sizeof(block_t)*BLOCK_BUFFER_SIZE); + SERIAL_ECHOLNPAIR(MSG_PLANNER_BUFFER_BYTES, int(sizeof(block_t))*(BLOCK_BUFFER_SIZE)); // Send "ok" after commands by default for (int8_t i = 0; i < BUFSIZE; i++) send_ok[i] = true; @@ -14602,7 +15229,6 @@ void setup() { #if ENABLED(BLTOUCH) // Make sure any BLTouch error condition is cleared bltouch_command(BLTOUCH_RESET); - set_bltouch_deployed(true); set_bltouch_deployed(false); #endif @@ -14640,6 +15266,17 @@ void setup() { #if ENABLED(USE_WATCHDOG) watchdog_init(); #endif + + #if ENABLED(HANGPRINTER) + enable_A(); + enable_B(); + enable_C(); + enable_D(); + #endif + + #if ENABLED(SDSUPPORT) && DISABLED(ULTRA_LCD) + card.beginautostart(); + #endif } /** @@ -14735,6 +15372,6 @@ void loop() { if (++cmd_queue_index_r >= BUFSIZE) cmd_queue_index_r = 0; } } - endstops.report_state(); + endstops.event_handler(); idle(); } diff --git a/Marlin/Max7219_Debug_LEDs.cpp b/Marlin/Max7219_Debug_LEDs.cpp index eba1ffcd27..2be4bfd4f1 100644 --- a/Marlin/Max7219_Debug_LEDs.cpp +++ b/Marlin/Max7219_Debug_LEDs.cpp @@ -31,7 +31,7 @@ * #define MAX7219_DIN_PIN 78 * #define MAX7219_LOAD_PIN 79 * - * Max7219_init() is called automatically at startup, and then there are a number of + * send() is called automatically at startup, and then there are a number of * support functions available to control the LEDs in the 8x8 grid. */ @@ -48,44 +48,92 @@ #include "Marlin.h" #include "delay.h" -static uint8_t LEDs[8] = { 0 }; +Max7219 max7219; -#ifndef MAX7219_ROTATE - #define MAX7219_ROTATE 0 -#endif -#define _ROT ((MAX7219_ROTATE + 360) % 360) -#if _ROT == 0 - #define _ROW_ y - #define _COL_ x - #define XOR_7219(x, y) LEDs[y] ^= _BV(7 - x) - #define BIT_7219(x, y) TEST(LEDs[y], 7 - x) - #define SEND_7219(R,V) Max7219(max7219_reg_digit0 + R, V) -#elif _ROT == 90 - #define _ROW_ x - #define _COL_ y - #define XOR_7219(x, y) LEDs[x] ^= _BV(y) - #define BIT_7219(x, y) TEST(LEDs[x], y) - #define SEND_7219(R,V) Max7219(max7219_reg_digit0 + R, V) -#elif _ROT == 180 - #define _ROW_ y - #define _COL_ x - #define XOR_7219(x, y) LEDs[y] ^= _BV(x) - #define BIT_7219(x, y) TEST(LEDs[y], x) - #define SEND_7219(R,V) Max7219(max7219_reg_digit7 - R, V) -#elif _ROT == 270 - #define _ROW_ x - #define _COL_ y - #define XOR_7219(x, y) LEDs[x] ^= _BV(7 - y) - #define BIT_7219(x, y) TEST(LEDs[x], 7 - y) - #define SEND_7219(R,V) Max7219(max7219_reg_digit7 - R, V) +uint8_t Max7219::led_line[MAX7219_LINES]; // = { 0 }; + +#define LINE_REG(Q) (max7219_reg_digit0 + ((Q) & 0x7)) +#if _ROT == 0 || _ROT == 270 + #define _LED_BIT(Q) (7 - ((Q) & 0x7)) + #define _LED_UNIT(Q) ((Q) & ~0x7) #else - #error "MAX7219_ROTATE must be a multiple of +/- 90°." + #define _LED_BIT(Q) ((Q) & 0x7) + #define _LED_UNIT(Q) ((MAX7219_NUMBER_UNITS - 1 - ((Q) >> 3)) << 3) +#endif +#if _ROT < 180 + #define _LED_IND(P,Q) (_LED_UNIT(P) + (Q)) +#else + #define _LED_IND(P,Q) (_LED_UNIT(P) + (7 - ((Q) & 0x7))) +#endif +#if _ROT == 0 || _ROT == 180 + #define LED_IND(X,Y) _LED_IND(X,Y) + #define LED_BIT(X,Y) _LED_BIT(X) +#elif _ROT == 90 || _ROT == 270 + #define LED_IND(X,Y) _LED_IND(Y,X) + #define LED_BIT(X,Y) _LED_BIT(Y) +#endif +#define XOR_7219(X,Y) do{ led_line[LED_IND(X,Y)] ^= _BV(LED_BIT(X,Y)); }while(0) +#define SET_7219(X,Y) do{ led_line[LED_IND(X,Y)] |= _BV(LED_BIT(X,Y)); }while(0) +#define CLR_7219(X,Y) do{ led_line[LED_IND(X,Y)] &= ~_BV(LED_BIT(X,Y)); }while(0) +#define BIT_7219(X,Y) TEST(led_line[LED_IND(X,Y)], LED_BIT(X,Y)) + +#ifdef CPU_32_BIT + #define SIG_DELAY() DELAY_US(1) // Approximate a 1µs delay on 32-bit ARM + #undef CRITICAL_SECTION_START + #undef CRITICAL_SECTION_END + #define CRITICAL_SECTION_START NOOP + #define CRITICAL_SECTION_END NOOP +#else + #define SIG_DELAY() DELAY_NS(188) // Delay for 0.1875µs (16MHz AVR) or 0.15µs (20MHz AVR) #endif -// Delay for 0.1875µs (16MHz AVR) or 0.15µs (20MHz AVR) -#define SIG_DELAY() DELAY_NS(188) +void Max7219::error(const char * const func, const int32_t v1, const int32_t v2/*=-1*/) { + #if ENABLED(MAX7219_ERRORS) + SERIAL_ECHOPGM("??? Max7219::"); + serialprintPGM(func); + SERIAL_CHAR('('); + SERIAL_ECHO(v1); + if (v2 > 0) SERIAL_ECHOPAIR(", ", v2); + SERIAL_CHAR(')'); + SERIAL_EOL(); + #else + UNUSED(func); UNUSED(v1); UNUSED(v2); + #endif +} -void Max7219_PutByte(uint8_t data) { +/** + * Flip the lowest n_bytes of the supplied bits: + * flipped(x, 1) flips the low 8 bits of x. + * flipped(x, 2) flips the low 16 bits of x. + * flipped(x, 3) flips the low 24 bits of x. + * flipped(x, 4) flips the low 32 bits of x. + */ +inline uint32_t flipped(const uint32_t bits, const uint8_t n_bytes) { + uint32_t mask = 1, outbits = 0; + for (uint8_t b = 0; b < n_bytes * 8; b++) { + outbits <<= 1; + if (bits & mask) outbits |= 1; + mask <<= 1; + } + return outbits; +} + +void Max7219::noop() { + CRITICAL_SECTION_START; + SIG_DELAY(); + WRITE(MAX7219_DIN_PIN, LOW); + for (uint8_t i = 16; i--;) { + SIG_DELAY(); + WRITE(MAX7219_CLK_PIN, LOW); + SIG_DELAY(); + SIG_DELAY(); + WRITE(MAX7219_CLK_PIN, HIGH); + SIG_DELAY(); + } + CRITICAL_SECTION_END; +} + +void Max7219::putbyte(uint8_t data) { CRITICAL_SECTION_START; for (uint8_t i = 8; i--;) { SIG_DELAY(); @@ -100,26 +148,47 @@ void Max7219_PutByte(uint8_t data) { CRITICAL_SECTION_END; } -void Max7219(const uint8_t reg, const uint8_t data) { +void Max7219::pulse_load() { SIG_DELAY(); - CRITICAL_SECTION_START; - WRITE(MAX7219_LOAD_PIN, LOW); // begin - SIG_DELAY(); - Max7219_PutByte(reg); // specify register - SIG_DELAY(); - Max7219_PutByte(data); // put data - SIG_DELAY(); - WRITE(MAX7219_LOAD_PIN, LOW); // and tell the chip to load the data + WRITE(MAX7219_LOAD_PIN, LOW); // tell the chip to load the data SIG_DELAY(); WRITE(MAX7219_LOAD_PIN, HIGH); - CRITICAL_SECTION_END; SIG_DELAY(); } +void Max7219::send(const uint8_t reg, const uint8_t data) { + SIG_DELAY(); + CRITICAL_SECTION_START; + SIG_DELAY(); + putbyte(reg); // specify register + SIG_DELAY(); + putbyte(data); // put data + CRITICAL_SECTION_END; +} + +// Send out a single native row of bits to all units +void Max7219::refresh_line(const uint8_t line) { + for (uint8_t u = MAX7219_NUMBER_UNITS; u--;) + send(LINE_REG(line), led_line[(u << 3) | (line & 0x7)]); + pulse_load(); +} + +// Send out a single native row of bits to just one unit +void Max7219::refresh_unit_line(const uint8_t line) { + for (uint8_t u = MAX7219_NUMBER_UNITS; u--;) + if (u == (line >> 3)) send(LINE_REG(line), led_line[line]); else noop(); + pulse_load(); +} + +void Max7219::set(const uint8_t line, const uint8_t bits) { + led_line[line] = bits; + refresh_line(line); +} + #if ENABLED(MAX7219_NUMERIC) // Draw an integer with optional leading zeros and optional decimal point - void Max7219_Print(const uint8_t start, int16_t value, uint8_t size, const bool leadzero=false, bool dec=false) { + void Max7219::print(const uint8_t start, int16_t value, uint8_t size, const bool leadzero=false, bool dec=false) { constexpr uint8_t led_numeral[10] = { 0x7E, 0x60, 0x6D, 0x79, 0x63, 0x5B, 0x5F, 0x70, 0x7F, 0x7A }, led_decimal = 0x80, led_minus = 0x01; @@ -128,10 +197,11 @@ void Max7219(const uint8_t reg, const uint8_t data) { while (size--) { const bool minus = neg && blank; if (minus) neg = false; - Max7219( + send( max7219_reg_digit0 + start + size, minus ? led_minus : blank ? 0x00 : led_numeral[value % 10] | (dec ? led_decimal : 0x00) ); + pulse_load(); // tell the chips to load the clocked out data value /= 10; if (!value && !leadzero) blank = true; dec = false; @@ -139,175 +209,210 @@ void Max7219(const uint8_t reg, const uint8_t data) { } // Draw a float with a decimal point and optional digits - void Max7219_Print(const uint8_t start, const float value, const uint8_t pre_size, const uint8_t post_size, const bool leadzero=false) { - if (pre_size) Max7219_Print(start, value, pre_size, leadzero, !!post_size); + void Max7219::print(const uint8_t start, const float value, const uint8_t pre_size, const uint8_t post_size, const bool leadzero=false) { + if (pre_size) print(start, value, pre_size, leadzero, !!post_size); if (post_size) { const int16_t after = ABS(value) * (10 ^ post_size); - Max7219_Print(start + pre_size, after, post_size, true); + print(start + pre_size, after, post_size, true); } } #endif // MAX7219_NUMERIC -inline void Max7219_Error(const char * const func, const int32_t v1, const int32_t v2=-1) { - #if ENABLED(MAX7219_ERRORS) - SERIAL_ECHOPGM("??? "); - serialprintPGM(func); - SERIAL_CHAR('('); - SERIAL_ECHO(v1); - if (v2 > 0) SERIAL_ECHOPAIR(", ", v2); - SERIAL_CHAR(')'); - SERIAL_EOL(); - #else - UNUSED(func); UNUSED(v1); UNUSED(v2); - #endif -} - -inline uint8_t flipped(const uint8_t bits) { - uint8_t outbits = 0; - for (uint8_t b = 0; b < 8; b++) - if (bits & _BV(b)) outbits |= _BV(7 - b); - return outbits; -} - // Modify a single LED bit and send the changed line -void Max7219_LED_Set(const uint8_t x, const uint8_t y, const bool on) { - if (x > 7 || y > 7) return Max7219_Error(PSTR("Max7219_LED_Set"), x, y); +void Max7219::led_set(const uint8_t x, const uint8_t y, const bool on) { + if (x > MAX7219_X_LEDS - 1 || y > MAX7219_Y_LEDS - 1) return error(PSTR("led_set"), x, y); if (BIT_7219(x, y) == on) return; XOR_7219(x, y); - SEND_7219(_ROW_, LEDs[_ROW_]); + refresh_line(LED_IND(x, y)); } -void Max7219_LED_On(const uint8_t x, const uint8_t y) { - if (x > 7 || y > 7) return Max7219_Error(PSTR("Max7219_LED_On"), x, y); - Max7219_LED_Set(x, y, true); +void Max7219::led_on(const uint8_t x, const uint8_t y) { + if (x > MAX7219_X_LEDS - 1 || y > MAX7219_Y_LEDS - 1) return error(PSTR("led_on"), x, y); + led_set(x, y, true); } -void Max7219_LED_Off(const uint8_t x, const uint8_t y) { - if (x > 7 || y > 7) return Max7219_Error(PSTR("Max7219_LED_Off"), x, y); - Max7219_LED_Set(x, y, false); +void Max7219::led_off(const uint8_t x, const uint8_t y) { + if (x > MAX7219_X_LEDS - 1 || y > MAX7219_Y_LEDS - 1) return error(PSTR("led_off"), x, y); + led_set(x, y, false); } -void Max7219_LED_Toggle(const uint8_t x, const uint8_t y) { - if (x > 7 || y > 7) return Max7219_Error(PSTR("Max7219_LED_Toggle"), x, y); - Max7219_LED_Set(x, y, !BIT_7219(x, y)); +void Max7219::led_toggle(const uint8_t x, const uint8_t y) { + if (x > MAX7219_X_LEDS - 1 || y > MAX7219_Y_LEDS - 1) return error(PSTR("led_toggle"), x, y); + led_set(x, y, !BIT_7219(x, y)); } -inline void _Max7219_Set_Reg(const uint8_t reg, const uint8_t val) { - LEDs[reg] = val; - SEND_7219(reg, val); -} - -void Max7219_Set_Row(const uint8_t _ROW_, const uint8_t val) { - if (_ROW_ > 7) return Max7219_Error(PSTR("Max7219_Set_Row"), _ROW_); - #if _ROT == 90 - for (uint8_t _COL_ = 0; _COL_ <= 7; _COL_++) Max7219_LED_Set(7 - _COL_, _ROW_, TEST(val, _COL_)); - #elif _ROT == 180 - _Max7219_Set_Reg(_ROW_, flipped(val)); - #elif _ROT == 270 - for (uint8_t _COL_ = 0; _COL_ <= 7; _COL_++) Max7219_LED_Set(_COL_, _ROW_, TEST(val, _COL_)); +void Max7219::send_row(const uint8_t row) { + #if _ROT == 0 || _ROT == 180 + refresh_line(LED_IND(0, row)); #else - _Max7219_Set_Reg(_ROW_, val); + UNUSED(row); + refresh(); #endif } -void Max7219_Clear_Row(const uint8_t _ROW_) { - if (_ROW_ > 7) return Max7219_Error(PSTR("Max7219_Clear_Row"), _ROW_); +void Max7219::send_column(const uint8_t col) { #if _ROT == 90 || _ROT == 270 - for (uint8_t _COL_ = 0; _COL_ <= 7; _COL_++) Max7219_LED_Off(_COL_, _ROW_); + refresh_line(LED_IND(col, 0)); #else - _Max7219_Set_Reg(_ROW_, 0); + UNUSED(col); + refresh(); #endif } -void Max7219_Set_Column(const uint8_t _COL_, const uint8_t val) { - if (_COL_ > 7) return Max7219_Error(PSTR("Max7219_Set_Column"), _COL_); - #if _ROT == 90 - _Max7219_Set_Reg(_COL_, val); - #elif _ROT == 180 - for (uint8_t _ROW_ = 0; _ROW_ <= 7; _ROW_++) Max7219_LED_Set(_COL_, _ROW_, TEST(val, _ROW_)); - #elif _ROT == 270 - _Max7219_Set_Reg(_COL_, flipped(val)); - #else - for (uint8_t _ROW_ = 0; _ROW_ <= 7; _ROW_++) Max7219_LED_Set(_COL_, _ROW_, TEST(val, _ROW_)); +void Max7219::clear() { + ZERO(led_line); + refresh(); +} + +void Max7219::fill() { + memset(led_line, 0xFF, sizeof(led_line)); + refresh(); +} + +void Max7219::clear_row(const uint8_t row) { + if (row >= MAX7219_Y_LEDS) return error(PSTR("clear_row"), row); + for (uint8_t x = 0; x < MAX7219_X_LEDS; x++) CLR_7219(x, row); + send_row(row); +} + +void Max7219::clear_column(const uint8_t col) { + if (col >= MAX7219_X_LEDS) return error(PSTR("set_column"), col); + for (uint8_t y = 0; y < MAX7219_Y_LEDS; y++) CLR_7219(col, y); + send_column(col); +} + +/** + * Plot the low order bits of val to the specified row of the matrix. + * With 4 Max7219 units in the chain, it's possible to set 32 bits at once with + * one call to the function (if rotated 90° or 180°). + */ +void Max7219::set_row(const uint8_t row, const uint32_t val) { + if (row >= MAX7219_Y_LEDS) return error(PSTR("set_row"), row); + uint32_t mask = _BV32(MAX7219_X_LEDS - 1); + for (uint8_t x = 0; x < MAX7219_X_LEDS; x++) { + if (val & mask) SET_7219(x, row); else CLR_7219(x, row); + mask >>= 1; + } + send_row(row); +} + +/** + * Plot the low order bits of val to the specified column of the matrix. + * With 4 Max7219 units in the chain, it's possible to set 32 bits at once with + * one call to the function (if rotated 90° or 180°). + */ +void Max7219::set_column(const uint8_t col, const uint32_t val) { + if (col >= MAX7219_X_LEDS) return error(PSTR("set_column"), col); + uint32_t mask = _BV32(MAX7219_Y_LEDS - 1); + for (uint8_t y = 0; y < MAX7219_Y_LEDS; y++) { + if (val & mask) SET_7219(col, y); else CLR_7219(col, y); + mask >>= 1; + } + send_column(col); +} + +void Max7219::set_rows_16bits(const uint8_t y, uint32_t val) { + #if MAX7219_X_LEDS == 8 + if (y > MAX7219_Y_LEDS - 2) return error(PSTR("set_rows_16bits"), y, val); + set_row(y + 1, val); val >>= 8; + set_row(y + 0, val); + #else // at least 16 bits on each row + if (y > MAX7219_Y_LEDS - 1) return error(PSTR("set_rows_16bits"), y, val); + set_row(y, val); #endif } -void Max7219_Clear_Column(const uint8_t _COL_) { - if (_COL_ > 7) return Max7219_Error(PSTR("Max7219_Clear_Column"), _COL_); - #if _ROT == 90 || _ROT == 270 - _Max7219_Set_Reg(_COL_, 0); - #else - for (uint8_t _ROW_ = 0; _ROW_ <= 7; _ROW_++) Max7219_LED_Off(_COL_, _ROW_); +void Max7219::set_rows_32bits(const uint8_t y, uint32_t val) { + #if MAX7219_X_LEDS == 8 + if (y > MAX7219_Y_LEDS - 4) return error(PSTR("set_rows_32bits"), y, val); + set_row(y + 3, val); val >>= 8; + set_row(y + 2, val); val >>= 8; + set_row(y + 1, val); val >>= 8; + set_row(y + 0, val); + #elif MAX7219_X_LEDS == 16 + if (y > MAX7219_Y_LEDS - 2) return error(PSTR("set_rows_32bits"), y, val); + set_row(y + 1, val); val >>= 16; + set_row(y + 0, val); + #else // at least 24 bits on each row. In the 3 matrix case, just display the low 24 bits + if (y > MAX7219_Y_LEDS - 1) return error(PSTR("set_rows_32bits"), y, val); + set_row(y, val); #endif } -void Max7219_Clear() { - for (uint8_t r = 0; r < 8; r++) _Max7219_Set_Reg(r, 0); +void Max7219::set_columns_16bits(const uint8_t x, uint32_t val) { + #if MAX7219_Y_LEDS == 8 + if (x > MAX7219_X_LEDS - 2) return error(PSTR("set_columns_16bits"), x, val); + set_column(x + 0, val); val >>= 8; + set_column(x + 1, val); + #else // at least 16 bits in each column + if (x > MAX7219_X_LEDS - 1) return error(PSTR("set_columns_16bits"), x, val); + set_column(x, val); + #endif } -void Max7219_Set_2_Rows(const uint8_t y, uint16_t val) { - if (y > 6) return Max7219_Error(PSTR("Max7219_Set_2_Rows"), y, val); - Max7219_Set_Row(y + 0, val & 0xFF); val >>= 8; - Max7219_Set_Row(y + 1, val & 0xFF); +void Max7219::set_columns_32bits(const uint8_t x, uint32_t val) { + #if MAX7219_Y_LEDS == 8 + if (x > MAX7219_X_LEDS - 4) return error(PSTR("set_rows_32bits"), x, val); + set_column(x + 3, val); val >>= 8; + set_column(x + 2, val); val >>= 8; + set_column(x + 1, val); val >>= 8; + set_column(x + 0, val); + #elif MAX7219_Y_LEDS == 16 + if (x > MAX7219_X_LEDS - 2) return error(PSTR("set_rows_32bits"), x, val); + set_column(x + 1, val); val >>= 16; + set_column(x + 0, val); + #else // at least 24 bits on each row. In the 3 matrix case, just display the low 24 bits + if (x > MAX7219_X_LEDS - 1) return error(PSTR("set_rows_32bits"), x, val); + set_column(x, val); + #endif } -void Max7219_Set_4_Rows(const uint8_t y, uint32_t val) { - if (y > 4) return Max7219_Error(PSTR("Max7219_Set_4_Rows"), y, val); - Max7219_Set_Row(y + 0, val & 0xFF); val >>= 8; - Max7219_Set_Row(y + 1, val & 0xFF); val >>= 8; - Max7219_Set_Row(y + 2, val & 0xFF); val >>= 8; - Max7219_Set_Row(y + 3, val & 0xFF); -} +// Initialize the Max7219 +void Max7219::register_setup() { + for (uint8_t i = 0; i < MAX7219_NUMBER_UNITS; i++) + send(max7219_reg_scanLimit, 0x07); + pulse_load(); // tell the chips to load the clocked out data -void Max7219_Set_2_Columns(const uint8_t x, uint16_t val) { - if (x > 6) return Max7219_Error(PSTR("Max7219_Set_2_Columns"), x, val); - Max7219_Set_Column(x + 0, val & 0xFF); val >>= 8; - Max7219_Set_Column(x + 1, val & 0xFF); -} + for (uint8_t i = 0; i < MAX7219_NUMBER_UNITS; i++) + send(max7219_reg_decodeMode, 0x00); // using an led matrix (not digits) + pulse_load(); // tell the chips to load the clocked out data -void Max7219_Set_4_Columns(const uint8_t x, uint32_t val) { - if (x > 4) return Max7219_Error(PSTR("Max7219_Set_4_Columns"), x, val); - Max7219_Set_Column(x + 0, val & 0xFF); val >>= 8; - Max7219_Set_Column(x + 1, val & 0xFF); val >>= 8; - Max7219_Set_Column(x + 2, val & 0xFF); val >>= 8; - Max7219_Set_Column(x + 3, val & 0xFF); -} + for (uint8_t i = 0; i < MAX7219_NUMBER_UNITS; i++) + send(max7219_reg_shutdown, 0x01); // not in shutdown mode + pulse_load(); // tell the chips to load the clocked out data -void Max7219_register_setup() { - // Initialize the Max7219 - Max7219(max7219_reg_scanLimit, 0x07); - Max7219(max7219_reg_decodeMode, 0x00); // using an led matrix (not digits) - Max7219(max7219_reg_shutdown, 0x01); // not in shutdown mode - Max7219(max7219_reg_displayTest, 0x00); // no display test - Max7219(max7219_reg_intensity, 0x01 & 0x0F); // the first 0x0F is the value you can set - // range: 0x00 to 0x0F + for (uint8_t i = 0; i < MAX7219_NUMBER_UNITS; i++) + send(max7219_reg_displayTest, 0x00); // no display test + pulse_load(); // tell the chips to load the clocked out data + + for (uint8_t i = 0; i < MAX7219_NUMBER_UNITS; i++) + send(max7219_reg_intensity, 0x01 & 0x0F); // the first 0x0F is the value you can set + // range: 0x00 to 0x0F + pulse_load(); // tell the chips to load the clocked out data } #ifdef MAX7219_INIT_TEST -#if (MAX7219_INIT_TEST + 0) == 2 +#if MAX7219_INIT_TEST == 2 - inline void Max7219_spiral(const bool on, const uint16_t del) { + void Max7219::spiral(const bool on, const uint16_t del) { constexpr int8_t way[] = { 1, 0, 0, 1, -1, 0, 0, -1 }; int8_t px = 0, py = 0, dir = 0; - for (uint8_t i = 64; i--;) { - Max7219_LED_Set(px, py, on); + for (uint8_t i = MAX7219_X_LEDS * MAX7219_Y_LEDS; i--;) { + led_set(px, py, on); delay(del); const int8_t x = px + way[dir], y = py + way[dir + 1]; - if (!WITHIN(x, 0, 7) || !WITHIN(y, 0, 7) || BIT_7219(x, y) == on) dir = (dir + 2) & 0x7; + if (!WITHIN(x, 0, MAX7219_X_LEDS-1) || !WITHIN(y, 0, MAX7219_Y_LEDS-1) || BIT_7219(x, y) == on) dir = (dir + 2) & 0x7; px += way[dir]; py += way[dir + 1]; } } #else - inline void Max7219_colset(const uint8_t x, const bool on) { - for (uint8_t y = 0; y <= 7; y++) Max7219_LED_Set(x, y, on); - } - inline void Max7219_sweep(const int8_t dir, const uint16_t ms, const bool on) { - uint8_t x = dir > 0 ? 0 : 7; - for (uint8_t i = 8; i--; x += dir) { - Max7219_Set_Column(x, on ? 0xFF : 0x00); + void Max7219::sweep(const int8_t dir, const uint16_t ms, const bool on) { + uint8_t x = dir > 0 ? 0 : MAX7219_X_LEDS-1; + for (uint8_t i = MAX7219_X_LEDS; i--; x += dir) { + set_column(x, on ? 0xFFFFFFFF : 0x00000000); delay(ms); } } @@ -315,32 +420,33 @@ void Max7219_register_setup() { #endif #endif // MAX7219_INIT_TEST -void Max7219_init() { +void Max7219::init() { SET_OUTPUT(MAX7219_DIN_PIN); SET_OUTPUT(MAX7219_CLK_PIN); OUT_WRITE(MAX7219_LOAD_PIN, HIGH); delay(1); - Max7219_register_setup(); + register_setup(); for (uint8_t i = 0; i <= 7; i++) { // Empty registers to turn all LEDs off - LEDs[i] = 0x00; - Max7219(max7219_reg_digit0 + i, 0); + led_line[i] = 0x00; + send(max7219_reg_digit0 + i, 0); + pulse_load(); // tell the chips to load the clocked out data } #ifdef MAX7219_INIT_TEST - #if (MAX7219_INIT_TEST + 0) == 2 - Max7219_spiral(true, 8); + #if MAX7219_INIT_TEST == 2 + spiral(true, 8); delay(150); - Max7219_spiral(false, 8); + spiral(false, 8); #else // Do an aesthetically-pleasing pattern to fully test the Max7219 module and LEDs. // Light up and turn off columns, both forward and backward. - Max7219_sweep(1, 20, true); - Max7219_sweep(1, 20, false); + sweep(1, 20, true); + sweep(1, 20, false); delay(150); - Max7219_sweep(-1, 20, true); - Max7219_sweep(-1, 20, false); + sweep(-1, 20, true); + sweep(-1, 20, false); #endif #endif } @@ -352,26 +458,58 @@ void Max7219_init() { */ // Apply changes to update a marker -inline void Max7219_Mark16(const uint8_t y, const uint8_t v1, const uint8_t v2) { - Max7219_LED_Off(v1 & 0x7, y + (v1 >= 8)); - Max7219_LED_On(v2 & 0x7, y + (v2 >= 8)); +void Max7219::mark16(const uint8_t y, const uint8_t v1, const uint8_t v2) { + #if MAX7219_X_LEDS == 8 + #if MAX7219_Y_LEDS == 8 + led_off(v1 & 0x7, y + (v1 >= 8)); + led_on(v2 & 0x7, y + (v2 >= 8)); + #else + led_off(y, v1 & 0xF); // At least 16 LEDs down. Use a single column. + led_on(y, v2 & 0xF); + #endif + #else + led_off(v1 & 0xF, y); // At least 16 LEDs across. Use a single row. + led_on(v2 & 0xF, y); + #endif } // Apply changes to update a tail-to-head range -inline void Max7219_Range16(const uint8_t y, const uint8_t ot, const uint8_t nt, const uint8_t oh, const uint8_t nh) { - if (ot != nt) for (uint8_t n = ot & 0xF; n != (nt & 0xF) && n != (nh & 0xF); n = (n + 1) & 0xF) - Max7219_LED_Off(n & 0x7, y + (n >= 8)); - if (oh != nh) for (uint8_t n = (oh + 1) & 0xF; n != ((nh + 1) & 0xF); n = (n + 1) & 0xF) - Max7219_LED_On(n & 0x7, y + (n >= 8)); +void Max7219::range16(const uint8_t y, const uint8_t ot, const uint8_t nt, const uint8_t oh, const uint8_t nh) { + #if MAX7219_X_LEDS == 8 + #if MAX7219_Y_LEDS == 8 + if (ot != nt) for (uint8_t n = ot & 0xF; n != (nt & 0xF) && n != (nh & 0xF); n = (n + 1) & 0xF) + led_off(n & 0x7, y + (n >= 8)); + if (oh != nh) for (uint8_t n = (oh + 1) & 0xF; n != ((nh + 1) & 0xF); n = (n + 1) & 0xF) + led_on(n & 0x7, y + (n >= 8)); + #else // The Max7219 Y-Axis has at least 16 LED's. So use a single column + if (ot != nt) for (uint8_t n = ot & 0xF; n != (nt & 0xF) && n != (nh & 0xF); n = (n + 1) & 0xF) + led_off(y, n & 0xF); + if (oh != nh) for (uint8_t n = (oh + 1) & 0xF; n != ((nh + 1) & 0xF); n = (n + 1) & 0xF) + led_on(y, n & 0xF); + #endif + #else // LED matrix has at least 16 LED's on the X-Axis. Use single line of LED's + if (ot != nt) for (uint8_t n = ot & 0xF; n != (nt & 0xF) && n != (nh & 0xF); n = (n + 1) & 0xF) + led_off(n & 0xF, y); + if (oh != nh) for (uint8_t n = (oh + 1) & 0xF; n != ((nh + 1) & 0xF); n = (n + 1) & 0xF) + led_on(n & 0xF, y); + #endif } // Apply changes to update a quantity -inline void Max7219_Quantity16(const uint8_t y, const uint8_t ov, const uint8_t nv) { +void Max7219::quantity16(const uint8_t y, const uint8_t ov, const uint8_t nv) { for (uint8_t i = MIN(nv, ov); i < MAX(nv, ov); i++) - Max7219_LED_Set(i >> 1, y + (i & 1), nv >= ov); + #if MAX7219_X_LEDS == 8 + #if MAX7219_Y_LEDS == 8 + led_set(i >> 1, y + (i & 1), nv >= ov); // single 8x8 LED matrix. Use two lines to get 16 LED's + #else + led_set(y, i, nv >= ov); // The Max7219 Y-Axis has at least 16 LED's. So use a single column + #endif + #else + led_set(i, y, nv >= ov); // LED matrix has at least 16 LED's on the X-Axis. Use single line of LED's + #endif } -void Max7219_idle_tasks() { +void Max7219::idle_tasks() { #define MAX7219_USE_HEAD (defined(MAX7219_DEBUG_PLANNER_HEAD) || defined(MAX7219_DEBUG_PLANNER_QUEUE)) #define MAX7219_USE_TAIL (defined(MAX7219_DEBUG_PLANNER_TAIL) || defined(MAX7219_DEBUG_PLANNER_QUEUE)) #if MAX7219_USE_HEAD || MAX7219_USE_TAIL @@ -402,12 +540,12 @@ void Max7219_idle_tasks() { // corrupted, this will fix it within a couple seconds. if (do_blink && ++refresh_cnt >= refresh_limit) { refresh_cnt = 0; - Max7219_register_setup(); + register_setup(); } #if ENABLED(MAX7219_DEBUG_PRINTER_ALIVE) if (do_blink) { - Max7219_LED_Toggle(7, 7); + led_toggle(MAX7219_X_LEDS - 1, MAX7219_Y_LEDS - 1); next_blink = ms + 1000; } #endif @@ -417,7 +555,7 @@ void Max7219_idle_tasks() { static int16_t last_head_cnt = 0xF, last_tail_cnt = 0xF; if (last_head_cnt != head || last_tail_cnt != tail) { - Max7219_Range16(MAX7219_DEBUG_PLANNER_HEAD, last_tail_cnt, tail, last_head_cnt, head); + range16(MAX7219_DEBUG_PLANNER_HEAD, last_tail_cnt, tail, last_head_cnt, head); last_head_cnt = head; last_tail_cnt = tail; } @@ -427,7 +565,7 @@ void Max7219_idle_tasks() { #ifdef MAX7219_DEBUG_PLANNER_HEAD static int16_t last_head_cnt = 0x1; if (last_head_cnt != head) { - Max7219_Mark16(MAX7219_DEBUG_PLANNER_HEAD, last_head_cnt, head); + mark16(MAX7219_DEBUG_PLANNER_HEAD, last_head_cnt, head); last_head_cnt = head; } #endif @@ -435,7 +573,7 @@ void Max7219_idle_tasks() { #ifdef MAX7219_DEBUG_PLANNER_TAIL static int16_t last_tail_cnt = 0x1; if (last_tail_cnt != tail) { - Max7219_Mark16(MAX7219_DEBUG_PLANNER_TAIL, last_tail_cnt, tail); + mark16(MAX7219_DEBUG_PLANNER_TAIL, last_tail_cnt, tail); last_tail_cnt = tail; } #endif @@ -446,7 +584,7 @@ void Max7219_idle_tasks() { static int16_t last_depth = 0; const int16_t current_depth = (head - tail + BLOCK_BUFFER_SIZE) & (BLOCK_BUFFER_SIZE - 1) & 0xF; if (current_depth != last_depth) { - Max7219_Quantity16(MAX7219_DEBUG_PLANNER_QUEUE, last_depth, current_depth); + quantity16(MAX7219_DEBUG_PLANNER_QUEUE, last_depth, current_depth); last_depth = current_depth; } #endif diff --git a/Marlin/Max7219_Debug_LEDs.h b/Marlin/Max7219_Debug_LEDs.h index f00f231749..3523eef40f 100644 --- a/Marlin/Max7219_Debug_LEDs.h +++ b/Marlin/Max7219_Debug_LEDs.h @@ -31,12 +31,33 @@ * #define MAX7219_DIN_PIN 78 * #define MAX7219_LOAD_PIN 79 * - * Max7219_init() is called automatically at startup, and then there are a number of + * max7219.init() is called automatically at startup, and then there are a number of * support functions available to control the LEDs in the 8x8 grid. + * + * If you are using the Max7219 matrix for firmware debug purposes in time sensitive + * areas of the code, please be aware that the orientation (rotation) of the display can + * affect the speed. The Max7219 can update a single column fairly fast. It is much + * faster to do a Max7219_Set_Column() with a rotation of 90 or 270 degrees than to do + * a Max7219_Set_Row(). The opposite is true for rotations of 0 or 180 degrees. */ +#pragma once -#ifndef __MAX7219_DEBUG_LEDS_H__ -#define __MAX7219_DEBUG_LEDS_H__ +#ifndef MAX7219_ROTATE + #define MAX7219_ROTATE 0 +#endif +#define _ROT ((MAX7219_ROTATE + 360) % 360) + +#define MAX7219_LINES (8 * (MAX7219_NUMBER_UNITS)) + +#if _ROT == 0 || _ROT == 180 + #define MAX7219_Y_LEDS 8 + #define MAX7219_X_LEDS MAX7219_LINES +#elif _ROT == 90 || _ROT == 270 + #define MAX7219_X_LEDS 8 + #define MAX7219_Y_LEDS MAX7219_LINES +#else + #error "MAX7219_ROTATE must be a multiple of +/- 90°." +#endif // // MAX7219 registers @@ -57,30 +78,77 @@ #define max7219_reg_shutdown 0x0C #define max7219_reg_displayTest 0x0F -void Max7219_init(); -void Max7219_PutByte(uint8_t data); +class Max7219 { +public: + static uint8_t led_line[MAX7219_LINES]; -// Set a single register (e.g., a whole native row) -void Max7219(const uint8_t reg, const uint8_t data); + Max7219() { } -// Set a single LED by XY coordinate -void Max7219_LED_Set(const uint8_t x, const uint8_t y, const bool on); -void Max7219_LED_On(const uint8_t x, const uint8_t y); -void Max7219_LED_Off(const uint8_t x, const uint8_t y); -void Max7219_LED_Toggle(const uint8_t x, const uint8_t y); + static void init(); + static void register_setup(); + static void putbyte(uint8_t data); + static void pulse_load(); -// Set all 8 LEDs in a single column -void Max7219_Set_Column(const uint8_t col, const uint8_t val); -void Max7219_Clear_Column(const uint8_t col); + // Set a single register (e.g., a whole native row) + static void send(const uint8_t reg, const uint8_t data); -// Set all 8 LEDs in a single row -void Max7219_Set_Row(const uint8_t row, const uint8_t val); -void Max7219_Clear_Row(const uint8_t row); + // Refresh all units + inline static void refresh() { for (uint8_t i = 0; i < 8; i++) refresh_line(i); } -// Quickly clear the whole matrix -void Max7219_Clear(); + // Update a single native line on all units + static void refresh_line(const uint8_t line); -// Apply custom code to update the matrix -void Max7219_idle_tasks(); + // Update a single native line on just one unit + static void refresh_unit_line(const uint8_t line); -#endif // __MAX7219_DEBUG_LEDS_H__ + // Set a single LED by XY coordinate + static void led_set(const uint8_t x, const uint8_t y, const bool on); + static void led_on(const uint8_t x, const uint8_t y); + static void led_off(const uint8_t x, const uint8_t y); + static void led_toggle(const uint8_t x, const uint8_t y); + + // Set all LEDs in a single column + static void set_column(const uint8_t col, const uint32_t val); + static void clear_column(const uint8_t col); + + // Set all LEDs in a single row + static void set_row(const uint8_t row, const uint32_t val); + static void clear_row(const uint8_t row); + + // 16 and 32 bit versions of Row and Column functions + // Multiple rows and columns will be used to display the value if + // the array of matrix LED's is too narrow to accomplish the goal + static void set_rows_16bits(const uint8_t y, uint32_t val); + static void set_rows_32bits(const uint8_t y, uint32_t val); + static void set_columns_16bits(const uint8_t x, uint32_t val); + static void set_columns_32bits(const uint8_t x, uint32_t val); + + // Quickly clear the whole matrix + static void clear(); + + // Quickly fill the whole matrix + static void fill(); + + // Apply custom code to update the matrix + static void idle_tasks(); + +private: + static void error(const char * const func, const int32_t v1, const int32_t v2=-1); + static void noop(); + static void set(const uint8_t line, const uint8_t bits); + static void send_row(const uint8_t row); + static void send_column(const uint8_t col); + static void mark16(const uint8_t y, const uint8_t v1, const uint8_t v2); + static void range16(const uint8_t y, const uint8_t ot, const uint8_t nt, const uint8_t oh, const uint8_t nh); + static void quantity16(const uint8_t y, const uint8_t ov, const uint8_t nv); + + #ifdef MAX7219_INIT_TEST + #if MAX7219_INIT_TEST == 2 + static void spiral(const bool on, const uint16_t del); + #else + static void sweep(const int8_t dir, const uint16_t ms, const bool on); + #endif + #endif +}; + +extern Max7219 max7219; diff --git a/Marlin/SanityCheck.h b/Marlin/SanityCheck.h index 1b9832ebc6..7538ac49d3 100644 --- a/Marlin/SanityCheck.h +++ b/Marlin/SanityCheck.h @@ -265,10 +265,28 @@ #elif defined(MEASURED_LOWER_LIMIT) || defined(MEASURED_UPPER_LIMIT) #error "MEASURED_(UPPER|LOWER)_LIMIT is now FILWIDTH_ERROR_MARGIN. Please update your configuration." #elif defined(HAVE_TMCDRIVER) - #error "HAVE_TMCDRIVER is now HAVE_TMC26X. Please update your Configuration_adv.h." + #error "HAVE_TMCDRIVER is now [AXIS]_DRIVER_TYPE TMC26X. Please update your Configuration.h." +#elif defined(HAVE_TMC26X) + #error "HAVE_TMC26X is now [AXIS]_DRIVER_TYPE TMC26X. Please update your Configuration.h." +#elif defined(HAVE_TMC2130) + #error "HAVE_TMC2130 is now [AXIS]_DRIVER_TYPE TMC2130. Please update your Configuration.h." +#elif defined(HAVE_L6470DRIVER) + #error "HAVE_L6470DRIVER is now [AXIS]_DRIVER_TYPE L6470. Please update your Configuration.h." #elif defined(X_IS_TMC) || defined(X2_IS_TMC) || defined(Y_IS_TMC) || defined(Y2_IS_TMC) || defined(Z_IS_TMC) || defined(Z2_IS_TMC) \ || defined(E0_IS_TMC) || defined(E1_IS_TMC) || defined(E2_IS_TMC) || defined(E3_IS_TMC) || defined(E4_IS_TMC) - #error "[AXIS]_IS_TMC is now [AXIS]_IS_TMC26X. Please update your Configuration_adv.h." + #error "[AXIS]_IS_TMC is now [AXIS]_DRIVER_TYPE TMC26X. Please update your Configuration.h." +#elif defined(X_IS_TMC26X) || defined(X2_IS_TMC26X) || defined(Y_IS_TMC26X) || defined(Y2_IS_TMC26X) || defined(Z_IS_TMC26X) || defined(Z2_IS_TMC26X) \ + || defined(E0_IS_TMC26X) || defined(E1_IS_TMC26X) || defined(E2_IS_TMC26X) || defined(E3_IS_TMC26X) || defined(E4_IS_TMC26X) + #error "[AXIS]_IS_TMC26X is now [AXIS]_DRIVER_TYPE TMC26X. Please update your Configuration.h." +#elif defined(X_IS_TMC2130) || defined(X2_IS_TMC2130) || defined(Y_IS_TMC2130) || defined(Y2_IS_TMC2130) || defined(Z_IS_TMC2130) || defined(Z2_IS_TMC2130) \ + || defined(E0_IS_TMC2130) || defined(E1_IS_TMC2130) || defined(E2_IS_TMC2130) || defined(E3_IS_TMC2130) || defined(E4_IS_TMC2130) + #error "[AXIS]_IS_TMC2130 is now [AXIS]_DRIVER_TYPE TMC2130. Please update your Configuration.h." +#elif defined(X_IS_TMC2208) || defined(X2_IS_TMC2208) || defined(Y_IS_TMC2208) || defined(Y2_IS_TMC2208) || defined(Z_IS_TMC2208) || defined(Z2_IS_TMC2208) \ + || defined(E0_IS_TMC2208) || defined(E1_IS_TMC2208) || defined(E2_IS_TMC2208) || defined(E3_IS_TMC2208) || defined(E4_IS_TMC2208) + #error "[AXIS]_IS_TMC2208 is now [AXIS]_DRIVER_TYPE TMC2208. Please update your Configuration.h." +#elif defined(X_IS_L6470) || defined(X2_IS_L6470) || defined(Y_IS_L6470) || defined(Y2_IS_L6470) || defined(Z_IS_L6470) || defined(Z2_IS_L6470) \ + || defined(E0_IS_L6470) || defined(E1_IS_L6470) || defined(E2_IS_L6470) || defined(E3_IS_L6470) || defined(E4_IS_L6470) + #error "[AXIS]_IS_L6470 is now [AXIS]_DRIVER_TYPE L6470. Please update your Configuration.h." #elif defined(AUTOMATIC_CURRENT_CONTROL) #error "AUTOMATIC_CURRENT_CONTROL is now MONITOR_DRIVER_STATUS. Please update your configuration." #elif defined(FILAMENT_CHANGE_LOAD_LENGTH) @@ -385,10 +403,10 @@ static_assert(X_MAX_LENGTH >= X_BED_SIZE && Y_MAX_LENGTH >= Y_BED_SIZE, #if ENABLED(LCD_PROGRESS_BAR) #if DISABLED(SDSUPPORT) && DISABLED(LCD_SET_PROGRESS_MANUALLY) #error "LCD_PROGRESS_BAR requires SDSUPPORT or LCD_SET_PROGRESS_MANUALLY." - #elif DISABLED(ULTRA_LCD) - #error "LCD_PROGRESS_BAR requires a character LCD." #elif ENABLED(DOGLCD) #error "LCD_PROGRESS_BAR does not apply to graphical displays." + #elif DISABLED(ULTIPANEL) + #error "LCD_PROGRESS_BAR requires a character LCD." #elif ENABLED(FILAMENT_LCD_DISPLAY) #error "LCD_PROGRESS_BAR and FILAMENT_LCD_DISPLAY are not fully compatible. Comment out this line to use both." #endif @@ -447,6 +465,8 @@ static_assert(X_MAX_LENGTH >= X_BED_SIZE && Y_MAX_LENGTH >= Y_BED_SIZE, #if ENABLED(BABYSTEPPING) #if ENABLED(SCARA) #error "BABYSTEPPING is not implemented for SCARA yet." + #elif ENABLED(HANGPRINTER) + #error "BABYSTEPPING is not implemented for HANGPRINTER." #elif ENABLED(DELTA) && ENABLED(BABYSTEP_XY) #error "BABYSTEPPING only implemented for Z axis on deltabots." #elif ENABLED(BABYSTEP_ZPROBE_OFFSET) && ENABLED(MESH_BED_LEVELING) @@ -509,8 +529,12 @@ static_assert(X_MAX_LENGTH >= X_BED_SIZE && Y_MAX_LENGTH >= Y_BED_SIZE, /** * Individual axis homing is useless for DELTAS */ -#if ENABLED(INDIVIDUAL_AXIS_HOMING_MENU) && ENABLED(DELTA) - #error "INDIVIDUAL_AXIS_HOMING_MENU is incompatible with DELTA kinematics." +#if ENABLED(INDIVIDUAL_AXIS_HOMING_MENU) + #if ENABLED(DELTA) + #error "INDIVIDUAL_AXIS_HOMING_MENU is incompatible with DELTA kinematics." + #elif ENABLED(HANGPRINTER) + #error "INDIVIDUAL_AXIS_HOMING_MENU is incompatible with HANGPRINTER kinematics." + #endif #endif /** @@ -668,6 +692,7 @@ static_assert(X_MAX_LENGTH >= X_BED_SIZE && Y_MAX_LENGTH >= Y_BED_SIZE, * Allow only one kinematic type to be defined */ #if 1 < 0 \ + + ENABLED(HANGPRINTER) \ + ENABLED(DELTA) \ + ENABLED(MORGAN_SCARA) \ + ENABLED(MAKERARM_SCARA) \ @@ -677,7 +702,7 @@ static_assert(X_MAX_LENGTH >= X_BED_SIZE && Y_MAX_LENGTH >= Y_BED_SIZE, + ENABLED(COREYX) \ + ENABLED(COREZX) \ + ENABLED(COREZY) - #error "Please enable only one of DELTA, MORGAN_SCARA, MAKERARM_SCARA, COREXY, COREYX, COREXZ, COREZX, COREYZ, or COREZY." + #error "Please enable only one of HANGPRINTER, DELTA, MORGAN_SCARA, MAKERARM_SCARA, COREXY, COREYX, COREXZ, COREZX, COREYZ, or COREZY." #endif /** @@ -699,6 +724,42 @@ static_assert(X_MAX_LENGTH >= X_BED_SIZE && Y_MAX_LENGTH >= Y_BED_SIZE, #endif #endif +/** + * Hangprinter requirements + */ +#if ENABLED(HANGPRINTER) + #if EXTRUDERS > 4 + #error "Marlin supports a maximum of 4 EXTRUDERS when driving a Hangprinter." + #elif ENABLED(CONVENTIONAL_GEOMETRY) + #if ANCHOR_A_Y > 0 + #error "ANCHOR_A_Y should be negative by convention." + #elif (ANCHOR_B_X) * (ANCHOR_C_X) > 0 + #error "ANCHOR_B_X and ANCHOR_C_X should have opposite signs by convention." + #elif ANCHOR_B_Y < 0 + #error "ANCHOR_B_Y should be positive by convention." + #elif ANCHOR_C_Y < 0 + #error "ANCHOR_C_Y should be positive by convention." + #elif ANCHOR_A_Z > 0 + #error "ANCHOR_A_Z should be negative by convention." + #elif ANCHOR_B_Z > 0 + #error "ANCHOR_B_Z should be negative by convention." + #elif ANCHOR_C_Z > 0 + #error "ANCHOR_C_Z should be negative by convention." + #elif ANCHOR_D_Z < 0 + #error "ANCHOR_D_Z should be positive by convention." + #endif + #endif +#elif ENABLED(LINE_BUILDUP_COMPENSATION_FEATURE) + #error "LINE_BUILDUP_COMPENSATION_FEATURE is only compatible with HANGPRINTER." +#endif + +/** + * Mechaduino requirements + */ +#if ENABLED(MECHADUINO_I2C_COMMANDS) && DISABLED(EXPERIMENTAL_I2CBUS) + #error "MECHADUINO_I2C_COMMANDS requires EXPERIMENTAL_I2CBUS to be enabled." +#endif + /** * Probes */ @@ -743,6 +804,14 @@ static_assert(X_MAX_LENGTH >= X_BED_SIZE && Y_MAX_LENGTH >= Y_BED_SIZE, #if HAS_Z_SERVO_PROBE #ifndef NUM_SERVOS #error "You must set NUM_SERVOS for a Z servo probe (Z_PROBE_SERVO_NR)." + #elif Z_PROBE_SERVO_NR == 0 && !PIN_EXISTS(SERVO0) + #error "SERVO0_PIN must be defined for your servo or BLTOUCH probe." + #elif Z_PROBE_SERVO_NR == 1 && !PIN_EXISTS(SERVO1) + #error "SERVO1_PIN must be defined for your servo or BLTOUCH probe." + #elif Z_PROBE_SERVO_NR == 2 && !PIN_EXISTS(SERVO2) + #error "SERVO2_PIN must be defined for your servo or BLTOUCH probe." + #elif Z_PROBE_SERVO_NR == 3 && !PIN_EXISTS(SERVO3) + #error "SERVO3_PIN must be defined for your servo or BLTOUCH probe." #elif Z_PROBE_SERVO_NR >= NUM_SERVOS #error "Z_PROBE_SERVO_NR must be smaller than NUM_SERVOS." #endif @@ -792,6 +861,9 @@ static_assert(X_MAX_LENGTH >= X_BED_SIZE && Y_MAX_LENGTH >= Y_BED_SIZE, #error "Z_PROBE_LOW_POINT must be less than or equal to 0." #endif + static_assert(int(X_PROBE_OFFSET_FROM_EXTRUDER) == (X_PROBE_OFFSET_FROM_EXTRUDER), "X_PROBE_OFFSET_FROM_EXTRUDER must be an integer value."); + static_assert(int(Y_PROBE_OFFSET_FROM_EXTRUDER) == (Y_PROBE_OFFSET_FROM_EXTRUDER), "Y_PROBE_OFFSET_FROM_EXTRUDER must be an integer value."); + #else /** @@ -1182,6 +1254,7 @@ static_assert(X_MAX_LENGTH >= X_BED_SIZE && Y_MAX_LENGTH >= Y_BED_SIZE, #endif #endif #endif + /** * Endstop Tests */ @@ -1189,33 +1262,33 @@ static_assert(X_MAX_LENGTH >= X_BED_SIZE && Y_MAX_LENGTH >= Y_BED_SIZE, #define _PLUG_UNUSED_TEST(AXIS,PLUG) (DISABLED(USE_##PLUG##MIN_PLUG) && DISABLED(USE_##PLUG##MAX_PLUG) && !(ENABLED(AXIS##_DUAL_ENDSTOPS) && WITHIN(AXIS##2_USE_ENDSTOP, _##PLUG##MAX_, _##PLUG##MIN_))) #define _AXIS_PLUG_UNUSED_TEST(AXIS) (_PLUG_UNUSED_TEST(AXIS,X) && _PLUG_UNUSED_TEST(AXIS,Y) && _PLUG_UNUSED_TEST(AXIS,Z)) -// At least 3 endstop plugs must be used -#if _AXIS_PLUG_UNUSED_TEST(X) - #error "You must enable USE_XMIN_PLUG or USE_XMAX_PLUG." -#endif -#if _AXIS_PLUG_UNUSED_TEST(Y) - #error "You must enable USE_YMIN_PLUG or USE_YMAX_PLUG." -#endif -#if _AXIS_PLUG_UNUSED_TEST(Z) - #error "You must enable USE_ZMIN_PLUG or USE_ZMAX_PLUG." -#endif - -// Delta and Cartesian use 3 homing endstops -#if !IS_SCARA - #if X_HOME_DIR < 0 && DISABLED(USE_XMIN_PLUG) - #error "Enable USE_XMIN_PLUG when homing X to MIN." - #elif X_HOME_DIR > 0 && DISABLED(USE_XMAX_PLUG) - #error "Enable USE_XMAX_PLUG when homing X to MAX." - #elif Y_HOME_DIR < 0 && DISABLED(USE_YMIN_PLUG) - #error "Enable USE_YMIN_PLUG when homing Y to MIN." - #elif Y_HOME_DIR > 0 && DISABLED(USE_YMAX_PLUG) - #error "Enable USE_YMAX_PLUG when homing Y to MAX." +#if DISABLED(HANGPRINTER) + // At least 3 endstop plugs must be used + #if _AXIS_PLUG_UNUSED_TEST(X) + #error "You must enable USE_XMIN_PLUG or USE_XMAX_PLUG." + #elif _AXIS_PLUG_UNUSED_TEST(Y) + #error "You must enable USE_YMIN_PLUG or USE_YMAX_PLUG." + #elif _AXIS_PLUG_UNUSED_TEST(Z) + #error "You must enable USE_ZMIN_PLUG or USE_ZMAX_PLUG." + #endif + + // Delta and Cartesian use 3 homing endstops + #if !IS_SCARA + #if X_HOME_DIR < 0 && DISABLED(USE_XMIN_PLUG) + #error "Enable USE_XMIN_PLUG when homing X to MIN." + #elif X_HOME_DIR > 0 && DISABLED(USE_XMAX_PLUG) + #error "Enable USE_XMAX_PLUG when homing X to MAX." + #elif Y_HOME_DIR < 0 && DISABLED(USE_YMIN_PLUG) + #error "Enable USE_YMIN_PLUG when homing Y to MIN." + #elif Y_HOME_DIR > 0 && DISABLED(USE_YMAX_PLUG) + #error "Enable USE_YMAX_PLUG when homing Y to MAX." + #endif + #endif + #if Z_HOME_DIR < 0 && DISABLED(USE_ZMIN_PLUG) + #error "Enable USE_ZMIN_PLUG when homing Z to MIN." + #elif Z_HOME_DIR > 0 && DISABLED(USE_ZMAX_PLUG) + #error "Enable USE_ZMAX_PLUG when homing Z to MAX." #endif -#endif -#if Z_HOME_DIR < 0 && DISABLED(USE_ZMIN_PLUG) - #error "Enable USE_ZMIN_PLUG when homing Z to MIN." -#elif Z_HOME_DIR > 0 && DISABLED(USE_ZMAX_PLUG) - #error "Enable USE_ZMAX_PLUG when homing Z to MAX." #endif // Dual endstops requirements @@ -1413,246 +1486,95 @@ static_assert(X_MAX_LENGTH >= X_BED_SIZE && Y_MAX_LENGTH >= Y_BED_SIZE, #endif /** - * Make sure HAVE_TMC26X is warranted + * Check existing CS pins against enabled TMC SPI drivers. */ -#if ENABLED(HAVE_TMC26X) && !( \ - ENABLED( X_IS_TMC26X) \ - || ENABLED(X2_IS_TMC26X) \ - || ENABLED( Y_IS_TMC26X) \ - || ENABLED(Y2_IS_TMC26X) \ - || ENABLED( Z_IS_TMC26X) \ - || ENABLED(Z2_IS_TMC26X) \ - || ENABLED(E0_IS_TMC26X) \ - || ENABLED(E1_IS_TMC26X) \ - || ENABLED(E2_IS_TMC26X) \ - || ENABLED(E3_IS_TMC26X) \ - || ENABLED(E4_IS_TMC26X) \ - ) - #error "HAVE_TMC26X requires at least one TMC26X stepper to be set." +#if AXIS_DRIVER_TYPE(X, TMC2130) && !PIN_EXISTS(X_CS) + #error "X_CS_PIN is required for TMC2130. Define X_CS_PIN in Configuration_adv.h." +#elif AXIS_DRIVER_TYPE(X2, TMC2130) && !PIN_EXISTS(X2_CS) + #error "X2_CS_PIN is required for X2. Define X2_CS_PIN in Configuration_adv.h." +#elif AXIS_DRIVER_TYPE(Y, TMC2130) && !PIN_EXISTS(Y_CS) + #error "Y_CS_PIN is required for TMC2130. Define Y_CS_PIN in Configuration_adv.h." +#elif AXIS_DRIVER_TYPE(Y2, TMC2130) && !PIN_EXISTS(Y2_CS) + #error "Y2_CS_PIN is required for TMC2130. Define Y2_CS_PIN in Configuration_adv.h." +#elif AXIS_DRIVER_TYPE(Z, TMC2130) && !PIN_EXISTS(Z_CS) + #error "Z_CS_PIN is required for TMC2130. Define Z_CS_PIN in Configuration_adv.h." +#elif AXIS_DRIVER_TYPE(Z2, TMC2130) && !PIN_EXISTS(Z2_CS) + #error "Z2_CS_PIN is required for TMC2130. Define Z2_CS_PIN in Configuration_adv.h." +#elif AXIS_DRIVER_TYPE(E0, TMC2130) && !PIN_EXISTS(E0_CS) + #error "E0_CS_PIN is required for TMC2130. Define E0_CS_PIN in Configuration_adv.h." +#elif AXIS_DRIVER_TYPE(E1, TMC2130) && !PIN_EXISTS(E1_CS) + #error "E1_CS_PIN is required for TMC2130. Define E1_CS_PIN in Configuration_adv.h." +#elif AXIS_DRIVER_TYPE(E2, TMC2130) && !PIN_EXISTS(E2_CS) + #error "E2_CS_PIN is required for TMC2130. Define E2_CS_PIN in Configuration_adv.h." +#elif AXIS_DRIVER_TYPE(E3, TMC2130) && !PIN_EXISTS(E3_CS) + #error "E3_CS_PIN is required for TMC2130. Define E3_CS_PIN in Configuration_adv.h." +#elif AXIS_DRIVER_TYPE(E4, TMC2130) && !PIN_EXISTS(E4_CS) + #error "E4_CS_PIN is required for TMC2130. Define E4_CS_PIN in Configuration_adv.h." #endif /** - * TMC2130 Requirements + * TMC2208 software UART and ENDSTOP_INTERRUPTS both use pin change interrupts (PCI) */ -#if ENABLED(HAVE_TMC2130) - #if !( ENABLED( X_IS_TMC2130) \ - || ENABLED(X2_IS_TMC2130) \ - || ENABLED( Y_IS_TMC2130) \ - || ENABLED(Y2_IS_TMC2130) \ - || ENABLED( Z_IS_TMC2130) \ - || ENABLED(Z2_IS_TMC2130) \ - || ENABLED(E0_IS_TMC2130) \ - || ENABLED(E1_IS_TMC2130) \ - || ENABLED(E2_IS_TMC2130) \ - || ENABLED(E3_IS_TMC2130) \ - || ENABLED(E4_IS_TMC2130) ) - #error "HAVE_TMC2130 requires at least one TMC2130 stepper to be set." - #elif ENABLED(HYBRID_THRESHOLD) && DISABLED(STEALTHCHOP) - #error "Enable STEALTHCHOP to use HYBRID_THRESHOLD." - #endif - - #if ENABLED(X_IS_TMC2130) && !PIN_EXISTS(X_CS) - #error "X_CS_PIN is required for X_IS_TMC2130. Define X_CS_PIN in Configuration_adv.h." - #elif ENABLED(X2_IS_TMC2130) && !PIN_EXISTS(X2_CS) - #error "X2_CS_PIN is required for X2_IS_TMC2130. Define X2_CS_PIN in Configuration_adv.h." - #elif ENABLED(Y_IS_TMC2130) && !PIN_EXISTS(Y_CS) - #error "Y_CS_PIN is required for Y_IS_TMC2130. Define Y_CS_PIN in Configuration_adv.h." - #elif ENABLED(Y2_IS_TMC2130) && !PIN_EXISTS(Y2_CS) - #error "Y2_CS_PIN is required for Y2_IS_TMC2130. Define Y2_CS_PIN in Configuration_adv.h." - #elif ENABLED(Z_IS_TMC2130) && !PIN_EXISTS(Z_CS) - #error "Z_CS_PIN is required for Z_IS_TMC2130. Define Z_CS_PIN in Configuration_adv.h." - #elif ENABLED(Z2_IS_TMC2130) && !PIN_EXISTS(Z2_CS) - #error "Z2_CS_PIN is required for Z2_IS_TMC2130. Define Z2_CS_PIN in Configuration_adv.h." - #elif ENABLED(E0_IS_TMC2130) && !PIN_EXISTS(E0_CS) - #error "E0_CS_PIN is required for E0_IS_TMC2130. Define E0_CS_PIN in Configuration_adv.h." - #elif ENABLED(E1_IS_TMC2130) && !PIN_EXISTS(E1_CS) - #error "E1_CS_PIN is required for E1_IS_TMC2130. Define E1_CS_PIN in Configuration_adv.h." - #elif ENABLED(E2_IS_TMC2130) && !PIN_EXISTS(E2_CS) - #error "E2_CS_PIN is required for E2_IS_TMC2130. Define E2_CS_PIN in Configuration_adv.h." - #elif ENABLED(E3_IS_TMC2130) && !PIN_EXISTS(E3_CS) - #error "E3_CS_PIN is required for E3_IS_TMC2130. Define E3_CS_PIN in Configuration_adv.h." - #elif ENABLED(E4_IS_TMC2130) && !PIN_EXISTS(E4_CS) - #error "E4_CS_PIN is required for E4_IS_TMC2130. Define E4_CS_PIN in Configuration_adv.h." - #endif - - #if ENABLED(SENSORLESS_HOMING) - // Require STEALTHCHOP for SENSORLESS_HOMING on DELTA as the transition from spreadCycle to stealthChop - // is necessary in order to reset the stallGuard indication between the initial movement of all three - // towers to +Z and the individual homing of each tower. This restriction can be removed once a means of - // clearing the stallGuard activated status is found. - #if ENABLED(DELTA) && !ENABLED(STEALTHCHOP) - #error "SENSORLESS_HOMING on DELTA currently requires STEALTHCHOP." - #elif X_SENSORLESS && X_HOME_DIR == -1 && (DISABLED(X_MIN_ENDSTOP_INVERTING) || DISABLED(ENDSTOPPULLUP_XMIN)) - #error "SENSORLESS_HOMING requires X_MIN_ENDSTOP_INVERTING and ENDSTOPPULLUP_XMIN when homing to X_MIN." - #elif X_SENSORLESS && X_HOME_DIR == 1 && (DISABLED(X_MAX_ENDSTOP_INVERTING) || DISABLED(ENDSTOPPULLUP_XMAX)) - #error "SENSORLESS_HOMING requires X_MAX_ENDSTOP_INVERTING and ENDSTOPPULLUP_XMAX when homing to X_MAX." - #elif Y_SENSORLESS && Y_HOME_DIR == -1 && (DISABLED(Y_MIN_ENDSTOP_INVERTING) || DISABLED(ENDSTOPPULLUP_YMIN)) - #error "SENSORLESS_HOMING requires Y_MIN_ENDSTOP_INVERTING and ENDSTOPPULLUP_YMIN when homing to Y_MIN." - #elif Y_SENSORLESS && Y_HOME_DIR == 1 && (DISABLED(Y_MAX_ENDSTOP_INVERTING) || DISABLED(ENDSTOPPULLUP_YMAX)) - #error "SENSORLESS_HOMING requires Y_MAX_ENDSTOP_INVERTING and ENDSTOPPULLUP_YMAX when homing to Y_MAX." - #elif Z_SENSORLESS && Z_HOME_DIR == -1 && (DISABLED(Z_MIN_ENDSTOP_INVERTING) || DISABLED(ENDSTOPPULLUP_ZMIN)) - #error "SENSORLESS_HOMING requires Z_MIN_ENDSTOP_INVERTING and ENDSTOPPULLUP_ZMIN when homing to Z_MIN." - #elif Z_SENSORLESS && Z_HOME_DIR == 1 && (DISABLED(Z_MAX_ENDSTOP_INVERTING) || DISABLED(ENDSTOPPULLUP_ZMAX)) - #error "SENSORLESS_HOMING requires Z_MAX_ENDSTOP_INVERTING and ENDSTOPPULLUP_ZMAX when homing to Z_MAX." - #elif ENABLED(ENDSTOP_NOISE_FILTER) - #error "SENSORLESS_HOMING is incompatible with ENDSTOP_NOISE_FILTER." - #endif - #endif - - // Sensorless homing is required for both combined steppers in an H-bot - #if CORE_IS_XY && X_SENSORLESS != Y_SENSORLESS - #error "CoreXY requires both X and Y to use sensorless homing if either does." - #elif CORE_IS_XZ && X_SENSORLESS != Z_SENSORLESS - #error "CoreXZ requires both X and Z to use sensorless homing if either does." - #elif CORE_IS_YZ && Y_SENSORLESS != Z_SENSORLESS - #error "CoreYZ requires both Y and Z to use sensorless homing if either does." - #endif - -#elif ENABLED(SENSORLESS_HOMING) - - #error "SENSORLESS_HOMING requires TMC2130 stepper drivers." - +#if HAS_DRIVER(TMC2208) && ENABLED(ENDSTOP_INTERRUPTS_FEATURE) && !( \ + defined(X_HARDWARE_SERIAL ) \ + || defined(X2_HARDWARE_SERIAL) \ + || defined(Y_HARDWARE_SERIAL ) \ + || defined(Y2_HARDWARE_SERIAL) \ + || defined(Z_HARDWARE_SERIAL ) \ + || defined(Z2_HARDWARE_SERIAL) \ + || defined(E0_HARDWARE_SERIAL) \ + || defined(E1_HARDWARE_SERIAL) \ + || defined(E2_HARDWARE_SERIAL) \ + || defined(E3_HARDWARE_SERIAL) \ + || defined(E4_HARDWARE_SERIAL) ) + #error "select hardware UART for TMC2208 to use both TMC2208 and ENDSTOP_INTERRUPTS_FEATURE." #endif -/** - * TMC2208 Requirements - */ -#if ENABLED(HAVE_TMC2208) - #if !( ENABLED( X_IS_TMC2208) \ - || ENABLED(X2_IS_TMC2208) \ - || ENABLED( Y_IS_TMC2208) \ - || ENABLED(Y2_IS_TMC2208) \ - || ENABLED( Z_IS_TMC2208) \ - || ENABLED(Z2_IS_TMC2208) \ - || ENABLED(E0_IS_TMC2208) \ - || ENABLED(E1_IS_TMC2208) \ - || ENABLED(E2_IS_TMC2208) \ - || ENABLED(E3_IS_TMC2208) \ - || ENABLED(E4_IS_TMC2208 ) ) - #error "HAVE_TMC2208 requires at least one TMC2208 stepper to be set." - // Software UART and ENDSTOP_INTERRUPTS both use Pin Change interrupts (PCI) - #elif ENABLED(ENDSTOP_INTERRUPTS_FEATURE) && \ - !( defined( X_HARDWARE_SERIAL) \ - || defined(X2_HARDWARE_SERIAL) \ - || defined( Y_HARDWARE_SERIAL) \ - || defined(Y2_HARDWARE_SERIAL) \ - || defined( Z_HARDWARE_SERIAL) \ - || defined(Z2_HARDWARE_SERIAL) \ - || defined(E0_HARDWARE_SERIAL) \ - || defined(E1_HARDWARE_SERIAL) \ - || defined(E2_HARDWARE_SERIAL) \ - || defined(E3_HARDWARE_SERIAL) \ - || defined(E4_HARDWARE_SERIAL) ) - #error "Select *_HARDWARE_SERIAL to use both TMC2208 and ENDSTOP_INTERRUPTS_FEATURE." +#if ENABLED(SENSORLESS_HOMING) + // Require STEALTHCHOP for SENSORLESS_HOMING on DELTA as the transition from spreadCycle to stealthChop + // is necessary in order to reset the stallGuard indication between the initial movement of all three + // towers to +Z and the individual homing of each tower. This restriction can be removed once a means of + // clearing the stallGuard activated status is found. + #if ENABLED(DELTA) && !ENABLED(STEALTHCHOP) + #error "SENSORLESS_HOMING on DELTA currently requires STEALTHCHOP." + #elif X_SENSORLESS && X_HOME_DIR == -1 && (DISABLED(X_MIN_ENDSTOP_INVERTING) || DISABLED(ENDSTOPPULLUP_XMIN)) + #error "SENSORLESS_HOMING requires X_MIN_ENDSTOP_INVERTING and ENDSTOPPULLUP_XMIN when homing to X_MIN." + #elif X_SENSORLESS && X_HOME_DIR == 1 && (DISABLED(X_MAX_ENDSTOP_INVERTING) || DISABLED(ENDSTOPPULLUP_XMAX)) + #error "SENSORLESS_HOMING requires X_MAX_ENDSTOP_INVERTING and ENDSTOPPULLUP_XMAX when homing to X_MAX." + #elif Y_SENSORLESS && Y_HOME_DIR == -1 && (DISABLED(Y_MIN_ENDSTOP_INVERTING) || DISABLED(ENDSTOPPULLUP_YMIN)) + #error "SENSORLESS_HOMING requires Y_MIN_ENDSTOP_INVERTING and ENDSTOPPULLUP_YMIN when homing to Y_MIN." + #elif Y_SENSORLESS && Y_HOME_DIR == 1 && (DISABLED(Y_MAX_ENDSTOP_INVERTING) || DISABLED(ENDSTOPPULLUP_YMAX)) + #error "SENSORLESS_HOMING requires Y_MAX_ENDSTOP_INVERTING and ENDSTOPPULLUP_YMAX when homing to Y_MAX." + #elif Z_SENSORLESS && Z_HOME_DIR == -1 && (DISABLED(Z_MIN_ENDSTOP_INVERTING) || DISABLED(ENDSTOPPULLUP_ZMIN)) + #error "SENSORLESS_HOMING requires Z_MIN_ENDSTOP_INVERTING and ENDSTOPPULLUP_ZMIN when homing to Z_MIN." + #elif Z_SENSORLESS && Z_HOME_DIR == 1 && (DISABLED(Z_MAX_ENDSTOP_INVERTING) || DISABLED(ENDSTOPPULLUP_ZMAX)) + #error "SENSORLESS_HOMING requires Z_MAX_ENDSTOP_INVERTING and ENDSTOPPULLUP_ZMAX when homing to Z_MAX." + #elif ENABLED(ENDSTOP_NOISE_FILTER) + #error "SENSORLESS_HOMING is incompatible with ENDSTOP_NOISE_FILTER." #endif #endif +// Sensorless homing is required for both combined steppers in an H-bot +#if CORE_IS_XY && X_SENSORLESS != Y_SENSORLESS + #error "CoreXY requires both X and Y to use sensorless homing if either does." +#elif CORE_IS_XZ && X_SENSORLESS != Z_SENSORLESS + #error "CoreXZ requires both X and Z to use sensorless homing if either does." +#elif CORE_IS_YZ && Y_SENSORLESS != Z_SENSORLESS + #error "CoreYZ requires both Y and Z to use sensorless homing if either does." +#endif + #if ENABLED(HYBRID_THRESHOLD) && DISABLED(STEALTHCHOP) #error "Enable STEALTHCHOP to use HYBRID_THRESHOLD." #endif - -#if ENABLED(TMC_Z_CALIBRATION) && !Z_IS_TRINAMIC && !Z2_IS_TRINAMIC +#if ENABLED(TMC_Z_CALIBRATION) && !AXIS_IS_TMC(Z) && !AXIS_IS_TMC(Z2) #error "TMC_Z_CALIBRATION requires at least one TMC driver on Z axis" #endif -/** - * Make sure HAVE_L6470DRIVER is warranted - */ -#if ENABLED(HAVE_L6470DRIVER) && !( \ - ENABLED( X_IS_L6470) \ - || ENABLED(X2_IS_L6470) \ - || ENABLED( Y_IS_L6470) \ - || ENABLED(Y2_IS_L6470) \ - || ENABLED( Z_IS_L6470) \ - || ENABLED(Z2_IS_L6470) \ - || ENABLED(E0_IS_L6470) \ - || ENABLED(E1_IS_L6470) \ - || ENABLED(E2_IS_L6470) \ - || ENABLED(E3_IS_L6470) \ - || ENABLED(E4_IS_L6470) \ - ) - #error "HAVE_L6470DRIVER requires at least one L6470 stepper to be set." +#if ENABLED(SENSORLESS_HOMING) && !HAS_STALLGUARD + #error "SENSORLESS_HOMING requires TMC2130 or TMC2660 stepper drivers." #endif - -/** - * Check that each axis has only one driver selected - */ -#if 1 < 0 \ - + ENABLED(X_IS_TMC26X) \ - + ENABLED(X_IS_TMC2130) \ - + ENABLED(X_IS_TMC2208) \ - + ENABLED(X_IS_L6470) - #error "Please enable only one stepper driver for the X axis." -#endif -#if 1 < 0 \ - + ENABLED(X2_IS_TMC26X) \ - + ENABLED(X2_IS_TMC2130) \ - + ENABLED(X2_IS_TMC2208) \ - + ENABLED(X2_IS_L6470) - #error "Please enable only one stepper driver for the X2 axis." -#endif -#if 1 < 0 \ - + ENABLED(Y_IS_TMC26X) \ - + ENABLED(Y_IS_TMC2130) \ - + ENABLED(Y_IS_TMC2208) \ - + ENABLED(Y_IS_L6470) - #error "Please enable only one stepper driver for the Y axis." -#endif -#if 1 < 0 \ - + ENABLED(Y2_IS_TMC26X) \ - + ENABLED(Y2_IS_TMC2130) \ - + ENABLED(Y2_IS_TMC2208) \ - + ENABLED(Y2_IS_L6470) - #error "Please enable only one stepper driver for the Y2 axis." -#endif -#if 1 < 0 \ - + ENABLED(Z_IS_TMC26X) \ - + ENABLED(Z_IS_TMC2130) \ - + ENABLED(Z_IS_TMC2208) \ - + ENABLED(Z_IS_L6470) - #error "Please enable only one stepper driver for the Z axis." -#endif -#if 1 < 0 \ - + ENABLED(Z2_IS_TMC26X) \ - + ENABLED(Z2_IS_TMC2130) \ - + ENABLED(Z2_IS_TMC2208) \ - + ENABLED(Z2_IS_L6470) - #error "Please enable only one stepper driver for the Z2 axis." -#endif -#if 1 < 0 \ - + ENABLED(E0_IS_TMC26X) \ - + ENABLED(E0_IS_TMC2130) \ - + ENABLED(E0_IS_TMC2208) \ - + ENABLED(E0_IS_L6470) - #error "Please enable only one stepper driver for the E0 axis." -#endif -#if 1 < 0 \ - + ENABLED(E1_IS_TMC26X) \ - + ENABLED(E1_IS_TMC2130) \ - + ENABLED(E1_IS_TMC2208) \ - + ENABLED(E1_IS_L6470) - #error "Please enable only one stepper driver for the E1 axis." -#endif -#if 1 < 0 \ - + ENABLED(E2_IS_TMC26X) \ - + ENABLED(E2_IS_TMC2130) \ - + ENABLED(E2_IS_TMC2208) \ - + ENABLED(E2_IS_L6470) - #error "Please enable only one stepper driver for the E2 axis." -#endif -#if 1 < 0 \ - + ENABLED(E3_IS_TMC26X) \ - + ENABLED(E3_IS_TMC2130) \ - + ENABLED(E3_IS_TMC2208) \ - + ENABLED(E3_IS_L6470) - #error "Please enable only one stepper driver for the E3 axis." -#endif -#if 1 < 0 \ - + ENABLED(E4_IS_TMC26X) \ - + ENABLED(E4_IS_TMC2130) \ - + ENABLED(E4_IS_TMC2208) \ - + ENABLED(E4_IS_L6470) - #error "Please enable only one stepper driver for the E4 axis." +#if ENABLED(STEALTHCHOP) && !HAS_STEALTHCHOP + #error "STEALTHCHOP requires TMC2130 or TMC2208 stepper drivers." #endif /** @@ -1666,17 +1588,24 @@ static_assert(X_MAX_LENGTH >= X_BED_SIZE && Y_MAX_LENGTH >= Y_BED_SIZE, #endif /** - * Require 4 or more elements in per-axis initializers + * Require 5/4 or more elements in per-axis initializers */ +#if ENABLED(HANGPRINTER) + #define MIN_ELEMENTS "5" +#else + #define MIN_ELEMENTS "4" +#endif + constexpr float sanity_arr_1[] = DEFAULT_AXIS_STEPS_PER_UNIT, sanity_arr_2[] = DEFAULT_MAX_FEEDRATE, sanity_arr_3[] = DEFAULT_MAX_ACCELERATION; -static_assert(COUNT(sanity_arr_1) >= XYZE, "DEFAULT_AXIS_STEPS_PER_UNIT requires 4 (or more) elements."); -static_assert(COUNT(sanity_arr_2) >= XYZE, "DEFAULT_MAX_FEEDRATE requires 4 (or more) elements."); -static_assert(COUNT(sanity_arr_3) >= XYZE, "DEFAULT_MAX_ACCELERATION requires 4 (or more) elements."); -static_assert(COUNT(sanity_arr_1) <= XYZE_N, "DEFAULT_AXIS_STEPS_PER_UNIT has too many elements."); -static_assert(COUNT(sanity_arr_2) <= XYZE_N, "DEFAULT_MAX_FEEDRATE has too many elements."); -static_assert(COUNT(sanity_arr_3) <= XYZE_N, "DEFAULT_MAX_ACCELERATION has too many elements."); + +static_assert(COUNT(sanity_arr_1) >= NUM_AXIS, "DEFAULT_AXIS_STEPS_PER_UNIT requires " MIN_ELEMENTS " (or more) elements for HANGPRINTER."); +static_assert(COUNT(sanity_arr_2) >= NUM_AXIS, "DEFAULT_MAX_FEEDRATE requires " MIN_ELEMENTS " (or more) elements for HANGPRINTER."); +static_assert(COUNT(sanity_arr_3) >= NUM_AXIS, "DEFAULT_MAX_ACCELERATION requires " MIN_ELEMENTS " (or more) elements for HANGPRINTER."); +static_assert(COUNT(sanity_arr_1) <= NUM_AXIS_N, "DEFAULT_AXIS_STEPS_PER_UNIT has too many elements."); +static_assert(COUNT(sanity_arr_2) <= NUM_AXIS_N, "DEFAULT_MAX_FEEDRATE has too many elements."); +static_assert(COUNT(sanity_arr_3) <= NUM_AXIS_N, "DEFAULT_MAX_ACCELERATION has too many elements."); /** * Sanity checks for Spindle / Laser diff --git a/Marlin/Sd2Card.cpp b/Marlin/Sd2Card.cpp index ab3fc2f370..118b83cd9d 100644 --- a/Marlin/Sd2Card.cpp +++ b/Marlin/Sd2Card.cpp @@ -399,7 +399,7 @@ bool Sd2Card::readBlock(uint32_t blockNumber, uint8_t* dst) { #if ENABLED(SD_CHECK_AND_RETRY) uint8_t retryCnt = 3; - for(;;) { + for (;;) { if (cardCommand(CMD17, blockNumber)) error(SD_CARD_ERROR_CMD17); else if (readData(dst, 512)) diff --git a/Marlin/Version.h b/Marlin/Version.h index 47ad81d421..41d3e00561 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -35,7 +35,7 @@ /** * Marlin release version identifier */ - #define SHORT_BUILD_VERSION "1.1.8-R7" + #define SHORT_BUILD_VERSION "1.1.9-R2" /** * Verbose version identifier which should contain a reference to the location @@ -48,7 +48,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ - #define STRING_DISTRIBUTION_DATE "2018-07-07" + #define STRING_DISTRIBUTION_DATE "2018-09-28" /** * Required minimum Configuration.h and Configuration_adv.h file versions. @@ -89,6 +89,6 @@ * The WEBSITE_URL is the location where users can get more information such as * documentation about a specific Marlin release. */ - #define WEBSITE_URL "www.formbotusa.com" + #define WEBSITE_URL "tinymachines3d.com" #endif // USE_AUTOMATIC_VERSIONING diff --git a/Marlin/cardreader.cpp b/Marlin/cardreader.cpp index 5c4ff5e7d0..4f5fc0225e 100644 --- a/Marlin/cardreader.cpp +++ b/Marlin/cardreader.cpp @@ -35,8 +35,6 @@ #include "power_loss_recovery.h" #endif -#define LONGEST_FILENAME (longFilename[0] ? longFilename : filename) - CardReader::CardReader() { #if ENABLED(SDCARD_SORT_ALPHA) sort_count = 0; @@ -731,7 +729,7 @@ void CardReader::setroot() { getfilename(i); #if ENABLED(SDSORT_DYNAMIC_RAM) // Use dynamic method to copy long filename - sortnames[i] = strdup(LONGEST_FILENAME); + sortnames[i] = strdup(longest_filename()); #if ENABLED(SDSORT_CACHE_NAMES) // When caching also store the short name, since // we're replacing the getfilename() behavior. @@ -740,10 +738,10 @@ void CardReader::setroot() { #else // Copy filenames into the static array #if SORTED_LONGNAME_MAXLEN != LONG_FILENAME_LENGTH - strncpy(sortnames[i], LONGEST_FILENAME, SORTED_LONGNAME_MAXLEN); + strncpy(sortnames[i], longest_filename(), SORTED_LONGNAME_MAXLEN); sortnames[i][SORTED_LONGNAME_MAXLEN - 1] = '\0'; #else - strncpy(sortnames[i], LONGEST_FILENAME, SORTED_LONGNAME_MAXLEN); + strncpy(sortnames[i], longest_filename(), SORTED_LONGNAME_MAXLEN); #endif #if ENABLED(SDSORT_CACHE_NAMES) strcpy(sortshort[i], filename); @@ -791,12 +789,12 @@ void CardReader::setroot() { // throughout the loop. Slow if there are many. #if DISABLED(SDSORT_USES_RAM) getfilename(o1); - strcpy(name1, LONGEST_FILENAME); // save (or getfilename below will trounce it) + strcpy(name1, longest_filename()); // save (or getfilename below will trounce it) #if HAS_FOLDER_SORTING bool dir1 = filenameIsDir; #endif getfilename(o2); - char *name2 = LONGEST_FILENAME; // use the string in-place + char *name2 = longest_filename(); // use the string in-place #endif // !SDSORT_USES_RAM // Sort the current pair according to settings. @@ -834,7 +832,7 @@ void CardReader::setroot() { getfilename(0); #if ENABLED(SDSORT_DYNAMIC_RAM) sortnames = new char*[1]; - sortnames[0] = strdup(LONGEST_FILENAME); // malloc + sortnames[0] = strdup(longest_filename()); // malloc #if ENABLED(SDSORT_CACHE_NAMES) sortshort = new char*[1]; sortshort[0] = strdup(filename); // malloc @@ -842,10 +840,10 @@ void CardReader::setroot() { isDir = new uint8_t[1]; #else #if SORTED_LONGNAME_MAXLEN != LONG_FILENAME_LENGTH - strncpy(sortnames[0], LONGEST_FILENAME, SORTED_LONGNAME_MAXLEN); + strncpy(sortnames[0], longest_filename(), SORTED_LONGNAME_MAXLEN); sortnames[0][SORTED_LONGNAME_MAXLEN - 1] = '\0'; #else - strncpy(sortnames[0], LONGEST_FILENAME, SORTED_LONGNAME_MAXLEN); + strncpy(sortnames[0], longest_filename(), SORTED_LONGNAME_MAXLEN); #endif #if ENABLED(SDSORT_CACHE_NAMES) strcpy(sortshort[0], filename); diff --git a/Marlin/cardreader.h b/Marlin/cardreader.h index 15275c0729..bbc84d9db3 100644 --- a/Marlin/cardreader.h +++ b/Marlin/cardreader.h @@ -114,6 +114,8 @@ public: } #endif + FORCE_INLINE char* longest_filename() { return longFilename[0] ? longFilename : filename; } + public: bool saving, logging, sdprinting, cardOK, filenameIsDir; char filename[FILENAME_LENGTH], longFilename[LONG_FILENAME_LENGTH]; diff --git a/Marlin/configuration_store.cpp b/Marlin/configuration_store.cpp index 57d9de0e92..6ec8f53e43 100644 --- a/Marlin/configuration_store.cpp +++ b/Marlin/configuration_store.cpp @@ -95,19 +95,19 @@ typedef struct SettingsDataStruct { // // DISTINCT_E_FACTORS // - uint8_t esteppers; // XYZE_N - XYZ + uint8_t esteppers; // NUM_AXIS_N - MOV_AXIS - uint32_t planner_max_acceleration_mm_per_s2[XYZE_N], // M201 XYZE planner.max_acceleration_mm_per_s2[XYZE_N] - planner_min_segment_time_us; // M205 B planner.min_segment_time_us - float planner_axis_steps_per_mm[XYZE_N], // M92 XYZE planner.axis_steps_per_mm[XYZE_N] - planner_max_feedrate_mm_s[XYZE_N], // M203 XYZE planner.max_feedrate_mm_s[XYZE_N] - planner_acceleration, // M204 P planner.acceleration - planner_retract_acceleration, // M204 R planner.retract_acceleration - planner_travel_acceleration, // M204 T planner.travel_acceleration - planner_min_feedrate_mm_s, // M205 S planner.min_feedrate_mm_s - planner_min_travel_feedrate_mm_s, // M205 T planner.min_travel_feedrate_mm_s - planner_max_jerk[XYZE], // M205 XYZE planner.max_jerk[XYZE] - planner_junction_deviation_mm; // M205 J planner.junction_deviation_mm + uint32_t planner_max_acceleration_mm_per_s2[NUM_AXIS_N], // M201 XYZE/ABCDE planner.max_acceleration_mm_per_s2[NUM_AXIS_N] + planner_min_segment_time_us; // M205 Q planner.min_segment_time_us + float planner_axis_steps_per_mm[NUM_AXIS_N], // M92 XYZE/ABCDE planner.axis_steps_per_mm[NUM_AXIS_N] + planner_max_feedrate_mm_s[NUM_AXIS_N], // M203 XYZE/ABCDE planner.max_feedrate_mm_s[NUM_AXIS_N] + planner_acceleration, // M204 P planner.acceleration + planner_retract_acceleration, // M204 R planner.retract_acceleration + planner_travel_acceleration, // M204 T planner.travel_acceleration + planner_min_feedrate_mm_s, // M205 S planner.min_feedrate_mm_s + planner_min_travel_feedrate_mm_s, // M205 T planner.min_travel_feedrate_mm_s + planner_max_jerk[NUM_AXIS], // M205 XYZE/ABCDE planner.max_jerk[NUM_AXIS] + planner_junction_deviation_mm; // M205 J planner.junction_deviation_mm float home_offset[XYZ]; // M206 XYZ @@ -163,6 +163,7 @@ typedef struct SettingsDataStruct { // DELTA / [XYZ]_DUAL_ENDSTOPS // #if ENABLED(DELTA) + float delta_height, // M666 H delta_endstop_adj[ABC], // M666 XYZ delta_radius, // M665 R @@ -170,10 +171,27 @@ typedef struct SettingsDataStruct { delta_segments_per_second, // M665 S delta_calibration_radius, // M665 B delta_tower_angle_trim[ABC]; // M665 XYZ + + #elif ENABLED(HANGPRINTER) + + float anchor_A_y, // M665 W + anchor_A_z, // M665 E + anchor_B_x, // M665 R + anchor_B_y, // M665 T + anchor_B_z, // M665 Y + anchor_C_x, // M665 U + anchor_C_y, // M665 I + anchor_C_z, // M665 O + anchor_D_z, // M665 P + delta_segments_per_second, // M665 S + hangprinter_calibration_radius_placeholder; + #elif ENABLED(X_DUAL_ENDSTOPS) || ENABLED(Y_DUAL_ENDSTOPS) || ENABLED(Z_DUAL_ENDSTOPS) + float x_endstop_adj, // M666 X y_endstop_adj, // M666 Y z_endstop_adj; // M666 Z + #endif // @@ -285,6 +303,8 @@ void MarlinSettings::postprocess() { // planner position so the stepper counts will be set correctly. #if ENABLED(DELTA) recalc_delta_settings(); + #elif ENABLED(HANGPRINTER) + recalc_hangprinter_settings(); #endif #if ENABLED(PIDTEMP) @@ -418,7 +438,7 @@ void MarlinSettings::postprocess() { _FIELD_TEST(esteppers); - const uint8_t esteppers = COUNT(planner.axis_steps_per_mm) - XYZ; + const uint8_t esteppers = NUM_AXIS_N - MOV_AXIS; EEPROM_WRITE(esteppers); EEPROM_WRITE(planner.max_acceleration_mm_per_s2); @@ -432,7 +452,13 @@ void MarlinSettings::postprocess() { EEPROM_WRITE(planner.min_travel_feedrate_mm_s); #if ENABLED(JUNCTION_DEVIATION) - const float planner_max_jerk[] = { float(DEFAULT_XJERK), float(DEFAULT_YJERK), float(DEFAULT_ZJERK), float(DEFAULT_EJERK) }; + const float planner_max_jerk[] = { + #if ENABLED(HANGPRINTER) + float(DEFAULT_AJERK), float(DEFAULT_BJERK), float(DEFAULT_CJERK), float(DEFAULT_DJERK), float(DEFAULT_EJERK) + #else + float(DEFAULT_XJERK), float(DEFAULT_YJERK), float(DEFAULT_ZJERK), float(DEFAULT_EJERK) + #endif + }; EEPROM_WRITE(planner_max_jerk); EEPROM_WRITE(planner.junction_deviation_mm); #else @@ -560,6 +586,22 @@ void MarlinSettings::postprocess() { EEPROM_WRITE(delta_calibration_radius); // 1 float EEPROM_WRITE(delta_tower_angle_trim); // 3 floats + #elif ENABLED(HANGPRINTER) + + dummy = 0.0f; + _FIELD_TEST(anchor_A_y); + EEPROM_WRITE(anchor_A_y); // 1 float + EEPROM_WRITE(anchor_A_z); // 1 float + EEPROM_WRITE(anchor_B_x); // 1 float + EEPROM_WRITE(anchor_B_y); // 1 float + EEPROM_WRITE(anchor_B_z); // 1 float + EEPROM_WRITE(anchor_C_x); // 1 float + EEPROM_WRITE(anchor_C_y); // 1 float + EEPROM_WRITE(anchor_C_z); // 1 float + EEPROM_WRITE(anchor_D_z); // 1 float + EEPROM_WRITE(delta_segments_per_second); // 1 float + EEPROM_WRITE(dummy); // 1 float + #elif ENABLED(X_DUAL_ENDSTOPS) || ENABLED(Y_DUAL_ENDSTOPS) || ENABLED(Z_DUAL_ENDSTOPS) _FIELD_TEST(x_endstop_adj); @@ -696,57 +738,57 @@ void MarlinSettings::postprocess() { uint16_t tmc_stepper_current[TMC_AXES] = { #if HAS_TRINAMIC - #if X_IS_TRINAMIC + #if AXIS_IS_TMC(X) stepperX.getCurrent(), #else 0, #endif - #if Y_IS_TRINAMIC + #if AXIS_IS_TMC(Y) stepperY.getCurrent(), #else 0, #endif - #if Z_IS_TRINAMIC + #if AXIS_IS_TMC(Z) stepperZ.getCurrent(), #else 0, #endif - #if X2_IS_TRINAMIC + #if AXIS_IS_TMC(X2) stepperX2.getCurrent(), #else 0, #endif - #if Y2_IS_TRINAMIC + #if AXIS_IS_TMC(Y2) stepperY2.getCurrent(), #else 0, #endif - #if Z2_IS_TRINAMIC + #if AXIS_IS_TMC(Z2) stepperZ2.getCurrent(), #else 0, #endif - #if E0_IS_TRINAMIC + #if AXIS_IS_TMC(E0) stepperE0.getCurrent(), #else 0, #endif - #if E1_IS_TRINAMIC + #if AXIS_IS_TMC(E1) stepperE1.getCurrent(), #else 0, #endif - #if E2_IS_TRINAMIC + #if AXIS_IS_TMC(E2) stepperE2.getCurrent(), #else 0, #endif - #if E3_IS_TRINAMIC + #if AXIS_IS_TMC(E3) stepperE3.getCurrent(), #else 0, #endif - #if E4_IS_TRINAMIC + #if AXIS_IS_TMC(E4) stepperE4.getCurrent() #else 0 @@ -765,57 +807,57 @@ void MarlinSettings::postprocess() { uint32_t tmc_hybrid_threshold[TMC_AXES] = { #if ENABLED(HYBRID_THRESHOLD) - #if X_IS_TRINAMIC + #if AXIS_HAS_STEALTHCHOP(X) TMC_GET_PWMTHRS(X, X), #else X_HYBRID_THRESHOLD, #endif - #if Y_IS_TRINAMIC + #if AXIS_HAS_STEALTHCHOP(Y) TMC_GET_PWMTHRS(Y, Y), #else Y_HYBRID_THRESHOLD, #endif - #if Z_IS_TRINAMIC + #if AXIS_HAS_STEALTHCHOP(Z) TMC_GET_PWMTHRS(Z, Z), #else Z_HYBRID_THRESHOLD, #endif - #if X2_IS_TRINAMIC + #if AXIS_HAS_STEALTHCHOP(X2) TMC_GET_PWMTHRS(X, X2), #else X2_HYBRID_THRESHOLD, #endif - #if Y2_IS_TRINAMIC + #if AXIS_HAS_STEALTHCHOP(Y2) TMC_GET_PWMTHRS(Y, Y2), #else Y2_HYBRID_THRESHOLD, #endif - #if Z2_IS_TRINAMIC + #if AXIS_HAS_STEALTHCHOP(Z2) TMC_GET_PWMTHRS(Z, Z2), #else Z2_HYBRID_THRESHOLD, #endif - #if E0_IS_TRINAMIC + #if AXIS_HAS_STEALTHCHOP(E0) TMC_GET_PWMTHRS(E, E0), #else E0_HYBRID_THRESHOLD, #endif - #if E1_IS_TRINAMIC + #if AXIS_HAS_STEALTHCHOP(E1) TMC_GET_PWMTHRS(E, E1), #else E1_HYBRID_THRESHOLD, #endif - #if E2_IS_TRINAMIC + #if AXIS_HAS_STEALTHCHOP(E2) TMC_GET_PWMTHRS(E, E2), #else E2_HYBRID_THRESHOLD, #endif - #if E3_IS_TRINAMIC + #if AXIS_HAS_STEALTHCHOP(E3) TMC_GET_PWMTHRS(E, E3), #else E3_HYBRID_THRESHOLD, #endif - #if E4_IS_TRINAMIC + #if AXIS_HAS_STEALTHCHOP(E4) TMC_GET_PWMTHRS(E, E4) #else E4_HYBRID_THRESHOLD @@ -833,17 +875,17 @@ void MarlinSettings::postprocess() { // int16_t tmc_sgt[XYZ] = { #if ENABLED(SENSORLESS_HOMING) - #if defined(X_HOMING_SENSITIVITY) && (ENABLED(X_IS_TMC2130) || ENABLED(IS_TRAMS)) + #if X_SENSORLESS stepperX.sgt(), #else 0, #endif - #if defined(Y_HOMING_SENSITIVITY) && (ENABLED(Y_IS_TMC2130) || ENABLED(IS_TRAMS)) + #if Y_SENSORLESS stepperY.sgt(), #else 0, #endif - #if defined(Z_HOMING_SENSITIVITY) && (ENABLED(Z_IS_TMC2130) || ENABLED(IS_TRAMS)) + #if Z_SENSORLESS stepperZ.sgt() #else 0 @@ -1010,17 +1052,17 @@ void MarlinSettings::postprocess() { const uint32_t def1[] = DEFAULT_MAX_ACCELERATION; const float def2[] = DEFAULT_AXIS_STEPS_PER_UNIT, def3[] = DEFAULT_MAX_FEEDRATE; - uint32_t tmp1[XYZ + esteppers]; + uint32_t tmp1[MOV_AXIS + esteppers]; EEPROM_READ(tmp1); // max_acceleration_mm_per_s2 EEPROM_READ(planner.min_segment_time_us); - float tmp2[XYZ + esteppers], tmp3[XYZ + esteppers]; + float tmp2[MOV_AXIS + esteppers], tmp3[MOV_AXIS + esteppers]; EEPROM_READ(tmp2); // axis_steps_per_mm EEPROM_READ(tmp3); // max_feedrate_mm_s - if (!validating) LOOP_XYZE_N(i) { - planner.max_acceleration_mm_per_s2[i] = i < XYZ + esteppers ? tmp1[i] : def1[i < COUNT(def1) ? i : COUNT(def1) - 1]; - planner.axis_steps_per_mm[i] = i < XYZ + esteppers ? tmp2[i] : def2[i < COUNT(def2) ? i : COUNT(def2) - 1]; - planner.max_feedrate_mm_s[i] = i < XYZ + esteppers ? tmp3[i] : def3[i < COUNT(def3) ? i : COUNT(def3) - 1]; + if (!validating) LOOP_NUM_AXIS_N(i) { + planner.max_acceleration_mm_per_s2[i] = i < MOV_AXIS + esteppers ? tmp1[i] : def1[i < COUNT(def1) ? i : COUNT(def1) - 1]; + planner.axis_steps_per_mm[i] = i < MOV_AXIS + esteppers ? tmp2[i] : def2[i < COUNT(def2) ? i : COUNT(def2) - 1]; + planner.max_feedrate_mm_s[i] = i < MOV_AXIS + esteppers ? tmp3[i] : def3[i < COUNT(def3) ? i : COUNT(def3) - 1]; } EEPROM_READ(planner.acceleration); @@ -1165,6 +1207,19 @@ void MarlinSettings::postprocess() { EEPROM_READ(delta_calibration_radius); // 1 float EEPROM_READ(delta_tower_angle_trim); // 3 floats + #elif ENABLED(HANGPRINTER) + EEPROM_READ(anchor_A_y); // 1 float + EEPROM_READ(anchor_A_z); // 1 float + EEPROM_READ(anchor_B_x); // 1 float + EEPROM_READ(anchor_B_y); // 1 float + EEPROM_READ(anchor_B_z); // 1 float + EEPROM_READ(anchor_C_x); // 1 float + EEPROM_READ(anchor_C_y); // 1 float + EEPROM_READ(anchor_C_z); // 1 float + EEPROM_READ(anchor_D_z); // 1 float + EEPROM_READ(delta_segments_per_second); // 1 float + EEPROM_READ(dummy); // 1 float + #elif ENABLED(X_DUAL_ENDSTOPS) || ENABLED(Y_DUAL_ENDSTOPS) || ENABLED(Z_DUAL_ENDSTOPS) _FIELD_TEST(x_endstop_adj); @@ -1325,37 +1380,37 @@ void MarlinSettings::postprocess() { uint16_t currents[TMC_AXES]; EEPROM_READ(currents); if (!validating) { - #if X_IS_TRINAMIC + #if AXIS_IS_TMC(X) SET_CURR(X); #endif - #if Y_IS_TRINAMIC + #if AXIS_IS_TMC(Y) SET_CURR(Y); #endif - #if Z_IS_TRINAMIC + #if AXIS_IS_TMC(Z) SET_CURR(Z); #endif - #if X2_IS_TRINAMIC + #if AXIS_IS_TMC(X2) SET_CURR(X2); #endif - #if Y2_IS_TRINAMIC + #if AXIS_IS_TMC(Y2) SET_CURR(Y2); #endif - #if Z2_IS_TRINAMIC + #if AXIS_IS_TMC(Z2) SET_CURR(Z2); #endif - #if E0_IS_TRINAMIC + #if AXIS_IS_TMC(E0) SET_CURR(E0); #endif - #if E1_IS_TRINAMIC + #if AXIS_IS_TMC(E1) SET_CURR(E1); #endif - #if E2_IS_TRINAMIC + #if AXIS_IS_TMC(E2) SET_CURR(E2); #endif - #if E3_IS_TRINAMIC + #if AXIS_IS_TMC(E3) SET_CURR(E3); #endif - #if E4_IS_TRINAMIC + #if AXIS_IS_TMC(E4) SET_CURR(E4); #endif } @@ -1369,37 +1424,37 @@ void MarlinSettings::postprocess() { uint32_t tmc_hybrid_threshold[TMC_AXES]; EEPROM_READ(tmc_hybrid_threshold); if (!validating) { - #if X_IS_TRINAMIC + #if AXIS_HAS_STEALTHCHOP(X) TMC_SET_PWMTHRS(X, X); #endif - #if Y_IS_TRINAMIC + #if AXIS_HAS_STEALTHCHOP(Y) TMC_SET_PWMTHRS(Y, Y); #endif - #if Z_IS_TRINAMIC + #if AXIS_HAS_STEALTHCHOP(Z) TMC_SET_PWMTHRS(Z, Z); #endif - #if X2_IS_TRINAMIC + #if AXIS_HAS_STEALTHCHOP(X2) TMC_SET_PWMTHRS(X, X2); #endif - #if Y2_IS_TRINAMIC + #if AXIS_HAS_STEALTHCHOP(Y2) TMC_SET_PWMTHRS(Y, Y2); #endif - #if Z2_IS_TRINAMIC + #if AXIS_HAS_STEALTHCHOP(Z2) TMC_SET_PWMTHRS(Z, Z2); #endif - #if E0_IS_TRINAMIC + #if AXIS_HAS_STEALTHCHOP(E0) TMC_SET_PWMTHRS(E, E0); #endif - #if E1_IS_TRINAMIC + #if AXIS_HAS_STEALTHCHOP(E1) TMC_SET_PWMTHRS(E, E1); #endif - #if E2_IS_TRINAMIC + #if AXIS_HAS_STEALTHCHOP(E2) TMC_SET_PWMTHRS(E, E2); #endif - #if E3_IS_TRINAMIC + #if AXIS_HAS_STEALTHCHOP(E3) TMC_SET_PWMTHRS(E, E3); #endif - #if E4_IS_TRINAMIC + #if AXIS_HAS_STEALTHCHOP(E4) TMC_SET_PWMTHRS(E, E4); #endif } @@ -1419,26 +1474,26 @@ void MarlinSettings::postprocess() { #if ENABLED(SENSORLESS_HOMING) if (!validating) { #ifdef X_HOMING_SENSITIVITY - #if ENABLED(X_IS_TMC2130) || ENABLED(IS_TRAMS) + #if AXIS_HAS_STALLGUARD(X) stepperX.sgt(tmc_sgt[0]); #endif - #if ENABLED(X2_IS_TMC2130) + #if AXIS_HAS_STALLGUARD(X2) stepperX2.sgt(tmc_sgt[0]); #endif #endif #ifdef Y_HOMING_SENSITIVITY - #if ENABLED(Y_IS_TMC2130) || ENABLED(IS_TRAMS) + #if AXIS_HAS_STALLGUARD(Y) stepperY.sgt(tmc_sgt[1]); #endif - #if ENABLED(Y2_IS_TMC2130) + #if AXIS_HAS_STALLGUARD(Y2) stepperY2.sgt(tmc_sgt[1]); #endif #endif #ifdef Z_HOMING_SENSITIVITY - #if ENABLED(Z_IS_TMC2130) || ENABLED(IS_TRAMS) + #if AXIS_HAS_STALLGUARD(Z) stepperZ.sgt(tmc_sgt[2]); #endif - #if ENABLED(Z2_IS_TMC2130) + #if AXIS_HAS_STALLGUARD(Z2) stepperZ2.sgt(tmc_sgt[2]); #endif #endif @@ -1714,8 +1769,9 @@ void MarlinSettings::postprocess() { */ void MarlinSettings::reset() { static const float tmp1[] PROGMEM = DEFAULT_AXIS_STEPS_PER_UNIT, tmp2[] PROGMEM = DEFAULT_MAX_FEEDRATE; + static const uint32_t tmp3[] PROGMEM = DEFAULT_MAX_ACCELERATION; - LOOP_XYZE_N(i) { + LOOP_NUM_AXIS_N(i) { planner.axis_steps_per_mm[i] = pgm_read_float(&tmp1[i < COUNT(tmp1) ? i : COUNT(tmp1) - 1]); planner.max_feedrate_mm_s[i] = pgm_read_float(&tmp2[i < COUNT(tmp2) ? i : COUNT(tmp2) - 1]); planner.max_acceleration_mm_per_s2[i] = pgm_read_dword_near(&tmp3[i < COUNT(tmp3) ? i : COUNT(tmp3) - 1]); @@ -1731,9 +1787,16 @@ void MarlinSettings::reset() { #if ENABLED(JUNCTION_DEVIATION) planner.junction_deviation_mm = float(JUNCTION_DEVIATION_MM); #else - planner.max_jerk[X_AXIS] = DEFAULT_XJERK; - planner.max_jerk[Y_AXIS] = DEFAULT_YJERK; - planner.max_jerk[Z_AXIS] = DEFAULT_ZJERK; + #if ENABLED(HANGPRINTER) + planner.max_jerk[A_AXIS] = DEFAULT_AJERK; + planner.max_jerk[B_AXIS] = DEFAULT_BJERK; + planner.max_jerk[C_AXIS] = DEFAULT_CJERK; + planner.max_jerk[D_AXIS] = DEFAULT_DJERK; + #else + planner.max_jerk[X_AXIS] = DEFAULT_XJERK; + planner.max_jerk[Y_AXIS] = DEFAULT_YJERK; + planner.max_jerk[Z_AXIS] = DEFAULT_ZJERK; + #endif planner.max_jerk[E_AXIS] = DEFAULT_EJERK; #endif @@ -1785,6 +1848,19 @@ void MarlinSettings::reset() { delta_calibration_radius = DELTA_CALIBRATION_RADIUS; COPY(delta_tower_angle_trim, dta); + #elif ENABLED(HANGPRINTER) + + anchor_A_y = float(ANCHOR_A_Y); + anchor_A_z = float(ANCHOR_A_Z); + anchor_B_x = float(ANCHOR_B_X); + anchor_B_y = float(ANCHOR_B_Y); + anchor_B_z = float(ANCHOR_B_Z); + anchor_C_x = float(ANCHOR_C_X); + anchor_C_y = float(ANCHOR_C_Y); + anchor_C_z = float(ANCHOR_C_Z); + anchor_D_z = float(ANCHOR_D_Z); + delta_segments_per_second = KINEMATIC_SEGMENTS_PER_SECOND; + #elif ENABLED(X_DUAL_ENDSTOPS) || ENABLED(Y_DUAL_ENDSTOPS) || ENABLED(Z_DUAL_ENDSTOPS) #if ENABLED(X_DUAL_ENDSTOPS) @@ -1814,7 +1890,6 @@ void MarlinSettings::reset() { #endif ); #endif - #endif #if ENABLED(ULTIPANEL) @@ -2038,9 +2113,16 @@ void MarlinSettings::reset() { SERIAL_ECHOLNPGM("Steps per unit:"); } CONFIG_ECHO_START; - SERIAL_ECHOPAIR(" M92 X", LINEAR_UNIT(planner.axis_steps_per_mm[X_AXIS])); - SERIAL_ECHOPAIR(" Y", LINEAR_UNIT(planner.axis_steps_per_mm[Y_AXIS])); - SERIAL_ECHOPAIR(" Z", LINEAR_UNIT(planner.axis_steps_per_mm[Z_AXIS])); + #if ENABLED(HANGPRINTER) + SERIAL_ECHOPAIR(" M92 A", LINEAR_UNIT(planner.axis_steps_per_mm[A_AXIS])); + SERIAL_ECHOPAIR(" B", LINEAR_UNIT(planner.axis_steps_per_mm[B_AXIS])); + SERIAL_ECHOPAIR(" C", LINEAR_UNIT(planner.axis_steps_per_mm[C_AXIS])); + SERIAL_ECHOPAIR(" D", LINEAR_UNIT(planner.axis_steps_per_mm[D_AXIS])); + #else + SERIAL_ECHOPAIR(" M92 X", LINEAR_UNIT(planner.axis_steps_per_mm[X_AXIS])); + SERIAL_ECHOPAIR(" Y", LINEAR_UNIT(planner.axis_steps_per_mm[Y_AXIS])); + SERIAL_ECHOPAIR(" Z", LINEAR_UNIT(planner.axis_steps_per_mm[Z_AXIS])); + #endif #if DISABLED(DISTINCT_E_FACTORS) SERIAL_ECHOPAIR(" E", VOLUMETRIC_UNIT(planner.axis_steps_per_mm[E_AXIS])); #endif @@ -2058,9 +2140,16 @@ void MarlinSettings::reset() { SERIAL_ECHOLNPGM("Maximum feedrates (units/s):"); } CONFIG_ECHO_START; - SERIAL_ECHOPAIR(" M203 X", LINEAR_UNIT(planner.max_feedrate_mm_s[X_AXIS])); - SERIAL_ECHOPAIR(" Y", LINEAR_UNIT(planner.max_feedrate_mm_s[Y_AXIS])); - SERIAL_ECHOPAIR(" Z", LINEAR_UNIT(planner.max_feedrate_mm_s[Z_AXIS])); + #if ENABLED(HANGPRINTER) + SERIAL_ECHOPAIR(" M203 A", LINEAR_UNIT(planner.max_feedrate_mm_s[A_AXIS])); + SERIAL_ECHOPAIR(" B", LINEAR_UNIT(planner.max_feedrate_mm_s[B_AXIS])); + SERIAL_ECHOPAIR(" C", LINEAR_UNIT(planner.max_feedrate_mm_s[C_AXIS])); + SERIAL_ECHOPAIR(" D", LINEAR_UNIT(planner.max_feedrate_mm_s[D_AXIS])); + #else + SERIAL_ECHOPAIR(" M203 X", LINEAR_UNIT(planner.max_feedrate_mm_s[X_AXIS])); + SERIAL_ECHOPAIR(" Y", LINEAR_UNIT(planner.max_feedrate_mm_s[Y_AXIS])); + SERIAL_ECHOPAIR(" Z", LINEAR_UNIT(planner.max_feedrate_mm_s[Z_AXIS])); + #endif #if DISABLED(DISTINCT_E_FACTORS) SERIAL_ECHOPAIR(" E", VOLUMETRIC_UNIT(planner.max_feedrate_mm_s[E_AXIS])); #endif @@ -2078,9 +2167,16 @@ void MarlinSettings::reset() { SERIAL_ECHOLNPGM("Maximum Acceleration (units/s2):"); } CONFIG_ECHO_START; - SERIAL_ECHOPAIR(" M201 X", LINEAR_UNIT(planner.max_acceleration_mm_per_s2[X_AXIS])); - SERIAL_ECHOPAIR(" Y", LINEAR_UNIT(planner.max_acceleration_mm_per_s2[Y_AXIS])); - SERIAL_ECHOPAIR(" Z", LINEAR_UNIT(planner.max_acceleration_mm_per_s2[Z_AXIS])); + #if ENABLED(HANGPRINTER) + SERIAL_ECHOPAIR(" M201 A", LINEAR_UNIT(planner.max_acceleration_mm_per_s2[A_AXIS])); + SERIAL_ECHOPAIR(" B", LINEAR_UNIT(planner.max_acceleration_mm_per_s2[B_AXIS])); + SERIAL_ECHOPAIR(" C", LINEAR_UNIT(planner.max_acceleration_mm_per_s2[C_AXIS])); + SERIAL_ECHOPAIR(" D", LINEAR_UNIT(planner.max_acceleration_mm_per_s2[D_AXIS])); + #else + SERIAL_ECHOPAIR(" M201 X", LINEAR_UNIT(planner.max_acceleration_mm_per_s2[X_AXIS])); + SERIAL_ECHOPAIR(" Y", LINEAR_UNIT(planner.max_acceleration_mm_per_s2[Y_AXIS])); + SERIAL_ECHOPAIR(" Z", LINEAR_UNIT(planner.max_acceleration_mm_per_s2[Z_AXIS])); + #endif #if DISABLED(DISTINCT_E_FACTORS) SERIAL_ECHOPAIR(" E", VOLUMETRIC_UNIT(planner.max_acceleration_mm_per_s2[E_AXIS])); #endif @@ -2104,11 +2200,15 @@ void MarlinSettings::reset() { if (!forReplay) { CONFIG_ECHO_START; - SERIAL_ECHOPGM("Advanced: B S T"); + SERIAL_ECHOPGM("Advanced: Q S T"); #if ENABLED(JUNCTION_DEVIATION) SERIAL_ECHOPGM(" J"); #else - SERIAL_ECHOPGM(" X Y Z"); + #if ENABLED(HANGPRINTER) + SERIAL_ECHOPGM(" A B C D"); + #else + SERIAL_ECHOPGM(" X Y Z"); + #endif #endif #if DISABLED(JUNCTION_DEVIATION) || ENABLED(LIN_ADVANCE) SERIAL_ECHOPGM(" E"); @@ -2116,19 +2216,25 @@ void MarlinSettings::reset() { SERIAL_EOL(); } CONFIG_ECHO_START; - SERIAL_ECHOPAIR(" M205 B", LINEAR_UNIT(planner.min_segment_time_us)); + SERIAL_ECHOPAIR(" M205 Q", LINEAR_UNIT(planner.min_segment_time_us)); SERIAL_ECHOPAIR(" S", LINEAR_UNIT(planner.min_feedrate_mm_s)); SERIAL_ECHOPAIR(" T", LINEAR_UNIT(planner.min_travel_feedrate_mm_s)); #if ENABLED(JUNCTION_DEVIATION) SERIAL_ECHOPAIR(" J", LINEAR_UNIT(planner.junction_deviation_mm)); #else - SERIAL_ECHOPAIR(" X", LINEAR_UNIT(planner.max_jerk[X_AXIS])); - SERIAL_ECHOPAIR(" Y", LINEAR_UNIT(planner.max_jerk[Y_AXIS])); - SERIAL_ECHOPAIR(" Z", LINEAR_UNIT(planner.max_jerk[Z_AXIS])); + #if ENABLED(HANGPRINTER) + SERIAL_ECHOPAIR(" A", LINEAR_UNIT(planner.max_jerk[A_AXIS])); + SERIAL_ECHOPAIR(" B", LINEAR_UNIT(planner.max_jerk[B_AXIS])); + SERIAL_ECHOPAIR(" C", LINEAR_UNIT(planner.max_jerk[C_AXIS])); + SERIAL_ECHOPAIR(" D", LINEAR_UNIT(planner.max_jerk[D_AXIS])); + #else + SERIAL_ECHOPAIR(" X", LINEAR_UNIT(planner.max_jerk[X_AXIS])); + SERIAL_ECHOPAIR(" Y", LINEAR_UNIT(planner.max_jerk[Y_AXIS])); + SERIAL_ECHOPAIR(" Z", LINEAR_UNIT(planner.max_jerk[Z_AXIS])); + #endif SERIAL_ECHOPAIR(" E", LINEAR_UNIT(planner.max_jerk[E_AXIS])); #endif - SERIAL_EOL(); #if HAS_M206_COMMAND @@ -2220,8 +2326,8 @@ void MarlinSettings::reset() { SERIAL_ECHOLNPGM(" meshes.\n"); } - ubl.report_current_mesh(); - + //ubl.report_current_mesh(PORTVAR_SOLO); // This is too verbose for large mesh's. A better (more terse) + // solution needs to be found. #elif ENABLED(AUTO_BED_LEVELING_BILINEAR) if (leveling_is_valid()) { @@ -2266,6 +2372,24 @@ void MarlinSettings::reset() { SERIAL_ECHOPAIR(" Z", LINEAR_UNIT(delta_tower_angle_trim[C_AXIS])); SERIAL_EOL(); + #elif ENABLED(HANGPRINTER) + if (!forReplay) { + CONFIG_ECHO_START; + SERIAL_ECHOLNPGM("Hangprinter settings: W E R T Y U I O P S"); + } + CONFIG_ECHO_START; + SERIAL_ECHOPAIR(" M665 W", anchor_A_y); + SERIAL_ECHOPAIR(" E", anchor_A_z); + SERIAL_ECHOPAIR(" R", anchor_B_x); + SERIAL_ECHOPAIR(" T", anchor_B_y); + SERIAL_ECHOPAIR(" Y", anchor_B_z); + SERIAL_ECHOPAIR(" U", anchor_C_x); + SERIAL_ECHOPAIR(" I", anchor_C_y); + SERIAL_ECHOPAIR(" O", anchor_C_z); + SERIAL_ECHOPAIR(" P", anchor_D_z); + SERIAL_ECHOPAIR(" S", delta_segments_per_second); + SERIAL_EOL(); + #elif ENABLED(X_DUAL_ENDSTOPS) || ENABLED(Y_DUAL_ENDSTOPS) || ENABLED(Z_DUAL_ENDSTOPS) if (!forReplay) { @@ -2428,61 +2552,61 @@ void MarlinSettings::reset() { #if HAS_TRINAMIC /** - * TMC2130 / TMC2208 / TRAMS stepper driver current + * TMC2130 / TMC2208 stepper driver current */ if (!forReplay) { CONFIG_ECHO_START; SERIAL_ECHOLNPGM("Stepper driver current:"); } CONFIG_ECHO_START; - #if X_IS_TRINAMIC || Y_IS_TRINAMIC || Z_IS_TRINAMIC + #if AXIS_IS_TMC(X) || AXIS_IS_TMC(Y) || AXIS_IS_TMC(Z) say_M906(); #endif - #if X_IS_TRINAMIC + #if AXIS_IS_TMC(X) SERIAL_ECHOPAIR(" X", stepperX.getCurrent()); #endif - #if Y_IS_TRINAMIC + #if AXIS_IS_TMC(Y) SERIAL_ECHOPAIR(" Y", stepperY.getCurrent()); #endif - #if Z_IS_TRINAMIC + #if AXIS_IS_TMC(Z) SERIAL_ECHOPAIR(" Z", stepperZ.getCurrent()); #endif - #if X_IS_TRINAMIC || Y_IS_TRINAMIC || Z_IS_TRINAMIC + #if AXIS_IS_TMC(X) || AXIS_IS_TMC(Y) || AXIS_IS_TMC(Z) SERIAL_EOL(); #endif - #if X2_IS_TRINAMIC || Y2_IS_TRINAMIC || Z2_IS_TRINAMIC + #if AXIS_IS_TMC(X2) || AXIS_IS_TMC(Y2) || AXIS_IS_TMC(Z2) say_M906(); SERIAL_ECHOPGM(" I1"); #endif - #if X2_IS_TRINAMIC + #if AXIS_IS_TMC(X2) SERIAL_ECHOPAIR(" X", stepperX2.getCurrent()); #endif - #if Y2_IS_TRINAMIC + #if AXIS_IS_TMC(Y2) SERIAL_ECHOPAIR(" Y", stepperY2.getCurrent()); #endif - #if Z2_IS_TRINAMIC + #if AXIS_IS_TMC(Z2) SERIAL_ECHOPAIR(" Z", stepperZ2.getCurrent()); #endif - #if X2_IS_TRINAMIC || Y2_IS_TRINAMIC || Z2_IS_TRINAMIC + #if AXIS_IS_TMC(X2) || AXIS_IS_TMC(Y2) || AXIS_IS_TMC(Z2) SERIAL_EOL(); #endif - #if E0_IS_TRINAMIC + #if AXIS_IS_TMC(E0) say_M906(); SERIAL_ECHOLNPAIR(" T0 E", stepperE0.getCurrent()); #endif - #if E_STEPPERS > 1 && E1_IS_TRINAMIC + #if E_STEPPERS > 1 && AXIS_IS_TMC(E1) say_M906(); SERIAL_ECHOLNPAIR(" T1 E", stepperE1.getCurrent()); #endif - #if E_STEPPERS > 2 && E2_IS_TRINAMIC + #if E_STEPPERS > 2 && AXIS_IS_TMC(E2) say_M906(); SERIAL_ECHOLNPAIR(" T2 E", stepperE2.getCurrent()); #endif - #if E_STEPPERS > 3 && E3_IS_TRINAMIC + #if E_STEPPERS > 3 && AXIS_IS_TMC(E3) say_M906(); SERIAL_ECHOLNPAIR(" T3 E", stepperE3.getCurrent()); #endif - #if E_STEPPERS > 4 && E4_IS_TRINAMIC + #if E_STEPPERS > 4 && AXIS_IS_TMC(E4) say_M906(); SERIAL_ECHOLNPAIR(" T4 E", stepperE4.getCurrent()); #endif @@ -2497,54 +2621,54 @@ void MarlinSettings::reset() { SERIAL_ECHOLNPGM("Hybrid Threshold:"); } CONFIG_ECHO_START; - #if X_IS_TRINAMIC || Y_IS_TRINAMIC || Z_IS_TRINAMIC + #if AXIS_IS_TMC(X) || AXIS_IS_TMC(Y) || AXIS_IS_TMC(Z) say_M913(); #endif - #if X_IS_TRINAMIC + #if AXIS_IS_TMC(X) SERIAL_ECHOPAIR(" X", TMC_GET_PWMTHRS(X, X)); #endif - #if Y_IS_TRINAMIC + #if AXIS_IS_TMC(Y) SERIAL_ECHOPAIR(" Y", TMC_GET_PWMTHRS(Y, Y)); #endif - #if Z_IS_TRINAMIC + #if AXIS_IS_TMC(Z) SERIAL_ECHOPAIR(" Z", TMC_GET_PWMTHRS(Z, Z)); #endif - #if X_IS_TRINAMIC || Y_IS_TRINAMIC || Z_IS_TRINAMIC + #if AXIS_IS_TMC(X) || AXIS_IS_TMC(Y) || AXIS_IS_TMC(Z) SERIAL_EOL(); #endif - #if X2_IS_TRINAMIC || Y2_IS_TRINAMIC || Z2_IS_TRINAMIC + #if AXIS_IS_TMC(X2) || AXIS_IS_TMC(Y2) || AXIS_IS_TMC(Z2) say_M913(); SERIAL_ECHOPGM(" I1"); #endif - #if X2_IS_TRINAMIC + #if AXIS_IS_TMC(X2) SERIAL_ECHOPAIR(" X", TMC_GET_PWMTHRS(X, X2)); #endif - #if Y2_IS_TRINAMIC + #if AXIS_IS_TMC(Y2) SERIAL_ECHOPAIR(" Y", TMC_GET_PWMTHRS(Y, Y2)); #endif - #if Z2_IS_TRINAMIC + #if AXIS_IS_TMC(Z2) SERIAL_ECHOPAIR(" Z", TMC_GET_PWMTHRS(Z, Z2)); #endif - #if X2_IS_TRINAMIC || Y2_IS_TRINAMIC || Z2_IS_TRINAMIC + #if AXIS_IS_TMC(X2) || AXIS_IS_TMC(Y2) || AXIS_IS_TMC(Z2) SERIAL_EOL(); #endif - #if E0_IS_TRINAMIC + #if AXIS_IS_TMC(E0) say_M913(); SERIAL_ECHOLNPAIR(" T0 E", TMC_GET_PWMTHRS(E, E0)); #endif - #if E_STEPPERS > 1 && E1_IS_TRINAMIC + #if E_STEPPERS > 1 && AXIS_IS_TMC(E1) say_M913(); SERIAL_ECHOLNPAIR(" T1 E", TMC_GET_PWMTHRS(E, E1)); #endif - #if E_STEPPERS > 2 && E2_IS_TRINAMIC + #if E_STEPPERS > 2 && AXIS_IS_TMC(E2) say_M913(); SERIAL_ECHOLNPAIR(" T2 E", TMC_GET_PWMTHRS(E, E2)); #endif - #if E_STEPPERS > 3 && E3_IS_TRINAMIC + #if E_STEPPERS > 3 && AXIS_IS_TMC(E3) say_M913(); SERIAL_ECHOLNPAIR(" T3 E", TMC_GET_PWMTHRS(E, E3)); #endif - #if E_STEPPERS > 4 && E4_IS_TRINAMIC + #if E_STEPPERS > 4 && AXIS_IS_TMC(E4) say_M913(); SERIAL_ECHOLNPAIR(" T4 E", TMC_GET_PWMTHRS(E, E4)); #endif @@ -2560,36 +2684,33 @@ void MarlinSettings::reset() { SERIAL_ECHOLNPGM("Sensorless homing threshold:"); } CONFIG_ECHO_START; - #define HAS_X_SENSORLESS (defined(X_HOMING_SENSITIVITY) && (ENABLED(X_IS_TMC2130) || ENABLED(IS_TRAMS))) - #define HAS_Y_SENSORLESS (defined(Y_HOMING_SENSITIVITY) && (ENABLED(Y_IS_TMC2130) || ENABLED(IS_TRAMS))) - #define HAS_Z_SENSORLESS (defined(Z_HOMING_SENSITIVITY) && (ENABLED(Z_IS_TMC2130) || ENABLED(IS_TRAMS))) - #if HAS_X_SENSORLESS || HAS_Y_SENSORLESS || HAS_Z_SENSORLESS + #if X_SENSORLESS || Y_SENSORLESS || Z_SENSORLESS say_M914(); - #if HAS_X_SENSORLESS + #if X_SENSORLESS SERIAL_ECHOPAIR(" X", stepperX.sgt()); #endif - #if HAS_Y_SENSORLESS + #if Y_SENSORLESS SERIAL_ECHOPAIR(" Y", stepperY.sgt()); #endif - #if HAS_Z_SENSORLESS + #if Z_SENSORLESS SERIAL_ECHOPAIR(" Z", stepperZ.sgt()); #endif SERIAL_EOL(); #endif - #define HAS_X2_SENSORLESS (defined(X_HOMING_SENSITIVITY) && ENABLED(X2_IS_TMC2130)) - #define HAS_Y2_SENSORLESS (defined(Y_HOMING_SENSITIVITY) && ENABLED(Y2_IS_TMC2130)) - #define HAS_Z2_SENSORLESS (defined(Z_HOMING_SENSITIVITY) && ENABLED(Z2_IS_TMC2130)) - #if HAS_X2_SENSORLESS || HAS_Y2_SENSORLESS || HAS_Z2_SENSORLESS + #define X2_SENSORLESS (defined(X_HOMING_SENSITIVITY) && AXIS_HAS_STALLGUARD(X2)) + #define Y2_SENSORLESS (defined(Y_HOMING_SENSITIVITY) && AXIS_HAS_STALLGUARD(Y2)) + #define Z2_SENSORLESS (defined(Z_HOMING_SENSITIVITY) && AXIS_HAS_STALLGUARD(Z2)) + #if X2_SENSORLESS || Y2_SENSORLESS || Z2_SENSORLESS say_M914(); SERIAL_ECHOPGM(" I1"); - #if HAS_X2_SENSORLESS + #if X2_SENSORLESS SERIAL_ECHOPAIR(" X", stepperX2.sgt()); #endif - #if HAS_Y2_SENSORLESS + #if Y2_SENSORLESS SERIAL_ECHOPAIR(" Y", stepperY2.sgt()); #endif - #if HAS_Z2_SENSORLESS + #if Z2_SENSORLESS SERIAL_ECHOPAIR(" Z", stepperZ2.sgt()); #endif SERIAL_EOL(); diff --git a/Marlin/drivers.h b/Marlin/drivers.h new file mode 100644 index 0000000000..3a8ff4a2a0 --- /dev/null +++ b/Marlin/drivers.h @@ -0,0 +1,73 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (C) 2016 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 . + * + */ +#ifndef _DRIVERS_H_ +#define _DRIVERS_H_ + +#include "MarlinConfig.h" + +#define A4988 0x001 +#define DRV8825 0x002 +#define LV8729 0x003 +#define L6470 0x104 +#define TB6560 0x005 +#define TB6600 0x006 +#define TMC2100 0x007 +#define TMC2130 0x108 +#define TMC2130_STANDALONE 0x008 +#define TMC2208 0x109 +#define TMC2208_STANDALONE 0x009 +#define TMC26X 0x10A +#define TMC26X_STANDALONE 0x00A +#define TMC2660 0x10B +#define TMC2660_STANDALONE 0x00B + +#define _AXIS_DRIVER_TYPE(A,T) ( defined(A##_DRIVER_TYPE) && (A##_DRIVER_TYPE == T) ) + +#define AXIS_DRIVER_TYPE_X(T) _AXIS_DRIVER_TYPE(X,T) +#define AXIS_DRIVER_TYPE_Y(T) _AXIS_DRIVER_TYPE(Y,T) +#define AXIS_DRIVER_TYPE_Z(T) _AXIS_DRIVER_TYPE(Z,T) +#define AXIS_DRIVER_TYPE_X2(T) (ENABLED(X_DUAL_STEPPER_DRIVERS) || ENABLED(DUAL_X_CARRIAGE)) && _AXIS_DRIVER_TYPE(X2,T) +#define AXIS_DRIVER_TYPE_Y2(T) (ENABLED(Y_DUAL_STEPPER_DRIVERS) && _AXIS_DRIVER_TYPE(Y2,T)) +#define AXIS_DRIVER_TYPE_Z2(T) (ENABLED(Z_DUAL_STEPPER_DRIVERS) && _AXIS_DRIVER_TYPE(Z2,T)) +#define AXIS_DRIVER_TYPE_E0(T) (E_STEPPERS > 0 && _AXIS_DRIVER_TYPE(E0,T)) +#define AXIS_DRIVER_TYPE_E1(T) (E_STEPPERS > 1 && _AXIS_DRIVER_TYPE(E1,T)) +#define AXIS_DRIVER_TYPE_E2(T) (E_STEPPERS > 2 && _AXIS_DRIVER_TYPE(E2,T)) +#define AXIS_DRIVER_TYPE_E3(T) (E_STEPPERS > 3 && _AXIS_DRIVER_TYPE(E3,T)) +#define AXIS_DRIVER_TYPE_E4(T) (E_STEPPERS > 4 && _AXIS_DRIVER_TYPE(E4,T)) + +#define AXIS_DRIVER_TYPE(A,T) AXIS_DRIVER_TYPE_##A(T) + +#define HAS_DRIVER(T) (AXIS_DRIVER_TYPE_X(T) || AXIS_DRIVER_TYPE_X2(T) || \ + AXIS_DRIVER_TYPE_Y(T) || AXIS_DRIVER_TYPE_Y2(T) || \ + AXIS_DRIVER_TYPE_Z(T) || AXIS_DRIVER_TYPE_Z2(T) || \ + AXIS_DRIVER_TYPE_E0(T) || AXIS_DRIVER_TYPE_E1(T) || \ + AXIS_DRIVER_TYPE_E2(T) || AXIS_DRIVER_TYPE_E3(T) || \ + AXIS_DRIVER_TYPE_E4(T) ) + +// Test for supported TMC drivers that require advanced configuration +// Does not match standalone configurations +#define HAS_TRINAMIC (HAS_DRIVER(TMC2130) || HAS_DRIVER(TMC2208)) + +#define AXIS_IS_TMC(A) ( AXIS_DRIVER_TYPE_##A(TMC2130) || \ + AXIS_DRIVER_TYPE_##A(TMC2208) ) + +#endif // _DRIVERS_H_ diff --git a/Marlin/endstops.cpp b/Marlin/endstops.cpp index 3cffff1832..39fbc80134 100644 --- a/Marlin/endstops.cpp +++ b/Marlin/endstops.cpp @@ -189,7 +189,7 @@ void Endstops::init() { } // Endstops::init -// Called from ISR: Poll endstop state if required +// Called at ~1KHz from Temperature ISR: Poll endstop state if required void Endstops::poll() { #if ENABLED(PINS_DEBUGGING) @@ -229,11 +229,13 @@ void Endstops::not_homing() { #endif } -// If the last move failed to trigger an endstop, call kill -void Endstops::validate_homing_move() { - if (!trigger_state()) kill(PSTR(MSG_ERR_HOMING_FAILED)); - hit_on_purpose(); -} +#if ENABLED(VALIDATE_HOMING_ENDSTOPS) + // If the last move failed to trigger an endstop, call kill + void Endstops::validate_homing_move() { + if (trigger_state()) hit_on_purpose(); + else kill(PSTR(MSG_ERR_HOMING_FAILED)); + } +#endif // Enable / disable endstop z-probe checking #if HAS_BED_PROBE @@ -256,8 +258,9 @@ void Endstops::validate_homing_move() { } #endif -void Endstops::report_state() { - if (hit_state) { +void Endstops::event_handler() { + static uint8_t prev_hit_state; // = 0 + if (hit_state && hit_state != prev_hit_state) { #if ENABLED(ULTRA_LCD) char chrX = ' ', chrY = ' ', chrZ = ' ', chrP = ' '; #define _SET_STOP_CHAR(A,C) (chr## A = C) @@ -293,8 +296,6 @@ void Endstops::report_state() { lcd_status_printf_P(0, PSTR(MSG_LCD_ENDSTOPS " %c %c %c %c"), chrX, chrY, chrZ, chrP); #endif - hit_on_purpose(); - #if ENABLED(ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED) && ENABLED(SDSUPPORT) if (planner.abort_on_endstop_hit) { card.sdprinting = false; @@ -304,14 +305,19 @@ void Endstops::report_state() { } #endif } + prev_hit_state = hit_state; } // Endstops::report_state -void Endstops::M119() { +static void print_es_state(const bool is_hit, const char * const label=NULL) { + if (label) serialprintPGM(label); + SERIAL_PROTOCOLPGM(": "); + serialprintPGM(is_hit ? PSTR(MSG_ENDSTOP_HIT) : PSTR(MSG_ENDSTOP_OPEN)); + SERIAL_EOL(); +} + +void _O2 Endstops::M119() { SERIAL_PROTOCOLLNPGM(MSG_M119_REPORT); - #define ES_REPORT(AXIS) do{ \ - SERIAL_PROTOCOLPGM(MSG_##AXIS); \ - SERIAL_PROTOCOLLN(((READ(AXIS##_PIN)^AXIS##_ENDSTOP_INVERTING) ? MSG_ENDSTOP_HIT : MSG_ENDSTOP_OPEN)); \ - }while(0) + #define ES_REPORT(S) print_es_state(READ(S##_PIN) != S##_ENDSTOP_INVERTING, PSTR(MSG_##S)) #if HAS_X_MIN ES_REPORT(X_MIN); #endif @@ -349,12 +355,33 @@ void Endstops::M119() { ES_REPORT(Z2_MAX); #endif #if ENABLED(Z_MIN_PROBE_ENDSTOP) - SERIAL_PROTOCOLPGM(MSG_Z_PROBE); - SERIAL_PROTOCOLLN(((READ(Z_MIN_PROBE_PIN)^Z_MIN_PROBE_ENDSTOP_INVERTING) ? MSG_ENDSTOP_HIT : MSG_ENDSTOP_OPEN)); + print_es_state(READ(Z_MIN_PROBE_PIN) != Z_MIN_PROBE_ENDSTOP_INVERTING, PSTR(MSG_Z_PROBE)); #endif #if ENABLED(FILAMENT_RUNOUT_SENSOR) - SERIAL_PROTOCOLPGM(MSG_FILAMENT_RUNOUT_SENSOR); - SERIAL_PROTOCOLLN(((READ(FIL_RUNOUT_PIN)^FIL_RUNOUT_INVERTING) ? MSG_ENDSTOP_HIT : MSG_ENDSTOP_OPEN)); + #if NUM_RUNOUT_SENSORS == 1 + print_es_state(READ(FIL_RUNOUT_PIN) != FIL_RUNOUT_INVERTING, PSTR(MSG_FILAMENT_RUNOUT_SENSOR)); + #else + for (uint8_t i = 1; i <= NUM_RUNOUT_SENSORS; i++) { + pin_t pin; + switch (i) { + default: continue; + case 1: pin = FIL_RUNOUT_PIN; break; + case 2: pin = FIL_RUNOUT2_PIN; break; + #if NUM_RUNOUT_SENSORS > 2 + case 3: pin = FIL_RUNOUT3_PIN; break; + #if NUM_RUNOUT_SENSORS > 3 + case 4: pin = FIL_RUNOUT4_PIN; break; + #if NUM_RUNOUT_SENSORS > 4 + case 5: pin = FIL_RUNOUT5_PIN; break; + #endif + #endif + #endif + } + SERIAL_PROTOCOLPGM(MSG_FILAMENT_RUNOUT_SENSOR); + if (i > 1) { SERIAL_CHAR(' '); SERIAL_CHAR('0' + i); } + print_es_state(digitalRead(pin) != FIL_RUNOUT_INVERTING); + } + #endif #endif } // Endstops::M119 @@ -365,7 +392,7 @@ void Endstops::M119() { #define _ENDSTOP_PIN(AXIS, MINMAX) AXIS ##_## MINMAX ##_PIN #define _ENDSTOP_INVERTING(AXIS, MINMAX) AXIS ##_## MINMAX ##_ENDSTOP_INVERTING -// Check endstops - Could be called from ISR! +// Check endstops - Could be called from Temperature ISR! void Endstops::update() { #if DISABLED(ENDSTOP_NOISE_FILTER) @@ -540,7 +567,7 @@ void Endstops::update() { if (dual_hit) { \ _ENDSTOP_HIT(AXIS1, MINMAX); \ /* if not performing home or if both endstops were trigged during homing... */ \ - if (!stepper.homing_dual_axis || dual_hit == 0x3) \ + if (!stepper.homing_dual_axis || dual_hit == 0b11) \ planner.endstop_triggered(_AXIS(AXIS1)); \ } \ }while(0) diff --git a/Marlin/endstops.h b/Marlin/endstops.h index a6ea580d30..2114e23e3a 100644 --- a/Marlin/endstops.h +++ b/Marlin/endstops.h @@ -29,6 +29,8 @@ #include "MarlinConfig.h" +#define VALIDATE_HOMING_ENDSTOPS + enum EndstopEnum : char { X_MIN, Y_MIN, @@ -127,7 +129,7 @@ class Endstops { /** * Report endstop hits to serial. Called from loop(). */ - static void report_state(); + static void event_handler(); /** * Report endstop positions in response to M119 @@ -143,8 +145,12 @@ class Endstops { // Disable / Enable endstops based on ENSTOPS_ONLY_FOR_HOMING and global enable static void not_homing(); - // If the last move failed to trigger an endstop, call kill - static void validate_homing_move(); + #if ENABLED(VALIDATE_HOMING_ENDSTOPS) + // If the last move failed to trigger an endstop, call kill + static void validate_homing_move(); + #else + FORCE_INLINE static void validate_homing_move() { hit_on_purpose(); } + #endif // Clear endstops (i.e., they were hit intentionally) to suppress the report FORCE_INLINE static void hit_on_purpose() { hit_state = 0; } diff --git a/Marlin/enum.h b/Marlin/enum.h index d525e8ee9b..470afef1da 100644 --- a/Marlin/enum.h +++ b/Marlin/enum.h @@ -39,10 +39,14 @@ enum AxisEnum : unsigned char { B_AXIS = 1, Z_AXIS = 2, C_AXIS = 2, - E_AXIS = 3, - X_HEAD = 4, - Y_HEAD = 5, - Z_HEAD = 6, + E_CART = 3, + #if ENABLED(HANGPRINTER) // Hangprinter order: A_AXIS, B_AXIS, C_AXIS, D_AXIS, E_AXIS + D_AXIS = 3, + E_AXIS = 4, + #else + E_AXIS = 3, + #endif + X_HEAD, Y_HEAD, Z_HEAD, ALL_AXES = 0xFE, NO_AXIS = 0xFF }; @@ -54,11 +58,11 @@ enum AxisEnum : unsigned char { #define LOOP_NA(VAR) LOOP_L_N(VAR, NUM_AXIS) #define LOOP_XYZ(VAR) LOOP_S_LE_N(VAR, X_AXIS, Z_AXIS) -#define LOOP_XYZE(VAR) LOOP_S_LE_N(VAR, X_AXIS, E_AXIS) +#define LOOP_XYZE(VAR) LOOP_S_LE_N(VAR, X_AXIS, E_CART) #define LOOP_XYZE_N(VAR) LOOP_S_L_N(VAR, X_AXIS, XYZE_N) -#define LOOP_ABC(VAR) LOOP_S_LE_N(VAR, A_AXIS, C_AXIS) -#define LOOP_ABCE(VAR) LOOP_S_LE_N(VAR, A_AXIS, E_AXIS) -#define LOOP_ABCE_N(VAR) LOOP_S_L_N(VAR, A_AXIS, XYZE_N) +#define LOOP_MOV_AXIS(VAR) LOOP_S_L_N(VAR, A_AXIS, MOV_AXIS) +#define LOOP_NUM_AXIS(VAR) LOOP_S_L_N(VAR, A_AXIS, NUM_AXIS) +#define LOOP_NUM_AXIS_N(VAR) LOOP_S_L_N(VAR, A_AXIS, NUM_AXIS_N) typedef enum { LINEARUNIT_MM, diff --git a/Marlin/fastio_1280.h b/Marlin/fastio_1280.h index b95ddffbad..09bac1fd11 100644 --- a/Marlin/fastio_1280.h +++ b/Marlin/fastio_1280.h @@ -23,8 +23,9 @@ /** * Pin mapping for the 1280 and 2560 * - * Logical Pin: 22 23 24 25 26 27 28 29 53 52 51 50 10 11 12 13 37 36 35 34 33 32 31 30 21 20 19 18 81 82 83 38 00 01 78 05 02 03 79 80 54 55 56 57 58 59 60 61 41 40 39 71 70 04 17 16 84 06 07 08 09 85 15 14 72 73 75 76 77 74 62 63 64 65 66 67 68 69 49 48 47 46 45 44 43 42 - * Port: A0 A1 A2 A3 A4 A5 A6 A7 B0 B1 B2 B3 B4 B5 B6 B7 C0 C1 C2 C3 C4 C5 C6 C7 D0 D1 D2 D3 D4 D5 D6 D7 E0 E1 E2 E3 E4 E5 E6 E7 F0 F1 F2 F3 F4 F5 F6 F7 G0 G1 G2 G3 G4 G5 H0 H1 H2 H3 H4 H5 H6 H7 J0 J1 J2 J3 J4 J5 J6 J7 K0 K1 K2 K3 K4 K5 K6 K7 L0 L1 L2 L3 L4 L5 L6 L7 + * Hardware Pin : 02 03 06 07 01 05 15 16 17 18 23 24 25 26 64 63 13 12 46 45 44 43 78 77 76 75 74 73 72 71 60 59 58 57 56 55 54 53 50 70 52 51 42 41 40 39 38 37 36 35 22 21 20 19 97 96 95 94 93 92 91 90 89 88 87 86 85 84 83 82 04 08 09 10 11 14 27 28 29 30 31 32 33 34 47 48 49 61 62 65 66 67 68 69 79 80 81 98 99 100 + * Port : E0 E1 E4 E5 G5 E3 H3 H4 H5 H6 B4 B5 B6 B7 J1 J0 H1 H0 D3 D2 D1 D0 A0 A1 A2 A3 A4 A5 A6 A7 C7 C6 C5 C4 C3 C2 C1 C0 D7 G2 G1 G0 L7 L6 L5 L4 L3 L2 L1 L0 B3 B2 B1 B0 F0 F1 F2 F3 F4 F5 F6 F7 K0 K1 K2 K3 K4 K5 K6 K7 E2 E6 E7 xx xx H2 H7 G3 G4 xx xx xx xx xx D4 D5 D6 xx xx J2 J3 J4 J5 J6 J7 xx xx xx xx xx + * Logical Pin : 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx */ #ifndef _FASTIO_1280 diff --git a/Marlin/fwretract.cpp b/Marlin/fwretract.cpp index 997e49a7f9..7723fcd1cd 100644 --- a/Marlin/fwretract.cpp +++ b/Marlin/fwretract.cpp @@ -123,7 +123,7 @@ void FWRetract::retract(const bool retracting #endif } SERIAL_ECHOLNPAIR("current_position[z] ", current_position[Z_AXIS]); - SERIAL_ECHOLNPAIR("current_position[e] ", current_position[E_AXIS]); + SERIAL_ECHOLNPAIR("current_position[e] ", current_position[E_CART]); SERIAL_ECHOLNPAIR("hop_amount ", hop_amount); //*/ @@ -131,7 +131,7 @@ void FWRetract::retract(const bool retracting renormalize = RECIPROCAL(planner.e_factor[active_extruder]), base_retract = swapping ? swap_retract_length : retract_length, old_z = current_position[Z_AXIS], - old_e = current_position[E_AXIS]; + old_e = current_position[E_CART]; // The current position will be the destination for E and Z moves set_destination_from_current(); @@ -139,7 +139,7 @@ void FWRetract::retract(const bool retracting if (retracting) { // Retract by moving from a faux E position back to the current E position feedrate_mm_s = retract_feedrate_mm_s; - destination[E_AXIS] -= base_retract * renormalize; + destination[E_CART] -= base_retract * renormalize; prepare_move_to_destination(); // set_current_to_destination // Is a Z hop set, and has the hop not yet been done? @@ -160,14 +160,14 @@ void FWRetract::retract(const bool retracting hop_amount = 0.0; // Clear the hop amount } - destination[E_AXIS] += (base_retract + (swapping ? swap_retract_recover_length : retract_recover_length)) * renormalize; + destination[E_CART] += (base_retract + (swapping ? swap_retract_recover_length : retract_recover_length)) * renormalize; feedrate_mm_s = swapping ? swap_retract_recover_feedrate_mm_s : retract_recover_feedrate_mm_s; prepare_move_to_destination(); // Recover E, set_current_to_destination } feedrate_mm_s = old_feedrate_mm_s; // Restore original feedrate current_position[Z_AXIS] = old_z; // Restore Z and E positions - current_position[E_AXIS] = old_e; + current_position[E_CART] = old_e; SYNC_PLAN_POSITION_KINEMATIC(); // As if the move never took place retracted[active_extruder] = retracting; // Active extruder now retracted / recovered @@ -190,7 +190,7 @@ void FWRetract::retract(const bool retracting #endif } SERIAL_ECHOLNPAIR("current_position[z] ", current_position[Z_AXIS]); - SERIAL_ECHOLNPAIR("current_position[e] ", current_position[E_AXIS]); + SERIAL_ECHOLNPAIR("current_position[e] ", current_position[E_CART]); SERIAL_ECHOLNPAIR("hop_amount ", hop_amount); //*/ diff --git a/Marlin/language.h b/Marlin/language.h index f16c7242ae..d0eea744ad 100644 --- a/Marlin/language.h +++ b/Marlin/language.h @@ -149,23 +149,23 @@ #define MSG_RESEND "Resend: " #define MSG_UNKNOWN_COMMAND "Unknown command: \"" #define MSG_ACTIVE_EXTRUDER "Active Extruder: " -#define MSG_X_MIN "x_min: " -#define MSG_X_MAX "x_max: " -#define MSG_X2_MIN "x2_min: " -#define MSG_X2_MAX "x2_max: " -#define MSG_Y_MIN "y_min: " -#define MSG_Y_MAX "y_max: " -#define MSG_Y2_MIN "y2_min: " -#define MSG_Y2_MAX "y2_max: " -#define MSG_Z_MIN "z_min: " -#define MSG_Z_MAX "z_max: " -#define MSG_Z2_MIN "z2_min: " -#define MSG_Z2_MAX "z2_max: " -#define MSG_Z_PROBE "z_probe: " +#define MSG_X_MIN "x_min" +#define MSG_X_MAX "x_max" +#define MSG_X2_MIN "x2_min" +#define MSG_X2_MAX "x2_max" +#define MSG_Y_MIN "y_min" +#define MSG_Y_MAX "y_max" +#define MSG_Y2_MIN "y2_min" +#define MSG_Y2_MAX "y2_max" +#define MSG_Z_MIN "z_min" +#define MSG_Z_MAX "z_max" +#define MSG_Z2_MIN "z2_min" +#define MSG_Z2_MAX "z2_max" +#define MSG_Z_PROBE "z_probe" +#define MSG_FILAMENT_RUNOUT_SENSOR "filament" #define MSG_PROBE_Z_OFFSET "Probe Z Offset" #define MSG_SKEW_MIN "min_skew_factor: " #define MSG_SKEW_MAX "max_skew_factor: " -#define MSG_FILAMENT_RUNOUT_SENSOR "filament: " #define MSG_ERR_MATERIAL_INDEX "M145 S out of range (0-1)" #define MSG_ERR_M355_NONE "No case light" #define MSG_ERR_M421_PARAMETERS "M421 incorrect parameter usage" diff --git a/Marlin/language_an.h b/Marlin/language_an.h index fe766d1211..679ed1cf3f 100644 --- a/Marlin/language_an.h +++ b/Marlin/language_an.h @@ -44,6 +44,7 @@ #define MSG_AUTO_HOME_X _UxGT("Orichen X") #define MSG_AUTO_HOME_Y _UxGT("Orichen Y") #define MSG_AUTO_HOME_Z _UxGT("Orichen Z") +#define MSG_TMC_Z_CALIBRATION _UxGT("Calibrar Z") #define MSG_LEVEL_BED_HOMING _UxGT("Orichen XYZ") #define MSG_LEVEL_BED_WAITING _UxGT("Encetar (pretar)") #define MSG_LEVEL_BED_NEXT_POINT _UxGT("Vinient punto") diff --git a/Marlin/language_bg.h b/Marlin/language_bg.h index 8edeed405f..5920bac25f 100644 --- a/Marlin/language_bg.h +++ b/Marlin/language_bg.h @@ -41,6 +41,7 @@ #define MSG_AUTOSTART _UxGT("Автостарт") #define MSG_DISABLE_STEPPERS _UxGT("Изкл. двигатели") #define MSG_AUTO_HOME _UxGT("Паркиране") +#define MSG_TMC_Z_CALIBRATION _UxGT("Калибровка Z") #define MSG_SET_HOME_OFFSETS _UxGT("Задай Начало") #define MSG_SET_ORIGIN _UxGT("Изходна точка") #define MSG_PREHEAT_1 _UxGT("Подгряване PLA") diff --git a/Marlin/language_ca.h b/Marlin/language_ca.h index 7aa5f00298..8c8af7c308 100644 --- a/Marlin/language_ca.h +++ b/Marlin/language_ca.h @@ -47,6 +47,7 @@ #define MSG_AUTO_HOME_X _UxGT("X a origen") #define MSG_AUTO_HOME_Y _UxGT("Y a origen") #define MSG_AUTO_HOME_Z _UxGT("Z a origen") +#define MSG_TMC_Z_CALIBRATION _UxGT("Calibra Z") #define MSG_LEVEL_BED_HOMING _UxGT("Origen XYZ") #define MSG_LEVEL_BED_WAITING _UxGT("Premeu per iniciar") #define MSG_LEVEL_BED_NEXT_POINT _UxGT("Següent punt") diff --git a/Marlin/language_cn.h b/Marlin/language_cn.h index 96c6f666d5..f02a23acab 100644 --- a/Marlin/language_cn.h +++ b/Marlin/language_cn.h @@ -40,6 +40,7 @@ #define MSG_AUTOSTART "\xb1\xb2\xb3\xb4" #define MSG_DISABLE_STEPPERS "\xb5\xb6\xb7\xb8\xb9\xba" #define MSG_AUTO_HOME "\xbb\xbc\xbd" +#define MSG_TMC_Z_CALIBRATION "Calibrate Z" #define MSG_LEVEL_BED_HOMING "Homing XYZ" #define MSG_LEVEL_BED_WAITING "Click to Begin" #define MSG_LEVEL_BED_DONE "Leveling Done!" diff --git a/Marlin/language_cz.h b/Marlin/language_cz.h index 3002390b38..950b58a172 100644 --- a/Marlin/language_cz.h +++ b/Marlin/language_cz.h @@ -50,6 +50,7 @@ #define MSG_AUTO_HOME_X _UxGT("Domu osa X") #define MSG_AUTO_HOME_Y _UxGT("Domu osa Y") #define MSG_AUTO_HOME_Z _UxGT("Domu osa Z") +#define MSG_TMC_Z_CALIBRATION _UxGT("Kalibrovat Z") #define MSG_LEVEL_BED_HOMING _UxGT("Mereni podlozky") #define MSG_LEVEL_BED_WAITING _UxGT("Kliknutim spustte") #define MSG_LEVEL_BED_NEXT_POINT _UxGT("Dalsi bod") diff --git a/Marlin/language_cz_utf8.h b/Marlin/language_cz_utf8.h index f962d41a80..e76c947e48 100644 --- a/Marlin/language_cz_utf8.h +++ b/Marlin/language_cz_utf8.h @@ -44,6 +44,7 @@ #define MSG_SD_INSERTED _UxGT("Karta vložena") #define MSG_SD_REMOVED _UxGT("Karta vyjmuta") #define MSG_LCD_ENDSTOPS _UxGT("Endstopy") // max 8 znaku +#define MSG_LCD_SOFT_ENDSTOPS _UxGT("Soft Endstopy") #define MSG_MAIN _UxGT("Hlavní nabídka") #define MSG_AUTOSTART _UxGT("Autostart") #define MSG_DISABLE_STEPPERS _UxGT("Uvolnit motory") @@ -53,6 +54,7 @@ #define MSG_AUTO_HOME_X _UxGT("Domů osa X") #define MSG_AUTO_HOME_Y _UxGT("Domů osa Y") #define MSG_AUTO_HOME_Z _UxGT("Domů osa Z") +#define MSG_TMC_Z_CALIBRATION _UxGT("Kalibrovat Z") #define MSG_LEVEL_BED_HOMING _UxGT("Měření podložky") #define MSG_LEVEL_BED_WAITING _UxGT("Kliknutím spusťte") #define MSG_LEVEL_BED_NEXT_POINT _UxGT("Další bod") @@ -252,11 +254,13 @@ #define MSG_PAUSE_PRINT _UxGT("Pozastavit tisk") #define MSG_RESUME_PRINT _UxGT("Obnovit tisk") #define MSG_STOP_PRINT _UxGT("Zastavit tisk") +#define MSG_POWER_LOSS_RECOVERY _UxGT("Obnova vypadku") #define MSG_CARD_MENU _UxGT("Tisknout z SD") #define MSG_NO_CARD _UxGT("Žádná SD karta") #define MSG_DWELL _UxGT("Uspáno...") #define MSG_USERWAIT _UxGT("Čekání na uživ...") #define MSG_PRINT_PAUSED _UxGT("Tisk pozastaven") +#define MSG_PRINTING _UxGT("Tisknu...") #define MSG_PRINT_ABORTED _UxGT("Tisk zrušen") #define MSG_NO_MOVE _UxGT("Žádný pohyb.") #define MSG_KILLED _UxGT("PŘERUSENO. ") @@ -292,8 +296,10 @@ #define MSG_BABYSTEP_Z _UxGT("Babystep Z") #define MSG_ENDSTOP_ABORT _UxGT("Endstop abort") #define MSG_HEATING_FAILED_LCD _UxGT("Chyba zahřívání") +#define MSG_HEATING_FAILED_LCD_BED _UxGT("Chyba zahř. podl.") #define MSG_ERR_REDUNDANT_TEMP _UxGT("REDUND. TEPLOTA") #define MSG_THERMAL_RUNAWAY _UxGT("TEPLOTNÍ SKOK") +#define MSG_THERMAL_RUNAWAY_BED _UxGT("PODL. TEPL. SKOK") #define MSG_ERR_MAXTEMP _UxGT("VYSOKÁ TEPLOTA") #define MSG_ERR_MINTEMP _UxGT("NÍZKA TEPLOTA") #define MSG_ERR_MAXTEMP_BED _UxGT("VYS. TEPL. PODL.") @@ -305,7 +311,9 @@ #define MSG_SHORT_HOUR _UxGT("h") #define MSG_SHORT_MINUTE _UxGT("m") #define MSG_HEATING _UxGT("Zahřívání...") +#define MSG_COOLING _UxGT("Chlazení") #define MSG_BED_HEATING _UxGT("Zahřívání podl...") +#define MSG_BED_COOLING _UxGT("Chlazení podl...") #define MSG_DELTA_CALIBRATE _UxGT("Delta Kalibrace") #define MSG_DELTA_CALIBRATE_X _UxGT("Kalibrovat X") #define MSG_DELTA_CALIBRATE_Y _UxGT("Kalibrovat Y") @@ -314,6 +322,7 @@ #define MSG_DELTA_SETTINGS _UxGT("Delta nastavení") #define MSG_DELTA_AUTO_CALIBRATE _UxGT("Autokalibrace") #define MSG_DELTA_HEIGHT_CALIBRATE _UxGT("Nast.výšku delty") +#define MSG_DELTA_Z_OFFSET_CALIBRATE _UxGT("Nast. Z-ofset") #define MSG_DELTA_DIAG_ROD _UxGT("Diag rameno") #define MSG_DELTA_HEIGHT _UxGT("Výška") #define MSG_DELTA_RADIUS _UxGT("Poloměr") diff --git a/Marlin/language_da.h b/Marlin/language_da.h index 1bd2b02df6..e51f8d014a 100644 --- a/Marlin/language_da.h +++ b/Marlin/language_da.h @@ -45,6 +45,7 @@ #define MSG_AUTO_HOME_X _UxGT("Home X") #define MSG_AUTO_HOME_Y _UxGT("Home Y") #define MSG_AUTO_HOME_Z _UxGT("Home Z") +#define MSG_TMC_Z_CALIBRATION _UxGT("Kalibrer Z") #define MSG_LEVEL_BED_HOMING _UxGT("Homing XYZ") #define MSG_LEVEL_BED_WAITING _UxGT("Klik når du er klar") #define MSG_LEVEL_BED_NEXT_POINT _UxGT("Næste punkt") diff --git a/Marlin/language_de.h b/Marlin/language_de.h index c662ec25a2..2a28c9145d 100644 --- a/Marlin/language_de.h +++ b/Marlin/language_de.h @@ -50,6 +50,7 @@ #define MSG_AUTO_HOME_X _UxGT("Home X") #define MSG_AUTO_HOME_Y _UxGT("Home Y") #define MSG_AUTO_HOME_Z _UxGT("Home Z") +#define MSG_TMC_Z_CALIBRATION _UxGT("Kalibriere Z") #define MSG_LEVEL_BED_HOMING _UxGT("Home XYZ") #define MSG_LEVEL_BED_WAITING _UxGT("Klick für Start") #define MSG_LEVEL_BED_NEXT_POINT _UxGT("Nächste Koordinate") diff --git a/Marlin/language_el-gr.h b/Marlin/language_el-gr.h index 89ac76eb03..775242bb8f 100644 --- a/Marlin/language_el-gr.h +++ b/Marlin/language_el-gr.h @@ -45,6 +45,7 @@ #define MSG_AUTO_HOME_X _UxGT("Αρχικό σημείο X") #define MSG_AUTO_HOME_Y _UxGT("Αρχικό σημείο Y") #define MSG_AUTO_HOME_Z _UxGT("Αρχικό σημείο Z") +#define MSG_TMC_Z_CALIBRATION _UxGT("Βαθμονόμηση Z") #define MSG_LEVEL_BED_HOMING _UxGT("Επαναφορά στο αρχικό σημείο ΧΥΖ") #define MSG_LEVEL_BED_WAITING _UxGT("Κάντε κλικ για να ξεκινήσετε") #define MSG_LEVEL_BED_NEXT_POINT _UxGT("Επόμενο σημείο") diff --git a/Marlin/language_el.h b/Marlin/language_el.h index 8cfda5a171..b4fe4d37f0 100644 --- a/Marlin/language_el.h +++ b/Marlin/language_el.h @@ -45,6 +45,7 @@ #define MSG_AUTO_HOME_X _UxGT("Αρχικό σημείο X") #define MSG_AUTO_HOME_Y _UxGT("Αρχικό σημείο Y") #define MSG_AUTO_HOME_Z _UxGT("Αρχικό σημείο Z") +#define MSG_TMC_Z_CALIBRATION _UxGT("Βαθμονόμηση Z") #define MSG_LEVEL_BED_HOMING _UxGT("Επαναφορά Επ. Εκτύπωσης") //SHORTEN #define MSG_LEVEL_BED_WAITING _UxGT("Επιπεδοποίηση επ. Εκτύπωσης περιμενει") //SHORTEN #define MSG_LEVEL_BED_NEXT_POINT _UxGT("Επόμενο σημείο") diff --git a/Marlin/language_en.h b/Marlin/language_en.h index 1f5ad92508..c23f4634ae 100644 --- a/Marlin/language_en.h +++ b/Marlin/language_en.h @@ -85,6 +85,9 @@ #ifndef MSG_AUTO_HOME_Z #define MSG_AUTO_HOME_Z _UxGT("Home Z") #endif +#ifndef MSG_TMC_Z_CALIBRATION + #define MSG_TMC_Z_CALIBRATION _UxGT("Calibrate Z") +#endif #ifndef MSG_LEVEL_BED_HOMING #define MSG_LEVEL_BED_HOMING _UxGT("Homing XYZ") #endif @@ -1055,6 +1058,9 @@ #ifndef MSG_FILAMENT_CHANGE_INSERT_1 #define MSG_FILAMENT_CHANGE_INSERT_1 _UxGT("Insert and Click") #endif + #ifndef MSG_FILAMENT_CHANGE_HEAT_1 + #define MSG_FILAMENT_CHANGE_HEAT_1 _UxGT("Click to heat") + #endif #ifndef MSG_FILAMENT_CHANGE_HEATING_1 #define MSG_FILAMENT_CHANGE_HEATING_1 _UxGT("Heating...") #endif diff --git a/Marlin/language_es.h b/Marlin/language_es.h index cbff5ee08e..a4267af2b3 100644 --- a/Marlin/language_es.h +++ b/Marlin/language_es.h @@ -48,6 +48,7 @@ #define MSG_AUTO_HOME_X _UxGT("Origen X") #define MSG_AUTO_HOME_Y _UxGT("Origen Y") #define MSG_AUTO_HOME_Z _UxGT("Origen Z") +#define MSG_TMC_Z_CALIBRATION _UxGT("Calibrar Z") #define MSG_LEVEL_BED_HOMING _UxGT("Origen XYZ") #define MSG_LEVEL_BED_WAITING _UxGT("Iniciar (Presione)") #define MSG_LEVEL_BED_NEXT_POINT _UxGT("Siguiente punto") diff --git a/Marlin/language_es_utf8.h b/Marlin/language_es_utf8.h index 57ac43b82f..a0c87452d9 100644 --- a/Marlin/language_es_utf8.h +++ b/Marlin/language_es_utf8.h @@ -48,6 +48,7 @@ #define MSG_AUTO_HOME_X _UxGT("Origen X") #define MSG_AUTO_HOME_Y _UxGT("Origen Y") #define MSG_AUTO_HOME_Z _UxGT("Origen Z") +#define MSG_TMC_Z_CALIBRATION _UxGT("Calibrar Z") #define MSG_LEVEL_BED_HOMING _UxGT("Origen XYZ") #define MSG_LEVEL_BED_WAITING _UxGT("Iniciar (Presione)") #define MSG_LEVEL_BED_NEXT_POINT _UxGT("Siguiente punto") diff --git a/Marlin/language_eu.h b/Marlin/language_eu.h index c28eaa6f94..999855ef37 100644 --- a/Marlin/language_eu.h +++ b/Marlin/language_eu.h @@ -47,6 +47,7 @@ #define MSG_AUTO_HOME_X _UxGT("X jatorrira") #define MSG_AUTO_HOME_Y _UxGT("Y jatorrira") #define MSG_AUTO_HOME_Z _UxGT("Z jatorrira") +#define MSG_TMC_Z_CALIBRATION _UxGT("Kalibratu Z") #define MSG_LEVEL_BED_HOMING _UxGT("XYZ hasieraratzen") #define MSG_LEVEL_BED_WAITING _UxGT("Klik egin hasteko") #define MSG_LEVEL_BED_NEXT_POINT _UxGT("Hurrengo Puntua") diff --git a/Marlin/language_fi.h b/Marlin/language_fi.h index 70ef4cf90a..4e26bdb2b3 100644 --- a/Marlin/language_fi.h +++ b/Marlin/language_fi.h @@ -41,6 +41,7 @@ #define MSG_AUTOSTART _UxGT("Automaatti") #define MSG_DISABLE_STEPPERS _UxGT("Vapauta moottorit") #define MSG_AUTO_HOME _UxGT("Aja referenssiin") +#define MSG_TMC_Z_CALIBRATION _UxGT("Kalibroi Z") #define MSG_LEVEL_BED_HOMING _UxGT("Homing XYZ") #define MSG_LEVEL_BED_WAITING _UxGT("Click to Begin") #define MSG_LEVEL_BED_DONE _UxGT("Leveling Done!") diff --git a/Marlin/language_fr.h b/Marlin/language_fr.h index 20d542433a..fe3e6c8c71 100644 --- a/Marlin/language_fr.h +++ b/Marlin/language_fr.h @@ -47,6 +47,7 @@ #define MSG_AUTO_HOME_X _UxGT("Origine X Auto.") #define MSG_AUTO_HOME_Y _UxGT("Origine Y Auto.") #define MSG_AUTO_HOME_Z _UxGT("Origine Z Auto.") +#define MSG_TMC_Z_CALIBRATION _UxGT("Calibrer Z") #define MSG_LEVEL_BED_HOMING _UxGT("Origine XYZ") #define MSG_LEVEL_BED_WAITING _UxGT("Clic pour commencer") #define MSG_LEVEL_BED_NEXT_POINT _UxGT("Point suivant") @@ -58,13 +59,13 @@ #define MSG_PREHEAT_1 _UxGT("Prechauffage PLA") #define MSG_PREHEAT_1_N _UxGT("Prechauff. PLA ") #define MSG_PREHEAT_1_ALL _UxGT("Prech. PLA Tout") -#define MSG_PREHEAT_1_END MSG_PREHEAT_1 _UxGT(" fini") +#define MSG_PREHEAT_1_END MSG_PREHEAT_1 _UxGT(" buse") #define MSG_PREHEAT_1_BEDONLY _UxGT("Prech. PLA lit") #define MSG_PREHEAT_1_SETTINGS _UxGT("Regl. prech. PLA") #define MSG_PREHEAT_2 _UxGT("Prechauffage ABS") #define MSG_PREHEAT_2_N _UxGT("Prechauff. ABS ") #define MSG_PREHEAT_2_ALL _UxGT("Prech. ABS Tout") -#define MSG_PREHEAT_2_END MSG_PREHEAT_2 _UxGT(" fini") +#define MSG_PREHEAT_2_END MSG_PREHEAT_2 _UxGT(" buse") #define MSG_PREHEAT_2_BEDONLY _UxGT("Prech. ABS lit") #define MSG_PREHEAT_2_SETTINGS _UxGT("Regl. prech. ABS") #define MSG_COOLDOWN _UxGT("Refroidir") diff --git a/Marlin/language_fr_utf8.h b/Marlin/language_fr_utf8.h index 8365242255..12e841ba8c 100644 --- a/Marlin/language_fr_utf8.h +++ b/Marlin/language_fr_utf8.h @@ -40,7 +40,7 @@ #define MSG_SD_REMOVED _UxGT("Carte retirée") #define MSG_LCD_ENDSTOPS _UxGT("Butées") // Max length 8 characters #define MSG_MAIN _UxGT("Menu principal") -#define MSG_AUTOSTART _UxGT("Demarrage auto") +#define MSG_AUTOSTART _UxGT("Démarrage auto") #define MSG_DISABLE_STEPPERS _UxGT("Arrêter moteurs") #define MSG_DEBUG_MENU _UxGT("Menu debug") #define MSG_PROGRESS_BAR_TEST _UxGT("Test barre progress.") @@ -48,6 +48,7 @@ #define MSG_AUTO_HOME_X _UxGT("Origine X Auto.") #define MSG_AUTO_HOME_Y _UxGT("Origine Y Auto.") #define MSG_AUTO_HOME_Z _UxGT("Origine Z Auto.") +#define MSG_TMC_Z_CALIBRATION _UxGT("Calibrer Z") #define MSG_LEVEL_BED_HOMING _UxGT("Origine XYZ") #define MSG_LEVEL_BED_WAITING _UxGT("Clic pour commencer") #define MSG_LEVEL_BED_NEXT_POINT _UxGT("Point suivant") @@ -59,18 +60,18 @@ #define MSG_PREHEAT_1 _UxGT("Préchauffage PLA") #define MSG_PREHEAT_1_N _UxGT("Préchauff. PLA ") #define MSG_PREHEAT_1_ALL _UxGT("Préch. PLA Tout") -#define MSG_PREHEAT_1_END MSG_PREHEAT_1 _UxGT(" fini") +#define MSG_PREHEAT_1_END MSG_PREHEAT_1 _UxGT(" buse") #define MSG_PREHEAT_1_BEDONLY _UxGT("Préch. PLA lit") #define MSG_PREHEAT_1_SETTINGS _UxGT("Régl. prech. PLA") #define MSG_PREHEAT_2 _UxGT("Préchauffage ABS") #define MSG_PREHEAT_2_N _UxGT("Préchauff. ABS ") #define MSG_PREHEAT_2_ALL _UxGT("Préch. ABS Tout") -#define MSG_PREHEAT_2_END MSG_PREHEAT_2 _UxGT(" fini") +#define MSG_PREHEAT_2_END MSG_PREHEAT_2 _UxGT(" buse") #define MSG_PREHEAT_2_BEDONLY _UxGT("Préch. ABS lit") #define MSG_PREHEAT_2_SETTINGS _UxGT("Régl. prech. ABS") #define MSG_COOLDOWN _UxGT("Refroidir") #define MSG_SWITCH_PS_ON _UxGT("Allumer alim.") -#define MSG_SWITCH_PS_OFF _UxGT("Eteindre alim.") +#define MSG_SWITCH_PS_OFF _UxGT("Éteindre alim.") #define MSG_EXTRUDE _UxGT("Extrusion") #define MSG_RETRACT _UxGT("Retrait") #define MSG_MOVE_AXIS _UxGT("Déplacer un axe") @@ -86,9 +87,9 @@ #define MSG_UBL_TOOLS _UxGT("Outils UBL") #define MSG_UBL_LEVEL_BED _UxGT("Niveau lit unifié") #define MSG_UBL_MANUAL_MESH _UxGT("Maillage manuel") -#define MSG_UBL_BC_INSERT _UxGT("Poser câle & mesurer") +#define MSG_UBL_BC_INSERT _UxGT("Poser cale & mesurer") #define MSG_UBL_BC_INSERT2 _UxGT("Mesure") -#define MSG_UBL_BC_REMOVE _UxGT("ôter et mesurer lit") +#define MSG_UBL_BC_REMOVE _UxGT("Ôter et mesurer lit") #define MSG_UBL_MOVING_TO_NEXT _UxGT("Aller au suivant") #define MSG_UBL_ACTIVATE_MESH _UxGT("Activer l'UBL") #define MSG_UBL_DEACTIVATE_MESH _UxGT("Désactiver l'UBL") @@ -96,8 +97,8 @@ #define MSG_UBL_CUSTOM_BED_TEMP MSG_UBL_SET_BED_TEMP #define MSG_UBL_SET_HOTEND_TEMP _UxGT("Température buse") #define MSG_UBL_CUSTOM_HOTEND_TEMP MSG_UBL_SET_HOTEND_TEMP -#define MSG_UBL_MESH_EDIT _UxGT("Editer maille") -#define MSG_UBL_EDIT_CUSTOM_MESH _UxGT("Editer maille perso") +#define MSG_UBL_MESH_EDIT _UxGT("Éditer maille") +#define MSG_UBL_EDIT_CUSTOM_MESH _UxGT("Éditer maille perso") #define MSG_UBL_FINE_TUNE_MESH _UxGT("Réglage fin maille") #define MSG_UBL_DONE_EDITING_MESH _UxGT("Terminer maille") #define MSG_UBL_BUILD_CUSTOM_MESH _UxGT("Créer maille perso") @@ -155,7 +156,7 @@ #define MSG_SET_LEDS_INDIGO _UxGT("Indigo") #define MSG_SET_LEDS_VIOLET _UxGT("Violet") #define MSG_SET_LEDS_WHITE _UxGT("Blanc") -#define MSG_SET_LEDS_DEFAULT _UxGT("Defaut") +#define MSG_SET_LEDS_DEFAULT _UxGT("Défaut") #define MSG_CUSTOM_LEDS _UxGT("Lum. perso.") #define MSG_INTENSITY_R _UxGT("Intensité rouge") #define MSG_INTENSITY_G _UxGT("Intensité vert") diff --git a/Marlin/language_gl.h b/Marlin/language_gl.h index b97a414417..e0524d8df9 100644 --- a/Marlin/language_gl.h +++ b/Marlin/language_gl.h @@ -45,6 +45,7 @@ #define MSG_AUTO_HOME_X _UxGT("Ir orixe X") #define MSG_AUTO_HOME_Y _UxGT("Ir orixe Y") #define MSG_AUTO_HOME_Z _UxGT("Ir orixe Z") +#define MSG_TMC_Z_CALIBRATION _UxGT("Calibrar Z") #define MSG_LEVEL_BED_HOMING _UxGT("Ir orixes XYZ") #define MSG_LEVEL_BED_WAITING _UxGT("Prema pulsador") #define MSG_LEVEL_BED_NEXT_POINT _UxGT("Seguinte punto") @@ -252,4 +253,3 @@ #endif // LCD_HEIGHT < 4 #endif // LANGUAGE_GL_H - diff --git a/Marlin/language_hr.h b/Marlin/language_hr.h index 3b8fdd7433..efdeae8b5b 100644 --- a/Marlin/language_hr.h +++ b/Marlin/language_hr.h @@ -44,6 +44,7 @@ #define MSG_AUTO_HOME_X _UxGT("Home-aj X") #define MSG_AUTO_HOME_Y _UxGT("Home-aj Y") #define MSG_AUTO_HOME_Z _UxGT("Home-aj Z") +#define MSG_TMC_Z_CALIBRATION _UxGT("Kalibriraj Z") #define MSG_LEVEL_BED_HOMING _UxGT("Home-aj XYZ") #define MSG_LEVEL_BED_WAITING _UxGT("Klikni za početak") #define MSG_LEVEL_BED_NEXT_POINT _UxGT("Sljedeća točka") diff --git a/Marlin/language_it.h b/Marlin/language_it.h index e3b83312bb..306faa3313 100644 --- a/Marlin/language_it.h +++ b/Marlin/language_it.h @@ -47,6 +47,7 @@ #define MSG_AUTO_HOME_X _UxGT("Home asse X") #define MSG_AUTO_HOME_Y _UxGT("Home asse Y") #define MSG_AUTO_HOME_Z _UxGT("Home asse Z") +#define MSG_TMC_Z_CALIBRATION _UxGT("Calibra Z") #define MSG_LEVEL_BED_HOMING _UxGT("Home assi XYZ") #define MSG_LEVEL_BED_WAITING _UxGT("Premi per iniziare") #define MSG_LEVEL_BED_NEXT_POINT _UxGT("Punto successivo") diff --git a/Marlin/language_kana.h b/Marlin/language_kana.h index 4989ebf1bc..e75be4c210 100644 --- a/Marlin/language_kana.h +++ b/Marlin/language_kana.h @@ -50,6 +50,7 @@ #define MSG_AUTO_HOME_X "X\xbc\xde\xb8\x20\xb9\xde\xdd\xc3\xdd\xcc\xaf\xb7" // "Xジク ゲンテンフッキ" ("Home X") #define MSG_AUTO_HOME_Y "Y\xbc\xde\xb8\x20\xb9\xde\xdd\xc3\xdd\xcc\xaf\xb7" // "Yジク ゲンテンフッキ" ("Home Y") #define MSG_AUTO_HOME_Z "Z\xbc\xde\xb8\x20\xb9\xde\xdd\xc3\xdd\xcc\xaf\xb7" // "Zジク ゲンテンフッキ" ("Home Z") +#define MSG_TMC_Z_CALIBRATION "Z\xbc\xde\xb8\x20\xba\xb3\xbe\xb2" // "Zジク コウセイ" ("Calibrate Z") #define MSG_LEVEL_BED_HOMING "\xb9\xde\xdd\xc3\xdd\xcc\xaf\xb7\xc1\xad\xb3" // "ゲンテンフッキチュウ" ("Homing XYZ") #define MSG_LEVEL_BED_WAITING "\xda\xcd\xde\xd8\xdd\xb8\xde\xb6\xb2\xbc" // "レベリングカイシ" ("Click to Begin") #define MSG_LEVEL_BED_NEXT_POINT "\xc2\xb7\xde\xc9\xbf\xb8\xc3\xb2\xc3\xdd\xcd" // "ツギノソクテイテンヘ" ("Next Point") diff --git a/Marlin/language_kana_utf8.h b/Marlin/language_kana_utf8.h index f33432532f..050f3277a7 100644 --- a/Marlin/language_kana_utf8.h +++ b/Marlin/language_kana_utf8.h @@ -53,6 +53,7 @@ #define MSG_AUTO_HOME_X _UxGT("Xジク ゲンテンフッキ") // "Home X" #define MSG_AUTO_HOME_Y _UxGT("Yジク ゲンテンフッキ") // "Home Y" #define MSG_AUTO_HOME_Z _UxGT("Zジク ゲンテンフッキ") // "Home Z" +#define MSG_TMC_Z_CALIBRATION _UxGT("Zジク コウセイ") // "Calibrate Z" #define MSG_LEVEL_BED_HOMING _UxGT("ゲンテンフッキチュウ") // "Homing XYZ" #define MSG_LEVEL_BED_WAITING _UxGT("レベリングカイシ") // "Click to Begin" #define MSG_LEVEL_BED_NEXT_POINT _UxGT("ツギノソクテイテンヘ") // "Next Point" diff --git a/Marlin/language_nl.h b/Marlin/language_nl.h index 0a2726294d..128bceaf41 100644 --- a/Marlin/language_nl.h +++ b/Marlin/language_nl.h @@ -47,6 +47,7 @@ #define MSG_AUTO_HOME_X _UxGT("Home X") #define MSG_AUTO_HOME_Y _UxGT("Home Y") #define MSG_AUTO_HOME_Z _UxGT("Home Z") +#define MSG_TMC_Z_CALIBRATION _UxGT("Kalibreer Z") #define MSG_LEVEL_BED_HOMING _UxGT("Homing XYZ") #define MSG_LEVEL_BED_WAITING _UxGT("Klik voor begin") #define MSG_LEVEL_BED_NEXT_POINT _UxGT("Volgende Plaats") diff --git a/Marlin/language_pl-DOGM.h b/Marlin/language_pl-DOGM.h index 8210fe51f2..5839325726 100644 --- a/Marlin/language_pl-DOGM.h +++ b/Marlin/language_pl-DOGM.h @@ -39,6 +39,7 @@ #define MSG_AUTO_HOME_X _UxGT("Zeruj X") #define MSG_AUTO_HOME_Y _UxGT("Zeruj Y") #define MSG_AUTO_HOME_Z _UxGT("Zeruj Z") +#define MSG_TMC_Z_CALIBRATION _UxGT("Kalibruj Z") #define MSG_LEVEL_BED _UxGT("Poziom. stołu") #define MSG_LEVEL_BED_HOMING _UxGT("Pozycja zerowa") #define MSG_LEVEL_BED_WAITING _UxGT("Kliknij by rozp.") diff --git a/Marlin/language_pl-HD44780.h b/Marlin/language_pl-HD44780.h index 6968fc8a37..933b5b9e53 100644 --- a/Marlin/language_pl-HD44780.h +++ b/Marlin/language_pl-HD44780.h @@ -40,6 +40,7 @@ #define MSG_AUTO_HOME_X _UxGT("Zeruj X") #define MSG_AUTO_HOME_Y _UxGT("Zeruj Y") #define MSG_AUTO_HOME_Z _UxGT("Zeruj Z") +#define MSG_TMC_Z_CALIBRATION _UxGT("Kalibruj Z") #define MSG_LEVEL_BED _UxGT("Poziom. stolu") #define MSG_LEVEL_BED_HOMING _UxGT("Pozycja zerowa") #define MSG_LEVEL_BED_WAITING _UxGT("Kliknij by rozp.") diff --git a/Marlin/language_pt-br.h b/Marlin/language_pt-br.h index 4d9c64261c..303ea1aaa6 100644 --- a/Marlin/language_pt-br.h +++ b/Marlin/language_pt-br.h @@ -48,6 +48,7 @@ #define MSG_AUTO_HOME_Y _UxGT("Ir na origem Y") #define MSG_AUTO_HOME_Z _UxGT("Ir na origem Z") #define MSG_AUTO_HOME _UxGT("Ir na origem XYZ") +#define MSG_TMC_Z_CALIBRATION _UxGT("Calibrar Z") #define MSG_LEVEL_BED_HOMING _UxGT("Indo para origem") #define MSG_LEVEL_BED_WAITING _UxGT("Clique para Iniciar") #define MSG_LEVEL_BED_NEXT_POINT _UxGT("Proximo Ponto") diff --git a/Marlin/language_pt-br_utf8.h b/Marlin/language_pt-br_utf8.h index b297b7b4b0..880b396ff3 100644 --- a/Marlin/language_pt-br_utf8.h +++ b/Marlin/language_pt-br_utf8.h @@ -50,6 +50,7 @@ #define MSG_AUTO_HOME_Y _UxGT("Ir na origem Y") #define MSG_AUTO_HOME_Z _UxGT("Ir na origem Z") #define MSG_AUTO_HOME _UxGT("Ir na origem XYZ") +#define MSG_TMC_Z_CALIBRATION _UxGT("Calibrar Z") #define MSG_LEVEL_BED_HOMING _UxGT("Indo para origem") #define MSG_LEVEL_BED_WAITING _UxGT("Clique para Iniciar") #define MSG_LEVEL_BED_NEXT_POINT _UxGT("Próximo Ponto") diff --git a/Marlin/language_pt.h b/Marlin/language_pt.h index c314cc80da..949381142d 100644 --- a/Marlin/language_pt.h +++ b/Marlin/language_pt.h @@ -43,6 +43,7 @@ #define MSG_AUTO_HOME_X "Ir para origem X" #define MSG_AUTO_HOME_Y "Ir para origem Y" #define MSG_AUTO_HOME_Z "Ir para origem Z" +#define MSG_TMC_Z_CALIBRATION "Calibrar Z" #define MSG_LEVEL_BED_HOMING "Indo para origem" #define MSG_LEVEL_BED_WAITING "Click para iniciar" #define MSG_LEVEL_BED_NEXT_POINT "Proximo ponto" diff --git a/Marlin/language_pt_utf8.h b/Marlin/language_pt_utf8.h index df402884fa..0b0113c1d8 100644 --- a/Marlin/language_pt_utf8.h +++ b/Marlin/language_pt_utf8.h @@ -45,6 +45,7 @@ #define MSG_AUTO_HOME_X _UxGT("Ir para origem X") #define MSG_AUTO_HOME_Y _UxGT("Ir para origem Y") #define MSG_AUTO_HOME_Z _UxGT("Ir para origem Z") +#define MSG_TMC_Z_CALIBRATION _UxGT("Calibrar Z") #define MSG_LEVEL_BED_HOMING _UxGT("Indo para origem") #define MSG_LEVEL_BED_WAITING _UxGT("Click para iniciar") #define MSG_LEVEL_BED_NEXT_POINT _UxGT("Próximo ponto") diff --git a/Marlin/language_ru.h b/Marlin/language_ru.h index 0e54d6be0c..4a9fc53fe7 100644 --- a/Marlin/language_ru.h +++ b/Marlin/language_ru.h @@ -49,6 +49,7 @@ #define MSG_AUTO_HOME_X _UxGT("Парковка X") #define MSG_AUTO_HOME_Y _UxGT("Парковка Y") #define MSG_AUTO_HOME_Z _UxGT("Парковка Z") +#define MSG_TMC_Z_CALIBRATION _UxGT("Калибровать Z") #define MSG_LEVEL_BED_HOMING _UxGT("Нулевое положение") #define MSG_LEVEL_BED_WAITING _UxGT("Нажмите чтобы начать") #define MSG_LEVEL_BED_NEXT_POINT _UxGT("Следующая точка") diff --git a/Marlin/language_sk_utf8.h b/Marlin/language_sk_utf8.h index 3b43007e54..de3b2ba38b 100644 --- a/Marlin/language_sk_utf8.h +++ b/Marlin/language_sk_utf8.h @@ -53,6 +53,7 @@ #define MSG_AUTO_HOME_X _UxGT("Domov os X") #define MSG_AUTO_HOME_Y _UxGT("Domov os Y") #define MSG_AUTO_HOME_Z _UxGT("Domov os Z") +#define MSG_TMC_Z_CALIBRATION _UxGT("Kalibrovať Z") #define MSG_LEVEL_BED_HOMING _UxGT("Meranie podložky") #define MSG_LEVEL_BED_WAITING _UxGT("Kliknutím spusťte") #define MSG_LEVEL_BED_NEXT_POINT _UxGT("Ďalší bod") diff --git a/Marlin/language_tr.h b/Marlin/language_tr.h index 9df9f32396..6234d149ac 100644 --- a/Marlin/language_tr.h +++ b/Marlin/language_tr.h @@ -52,6 +52,7 @@ #define MSG_AUTO_HOME_X _UxGT("X Sıfırla") // X Sıfırla #define MSG_AUTO_HOME_Y _UxGT("Y Sıfırla") // Y Sıfırla #define MSG_AUTO_HOME_Z _UxGT("Z Sıfırla") // Z Sıfırla +#define MSG_TMC_Z_CALIBRATION _UxGT("Ayarla Z") // Ayarla Z #define MSG_LEVEL_BED_HOMING _UxGT("XYZ Sıfırlanıyor") // XYZ Sıfırlanıyor #define MSG_LEVEL_BED_WAITING _UxGT("Başlatmak için tıkla") // Başlatmak için tıkla #define MSG_LEVEL_BED_NEXT_POINT _UxGT("Sıradaki Nokta") // Sıradaki Nokta diff --git a/Marlin/language_uk.h b/Marlin/language_uk.h index 3e3227d867..ed71d1a6c5 100644 --- a/Marlin/language_uk.h +++ b/Marlin/language_uk.h @@ -45,6 +45,7 @@ #define MSG_AUTO_HOME_X _UxGT("Паркування X") #define MSG_AUTO_HOME_Y _UxGT("Паркування Y") #define MSG_AUTO_HOME_Z _UxGT("Паркування Z") +#define MSG_TMC_Z_CALIBRATION _UxGT("Калібрування Z") #define MSG_LEVEL_BED_HOMING _UxGT("Паркування XYZ") #define MSG_LEVEL_BED_WAITING _UxGT("Почати") #define MSG_LEVEL_BED_NEXT_POINT _UxGT("Слідуюча Точка") diff --git a/Marlin/language_zh_CN.h b/Marlin/language_zh_CN.h index 3a1a065d5e..214c3459f0 100644 --- a/Marlin/language_zh_CN.h +++ b/Marlin/language_zh_CN.h @@ -46,6 +46,7 @@ #define MSG_AUTO_HOME_X _UxGT("回X原位") //"Home X" #define MSG_AUTO_HOME_Y _UxGT("回Y原位") //"Home Y" #define MSG_AUTO_HOME_Z _UxGT("回Z原位") //"Home Z" +#define MSG_TMC_Z_CALIBRATION _UxGT("⊿校准Z") //"Calibrate Z" #define MSG_LEVEL_BED_HOMING _UxGT("平台调平XYZ归原位") //"Homing XYZ" #define MSG_LEVEL_BED_WAITING _UxGT("单击开始热床调平") //"Click to Begin" #define MSG_LEVEL_BED_NEXT_POINT _UxGT("下个热床调平点") //"Next Point" diff --git a/Marlin/language_zh_TW.h b/Marlin/language_zh_TW.h index 2a0399e358..b5a62a984e 100644 --- a/Marlin/language_zh_TW.h +++ b/Marlin/language_zh_TW.h @@ -46,6 +46,7 @@ #define MSG_AUTO_HOME_X _UxGT("回X原點") //"Home X" #define MSG_AUTO_HOME_Y _UxGT("回Y原點") //"Home Y" #define MSG_AUTO_HOME_Z _UxGT("回Z原點") //"Home Z" +#define MSG_TMC_Z_CALIBRATION _UxGT("⊿校準Z") //"Calibrate Z" #define MSG_LEVEL_BED_HOMING _UxGT("平台調平XYZ歸原點") //"Homing XYZ" #define MSG_LEVEL_BED_WAITING _UxGT("單擊開始熱床調平") //"Click to Begin" #define MSG_LEVEL_BED_NEXT_POINT _UxGT("下個熱床調平點") //"Next Point" diff --git a/Marlin/macros.h b/Marlin/macros.h index 45c4334ae2..a081744f79 100644 --- a/Marlin/macros.h +++ b/Marlin/macros.h @@ -23,13 +23,18 @@ #ifndef MACROS_H #define MACROS_H -#define NUM_AXIS 4 -#define ABCE 4 -#define XYZE 4 -#define ABC 3 -#define XYZ 3 +#define XYZ 3 +#define XYZE 4 +#define ABC 3 +#define ABCD 4 +#define ABCE 4 +#define ABCDE 5 -// For use in macros that take a single axis letter +/** + * For use in macros that take a single axis letter + * The axis order in all axis related arrays is X, Y, Z, E + * For Hangprinter it is A, B, C, D, E + */ #define _AXIS(A) (A##_AXIS) #define _XMIN_ 100 @@ -231,4 +236,4 @@ #define FMOD(x, y) fmodf(x, y) #define HYPOT(x,y) SQRT(HYPOT2(x,y)) -#endif //__MACROS_H +#endif // MACROS_H diff --git a/Marlin/malyanlcd.cpp b/Marlin/malyanlcd.cpp index e8d6c25143..74a5b611d8 100644 --- a/Marlin/malyanlcd.cpp +++ b/Marlin/malyanlcd.cpp @@ -83,6 +83,9 @@ // Track incoming command bytes from the LCD int inbound_count; +// For sending print completion messages +bool last_printing_status = false; + // Everything written needs the high bit set. void write_to_lcd_P(const char * const message) { char encoded_message[MAX_CURLY_COMMAND]; @@ -112,22 +115,23 @@ void write_to_lcd(const char * const message) { * {C:P050} * Set temp for bed to 50 * + * {C:S09} set feedrate to 90 %. + * {C:S12} set feedrate to 120 %. + * * the command portion begins after the : */ void process_lcd_c_command(const char* command) { switch (command[0]) { - case 'T': { - // M104 S - char cmd[20]; - sprintf_P(cmd, PSTR("M104 S%s"), command + 1); - enqueue_and_echo_command_now(cmd); + case 'C': { + int raw_feedrate = atoi(command + 1); + feedrate_percentage = raw_feedrate * 10; + feedrate_percentage = constrain(feedrate_percentage, 10, 999); + } break; + case 'T': { + thermalManager.setTargetHotend(atoi(command + 1), 0); } break; - case 'P': { - // M140 S - char cmd[20]; - sprintf_P(cmd, PSTR("M140 S%s"), command + 1); - enqueue_and_echo_command_now(cmd); + thermalManager.setTargetBed(atoi(command + 1)); } break; default: @@ -246,6 +250,7 @@ void process_lcd_p_command(const char* command) { #if ENABLED(SDSUPPORT) // cancel print write_to_lcd_P(PSTR("{SYS:CANCELING}")); + last_printing_status = false; card.stopSDPrint( #if SD_RESORT true @@ -286,7 +291,7 @@ void process_lcd_p_command(const char* command) { } else { char message_buffer[MAX_CURLY_COMMAND]; - sprintf_P(message_buffer, PSTR("{PRINTFILE:%s}"), card.filename); + sprintf_P(message_buffer, PSTR("{PRINTFILE:%s}"), card.longest_filename()); write_to_lcd(message_buffer); write_to_lcd_P(PSTR("{SYS:BUILD}")); card.openAndPrintFile(card.filename); @@ -327,7 +332,7 @@ void process_lcd_s_command(const char* command) { case 'H': // Home all axis - enqueue_and_echo_command("G28", false); + enqueue_and_echo_command("G28"); break; case 'L': { @@ -344,7 +349,7 @@ void process_lcd_s_command(const char* command) { uint16_t file_count = card.get_num_Files(); for (uint16_t i = 0; i < file_count; i++) { card.getfilename(i); - sprintf_P(message_buffer, card.filenameIsDir ? PSTR("{DIR:%s}") : PSTR("{FILE:%s}"), card.filename); + sprintf_P(message_buffer, card.filenameIsDir ? PSTR("{DIR:%s}") : PSTR("{FILE:%s}"), card.longest_filename()); write_to_lcd(message_buffer); } @@ -439,14 +444,21 @@ void _O2 lcd_update() { } #if ENABLED(SDSUPPORT) - // If there's a print in progress, we need to emit the status as - // {TQ:} - if (card.sdprinting) { - // We also need to send: T:-2538.0 E:0 - // I have no idea what this means. + // The way last printing status works is simple: + // The UI needs to see at least one TQ which is not 100% + // and then when the print is complete, one which is. + static uint8_t last_percent_done = 100; + + // If there was a print in progress, we need to emit the final + // print status as {TQ:100}. Reset last percent done so a new print will + // issue a percent of 0. + const uint8_t percent_done = card.sdprinting ? card.percentDone() : last_printing_status ? 100 : 0; + if (percent_done != last_percent_done) { char message_buffer[10]; - sprintf_P(message_buffer, PSTR("{TQ:%03i}"), card.percentDone()); + sprintf_P(message_buffer, PSTR("{TQ:%03i}"), percent_done); write_to_lcd(message_buffer); + last_percent_done = percent_done; + last_printing_status = card.sdprinting; } #endif } diff --git a/Marlin/nozzle.cpp b/Marlin/nozzle.cpp index 8bff692e44..3e2607c58d 100644 --- a/Marlin/nozzle.cpp +++ b/Marlin/nozzle.cpp @@ -161,9 +161,11 @@ #if ENABLED(NOZZLE_PARK_FEATURE) - void Nozzle::park(const uint8_t &z_action, const point_t &park /*= NOZZLE_PARK_POINT*/) { - const float fr_xy = NOZZLE_PARK_XY_FEEDRATE; - const float fr_z = NOZZLE_PARK_Z_FEEDRATE; + constexpr float npp[] = NOZZLE_PARK_POINT; + static_assert(COUNT(npp) == XYZ, "NOZZLE_PARK_POINT requires X, Y, and Z values."); + + void Nozzle::park(const uint8_t &z_action, const point_t &park/*=NOZZLE_PARK_POINT*/) { + const float fr_xy = NOZZLE_PARK_XY_FEEDRATE, fr_z = NOZZLE_PARK_Z_FEEDRATE; switch (z_action) { case 1: // Go to Z-park height diff --git a/Marlin/parser.h b/Marlin/parser.h index 949c489cd0..6a86ad373e 100644 --- a/Marlin/parser.h +++ b/Marlin/parser.h @@ -90,9 +90,15 @@ public: #endif #if ENABLED(DEBUG_GCODE_PARSER) - void debug(); + static void debug(); #endif + GCodeParser() { + #if ENABLED(INCH_MODE_SUPPORT) + set_input_linear_units(LINEARUNIT_MM); + #endif + } + // Reset is done before parsing static void reset(); diff --git a/Marlin/pca9632.cpp b/Marlin/pca9632.cpp index 2b4ee7f40b..4c339f4604 100644 --- a/Marlin/pca9632.cpp +++ b/Marlin/pca9632.cpp @@ -100,9 +100,9 @@ static void PCA9632_WriteAllRegisters(const byte addr, const byte regadd, const #endif void pca9632_set_led_color(const LEDColor &color) { + Wire.begin(); if (!PCA_init) { PCA_init = 1; - Wire.begin(); PCA9632_WriteRegister(PCA9632_ADDRESS,PCA9632_MODE1, PCA9632_MODE1_VALUE); PCA9632_WriteRegister(PCA9632_ADDRESS,PCA9632_MODE2, PCA9632_MODE2_VALUE); } diff --git a/Marlin/pins.h b/Marlin/pins.h index 20ba513a56..b32eeb75b9 100644 --- a/Marlin/pins.h +++ b/Marlin/pins.h @@ -696,6 +696,7 @@ // Dual X-carriage, Dual Y, Dual Z support // +#define _D_PINS #define _X2_PINS #define _Y2_PINS #define _Z2_PINS @@ -703,16 +704,64 @@ #define __EPIN(p,q) E##p##_##q##_PIN #define _EPIN(p,q) __EPIN(p,q) +// The HANGPRINTER A, B, C, D axes +#if ENABLED(HANGPRINTER) + #define A_ENABLE_PIN X_ENABLE_PIN + #define A_DIR_PIN X_DIR_PIN + #define A_STEP_PIN X_STEP_PIN + #define A_MS1_PIN X_MS1_PIN + + #define B_ENABLE_PIN Y_ENABLE_PIN + #define B_DIR_PIN Y_DIR_PIN + #define B_STEP_PIN Y_STEP_PIN + #define B_MS1_PIN Y_MS1_PIN + + #define C_ENABLE_PIN Z_ENABLE_PIN + #define C_DIR_PIN Z_DIR_PIN + #define C_STEP_PIN Z_STEP_PIN + #define C_MS1_PIN Z_MS1_PIN + + #ifndef D_STEP_PIN + #define D_STEP_PIN _EPIN(E_STEPPERS, STEP) + #define D_DIR_PIN _EPIN(E_STEPPERS, DIR) + #define D_ENABLE_PIN _EPIN(E_STEPPERS, ENABLE) + #ifndef D_CS_PIN + #define D_CS_PIN _EPIN(E_STEPPERS, CS) + #endif + #ifndef D_MS1_PIN + #define D_MS1_PIN _EPIN(E_STEPPERS, MS1) + #endif + #if E_STEPPERS >= MAX_EXTRUDERS || !PIN_EXISTS(D_ENABLE) + #error "No E stepper plug left for D Axis!" + #endif + #endif + #undef _D_PINS + #define ___D_PINS D_STEP_PIN, D_DIR_PIN, D_ENABLE_PIN, + #ifdef D_CS_PIN + #define __D_PINS ___D_PINS D_CS_PIN, + #else + #define __D_PINS ___D_PINS + #endif + #ifdef D_MS1_PIN + #define _D_PINS __D_PINS D_MS1_PIN, + #else + #define _D_PINS __D_PINS + #endif + #define X2_E_INDEX INCREMENT(E_STEPPERS) +#else + #define X2_E_INDEX E_STEPPERS +#endif + // The X2 axis, if any, should be the next open extruder port #if ENABLED(DUAL_X_CARRIAGE) || ENABLED(X_DUAL_STEPPER_DRIVERS) #ifndef X2_STEP_PIN - #define X2_STEP_PIN _EPIN(E_STEPPERS, STEP) - #define X2_DIR_PIN _EPIN(E_STEPPERS, DIR) - #define X2_ENABLE_PIN _EPIN(E_STEPPERS, ENABLE) + #define X2_STEP_PIN _EPIN(X2_E_INDEX, STEP) + #define X2_DIR_PIN _EPIN(X2_E_INDEX, DIR) + #define X2_ENABLE_PIN _EPIN(X2_E_INDEX, ENABLE) #ifndef X2_CS_PIN - #define X2_CS_PIN _EPIN(E_STEPPERS, CS) + #define X2_CS_PIN _EPIN(X2_E_INDEX, CS) #endif - #if E_STEPPERS > 4 || !PIN_EXISTS(X2_ENABLE) + #if X2_E_INDEX >= MAX_EXTRUDERS || !PIN_EXISTS(X2_ENABLE) #error "No E stepper plug left for X2!" #endif #endif @@ -723,9 +772,9 @@ #else #define _X2_PINS __X2_PINS #endif - #define Y2_E_INDEX INCREMENT(E_STEPPERS) + #define Y2_E_INDEX INCREMENT(X2_E_INDEX) #else - #define Y2_E_INDEX E_STEPPERS + #define Y2_E_INDEX X2_E_INDEX #endif // The Y2 axis, if any, should be the next open extruder port @@ -737,7 +786,7 @@ #ifndef Y2_CS_PIN #define Y2_CS_PIN _EPIN(Y2_E_INDEX, CS) #endif - #if Y2_E_INDEX > 4 || !PIN_EXISTS(Y2_ENABLE) + #if Y2_E_INDEX >= MAX_EXTRUDERS || !PIN_EXISTS(Y2_ENABLE) #error "No E stepper plug left for Y2!" #endif #endif @@ -762,7 +811,7 @@ #ifndef Z2_CS_PIN #define Z2_CS_PIN _EPIN(Z2_E_INDEX, CS) #endif - #if Z2_E_INDEX > 4 || !PIN_EXISTS(Z2_ENABLE) + #if Z2_E_INDEX >= MAX_EXTRUDERS || !PIN_EXISTS(Z2_ENABLE) #error "No E stepper plug left for Z2!" #endif #endif @@ -782,7 +831,7 @@ PS_ON_PIN, HEATER_BED_PIN, FAN_PIN, FAN1_PIN, FAN2_PIN, CONTROLLER_FAN_PIN, \ _E0_PINS _E1_PINS _E2_PINS _E3_PINS _E4_PINS BED_PINS \ _H0_PINS _H1_PINS _H2_PINS _H3_PINS _H4_PINS \ - _X2_PINS _Y2_PINS _Z2_PINS \ + _D_PINS _X2_PINS _Y2_PINS _Z2_PINS \ } #define HAS_DIGIPOTSS (PIN_EXISTS(DIGIPOTSS)) diff --git a/Marlin/pinsDebug_list.h b/Marlin/pinsDebug_list.h index e19858d528..b72c26dfe0 100644 --- a/Marlin/pinsDebug_list.h +++ b/Marlin/pinsDebug_list.h @@ -443,6 +443,18 @@ #if PIN_EXISTS(FIL_RUNOUT) REPORT_NAME_DIGITAL(__LINE__, FIL_RUNOUT_PIN) #endif +#if PIN_EXISTS(FIL_RUNOUT2) + REPORT_NAME_DIGITAL(__LINE__, FIL_RUNOUT2_PIN) +#endif +#if PIN_EXISTS(FIL_RUNOUT3) + REPORT_NAME_DIGITAL(__LINE__, FIL_RUNOUT3_PIN) +#endif +#if PIN_EXISTS(FIL_RUNOUT4) + REPORT_NAME_DIGITAL(__LINE__, FIL_RUNOUT4_PIN) +#endif +#if PIN_EXISTS(FIL_RUNOUT5) + REPORT_NAME_DIGITAL(__LINE__, FIL_RUNOUT5_PIN) +#endif #if PIN_EXISTS(HEATER_0) REPORT_NAME_DIGITAL(__LINE__, HEATER_0_PIN) #endif diff --git a/Marlin/pins_ANET_10.h b/Marlin/pins_ANET_10.h index bdd277e35c..a8cbd5f29c 100644 --- a/Marlin/pins_ANET_10.h +++ b/Marlin/pins_ANET_10.h @@ -153,7 +153,7 @@ * REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER */ -#if ENABLED(ULTRA_LCD) && ENABLED(NEWPANEL) +#if ENABLED(ULTRA_LCD) #define LCD_SDSS 28 #if ENABLED(ADC_KEYPAD) #define SERVO0_PIN 27 // free for BLTouch/3D-Touch @@ -193,7 +193,7 @@ #endif #else #define SERVO0_PIN 27 -#endif // ULTRA_LCD && NEWPANEL +#endif /** * ==================================================================== diff --git a/Marlin/pins_EINSY_RAMBO.h b/Marlin/pins_EINSY_RAMBO.h index b3c1d1caa0..e3f67059fa 100644 --- a/Marlin/pins_EINSY_RAMBO.h +++ b/Marlin/pins_EINSY_RAMBO.h @@ -33,10 +33,8 @@ // // TMC2130 Configuration_adv defaults for EinsyRambo // -#if DISABLED(HAVE_TMC2130) - #error "You must enable TMC2130 support in Configuration_adv.h for EinsyRambo." -#elif DISABLED(X_IS_TMC2130) || DISABLED(Y_IS_TMC2130) || DISABLED(Z_IS_TMC2130) || DISABLED(E0_IS_TMC2130) - #error "You must enable ([XYZ]|E0)_IS_TMC2130 in Configuration_adv.h for EinsyRambo." +#if !AXIS_DRIVER_TYPE(X, TMC2130) || !AXIS_DRIVER_TYPE(Y, TMC2130) || !AXIS_DRIVER_TYPE(Z, TMC2130) || !AXIS_DRIVER_TYPE(E0, TMC2130) + #error "You must set ([XYZ]|E0)_DRIVER_TYPE to TMC2130 in Configuration.h for EinsyRambo." #endif // TMC2130 Diag Pins (currently just for reference) @@ -120,7 +118,10 @@ #ifndef FAN_PIN #define FAN_PIN 8 #endif -#define FAN1_PIN 6 + +#ifndef FAN1_PIN + #define FAN1_PIN 6 +#endif // // Misc. Functions diff --git a/Marlin/pins_EINSY_RETRO.h b/Marlin/pins_EINSY_RETRO.h index df4f1c20be..a100d9329e 100644 --- a/Marlin/pins_EINSY_RETRO.h +++ b/Marlin/pins_EINSY_RETRO.h @@ -33,10 +33,8 @@ // // TMC2130 Configuration_adv defaults for EinsyRetro // -#if DISABLED(HAVE_TMC2130) - #error "You must enable TMC2130 support in Configuration_adv.h for EinsyRetro." -#elif DISABLED(X_IS_TMC2130) || DISABLED(Y_IS_TMC2130) || DISABLED(Z_IS_TMC2130) || DISABLED(E0_IS_TMC2130) - #error "You must enable ([XYZ]|E0)_IS_TMC2130 in Configuration_adv.h for EinsyRetro." +#if !AXIS_DRIVER_TYPE(X, TMC2130) || !AXIS_DRIVER_TYPE(Y, TMC2130) || !AXIS_DRIVER_TYPE(Z, TMC2130) || !AXIS_DRIVER_TYPE(E0, TMC2130) + #error "You must set ([XYZ]|E0)_DRIVER_TYPE to TMC2130 in Configuration.h for EinsyRetro." #endif // TMC2130 Diag Pins (currently just for reference) diff --git a/Marlin/pins_RIGIDBOARD.h b/Marlin/pins_RIGIDBOARD.h index e985963505..f783d83c61 100644 --- a/Marlin/pins_RIGIDBOARD.h +++ b/Marlin/pins_RIGIDBOARD.h @@ -36,6 +36,7 @@ // // MOSFET changes // +#define RAMPS_D9_PIN 8 // FAN (by default) #define RAMPS_D10_PIN 9 // EXTRUDER 1 #define MOSFET_D_PIN 12 // EXTRUDER 2 or FAN diff --git a/Marlin/pins_TRIGORILLA_14.h b/Marlin/pins_TRIGORILLA_14.h index 70b0a930a9..80ce3bc98c 100644 --- a/Marlin/pins_TRIGORILLA_14.h +++ b/Marlin/pins_TRIGORILLA_14.h @@ -30,7 +30,52 @@ #define IS_RAMPS_EFB -#define FAN2_PIN 44 -#define ORIG_E0_AUTO_FAN_PIN 44 +// FAN0 / D9 - Typically used for the part fan on Anycubic Delta devices +#define FAN_PIN 9 + +// FAN1 / D7 - Typically unused, can be allocated as Case Fan + +// FAN2 / D44 - Typical Extruder Fan on Anycubic Delta devices +#define FAN2_PIN 44 +#define ORIG_E0_AUTO_FAN_PIN 44 #include "pins_RAMPS.h" + +// TODO 1.4 boards do have an E1 stepper driver. However the pin definitions +// from pins_RAMPS.h are incorrect for this board. e.g., Pin 44 is the Extruder fan. +#undef E1_STEP_PIN +#undef E1_DIR_PIN +#undef E1_ENABLE_PIN +#undef E1_CS_PIN + +// +// AnyCubic made the following changes to 1.1.0-RC8 +// If these are appropriate for your LCD let us know. +// +#if 0 && ENABLED(ULTRA_LCD) + + // LCD Display output pins + #if ENABLED(NEWPANEL) && ENABLED(PANEL_ONE) + #undef LCD_PINS_D6 + #define LCD_PINS_D6 57 + #endif + + // LCD Display input pins + #if ENABLED(NEWPANEL) + #if ENABLED(VIKI2) || ENABLED(miniVIKI) + #undef DOGLCD_A0 + #define DOGLCD_A0 23 + #elif ENABLED(ELB_FULL_GRAPHIC_CONTROLLER) + #undef BEEPER_PIN + #define BEEPER_PIN 33 + #undef LCD_BACKLIGHT_PIN + #define LCD_BACKLIGHT_PIN 67 + #endif + #elif ENABLED(MINIPANEL) + #undef BEEPER_PIN + #define BEEPER_PIN 33 + #undef DOGLCD_A0 + #define DOGLCD_A0 42 + #endif + +#endif // ULTRA_LCD diff --git a/Marlin/pins_ULTIMAKER.h b/Marlin/pins_ULTIMAKER.h index 4b6488aede..23941a1624 100644 --- a/Marlin/pins_ULTIMAKER.h +++ b/Marlin/pins_ULTIMAKER.h @@ -43,7 +43,7 @@ // // Servos // -#define SERVO0_PIN 13 // UNTESTED +#define SERVO0_PIN 11 // // Limit Switches diff --git a/Marlin/planner.cpp b/Marlin/planner.cpp index 7a73c50f6d..e21c50126c 100644 --- a/Marlin/planner.cpp +++ b/Marlin/planner.cpp @@ -100,13 +100,13 @@ volatile uint8_t Planner::block_buffer_head, // Index of the next block to be uint16_t Planner::cleaning_buffer_counter; // A counter to disable queuing of blocks uint8_t Planner::delay_before_delivering; // This counter delays delivery of blocks when queue becomes empty to allow the opportunity of merging blocks -uint32_t Planner::max_acceleration_mm_per_s2[XYZE_N], // (mm/s^2) M201 XYZE - Planner::max_acceleration_steps_per_s2[XYZE_N], // (steps/s^2) Derived from mm_per_s2 - Planner::min_segment_time_us; // (µs) M205 B +uint32_t Planner::max_acceleration_mm_per_s2[NUM_AXIS_N], // (mm/s^2) M201 XYZE + Planner::max_acceleration_steps_per_s2[NUM_AXIS_N], // (steps/s^2) Derived from mm_per_s2 + Planner::min_segment_time_us; // (µs) M205 Q -float Planner::max_feedrate_mm_s[XYZE_N], // (mm/s) M203 XYZE - Max speeds - Planner::axis_steps_per_mm[XYZE_N], // (steps) M92 XYZE - Steps per millimeter - Planner::steps_to_mm[XYZE_N], // (mm) Millimeters per step +float Planner::max_feedrate_mm_s[NUM_AXIS_N], // (mm/s) M203 XYZE - Max speeds + Planner::axis_steps_per_mm[NUM_AXIS_N], // (steps) M92 XYZE - Steps per millimeter + Planner::steps_to_mm[NUM_AXIS_N], // (mm) Millimeters per step Planner::min_feedrate_mm_s, // (mm/s) M205 S - Minimum linear feedrate Planner::acceleration, // (mm/s^2) M204 S - Normal acceleration. DEFAULT ACCELERATION for all printing moves. Planner::retract_acceleration, // (mm/s^2) M204 R - Retract acceleration. Filament pull-back and push-forward while standing still in the other axes @@ -123,7 +123,14 @@ float Planner::max_feedrate_mm_s[XYZE_N], // (mm/s) M203 XYZE - Max speeds #endif #endif #else - float Planner::max_jerk[XYZE]; // (mm/s^2) M205 XYZE - The largest speed change requiring no acceleration. + float Planner::max_jerk[NUM_AXIS]; // (mm/s^2) M205 XYZE - The largest speed change requiring no acceleration. +#endif + +#if ENABLED(LINE_BUILDUP_COMPENSATION_FEATURE) + float Planner::k0[MOV_AXIS], + Planner::k1[MOV_AXIS], + Planner::k2[MOV_AXIS], + Planner::sqrtk1[MOV_AXIS]; #endif #if ENABLED(ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED) @@ -206,7 +213,7 @@ float Planner::previous_speed[NUM_AXIS], #endif #if HAS_POSITION_FLOAT - float Planner::position_float[XYZE]; // Needed for accurate maths. Steps cannot be used! + float Planner::position_float[NUM_AXIS]; // Needed for accurate maths. Steps cannot be used! #endif #if ENABLED(ULTRA_LCD) @@ -1137,7 +1144,13 @@ void Planner::recalculate() { 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 (block->steps[X_AXIS] || block->steps[Y_AXIS] || block->steps[Z_AXIS]) { + if ( + #if ENABLED(HANGPRINTER) + block->steps[A_AXIS] || block->steps[B_AXIS] || block->steps[C_AXIS] || block->steps[D_AXIS] + #else + block->steps[X_AXIS] || block->steps[Y_AXIS] || block->steps[Z_AXIS] + #endif + ) { const float se = (float)block->steps[E_AXIS] / block->step_event_count * SQRT(block->nominal_speed_sqr); // mm/sec; NOLESS(high, se); } @@ -1514,6 +1527,9 @@ float Planner::get_axis_position_mm(const AxisEnum axis) { #else axis_steps = stepper.position(axis); #endif + #if ENABLED(LINE_BUILDUP_COMPENSATION_FEATURE) + if (axis != E_AXIS) return (sq(axis_steps / k0[axis] + sqrtk1[axis]) - k1[axis]) / k2[axis]; + #endif return axis_steps * steps_to_mm[axis]; } @@ -1522,23 +1538,34 @@ float Planner::get_axis_position_mm(const AxisEnum axis) { */ void Planner::synchronize() { while (has_blocks_queued() || cleaning_buffer_counter) idle(); } +#if ENABLED(UNREGISTERED_MOVE_SUPPORT) + #define COUNT_MOVE count_it +#else + #define COUNT_MOVE true +#endif + /** * Planner::_buffer_steps * * Add a new linear movement to the planner queue (in terms of steps). * - * target - target position in steps units - * fr_mm_s - (target) speed of the move - * extruder - target extruder - * millimeters - the length of the movement, if known + * target - target position in steps units + * target_float - target position in mm (HAS_POSITION_FLOAT) + * fr_mm_s - (target) speed of the move + * extruder - target extruder + * millimeters - the length of the movement, if known + * count_it - apply this move to the counters (UNREGISTERED_MOVE_SUPPORT) * * Returns true if movement was properly queued, false otherwise */ -bool Planner::_buffer_steps(const int32_t (&target)[XYZE] +bool Planner::_buffer_steps(const int32_t (&target)[NUM_AXIS] #if HAS_POSITION_FLOAT - , const float (&target_float)[XYZE] + , const float (&target_float)[NUM_AXIS] + #endif + , float fr_mm_s, const uint8_t extruder, const float &millimeters/*=0.0*/ + #if ENABLED(UNREGISTERED_MOVE_SUPPORT) + , const bool count_it/*=true*/ #endif - , float fr_mm_s, const uint8_t extruder, const float &millimeters ) { // If we are cleaning, do not accept queuing of movements @@ -1554,6 +1581,9 @@ bool Planner::_buffer_steps(const int32_t (&target)[XYZE] , target_float #endif , fr_mm_s, extruder, millimeters + #if ENABLED(UNREGISTERED_MOVE_SUPPORT) + , count_it + #endif )) { // Movement was not queued, probably because it was too short. // Simply accept that as movement queued and done @@ -1585,24 +1615,33 @@ bool Planner::_buffer_steps(const int32_t (&target)[XYZE] * * Fills a new linear movement in the block (in terms of steps). * - * target - target position in steps units - * fr_mm_s - (target) speed of the move - * extruder - target extruder + * target - target position in steps units + * target_float - target position in mm (HAS_POSITION_FLOAT) + * fr_mm_s - (target) speed of the move + * extruder - target extruder + * millimeters - the length of the movement, if known + * count_it - apply this move to the counters (UNREGISTERED_MOVE_SUPPORT) * * Returns true is movement is acceptable, false otherwise */ bool Planner::_populate_block(block_t * const block, bool split_move, - const int32_t (&target)[XYZE] + const int32_t (&target)[NUM_AXIS] #if HAS_POSITION_FLOAT - , const float (&target_float)[XYZE] + , const float (&target_float)[NUM_AXIS] #endif , float fr_mm_s, const uint8_t extruder, const float &millimeters/*=0.0*/ + #if ENABLED(UNREGISTERED_MOVE_SUPPORT) + , const bool count_it/*=true*/ + #endif ) { const int32_t da = target[A_AXIS] - position[A_AXIS], db = target[B_AXIS] - position[B_AXIS], - dc = target[C_AXIS] - position[C_AXIS]; - + dc = target[C_AXIS] - position[C_AXIS] + #if ENABLED(HANGPRINTER) + , dd = target[D_AXIS] - position[D_AXIS] + #endif + ; int32_t de = target[E_AXIS] - position[E_AXIS]; /* <-- add a slash to enable @@ -1622,10 +1661,12 @@ bool Planner::_populate_block(block_t * const block, bool split_move, if (de) { #if ENABLED(PREVENT_COLD_EXTRUSION) if (thermalManager.tooColdToExtrude(extruder)) { - position[E_AXIS] = target[E_AXIS]; // Behave as if the move really took place, but ignore E part - #if HAS_POSITION_FLOAT - position_float[E_AXIS] = target_float[E_AXIS]; - #endif + if (COUNT_MOVE) { + position[E_AXIS] = target[E_AXIS]; // Behave as if the move really took place, but ignore E part + #if HAS_POSITION_FLOAT + position_float[E_AXIS] = target_float[E_AXIS]; + #endif + } de = 0; // no difference SERIAL_ECHO_START(); SERIAL_ECHOLNPGM(MSG_ERR_COLD_EXTRUDE_STOP); @@ -1633,10 +1674,12 @@ bool Planner::_populate_block(block_t * const block, bool split_move, #endif // PREVENT_COLD_EXTRUSION #if ENABLED(PREVENT_LENGTHY_EXTRUDE) if (ABS(de * e_factor[extruder]) > (int32_t)axis_steps_per_mm[E_AXIS_N] * (EXTRUDE_MAXLENGTH)) { // It's not important to get max. extrusion length in a precision < 1mm, so save some cycles and cast to int - position[E_AXIS] = target[E_AXIS]; // Behave as if the move really took place, but ignore E part - #if HAS_POSITION_FLOAT - position_float[E_AXIS] = target_float[E_AXIS]; - #endif + if (COUNT_MOVE) { + position[E_AXIS] = target[E_AXIS]; // Behave as if the move really took place, but ignore E part + #if HAS_POSITION_FLOAT + position_float[E_AXIS] = target_float[E_AXIS]; + #endif + } de = 0; // no difference SERIAL_ECHO_START(); SERIAL_ECHOLNPGM(MSG_ERR_LONG_EXTRUDE_STOP); @@ -1665,6 +1708,11 @@ bool Planner::_populate_block(block_t * const block, bool split_move, if (dc < 0) SBI(dm, Z_HEAD); // ...and Z if (db + dc < 0) SBI(dm, B_AXIS); // Motor B direction if (CORESIGN(db - dc) < 0) SBI(dm, C_AXIS); // Motor C direction + #elif ENABLED(HANGPRINTER) + if (da < 0) SBI(dm, A_AXIS); + if (db < 0) SBI(dm, B_AXIS); + if (dc < 0) SBI(dm, C_AXIS); + if (dd < 0) SBI(dm, D_AXIS); #else if (da < 0) SBI(dm, X_AXIS); if (db < 0) SBI(dm, Y_AXIS); @@ -1681,6 +1729,11 @@ bool Planner::_populate_block(block_t * const block, bool split_move, // Set direction bits block->direction_bits = dm; + // Specify if block is to be counted or not + #if ENABLED(UNREGISTERED_MOVE_SUPPORT) + block->count_it = count_it; + #endif + // Number of steps for each axis // See http://www.corexy.com/theory.html #if CORE_IS_XY @@ -1699,6 +1752,11 @@ bool Planner::_populate_block(block_t * const block, bool split_move, block->steps[A_AXIS] = ABS(da); block->steps[B_AXIS] = ABS(db); block->steps[Z_AXIS] = ABS(dc); + #elif ENABLED(HANGPRINTER) + block->steps[A_AXIS] = ABS(da); + block->steps[B_AXIS] = ABS(db); + block->steps[C_AXIS] = ABS(dc); + block->steps[D_AXIS] = ABS(dd); #else // default non-h-bot planning block->steps[A_AXIS] = ABS(da); @@ -1707,7 +1765,14 @@ bool Planner::_populate_block(block_t * const block, bool split_move, #endif block->steps[E_AXIS] = esteps; - block->step_event_count = MAX4(block->steps[A_AXIS], block->steps[B_AXIS], block->steps[C_AXIS], esteps); + + block->step_event_count = ( + #if ENABLED(HANGPRINTER) + MAX5(block->steps[A_AXIS], block->steps[B_AXIS], block->steps[C_AXIS], block->steps[D_AXIS], esteps) + #else + MAX4(block->steps[A_AXIS], block->steps[B_AXIS], block->steps[C_AXIS], esteps) + #endif + ); // Bail if this is a zero-length block if (block->step_event_count < MIN_STEPS_PER_SEGMENT) return false; @@ -1715,13 +1780,7 @@ bool Planner::_populate_block(block_t * const block, bool split_move, // For a mixing extruder, get a magnified esteps for each #if ENABLED(MIXING_EXTRUDER) for (uint8_t i = 0; i < MIXING_STEPPERS; i++) - block->mix_steps[i] = mixing_factor[i] * ( - #if ENABLED(LIN_ADVANCE) - esteps - #else - block->step_event_count - #endif - ); + block->mix_steps[i] = mixing_factor[i] * esteps; #endif #if FAN_COUNT > 0 @@ -1761,7 +1820,7 @@ bool Planner::_populate_block(block_t * const block, bool split_move, enable_Z(); } if (block->steps[X_AXIS]) enable_X(); - #else + #elif DISABLED(HANGPRINTER) // Hangprinters X, Y, Z, E0 axes should always be enabled anyways if (block->steps[X_AXIS]) enable_X(); if (block->steps[Y_AXIS]) enable_Y(); #if DISABLED(Z_LATE_ENABLE) @@ -1902,14 +1961,21 @@ bool Planner::_populate_block(block_t * const block, bool split_move, delta_mm[C_AXIS] = CORESIGN(db - dc) * steps_to_mm[C_AXIS]; #endif #else - float delta_mm[ABCE]; + float delta_mm[NUM_AXIS]; delta_mm[A_AXIS] = da * steps_to_mm[A_AXIS]; delta_mm[B_AXIS] = db * steps_to_mm[B_AXIS]; delta_mm[C_AXIS] = dc * steps_to_mm[C_AXIS]; + #if ENABLED(HANGPRINTER) + delta_mm[D_AXIS] = dd * steps_to_mm[D_AXIS]; + #endif #endif delta_mm[E_AXIS] = esteps_float * steps_to_mm[E_AXIS_N]; - if (block->steps[A_AXIS] < MIN_STEPS_PER_SEGMENT && block->steps[B_AXIS] < MIN_STEPS_PER_SEGMENT && block->steps[C_AXIS] < MIN_STEPS_PER_SEGMENT) { + if (block->steps[A_AXIS] < MIN_STEPS_PER_SEGMENT && block->steps[B_AXIS] < MIN_STEPS_PER_SEGMENT && block->steps[C_AXIS] < MIN_STEPS_PER_SEGMENT + #if ENABLED(HANGPRINTER) + && block->steps[D_AXIS] < MIN_STEPS_PER_SEGMENT + #endif + ) { block->millimeters = ABS(delta_mm[E_AXIS]); } else if (!millimeters) { @@ -1920,6 +1986,8 @@ bool Planner::_populate_block(block_t * const block, bool split_move, sq(delta_mm[X_HEAD]) + sq(delta_mm[Y_AXIS]) + sq(delta_mm[Z_HEAD]) #elif CORE_IS_YZ sq(delta_mm[X_AXIS]) + sq(delta_mm[Y_HEAD]) + sq(delta_mm[Z_HEAD]) + #elif ENABLED(HANGPRINTER) + sq(delta_mm[A_AXIS]) + sq(delta_mm[B_AXIS]) + sq(delta_mm[C_AXIS]) + sq(delta_mm[D_AXIS]) #else sq(delta_mm[X_AXIS]) + sq(delta_mm[Y_AXIS]) + sq(delta_mm[Z_AXIS]) #endif @@ -2005,7 +2073,7 @@ bool Planner::_populate_block(block_t * const block, bool split_move, // Calculate and limit speed in mm/sec for each axis float current_speed[NUM_AXIS], speed_factor = 1.0f; // factor <1 decreases speed - LOOP_XYZE(i) { + LOOP_NUM_AXIS(i) { const float cs = ABS((current_speed[i] = delta_mm[i] * inverse_secs)); #if ENABLED(DISTINCT_E_FACTORS) if (i == E_AXIS) i += extruder; @@ -2053,7 +2121,7 @@ bool Planner::_populate_block(block_t * const block, bool split_move, // Correct the speed if (speed_factor < 1.0f) { - LOOP_XYZE(i) current_speed[i] *= speed_factor; + LOOP_NUM_AXIS(i) current_speed[i] *= speed_factor; block->nominal_rate *= speed_factor; block->nominal_speed_sqr = block->nominal_speed_sqr * sq(speed_factor); } @@ -2061,7 +2129,11 @@ 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 (!block->steps[A_AXIS] && !block->steps[B_AXIS] && !block->steps[C_AXIS]) { + if (!block->steps[A_AXIS] && !block->steps[B_AXIS] && !block->steps[C_AXIS] + #if ENABLED(HANGPRINTER) + && !block->steps[D_AXIS] + #endif + ) { // convert to: acceleration steps/sec^2 accel = CEIL(retract_acceleration * steps_per_mm); #if ENABLED(LIN_ADVANCE) @@ -2148,12 +2220,18 @@ bool Planner::_populate_block(block_t * const block, bool split_move, LIMIT_ACCEL_LONG(A_AXIS, 0); LIMIT_ACCEL_LONG(B_AXIS, 0); LIMIT_ACCEL_LONG(C_AXIS, 0); + #if ENABLED(HANGPRINTER) + LIMIT_ACCEL_LONG(D_AXIS, 0); + #endif LIMIT_ACCEL_LONG(E_AXIS, ACCEL_IDX); } else { LIMIT_ACCEL_FLOAT(A_AXIS, 0); LIMIT_ACCEL_FLOAT(B_AXIS, 0); LIMIT_ACCEL_FLOAT(C_AXIS, 0); + #if ENABLED(HANGPRINTER) + LIMIT_ACCEL_FLOAT(D_AXIS, 0); + #endif LIMIT_ACCEL_FLOAT(E_AXIS, ACCEL_IDX); } } @@ -2279,27 +2357,27 @@ bool Planner::_populate_block(block_t * const block, bool split_move, /** * Adapted from Průša MKS firmware * https://github.com/prusa3d/Prusa-Firmware - * - * Start with a safe speed (from which the machine may halt to stop immediately). */ + const float nominal_speed = SQRT(block->nominal_speed_sqr); // Exit speed limited by a jerk to full halt of a previous last segment static float previous_safe_speed; - const float nominal_speed = SQRT(block->nominal_speed_sqr); + // Start with a safe speed (from which the machine may halt to stop immediately). float safe_speed = nominal_speed; uint8_t limited = 0; - LOOP_XYZE(i) { - const float jerk = ABS(current_speed[i]), maxj = max_jerk[i]; - if (jerk > maxj) { - if (limited) { - const float mjerk = maxj * nominal_speed; - if (jerk * safe_speed > mjerk) safe_speed = mjerk / jerk; + LOOP_NUM_AXIS(i) { + const float jerk = ABS(current_speed[i]), // cs : Starting from zero, change in speed for this axis + maxj = max_jerk[i]; // mj : The max jerk setting for this axis + if (jerk > maxj) { // cs > mj : New current speed too fast? + if (limited) { // limited already? + const float mjerk = nominal_speed * maxj; // ns*mj + if (jerk * safe_speed > mjerk) safe_speed = mjerk / jerk; // ns*mj/cs } else { - ++limited; - safe_speed = maxj; + safe_speed *= maxj / jerk; // Initial limit: ns*mj/cs + ++limited; // Initially limited } } } @@ -2321,7 +2399,7 @@ bool Planner::_populate_block(block_t * const block, bool split_move, // Now limit the jerk in all axes. const float smaller_speed_factor = vmax_junction / previous_nominal_speed; - LOOP_XYZE(axis) { + LOOP_NUM_AXIS(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]; @@ -2381,12 +2459,22 @@ bool Planner::_populate_block(block_t * const block, bool split_move, COPY(previous_speed, current_speed); previous_nominal_speed_sqr = block->nominal_speed_sqr; - // Update the position - static_assert(COUNT(target) > 1, "Parameter to _buffer_steps must be (&target)[XYZE]!"); - COPY(position, target); - #if HAS_POSITION_FLOAT - COPY(position_float, target_float); - #endif + // Update the position (only when a move was queued) + static_assert(COUNT(target) > 1, "Parameter to _populate_block must be (&target)[" + #if ENABLED(HANGPRINTER) + "ABCD" + #else + "XYZ" + #endif + "E]!" + ); + + if (COUNT_MOVE) { + COPY(position, target); + #if HAS_POSITION_FLOAT + COPY(position_float, target_float); + #endif + } // Movement was accepted return true; @@ -2409,6 +2497,9 @@ void Planner::buffer_sync_block() { block->position[A_AXIS] = position[A_AXIS]; block->position[B_AXIS] = position[B_AXIS]; block->position[C_AXIS] = position[C_AXIS]; + #if ENABLED(HANGPRINTER) + block->position[D_AXIS] = position[D_AXIS]; + #endif block->position[E_AXIS] = position[E_AXIS]; // If this is the first added movement, reload the delay, otherwise, cancel it. @@ -2438,7 +2529,15 @@ void Planner::buffer_sync_block() { * extruder - target extruder * millimeters - the length of the movement, if known */ -bool Planner::buffer_segment(const float &a, const float &b, const float &c, const float &e, const float &fr_mm_s, const uint8_t extruder, const float &millimeters/*=0.0*/) { +bool Planner::buffer_segment(const float &a, const float &b, const float &c + #if ENABLED(HANGPRINTER) + , const float &d + #endif + , const float &e, const float &fr_mm_s, const uint8_t extruder, const float &millimeters/*=0.0*/ + #if ENABLED(UNREGISTERED_MOVE_SUPPORT) + , bool count_it /* = true */ + #endif +) { // If we are cleaning, do not accept queuing of movements if (cleaning_buffer_counter) return false; @@ -2453,23 +2552,40 @@ bool Planner::buffer_segment(const float &a, const float &b, const float &c, con // The target position of the tool in absolute steps // Calculate target position in absolute steps - const int32_t target[ABCE] = { - LROUND(a * axis_steps_per_mm[A_AXIS]), - LROUND(b * axis_steps_per_mm[B_AXIS]), - LROUND(c * axis_steps_per_mm[C_AXIS]), + const int32_t target[NUM_AXIS] = { + #if ENABLED(LINE_BUILDUP_COMPENSATION_FEATURE) + LROUND(k0[A_AXIS] * (SQRT(k1[A_AXIS] + a * k2[A_AXIS]) - sqrtk1[A_AXIS])), + LROUND(k0[B_AXIS] * (SQRT(k1[B_AXIS] + b * k2[B_AXIS]) - sqrtk1[B_AXIS])), + LROUND(k0[C_AXIS] * (SQRT(k1[C_AXIS] + c * k2[C_AXIS]) - sqrtk1[C_AXIS])), + LROUND(k0[D_AXIS] * (SQRT(k1[D_AXIS] + d * k2[D_AXIS]) - sqrtk1[D_AXIS])), + #else + LROUND(a * axis_steps_per_mm[A_AXIS]), + LROUND(b * axis_steps_per_mm[B_AXIS]), + LROUND(c * axis_steps_per_mm[C_AXIS]), + #if ENABLED(HANGPRINTER) + LROUND(d * axis_steps_per_mm[D_AXIS]), + #endif + #endif LROUND(e * axis_steps_per_mm[E_AXIS_N]) }; #if HAS_POSITION_FLOAT - const float target_float[XYZE] = { a, b, c, e }; + const float target_float[NUM_AXIS] = { a, b, c + #if ENABLED(HANGPRINTER) + , d + #endif + , e + }; #endif // DRYRUN prevents E moves from taking place if (DEBUGGING(DRYRUN)) { - position[E_AXIS] = target[E_AXIS]; - #if HAS_POSITION_FLOAT - position_float[E_AXIS] = e; - #endif + if (COUNT_MOVE) { + position[E_AXIS] = target[E_AXIS]; + #if HAS_POSITION_FLOAT + position_float[E_AXIS] = e; + #endif + } } /* <-- add a slash to enable @@ -2487,13 +2603,18 @@ bool Planner::buffer_segment(const float &a, const float &b, const float &c, con #endif SERIAL_ECHOPAIR(" (", position[Y_AXIS]); SERIAL_ECHOPAIR("->", target[Y_AXIS]); - #if ENABLED(DELTA) + #if ENABLED(DELTA) || ENABLED(HANGPRINTER) SERIAL_ECHOPAIR(") C:", c); #else SERIAL_ECHOPAIR(") Z:", c); #endif SERIAL_ECHOPAIR(" (", position[Z_AXIS]); SERIAL_ECHOPAIR("->", target[Z_AXIS]); + #if ENABLED(HANGPRINTER) + SERIAL_ECHOPAIR(") D:", d); + SERIAL_ECHOPAIR(" (", position[D_AXIS]); + SERIAL_ECHOPAIR("->", target[D_AXIS]); + #endif SERIAL_ECHOPAIR(") E:", e); SERIAL_ECHOPAIR(" (", position[E_AXIS]); SERIAL_ECHOPAIR("->", target[E_AXIS]); @@ -2501,12 +2622,15 @@ bool Planner::buffer_segment(const float &a, const float &b, const float &c, con //*/ // Queue the movement - if ( + if ( !_buffer_steps(target #if HAS_POSITION_FLOAT , target_float #endif , fr_mm_s, extruder, millimeters + #if ENABLED(UNREGISTERED_MOVE_SUPPORT) + , count_it + #endif ) ) return false; @@ -2521,18 +2645,41 @@ bool Planner::buffer_segment(const float &a, const float &b, const float &c, con * On CORE machines stepper ABC will be translated from the given XYZ. */ -void Planner::_set_position_mm(const float &a, const float &b, const float &c, const float &e) { +void Planner::_set_position_mm(const float &a, const float &b, const float &c + #if ENABLED(HANGPRINTER) + , const float &d + #endif + , const float &e +) { #if ENABLED(DISTINCT_E_FACTORS) last_extruder = active_extruder; #endif - position[A_AXIS] = LROUND(a * axis_steps_per_mm[A_AXIS]), - position[B_AXIS] = LROUND(b * axis_steps_per_mm[B_AXIS]), - position[C_AXIS] = LROUND(c * axis_steps_per_mm[C_AXIS]), + #if ENABLED(LINE_BUILDUP_COMPENSATION_FEATURE) + position[A_AXIS] = LROUND(k0[A_AXIS] * (SQRT(k1[A_AXIS] + a * k2[A_AXIS]) - sqrtk1[A_AXIS])), + position[B_AXIS] = LROUND(k0[B_AXIS] * (SQRT(k1[B_AXIS] + b * k2[B_AXIS]) - sqrtk1[B_AXIS])), + position[C_AXIS] = LROUND(k0[C_AXIS] * (SQRT(k1[C_AXIS] + c * k2[C_AXIS]) - sqrtk1[C_AXIS])), + position[D_AXIS] = LROUND(k0[D_AXIS] * (SQRT(k1[D_AXIS] + d * k2[D_AXIS]) - sqrtk1[D_AXIS])), + #else + position[A_AXIS] = LROUND(a * axis_steps_per_mm[A_AXIS]); + position[B_AXIS] = LROUND(b * axis_steps_per_mm[B_AXIS]); + position[C_AXIS] = LROUND(axis_steps_per_mm[C_AXIS] * (c + ( + #if !IS_KINEMATIC && ENABLED(AUTO_BED_LEVELING_UBL) + leveling_active ? ubl.get_z_correction(a, b) : + #endif + 0) + )); + #if ENABLED(HANGPRINTER) + position[D_AXIS] = LROUND(d * axis_steps_per_mm[D_AXIS]), + #endif + #endif position[E_AXIS] = LROUND(e * axis_steps_per_mm[_EINDEX]); #if HAS_POSITION_FLOAT position_float[A_AXIS] = a; position_float[B_AXIS] = b; position_float[C_AXIS] = c; + #if ENABLED(HANGPRINTER) + position_float[D_AXIS] = d; + #endif position_float[E_AXIS] = e; #endif if (has_blocks_queued()) { @@ -2541,21 +2688,32 @@ void Planner::_set_position_mm(const float &a, const float &b, const float &c, c buffer_sync_block(); } else - stepper.set_position(position[A_AXIS], position[B_AXIS], position[C_AXIS], position[E_AXIS]); + stepper.set_position(position[A_AXIS], position[B_AXIS], position[C_AXIS], + #if ENABLED(HANGPRINTER) + position[D_AXIS], + #endif + position[E_AXIS] + ); } void Planner::set_position_mm_kinematic(const float (&cart)[XYZE]) { #if PLANNER_LEVELING float raw[XYZ] = { cart[X_AXIS], cart[Y_AXIS], cart[Z_AXIS] }; apply_leveling(raw); + #elif ENABLED(HANGPRINTER) + float raw[XYZ] = { cart[X_AXIS], cart[Y_AXIS], cart[Z_AXIS] }; #else const float (&raw)[XYZE] = cart; #endif #if IS_KINEMATIC inverse_kinematics(raw); - _set_position_mm(delta[A_AXIS], delta[B_AXIS], delta[C_AXIS], cart[E_AXIS]); + #if ENABLED(HANGPRINTER) + _set_position_mm(line_lengths[A_AXIS], line_lengths[B_AXIS], line_lengths[C_AXIS], line_lengths[D_AXIS], cart[E_CART]); + #else + _set_position_mm(delta[A_AXIS], delta[B_AXIS], delta[C_AXIS], cart[E_CART]); + #endif #else - _set_position_mm(raw[X_AXIS], raw[Y_AXIS], raw[Z_AXIS], cart[E_AXIS]); + _set_position_mm(raw[X_AXIS], raw[Y_AXIS], raw[Z_AXIS], cart[E_CART]); #endif } @@ -2569,14 +2727,17 @@ void Planner::set_position_mm(const AxisEnum axis, const float &v) { #else const uint8_t axis_index = axis; #endif - position[axis] = LROUND(v * axis_steps_per_mm[axis_index]); + position[axis] = LROUND(axis_steps_per_mm[axis_index] * (v + ( + #if ENABLED(AUTO_BED_LEVELING_UBL) + axis == Z_AXIS && leveling_active ? ubl.get_z_correction(current_position[X_AXIS], current_position[Y_AXIS]) : + #endif + 0) + )); #if HAS_POSITION_FLOAT position_float[axis] = v; #endif - if (has_blocks_queued()) { - //previous_speed[axis] = 0.0; + if (has_blocks_queued()) buffer_sync_block(); - } else stepper.set_position(axis, position[axis]); } @@ -2589,7 +2750,7 @@ void Planner::reset_acceleration_rates() { #define AXIS_CONDITION true #endif uint32_t highest_rate = 1; - LOOP_XYZE_N(i) { + LOOP_NUM_AXIS_N(i) { max_acceleration_steps_per_s2[i] = max_acceleration_mm_per_s2[i] * axis_steps_per_mm[i]; if (AXIS_CONDITION) NOLESS(highest_rate, max_acceleration_steps_per_s2[i]); } @@ -2601,7 +2762,7 @@ void Planner::reset_acceleration_rates() { // Recalculate position, steps_to_mm if axis_steps_per_mm changes! void Planner::refresh_positioning() { - LOOP_XYZE_N(i) steps_to_mm[i] = 1.0f / axis_steps_per_mm[i]; + LOOP_NUM_AXIS_N(i) steps_to_mm[i] = 1.0f / axis_steps_per_mm[i]; set_position_mm_kinematic(current_position); reset_acceleration_rates(); } diff --git a/Marlin/planner.h b/Marlin/planner.h index fd06be588c..c4d459de91 100644 --- a/Marlin/planner.h +++ b/Marlin/planner.h @@ -76,6 +76,10 @@ typedef struct { volatile uint8_t flag; // Block flags (See BlockFlag enum above) - Modified by ISR and main thread! + #if ENABLED(UNREGISTERED_MOVE_SUPPORT) + bool count_it; + #endif + // Fields used by the motion planner to manage acceleration float nominal_speed_sqr, // The nominal speed for this block in (mm/sec)^2 entry_speed_sqr, // Entry speed at previous-current junction in (mm/sec)^2 @@ -188,12 +192,12 @@ class Planner { // May be auto-adjusted by a filament width sensor #endif - static uint32_t max_acceleration_mm_per_s2[XYZE_N], // (mm/s^2) M201 XYZE - max_acceleration_steps_per_s2[XYZE_N], // (steps/s^2) Derived from mm_per_s2 - min_segment_time_us; // (µs) M205 B - static float max_feedrate_mm_s[XYZE_N], // (mm/s) M203 XYZE - Max speeds - axis_steps_per_mm[XYZE_N], // (steps) M92 XYZE - Steps per millimeter - steps_to_mm[XYZE_N], // (mm) Millimeters per step + static uint32_t max_acceleration_mm_per_s2[NUM_AXIS_N], // (mm/s^2) M201 XYZE + max_acceleration_steps_per_s2[NUM_AXIS_N], // (steps/s^2) Derived from mm_per_s2 + min_segment_time_us; // (µs) M205 Q + static float max_feedrate_mm_s[NUM_AXIS_N], // (mm/s) M203 XYZE - Max speeds + axis_steps_per_mm[NUM_AXIS_N], // (steps) M92 XYZE - Steps per millimeter + steps_to_mm[NUM_AXIS_N], // (mm) Millimeters per step min_feedrate_mm_s, // (mm/s) M205 S - Minimum linear feedrate acceleration, // (mm/s^2) M204 S - Normal acceleration. DEFAULT ACCELERATION for all printing moves. retract_acceleration, // (mm/s^2) M204 R - Retract acceleration. Filament pull-back and push-forward while standing still in the other axes @@ -210,7 +214,19 @@ class Planner { #endif #endif #else - static float max_jerk[XYZE]; // (mm/s^2) M205 XYZE - The largest speed change requiring no acceleration. + static float max_jerk[NUM_AXIS]; // (mm/s^2) M205 XYZE - The largest speed change requiring no acceleration. + #endif + + #if ENABLED(LINE_BUILDUP_COMPENSATION_FEATURE) + /* + * Parameters for calculating target[] + * See buildup compensation theory: + * https://vitana.se/opr3d/tbear/2017.html#hangprinter_project_29 + */ + static float k0[MOV_AXIS], + k1[MOV_AXIS], + k2[MOV_AXIS], + sqrtk1[MOV_AXIS]; #endif #if HAS_LEVELING @@ -230,7 +246,7 @@ class Planner { #endif #if HAS_POSITION_FLOAT - static float position_float[XYZE]; + static float position_float[NUM_AXIS]; #endif #if ENABLED(SKEW_CORRECTION) @@ -429,11 +445,17 @@ class Planner { #define ARG_X float rx #define ARG_Y float ry #define ARG_Z float rz + #if ENABLED(HANGPRINTER) + #define ARG_E1 float re1 + #endif static void unapply_leveling(float raw[XYZ]); #else #define ARG_X const float &rx #define ARG_Y const float &ry #define ARG_Z const float &rz + #if ENABLED(HANGPRINTER) + #define ARG_E1 const float &re1 + #endif #endif // Number of moves currently in the planner including the busy block, if any @@ -477,14 +499,18 @@ class Planner { * fr_mm_s - (target) speed of the move * extruder - target extruder * millimeters - the length of the movement, if known + * count_it - apply this move to the counters (UNREGISTERED_MOVE_SUPPORT) * * Returns true if movement was buffered, false otherwise */ - static bool _buffer_steps(const int32_t (&target)[XYZE] + static bool _buffer_steps(const int32_t (&target)[NUM_AXIS] #if HAS_POSITION_FLOAT - , const float (&target_float)[XYZE] + , const float (&target_float)[NUM_AXIS] #endif , float fr_mm_s, const uint8_t extruder, const float &millimeters=0.0 + #if ENABLED(UNREGISTERED_MOVE_SUPPORT) + , const bool count_it=true + #endif ); /** @@ -496,15 +522,19 @@ class Planner { * fr_mm_s - (target) speed of the move * extruder - target extruder * millimeters - the length of the movement, if known + * count_it - apply this move to the counters (UNREGISTERED_MOVE_SUPPORT) * * Returns true is movement is acceptable, false otherwise */ static bool _populate_block(block_t * const block, bool split_move, - const int32_t (&target)[XYZE] + const int32_t (&target)[NUM_AXIS] #if HAS_POSITION_FLOAT - , const float (&target_float)[XYZE] + , const float (&target_float)[NUM_AXIS] #endif , float fr_mm_s, const uint8_t extruder, const float &millimeters=0.0 + #if ENABLED(UNREGISTERED_MOVE_SUPPORT) + , const bool count_it=true + #endif ); /** @@ -521,13 +551,28 @@ class Planner { * Leveling and kinematics should be applied ahead of calling this. * * a,b,c,e - target positions in mm and/or degrees + * (a, b, c, d, e for Hangprinter) * fr_mm_s - (target) speed of the move * extruder - target extruder * millimeters - the length of the movement, if known + * count_it - remember this move in its counters (UNREGISTERED_MOVE_SUPPORT) */ - static bool buffer_segment(const float &a, const float &b, const float &c, const float &e, const float &fr_mm_s, const uint8_t extruder, const float &millimeters=0.0); + static bool buffer_segment(const float &a, const float &b, const float &c, + #if ENABLED(HANGPRINTER) + const float &d, + #endif + const float &e, const float &fr_mm_s, const uint8_t extruder, const float &millimeters=0.0 + #if ENABLED(UNREGISTERED_MOVE_SUPPORT) + , bool count_it=true + #endif + ); - static void _set_position_mm(const float &a, const float &b, const float &c, const float &e); + static void _set_position_mm(const float &a, const float &b, const float &c, + #if ENABLED(HANGPRINTER) + const float &d, + #endif + const float &e + ); /** * Add a new linear movement to the buffer. @@ -538,15 +583,26 @@ class Planner { * (Cartesians may also call buffer_line_kinematic.) * * rx,ry,rz,e - target position in mm or degrees + * (rx, ry, rz, re1 for Hangprinter) * fr_mm_s - (target) speed of the move (mm/s) * extruder - target extruder * millimeters - the length of the movement, if known */ - FORCE_INLINE static bool buffer_line(ARG_X, ARG_Y, ARG_Z, const float &e, const float &fr_mm_s, const uint8_t extruder, const float millimeters = 0.0) { + FORCE_INLINE static bool buffer_line(ARG_X, ARG_Y, ARG_Z, + #if ENABLED(HANGPRINTER) + ARG_E1, + #endif + const float &e, const float &fr_mm_s, const uint8_t extruder, const float millimeters = 0.0 + ) { #if PLANNER_LEVELING && IS_CARTESIAN apply_leveling(rx, ry, rz); #endif - return buffer_segment(rx, ry, rz, e, fr_mm_s, extruder, millimeters); + return buffer_segment(rx, ry, rz, + #if ENABLED(HANGPRINTER) + re1, + #endif + e, fr_mm_s, extruder, millimeters + ); } /** @@ -568,9 +624,16 @@ class Planner { #endif #if IS_KINEMATIC inverse_kinematics(raw); - return buffer_segment(delta[A_AXIS], delta[B_AXIS], delta[C_AXIS], cart[E_AXIS], fr_mm_s, extruder, millimeters); + return buffer_segment( + #if ENABLED(HANGPRINTER) + line_lengths[A_AXIS], line_lengths[B_AXIS], line_lengths[C_AXIS], line_lengths[D_AXIS] + #else + delta[A_AXIS], delta[B_AXIS], delta[C_AXIS] + #endif + , cart[E_CART], fr_mm_s, extruder, millimeters + ); #else - return buffer_segment(raw[X_AXIS], raw[Y_AXIS], raw[Z_AXIS], cart[E_AXIS], fr_mm_s, extruder, millimeters); + return buffer_segment(raw[X_AXIS], raw[Y_AXIS], raw[Z_AXIS], cart[E_CART], fr_mm_s, extruder, millimeters); #endif } @@ -583,11 +646,21 @@ class Planner { * * Clears previous speed values. */ - FORCE_INLINE static void set_position_mm(ARG_X, ARG_Y, ARG_Z, const float &e) { + FORCE_INLINE static void set_position_mm(ARG_X, ARG_Y, ARG_Z, + #if ENABLED(HANGPRINTER) + ARG_E1, + #endif + const float &e + ) { #if PLANNER_LEVELING && IS_CARTESIAN apply_leveling(rx, ry, rz); #endif - _set_position_mm(rx, ry, rz, e); + _set_position_mm(rx, ry, rz, + #if ENABLED(HANGPRINTER) + re1, + #endif + e + ); } static void set_position_mm_kinematic(const float (&cart)[XYZE]); static void set_position_mm(const AxisEnum axis, const float &v); diff --git a/Marlin/planner_bezier.cpp b/Marlin/planner_bezier.cpp index fdb4bab86b..6edc02b56c 100644 --- a/Marlin/planner_bezier.cpp +++ b/Marlin/planner_bezier.cpp @@ -105,17 +105,17 @@ inline static float dist1(float x1, float y1, float x2, float y2) { return ABS(x * the mitigation offered by MIN_STEP and the small computational * power available on Arduino, I think it is not wise to implement it. */ -void cubic_b_spline(const float position[NUM_AXIS], const float target[NUM_AXIS], const float offset[4], float fr_mm_s, uint8_t extruder) { +void cubic_b_spline(const float pos[XYZE], const float cart_target[XYZE], const float offset[4], float fr_mm_s, uint8_t extruder) { // Absolute first and second control points are recovered. - const float first0 = position[X_AXIS] + offset[0], - first1 = position[Y_AXIS] + offset[1], - second0 = target[X_AXIS] + offset[2], - second1 = target[Y_AXIS] + offset[3]; + const float first0 = pos[X_AXIS] + offset[0], + first1 = pos[Y_AXIS] + offset[1], + second0 = cart_target[X_AXIS] + offset[2], + second1 = cart_target[Y_AXIS] + offset[3]; float t = 0; - float bez_target[4]; - bez_target[X_AXIS] = position[X_AXIS]; - bez_target[Y_AXIS] = position[Y_AXIS]; + float bez_target[XYZE]; + bez_target[X_AXIS] = pos[X_AXIS]; + bez_target[Y_AXIS] = pos[Y_AXIS]; float step = MAX_STEP; millis_t next_idle_ms = millis() + 200UL; @@ -134,13 +134,13 @@ void cubic_b_spline(const float position[NUM_AXIS], const float target[NUM_AXIS] bool did_reduce = false; float new_t = t + step; NOMORE(new_t, 1); - float new_pos0 = eval_bezier(position[X_AXIS], first0, second0, target[X_AXIS], new_t), - new_pos1 = eval_bezier(position[Y_AXIS], first1, second1, target[Y_AXIS], new_t); + float new_pos0 = eval_bezier(pos[X_AXIS], first0, second0, cart_target[X_AXIS], new_t), + new_pos1 = eval_bezier(pos[Y_AXIS], first1, second1, cart_target[Y_AXIS], new_t); for (;;) { if (new_t - t < (MIN_STEP)) break; const float candidate_t = 0.5f * (t + new_t), - candidate_pos0 = eval_bezier(position[X_AXIS], first0, second0, target[X_AXIS], candidate_t), - candidate_pos1 = eval_bezier(position[Y_AXIS], first1, second1, target[Y_AXIS], candidate_t), + candidate_pos0 = eval_bezier(pos[X_AXIS], first0, second0, cart_target[X_AXIS], candidate_t), + candidate_pos1 = eval_bezier(pos[Y_AXIS], first1, second1, cart_target[Y_AXIS], candidate_t), interp_pos0 = 0.5f * (bez_target[X_AXIS] + new_pos0), interp_pos1 = 0.5f * (bez_target[Y_AXIS] + new_pos1); if (dist1(candidate_pos0, candidate_pos1, interp_pos0, interp_pos1) <= (SIGMA)) break; @@ -155,8 +155,8 @@ void cubic_b_spline(const float position[NUM_AXIS], const float target[NUM_AXIS] if (new_t - t > MAX_STEP) break; const float candidate_t = t + 2 * (new_t - t); if (candidate_t >= 1) break; - const float candidate_pos0 = eval_bezier(position[X_AXIS], first0, second0, target[X_AXIS], candidate_t), - candidate_pos1 = eval_bezier(position[Y_AXIS], first1, second1, target[Y_AXIS], candidate_t), + const float candidate_pos0 = eval_bezier(pos[X_AXIS], first0, second0, cart_target[X_AXIS], candidate_t), + candidate_pos1 = eval_bezier(pos[Y_AXIS], first1, second1, cart_target[Y_AXIS], candidate_t), interp_pos0 = 0.5f * (bez_target[X_AXIS] + candidate_pos0), interp_pos1 = 0.5f * (bez_target[Y_AXIS] + candidate_pos1); if (dist1(new_pos0, new_pos1, interp_pos0, interp_pos1) > (SIGMA)) break; @@ -184,14 +184,14 @@ void cubic_b_spline(const float position[NUM_AXIS], const float target[NUM_AXIS] bez_target[Y_AXIS] = new_pos1; // FIXME. The following two are wrong, since the parameter t is // not linear in the distance. - bez_target[Z_AXIS] = interp(position[Z_AXIS], target[Z_AXIS], t); - bez_target[E_AXIS] = interp(position[E_AXIS], target[E_AXIS], t); + bez_target[Z_AXIS] = interp(pos[Z_AXIS], cart_target[Z_AXIS], t); + bez_target[E_CART] = interp(pos[E_CART], cart_target[E_CART], t); clamp_to_software_endstops(bez_target); #if HAS_UBL_AND_CURVES - float pos[XYZ] = { bez_target[X_AXIS], bez_target[Y_AXIS], bez_target[Z_AXIS] }; - planner.apply_leveling(pos); - if (!planner.buffer_segment(pos[X_AXIS], pos[Y_AXIS], pos[Z_AXIS], bez_target[E_AXIS], fr_mm_s, active_extruder)) + float bez_copy[XYZ] = { bez_target[X_AXIS], bez_target[Y_AXIS], bez_target[Z_AXIS] }; + planner.apply_leveling(bez_copy); + if (!planner.buffer_segment(bez_copy[X_AXIS], bez_copy[Y_AXIS], bez_copy[Z_AXIS], bez_target[E_CART], fr_mm_s, active_extruder)) break; #else if (!planner.buffer_line_kinematic(bez_target, fr_mm_s, extruder)) diff --git a/Marlin/power.cpp b/Marlin/power.cpp index df0579153a..2f4708b075 100644 --- a/Marlin/power.cpp +++ b/Marlin/power.cpp @@ -49,27 +49,39 @@ bool Power::is_power_needed() { if (controllerFanSpeed > 0) return true; #endif + // If any of the drivers or the bed are enabled... if (X_ENABLE_READ == X_ENABLE_ON || Y_ENABLE_READ == Y_ENABLE_ON || Z_ENABLE_READ == Z_ENABLE_ON - #if HAS_HEATED_BED - || thermalManager.soft_pwm_amount_bed > 0 + #if HAS_HEATED_BED + || thermalManager.soft_pwm_amount_bed > 0 + #endif + #if HAS_X2_ENABLE + || X2_ENABLE_READ == X_ENABLE_ON #endif - || E0_ENABLE_READ == E_ENABLE_ON // If any of the drivers are enabled... + #if HAS_Y2_ENABLE + || Y2_ENABLE_READ == Y_ENABLE_ON + #endif + #if HAS_Z2_ENABLE + || Z2_ENABLE_READ == Z_ENABLE_ON + #endif + || E0_ENABLE_READ == E_ENABLE_ON #if E_STEPPERS > 1 || E1_ENABLE_READ == E_ENABLE_ON - #if HAS_X2_ENABLE - || X2_ENABLE_READ == X_ENABLE_ON - #endif #if E_STEPPERS > 2 || E2_ENABLE_READ == E_ENABLE_ON #if E_STEPPERS > 3 || E3_ENABLE_READ == E_ENABLE_ON + #if E_STEPPERS > 4 + || E4_ENABLE_READ == E_ENABLE_ON + #endif #endif #endif #endif ) return true; HOTEND_LOOP() if (thermalManager.degTargetHotend(e) > 0) return true; - if (thermalManager.degTargetBed() > 0) return true; + #if HAS_HEATED_BED + if (thermalManager.degTargetBed() > 0) return true; + #endif return false; } diff --git a/Marlin/power_loss_recovery.cpp b/Marlin/power_loss_recovery.cpp index 8534fd8fe0..fef41f3a49 100644 --- a/Marlin/power_loss_recovery.cpp +++ b/Marlin/power_loss_recovery.cpp @@ -159,7 +159,7 @@ void check_print_job_recovery() { #endif dtostrf(job_recovery_info.current_position[Z_AXIS] + 2, 1, 3, str_1); - dtostrf(job_recovery_info.current_position[E_AXIS] + dtostrf(job_recovery_info.current_position[E_CART] #if ENABLED(SAVE_EACH_CMD_MODE) - 5 #endif @@ -201,12 +201,19 @@ void save_job_recovery_info() { millis_t ms = millis(); #endif if ( - #if SAVE_INFO_INTERVAL_MS > 0 - ELAPSED(ms, next_save_ms) || - #endif + // Save on every command #if ENABLED(SAVE_EACH_CMD_MODE) true #else + // Save if power loss pin is triggered + #if PIN_EXISTS(POWER_LOSS) + READ(POWER_LOSS_PIN) == POWER_LOSS_STATE || + #endif + // Save if interval is elapsed + #if SAVE_INFO_INTERVAL_MS > 0 + ELAPSED(ms, next_save_ms) || + #endif + // Save on every new Z height (current_position[Z_AXIS] > 0 && current_position[Z_AXIS] > job_recovery_info.current_position[Z_AXIS]) #endif ) { @@ -266,6 +273,11 @@ void save_job_recovery_info() { card.openJobRecoveryFile(false); (void)card.saveJobRecoveryInfo(); + + // If power-loss pin was triggered, write just once then kill + #if PIN_EXISTS(POWER_LOSS) + if (READ(POWER_LOSS_PIN) == POWER_LOSS_STATE) kill(MSG_POWER_LOSS_RECOVERY); + #endif } } diff --git a/Marlin/status_screen_DOGM.h b/Marlin/status_screen_DOGM.h index 038351cc81..98678807be 100644 --- a/Marlin/status_screen_DOGM.h +++ b/Marlin/status_screen_DOGM.h @@ -126,7 +126,7 @@ inline void lcd_implementation_status_message(const bool blink) { static bool last_blink = false; // Get the UTF8 character count of the string - uint8_t slen = lcd_strlen(lcd_status_message); + uint8_t slen = utf8_strlen(lcd_status_message); // If the string fits into the LCD, just print it and do not scroll it if (slen <= LCD_WIDTH) { @@ -147,7 +147,7 @@ inline void lcd_implementation_status_message(const bool blink) { const char *stat = lcd_status_message + status_scroll_offset; // Get the string remaining length - const uint8_t rlen = lcd_strlen(stat); + const uint8_t rlen = utf8_strlen(stat); // If we have enough characters to display if (rlen >= LCD_WIDTH) { @@ -183,7 +183,7 @@ inline void lcd_implementation_status_message(const bool blink) { UNUSED(blink); // Get the UTF8 character count of the string - uint8_t slen = lcd_strlen(lcd_status_message); + uint8_t slen = utf8_strlen(lcd_status_message); // Just print the string to the LCD lcd_print_utf(lcd_status_message, LCD_WIDTH); diff --git a/Marlin/status_screen_lite_ST7920.h b/Marlin/status_screen_lite_ST7920.h index 2acb6a9736..8bf1b4176c 100644 --- a/Marlin/status_screen_lite_ST7920.h +++ b/Marlin/status_screen_lite_ST7920.h @@ -395,7 +395,7 @@ void ST7920_Lite_Status_Screen::draw_degree_symbol(uint8_t x, uint8_t y, bool dr const uint8_t x_word = x >> 1; const uint8_t y_top = degree_symbol_y_top; const uint8_t y_bot = y_top + sizeof(degree_symbol)/sizeof(degree_symbol[0]); - for(uint8_t i = y_top; i < y_bot; i++) { + for (uint8_t i = y_top; i < y_bot; i++) { uint8_t byte = pgm_read_byte_near(p_bytes++); set_gdram_address(x_word,i+y*16); begin_data(); @@ -618,7 +618,7 @@ void ST7920_Lite_Status_Screen::draw_status_message(const char *str) { const uint8_t lcd_len = 16; #if ENABLED(STATUS_MESSAGE_SCROLLING) - uint8_t slen = lcd_strlen(str); + uint8_t slen = utf8_strlen(str); // If the string fits into the LCD, just print it and do not scroll it if (slen <= lcd_len) { @@ -639,7 +639,7 @@ void ST7920_Lite_Status_Screen::draw_status_message(const char *str) { const char *stat = str + status_scroll_offset; // Get the string remaining length - const uint8_t rlen = lcd_strlen(stat); + const uint8_t rlen = utf8_strlen(stat); // If we have enough characters to display if (rlen >= lcd_len) { @@ -670,7 +670,7 @@ void ST7920_Lite_Status_Screen::draw_status_message(const char *str) { } #else // Get the UTF8 character count of the string - uint8_t slen = lcd_strlen(str); + uint8_t slen = utf8_strlen(str); // Just print the string to the LCD write_str(str, lcd_len); @@ -876,24 +876,32 @@ void ST7920_Lite_Status_Screen::update_status_or_position(bool forceUpdate) { } void ST7920_Lite_Status_Screen::update_progress(const bool forceUpdate) { - #if DISABLED(LCD_SET_PROGRESS_MANUALLY) - uint8_t progress_bar_percent; - #endif + #if ENABLED(LCD_SET_PROGRESS_MANUALLY) || ENABLED(SDSUPPORT) - // Set current percentage from SD when actively printing - #if ENABLED(SDSUPPORT) - if (IS_SD_PRINTING) progress_bar_percent = card.percentDone(); - #endif + #if DISABLED(LCD_SET_PROGRESS_MANUALLY) + uint8_t progress_bar_percent; //=0 + #endif - // Since the progress bar involves writing - // quite a few bytes to GDRAM, only do this - // when an update is actually necessary. + #if ENABLED(SDSUPPORT) + // Progress bar % comes from SD when actively printing + if (IS_SD_PRINTING) progress_bar_percent = card.percentDone(); + #endif - static uint8_t last_progress = 0; - if (!forceUpdate && last_progress == progress_bar_percent) return; - last_progress = progress_bar_percent; + // Since the progress bar involves writing + // quite a few bytes to GDRAM, only do this + // when an update is actually necessary. - draw_progress_bar(progress_bar_percent); + static uint8_t last_progress = 0; + if (!forceUpdate && last_progress == progress_bar_percent) return; + last_progress = progress_bar_percent; + + draw_progress_bar(progress_bar_percent); + + #else + + UNUSED(forceUpdate); + + #endif // LCD_SET_PROGRESS_MANUALLY || SDSUPPORT } void ST7920_Lite_Status_Screen::update(const bool forceUpdate) { diff --git a/Marlin/stepper.cpp b/Marlin/stepper.cpp index 8c965c45da..dd70c8b0dc 100644 --- a/Marlin/stepper.cpp +++ b/Marlin/stepper.cpp @@ -135,9 +135,8 @@ uint8_t Stepper::steps_per_isr; #endif uint8_t Stepper::oversampling_factor; -int32_t Stepper::delta_error[XYZE] = { 0 }; - -uint32_t Stepper::advance_dividend[XYZE] = { 0 }, +int32_t Stepper::delta_error[NUM_AXIS] = { 0 }; +uint32_t Stepper::advance_dividend[NUM_AXIS] = { 0 }, Stepper::advance_divisor = 0, Stepper::step_events_completed = 0, // The number of step events executed in the current block Stepper::accelerate_until, // The point from where we need to stop acceleration @@ -180,14 +179,19 @@ uint32_t Stepper::nextMainISR = 0; #endif // LIN_ADVANCE int32_t Stepper::ticks_nominal = -1; + #if DISABLED(S_CURVE_ACCELERATION) uint32_t Stepper::acc_step_rate; // needed for deceleration start point #endif -volatile int32_t Stepper::endstops_trigsteps[XYZ]; - -volatile int32_t Stepper::count_position[NUM_AXIS] = { 0 }; -int8_t Stepper::count_direction[NUM_AXIS] = { 0, 0, 0, 0 }; +volatile int32_t Stepper::endstops_trigsteps[XYZ], + Stepper::count_position[NUM_AXIS] = { 0 }; +int8_t Stepper::count_direction[NUM_AXIS] = { + 1, 1, 1, 1 + #if ENABLED(HANGPRINTER) + , 1 + #endif +}; #if ENABLED(X_DUAL_ENDSTOPS) || ENABLED(Y_DUAL_ENDSTOPS) || ENABLED(Z_DUAL_ENDSTOPS) #define DUAL_ENDSTOP_APPLY_STEP(A,V) \ @@ -260,6 +264,28 @@ int8_t Stepper::count_direction[NUM_AXIS] = { 0, 0, 0, 0 }; #define Z_APPLY_STEP(v,Q) Z_STEP_WRITE(v) #endif +/** + * Hangprinter's mapping {A,B,C,D} <-> {X,Y,Z,E1} happens here. + * If you have two extruders: {A,B,C,D} <-> {X,Y,Z,E2} + * ... etc up to max 4 extruders. + * Place D connector on your first "free" extruder output. + */ +#if ENABLED(HANGPRINTER) + #define A_APPLY_DIR(v,Q) X_APPLY_DIR(v,Q) + #define A_APPLY_STEP(v,Q) X_APPLY_STEP(v,Q) + + #define B_APPLY_DIR(v,Q) Y_APPLY_DIR(v,Q) + #define B_APPLY_STEP(v,Q) Y_APPLY_STEP(v,Q) + + #define C_APPLY_DIR(v,Q) Z_APPLY_DIR(v,Q) + #define C_APPLY_STEP(v,Q) Z_APPLY_STEP(v,Q) + + #define __D_APPLY(I,T,v) E##I##_##T##_WRITE(v) + #define _D_APPLY(I,T,v) __D_APPLY(I,T,v) + #define D_APPLY_DIR(v,Q) _D_APPLY(EXTRUDERS, DIR, v) + #define D_APPLY_STEP(v,Q) _D_APPLY(EXTRUDERS, STEP, v) +#endif + #if DISABLED(MIXING_EXTRUDER) #define E_APPLY_STEP(v,Q) E_STEP_WRITE(active_extruder, v) #endif @@ -357,6 +383,9 @@ void Stepper::set_directions() { #if HAS_Z_DIR SET_STEP_DIR(Z); // C #endif + #if ENABLED(HANGPRINTER) + SET_STEP_DIR(D); + #endif #if DISABLED(LIN_ADVANCE) #if ENABLED(MIXING_EXTRUDER) @@ -1251,6 +1280,12 @@ void Stepper::isr() { * call to this method that might cause variation in the timing. The aim * is to keep pulse timing as regular as possible. */ +#if ENABLED(UNREGISTERED_MOVE_SUPPORT) + #define COUNT_IT current_block->count_it +#else + #define COUNT_IT true +#endif + void Stepper::stepper_pulse_phase_isr() { // If we must abort the current block, do so! @@ -1289,7 +1324,7 @@ void Stepper::stepper_pulse_phase_isr() { delta_error[_AXIS(AXIS)] += advance_dividend[_AXIS(AXIS)]; \ if (delta_error[_AXIS(AXIS)] >= 0) { \ _APPLY_STEP(AXIS)(!_INVERT_STEP_PIN(AXIS), 0); \ - count_position[_AXIS(AXIS)] += count_direction[_AXIS(AXIS)]; \ + if (COUNT_IT) count_position[_AXIS(AXIS)] += count_direction[_AXIS(AXIS)]; \ } \ }while(0) @@ -1302,22 +1337,37 @@ void Stepper::stepper_pulse_phase_isr() { }while(0) // Pulse start - #if HAS_X_STEP - PULSE_START(X); - #endif - #if HAS_Y_STEP - PULSE_START(Y); - #endif - #if HAS_Z_STEP - PULSE_START(Z); - #endif + #if ENABLED(HANGPRINTER) + #if HAS_A_STEP + PULSE_START(A); + #endif + #if HAS_B_STEP + PULSE_START(B); + #endif + #if HAS_C_STEP + PULSE_START(C); + #endif + #if HAS_D_STEP + PULSE_START(D); + #endif + #else + #if HAS_X_STEP + PULSE_START(X); + #endif + #if HAS_Y_STEP + PULSE_START(Y); + #endif + #if HAS_Z_STEP + PULSE_START(Z); + #endif + #endif // HANGPRINTER // Pulse E/Mixing extruders #if ENABLED(LIN_ADVANCE) // Tick the E axis, correct error term and update position delta_error[E_AXIS] += advance_dividend[E_AXIS]; if (delta_error[E_AXIS] >= 0) { - count_position[E_AXIS] += count_direction[E_AXIS]; + if (COUNT_IT) count_position[E_AXIS] += count_direction[E_AXIS]; delta_error[E_AXIS] -= advance_divisor; // Don't step E here - But remember the number of steps to perform @@ -1329,7 +1379,7 @@ void Stepper::stepper_pulse_phase_isr() { // Tick the E axis delta_error[E_AXIS] += advance_dividend[E_AXIS]; if (delta_error[E_AXIS] >= 0) { - count_position[E_AXIS] += count_direction[E_AXIS]; + if (COUNT_IT) count_position[E_AXIS] += count_direction[E_AXIS]; delta_error[E_AXIS] -= advance_divisor; } @@ -1354,15 +1404,29 @@ void Stepper::stepper_pulse_phase_isr() { // Add the delay needed to ensure the maximum driver rate is enforced if (signed(added_step_ticks) > 0) pulse_end += hal_timer_t(added_step_ticks); - // Pulse stop - #if HAS_X_STEP - PULSE_STOP(X); - #endif - #if HAS_Y_STEP - PULSE_STOP(Y); - #endif - #if HAS_Z_STEP - PULSE_STOP(Z); + #if ENABLED(HANGPRINTER) + #if HAS_A_STEP + PULSE_STOP(A); + #endif + #if HAS_B_STEP + PULSE_STOP(B); + #endif + #if HAS_C_STEP + PULSE_STOP(C); + #endif + #if HAS_D_STEP + PULSE_STOP(D); + #endif + #else + #if HAS_X_STEP + PULSE_STOP(X); + #endif + #if HAS_Y_STEP + PULSE_STOP(Y); + #endif + #if HAS_Z_STEP + PULSE_STOP(Z); + #endif #endif #if DISABLED(LIN_ADVANCE) @@ -1437,16 +1501,10 @@ uint32_t Stepper::stepper_block_phase_isr() { #if ENABLED(LIN_ADVANCE) if (LA_use_advance_lead) { - // Wake up eISR on first acceleration loop and fire ISR if final adv_rate is reached - if (step_events_completed == steps_per_isr || (LA_steps && LA_isr_rate != current_block->advance_speed)) { - nextAdvanceISR = 0; - LA_isr_rate = current_block->advance_speed; - } - } - else { - LA_isr_rate = LA_ADV_NEVER; - if (LA_steps) nextAdvanceISR = 0; + // Fire ISR if final adv_rate is reached + if (LA_steps && LA_isr_rate != current_block->advance_speed) nextAdvanceISR = 0; } + else if (LA_steps) nextAdvanceISR = 0; #endif // LIN_ADVANCE } // Are we in Deceleration phase ? @@ -1488,17 +1546,13 @@ uint32_t Stepper::stepper_block_phase_isr() { #if ENABLED(LIN_ADVANCE) if (LA_use_advance_lead) { - if (step_events_completed <= decelerate_after + steps_per_isr || - (LA_steps && LA_isr_rate != current_block->advance_speed) - ) { - nextAdvanceISR = 0; // Wake up eISR on first deceleration loop + // Wake up eISR on first deceleration loop and fire ISR if final adv_rate is reached + if (step_events_completed <= decelerate_after + steps_per_isr || (LA_steps && LA_isr_rate != current_block->advance_speed)) { + nextAdvanceISR = 0; LA_isr_rate = current_block->advance_speed; } } - else { - LA_isr_rate = LA_ADV_NEVER; - if (LA_steps) nextAdvanceISR = 0; - } + else if (LA_steps) nextAdvanceISR = 0; #endif // LIN_ADVANCE } // We must be in cruise phase otherwise @@ -1531,8 +1585,11 @@ uint32_t Stepper::stepper_block_phase_isr() { // Sync block? Sync the stepper counts and return while (TEST(current_block->flag, BLOCK_BIT_SYNC_POSITION)) { _set_position( - current_block->position[A_AXIS], current_block->position[B_AXIS], - current_block->position[C_AXIS], current_block->position[E_AXIS] + current_block->position[A_AXIS], current_block->position[B_AXIS], current_block->position[C_AXIS], + #if ENABLED(HANGPRINTER) + current_block->position[D_AXIS], + #endif + current_block->position[E_AXIS] ); planner.discard_current_block(); @@ -1678,7 +1735,11 @@ uint32_t Stepper::stepper_block_phase_isr() { if ((LA_use_advance_lead = current_block->use_advance_lead)) { LA_final_adv_steps = current_block->final_adv_steps; LA_max_adv_steps = current_block->max_adv_steps; + //Start the ISR + nextAdvanceISR = 0; + LA_isr_rate = current_block->advance_speed; } + else LA_isr_rate = LA_ADV_NEVER; #endif if (current_block->direction_bits != last_direction_bits @@ -2015,7 +2076,12 @@ void Stepper::init() { * This allows get_axis_position_mm to correctly * derive the current XYZ position later on. */ -void Stepper::_set_position(const int32_t &a, const int32_t &b, const int32_t &c, const int32_t &e) { +void Stepper::_set_position(const int32_t &a, const int32_t &b, const int32_t &c, + #if ENABLED(HANGPRINTER) + const int32_t &d, + #endif + const int32_t &e +) { #if CORE_IS_XY // corexy positioning // these equations follow the form of the dA and dB equations on http://www.corexy.com/theory.html @@ -2037,6 +2103,9 @@ void Stepper::_set_position(const int32_t &a, const int32_t &b, const int32_t &c count_position[X_AXIS] = a; count_position[Y_AXIS] = b; count_position[Z_AXIS] = c; + #if ENABLED(HANGPRINTER) + count_position[D_AXIS] = d; + #endif #endif count_position[E_AXIS] = e; } @@ -2103,31 +2172,38 @@ void Stepper::report_positions() { const int32_t xpos = count_position[X_AXIS], ypos = count_position[Y_AXIS], + #if ENABLED(HANGPRINTER) + dpos = count_position[D_AXIS], + #endif zpos = count_position[Z_AXIS]; if (was_enabled) ENABLE_STEPPER_DRIVER_INTERRUPT(); - #if CORE_IS_XY || CORE_IS_XZ || IS_DELTA || IS_SCARA + #if CORE_IS_XY || CORE_IS_XZ || IS_DELTA || IS_SCARA || ENABLED(HANGPRINTER) SERIAL_PROTOCOLPGM(MSG_COUNT_A); #else SERIAL_PROTOCOLPGM(MSG_COUNT_X); #endif SERIAL_PROTOCOL(xpos); - #if CORE_IS_XY || CORE_IS_YZ || IS_DELTA || IS_SCARA + #if CORE_IS_XY || CORE_IS_YZ || IS_DELTA || IS_SCARA || ENABLED(HANGPRINTER) SERIAL_PROTOCOLPGM(" B:"); #else SERIAL_PROTOCOLPGM(" Y:"); #endif SERIAL_PROTOCOL(ypos); - #if CORE_IS_XZ || CORE_IS_YZ || IS_DELTA + #if CORE_IS_XZ || CORE_IS_YZ || IS_DELTA || ENABLED(HANGPRINTER) SERIAL_PROTOCOLPGM(" C:"); #else SERIAL_PROTOCOLPGM(" Z:"); #endif SERIAL_PROTOCOL(zpos); + #if ENABLED(HANGPRINTER) + SERIAL_PROTOCOLPAIR(" D:", dpos); + #endif + SERIAL_EOL(); } @@ -2171,7 +2247,7 @@ void Stepper::report_positions() { const uint8_t old_dir = _READ_DIR(AXIS); \ _ENABLE(AXIS); \ _APPLY_DIR(AXIS, _INVERT_DIR(AXIS)^DIR^INVERT); \ - DELAY_NS(400); /* DRV8825 */ \ + DELAY_NS(MINIMUM_STEPPER_DIR_DELAY); \ _SAVE_START; \ _APPLY_STEP(AXIS)(!_INVERT_STEP_PIN(AXIS), true); \ _PULSE_WAIT; \ @@ -2243,7 +2319,9 @@ void Stepper::report_positions() { Y_DIR_WRITE(INVERT_Y_DIR ^ z_direction); Z_DIR_WRITE(INVERT_Z_DIR ^ z_direction); - DELAY_NS(400); // DRV8825 + #if MINIMUM_STEPPER_DIR_DELAY > 0 + DELAY_NS(MINIMUM_STEPPER_DIR_DELAY); + #endif _SAVE_START; diff --git a/Marlin/stepper.h b/Marlin/stepper.h index 2ac9c7756a..786a376e9e 100644 --- a/Marlin/stepper.h +++ b/Marlin/stepper.h @@ -270,8 +270,8 @@ class Stepper { #endif // Delta error variables for the Bresenham line tracer - static int32_t delta_error[XYZE]; - static uint32_t advance_dividend[XYZE], + static int32_t delta_error[NUM_AXIS]; + static uint32_t advance_dividend[NUM_AXIS], advance_divisor, step_events_completed, // The number of step events executed in the current block accelerate_until, // The point from where we need to stop acceleration @@ -425,11 +425,21 @@ class Stepper { #endif // Set the current position in steps - inline static void set_position(const int32_t &a, const int32_t &b, const int32_t &c, const int32_t &e) { + inline static void set_position(const int32_t &a, const int32_t &b, const int32_t &c + #if ENABLED(HANGPRINTER) + , const int32_t &d + #endif + , const int32_t &e + ) { planner.synchronize(); const bool was_enabled = STEPPER_ISR_ENABLED(); if (was_enabled) DISABLE_STEPPER_DRIVER_INTERRUPT(); - _set_position(a, b, c, e); + _set_position(a, b, c + #if ENABLED(HANGPRINTER) + , d + #endif + , e + ); if (was_enabled) ENABLE_STEPPER_DRIVER_INTERRUPT(); } @@ -447,11 +457,19 @@ class Stepper { private: // Set the current position in steps - static void _set_position(const int32_t &a, const int32_t &b, const int32_t &c, const int32_t &e); + static void _set_position(const int32_t &a, const int32_t &b, const int32_t &c + #if ENABLED(HANGPRINTER) + , const int32_t &d + #endif + , const int32_t &e + ); // Set direction bits for all steppers static void set_directions(); + // Allow reset_stepper_drivers to access private set_directions + friend void reset_stepper_drivers(); + FORCE_INLINE static uint32_t calc_timer_interval(uint32_t step_rate, uint8_t scale, uint8_t* loops) { uint32_t timer; diff --git a/Marlin/stepper_indirection.cpp b/Marlin/stepper_indirection.cpp index 32ef99a710..cde4c31a23 100644 --- a/Marlin/stepper_indirection.cpp +++ b/Marlin/stepper_indirection.cpp @@ -35,46 +35,48 @@ #include "MarlinConfig.h" +#include "stepper.h" + // // TMC26X Driver objects and inits // -#if ENABLED(HAVE_TMC26X) +#if HAS_DRIVER(TMC26X) #include #include #define _TMC26X_DEFINE(ST) TMC26XStepper stepper##ST(200, ST##_CS_PIN, ST##_STEP_PIN, ST##_DIR_PIN, ST##_MAX_CURRENT, ST##_SENSE_RESISTOR) - #if ENABLED(X_IS_TMC26X) + #if AXIS_DRIVER_TYPE(X, TMC26X) _TMC26X_DEFINE(X); #endif - #if ENABLED(X2_IS_TMC26X) + #if AXIS_DRIVER_TYPE(X2, TMC26X) _TMC26X_DEFINE(X2); #endif - #if ENABLED(Y_IS_TMC26X) + #if AXIS_DRIVER_TYPE(Y, TMC26X) _TMC26X_DEFINE(Y); #endif - #if ENABLED(Y2_IS_TMC26X) + #if AXIS_DRIVER_TYPE(Y2, TMC26X) _TMC26X_DEFINE(Y2); #endif - #if ENABLED(Z_IS_TMC26X) + #if AXIS_DRIVER_TYPE(Z, TMC26X) _TMC26X_DEFINE(Z); #endif - #if ENABLED(Z2_IS_TMC26X) + #if AXIS_DRIVER_TYPE(Z2, TMC26X) _TMC26X_DEFINE(Z2); #endif - #if ENABLED(E0_IS_TMC26X) + #if AXIS_DRIVER_TYPE(E0, TMC26X) _TMC26X_DEFINE(E0); #endif - #if ENABLED(E1_IS_TMC26X) + #if AXIS_DRIVER_TYPE(E1, TMC26X) _TMC26X_DEFINE(E1); #endif - #if ENABLED(E2_IS_TMC26X) + #if AXIS_DRIVER_TYPE(E2, TMC26X) _TMC26X_DEFINE(E2); #endif - #if ENABLED(E3_IS_TMC26X) + #if AXIS_DRIVER_TYPE(E3, TMC26X) _TMC26X_DEFINE(E3); #endif - #if ENABLED(E4_IS_TMC26X) + #if AXIS_DRIVER_TYPE(E4, TMC26X) _TMC26X_DEFINE(E4); #endif @@ -84,46 +86,46 @@ }while(0) void tmc26x_init_to_defaults() { - #if ENABLED(X_IS_TMC26X) + #if AXIS_DRIVER_TYPE(X, TMC26X) _TMC26X_INIT(X); #endif - #if ENABLED(X2_IS_TMC26X) + #if AXIS_DRIVER_TYPE(X2, TMC26X) _TMC26X_INIT(X2); #endif - #if ENABLED(Y_IS_TMC26X) + #if AXIS_DRIVER_TYPE(Y, TMC26X) _TMC26X_INIT(Y); #endif - #if ENABLED(Y2_IS_TMC26X) + #if AXIS_DRIVER_TYPE(Y2, TMC26X) _TMC26X_INIT(Y2); #endif - #if ENABLED(Z_IS_TMC26X) + #if AXIS_DRIVER_TYPE(Z, TMC26X) _TMC26X_INIT(Z); #endif - #if ENABLED(Z2_IS_TMC26X) + #if AXIS_DRIVER_TYPE(Z2, TMC26X) _TMC26X_INIT(Z2); #endif - #if ENABLED(E0_IS_TMC26X) + #if AXIS_DRIVER_TYPE(E0, TMC26X) _TMC26X_INIT(E0); #endif - #if ENABLED(E1_IS_TMC26X) + #if AXIS_DRIVER_TYPE(E1, TMC26X) _TMC26X_INIT(E1); #endif - #if ENABLED(E2_IS_TMC26X) + #if AXIS_DRIVER_TYPE(E2, TMC26X) _TMC26X_INIT(E2); #endif - #if ENABLED(E3_IS_TMC26X) + #if AXIS_DRIVER_TYPE(E3, TMC26X) _TMC26X_INIT(E3); #endif - #if ENABLED(E4_IS_TMC26X) + #if AXIS_DRIVER_TYPE(E4, TMC26X) _TMC26X_INIT(E4); #endif } -#endif // HAVE_TMC26X +#endif // TMC26X // // TMC2130 Driver objects and inits // -#if ENABLED(HAVE_TMC2130) +#if HAS_DRIVER(TMC2130) #include #include @@ -141,37 +143,37 @@ #endif // Stepper objects of TMC2130 steppers used - #if ENABLED(X_IS_TMC2130) + #if AXIS_DRIVER_TYPE(X, TMC2130) _TMC2130_DEFINE(X); #endif - #if ENABLED(X2_IS_TMC2130) + #if AXIS_DRIVER_TYPE(X2, TMC2130) _TMC2130_DEFINE(X2); #endif - #if ENABLED(Y_IS_TMC2130) + #if AXIS_DRIVER_TYPE(Y, TMC2130) _TMC2130_DEFINE(Y); #endif - #if ENABLED(Y2_IS_TMC2130) + #if AXIS_DRIVER_TYPE(Y2, TMC2130) _TMC2130_DEFINE(Y2); #endif - #if ENABLED(Z_IS_TMC2130) + #if AXIS_DRIVER_TYPE(Z, TMC2130) _TMC2130_DEFINE(Z); #endif - #if ENABLED(Z2_IS_TMC2130) + #if AXIS_DRIVER_TYPE(Z2, TMC2130) _TMC2130_DEFINE(Z2); #endif - #if ENABLED(E0_IS_TMC2130) + #if AXIS_DRIVER_TYPE(E0, TMC2130) _TMC2130_DEFINE(E0); #endif - #if ENABLED(E1_IS_TMC2130) + #if AXIS_DRIVER_TYPE(E1, TMC2130) _TMC2130_DEFINE(E1); #endif - #if ENABLED(E2_IS_TMC2130) + #if AXIS_DRIVER_TYPE(E2, TMC2130) _TMC2130_DEFINE(E2); #endif - #if ENABLED(E3_IS_TMC2130) + #if AXIS_DRIVER_TYPE(E3, TMC2130) _TMC2130_DEFINE(E3); #endif - #if ENABLED(E4_IS_TMC2130) + #if AXIS_DRIVER_TYPE(E4, TMC2130) _TMC2130_DEFINE(E4); #endif @@ -208,75 +210,74 @@ #define _TMC2130_INIT(ST, SPMM) tmc2130_init(stepper##ST, ST##_CURRENT, ST##_MICROSTEPS, ST##_HYBRID_THRESHOLD, SPMM) void tmc2130_init_to_defaults() { - #if ENABLED(X_IS_TMC2130) + #if AXIS_DRIVER_TYPE(X, TMC2130) _TMC2130_INIT( X, planner.axis_steps_per_mm[X_AXIS]); #endif - #if ENABLED(X2_IS_TMC2130) + #if AXIS_DRIVER_TYPE(X2, TMC2130) _TMC2130_INIT(X2, planner.axis_steps_per_mm[X_AXIS]); #endif - #if ENABLED(Y_IS_TMC2130) + #if AXIS_DRIVER_TYPE(Y, TMC2130) _TMC2130_INIT( Y, planner.axis_steps_per_mm[Y_AXIS]); #endif - #if ENABLED(Y2_IS_TMC2130) + #if AXIS_DRIVER_TYPE(Y2, TMC2130) _TMC2130_INIT(Y2, planner.axis_steps_per_mm[Y_AXIS]); #endif - #if ENABLED(Z_IS_TMC2130) + #if AXIS_DRIVER_TYPE(Z, TMC2130) _TMC2130_INIT( Z, planner.axis_steps_per_mm[Z_AXIS]); #endif - #if ENABLED(Z2_IS_TMC2130) + #if AXIS_DRIVER_TYPE(Z2, TMC2130) _TMC2130_INIT(Z2, planner.axis_steps_per_mm[Z_AXIS]); #endif - #if ENABLED(E0_IS_TMC2130) + #if AXIS_DRIVER_TYPE(E0, TMC2130) _TMC2130_INIT(E0, planner.axis_steps_per_mm[E_AXIS]); #endif - #if ENABLED(E1_IS_TMC2130) + #if AXIS_DRIVER_TYPE(E1, TMC2130) { constexpr int extruder = 1; _TMC2130_INIT(E1, planner.axis_steps_per_mm[E_AXIS_N]); } #endif - #if ENABLED(E2_IS_TMC2130) + #if AXIS_DRIVER_TYPE(E2, TMC2130) { constexpr int extruder = 2; _TMC2130_INIT(E2, planner.axis_steps_per_mm[E_AXIS_N]); } #endif - #if ENABLED(E3_IS_TMC2130) + #if AXIS_DRIVER_TYPE(E3, TMC2130) { constexpr int extruder = 3; _TMC2130_INIT(E3, planner.axis_steps_per_mm[E_AXIS_N]); } #endif - #if ENABLED(E4_IS_TMC2130) + #if AXIS_DRIVER_TYPE(E4, TMC2130) { constexpr int extruder = 4; _TMC2130_INIT(E4, planner.axis_steps_per_mm[E_AXIS_N]); } #endif #if ENABLED(SENSORLESS_HOMING) #define TMC_INIT_SGT(P,Q) stepper##Q.sgt(P##_HOMING_SENSITIVITY); #if X_SENSORLESS - #if ENABLED(X_IS_TMC2130) || ENABLED(IS_TRAMS) + #if AXIS_DRIVER_TYPE(X, TMC2130) stepperX.sgt(X_HOMING_SENSITIVITY); #endif - #if ENABLED(X2_IS_TMC2130) + #if AXIS_DRIVER_TYPE(X2, TMC2130) stepperX2.sgt(X_HOMING_SENSITIVITY); #endif #endif #if Y_SENSORLESS - #if ENABLED(Y_IS_TMC2130) || ENABLED(IS_TRAMS) + #if AXIS_DRIVER_TYPE(Y, TMC2130) stepperY.sgt(Y_HOMING_SENSITIVITY); #endif - #if ENABLED(Y2_IS_TMC2130) + #if AXIS_DRIVER_TYPE(Y2, TMC2130) stepperY2.sgt(Y_HOMING_SENSITIVITY); #endif #endif #if Z_SENSORLESS - #if ENABLED(Z_IS_TMC2130) || ENABLED(IS_TRAMS) + #if AXIS_DRIVER_TYPE(Z, TMC2130) stepperZ.sgt(Z_HOMING_SENSITIVITY); #endif - #if ENABLED(Z2_IS_TMC2130) + #if AXIS_DRIVER_TYPE(Z2, TMC2130) stepperZ2.sgt(Z_HOMING_SENSITIVITY); #endif #endif #endif } - -#endif // HAVE_TMC2130 +#endif // TMC2130 // // TMC2208 Driver objects and inits // -#if ENABLED(HAVE_TMC2208) +#if HAS_DRIVER(TMC2208) #undef HardwareSerial_h // undo Marlin trickery #include @@ -289,81 +290,80 @@ #endif #define _TMC2208_DEFINE_HARDWARE(ST) TMC2208Stepper stepper##ST(&ST##_HARDWARE_SERIAL) - #define _TMC2208_DEFINE_SOFTWARE(ST) SoftwareSerial ST##_HARDWARE_SERIAL = SoftwareSerial(ST##_SERIAL_RX_PIN, ST##_SERIAL_TX_PIN); \ - TMC2208Stepper stepper##ST(&ST##_HARDWARE_SERIAL, ST##_SERIAL_RX_PIN > -1) + #define _TMC2208_DEFINE_SOFTWARE(ST) TMC2208Stepper stepper##ST(ST##_SERIAL_RX_PIN, ST##_SERIAL_TX_PIN, ST##_SERIAL_RX_PIN > -1) // Stepper objects of TMC2208 steppers used - #if ENABLED(X_IS_TMC2208) + #if AXIS_DRIVER_TYPE(X, TMC2208) #ifdef X_HARDWARE_SERIAL _TMC2208_DEFINE_HARDWARE(X); #else _TMC2208_DEFINE_SOFTWARE(X); #endif #endif - #if ENABLED(X2_IS_TMC2208) + #if AXIS_DRIVER_TYPE(X2, TMC2208) #ifdef X2_HARDWARE_SERIAL _TMC2208_DEFINE_HARDWARE(X2); #else _TMC2208_DEFINE_SOFTWARE(X2); #endif #endif - #if ENABLED(Y_IS_TMC2208) + #if AXIS_DRIVER_TYPE(Y, TMC2208) #ifdef Y_HARDWARE_SERIAL _TMC2208_DEFINE_HARDWARE(Y); #else _TMC2208_DEFINE_SOFTWARE(Y); #endif #endif - #if ENABLED(Y2_IS_TMC2208) + #if AXIS_DRIVER_TYPE(Y2, TMC2208) #ifdef Y2_HARDWARE_SERIAL _TMC2208_DEFINE_HARDWARE(Y2); #else _TMC2208_DEFINE_SOFTWARE(Y2); #endif #endif - #if ENABLED(Z_IS_TMC2208) + #if AXIS_DRIVER_TYPE(Z, TMC2208) #ifdef Z_HARDWARE_SERIAL _TMC2208_DEFINE_HARDWARE(Z); #else _TMC2208_DEFINE_SOFTWARE(Z); #endif #endif - #if ENABLED(Z2_IS_TMC2208) + #if AXIS_DRIVER_TYPE(Z2, TMC2208) #ifdef Z2_HARDWARE_SERIAL _TMC2208_DEFINE_HARDWARE(Z2); #else _TMC2208_DEFINE_SOFTWARE(Z2); #endif #endif - #if ENABLED(E0_IS_TMC2208) + #if AXIS_DRIVER_TYPE(E0, TMC2208) #ifdef E0_HARDWARE_SERIAL _TMC2208_DEFINE_HARDWARE(E0); #else _TMC2208_DEFINE_SOFTWARE(E0); #endif #endif - #if ENABLED(E1_IS_TMC2208) + #if AXIS_DRIVER_TYPE(E1, TMC2208) #ifdef E1_HARDWARE_SERIAL _TMC2208_DEFINE_HARDWARE(E1); #else _TMC2208_DEFINE_SOFTWARE(E1); #endif #endif - #if ENABLED(E2_IS_TMC2208) + #if AXIS_DRIVER_TYPE(E2, TMC2208) #ifdef E2_HARDWARE_SERIAL _TMC2208_DEFINE_HARDWARE(E2); #else _TMC2208_DEFINE_SOFTWARE(E2); #endif #endif - #if ENABLED(E3_IS_TMC2208) + #if AXIS_DRIVER_TYPE(E3, TMC2208) #ifdef E3_HARDWARE_SERIAL _TMC2208_DEFINE_HARDWARE(E3); #else _TMC2208_DEFINE_SOFTWARE(E3); #endif #endif - #if ENABLED(E4_IS_TMC2208) + #if AXIS_DRIVER_TYPE(E4, TMC2208) #ifdef E4_HARDWARE_SERIAL _TMC2208_DEFINE_HARDWARE(E4); #else @@ -372,38 +372,82 @@ #endif void tmc2208_serial_begin() { - #if ENABLED(X_IS_TMC2208) - X_HARDWARE_SERIAL.begin(115200); + #if AXIS_DRIVER_TYPE(X, TMC2208) + #ifdef X_HARDWARE_SERIAL + X_HARDWARE_SERIAL.begin(115200); + #else + stepperX.beginSerial(115200); + #endif #endif - #if ENABLED(X2_IS_TMC2208) - X2_HARDWARE_SERIAL.begin(115200); + #if AXIS_DRIVER_TYPE(X2, TMC2208) + #ifdef X2_HARDWARE_SERIAL + X2_HARDWARE_SERIAL.begin(115200); + #else + stepperX2.beginSerial(115200); + #endif #endif - #if ENABLED(Y_IS_TMC2208) - Y_HARDWARE_SERIAL.begin(115200); + #if AXIS_DRIVER_TYPE(Y, TMC2208) + #ifdef Y_HARDWARE_SERIAL + Y_HARDWARE_SERIAL.begin(115200); + #else + stepperY.beginSerial(115200); + #endif #endif - #if ENABLED(Y2_IS_TMC2208) - Y2_HARDWARE_SERIAL.begin(115200); + #if AXIS_DRIVER_TYPE(Y2, TMC2208) + #ifdef Y2_HARDWARE_SERIAL + Y2_HARDWARE_SERIAL.begin(115200); + #else + stepperY2.beginSerial(115200); + #endif #endif - #if ENABLED(Z_IS_TMC2208) - Z_HARDWARE_SERIAL.begin(115200); + #if AXIS_DRIVER_TYPE(Z, TMC2208) + #ifdef Z_HARDWARE_SERIAL + Z_HARDWARE_SERIAL.begin(115200); + #else + stepperZ.beginSerial(115200); + #endif #endif - #if ENABLED(Z2_IS_TMC2208) - Z2_HARDWARE_SERIAL.begin(115200); + #if AXIS_DRIVER_TYPE(Z2, TMC2208) + #ifdef Z2_HARDWARE_SERIAL + Z2_HARDWARE_SERIAL.begin(115200); + #else + stepperZ2.beginSerial(115200); + #endif #endif - #if ENABLED(E0_IS_TMC2208) - E0_HARDWARE_SERIAL.begin(115200); + #if AXIS_DRIVER_TYPE(E0, TMC2208) + #ifdef E0_HARDWARE_SERIAL + E0_HARDWARE_SERIAL.begin(115200); + #else + stepperE0.beginSerial(115200); + #endif #endif - #if ENABLED(E1_IS_TMC2208) - E1_HARDWARE_SERIAL.begin(115200); + #if AXIS_DRIVER_TYPE(E1, TMC2208) + #ifdef E1_HARDWARE_SERIAL + E1_HARDWARE_SERIAL.begin(115200); + #else + stepperE1.beginSerial(115200); + #endif #endif - #if ENABLED(E2_IS_TMC2208) - E2_HARDWARE_SERIAL.begin(115200); + #if AXIS_DRIVER_TYPE(E2, TMC2208) + #ifdef E2_HARDWARE_SERIAL + E2_HARDWARE_SERIAL.begin(115200); + #else + stepperE2.beginSerial(115200); + #endif #endif - #if ENABLED(E3_IS_TMC2208) - E3_HARDWARE_SERIAL.begin(115200); + #if AXIS_DRIVER_TYPE(E3, TMC2208) + #ifdef E3_HARDWARE_SERIAL + E3_HARDWARE_SERIAL.begin(115200); + #else + stepperE3.beginSerial(115200); + #endif #endif - #if ENABLED(E4_IS_TMC2208) - E4_HARDWARE_SERIAL.begin(115200); + #if AXIS_DRIVER_TYPE(E4, TMC2208) + #ifdef E4_HARDWARE_SERIAL + E4_HARDWARE_SERIAL.begin(115200); + #else + stepperE4.beginSerial(115200); + #endif #endif } @@ -446,101 +490,103 @@ #define _TMC2208_INIT(ST, SPMM) tmc2208_init(stepper##ST, ST##_CURRENT, ST##_MICROSTEPS, ST##_HYBRID_THRESHOLD, SPMM) void tmc2208_init_to_defaults() { - #if ENABLED(X_IS_TMC2208) + #if AXIS_DRIVER_TYPE(X, TMC2208) _TMC2208_INIT(X, planner.axis_steps_per_mm[X_AXIS]); #endif - #if ENABLED(X2_IS_TMC2208) + #if AXIS_DRIVER_TYPE(X2, TMC2208) _TMC2208_INIT(X2, planner.axis_steps_per_mm[X_AXIS]); #endif - #if ENABLED(Y_IS_TMC2208) + #if AXIS_DRIVER_TYPE(Y, TMC2208) _TMC2208_INIT(Y, planner.axis_steps_per_mm[Y_AXIS]); #endif - #if ENABLED(Y2_IS_TMC2208) + #if AXIS_DRIVER_TYPE(Y2, TMC2208) _TMC2208_INIT(Y2, planner.axis_steps_per_mm[Y_AXIS]); #endif - #if ENABLED(Z_IS_TMC2208) + #if AXIS_DRIVER_TYPE(Z, TMC2208) _TMC2208_INIT(Z, planner.axis_steps_per_mm[Z_AXIS]); #endif - #if ENABLED(Z2_IS_TMC2208) + #if AXIS_DRIVER_TYPE(Z2, TMC2208) _TMC2208_INIT(Z2, planner.axis_steps_per_mm[Z_AXIS]); #endif - #if ENABLED(E0_IS_TMC2208) + #if AXIS_DRIVER_TYPE(E0, TMC2208) _TMC2208_INIT(E0, planner.axis_steps_per_mm[E_AXIS]); #endif - #if ENABLED(E1_IS_TMC2208) + #if AXIS_DRIVER_TYPE(E1, TMC2208) { constexpr int extruder = 1; _TMC2208_INIT(E1, planner.axis_steps_per_mm[E_AXIS_N]); } #endif - #if ENABLED(E2_IS_TMC2208) + #if AXIS_DRIVER_TYPE(E2, TMC2208) { constexpr int extruder = 2; _TMC2208_INIT(E2, planner.axis_steps_per_mm[E_AXIS_N]); } #endif - #if ENABLED(E3_IS_TMC2208) + #if AXIS_DRIVER_TYPE(E3, TMC2208) { constexpr int extruder = 3; _TMC2208_INIT(E3, planner.axis_steps_per_mm[E_AXIS_N]); } #endif - #if ENABLED(E4_IS_TMC2208) + #if AXIS_DRIVER_TYPE(E4, TMC2208) { constexpr int extruder = 4; _TMC2208_INIT(E4, planner.axis_steps_per_mm[E_AXIS_N]); } #endif } - -#endif // HAVE_TMC2208 +#endif // TMC2208 void restore_stepper_drivers() { - #if X_IS_TRINAMIC + #if AXIS_IS_TMC(X) stepperX.push(); #endif - #if X2_IS_TRINAMIC + #if AXIS_IS_TMC(X2) stepperX2.push(); #endif - #if Y_IS_TRINAMIC + #if AXIS_IS_TMC(Y) stepperY.push(); #endif - #if Y2_IS_TRINAMIC + #if AXIS_IS_TMC(Y2) stepperY2.push(); #endif - #if Z_IS_TRINAMIC + #if AXIS_IS_TMC(Z) stepperZ.push(); #endif - #if Z2_IS_TRINAMIC + #if AXIS_IS_TMC(Z2) stepperZ2.push(); #endif - #if E0_IS_TRINAMIC + #if AXIS_IS_TMC(E0) stepperE0.push(); #endif - #if E1_IS_TRINAMIC + #if AXIS_IS_TMC(E1) stepperE1.push(); #endif - #if E2_IS_TRINAMIC + #if AXIS_IS_TMC(E2) stepperE2.push(); #endif - #if E3_IS_TRINAMIC + #if AXIS_IS_TMC(E3) stepperE3.push(); #endif - #if E4_IS_TRINAMIC + #if AXIS_IS_TMC(E4) stepperE4.push(); #endif } void reset_stepper_drivers() { - #if ENABLED(HAVE_TMC26X) + #if HAS_DRIVER(TMC26X) tmc26x_init_to_defaults(); #endif - #if ENABLED(HAVE_TMC2130) + #if HAS_DRIVER(TMC2130) + delay(100); tmc2130_init_to_defaults(); #endif - #if ENABLED(HAVE_TMC2208) + #if HAS_DRIVER(TMC2208) + delay(100); tmc2208_init_to_defaults(); #endif #ifdef TMC_ADV TMC_ADV() #endif - #if ENABLED(HAVE_L6470DRIVER) + #if HAS_DRIVER(L6470) L6470_init_to_defaults(); #endif + stepper.set_directions(); } // // L6470 Driver objects and inits // -#if ENABLED(HAVE_L6470DRIVER) +#if HAS_DRIVER(L6470) #include #include @@ -548,37 +594,37 @@ void reset_stepper_drivers() { #define _L6470_DEFINE(ST) L6470 stepper##ST(ST##_ENABLE_PIN) // L6470 Stepper objects - #if ENABLED(X_IS_L6470) + #if AXIS_DRIVER_TYPE(X, L6470) _L6470_DEFINE(X); #endif - #if ENABLED(X2_IS_L6470) + #if AXIS_DRIVER_TYPE(X2, L6470) _L6470_DEFINE(X2); #endif - #if ENABLED(Y_IS_L6470) + #if AXIS_DRIVER_TYPE(Y, L6470) _L6470_DEFINE(Y); #endif - #if ENABLED(Y2_IS_L6470) + #if AXIS_DRIVER_TYPE(Y2, L6470) _L6470_DEFINE(Y2); #endif - #if ENABLED(Z_IS_L6470) + #if AXIS_DRIVER_TYPE(Z, L6470) _L6470_DEFINE(Z); #endif - #if ENABLED(Z2_IS_L6470) + #if AXIS_DRIVER_TYPE(Z2, L6470) _L6470_DEFINE(Z2); #endif - #if ENABLED(E0_IS_L6470) + #if AXIS_DRIVER_TYPE(E0, L6470) _L6470_DEFINE(E0); #endif - #if ENABLED(E1_IS_L6470) + #if AXIS_DRIVER_TYPE(E1, L6470) _L6470_DEFINE(E1); #endif - #if ENABLED(E2_IS_L6470) + #if AXIS_DRIVER_TYPE(E2, L6470) _L6470_DEFINE(E2); #endif - #if ENABLED(E3_IS_L6470) + #if AXIS_DRIVER_TYPE(E3, L6470) _L6470_DEFINE(E3); #endif - #if ENABLED(E4_IS_L6470) + #if AXIS_DRIVER_TYPE(E4, L6470) _L6470_DEFINE(E4); #endif @@ -591,39 +637,39 @@ void reset_stepper_drivers() { }while(0) void L6470_init_to_defaults() { - #if ENABLED(X_IS_L6470) + #if AXIS_DRIVER_TYPE(X, L6470) _L6470_INIT(X); #endif - #if ENABLED(X2_IS_L6470) + #if AXIS_DRIVER_TYPE(X2, L6470) _L6470_INIT(X2); #endif - #if ENABLED(Y_IS_L6470) + #if AXIS_DRIVER_TYPE(Y, L6470) _L6470_INIT(Y); #endif - #if ENABLED(Y2_IS_L6470) + #if AXIS_DRIVER_TYPE(Y2, L6470) _L6470_INIT(Y2); #endif - #if ENABLED(Z_IS_L6470) + #if AXIS_DRIVER_TYPE(Z, L6470) _L6470_INIT(Z); #endif - #if ENABLED(Z2_IS_L6470) + #if AXIS_DRIVER_TYPE(Z2, L6470) _L6470_INIT(Z2); #endif - #if ENABLED(E0_IS_L6470) + #if AXIS_DRIVER_TYPE(E0, L6470) _L6470_INIT(E0); #endif - #if ENABLED(E1_IS_L6470) + #if AXIS_DRIVER_TYPE(E1, L6470) _L6470_INIT(E1); #endif - #if ENABLED(E2_IS_L6470) + #if AXIS_DRIVER_TYPE(E2, L6470) _L6470_INIT(E2); #endif - #if ENABLED(E3_IS_L6470) + #if AXIS_DRIVER_TYPE(E3, L6470) _L6470_INIT(E3); #endif - #if ENABLED(E4_IS_L6470) + #if AXIS_DRIVER_TYPE(E4, L6470) _L6470_INIT(E4); #endif } -#endif // HAVE_L6470DRIVER +#endif // L6470 diff --git a/Marlin/stepper_indirection.h b/Marlin/stepper_indirection.h index 3e67118d86..54a17c51e1 100644 --- a/Marlin/stepper_indirection.h +++ b/Marlin/stepper_indirection.h @@ -47,25 +47,25 @@ #include "MarlinConfig.h" // TMC26X drivers have STEP/DIR on normal pins, but ENABLE via SPI -#if ENABLED(HAVE_TMC26X) +#if HAS_DRIVER(TMC26X) #include #include void tmc26x_init_to_defaults(); #endif -#if ENABLED(HAVE_TMC2130) +#if HAS_DRIVER(TMC2130) #include void tmc2130_init_to_defaults(); #endif -#if ENABLED(HAVE_TMC2208) +#if HAS_DRIVER(TMC2208) #include void tmc2208_serial_begin(); void tmc2208_init_to_defaults(); #endif // L6470 has STEP on normal pins, but DIR/ENABLE via SPI -#if ENABLED(HAVE_L6470DRIVER) +#if HAS_DRIVER(L6470) #include #include void L6470_init_to_defaults(); @@ -75,7 +75,7 @@ void restore_stepper_drivers(); // Called by PSU_ON void reset_stepper_drivers(); // Called by settings.load / settings.reset // X Stepper -#if ENABLED(X_IS_L6470) +#if AXIS_DRIVER_TYPE(X, L6470) extern L6470 stepperX; #define X_ENABLE_INIT NOOP #define X_ENABLE_WRITE(STATE) do{ if (STATE) stepperX.Step_Clock(stepperX.getStatus() & STATUS_HIZ); else stepperX.softFree(); }while(0) @@ -84,15 +84,15 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset #define X_DIR_WRITE(STATE) stepperX.Step_Clock(STATE) #define X_DIR_READ (stepperX.getStatus() & STATUS_DIR) #else - #if ENABLED(X_IS_TMC26X) + #if AXIS_DRIVER_TYPE(X, TMC26X) extern TMC26XStepper stepperX; #define X_ENABLE_INIT NOOP #define X_ENABLE_WRITE(STATE) stepperX.setEnabled(STATE) #define X_ENABLE_READ stepperX.isEnabled() #else - #if ENABLED(X_IS_TMC2130) + #if AXIS_DRIVER_TYPE(X, TMC2130) extern TMC2130Stepper stepperX; - #elif ENABLED(X_IS_TMC2208) + #elif AXIS_DRIVER_TYPE(X, TMC2208) extern TMC2208Stepper stepperX; #endif #define X_ENABLE_INIT SET_OUTPUT(X_ENABLE_PIN) @@ -108,7 +108,7 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset #define X_STEP_READ READ(X_STEP_PIN) // Y Stepper -#if ENABLED(Y_IS_L6470) +#if AXIS_DRIVER_TYPE(Y, L6470) extern L6470 stepperY; #define Y_ENABLE_INIT NOOP #define Y_ENABLE_WRITE(STATE) do{ if (STATE) stepperY.Step_Clock(stepperY.getStatus() & STATUS_HIZ); else stepperY.softFree(); }while(0) @@ -117,15 +117,15 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset #define Y_DIR_WRITE(STATE) stepperY.Step_Clock(STATE) #define Y_DIR_READ (stepperY.getStatus() & STATUS_DIR) #else - #if ENABLED(Y_IS_TMC26X) + #if AXIS_DRIVER_TYPE(Y, TMC26X) extern TMC26XStepper stepperY; #define Y_ENABLE_INIT NOOP #define Y_ENABLE_WRITE(STATE) stepperY.setEnabled(STATE) #define Y_ENABLE_READ stepperY.isEnabled() #else - #if ENABLED(Y_IS_TMC2130) + #if AXIS_DRIVER_TYPE(Y, TMC2130) extern TMC2130Stepper stepperY; - #elif ENABLED(Y_IS_TMC2208) + #elif AXIS_DRIVER_TYPE(Y, TMC2208) extern TMC2208Stepper stepperY; #endif #define Y_ENABLE_INIT SET_OUTPUT(Y_ENABLE_PIN) @@ -141,7 +141,7 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset #define Y_STEP_READ READ(Y_STEP_PIN) // Z Stepper -#if ENABLED(Z_IS_L6470) +#if AXIS_DRIVER_TYPE(Z, L6470) extern L6470 stepperZ; #define Z_ENABLE_INIT NOOP #define Z_ENABLE_WRITE(STATE) do{ if (STATE) stepperZ.Step_Clock(stepperZ.getStatus() & STATUS_HIZ); else stepperZ.softFree(); }while(0) @@ -150,15 +150,15 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset #define Z_DIR_WRITE(STATE) stepperZ.Step_Clock(STATE) #define Z_DIR_READ (stepperZ.getStatus() & STATUS_DIR) #else - #if ENABLED(Z_IS_TMC26X) + #if AXIS_DRIVER_TYPE(Z, TMC26X) extern TMC26XStepper stepperZ; #define Z_ENABLE_INIT NOOP #define Z_ENABLE_WRITE(STATE) stepperZ.setEnabled(STATE) #define Z_ENABLE_READ stepperZ.isEnabled() #else - #if ENABLED(Z_IS_TMC2130) + #if AXIS_DRIVER_TYPE(Z, TMC2130) extern TMC2130Stepper stepperZ; - #elif ENABLED(Z_IS_TMC2208) + #elif AXIS_DRIVER_TYPE(Z, TMC2208) extern TMC2208Stepper stepperZ; #endif #define Z_ENABLE_INIT SET_OUTPUT(Z_ENABLE_PIN) @@ -175,7 +175,7 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset // X2 Stepper #if HAS_X2_ENABLE - #if ENABLED(X2_IS_L6470) + #if AXIS_DRIVER_TYPE(X2, L6470) extern L6470 stepperX2; #define X2_ENABLE_INIT NOOP #define X2_ENABLE_WRITE(STATE) do{ if (STATE) stepperX2.Step_Clock(stepperX2.getStatus() & STATUS_HIZ); else stepperX2.softFree(); }while(0) @@ -184,15 +184,15 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset #define X2_DIR_WRITE(STATE) stepperX2.Step_Clock(STATE) #define X2_DIR_READ (stepperX2.getStatus() & STATUS_DIR) #else - #if ENABLED(X2_IS_TMC26X) + #if AXIS_DRIVER_TYPE(X2, TMC26X) extern TMC26XStepper stepperX2; #define X2_ENABLE_INIT NOOP #define X2_ENABLE_WRITE(STATE) stepperX2.setEnabled(STATE) #define X2_ENABLE_READ stepperX2.isEnabled() #else - #if ENABLED(X2_IS_TMC2130) + #if AXIS_DRIVER_TYPE(X2, TMC2130) extern TMC2130Stepper stepperX2; - #elif ENABLED(X2_IS_TMC2208) + #elif AXIS_DRIVER_TYPE(X2, TMC2208) extern TMC2208Stepper stepperX2; #endif #define X2_ENABLE_INIT SET_OUTPUT(X2_ENABLE_PIN) @@ -210,7 +210,7 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset // Y2 Stepper #if HAS_Y2_ENABLE - #if ENABLED(Y2_IS_L6470) + #if AXIS_DRIVER_TYPE(Y2, L6470) extern L6470 stepperY2; #define Y2_ENABLE_INIT NOOP #define Y2_ENABLE_WRITE(STATE) do{ if (STATE) stepperY2.Step_Clock(stepperY2.getStatus() & STATUS_HIZ); else stepperY2.softFree(); }while(0) @@ -219,15 +219,15 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset #define Y2_DIR_WRITE(STATE) stepperY2.Step_Clock(STATE) #define Y2_DIR_READ (stepperY2.getStatus() & STATUS_DIR) #else - #if ENABLED(Y2_IS_TMC26X) + #if AXIS_DRIVER_TYPE(Y2, TMC26X) extern TMC26XStepper stepperY2; #define Y2_ENABLE_INIT NOOP #define Y2_ENABLE_WRITE(STATE) stepperY2.setEnabled(STATE) #define Y2_ENABLE_READ stepperY2.isEnabled() #else - #if ENABLED(Y2_IS_TMC2130) + #if AXIS_DRIVER_TYPE(Y2, TMC2130) extern TMC2130Stepper stepperY2; - #elif ENABLED(Y2_IS_TMC2208) + #elif AXIS_DRIVER_TYPE(Y2, TMC2208) extern TMC2208Stepper stepperY2; #endif #define Y2_ENABLE_INIT SET_OUTPUT(Y2_ENABLE_PIN) @@ -245,7 +245,7 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset // Z2 Stepper #if HAS_Z2_ENABLE - #if ENABLED(Z2_IS_L6470) + #if AXIS_DRIVER_TYPE(Z2, L6470) extern L6470 stepperZ2; #define Z2_ENABLE_INIT NOOP #define Z2_ENABLE_WRITE(STATE) do{ if (STATE) stepperZ2.Step_Clock(stepperZ2.getStatus() & STATUS_HIZ); else stepperZ2.softFree(); }while(0) @@ -254,15 +254,15 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset #define Z2_DIR_WRITE(STATE) stepperZ2.Step_Clock(STATE) #define Z2_DIR_READ (stepperZ2.getStatus() & STATUS_DIR) #else - #if ENABLED(Z2_IS_TMC26X) + #if AXIS_DRIVER_TYPE(Z2, TMC26X) extern TMC26XStepper stepperZ2; #define Z2_ENABLE_INIT NOOP #define Z2_ENABLE_WRITE(STATE) stepperZ2.setEnabled(STATE) #define Z2_ENABLE_READ stepperZ2.isEnabled() #else - #if ENABLED(Z2_IS_TMC2130) + #if AXIS_DRIVER_TYPE(Z2, TMC2130) extern TMC2130Stepper stepperZ2; - #elif ENABLED(Z2_IS_TMC2208) + #elif AXIS_DRIVER_TYPE(Z2, TMC2208) extern TMC2208Stepper stepperZ2; #endif #define Z2_ENABLE_INIT SET_OUTPUT(Z2_ENABLE_PIN) @@ -279,7 +279,7 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset #endif // E0 Stepper -#if ENABLED(E0_IS_L6470) +#if AXIS_DRIVER_TYPE(E0, L6470) extern L6470 stepperE0; #define E0_ENABLE_INIT NOOP #define E0_ENABLE_WRITE(STATE) do{ if (STATE) stepperE0.Step_Clock(stepperE0.getStatus() & STATUS_HIZ); else stepperE0.softFree(); }while(0) @@ -288,15 +288,15 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset #define E0_DIR_WRITE(STATE) stepperE0.Step_Clock(STATE) #define E0_DIR_READ (stepperE0.getStatus() & STATUS_DIR) #else - #if ENABLED(E0_IS_TMC26X) + #if AXIS_DRIVER_TYPE(E0, TMC26X) extern TMC26XStepper stepperE0; #define E0_ENABLE_INIT NOOP #define E0_ENABLE_WRITE(STATE) stepperE0.setEnabled(STATE) #define E0_ENABLE_READ stepperE0.isEnabled() #else - #if ENABLED(E0_IS_TMC2130) + #if AXIS_DRIVER_TYPE(E0, TMC2130) extern TMC2130Stepper stepperE0; - #elif ENABLED(E0_IS_TMC2208) + #elif AXIS_DRIVER_TYPE(E0, TMC2208) extern TMC2208Stepper stepperE0; #endif #define E0_ENABLE_INIT SET_OUTPUT(E0_ENABLE_PIN) @@ -312,7 +312,7 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset #define E0_STEP_READ READ(E0_STEP_PIN) // E1 Stepper -#if ENABLED(E1_IS_L6470) +#if AXIS_DRIVER_TYPE(E1, L6470) extern L6470 stepperE1; #define E1_ENABLE_INIT NOOP #define E1_ENABLE_WRITE(STATE) do{ if (STATE) stepperE1.Step_Clock(stepperE1.getStatus() & STATUS_HIZ); else stepperE1.softFree(); }while(0) @@ -321,15 +321,15 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset #define E1_DIR_WRITE(STATE) stepperE1.Step_Clock(STATE) #define E1_DIR_READ (stepperE1.getStatus() & STATUS_DIR) #else - #if ENABLED(E1_IS_TMC26X) + #if AXIS_DRIVER_TYPE(E1, TMC26X) extern TMC26XStepper stepperE1; #define E1_ENABLE_INIT NOOP #define E1_ENABLE_WRITE(STATE) stepperE1.setEnabled(STATE) #define E1_ENABLE_READ stepperE1.isEnabled() #else - #if ENABLED(E1_IS_TMC2130) + #if AXIS_DRIVER_TYPE(E1, TMC2130) extern TMC2130Stepper stepperE1; - #elif ENABLED(E1_IS_TMC2208) + #elif AXIS_DRIVER_TYPE(E1, TMC2208) extern TMC2208Stepper stepperE1; #endif #define E1_ENABLE_INIT SET_OUTPUT(E1_ENABLE_PIN) @@ -345,7 +345,7 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset #define E1_STEP_READ READ(E1_STEP_PIN) // E2 Stepper -#if ENABLED(E2_IS_L6470) +#if AXIS_DRIVER_TYPE(E2, L6470) extern L6470 stepperE2; #define E2_ENABLE_INIT NOOP #define E2_ENABLE_WRITE(STATE) do{ if (STATE) stepperE2.Step_Clock(stepperE2.getStatus() & STATUS_HIZ); else stepperE2.softFree(); }while(0) @@ -354,15 +354,15 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset #define E2_DIR_WRITE(STATE) stepperE2.Step_Clock(STATE) #define E2_DIR_READ (stepperE2.getStatus() & STATUS_DIR) #else - #if ENABLED(E2_IS_TMC26X) + #if AXIS_DRIVER_TYPE(E2, TMC26X) extern TMC26XStepper stepperE2; #define E2_ENABLE_INIT NOOP #define E2_ENABLE_WRITE(STATE) stepperE2.setEnabled(STATE) #define E2_ENABLE_READ stepperE2.isEnabled() #else - #if ENABLED(E2_IS_TMC2130) + #if AXIS_DRIVER_TYPE(E2, TMC2130) extern TMC2130Stepper stepperE2; - #elif ENABLED(E2_IS_TMC2208) + #elif AXIS_DRIVER_TYPE(E2, TMC2208) extern TMC2208Stepper stepperE2; #endif #define E2_ENABLE_INIT SET_OUTPUT(E2_ENABLE_PIN) @@ -378,7 +378,7 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset #define E2_STEP_READ READ(E2_STEP_PIN) // E3 Stepper -#if ENABLED(E3_IS_L6470) +#if AXIS_DRIVER_TYPE(E3, L6470) extern L6470 stepperE3; #define E3_ENABLE_INIT NOOP #define E3_ENABLE_WRITE(STATE) do{ if (STATE) stepperE3.Step_Clock(stepperE3.getStatus() & STATUS_HIZ); else stepperE3.softFree(); }while(0) @@ -387,15 +387,15 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset #define E3_DIR_WRITE(STATE) stepperE3.Step_Clock(STATE) #define E3_DIR_READ (stepperE3.getStatus() & STATUS_DIR) #else - #if ENABLED(E3_IS_TMC26X) + #if AXIS_DRIVER_TYPE(E3, TMC26X) extern TMC26XStepper stepperE3; #define E3_ENABLE_INIT NOOP #define E3_ENABLE_WRITE(STATE) stepperE3.setEnabled(STATE) #define E3_ENABLE_READ stepperE3.isEnabled() #else - #if ENABLED(E3_IS_TMC2130) + #if AXIS_DRIVER_TYPE(E3, TMC2130) extern TMC2130Stepper stepperE3; - #elif ENABLED(E3_IS_TMC2208) + #elif AXIS_DRIVER_TYPE(E3, TMC2208) extern TMC2208Stepper stepperE3; #endif #define E3_ENABLE_INIT SET_OUTPUT(E3_ENABLE_PIN) @@ -411,7 +411,7 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset #define E3_STEP_READ READ(E3_STEP_PIN) // E4 Stepper -#if ENABLED(E4_IS_L6470) +#if AXIS_DRIVER_TYPE(E4, L6470) extern L6470 stepperE4; #define E4_ENABLE_INIT NOOP #define E4_ENABLE_WRITE(STATE) do{ if (STATE) stepperE4.Step_Clock(stepperE4.getStatus() & STATUS_HIZ); else stepperE4.softFree(); }while(0) @@ -420,15 +420,15 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset #define E4_DIR_WRITE(STATE) stepperE4.Step_Clock(STATE) #define E4_DIR_READ (stepperE4.getStatus() & STATUS_DIR) #else - #if ENABLED(E4_IS_TMC26X) + #if AXIS_DRIVER_TYPE(E4, TMC26X) extern TMC26XStepper stepperE4; #define E4_ENABLE_INIT NOOP #define E4_ENABLE_WRITE(STATE) stepperE4.setEnabled(STATE) #define E4_ENABLE_READ stepperE4.isEnabled() #else - #if ENABLED(E4_IS_TMC2130) + #if AXIS_DRIVER_TYPE(E4, TMC2130) extern TMC2130Stepper stepperE4; - #elif ENABLED(E4_IS_TMC2208) + #elif AXIS_DRIVER_TYPE(E4, TMC2208) extern TMC2208Stepper stepperE4; #endif #define E4_ENABLE_INIT SET_OUTPUT(E4_ENABLE_PIN) diff --git a/Marlin/temperature.cpp b/Marlin/temperature.cpp index e287a47794..665e5b5ec9 100644 --- a/Marlin/temperature.cpp +++ b/Marlin/temperature.cpp @@ -260,19 +260,29 @@ uint8_t Temperature::soft_pwm_amount[HOTENDS]; workKp = 0, workKi = 0, workKd = 0, max = 0, min = 10000; - #define HAS_TP_BED (ENABLED(THERMAL_PROTECTION_BED) && ENABLED(PIDTEMPBED)) - #if HAS_TP_BED && ENABLED(THERMAL_PROTECTION_HOTENDS) && ENABLED(PIDTEMP) - #define TV(B,H) (hotend < 0 ? (B) : (H)) - #elif HAS_TP_BED - #define TV(B,H) (B) + #if HAS_PID_FOR_BOTH + #define GHV(B,H) (hotend < 0 ? (B) : (H)) + #define SHV(S,B,H) if (hotend < 0) S##_bed = B; else S [hotend] = H; + #elif ENABLED(PIDTEMPBED) + #define GHV(B,H) B + #define SHV(S,B,H) (S##_bed = B) #else - #define TV(B,H) (H) + #define GHV(B,H) H + #define SHV(S,B,H) (S [hotend] = H) #endif #if WATCH_THE_BED || WATCH_HOTENDS - const uint16_t watch_temp_period = TV(WATCH_BED_TEMP_PERIOD, WATCH_TEMP_PERIOD); - const uint8_t watch_temp_increase = TV(WATCH_BED_TEMP_INCREASE, WATCH_TEMP_INCREASE); - const float watch_temp_target = target - float(watch_temp_increase + TV(TEMP_BED_HYSTERESIS, TEMP_HYSTERESIS) + 1); + #define HAS_TP_BED (ENABLED(THERMAL_PROTECTION_BED) && ENABLED(PIDTEMPBED)) + #if HAS_TP_BED && ENABLED(THERMAL_PROTECTION_HOTENDS) && ENABLED(PIDTEMP) + #define GTV(B,H) (hotend < 0 ? (B) : (H)) + #elif HAS_TP_BED + #define GTV(B,H) (B) + #else + #define GTV(B,H) (H) + #endif + const uint16_t watch_temp_period = GTV(WATCH_BED_TEMP_PERIOD, WATCH_TEMP_PERIOD); + const uint8_t watch_temp_increase = GTV(WATCH_BED_TEMP_INCREASE, WATCH_TEMP_INCREASE); + const float watch_temp_target = target - float(watch_temp_increase + GTV(TEMP_BED_HYSTERESIS, TEMP_HYSTERESIS) + 1); millis_t temp_change_ms = next_temp_ms + watch_temp_period * 1000UL; float next_watch_temp = 0.0; bool heated = false; @@ -302,16 +312,7 @@ uint8_t Temperature::soft_pwm_amount[HOTENDS]; disable_all_heaters(); // switch off all heaters. - #if HAS_PID_FOR_BOTH - if (hotend < 0) - soft_pwm_amount_bed = bias = d = (MAX_BED_POWER) >> 1; - else - soft_pwm_amount[hotend] = bias = d = (PID_MAX) >> 1; - #elif ENABLED(PIDTEMP) - soft_pwm_amount[hotend] = bias = d = (PID_MAX) >> 1; - #else - soft_pwm_amount_bed = bias = d = (MAX_BED_POWER) >> 1; - #endif + SHV(soft_pwm_amount, bias = d = (MAX_BED_POWER) >> 1, bias = d = (PID_MAX) >> 1); wait_for_heatup = true; // Can be interrupted with M108 @@ -324,15 +325,7 @@ uint8_t Temperature::soft_pwm_amount[HOTENDS]; updateTemperaturesFromRawValues(); // Get the current temperature and constrain it - current = - #if HAS_PID_FOR_BOTH - hotend < 0 ? current_temperature_bed : current_temperature[hotend] - #elif ENABLED(PIDTEMP) - current_temperature[hotend] - #else - current_temperature_bed - #endif - ; + current = GHV(current_temperature_bed, current_temperature[hotend]); NOLESS(max, current); NOMORE(min, current); @@ -346,16 +339,7 @@ uint8_t Temperature::soft_pwm_amount[HOTENDS]; if (heating && current > target) { if (ELAPSED(ms, t2 + 5000UL)) { heating = false; - #if HAS_PID_FOR_BOTH - if (hotend < 0) - soft_pwm_amount_bed = (bias - d) >> 1; - else - soft_pwm_amount[hotend] = (bias - d) >> 1; - #elif ENABLED(PIDTEMP) - soft_pwm_amount[hotend] = (bias - d) >> 1; - #elif ENABLED(PIDTEMPBED) - soft_pwm_amount_bed = (bias - d) >> 1; - #endif + SHV(soft_pwm_amount, (bias - d) >> 1, (bias - d) >> 1); t1 = ms; t_high = t1 - t2; max = target; @@ -368,15 +352,7 @@ uint8_t Temperature::soft_pwm_amount[HOTENDS]; t2 = ms; t_low = t2 - t1; if (cycles > 0) { - long max_pow = - #if HAS_PID_FOR_BOTH - hotend < 0 ? MAX_BED_POWER : PID_MAX - #elif ENABLED(PIDTEMP) - PID_MAX - #else - MAX_BED_POWER - #endif - ; + const long max_pow = GHV(MAX_BED_POWER, PID_MAX); bias += (d * (t_high - t_low)) / (t_low + t_high); bias = constrain(bias, 20, max_pow - 20); d = (bias > max_pow >> 1) ? max_pow - 1 - bias : bias; @@ -415,16 +391,7 @@ uint8_t Temperature::soft_pwm_amount[HOTENDS]; */ } } - #if HAS_PID_FOR_BOTH - if (hotend < 0) - soft_pwm_amount_bed = (bias + d) >> 1; - else - soft_pwm_amount[hotend] = (bias + d) >> 1; - #elif ENABLED(PIDTEMP) - soft_pwm_amount[hotend] = (bias + d) >> 1; - #else - soft_pwm_amount_bed = (bias + d) >> 1; - #endif + SHV(soft_pwm_amount, (bias + d) >> 1, (bias + d) >> 1); cycles++; min = target; } @@ -453,10 +420,10 @@ uint8_t Temperature::soft_pwm_amount[HOTENDS]; if ( #if WATCH_THE_BED && WATCH_HOTENDS true - #elif WATCH_THE_BED - hotend < 0 - #else + #elif WATCH_HOTENDS hotend >= 0 + #else + hotend < 0 #endif ) { if (!heated) { // If not yet reached target... @@ -487,7 +454,7 @@ uint8_t Temperature::soft_pwm_amount[HOTENDS]; SERIAL_PROTOCOLLNPGM(MSG_PID_AUTOTUNE_FINISHED); #if HAS_PID_FOR_BOTH - const char* estring = hotend < 0 ? "bed" : ""; + const char* estring = GHV("bed", ""); SERIAL_PROTOCOLPAIR("#define DEFAULT_", estring); SERIAL_PROTOCOLPAIR("Kp ", workKp); SERIAL_EOL(); SERIAL_PROTOCOLPAIR("#define DEFAULT_", estring); SERIAL_PROTOCOLPAIR("Ki ", workKi); SERIAL_EOL(); SERIAL_PROTOCOLPAIR("#define DEFAULT_", estring); SERIAL_PROTOCOLPAIR("Kd ", workKd); SERIAL_EOL(); @@ -575,7 +542,13 @@ int Temperature::getHeaterPower(const int heater) { uint8_t fanDone = 0; for (uint8_t f = 0; f < COUNT(fanPin); f++) { - pin_t pin = pgm_read_byte(&fanPin[f]); + const pin_t pin = + #ifdef ARDUINO + pgm_read_byte(&fanPin[f]) + #else + fanPin[f] + #endif + ; const uint8_t bit = pgm_read_byte(&fanBit[f]); if (pin >= 0 && !TEST(fanDone, bit)) { uint8_t newFanSpeed = TEST(fanState, bit) ? EXTRUDER_AUTO_FAN_SPEED : 0; @@ -596,7 +569,6 @@ int Temperature::getHeaterPower(const int heater) { // Temperature Error Handlers // void Temperature::_temp_error(const int8_t e, const char * const serial_msg, const char * const lcd_msg) { - static bool killed = false; if (IsRunning()) { SERIAL_ERROR_START(); serialprintPGM(serial_msg); @@ -604,6 +576,7 @@ void Temperature::_temp_error(const int8_t e, const char * const serial_msg, con if (e >= 0) SERIAL_ERRORLN((int)e); else SERIAL_ERRORLNPGM(MSG_HEATER_BED); } #if DISABLED(BOGUS_TEMPERATURE_FAILSAFE_OVERRIDE) + static bool killed = false; if (!killed) { Running = false; killed = true; @@ -1770,8 +1743,89 @@ void Temperature::set_current_temp_raw() { } #endif // PINS_DEBUGGING +#if ENABLED(FILAMENT_WIDTH_SENSOR) + uint32_t raw_filwidth_value; // = 0 +#endif + +void Temperature::readings_ready() { + // Update the raw values if they've been read. Else we could be updating them during reading. + if (!temp_meas_ready) set_current_temp_raw(); + + // Filament Sensor - can be read any time since IIR filtering is used + #if ENABLED(FILAMENT_WIDTH_SENSOR) + current_raw_filwidth = raw_filwidth_value >> 10; // Divide to get to 0-16384 range since we used 1/128 IIR filter approach + #endif + + ZERO(raw_temp_value); + + #if HAS_HEATED_BED + raw_temp_bed_value = 0; + #endif + + #if HAS_TEMP_CHAMBER + raw_temp_chamber_value = 0; + #endif + + #define TEMPDIR(N) ((HEATER_##N##_RAW_LO_TEMP) > (HEATER_##N##_RAW_HI_TEMP) ? -1 : 1) + + int constexpr temp_dir[] = { + #if ENABLED(HEATER_0_USES_MAX6675) + 0 + #else + TEMPDIR(0) + #endif + #if HOTENDS > 1 + , TEMPDIR(1) + #if HOTENDS > 2 + , TEMPDIR(2) + #if HOTENDS > 3 + , TEMPDIR(3) + #if HOTENDS > 4 + , TEMPDIR(4) + #endif // HOTENDS > 4 + #endif // HOTENDS > 3 + #endif // HOTENDS > 2 + #endif // HOTENDS > 1 + }; + + for (uint8_t e = 0; e < COUNT(temp_dir); e++) { + const int16_t tdir = temp_dir[e], rawtemp = current_temperature_raw[e] * tdir; + const bool heater_on = (target_temperature[e] > 0) + #if ENABLED(PIDTEMP) + || (soft_pwm_amount[e] > 0) + #endif + ; + if (rawtemp > maxttemp_raw[e] * tdir) max_temp_error(e); + if (rawtemp < minttemp_raw[e] * tdir && !is_preheating(e) && heater_on) { + #ifdef MAX_CONSECUTIVE_LOW_TEMPERATURE_ERROR_ALLOWED + if (++consecutive_low_temperature_error[e] >= MAX_CONSECUTIVE_LOW_TEMPERATURE_ERROR_ALLOWED) + #endif + min_temp_error(e); + } + #ifdef MAX_CONSECUTIVE_LOW_TEMPERATURE_ERROR_ALLOWED + else + consecutive_low_temperature_error[e] = 0; + #endif + } + + #if HAS_HEATED_BED + #if HEATER_BED_RAW_LO_TEMP > HEATER_BED_RAW_HI_TEMP + #define GEBED <= + #else + #define GEBED >= + #endif + const bool bed_on = (target_temperature_bed > 0) + #if ENABLED(PIDTEMPBED) + || (soft_pwm_amount_bed > 0) + #endif + ; + if (current_temperature_bed_raw GEBED bed_maxttemp_raw) max_temp_error(-1); + if (bed_minttemp_raw GEBED current_temperature_bed_raw && bed_on) min_temp_error(-1); + #endif +} + /** - * Timer 0 is shared with millies so don't change the prescaler. + * Timer 0 is shared with millis so don't change the prescaler. * * This ISR uses the compare method so it runs at the base * frequency (16 MHz / 64 / 256 = 976.5625 Hz), but at the TCNT0 set @@ -1833,10 +1887,6 @@ void Temperature::isr() { ISR_STATICS(BED); #endif - #if ENABLED(FILAMENT_WIDTH_SENSOR) - static unsigned long raw_filwidth_value = 0; - #endif - #if DISABLED(SLOW_PWM_HEATERS) constexpr uint8_t pwm_mask = #if ENABLED(SOFT_PWM_DITHER) @@ -2087,6 +2137,12 @@ void Temperature::isr() { * * This gives each ADC 0.9765ms to charge up. */ + #define ACCUMULATE_ADC(var) do{ \ + if (!HAL_ADC_READY()) next_sensor_state = adc_sensor_state; \ + else var += HAL_READ_ADC(); \ + }while(0) + + ADCSensorState next_sensor_state = adc_sensor_state < SensorsReady ? (ADCSensorState)(int(adc_sensor_state) + 1) : StartSampling; switch (adc_sensor_state) { @@ -2096,21 +2152,30 @@ void Temperature::isr() { constexpr int8_t extra_loops = MIN_ADC_ISR_LOOPS - (int8_t)SensorsReady; static uint8_t delay_count = 0; if (extra_loops > 0) { - if (delay_count == 0) delay_count = extra_loops; // Init this delay - if (--delay_count) // While delaying... - adc_sensor_state = (ADCSensorState)(int(SensorsReady) - 1); // retain this state (else, next state will be 0) + if (delay_count == 0) delay_count = extra_loops; // Init this delay + if (--delay_count) // While delaying... + next_sensor_state = SensorsReady; // retain this state (else, next state will be 0) break; } - else - adc_sensor_state = (ADCSensorState)0; // Fall-through to start first sensor now + else { + adc_sensor_state = StartSampling; // Fall-through to start sampling + next_sensor_state = (ADCSensorState)(int(StartSampling) + 1); + } } + case StartSampling: // Start of sampling loops. Do updates/checks. + if (++temp_count >= OVERSAMPLENR) { // 10 * 16 * 1/(16000000/64/256) = 164ms. + temp_count = 0; + readings_ready(); + } + break; + #if HAS_TEMP_ADC_0 case PrepareTemp_0: HAL_START_ADC(TEMP_0_PIN); break; case MeasureTemp_0: - raw_temp_value[0] += HAL_READ_ADC; + ACCUMULATE_ADC(raw_temp_value[0]); break; #endif @@ -2119,7 +2184,7 @@ void Temperature::isr() { HAL_START_ADC(TEMP_BED_PIN); break; case MeasureTemp_BED: - raw_temp_bed_value += HAL_READ_ADC; + ACCUMULATE_ADC(raw_temp_bed_value); break; #endif @@ -2128,7 +2193,7 @@ void Temperature::isr() { HAL_START_ADC(TEMP_CHAMBER_PIN); break; case MeasureTemp_CHAMBER: - raw_temp_chamber_value += HAL_READ_ADC; + ACCUMULATE_ADC(raw_temp_chamber_value); break; #endif @@ -2137,7 +2202,7 @@ void Temperature::isr() { HAL_START_ADC(TEMP_1_PIN); break; case MeasureTemp_1: - raw_temp_value[1] += HAL_READ_ADC; + ACCUMULATE_ADC(raw_temp_value[1]); break; #endif @@ -2146,7 +2211,7 @@ void Temperature::isr() { HAL_START_ADC(TEMP_2_PIN); break; case MeasureTemp_2: - raw_temp_value[2] += HAL_READ_ADC; + ACCUMULATE_ADC(raw_temp_value[2]); break; #endif @@ -2155,7 +2220,7 @@ void Temperature::isr() { HAL_START_ADC(TEMP_3_PIN); break; case MeasureTemp_3: - raw_temp_value[3] += HAL_READ_ADC; + ACCUMULATE_ADC(raw_temp_value[3]); break; #endif @@ -2164,7 +2229,7 @@ void Temperature::isr() { HAL_START_ADC(TEMP_4_PIN); break; case MeasureTemp_4: - raw_temp_value[4] += HAL_READ_ADC; + ACCUMULATE_ADC(raw_temp_value[4]); break; #endif @@ -2173,9 +2238,11 @@ void Temperature::isr() { HAL_START_ADC(FILWIDTH_PIN); break; case Measure_FILWIDTH: - if (HAL_READ_ADC > 102) { // Make sure ADC is reading > 0.5 volts, otherwise don't read. - raw_filwidth_value -= (raw_filwidth_value >> 7); // Subtract 1/128th of the raw_filwidth_value - raw_filwidth_value += ((unsigned long)HAL_READ_ADC << 7); // Add new ADC reading, scaled by 128 + if (!HAL_ADC_READY()) + next_sensor_state = adc_sensor_state; // redo this state + else if (HAL_READ_ADC() > 102) { // Make sure ADC is reading > 0.5 volts, otherwise don't read. + raw_filwidth_value -= raw_filwidth_value >> 7; // Subtract 1/128th of the raw_filwidth_value + raw_filwidth_value += uint32_t(HAL_READ_ADC()) << 7; // Add new ADC reading, scaled by 128 } break; #endif @@ -2185,8 +2252,10 @@ void Temperature::isr() { HAL_START_ADC(ADC_KEYPAD_PIN); break; case Measure_ADC_KEY: - if (ADCKey_count < 16) { - raw_ADCKey_value = HAL_READ_ADC; + if (!HAL_ADC_READY()) + next_sensor_state = adc_sensor_state; // redo this state + else if (ADCKey_count < 16) { + raw_ADCKey_value = HAL_READ_ADC(); if (raw_ADCKey_value > 900) { //ADC Key release ADCKey_count = 0; @@ -2204,94 +2273,12 @@ void Temperature::isr() { } // switch(adc_sensor_state) - if (!adc_sensor_state && ++temp_count >= OVERSAMPLENR) { // 10 * 16 * 1/(16000000/64/256) = 164ms. + // Go to the next state + adc_sensor_state = next_sensor_state; - temp_count = 0; - - // Update the raw values if they've been read. Else we could be updating them during reading. - if (!temp_meas_ready) set_current_temp_raw(); - - // Filament Sensor - can be read any time since IIR filtering is used - #if ENABLED(FILAMENT_WIDTH_SENSOR) - current_raw_filwidth = raw_filwidth_value >> 10; // Divide to get to 0-16384 range since we used 1/128 IIR filter approach - #endif - - ZERO(raw_temp_value); - - #if HAS_HEATED_BED - raw_temp_bed_value = 0; - #endif - - #if HAS_TEMP_CHAMBER - raw_temp_chamber_value = 0; - #endif - - #define TEMPDIR(N) ((HEATER_##N##_RAW_LO_TEMP) > (HEATER_##N##_RAW_HI_TEMP) ? -1 : 1) - - int constexpr temp_dir[] = { - #if ENABLED(HEATER_0_USES_MAX6675) - 0 - #else - TEMPDIR(0) - #endif - #if HOTENDS > 1 - , TEMPDIR(1) - #if HOTENDS > 2 - , TEMPDIR(2) - #if HOTENDS > 3 - , TEMPDIR(3) - #if HOTENDS > 4 - , TEMPDIR(4) - #endif // HOTENDS > 4 - #endif // HOTENDS > 3 - #endif // HOTENDS > 2 - #endif // HOTENDS > 1 - }; - - for (uint8_t e = 0; e < COUNT(temp_dir); e++) { - const int16_t tdir = temp_dir[e], rawtemp = current_temperature_raw[e] * tdir; - const bool heater_on = 0 < - #if ENABLED(PIDTEMP) - soft_pwm_amount[e] - #else - target_temperature[e] - #endif - ; - if (rawtemp > maxttemp_raw[e] * tdir && heater_on) max_temp_error(e); - if (rawtemp < minttemp_raw[e] * tdir && !is_preheating(e) && heater_on) { - #ifdef MAX_CONSECUTIVE_LOW_TEMPERATURE_ERROR_ALLOWED - if (++consecutive_low_temperature_error[e] >= MAX_CONSECUTIVE_LOW_TEMPERATURE_ERROR_ALLOWED) - #endif - min_temp_error(e); - } - #ifdef MAX_CONSECUTIVE_LOW_TEMPERATURE_ERROR_ALLOWED - else - consecutive_low_temperature_error[e] = 0; - #endif - } - - #if HAS_HEATED_BED - #if HEATER_BED_RAW_LO_TEMP > HEATER_BED_RAW_HI_TEMP - #define GEBED <= - #else - #define GEBED >= - #endif - const bool bed_on = 0 < - #if ENABLED(PIDTEMPBED) - soft_pwm_amount_bed - #else - target_temperature_bed - #endif - ; - if (current_temperature_bed_raw GEBED bed_maxttemp_raw && bed_on) max_temp_error(-1); - if (bed_minttemp_raw GEBED current_temperature_bed_raw && bed_on) min_temp_error(-1); - #endif - - } // temp_count >= OVERSAMPLENR - - // Go to the next state, up to SensorsReady - adc_sensor_state = (ADCSensorState)(int(adc_sensor_state) + 1); - if (adc_sensor_state > SensorsReady) adc_sensor_state = (ADCSensorState)0; + // + // Additional ~1KHz Tasks + // #if ENABLED(BABYSTEPPING) LOOP_XYZ(axis) { diff --git a/Marlin/temperature.h b/Marlin/temperature.h index 1112e1799e..cc6df0bdf7 100644 --- a/Marlin/temperature.h +++ b/Marlin/temperature.h @@ -59,6 +59,7 @@ * States for ADC reading in the ISR */ enum ADCSensorState : char { + StartSampling, #if HAS_TEMP_ADC_0 PrepareTemp_0, MeasureTemp_0, @@ -329,6 +330,7 @@ class Temperature { /** * Called from the Temperature ISR */ + static void readings_ready(); static void isr(); /** diff --git a/Marlin/thermistortable_501.h b/Marlin/thermistortable_501.h index 512ac0d8d8..ac40d119b3 100644 --- a/Marlin/thermistortable_501.h +++ b/Marlin/thermistortable_501.h @@ -28,8 +28,8 @@ const short temptable_501[][2] PROGMEM = { {OV( 19), 280}, {OV( 23), 270}, {OV( 27), 260}, - {OV( 32), 250}, - {OV( 30), 240}, + {OV( 31), 250}, + {OV( 37), 240}, {OV( 47), 230}, {OV( 57), 220}, {OV( 68), 210}, diff --git a/Marlin/thermistortable_71.h b/Marlin/thermistortable_71.h index c7b8a64e30..f28a4ceabb 100644 --- a/Marlin/thermistortable_71.h +++ b/Marlin/thermistortable_71.h @@ -28,78 +28,26 @@ // R2 = 4700 Ohm const short temptable_71[][2] PROGMEM = { { OV( 35), 300 }, - { OV( 51), 270 }, - { OV( 54), 265 }, - { OV( 58), 260 }, + { OV( 51), 269 }, { OV( 59), 258 }, - { OV( 61), 256 }, - { OV( 63), 254 }, { OV( 64), 252 }, - { OV( 66), 250 }, - { OV( 67), 249 }, - { OV( 68), 248 }, - { OV( 69), 247 }, - { OV( 70), 246 }, - { OV( 71), 245 }, - { OV( 72), 244 }, - { OV( 73), 243 }, - { OV( 74), 242 }, - { OV( 75), 241 }, - { OV( 76), 240 }, - { OV( 77), 239 }, - { OV( 78), 238 }, - { OV( 79), 237 }, - { OV( 80), 236 }, + { OV( 71), 244 }, { OV( 81), 235 }, - { OV( 82), 234 }, - { OV( 84), 233 }, - { OV( 85), 232 }, - { OV( 86), 231 }, { OV( 87), 230 }, - { OV( 89), 229 }, - { OV( 90), 228 }, - { OV( 91), 227 }, { OV( 92), 226 }, - { OV( 94), 225 }, - { OV( 95), 224 }, - { OV( 97), 223 }, - { OV( 98), 222 }, - { OV( 99), 221 }, - { OV( 101), 220 }, { OV( 102), 219 }, - { OV( 104), 218 }, - { OV( 106), 217 }, - { OV( 107), 216 }, - { OV( 109), 215 }, { OV( 110), 214 }, - { OV( 112), 213 }, - { OV( 114), 212 }, { OV( 115), 211 }, - { OV( 117), 210 }, - { OV( 119), 209 }, - { OV( 121), 208 }, - { OV( 123), 207 }, - { OV( 125), 206 }, { OV( 126), 205 }, { OV( 128), 204 }, { OV( 130), 203 }, { OV( 132), 202 }, { OV( 134), 201 }, { OV( 136), 200 }, - { OV( 139), 199 }, - { OV( 141), 198 }, - { OV( 143), 197 }, - { OV( 145), 196 }, { OV( 147), 195 }, - { OV( 150), 194 }, - { OV( 152), 193 }, { OV( 154), 192 }, - { OV( 157), 191 }, { OV( 159), 190 }, - { OV( 162), 189 }, { OV( 164), 188 }, - { OV( 167), 187 }, - { OV( 170), 186 }, { OV( 172), 185 }, { OV( 175), 184 }, { OV( 178), 183 }, @@ -113,9 +61,7 @@ const short temptable_71[][2] PROGMEM = { { OV( 202), 175 }, { OV( 205), 174 }, { OV( 208), 173 }, - { OV( 212), 172 }, { OV( 215), 171 }, - { OV( 219), 170 }, { OV( 237), 165 }, { OV( 256), 160 }, { OV( 300), 150 }, @@ -123,46 +69,22 @@ const short temptable_71[][2] PROGMEM = { { OV( 470), 120 }, { OV( 504), 115 }, { OV( 538), 110 }, - { OV( 552), 108 }, - { OV( 566), 106 }, - { OV( 580), 104 }, - { OV( 594), 102 }, - { OV( 608), 100 }, - { OV( 622), 98 }, - { OV( 636), 96 }, - { OV( 650), 94 }, - { OV( 664), 92 }, - { OV( 678), 90 }, - { OV( 712), 85 }, { OV( 745), 80 }, - { OV( 758), 78 }, { OV( 770), 76 }, - { OV( 783), 74 }, - { OV( 795), 72 }, { OV( 806), 70 }, - { OV( 818), 68 }, { OV( 829), 66 }, - { OV( 840), 64 }, - { OV( 850), 62 }, { OV( 860), 60 }, - { OV( 870), 58 }, { OV( 879), 56 }, { OV( 888), 54 }, - { OV( 897), 52 }, { OV( 905), 50 }, { OV( 924), 45 }, { OV( 940), 40 }, { OV( 955), 35 }, - { OV( 967), 30 }, - { OV( 970), 29 }, { OV( 972), 28 }, { OV( 974), 27 }, { OV( 976), 26 }, { OV( 978), 25 }, { OV( 980), 24 }, - { OV( 982), 23 }, - { OV( 984), 22 }, - { OV( 985), 21 }, { OV( 987), 20 }, { OV( 995), 15 }, { OV(1001), 10 }, diff --git a/Marlin/thermistortables.h b/Marlin/thermistortables.h index 462337778d..a65d3eb501 100644 --- a/Marlin/thermistortables.h +++ b/Marlin/thermistortables.h @@ -204,8 +204,8 @@ #endif // The SCAN_THERMISTOR_TABLE macro needs alteration? -static_assert(HEATER_0_TEMPTABLE_LEN < 128 && HEATER_1_TEMPTABLE_LEN < 128 && HEATER_2_TEMPTABLE_LEN < 128 && HEATER_3_TEMPTABLE_LEN < 128 && HEATER_4_TEMPTABLE_LEN < 128 && BEDTEMPTABLE_LEN < 128 && CHAMBERTEMPTABLE_LEN < 128, - "Temperature conversion tables over 127 entries need special consideration." +static_assert(HEATER_0_TEMPTABLE_LEN < 256 && HEATER_1_TEMPTABLE_LEN < 256 && HEATER_2_TEMPTABLE_LEN < 256 && HEATER_3_TEMPTABLE_LEN < 256 && HEATER_4_TEMPTABLE_LEN < 256 && BEDTEMPTABLE_LEN < 256 && CHAMBERTEMPTABLE_LEN < 256, + "Temperature conversion tables over 255 entries need special consideration." ); // Set the high and low raw values for the heaters diff --git a/Marlin/tmc_util.cpp b/Marlin/tmc_util.cpp index 662fbc176c..2e9ba5575c 100644 --- a/Marlin/tmc_util.cpp +++ b/Marlin/tmc_util.cpp @@ -50,7 +50,7 @@ bool report_tmc_status = false; bool is_ot; bool is_error; }; - #if ENABLED(HAVE_TMC2130) + #if HAS_DRIVER(TMC2130) static uint32_t get_pwm_scale(TMC2130Stepper &st) { return st.PWM_SCALE(); } static uint8_t get_status_response(TMC2130Stepper &st) { return st.status_response & 0xF; } static TMC_driver_data get_driver_data(TMC2130Stepper &st) { @@ -68,7 +68,7 @@ bool report_tmc_status = false; return data; } #endif - #if ENABLED(HAVE_TMC2208) + #if HAS_DRIVER(TMC2208) static uint32_t get_pwm_scale(TMC2208Stepper &st) { return st.pwm_scale_sum(); } static uint8_t get_status_response(TMC2208Stepper &st) { uint32_t drv_status = st.DRV_STATUS(); @@ -157,21 +157,21 @@ bool report_tmc_status = false; } } - #define HAS_HW_COMMS(ST) ENABLED(ST##_IS_TMC2130)|| (ENABLED(ST##_IS_TMC2208) && defined(ST##_HARDWARE_SERIAL)) + #define HAS_HW_COMMS(ST) AXIS_DRIVER_TYPE(ST, TMC2130) || (AXIS_DRIVER_TYPE(ST, TMC2208) && defined(ST##_HARDWARE_SERIAL)) void monitor_tmc_driver() { static millis_t next_cOT = 0; if (ELAPSED(millis(), next_cOT)) { next_cOT = millis() + 500; - #if HAS_HW_COMMS(X) || ENABLED(IS_TRAMS) + #if HAS_HW_COMMS(X) static uint8_t x_otpw_cnt = 0; monitor_tmc_driver(stepperX, TMC_X, x_otpw_cnt); #endif - #if HAS_HW_COMMS(Y) || ENABLED(IS_TRAMS) + #if HAS_HW_COMMS(Y) static uint8_t y_otpw_cnt = 0; monitor_tmc_driver(stepperY, TMC_Y, y_otpw_cnt); #endif - #if HAS_HW_COMMS(Z) || ENABLED(IS_TRAMS) + #if HAS_HW_COMMS(Z) static uint8_t z_otpw_cnt = 0; monitor_tmc_driver(stepperZ, TMC_Z, z_otpw_cnt); #endif @@ -187,7 +187,7 @@ bool report_tmc_status = false; static uint8_t z2_otpw_cnt = 0; monitor_tmc_driver(stepperZ2, TMC_Z, z2_otpw_cnt); #endif - #if HAS_HW_COMMS(E0) || ENABLED(IS_TRAMS) + #if HAS_HW_COMMS(E0) static uint8_t e0_otpw_cnt = 0; monitor_tmc_driver(stepperE0, TMC_E0, e0_otpw_cnt); #endif @@ -309,7 +309,7 @@ void _tmc_say_sgt(const TMC_AxisEnum axis, const int8_t sgt) { SERIAL_EOL(); } - #if ENABLED(HAVE_TMC2130) + #if HAS_DRIVER(TMC2130) static void tmc_status(TMC2130Stepper &st, const TMC_debug_enum i) { switch (i) { case TMC_PWM_SCALE: SERIAL_PRINT(st.PWM_SCALE(), DEC); break; @@ -329,7 +329,7 @@ void _tmc_say_sgt(const TMC_AxisEnum axis, const int8_t sgt) { } #endif - #if ENABLED(HAVE_TMC2208) + #if HAS_DRIVER(TMC2208) static void tmc_status(TMC2208Stepper &st, const TMC_debug_enum i) { switch (i) { case TMC_TSTEP: { uint32_t data = 0; st.TSTEP(&data); SERIAL_PROTOCOL(data); break; } @@ -418,52 +418,52 @@ void _tmc_say_sgt(const TMC_AxisEnum axis, const int8_t sgt) { } static void tmc_debug_loop(const TMC_debug_enum i) { - #if X_IS_TRINAMIC + #if AXIS_IS_TMC(X) tmc_status(stepperX, TMC_X, i, planner.axis_steps_per_mm[X_AXIS]); #endif - #if X2_IS_TRINAMIC + #if AXIS_IS_TMC(X2) tmc_status(stepperX2, TMC_X2, i, planner.axis_steps_per_mm[X_AXIS]); #endif - #if Y_IS_TRINAMIC + #if AXIS_IS_TMC(Y) tmc_status(stepperY, TMC_Y, i, planner.axis_steps_per_mm[Y_AXIS]); #endif - #if Y2_IS_TRINAMIC + #if AXIS_IS_TMC(Y2) tmc_status(stepperY2, TMC_Y2, i, planner.axis_steps_per_mm[Y_AXIS]); #endif - #if Z_IS_TRINAMIC + #if AXIS_IS_TMC(Z) tmc_status(stepperZ, TMC_Z, i, planner.axis_steps_per_mm[Z_AXIS]); #endif - #if Z2_IS_TRINAMIC + #if AXIS_IS_TMC(Z2) tmc_status(stepperZ2, TMC_Z2, i, planner.axis_steps_per_mm[Z_AXIS]); #endif - #if E0_IS_TRINAMIC + #if AXIS_IS_TMC(E0) tmc_status(stepperE0, TMC_E0, i, planner.axis_steps_per_mm[E_AXIS]); #endif - #if E1_IS_TRINAMIC + #if AXIS_IS_TMC(E1) tmc_status(stepperE1, TMC_E1, i, planner.axis_steps_per_mm[E_AXIS #if ENABLED(DISTINCT_E_FACTORS) + 1 #endif ]); #endif - #if E2_IS_TRINAMIC + #if AXIS_IS_TMC(E2) tmc_status(stepperE2, TMC_E2, i, planner.axis_steps_per_mm[E_AXIS #if ENABLED(DISTINCT_E_FACTORS) + 2 #endif ]); #endif - #if E3_IS_TRINAMIC + #if AXIS_IS_TMC(E3) tmc_status(stepperE3, TMC_E3, i, planner.axis_steps_per_mm[E_AXIS #if ENABLED(DISTINCT_E_FACTORS) + 3 #endif ]); #endif - #if E4_IS_TRINAMIC + #if AXIS_IS_TMC(E4) tmc_status(stepperE4, TMC_E4, i, planner.axis_steps_per_mm[E_AXIS #if ENABLED(DISTINCT_E_FACTORS) + 4 @@ -475,40 +475,40 @@ void _tmc_say_sgt(const TMC_AxisEnum axis, const int8_t sgt) { } static void drv_status_loop(const TMC_drv_status_enum i) { - #if X_IS_TRINAMIC + #if AXIS_IS_TMC(X) tmc_parse_drv_status(stepperX, TMC_X, i); #endif - #if X2_IS_TRINAMIC + #if AXIS_IS_TMC(X2) tmc_parse_drv_status(stepperX2, TMC_X2, i); #endif - #if Y_IS_TRINAMIC + #if AXIS_IS_TMC(Y) tmc_parse_drv_status(stepperY, TMC_Y, i); #endif - #if Y2_IS_TRINAMIC + #if AXIS_IS_TMC(Y2) tmc_parse_drv_status(stepperY2, TMC_Y2, i); #endif - #if Z_IS_TRINAMIC + #if AXIS_IS_TMC(Z) tmc_parse_drv_status(stepperZ, TMC_Z, i); #endif - #if Z2_IS_TRINAMIC + #if AXIS_IS_TMC(Z2) tmc_parse_drv_status(stepperZ2, TMC_Z2, i); #endif - #if E0_IS_TRINAMIC + #if AXIS_IS_TMC(E0) tmc_parse_drv_status(stepperE0, TMC_E0, i); #endif - #if E1_IS_TRINAMIC + #if AXIS_IS_TMC(E1) tmc_parse_drv_status(stepperE1, TMC_E1, i); #endif - #if E2_IS_TRINAMIC + #if AXIS_IS_TMC(E2) tmc_parse_drv_status(stepperE2, TMC_E2, i); #endif - #if E3_IS_TRINAMIC + #if AXIS_IS_TMC(E3) tmc_parse_drv_status(stepperE3, TMC_E3, i); #endif - #if E4_IS_TRINAMIC + #if AXIS_IS_TMC(E4) tmc_parse_drv_status(stepperE4, TMC_E4, i); #endif @@ -551,7 +551,7 @@ void _tmc_say_sgt(const TMC_AxisEnum axis, const int8_t sgt) { TMC_REPORT("Stallguard thrs", TMC_SGT); DRV_REPORT("DRVSTATUS", TMC_DRV_CODES); - #if ENABLED(HAVE_TMC2130) + #if HAS_DRIVER(TMC2130) DRV_REPORT("stallguard\t", TMC_STALLGUARD); DRV_REPORT("sg_result\t", TMC_SG_RESULT); DRV_REPORT("fsactive\t", TMC_FSACTIVE); @@ -563,7 +563,7 @@ void _tmc_say_sgt(const TMC_AxisEnum axis, const int8_t sgt) { DRV_REPORT("s2ga\t", TMC_S2GA); DRV_REPORT("otpw\t", TMC_DRV_OTPW); DRV_REPORT("ot\t", TMC_OT); - #if ENABLED(HAVE_TMC2208) + #if HAS_DRIVER(TMC2208) DRV_REPORT("157C\t", TMC_T157); DRV_REPORT("150C\t", TMC_T150); DRV_REPORT("143C\t", TMC_T143); @@ -589,43 +589,43 @@ void _tmc_say_sgt(const TMC_AxisEnum axis, const int8_t sgt) { #endif // SENSORLESS_HOMING -#if ENABLED(HAVE_TMC2130) +#if HAS_DRIVER(TMC2130) #define SET_CS_PIN(st) OUT_WRITE(st##_CS_PIN, HIGH) void tmc_init_cs_pins() { - #if ENABLED(X_IS_TMC2130) + #if AXIS_DRIVER_TYPE(X, TMC2130) SET_CS_PIN(X); #endif - #if ENABLED(Y_IS_TMC2130) + #if AXIS_DRIVER_TYPE(Y, TMC2130) SET_CS_PIN(Y); #endif - #if ENABLED(Z_IS_TMC2130) + #if AXIS_DRIVER_TYPE(Z, TMC2130) SET_CS_PIN(Z); #endif - #if ENABLED(X2_IS_TMC2130) + #if AXIS_DRIVER_TYPE(X2, TMC2130) SET_CS_PIN(X2); #endif - #if ENABLED(Y2_IS_TMC2130) + #if AXIS_DRIVER_TYPE(Y2, TMC2130) SET_CS_PIN(Y2); #endif - #if ENABLED(Z2_IS_TMC2130) + #if AXIS_DRIVER_TYPE(Z2, TMC2130) SET_CS_PIN(Z2); #endif - #if ENABLED(E0_IS_TMC2130) + #if AXIS_DRIVER_TYPE(E0, TMC2130) SET_CS_PIN(E0); #endif - #if ENABLED(E1_IS_TMC2130) + #if AXIS_DRIVER_TYPE(E1, TMC2130) SET_CS_PIN(E1); #endif - #if ENABLED(E2_IS_TMC2130) + #if AXIS_DRIVER_TYPE(E2, TMC2130) SET_CS_PIN(E2); #endif - #if ENABLED(E3_IS_TMC2130) + #if AXIS_DRIVER_TYPE(E3, TMC2130) SET_CS_PIN(E3); #endif - #if ENABLED(E4_IS_TMC2130) + #if AXIS_DRIVER_TYPE(E4, TMC2130) SET_CS_PIN(E4); #endif } -#endif // HAVE_TMC2130 +#endif // TMC2130 #endif // HAS_TRINAMIC diff --git a/Marlin/tmc_util.h b/Marlin/tmc_util.h index 08d461e424..7efe67a502 100644 --- a/Marlin/tmc_util.h +++ b/Marlin/tmc_util.h @@ -25,11 +25,11 @@ #include "MarlinConfig.h" -#if ENABLED(HAVE_TMC2130) +#if HAS_DRIVER(TMC2130) #include #endif -#if ENABLED(HAVE_TMC2208) +#if HAS_DRIVER(TMC2208) #include #endif @@ -100,7 +100,7 @@ void monitor_tmc_driver(); void tmc_sensorless_homing(TMC2130Stepper &st, const bool enable=true); #endif -#if ENABLED(HAVE_TMC2130) +#if HAS_DRIVER(TMC2130) void tmc_init_cs_pins(); #endif diff --git a/Marlin/twibus.cpp b/Marlin/twibus.cpp index 777d151e4f..5156c89797 100644 --- a/Marlin/twibus.cpp +++ b/Marlin/twibus.cpp @@ -55,7 +55,7 @@ void TWIBus::address(const uint8_t adr) { #endif } -void TWIBus::addbyte(const char c) { +void TWIBus::addbyte(const byte c) { if (this->buffer_s >= COUNT(this->buffer)) return; this->buffer[this->buffer_s++] = c; #if ENABLED(DEBUG_TWIBUS) @@ -63,7 +63,7 @@ void TWIBus::addbyte(const char c) { #endif } -void TWIBus::addbytes(char src[], uint8_t bytes) { +void TWIBus::addbytes(byte src[], uint8_t bytes) { #if ENABLED(DEBUG_TWIBUS) debug(PSTR("addbytes"), bytes); #endif @@ -138,7 +138,7 @@ void TWIBus::relay(const uint8_t bytes) { echodata(bytes, PSTR("i2c-reply"), this->addr); } -uint8_t TWIBus::capture(char *dst, const uint8_t bytes) { +uint8_t TWIBus::capture(byte *dst, const uint8_t bytes) { this->reset(); uint8_t count = 0; while (count < bytes && Wire.available()) diff --git a/Marlin/twibus.h b/Marlin/twibus.h index 03763972a7..8759c40dba 100644 --- a/Marlin/twibus.h +++ b/Marlin/twibus.h @@ -33,6 +33,13 @@ typedef void (*twiReceiveFunc_t)(int bytes); typedef void (*twiRequestFunc_t)(); +#if ENABLED(MECHADUINO_I2C_COMMANDS) + typedef union { + float fval; + byte bval[sizeof(float)]; + } i2cFloat; +#endif + #define TWIBUS_BUFFER_SIZE 32 /** @@ -99,7 +106,7 @@ class TWIBus { * * @param c a data byte */ - void addbyte(const char c); + void addbyte(const byte c); /** * @brief Add some bytes to the buffer @@ -109,7 +116,7 @@ class TWIBus { * @param src source data address * @param bytes the number of bytes to add */ - void addbytes(char src[], uint8_t bytes); + void addbytes(byte src[], uint8_t bytes); /** * @brief Add a null-terminated string to the buffer @@ -172,7 +179,7 @@ class TWIBus { * @param bytes the number of bytes to request * @return the number of bytes captured to the buffer */ - uint8_t capture(char *dst, const uint8_t bytes); + uint8_t capture(byte *dst, const uint8_t bytes); /** * @brief Flush the i2c bus. diff --git a/Marlin/ubl.cpp b/Marlin/ubl.cpp index df9c212bbf..26485c5d02 100644 --- a/Marlin/ubl.cpp +++ b/Marlin/ubl.cpp @@ -76,7 +76,7 @@ // ignore the status of the g26_debug_flag if (*title != '!' && !g26_debug_flag) return; - const float de = destination[E_AXIS] - current_position[E_AXIS]; + const float de = destination[E_CART] - current_position[E_CART]; if (de == 0.0) return; // Printing moves only @@ -97,7 +97,7 @@ SERIAL_ECHOPGM(", "); SERIAL_ECHO_F(current_position[Z_AXIS], 6); SERIAL_ECHOPGM(", "); - SERIAL_ECHO_F(current_position[E_AXIS], 6); + SERIAL_ECHO_F(current_position[E_CART], 6); SERIAL_ECHOPGM(" ) destination=( "); debug_echo_axis(X_AXIS); SERIAL_ECHOPGM(", "); diff --git a/Marlin/ubl.h b/Marlin/ubl.h index 873e5e6ec4..03380af452 100644 --- a/Marlin/ubl.h +++ b/Marlin/ubl.h @@ -54,7 +54,6 @@ enum MeshPointType : char { INVALID, REAL, SET_IN_BITMAP }; // External references char *ftostr43sign(const float&, char); -void home_all_axes(); extern uint8_t ubl_cnt; diff --git a/Marlin/ubl_G29.cpp b/Marlin/ubl_G29.cpp index 0286a76858..c401fa6962 100644 --- a/Marlin/ubl_G29.cpp +++ b/Marlin/ubl_G29.cpp @@ -296,10 +296,10 @@ // Check for commands that require the printer to be homed if (may_move) { - if (axis_unhomed_error()) home_all_axes(); #if ENABLED(DUAL_X_CARRIAGE) if (active_extruder != 0) tool_change(0); #endif + if (axis_unhomed_error()) home_all_axes(); } // Invalidate Mesh Points. This command is a little bit asymmetrical because @@ -1559,12 +1559,12 @@ incremental_LSF(&lsf_results, PROBE_PT_3_X, PROBE_PT_3_Y, measured_z); } } - + STOW_PROBE(); #ifdef Z_AFTER_PROBING move_z_after_probing(); #endif - + if (abort_flag) { SERIAL_ECHOPGM("?Error probing point. Aborting operation.\n"); return; @@ -1625,7 +1625,7 @@ #ifdef Z_AFTER_PROBING move_z_after_probing(); #endif - + if (abort_flag || finish_incremental_LSF(&lsf_results)) { SERIAL_ECHOPGM("Could not complete LSF!"); return; diff --git a/Marlin/ubl_motion.cpp b/Marlin/ubl_motion.cpp index 5272e20795..0751c95720 100644 --- a/Marlin/ubl_motion.cpp +++ b/Marlin/ubl_motion.cpp @@ -46,8 +46,8 @@ */ #if ENABLED(SKEW_CORRECTION) // For skew correction just adjust the destination point and we're done - float start[XYZE] = { current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS] }, - end[XYZE] = { destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS] }; + float start[XYZE] = { current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_CART] }, + end[XYZE] = { destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_CART] }; planner.skew(start[X_AXIS], start[Y_AXIS], start[Z_AXIS]); planner.skew(end[X_AXIS], end[Y_AXIS], end[Z_AXIS]); #else @@ -64,7 +64,7 @@ SERIAL_ECHOPAIR(" ubl.line_to_destination_cartesian(xe=", destination[X_AXIS]); SERIAL_ECHOPAIR(", ye=", destination[Y_AXIS]); SERIAL_ECHOPAIR(", ze=", destination[Z_AXIS]); - SERIAL_ECHOPAIR(", ee=", destination[E_AXIS]); + SERIAL_ECHOPAIR(", ee=", destination[E_CART]); SERIAL_CHAR(')'); SERIAL_EOL(); debug_current_and_destination(PSTR("Start of ubl.line_to_destination_cartesian()")); @@ -85,7 +85,7 @@ + UBL_Z_RAISE_WHEN_OFF_MESH #endif ; - planner.buffer_segment(end[X_AXIS], end[Y_AXIS], end[Z_AXIS] + z_raise, end[E_AXIS], feed_rate, extruder); + planner.buffer_segment(end[X_AXIS], end[Y_AXIS], end[Z_AXIS] + z_raise, end[E_CART], feed_rate, extruder); set_current_from_destination(); if (g26_debug_flag) @@ -112,7 +112,7 @@ // Undefined parts of the Mesh in z_values[][] are NAN. // Replace NAN corrections with 0.0 to prevent NAN propagation. - planner.buffer_segment(end[X_AXIS], end[Y_AXIS], end[Z_AXIS] + (isnan(z0) ? 0.0 : z0), end[E_AXIS], feed_rate, extruder); + planner.buffer_segment(end[X_AXIS], end[Y_AXIS], end[Z_AXIS] + (isnan(z0) ? 0.0 : z0), end[E_CART], feed_rate, extruder); if (g26_debug_flag) debug_current_and_destination(PSTR("FINAL_MOVE in ubl.line_to_destination_cartesian()")); @@ -149,7 +149,7 @@ const bool use_x_dist = adx > ady; float on_axis_distance = use_x_dist ? dx : dy, - e_position = end[E_AXIS] - start[E_AXIS], + e_position = end[E_CART] - start[E_CART], z_position = end[Z_AXIS] - start[Z_AXIS]; const float e_normalized_dist = e_position / on_axis_distance, @@ -198,11 +198,11 @@ if (ry != start[Y_AXIS]) { if (!inf_normalized_flag) { on_axis_distance = use_x_dist ? rx - start[X_AXIS] : ry - start[Y_AXIS]; - e_position = start[E_AXIS] + on_axis_distance * e_normalized_dist; + e_position = start[E_CART] + on_axis_distance * e_normalized_dist; z_position = start[Z_AXIS] + on_axis_distance * z_normalized_dist; } else { - e_position = end[E_AXIS]; + e_position = end[E_CART]; z_position = end[Z_AXIS]; } @@ -249,11 +249,11 @@ if (rx != start[X_AXIS]) { if (!inf_normalized_flag) { on_axis_distance = use_x_dist ? rx - start[X_AXIS] : ry - start[Y_AXIS]; - e_position = start[E_AXIS] + on_axis_distance * e_normalized_dist; // is based on X or Y because this is a horizontal move + e_position = start[E_CART] + on_axis_distance * e_normalized_dist; // is based on X or Y because this is a horizontal move z_position = start[Z_AXIS] + on_axis_distance * z_normalized_dist; } else { - e_position = end[E_AXIS]; + e_position = end[E_CART]; z_position = end[Z_AXIS]; } @@ -308,11 +308,11 @@ if (!inf_normalized_flag) { on_axis_distance = use_x_dist ? rx - start[X_AXIS] : next_mesh_line_y - start[Y_AXIS]; - e_position = start[E_AXIS] + on_axis_distance * e_normalized_dist; + e_position = start[E_CART] + on_axis_distance * e_normalized_dist; z_position = start[Z_AXIS] + on_axis_distance * z_normalized_dist; } else { - e_position = end[E_AXIS]; + e_position = end[E_CART]; z_position = end[Z_AXIS]; } if (!planner.buffer_segment(rx, next_mesh_line_y, z_position + z0, e_position, feed_rate, extruder)) @@ -331,11 +331,11 @@ if (!inf_normalized_flag) { on_axis_distance = use_x_dist ? next_mesh_line_x - start[X_AXIS] : ry - start[Y_AXIS]; - e_position = start[E_AXIS] + on_axis_distance * e_normalized_dist; + e_position = start[E_CART] + on_axis_distance * e_normalized_dist; z_position = start[Z_AXIS] + on_axis_distance * z_normalized_dist; } else { - e_position = end[E_AXIS]; + e_position = end[E_CART]; z_position = end[Z_AXIS]; } @@ -378,7 +378,12 @@ #if ENABLED(DELTA) // apply delta inverse_kinematics DELTA_IK(raw); - planner.buffer_segment(delta[A_AXIS], delta[B_AXIS], delta[C_AXIS], in_raw[E_AXIS], fr, active_extruder); + planner.buffer_segment(delta[A_AXIS], delta[B_AXIS], delta[C_AXIS], in_raw[E_CART], fr, active_extruder); + + #elif ENABLED(HANGPRINTER) // apply hangprinter inverse_kinematics + + HANGPRINTER_IK(raw); + planner.buffer_segment(line_lengths[A_AXIS], line_lengths[B_AXIS], line_lengths[C_AXIS], line_lengths[D_AXIS], in_raw[E_CART], fr, active_extruder); #elif IS_SCARA // apply scara inverse_kinematics (should be changed to save raw->logical->raw) @@ -391,11 +396,11 @@ scara_oldB = delta[B_AXIS]; float s_feedrate = MAX(adiff, bdiff) * scara_feed_factor; - planner.buffer_segment(delta[A_AXIS], delta[B_AXIS], delta[C_AXIS], in_raw[E_AXIS], s_feedrate, active_extruder); + planner.buffer_segment(delta[A_AXIS], delta[B_AXIS], delta[C_AXIS], in_raw[E_CART], s_feedrate, active_extruder); #else // CARTESIAN - planner.buffer_segment(raw[X_AXIS], raw[Y_AXIS], raw[Z_AXIS], in_raw[E_AXIS], fr, active_extruder); + planner.buffer_segment(raw[X_AXIS], raw[Y_AXIS], raw[Z_AXIS], in_raw[E_CART], fr, active_extruder); #endif } @@ -427,7 +432,7 @@ rtarget[X_AXIS] - current_position[X_AXIS], rtarget[Y_AXIS] - current_position[Y_AXIS], rtarget[Z_AXIS] - current_position[Z_AXIS], - rtarget[E_AXIS] - current_position[E_AXIS] + rtarget[E_CART] - current_position[E_CART] }; const float cartesian_xy_mm = HYPOT(total[X_AXIS], total[Y_AXIS]); // total horizontal xy distance @@ -454,7 +459,7 @@ total[X_AXIS] * inv_segments, total[Y_AXIS] * inv_segments, total[Z_AXIS] * inv_segments, - total[E_AXIS] * inv_segments + total[E_CART] * inv_segments }; // Note that E segment distance could vary slightly as z mesh height @@ -464,7 +469,7 @@ current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], - current_position[E_AXIS] + current_position[E_CART] }; // Only compute leveling per segment if ubl active and target below z_fade_height. diff --git a/Marlin/ultralcd.cpp b/Marlin/ultralcd.cpp index 80aeadd29e..7ba2b94b72 100644 --- a/Marlin/ultralcd.cpp +++ b/Marlin/ultralcd.cpp @@ -265,8 +265,8 @@ uint16_t max_display_update_time = 0; #if ENABLED(SDSUPPORT) void lcd_sdcard_menu(); - void menu_action_sdfile(const char* filename, char* longFilename); - void menu_action_sddirectory(const char* filename, char* longFilename); + void menu_action_sdfile(CardReader& theCard); + void menu_action_sddirectory(CardReader& theCard); #endif //////////////////////////////////////////// @@ -756,7 +756,7 @@ void lcd_reset_status() { msg = paused; #if ENABLED(SDSUPPORT) else if (card.sdprinting) - return lcd_setstatus(card.longFilename[0] ? card.longFilename : card.filename, true); + return lcd_setstatus(card.longest_filename(), true); #endif else if (print_job_timer.isRunning()) msg = printing; @@ -874,7 +874,7 @@ void lcd_quick_feedback(const bool clear_buttons) { lcd_return_to_status(); // Turn leveling off and home - enqueue_and_echo_commands_P(PSTR("M420 S0\nG28" + enqueue_and_echo_commands_P(PSTR("M420 S0\nG28 R0" #if ENABLED(MARLIN_DEV_MODE) " S" #elif !IS_KINEMATIC @@ -1275,7 +1275,7 @@ void lcd_quick_feedback(const bool clear_buttons) { ubl_encoderPosition = (ubl.encoder_diff > 0) ? 1 : -1; ubl.encoder_diff = 0; - mesh_edit_accumulator += float(ubl_encoderPosition) * 0.005f / 2.0f; + mesh_edit_accumulator += float(ubl_encoderPosition) * 0.005f * 0.5f; mesh_edit_value = mesh_edit_accumulator; encoderPosition = 0; lcdDrawUpdate = LCDVIEW_CALL_REDRAW_NEXT; @@ -2414,9 +2414,6 @@ void lcd_quick_feedback(const bool clear_buttons) { void _lcd_ubl_output_map_lcd() { static int16_t step_scaler = 0; - if (!all_axes_known()) - return lcd_goto_screen(_lcd_ubl_map_homing); - if (use_click()) return _lcd_ubl_map_lcd_edit_cmd(); ENCODER_DIRECTION_NORMAL(); @@ -2678,6 +2675,13 @@ void lcd_quick_feedback(const bool clear_buttons) { MENU_ITEM(gcode, MSG_AUTO_HOME_Z, PSTR("G28 Z")); #endif + // + // TMC Z Calibration + // + #if ENABLED(TMC_Z_CALIBRATION) + MENU_ITEM(gcode, MSG_TMC_Z_CALIBRATION, PSTR("G28\nM915")); + #endif + // // Level Bed // @@ -2922,7 +2926,7 @@ void lcd_quick_feedback(const bool clear_buttons) { #if EXTRUDERS > 1 const int8_t old_extruder = active_extruder; - active_extruder = manual_move_e_index; + if (manual_move_axis == E_AXIS) active_extruder = manual_move_e_index; #endif // Set movement on a single axis @@ -2948,7 +2952,7 @@ void lcd_quick_feedback(const bool clear_buttons) { #else - planner.buffer_line_kinematic(current_position, MMM_TO_MMS(manual_feedrate_mm_m[manual_move_axis]), manual_move_e_index); + planner.buffer_line_kinematic(current_position, MMM_TO_MMS(manual_feedrate_mm_m[manual_move_axis]), manual_move_axis == E_AXIS ? manual_move_e_index : active_extruder); manual_move_axis = (int8_t)NO_AXIS; #endif @@ -3073,7 +3077,7 @@ void lcd_quick_feedback(const bool clear_buttons) { #if IS_KINEMATIC manual_move_offset += diff; #else - current_position[E_AXIS] += diff; + current_position[E_CART] += diff; #endif manual_move_to_current(E_AXIS #if E_MANUAL > 1 @@ -3103,7 +3107,7 @@ void lcd_quick_feedback(const bool clear_buttons) { #endif // E_MANUAL > 2 } #endif // E_MANUAL > 1 - lcd_implementation_drawedit(pos_label, ftostr41sign(current_position[E_AXIS] + lcd_implementation_drawedit(pos_label, ftostr41sign(current_position[E_CART] #if IS_KINEMATIC + manual_move_offset #endif @@ -3518,7 +3522,7 @@ void lcd_quick_feedback(const bool clear_buttons) { MENU_ITEM_EDIT(bool, MSG_AUTOTEMP, &planner.autotemp_enabled); MENU_ITEM_EDIT(float3, MSG_MIN, &planner.autotemp_min, 0, float(HEATER_0_MAXTEMP) - 15); MENU_ITEM_EDIT(float3, MSG_MAX, &planner.autotemp_max, 0, float(HEATER_0_MAXTEMP) - 15); - MENU_ITEM_EDIT(float52, MSG_FACTOR, &planner.autotemp_factor, 0.0, 1.0); + MENU_ITEM_EDIT(float52, MSG_FACTOR, &planner.autotemp_factor, 0, 1); #endif // @@ -4034,9 +4038,9 @@ void lcd_quick_feedback(const bool clear_buttons) { #endif if (card.filenameIsDir) - MENU_ITEM(sddirectory, MSG_CARD_MENU, card.filename, card.longFilename); + MENU_ITEM(sddirectory, MSG_CARD_MENU, card); else - MENU_ITEM(sdfile, MSG_CARD_MENU, card.filename, card.longFilename); + MENU_ITEM(sdfile, MSG_CARD_MENU, card); } else { MENU_ITEM_DUMMY(); @@ -4846,13 +4850,13 @@ void lcd_quick_feedback(const bool clear_buttons) { DEFINE_MENU_EDIT_TYPE(int16_t, int3, itostr3, 1); DEFINE_MENU_EDIT_TYPE(uint8_t, int8, i8tostr3, 1); - DEFINE_MENU_EDIT_TYPE(float, float3, ftostr3, 1.0f); - DEFINE_MENU_EDIT_TYPE(float, float52, ftostr52, 100.0f); - DEFINE_MENU_EDIT_TYPE(float, float43, ftostr43sign, 1000.0f); + DEFINE_MENU_EDIT_TYPE(float, float3, ftostr3, 1); + DEFINE_MENU_EDIT_TYPE(float, float52, ftostr52, 100); + DEFINE_MENU_EDIT_TYPE(float, float43, ftostr43sign, 1000); DEFINE_MENU_EDIT_TYPE(float, float5, ftostr5rj, 0.01f); - DEFINE_MENU_EDIT_TYPE(float, float51, ftostr51sign, 10.0f); - DEFINE_MENU_EDIT_TYPE(float, float52sign, ftostr52sign, 100.0f); - DEFINE_MENU_EDIT_TYPE(float, float62, ftostr62rj, 100.0f); + DEFINE_MENU_EDIT_TYPE(float, float51, ftostr51sign, 10); + DEFINE_MENU_EDIT_TYPE(float, float52sign, ftostr52sign, 100); + DEFINE_MENU_EDIT_TYPE(float, float62, ftostr62rj, 100); DEFINE_MENU_EDIT_TYPE(uint32_t, long5, ftostr5rj, 0.01f); /** @@ -4957,19 +4961,17 @@ void lcd_quick_feedback(const bool clear_buttons) { #if ENABLED(SDSUPPORT) - void menu_action_sdfile(const char* filename, char* longFilename) { + void menu_action_sdfile(CardReader& theCard) { #if ENABLED(SD_REPRINT_LAST_SELECTED_FILE) last_sdfile_encoderPosition = encoderPosition; // Save which file was selected for later use #endif - UNUSED(longFilename); - card.openAndPrintFile(filename); + card.openAndPrintFile(theCard.filename); lcd_return_to_status(); lcd_reset_status(); } - void menu_action_sddirectory(const char* filename, char* longFilename) { - UNUSED(longFilename); - card.chdir(filename); + void menu_action_sddirectory(CardReader& theCard) { + card.chdir(theCard.filename); encoderTopLine = 0; encoderPosition = 2 * ENCODER_STEPS_PER_MENU_ITEM; screen_changed = true; @@ -5053,7 +5055,7 @@ void lcd_init() { #endif } -int16_t lcd_strlen(const char* s) { +int16_t utf8_strlen(const char* s) { int16_t i = 0, j = 0; while (s[i]) { if (START_OF_UTF8_CHAR(s[i])) j++; @@ -5062,7 +5064,7 @@ int16_t lcd_strlen(const char* s) { return j; } -int16_t lcd_strlen_P(const char* s) { +int16_t utf8_strlen_P(const char* s) { int16_t j = 0; while (pgm_read_byte(s)) { if (START_OF_UTF8_CHAR(pgm_read_byte(s))) j++; diff --git a/Marlin/ultralcd.h b/Marlin/ultralcd.h index e03efceba1..d6bc799681 100644 --- a/Marlin/ultralcd.h +++ b/Marlin/ultralcd.h @@ -41,8 +41,8 @@ #include "Marlin.h" - int16_t lcd_strlen(const char* s); - int16_t lcd_strlen_P(const char* s); + int16_t utf8_strlen(const char* s); + int16_t utf8_strlen_P(const char* s); bool lcd_hasstatus(); void lcd_setstatus(const char* message, const bool persist=false); void lcd_setstatusPGM(const char* message, const int8_t level=0); diff --git a/Marlin/ultralcd_impl_DOGM.h b/Marlin/ultralcd_impl_DOGM.h index c5fd1999cb..935b9929d4 100644 --- a/Marlin/ultralcd_impl_DOGM.h +++ b/Marlin/ultralcd_impl_DOGM.h @@ -356,10 +356,8 @@ static void lcd_implementation_init() { OUT_WRITE(LCD_BACKLIGHT_PIN, HIGH); #endif - #if ENABLED(MKS_12864OLED) || ENABLED(MKS_12864OLED_SSD1306) - OUT_WRITE(LCD_PINS_RS, LOW); - _delay_ms(500); - OUT_WRITE(LCD_PINS_RS, HIGH); + #if !defined(LCD_RESET_PIN) && (ENABLED(MKS_12864OLED) || ENABLED(MKS_12864OLED_SSD1306)) + #define LCD_RESET_PIN LCD_PINS_RS #endif #if PIN_EXISTS(LCD_RESET) @@ -369,7 +367,7 @@ static void lcd_implementation_init() { _delay_ms(5); // delay to allow the display to initalize #endif - #if PIN_EXISTS(LCD_RESET) || ENABLED(MKS_12864OLED) || ENABLED(MKS_12864OLED_SSD1306) + #if PIN_EXISTS(LCD_RESET) u8g.begin(); #endif @@ -468,7 +466,7 @@ void lcd_implementation_clear() { } // Automatically cleared by Picture Loop int8_t n = LCD_WIDTH - (START_COL); if (center && !valstr) { - int8_t pad = (LCD_WIDTH - lcd_strlen_P(pstr)) / 2; + int8_t pad = (LCD_WIDTH - utf8_strlen_P(pstr)) / 2; while (--pad >= 0) { u8g.print(' '); n--; } } while (n > 0 && (c = pgm_read_byte(pstr))) { @@ -514,7 +512,7 @@ void lcd_implementation_clear() { } // Automatically cleared by Picture Loop if (!PAGE_CONTAINS(row_y1, row_y2)) return; - const uint8_t vallen = (pgm ? lcd_strlen_P(data) : (lcd_strlen((char*)data))); + const uint8_t vallen = (pgm ? utf8_strlen_P(data) : utf8_strlen((char*)data)); uint8_t n = LCD_WIDTH - (START_COL) - 2 - vallen; while (char c = pgm_read_byte(pstr)) { @@ -535,8 +533,8 @@ void lcd_implementation_clear() { } // Automatically cleared by Picture Loop #define DRAW_BOOL_SETTING(sel, row, pstr, data) lcd_implementation_drawmenu_setting_edit_generic_P(sel, row, pstr, (*(data))?PSTR(MSG_ON):PSTR(MSG_OFF)) void lcd_implementation_drawedit(const char* const pstr, const char* const value=NULL) { - const uint8_t labellen = lcd_strlen_P(pstr), - vallen = lcd_strlen(value); + const uint8_t labellen = utf8_strlen_P(pstr), + vallen = utf8_strlen(value); uint8_t rows = (labellen > LCD_WIDTH - 2 - vallen) ? 2 : 1; @@ -586,7 +584,7 @@ void lcd_implementation_clear() { } // Automatically cleared by Picture Loop #if ENABLED(SDSUPPORT) - static void _drawmenu_sd(const bool isSelected, const uint8_t row, const char* const pstr, const char* filename, char* const longFilename, const bool isDir) { + static void _drawmenu_sd(const bool isSelected, const uint8_t row, const char* const pstr, CardReader& theCard, const bool isDir) { UNUSED(pstr); lcd_implementation_mark_as_selected(row, isSelected); @@ -594,23 +592,23 @@ void lcd_implementation_clear() { } // Automatically cleared by Picture Loop if (!PAGE_CONTAINS(row_y1, row_y2)) return; constexpr uint8_t maxlen = LCD_WIDTH - (START_COL) - 1; - const char *outstr = longFilename[0] ? longFilename : filename; - if (longFilename[0]) { + const char *outstr = theCard.longest_filename(); + if (theCard.longFilename[0]) { #if ENABLED(SCROLL_LONG_FILENAMES) if (isSelected) { uint8_t name_hash = row; for (uint8_t l = FILENAME_LENGTH; l--;) - name_hash = ((name_hash << 1) | (name_hash >> 7)) ^ filename[l]; // rotate, xor + name_hash = ((name_hash << 1) | (name_hash >> 7)) ^ theCard.filename[l]; // rotate, xor if (filename_scroll_hash != name_hash) { // If the hash changed... filename_scroll_hash = name_hash; // Save the new hash - filename_scroll_max = MAX(0, lcd_strlen(longFilename) - maxlen); // Update the scroll limit + filename_scroll_max = MAX(0, utf8_strlen(theCard.longFilename) - maxlen); // Update the scroll limit filename_scroll_pos = 0; // Reset scroll to the start lcd_status_update_delay = 8; // Don't scroll right away } outstr += filename_scroll_pos; } #else - longFilename[maxlen] = '\0'; // cutoff at screen edge + theCard.longFilename[maxlen] = '\0'; // cutoff at screen edge #endif } @@ -625,8 +623,8 @@ void lcd_implementation_clear() { } // Automatically cleared by Picture Loop while (n) { --n; u8g.print(' '); } } - #define lcd_implementation_drawmenu_sdfile(sel, row, pstr, filename, longFilename) _drawmenu_sd(sel, row, pstr, filename, longFilename, false) - #define lcd_implementation_drawmenu_sddirectory(sel, row, pstr, filename, longFilename) _drawmenu_sd(sel, row, pstr, filename, longFilename, true) + #define lcd_implementation_drawmenu_sdfile(sel, row, pstr, theCard) _drawmenu_sd(sel, row, pstr, theCard, false) + #define lcd_implementation_drawmenu_sddirectory(sel, row, pstr, theCard) _drawmenu_sd(sel, row, pstr, theCard, true) #endif // SDSUPPORT diff --git a/Marlin/ultralcd_impl_HD44780.h b/Marlin/ultralcd_impl_HD44780.h index e2be71332b..d229a8378b 100644 --- a/Marlin/ultralcd_impl_HD44780.h +++ b/Marlin/ultralcd_impl_HD44780.h @@ -491,7 +491,7 @@ void lcd_printPGM_utf(const char *str, uint8_t n=LCD_WIDTH) { // Scroll the PSTR 'text' in a 'len' wide field for 'time' milliseconds at position col,line void lcd_scroll(const int16_t col, const int16_t line, const char* const text, const int16_t len, const int16_t time) { - uint8_t slen = lcd_strlen_P(text); + uint8_t slen = utf8_strlen_P(text); if (slen < len) { // Fits into, lcd.setCursor(col, line); @@ -531,7 +531,7 @@ void lcd_printPGM_utf(const char *str, uint8_t n=LCD_WIDTH) { } static void logo_lines(const char* const extra) { - int16_t indent = (LCD_WIDTH - 8 - lcd_strlen_P(extra)) / 2; + int16_t indent = (LCD_WIDTH - 8 - utf8_strlen_P(extra)) / 2; lcd.setCursor(indent, 0); lcd.print('\x00'); lcd_printPGM(PSTR( "------" )); lcd.write('\x01'); lcd.setCursor(indent, 1); lcd_printPGM(PSTR("|Marlin|")); lcd_printPGM(extra); lcd.setCursor(indent, 2); lcd.write('\x02'); lcd_printPGM(PSTR( "------" )); lcd.write('\x03'); @@ -546,7 +546,7 @@ void lcd_printPGM_utf(const char *str, uint8_t n=LCD_WIDTH) { #define CENTER_OR_SCROLL(STRING,DELAY) \ lcd_erase_line(3); \ if (strlen(STRING) <= LCD_WIDTH) { \ - lcd.setCursor((LCD_WIDTH - lcd_strlen_P(PSTR(STRING))) / 2, 3); \ + lcd.setCursor((LCD_WIDTH - utf8_strlen_P(PSTR(STRING))) / 2, 3); \ lcd_printPGM_utf(PSTR(STRING)); \ safe_delay(DELAY); \ } \ @@ -926,7 +926,7 @@ static void lcd_implementation_status_screen() { static bool last_blink = false; // Get the UTF8 character count of the string - uint8_t slen = lcd_strlen(lcd_status_message); + uint8_t slen = utf8_strlen(lcd_status_message); // If the string fits into the LCD, just print it and do not scroll it if (slen <= LCD_WIDTH) { @@ -947,7 +947,7 @@ static void lcd_implementation_status_screen() { const char *stat = lcd_status_message + status_scroll_offset; // Get the string remaining length - const uint8_t rlen = lcd_strlen(stat); + const uint8_t rlen = utf8_strlen(stat); // If we have enough characters to display if (rlen >= LCD_WIDTH) { @@ -984,7 +984,7 @@ static void lcd_implementation_status_screen() { UNUSED(blink); // Get the UTF8 character count of the string - uint8_t slen = lcd_strlen(lcd_status_message); + uint8_t slen = utf8_strlen(lcd_status_message); // Just print the string to the LCD lcd_print_utf(lcd_status_message, LCD_WIDTH); @@ -995,11 +995,8 @@ static void lcd_implementation_status_screen() { ++slen; } #endif - } - - #if ENABLED(ULTIPANEL) #if ENABLED(ADVANCED_PAUSE_FEATURE) @@ -1019,7 +1016,7 @@ static void lcd_implementation_status_screen() { int8_t n = LCD_WIDTH; lcd.setCursor(0, row); if (center && !valstr) { - int8_t pad = (LCD_WIDTH - lcd_strlen_P(pstr)) / 2; + int8_t pad = (LCD_WIDTH - utf8_strlen_P(pstr)) / 2; while (--pad >= 0) { lcd.write(' '); n--; } } while (n > 0 && (c = pgm_read_byte(pstr))) { @@ -1048,7 +1045,7 @@ static void lcd_implementation_status_screen() { static void lcd_implementation_drawmenu_setting_edit_generic(const bool sel, const uint8_t row, const char* pstr, const char pre_char, const char* const data) { char c; - uint8_t n = LCD_WIDTH - 2 - lcd_strlen(data); + uint8_t n = LCD_WIDTH - 2 - utf8_strlen(data); lcd.setCursor(0, row); lcd.print(sel ? pre_char : ' '); while ((c = pgm_read_byte(pstr)) && n > 0) { @@ -1061,7 +1058,7 @@ static void lcd_implementation_status_screen() { } static void lcd_implementation_drawmenu_setting_edit_generic_P(const bool sel, const uint8_t row, const char* pstr, const char pre_char, const char* const data) { char c; - uint8_t n = LCD_WIDTH - 2 - lcd_strlen_P(data); + uint8_t n = LCD_WIDTH - 2 - utf8_strlen_P(data); lcd.setCursor(0, row); lcd.print(sel ? pre_char : ' '); while ((c = pgm_read_byte(pstr)) && n > 0) { @@ -1081,8 +1078,8 @@ static void lcd_implementation_status_screen() { lcd_printPGM_utf(pstr); if (value != NULL) { lcd.write(':'); - const uint8_t valrow = (lcd_strlen_P(pstr) + 1 + lcd_strlen(value) + 1) > (LCD_WIDTH - 2) ? 2 : 1; // Value on the next row if it won't fit - lcd.setCursor((LCD_WIDTH - 1) - (lcd_strlen(value) + 1), valrow); // Right-justified, padded by spaces + const uint8_t valrow = (utf8_strlen_P(pstr) + 1 + utf8_strlen(value) + 1) > (LCD_WIDTH - 2) ? 2 : 1; // Value on the next row if it won't fit + lcd.setCursor((LCD_WIDTH - 1) - (utf8_strlen(value) + 1), valrow); // Right-justified, padded by spaces lcd.write(' '); // overwrite char if value gets shorter lcd_print(value); } @@ -1090,29 +1087,29 @@ static void lcd_implementation_status_screen() { #if ENABLED(SDSUPPORT) - static void lcd_implementation_drawmenu_sd(const bool sel, const uint8_t row, const char* const pstr, const char* filename, char* const longFilename, const uint8_t concat, const char post_char) { + static void lcd_implementation_drawmenu_sd(const bool sel, const uint8_t row, const char* const pstr, CardReader& theCard, const uint8_t concat, const char post_char) { UNUSED(pstr); lcd.setCursor(0, row); lcd.print(sel ? '>' : ' '); uint8_t n = LCD_WIDTH - concat; - const char *outstr = longFilename[0] ? longFilename : filename; - if (longFilename[0]) { + const char *outstr = theCard.longest_filename(); + if (theCard.longFilename[0]) { #if ENABLED(SCROLL_LONG_FILENAMES) if (sel) { uint8_t name_hash = row; for (uint8_t l = FILENAME_LENGTH; l--;) - name_hash = ((name_hash << 1) | (name_hash >> 7)) ^ filename[l]; // rotate, xor + name_hash = ((name_hash << 1) | (name_hash >> 7)) ^ theCard.filename[l]; // rotate, xor if (filename_scroll_hash != name_hash) { // If the hash changed... filename_scroll_hash = name_hash; // Save the new hash - filename_scroll_max = MAX(0, lcd_strlen(longFilename) - n); // Update the scroll limit + filename_scroll_max = MAX(0, utf8_strlen(theCard.longFilename) - n); // Update the scroll limit filename_scroll_pos = 0; // Reset scroll to the start lcd_status_update_delay = 8; // Don't scroll right away } outstr += filename_scroll_pos; } #else - longFilename[n] = '\0'; // cutoff at screen edge + theCard.longFilename[n] = '\0'; // cutoff at screen edge #endif } @@ -1126,12 +1123,12 @@ static void lcd_implementation_status_screen() { lcd.print(post_char); } - static void lcd_implementation_drawmenu_sdfile(const bool sel, const uint8_t row, const char* pstr, const char* filename, char* const longFilename) { - lcd_implementation_drawmenu_sd(sel, row, pstr, filename, longFilename, 2, ' '); + static void lcd_implementation_drawmenu_sdfile(const bool sel, const uint8_t row, const char* pstr, CardReader& theCard) { + lcd_implementation_drawmenu_sd(sel, row, pstr, theCard, 2, ' '); } - static void lcd_implementation_drawmenu_sddirectory(const bool sel, const uint8_t row, const char* pstr, const char* filename, char* const longFilename) { - lcd_implementation_drawmenu_sd(sel, row, pstr, filename, longFilename, 2, LCD_STR_FOLDER[0]); + static void lcd_implementation_drawmenu_sddirectory(const bool sel, const uint8_t row, const char* pstr, CardReader& theCard) { + lcd_implementation_drawmenu_sd(sel, row, pstr, theCard, 2, LCD_STR_FOLDER[0]); } #endif // SDSUPPORT diff --git a/Marlin/ultralcd_st7565_u8glib_VIKI.h b/Marlin/ultralcd_st7565_u8glib_VIKI.h index 9ab142b2e8..adb48ea6b2 100644 --- a/Marlin/ultralcd_st7565_u8glib_VIKI.h +++ b/Marlin/ultralcd_st7565_u8glib_VIKI.h @@ -89,7 +89,7 @@ #if HARDWARE_SPI // using the hardware SPI #define ST7565_WRITE_BYTE(a) { SPDR = a; while (!TEST(SPSR, SPIF)); U8G_DELAY(); } - #define ST7560_WriteSequence(count, pointer) { uint8_t *ptr = pointer; for (uint8_t i = 0; i < count; i++) {SPDR = *ptr++; while (!TEST(SPSR, SPIF));} DELAY_10US; } + #define ST7560_WriteSequence(count, pointer) { uint8_t *ptr = pointer; for (uint8_t i = 0; i < count; i++) {SPDR = *ptr++; while (!TEST(SPSR, SPIF));} U8G_DELAY(); } #else // !HARDWARE_SPI @@ -112,7 +112,7 @@ } #define ST7565_WRITE_BYTE(a) { ST7565_SWSPI_SND_8BIT((uint8_t)a); U8G_DELAY(); } - #define ST7560_WriteSequence(count, pointer) { uint8_t *ptr = pointer; for (uint8_t i = 0; i < count; i++) { ST7565_SWSPI_SND_8BIT(*ptr++); } DELAY_10US; } + #define ST7560_WriteSequence(count, pointer) { uint8_t *ptr = pointer; for (uint8_t i = 0; i < count; i++) { ST7565_SWSPI_SND_8BIT(*ptr++); } U8G_DELAY(); } #endif // !HARDWARE_SPI